Backport patch to fix CVE-2021-36370.

Upstream-Status: Backport [https://github.com/MidnightCommander/mc/commit/9235d3c]
CVE: CVE-2021-36370

Signed-off-by: Kai Kang <kai.kang@windriver.com>

From 9235d3c232d13ad7f973346077c9cf2eaa77dc5f Mon Sep 17 00:00:00 2001
From: Andrew Borodin <aborodin@vmail.ru>
Date: Mon, 12 Jul 2021 08:48:18 +0300
Subject: [PATCH] SFTPFS: verify server fingerprint (fix CVE-2021-36370).

Use ~/.ssh/known_hosts file to verify server fingerprint
using ssh way:

$ ssh localhost
The authenticity of host 'localhost (127.0.0.1)' can't be established.
ED25519 key fingerprint is SHA256:FzqKTNTroFuNUj1wUzSeV2x/1lpcESnT0ZRCmq5H6o8.
Are you sure you want to continue connecting (yes/no)? no
ssh: Host key verification failed.

$ ssh localhost
The authenticity of host 'localhost (127.0.0.1)' can't be established.
ED25519 key fingerprint is SHA256:FzqKTNTroFuNUj1wUzSeV2x/1lpcESnT0ZRCmq5H6o8.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'localhost' (ED25519) to the list of known hosts.
andrew@localhost's password:

Thanks the Curl project for the used code.

Signed-off-by: Andrew Borodin <aborodin@vmail.ru>
Signed-off-by: Yury V. Zaytsev <yury.zaytsev@moneymeets.com>
---
 doc/man/mc.1.in             |  15 ++
 doc/man/ru/mc.1.in          |  14 ++
 src/vfs/sftpfs/connection.c | 428 +++++++++++++++++++++++++++++++++++-
 src/vfs/sftpfs/internal.h   |   5 +-
 4 files changed, 452 insertions(+), 10 deletions(-)

diff --git a/doc/man/mc.1.in b/doc/man/mc.1.in
index c0c06e32f7..7a3d118384 100644
--- a/doc/man/mc.1.in
+++ b/doc/man/mc.1.in
@@ -3364,6 +3364,21 @@ Examples:
     sftp://joe@noncompressed.ssh.edu/private
     sftp://joe@somehost.ssh.edu:2222/private
 .fi
+.PP
+When establishing the connection, server key fingerprint is verified using
+the ~/.ssh/known_hosts file. If the host/key pair is not found or the host is found,
+but the key doesn't match, an appropriate message is shown.
+There are three buttons in the message dialog:
+.PP
+.B [Yes]
+add new host/key pair to the ~/.ssh/known_hosts file and continue.
+.PP
+.B [Ignore]
+do not add new host/key pair to the ~/.ssh/known_hosts file, but continue
+nevertheless (at you own risk).
+.PP
+.B [No]
+abort connection.
 .\"NODE "  Undelete File System"
 .SH "  Undelete File System"
 On Linux systems, if you asked configure to use the ext2fs undelete
diff --git a/doc/man/ru/mc.1.in b/doc/man/ru/mc.1.in
index 7609da1127..bc0c1810a9 100644
--- a/doc/man/ru/mc.1.in
+++ b/doc/man/ru/mc.1.in
@@ -3874,6 +3874,20 @@ bash\-совместимая оболочка shell.
     sftp://joe@noncompressed.ssh.edu/private
     sftp://joe@somehost.ssh.edu:2222/private
 .fi
+При установлении соединения происходит проверка ключа сервера с использованием
+файла ~/.ssh/known_hosts file. Если пара сервер/ключ в этом файле не найдена
+или сервер найден, но ключ не соответствует, пользователю показывается
+окно с соответствующим сообщением, содержащее три кнопки:
+.PP
+.B [Да]
+добавить новую пару сервер/ключ в файл ~/.ssh/known_hosts и продолжить соединение.
+.PP
+.B [Игнорировать]
+не добавлять новую пару сервер/ключ в файл ~/.ssh/known_hosts и всё равно
+продолжить соединение (на свой страх и риск).
+.PP
+.B [Нет]
+прервать соединение.
 .\"NODE "  Undelete File System"
 .SH "  Файловая система UFS (Undelete File System)"
 В ОС Linux можно сконфигурировать файловую систему ext2fs, используемую
diff --git a/src/vfs/sftpfs/connection.c b/src/vfs/sftpfs/connection.c
index 9f8ea5633b..acd5026515 100644
--- a/src/vfs/sftpfs/connection.c
+++ b/src/vfs/sftpfs/connection.c
@@ -42,6 +42,8 @@
 #include "lib/util.h"
 #include "lib/tty/tty.h"        /* tty_enable_interrupt_key () */
 #include "lib/vfs/utilvfs.h"
+#include "lib/mcconfig.h"       /* mc_config_get_home_dir () */
+#include "lib/widget.h"         /* query_dialog () */
 
 #include "internal.h"
 
@@ -49,10 +51,37 @@
 
 /*** file scope macro definitions ****************************************************************/
 
+#define SHA1_DIGEST_LENGTH 20
+
 /*** file scope type declarations ****************************************************************/
 
 /*** file scope variables ************************************************************************/
 
+#ifdef LIBSSH2_KNOWNHOST_KEY_ED25519
+static const char *const hostkey_method_ssh_ed25519 = "ssh-ed25519";
+#endif
+#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_521
+static const char *const hostkey_method_ssh_ecdsa_521 = "ecdsa-sha2-nistp521";
+#endif
+#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_384
+static const char *const hostkey_method_ssh_ecdsa_384 = "ecdsa-sha2-nistp384";
+#endif
+#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_256
+static const char *const hostkey_method_ssh_ecdsa_256 = "ecdsa-sha2-nistp256";
+#endif
+static const char *const hostkey_method_ssh_rsa = "ssh-rsa";
+static const char *const hostkey_method_ssh_dss = "ssh-dss";
+
+/**
+ *
+ * The current implementation of know host key checking has following limitations:
+ *
+ *   - Only plain-text entries are supported (`HashKnownHosts no` OpenSSH option)
+ *   - Only HEX-encoded SHA1 fingerprint display is supported (`FingerprintHash` OpenSSH option)
+ *   - Resolved IP addresses are *not* saved/validated along with the hostnames
+ *
+ */
+
 static const char *kbi_passwd = NULL;
 static const struct vfs_s_super *kbi_super = NULL;
 
@@ -70,9 +99,12 @@ static const struct vfs_s_super *kbi_super = NULL;
 static int
 sftpfs_open_socket (struct vfs_s_super *super, GError ** mcerror)
 {
+    sftpfs_super_t *sftpfs_super = SFTP_SUPER (super);
     struct addrinfo hints, *res = NULL, *curr_res;
     int my_socket = 0;
     char port[BUF_TINY];
+    static char address_ipv4[INET_ADDRSTRLEN];
+    static char address_ipv6[INET6_ADDRSTRLEN];
     int e;
 
     mc_return_val_if_error (mcerror, LIBSSH2_INVALID_SOCKET);
@@ -120,6 +152,30 @@ sftpfs_open_socket (struct vfs_s_super *super, GError ** mcerror)
     {
         int save_errno;
 
+        switch (curr_res->ai_addr->sa_family)
+        {
+        case AF_INET:
+            sftpfs_super->ip_address =
+                inet_ntop (AF_INET, &((struct sockaddr_in *) curr_res->ai_addr)->sin_addr,
+                           address_ipv4, INET_ADDRSTRLEN);
+            break;
+        case AF_INET6:
+            sftpfs_super->ip_address =
+                inet_ntop (AF_INET6, &((struct sockaddr_in6 *) curr_res->ai_addr)->sin6_addr,
+                           address_ipv6, INET6_ADDRSTRLEN);
+            break;
+        default:
+            sftpfs_super->ip_address = NULL;
+        }
+
+        if (sftpfs_super->ip_address == NULL)
+        {
+            mc_propagate_error (mcerror, 0, "%s",
+                                _("sftp: failed to convert remote host IP address into text form"));
+            my_socket = LIBSSH2_INVALID_SOCKET;
+            goto ret;
+        }
+
         my_socket = socket (curr_res->ai_family, curr_res->ai_socktype, curr_res->ai_protocol);
 
         if (my_socket < 0)
@@ -161,8 +217,358 @@ sftpfs_open_socket (struct vfs_s_super *super, GError ** mcerror)
 }
 
 /* --------------------------------------------------------------------------------------------- */
+
+/**
+ * Read ~/.ssh/known_hosts file.
+ *
+ * @param super connection data
+ * @param mcerror pointer to the error handler
+ * @return TRUE on success, FALSE otherwise
+ *
+ * Thanks the Curl project for the code used in this function.
+ */
+static gboolean
+sftpfs_read_known_hosts (struct vfs_s_super *super, GError ** mcerror)
+{
+    sftpfs_super_t *sftpfs_super = SFTP_SUPER (super);
+    struct libssh2_knownhost *store = NULL;
+    int rc;
+    gboolean found = FALSE;
+
+    sftpfs_super->known_hosts = libssh2_knownhost_init (sftpfs_super->session);
+    if (sftpfs_super->known_hosts == NULL)
+        goto err;
+
+    sftpfs_super->known_hosts_file =
+        mc_build_filename (mc_config_get_home_dir (), ".ssh", "known_hosts", (char *) NULL);
+    rc = libssh2_knownhost_readfile (sftpfs_super->known_hosts, sftpfs_super->known_hosts_file,
+                                     LIBSSH2_KNOWNHOST_FILE_OPENSSH);
+    if (rc > 0)
+    {
+        const char *kh_name_end = NULL;
+
+        while (!found && libssh2_knownhost_get (sftpfs_super->known_hosts, &store, store) == 0)
+        {
+            /* For non-standard ports, the name will be enclosed in
+             * square brackets, followed by a colon and the port */
+            if (store == NULL)
+                continue;
+
+            if (store->name == NULL)
+                found = TRUE;
+            else if (store->name[0] != '[')
+                found = strcmp (store->name, super->path_element->host) == 0;
+            else
+            {
+                int port;
+
+                kh_name_end = strstr (store->name, "]:");
+                if (kh_name_end == NULL)
+                    /* Invalid host pattern */
+                    continue;
+
+                port = (int) g_ascii_strtoll (kh_name_end + 2, NULL, 10);
+                if (port == super->path_element->port)
+                {
+                    size_t kh_name_size;
+
+                    kh_name_size = strlen (store->name) - 1 - strlen (kh_name_end);
+                    found = strncmp (store->name + 1, super->path_element->host, kh_name_size) == 0;
+                }
+            }
+        }
+    }
+
+    if (found)
+    {
+        int mask;
+        const char *hostkey_method = NULL;
+
+        mask = store->typemask & LIBSSH2_KNOWNHOST_KEY_MASK;
+
+        switch (mask)
+        {
+#ifdef LIBSSH2_KNOWNHOST_KEY_ED25519
+        case LIBSSH2_KNOWNHOST_KEY_ED25519:
+            hostkey_method = hostkey_method_ssh_ed25519;
+            break;
+#endif
+#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_521
+        case LIBSSH2_KNOWNHOST_KEY_ECDSA_521:
+            hostkey_method = hostkey_method_ssh_ecdsa_521;
+            break;
+#endif
+#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_384
+        case LIBSSH2_KNOWNHOST_KEY_ECDSA_384:
+            hostkey_method = hostkey_method_ssh_ecdsa_384;
+            break;
+#endif
+#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_256
+        case LIBSSH2_KNOWNHOST_KEY_ECDSA_256:
+            hostkey_method = hostkey_method_ssh_ecdsa_256;
+            break;
+#endif
+        case LIBSSH2_KNOWNHOST_KEY_SSHRSA:
+            hostkey_method = hostkey_method_ssh_rsa;
+            break;
+        case LIBSSH2_KNOWNHOST_KEY_SSHDSS:
+            hostkey_method = hostkey_method_ssh_dss;
+            break;
+        case LIBSSH2_KNOWNHOST_KEY_RSA1:
+            mc_propagate_error (mcerror, 0, "%s",
+                                _("sftp: found host key of unsupported type: RSA1"));
+            return FALSE;
+        default:
+            mc_propagate_error (mcerror, 0, "%s %d", _("sftp: unknown host key type:"), mask);
+            return FALSE;
+        }
+
+        rc = libssh2_session_method_pref (sftpfs_super->session, LIBSSH2_METHOD_HOSTKEY,
+                                          hostkey_method);
+        if (rc < 0)
+            goto err;
+    }
+
+    return TRUE;
+
+  err:
+    {
+        int sftp_errno;
+
+        sftp_errno = libssh2_session_last_errno (sftpfs_super->session);
+        sftpfs_ssherror_to_gliberror (sftpfs_super, sftp_errno, mcerror);
+    }
+    return FALSE;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+/**
+ * Write new host + key pair to the ~/.ssh/known_hosts file.
+ *
+ * @param super connection data
+ * @param remote_key he key for the remote host
+ * @param remote_key_len length of @remote_key
+ * @param type_mask info about format of host name, key and key type
+ * @return 0 on success, regular libssh2 error code otherwise
+ *
+ * Thanks the Curl project for the code used in this function.
+ */
+static int
+sftpfs_update_known_hosts (struct vfs_s_super *super, const char *remote_key, size_t remote_key_len,
+                           int type_mask)
+{
+    sftpfs_super_t *sftpfs_super = SFTP_SUPER (super);
+    int rc;
+
+    /* add this host + key pair  */
+    rc = libssh2_knownhost_addc (sftpfs_super->known_hosts, super->path_element->host, NULL,
+                                 remote_key, remote_key_len, NULL, 0, type_mask, NULL);
+    if (rc < 0)
+        return rc;
+
+    /* write the entire in-memory list of known hosts to the known_hosts file */
+    rc = libssh2_knownhost_writefile (sftpfs_super->known_hosts, sftpfs_super->known_hosts_file,
+                                      LIBSSH2_KNOWNHOST_FILE_OPENSSH);
+
+    if (rc < 0)
+        return rc;
+
+    (void) message (D_NORMAL, _("Information"),
+                    _("Permanently added\n%s (%s)\nto the list of known hosts."),
+                    super->path_element->host, sftpfs_super->ip_address);
+
+    return 0;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+/**
+ * Compute and return readable host key fingerprint hash.
+ *
+ * @param session libssh2 session handle
+ * @return pointer to static buffer on success, NULL otherwise
+ */
+static const char *
+sftpfs_compute_fingerprint_hash (LIBSSH2_SESSION * session)
+{
+    static char result[SHA1_DIGEST_LENGTH * 3 + 1];     /* "XX:" for each byte, and EOL */
+    const char *fingerprint;
+    size_t i;
+
+    /* The fingerprint points to static storage (!), don't free() it. */
+    fingerprint = libssh2_hostkey_hash (session, LIBSSH2_HOSTKEY_HASH_SHA1);
+    if (fingerprint == NULL)
+        return NULL;
+
+    for (i = 0; i < SHA1_DIGEST_LENGTH && i * 3 < sizeof (result) - 1; i++)
+        g_snprintf ((gchar *) (result + i * 3), 4, "%02x:", (guint8) fingerprint[i]);
+
+    /* remove last ":" */
+    result[i * 3 - 1] = '\0';
+
+    return result;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
 /**
- * Recognize authenticaion types supported by remote side and filling internal 'super' structure by
+ * Process host info found in ~/.ssh/known_hosts file.
+ *
+ * @param super connection data
+ * @param mcerror pointer to the error handler
+ * @return TRUE on success, FALSE otherwise
+ *
+ * Thanks the Curl project for the code used in this function.
+ */
+static gboolean
+sftpfs_process_known_host (struct vfs_s_super *super, GError ** mcerror)
+{
+    sftpfs_super_t *sftpfs_super = SFTP_SUPER (super);
+    const char *remote_key;
+    const char *key_type;
+    const char *fingerprint_hash;
+    size_t remote_key_len = 0;
+    int remote_key_type = LIBSSH2_HOSTKEY_TYPE_UNKNOWN;
+    int keybit = 0;
+    struct libssh2_knownhost *host = NULL;
+    int rc;
+    char *msg = NULL;
+    gboolean handle_query = FALSE;
+
+    remote_key = libssh2_session_hostkey (sftpfs_super->session, &remote_key_len, &remote_key_type);
+    if (remote_key == NULL || remote_key_len == 0
+        || remote_key_type == LIBSSH2_HOSTKEY_TYPE_UNKNOWN)
+    {
+        mc_propagate_error (mcerror, 0, "%s", _("sftp: cannot get the remote host key"));
+        return FALSE;
+    }
+
+    switch (remote_key_type)
+    {
+    case LIBSSH2_HOSTKEY_TYPE_RSA:
+        keybit = LIBSSH2_KNOWNHOST_KEY_SSHRSA;
+        key_type = "RSA";
+        break;
+    case LIBSSH2_HOSTKEY_TYPE_DSS:
+        keybit = LIBSSH2_KNOWNHOST_KEY_SSHDSS;
+        key_type = "DSS";
+        break;
+#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_256
+    case LIBSSH2_HOSTKEY_TYPE_ECDSA_256:
+        keybit = LIBSSH2_KNOWNHOST_KEY_ECDSA_256;
+        key_type = "ECDSA";
+        break;
+#endif
+#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_384
+    case LIBSSH2_HOSTKEY_TYPE_ECDSA_384:
+        keybit = LIBSSH2_KNOWNHOST_KEY_ECDSA_384;
+        key_type = "ECDSA";
+        break;
+#endif
+#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_521
+    case LIBSSH2_HOSTKEY_TYPE_ECDSA_521:
+        keybit = LIBSSH2_KNOWNHOST_KEY_ECDSA_521;
+        key_type = "ECDSA";
+        break;
+#endif
+#ifdef LIBSSH2_HOSTKEY_TYPE_ED25519
+    case LIBSSH2_HOSTKEY_TYPE_ED25519:
+        keybit = LIBSSH2_KNOWNHOST_KEY_ED25519;
+        key_type = "ED25519";
+        break;
+#endif
+    default:
+        mc_propagate_error (mcerror, 0, "%s",
+                            _("sftp: unsupported key type, can't check remote host key"));
+        return FALSE;
+    }
+
+    fingerprint_hash = sftpfs_compute_fingerprint_hash (sftpfs_super->session);
+    if (fingerprint_hash == NULL)
+    {
+        mc_propagate_error (mcerror, 0, "%s", _("sftp: can't compute host key fingerprint hash"));
+        return FALSE;
+    }
+
+    rc = libssh2_knownhost_checkp (sftpfs_super->known_hosts, super->path_element->host,
+                                   super->path_element->port, remote_key, remote_key_len,
+                                   LIBSSH2_KNOWNHOST_TYPE_PLAIN | LIBSSH2_KNOWNHOST_KEYENC_RAW |
+                                   keybit, &host);
+
+    switch (rc)
+    {
+    default:
+    case LIBSSH2_KNOWNHOST_CHECK_FAILURE:
+        /* something prevented the check to be made */
+        goto err;
+
+    case LIBSSH2_KNOWNHOST_CHECK_MATCH:
+        /* host + key pair matched -- OK */
+        break;
+
+    case LIBSSH2_KNOWNHOST_CHECK_NOTFOUND:
+        /* no host match was found -- add it to the known_hosts file */
+        msg = g_strdup_printf (_("The authenticity of host\n%s (%s)\ncan't be established!\n"
+                                 "%s key fingerprint hash is\nSHA1:%s.\n"
+                                 "Do you want to add it to the list of known hosts and continue connecting?"),
+                               super->path_element->host, sftpfs_super->ip_address,
+                               key_type, fingerprint_hash);
+        /* Select "No" initially */
+        query_set_sel (2);
+        rc = query_dialog (_("Warning"), msg, D_NORMAL, 3, _("&Yes"), _("&Ignore"), _("&No"));
+        g_free (msg);
+        handle_query = TRUE;
+        break;
+
+    case LIBSSH2_KNOWNHOST_CHECK_MISMATCH:
+        msg = g_strdup_printf (_("%s (%s)\nis found in the list of known hosts but\n"
+                                 "KEYS DO NOT MATCH! THIS COULD BE A MITM ATTACK!\n"
+                                 "Are you sure you want to add it to the list of known hosts and continue connecting?"),
+                               super->path_element->host, sftpfs_super->ip_address);
+        /* Select "No" initially */
+        query_set_sel (2);
+        rc = query_dialog (MSG_ERROR, msg, D_ERROR, 3, _("&Yes"), _("&Ignore"), _("&No"));
+        g_free (msg);
+        handle_query = TRUE;
+        break;
+    }
+
+    if (handle_query)
+        switch (rc)
+        {
+        case 0:
+            /* Yes: add this host + key pair, continue connecting */
+            if (sftpfs_update_known_hosts (super, remote_key, remote_key_len,
+                                           LIBSSH2_KNOWNHOST_TYPE_PLAIN
+                                           | LIBSSH2_KNOWNHOST_KEYENC_RAW | keybit) < 0)
+                goto err;
+            break;
+        case 1:
+            /* Ignore: do not add this host + key pair, continue connecting anyway */
+            break;
+        case 2:
+        default:
+            mc_propagate_error (mcerror, 0, "%s", _("sftp: host key verification failed"));
+            /* No: abort connection */
+            goto err;
+        }
+
+    return TRUE;
+
+  err:
+    {
+        int sftp_errno;
+
+        sftp_errno = libssh2_session_last_errno (sftpfs_super->session);
+        sftpfs_ssherror_to_gliberror (sftpfs_super, sftp_errno, mcerror);
+    }
+
+    return FALSE;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+/**
+ * Recognize authentication types supported by remote side and filling internal 'super' structure by
  * proper enum's values.
  *
  * @param super connection data
@@ -461,6 +867,9 @@ sftpfs_open_connection (struct vfs_s_super *super, GError ** mcerror)
     if (sftpfs_super->session == NULL)
         return (-1);
 
+    if (!sftpfs_read_known_hosts (super, mcerror))
+        return (-1);
+
     /* ... start it up. This will trade welcome banners, exchange keys,
      * and setup crypto, compression, and MAC layers
      */
@@ -475,13 +884,8 @@ sftpfs_open_connection (struct vfs_s_super *super, GError ** mcerror)
         return (-1);
     }
 
-    /* At this point we havn't yet authenticated.  The first thing to do
-     * is check the hostkey's fingerprint against our known hosts Your app
-     * may have it hard coded, may go to a file, may present it to the
-     * user, that's your call
-     */
-    sftpfs_super->fingerprint =
-        libssh2_hostkey_hash (sftpfs_super->session, LIBSSH2_HOSTKEY_HASH_SHA1);
+    if (!sftpfs_process_known_host (super, mcerror))
+        return (-1);
 
     if (!sftpfs_recognize_auth_types (super))
     {
@@ -538,7 +942,13 @@ sftpfs_close_connection (struct vfs_s_super *super, const char *shutdown_message
         sftpfs_super->agent = NULL;
     }
 
-    sftpfs_super->fingerprint = NULL;
+    if (sftpfs_super->known_hosts != NULL)
+    {
+        libssh2_knownhost_free (sftpfs_super->known_hosts);
+        sftpfs_super->known_hosts = NULL;
+    }
+
+    MC_PTR_FREE (sftpfs_super->known_hosts_file);
 
     if (sftpfs_super->session != NULL)
     {
diff --git a/src/vfs/sftpfs/internal.h b/src/vfs/sftpfs/internal.h
index 5616fb8990..643ce5e3cc 100644
--- a/src/vfs/sftpfs/internal.h
+++ b/src/vfs/sftpfs/internal.h
@@ -42,6 +42,9 @@ typedef struct
     sftpfs_auth_type_t auth_type;
     sftpfs_auth_type_t config_auth_type;
 
+    LIBSSH2_KNOWNHOSTS *known_hosts;
+    char *known_hosts_file;
+
     LIBSSH2_SESSION *session;
     LIBSSH2_SFTP *sftp_session;
 
@@ -51,7 +54,7 @@ typedef struct
     char *privkey;
 
     int socket_handle;
-    const char *fingerprint;
+    const char *ip_address;
     vfs_path_element_t *original_connection_info;
 } sftpfs_super_t;
 
