From 84884111c312b3b469cdb5221de15c0b9d8617c8 Mon Sep 17 00:00:00 2001 From: michael musset Date: Wed, 15 Jul 2020 16:39:40 +0200 Subject: [PATCH] SFTP: add the option CURLKHSTAT_FINE_REPLACE this functionality is usefull when you need to update the fingerprint of the host. The other option : CURLKHSTAT_FINE_ADD_TO_FILE, append the new fingerprint in the file, but the old fingerprint is not deleted. --- docs/libcurl/opts/CURLOPT_SSH_KEYFUNCTION.3 | 8 ++++++++ docs/libcurl/symbols-in-versions | 1 + include/curl/curl.h | 1 + lib/vssh/libssh2.c | 11 +++++++++-- 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/docs/libcurl/opts/CURLOPT_SSH_KEYFUNCTION.3 b/docs/libcurl/opts/CURLOPT_SSH_KEYFUNCTION.3 index 895bc3687cd6c3..18a414c3d45874 100644 --- a/docs/libcurl/opts/CURLOPT_SSH_KEYFUNCTION.3 +++ b/docs/libcurl/opts/CURLOPT_SSH_KEYFUNCTION.3 @@ -35,6 +35,7 @@ enum curl_khstat { now so this causes a CURLE_DEFER error but otherwise the connection will be left intact etc */ + CURLKHSTAT_FINE_REPLACE }; enum curl_khmatch { @@ -73,6 +74,13 @@ info from libcurl on the matching status and a custom pointer (set with \fICURLOPT_SSH_KEYDATA(3)\fP). It MUST return one of the following return codes to tell libcurl how to act: +.IP CURLKHSTAT_FINE_REPLACE +Added in 7.73.0 The new host+key is accepted and libcurl will replace the old +host+key into the known_hosts file before continuing with the connection. +This will also add the new host+key combo to the known_host pool kept in memory +if it wasn't already present there. The adding of data to the file is done by +completely replacing the file with a new copy, so the permissions of the file +must allow this. .IP CURLKHSTAT_FINE_ADD_TO_FILE The host+key is accepted and libcurl will append it to the known_hosts file before continuing with the connection. This will also add the host+key combo diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions index ca28657258a958..aa93f262adbea7 100644 --- a/docs/libcurl/symbols-in-versions +++ b/docs/libcurl/symbols-in-versions @@ -310,6 +310,7 @@ CURLKHSTAT_DEFER 7.19.6 CURLKHSTAT_FINE 7.19.6 CURLKHSTAT_FINE_ADD_TO_FILE 7.19.6 CURLKHSTAT_REJECT 7.19.6 +CURLKHSTAT_FINE_REPLACE 7.73.0 CURLKHTYPE_DSS 7.19.6 CURLKHTYPE_ECDSA 7.58.0 CURLKHTYPE_ED25519 7.58.0 diff --git a/include/curl/curl.h b/include/curl/curl.h index e231b710cdb118..cad02bdc233c0b 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -789,6 +789,7 @@ enum curl_khstat { CURLKHSTAT_DEFER, /* do not accept it, but we can't answer right now so this causes a CURLE_DEFER error but otherwise the connection will be left intact etc */ + CURLKHSTAT_FINE_REPLACE, /* accept and replace the wrong key*/ CURLKHSTAT_LAST /* not for use, only a marker for last-in-list */ }; diff --git a/lib/vssh/libssh2.c b/lib/vssh/libssh2.c index 555afc9ef6bf66..f4ac85caced5f6 100644 --- a/lib/vssh/libssh2.c +++ b/lib/vssh/libssh2.c @@ -442,6 +442,7 @@ static CURLcode ssh_knownhost(struct connectdata *conn) if(data->set.str[STRING_SSH_KNOWNHOSTS]) { /* we're asked to verify the host against a file */ struct ssh_conn *sshc = &conn->proto.sshc; + struct libssh2_knownhost *host = NULL; int rc; int keytype; size_t keylen; @@ -456,7 +457,6 @@ static CURLcode ssh_knownhost(struct connectdata *conn) * What host name does OpenSSH store in its file if an IDN name is * used? */ - struct libssh2_knownhost *host; enum curl_khmatch keymatch; curl_sshkeycallback func = data->set.ssh_keyfunc?data->set.ssh_keyfunc:sshkeycallback; @@ -568,7 +568,13 @@ static CURLcode ssh_knownhost(struct connectdata *conn) /* DEFER means bail out but keep the SSH_HOSTKEY state */ result = sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION; break; + case CURLKHSTAT_FINE_REPLACE: + /* remove old host+key that doesn't match */ + if(host) + libssh2_knownhost_del(sshc->kh, host); + /*FALLTHROUGH*/ case CURLKHSTAT_FINE: + /*FALLTHROUGH*/ case CURLKHSTAT_FINE_ADD_TO_FILE: /* proceed */ if(keycheck != LIBSSH2_KNOWNHOST_CHECK_MATCH) { @@ -583,7 +589,8 @@ static CURLcode ssh_knownhost(struct connectdata *conn) if(addrc) infof(data, "Warning adding the known host %s failed!\n", conn->host.name); - else if(rc == CURLKHSTAT_FINE_ADD_TO_FILE) { + else if(rc == CURLKHSTAT_FINE_ADD_TO_FILE || + rc == CURLKHSTAT_FINE_REPLACE) { /* now we write the entire in-memory list of known hosts to the known_hosts file */ int wrc =