diff options
| -rw-r--r-- | meta/recipes-extended/mc/files/CVE-2021-36370.patch | 609 | ||||
| -rw-r--r-- | meta/recipes-extended/mc/mc_4.8.26.bb | 1 |
2 files changed, 610 insertions, 0 deletions
diff --git a/meta/recipes-extended/mc/files/CVE-2021-36370.patch b/meta/recipes-extended/mc/files/CVE-2021-36370.patch new file mode 100644 index 0000000000..d6a26871bd --- /dev/null +++ b/meta/recipes-extended/mc/files/CVE-2021-36370.patch | |||
| @@ -0,0 +1,609 @@ | |||
| 1 | Backport patch to fix CVE-2021-36370. | ||
| 2 | |||
| 3 | Upstream-Status: Backport [https://github.com/MidnightCommander/mc/commit/9235d3c] | ||
| 4 | CVE: CVE-2021-36370 | ||
| 5 | |||
| 6 | Signed-off-by: Kai Kang <kai.kang@windriver.com> | ||
| 7 | |||
| 8 | From 9235d3c232d13ad7f973346077c9cf2eaa77dc5f Mon Sep 17 00:00:00 2001 | ||
| 9 | From: Andrew Borodin <aborodin@vmail.ru> | ||
| 10 | Date: Mon, 12 Jul 2021 08:48:18 +0300 | ||
| 11 | Subject: [PATCH] SFTPFS: verify server fingerprint (fix CVE-2021-36370). | ||
| 12 | |||
| 13 | Use ~/.ssh/known_hosts file to verify server fingerprint | ||
| 14 | using ssh way: | ||
| 15 | |||
| 16 | $ ssh localhost | ||
| 17 | The authenticity of host 'localhost (127.0.0.1)' can't be established. | ||
| 18 | ED25519 key fingerprint is SHA256:FzqKTNTroFuNUj1wUzSeV2x/1lpcESnT0ZRCmq5H6o8. | ||
| 19 | Are you sure you want to continue connecting (yes/no)? no | ||
| 20 | ssh: Host key verification failed. | ||
| 21 | |||
| 22 | $ ssh localhost | ||
| 23 | The authenticity of host 'localhost (127.0.0.1)' can't be established. | ||
| 24 | ED25519 key fingerprint is SHA256:FzqKTNTroFuNUj1wUzSeV2x/1lpcESnT0ZRCmq5H6o8. | ||
| 25 | Are you sure you want to continue connecting (yes/no)? yes | ||
| 26 | Warning: Permanently added 'localhost' (ED25519) to the list of known hosts. | ||
| 27 | andrew@localhost's password: | ||
| 28 | |||
| 29 | Thanks the Curl project for the used code. | ||
| 30 | |||
| 31 | Signed-off-by: Andrew Borodin <aborodin@vmail.ru> | ||
| 32 | Signed-off-by: Yury V. Zaytsev <yury.zaytsev@moneymeets.com> | ||
| 33 | --- | ||
| 34 | doc/man/mc.1.in | 15 ++ | ||
| 35 | doc/man/ru/mc.1.in | 14 ++ | ||
| 36 | src/vfs/sftpfs/connection.c | 428 +++++++++++++++++++++++++++++++++++- | ||
| 37 | src/vfs/sftpfs/internal.h | 5 +- | ||
| 38 | 4 files changed, 452 insertions(+), 10 deletions(-) | ||
| 39 | |||
| 40 | diff --git a/doc/man/mc.1.in b/doc/man/mc.1.in | ||
| 41 | index c0c06e32f7..7a3d118384 100644 | ||
| 42 | --- a/doc/man/mc.1.in | ||
| 43 | +++ b/doc/man/mc.1.in | ||
| 44 | @@ -3364,6 +3364,21 @@ Examples: | ||
| 45 | sftp://joe@noncompressed.ssh.edu/private | ||
| 46 | sftp://joe@somehost.ssh.edu:2222/private | ||
| 47 | .fi | ||
| 48 | +.PP | ||
| 49 | +When establishing the connection, server key fingerprint is verified using | ||
| 50 | +the ~/.ssh/known_hosts file. If the host/key pair is not found or the host is found, | ||
| 51 | +but the key doesn't match, an appropriate message is shown. | ||
| 52 | +There are three buttons in the message dialog: | ||
| 53 | +.PP | ||
| 54 | +.B [Yes] | ||
| 55 | +add new host/key pair to the ~/.ssh/known_hosts file and continue. | ||
| 56 | +.PP | ||
| 57 | +.B [Ignore] | ||
| 58 | +do not add new host/key pair to the ~/.ssh/known_hosts file, but continue | ||
| 59 | +nevertheless (at you own risk). | ||
| 60 | +.PP | ||
| 61 | +.B [No] | ||
| 62 | +abort connection. | ||
| 63 | .\"NODE " Undelete File System" | ||
| 64 | .SH " Undelete File System" | ||
| 65 | On Linux systems, if you asked configure to use the ext2fs undelete | ||
| 66 | diff --git a/doc/man/ru/mc.1.in b/doc/man/ru/mc.1.in | ||
| 67 | index 7609da1127..bc0c1810a9 100644 | ||
| 68 | --- a/doc/man/ru/mc.1.in | ||
| 69 | +++ b/doc/man/ru/mc.1.in | ||
| 70 | @@ -3874,6 +3874,20 @@ bash\-совместимая оболочка shell. | ||
| 71 | sftp://joe@noncompressed.ssh.edu/private | ||
| 72 | sftp://joe@somehost.ssh.edu:2222/private | ||
| 73 | .fi | ||
| 74 | +При установлении соединения происходит проверка ключа сервера с использованием | ||
| 75 | +файла ~/.ssh/known_hosts file. Если пара сервер/ключ в этом файле не найдена | ||
| 76 | +или сервер найден, но ключ не соответствует, пользователю показывается | ||
| 77 | +окно с соответствующим сообщением, содержащее три кнопки: | ||
| 78 | +.PP | ||
| 79 | +.B [Да] | ||
| 80 | +добавить новую пару сервер/ключ в файл ~/.ssh/known_hosts и продолжить соединение. | ||
| 81 | +.PP | ||
| 82 | +.B [Игнорировать] | ||
| 83 | +не добавлять новую пару сервер/ключ в файл ~/.ssh/known_hosts и всё равно | ||
| 84 | +продолжить соединение (на свой страх и риск). | ||
| 85 | +.PP | ||
| 86 | +.B [Нет] | ||
| 87 | +прервать соединение. | ||
| 88 | .\"NODE " Undelete File System" | ||
| 89 | .SH " Файловая система UFS (Undelete File System)" | ||
| 90 | В ОС Linux можно сконфигурировать файловую систему ext2fs, используемую | ||
| 91 | diff --git a/src/vfs/sftpfs/connection.c b/src/vfs/sftpfs/connection.c | ||
| 92 | index 9f8ea5633b..acd5026515 100644 | ||
| 93 | --- a/src/vfs/sftpfs/connection.c | ||
| 94 | +++ b/src/vfs/sftpfs/connection.c | ||
| 95 | @@ -42,6 +42,8 @@ | ||
| 96 | #include "lib/util.h" | ||
| 97 | #include "lib/tty/tty.h" /* tty_enable_interrupt_key () */ | ||
| 98 | #include "lib/vfs/utilvfs.h" | ||
| 99 | +#include "lib/mcconfig.h" /* mc_config_get_home_dir () */ | ||
| 100 | +#include "lib/widget.h" /* query_dialog () */ | ||
| 101 | |||
| 102 | #include "internal.h" | ||
| 103 | |||
| 104 | @@ -49,10 +51,37 @@ | ||
| 105 | |||
| 106 | /*** file scope macro definitions ****************************************************************/ | ||
| 107 | |||
| 108 | +#define SHA1_DIGEST_LENGTH 20 | ||
| 109 | + | ||
| 110 | /*** file scope type declarations ****************************************************************/ | ||
| 111 | |||
| 112 | /*** file scope variables ************************************************************************/ | ||
| 113 | |||
| 114 | +#ifdef LIBSSH2_KNOWNHOST_KEY_ED25519 | ||
| 115 | +static const char *const hostkey_method_ssh_ed25519 = "ssh-ed25519"; | ||
| 116 | +#endif | ||
| 117 | +#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_521 | ||
| 118 | +static const char *const hostkey_method_ssh_ecdsa_521 = "ecdsa-sha2-nistp521"; | ||
| 119 | +#endif | ||
| 120 | +#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_384 | ||
| 121 | +static const char *const hostkey_method_ssh_ecdsa_384 = "ecdsa-sha2-nistp384"; | ||
| 122 | +#endif | ||
| 123 | +#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_256 | ||
| 124 | +static const char *const hostkey_method_ssh_ecdsa_256 = "ecdsa-sha2-nistp256"; | ||
| 125 | +#endif | ||
| 126 | +static const char *const hostkey_method_ssh_rsa = "ssh-rsa"; | ||
| 127 | +static const char *const hostkey_method_ssh_dss = "ssh-dss"; | ||
| 128 | + | ||
| 129 | +/** | ||
| 130 | + * | ||
| 131 | + * The current implementation of know host key checking has following limitations: | ||
| 132 | + * | ||
| 133 | + * - Only plain-text entries are supported (`HashKnownHosts no` OpenSSH option) | ||
| 134 | + * - Only HEX-encoded SHA1 fingerprint display is supported (`FingerprintHash` OpenSSH option) | ||
| 135 | + * - Resolved IP addresses are *not* saved/validated along with the hostnames | ||
| 136 | + * | ||
| 137 | + */ | ||
| 138 | + | ||
| 139 | static const char *kbi_passwd = NULL; | ||
| 140 | static const struct vfs_s_super *kbi_super = NULL; | ||
| 141 | |||
| 142 | @@ -70,9 +99,12 @@ static const struct vfs_s_super *kbi_super = NULL; | ||
| 143 | static int | ||
| 144 | sftpfs_open_socket (struct vfs_s_super *super, GError ** mcerror) | ||
| 145 | { | ||
| 146 | + sftpfs_super_t *sftpfs_super = SFTP_SUPER (super); | ||
| 147 | struct addrinfo hints, *res = NULL, *curr_res; | ||
| 148 | int my_socket = 0; | ||
| 149 | char port[BUF_TINY]; | ||
| 150 | + static char address_ipv4[INET_ADDRSTRLEN]; | ||
| 151 | + static char address_ipv6[INET6_ADDRSTRLEN]; | ||
| 152 | int e; | ||
| 153 | |||
| 154 | mc_return_val_if_error (mcerror, LIBSSH2_INVALID_SOCKET); | ||
| 155 | @@ -120,6 +152,30 @@ sftpfs_open_socket (struct vfs_s_super *super, GError ** mcerror) | ||
| 156 | { | ||
| 157 | int save_errno; | ||
| 158 | |||
| 159 | + switch (curr_res->ai_addr->sa_family) | ||
| 160 | + { | ||
| 161 | + case AF_INET: | ||
| 162 | + sftpfs_super->ip_address = | ||
| 163 | + inet_ntop (AF_INET, &((struct sockaddr_in *) curr_res->ai_addr)->sin_addr, | ||
| 164 | + address_ipv4, INET_ADDRSTRLEN); | ||
| 165 | + break; | ||
| 166 | + case AF_INET6: | ||
| 167 | + sftpfs_super->ip_address = | ||
| 168 | + inet_ntop (AF_INET6, &((struct sockaddr_in6 *) curr_res->ai_addr)->sin6_addr, | ||
| 169 | + address_ipv6, INET6_ADDRSTRLEN); | ||
| 170 | + break; | ||
| 171 | + default: | ||
| 172 | + sftpfs_super->ip_address = NULL; | ||
| 173 | + } | ||
| 174 | + | ||
| 175 | + if (sftpfs_super->ip_address == NULL) | ||
| 176 | + { | ||
| 177 | + mc_propagate_error (mcerror, 0, "%s", | ||
| 178 | + _("sftp: failed to convert remote host IP address into text form")); | ||
| 179 | + my_socket = LIBSSH2_INVALID_SOCKET; | ||
| 180 | + goto ret; | ||
| 181 | + } | ||
| 182 | + | ||
| 183 | my_socket = socket (curr_res->ai_family, curr_res->ai_socktype, curr_res->ai_protocol); | ||
| 184 | |||
| 185 | if (my_socket < 0) | ||
| 186 | @@ -161,8 +217,358 @@ sftpfs_open_socket (struct vfs_s_super *super, GError ** mcerror) | ||
| 187 | } | ||
| 188 | |||
| 189 | /* --------------------------------------------------------------------------------------------- */ | ||
| 190 | + | ||
| 191 | +/** | ||
| 192 | + * Read ~/.ssh/known_hosts file. | ||
| 193 | + * | ||
| 194 | + * @param super connection data | ||
| 195 | + * @param mcerror pointer to the error handler | ||
| 196 | + * @return TRUE on success, FALSE otherwise | ||
| 197 | + * | ||
| 198 | + * Thanks the Curl project for the code used in this function. | ||
| 199 | + */ | ||
| 200 | +static gboolean | ||
| 201 | +sftpfs_read_known_hosts (struct vfs_s_super *super, GError ** mcerror) | ||
| 202 | +{ | ||
| 203 | + sftpfs_super_t *sftpfs_super = SFTP_SUPER (super); | ||
| 204 | + struct libssh2_knownhost *store = NULL; | ||
| 205 | + int rc; | ||
| 206 | + gboolean found = FALSE; | ||
| 207 | + | ||
| 208 | + sftpfs_super->known_hosts = libssh2_knownhost_init (sftpfs_super->session); | ||
| 209 | + if (sftpfs_super->known_hosts == NULL) | ||
| 210 | + goto err; | ||
| 211 | + | ||
| 212 | + sftpfs_super->known_hosts_file = | ||
| 213 | + mc_build_filename (mc_config_get_home_dir (), ".ssh", "known_hosts", (char *) NULL); | ||
| 214 | + rc = libssh2_knownhost_readfile (sftpfs_super->known_hosts, sftpfs_super->known_hosts_file, | ||
| 215 | + LIBSSH2_KNOWNHOST_FILE_OPENSSH); | ||
| 216 | + if (rc > 0) | ||
| 217 | + { | ||
| 218 | + const char *kh_name_end = NULL; | ||
| 219 | + | ||
| 220 | + while (!found && libssh2_knownhost_get (sftpfs_super->known_hosts, &store, store) == 0) | ||
| 221 | + { | ||
| 222 | + /* For non-standard ports, the name will be enclosed in | ||
| 223 | + * square brackets, followed by a colon and the port */ | ||
| 224 | + if (store == NULL) | ||
| 225 | + continue; | ||
| 226 | + | ||
| 227 | + if (store->name == NULL) | ||
| 228 | + found = TRUE; | ||
| 229 | + else if (store->name[0] != '[') | ||
| 230 | + found = strcmp (store->name, super->path_element->host) == 0; | ||
| 231 | + else | ||
| 232 | + { | ||
| 233 | + int port; | ||
| 234 | + | ||
| 235 | + kh_name_end = strstr (store->name, "]:"); | ||
| 236 | + if (kh_name_end == NULL) | ||
| 237 | + /* Invalid host pattern */ | ||
| 238 | + continue; | ||
| 239 | + | ||
| 240 | + port = (int) g_ascii_strtoll (kh_name_end + 2, NULL, 10); | ||
| 241 | + if (port == super->path_element->port) | ||
| 242 | + { | ||
| 243 | + size_t kh_name_size; | ||
| 244 | + | ||
| 245 | + kh_name_size = strlen (store->name) - 1 - strlen (kh_name_end); | ||
| 246 | + found = strncmp (store->name + 1, super->path_element->host, kh_name_size) == 0; | ||
| 247 | + } | ||
| 248 | + } | ||
| 249 | + } | ||
| 250 | + } | ||
| 251 | + | ||
| 252 | + if (found) | ||
| 253 | + { | ||
| 254 | + int mask; | ||
| 255 | + const char *hostkey_method = NULL; | ||
| 256 | + | ||
| 257 | + mask = store->typemask & LIBSSH2_KNOWNHOST_KEY_MASK; | ||
| 258 | + | ||
| 259 | + switch (mask) | ||
| 260 | + { | ||
| 261 | +#ifdef LIBSSH2_KNOWNHOST_KEY_ED25519 | ||
| 262 | + case LIBSSH2_KNOWNHOST_KEY_ED25519: | ||
| 263 | + hostkey_method = hostkey_method_ssh_ed25519; | ||
| 264 | + break; | ||
| 265 | +#endif | ||
| 266 | +#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_521 | ||
| 267 | + case LIBSSH2_KNOWNHOST_KEY_ECDSA_521: | ||
| 268 | + hostkey_method = hostkey_method_ssh_ecdsa_521; | ||
| 269 | + break; | ||
| 270 | +#endif | ||
| 271 | +#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_384 | ||
| 272 | + case LIBSSH2_KNOWNHOST_KEY_ECDSA_384: | ||
| 273 | + hostkey_method = hostkey_method_ssh_ecdsa_384; | ||
| 274 | + break; | ||
| 275 | +#endif | ||
| 276 | +#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_256 | ||
| 277 | + case LIBSSH2_KNOWNHOST_KEY_ECDSA_256: | ||
| 278 | + hostkey_method = hostkey_method_ssh_ecdsa_256; | ||
| 279 | + break; | ||
| 280 | +#endif | ||
| 281 | + case LIBSSH2_KNOWNHOST_KEY_SSHRSA: | ||
| 282 | + hostkey_method = hostkey_method_ssh_rsa; | ||
| 283 | + break; | ||
| 284 | + case LIBSSH2_KNOWNHOST_KEY_SSHDSS: | ||
| 285 | + hostkey_method = hostkey_method_ssh_dss; | ||
| 286 | + break; | ||
| 287 | + case LIBSSH2_KNOWNHOST_KEY_RSA1: | ||
| 288 | + mc_propagate_error (mcerror, 0, "%s", | ||
| 289 | + _("sftp: found host key of unsupported type: RSA1")); | ||
| 290 | + return FALSE; | ||
| 291 | + default: | ||
| 292 | + mc_propagate_error (mcerror, 0, "%s %d", _("sftp: unknown host key type:"), mask); | ||
| 293 | + return FALSE; | ||
| 294 | + } | ||
| 295 | + | ||
| 296 | + rc = libssh2_session_method_pref (sftpfs_super->session, LIBSSH2_METHOD_HOSTKEY, | ||
| 297 | + hostkey_method); | ||
| 298 | + if (rc < 0) | ||
| 299 | + goto err; | ||
| 300 | + } | ||
| 301 | + | ||
| 302 | + return TRUE; | ||
| 303 | + | ||
| 304 | + err: | ||
| 305 | + { | ||
| 306 | + int sftp_errno; | ||
| 307 | + | ||
| 308 | + sftp_errno = libssh2_session_last_errno (sftpfs_super->session); | ||
| 309 | + sftpfs_ssherror_to_gliberror (sftpfs_super, sftp_errno, mcerror); | ||
| 310 | + } | ||
| 311 | + return FALSE; | ||
| 312 | +} | ||
| 313 | + | ||
| 314 | +/* --------------------------------------------------------------------------------------------- */ | ||
| 315 | + | ||
| 316 | +/** | ||
| 317 | + * Write new host + key pair to the ~/.ssh/known_hosts file. | ||
| 318 | + * | ||
| 319 | + * @param super connection data | ||
| 320 | + * @param remote_key he key for the remote host | ||
| 321 | + * @param remote_key_len length of @remote_key | ||
| 322 | + * @param type_mask info about format of host name, key and key type | ||
| 323 | + * @return 0 on success, regular libssh2 error code otherwise | ||
| 324 | + * | ||
| 325 | + * Thanks the Curl project for the code used in this function. | ||
| 326 | + */ | ||
| 327 | +static int | ||
| 328 | +sftpfs_update_known_hosts (struct vfs_s_super *super, const char *remote_key, size_t remote_key_len, | ||
| 329 | + int type_mask) | ||
| 330 | +{ | ||
| 331 | + sftpfs_super_t *sftpfs_super = SFTP_SUPER (super); | ||
| 332 | + int rc; | ||
| 333 | + | ||
| 334 | + /* add this host + key pair */ | ||
| 335 | + rc = libssh2_knownhost_addc (sftpfs_super->known_hosts, super->path_element->host, NULL, | ||
| 336 | + remote_key, remote_key_len, NULL, 0, type_mask, NULL); | ||
| 337 | + if (rc < 0) | ||
| 338 | + return rc; | ||
| 339 | + | ||
| 340 | + /* write the entire in-memory list of known hosts to the known_hosts file */ | ||
| 341 | + rc = libssh2_knownhost_writefile (sftpfs_super->known_hosts, sftpfs_super->known_hosts_file, | ||
| 342 | + LIBSSH2_KNOWNHOST_FILE_OPENSSH); | ||
| 343 | + | ||
| 344 | + if (rc < 0) | ||
| 345 | + return rc; | ||
| 346 | + | ||
| 347 | + (void) message (D_NORMAL, _("Information"), | ||
| 348 | + _("Permanently added\n%s (%s)\nto the list of known hosts."), | ||
| 349 | + super->path_element->host, sftpfs_super->ip_address); | ||
| 350 | + | ||
| 351 | + return 0; | ||
| 352 | +} | ||
| 353 | + | ||
| 354 | +/* --------------------------------------------------------------------------------------------- */ | ||
| 355 | +/** | ||
| 356 | + * Compute and return readable host key fingerprint hash. | ||
| 357 | + * | ||
| 358 | + * @param session libssh2 session handle | ||
| 359 | + * @return pointer to static buffer on success, NULL otherwise | ||
| 360 | + */ | ||
| 361 | +static const char * | ||
| 362 | +sftpfs_compute_fingerprint_hash (LIBSSH2_SESSION * session) | ||
| 363 | +{ | ||
| 364 | + static char result[SHA1_DIGEST_LENGTH * 3 + 1]; /* "XX:" for each byte, and EOL */ | ||
| 365 | + const char *fingerprint; | ||
| 366 | + size_t i; | ||
| 367 | + | ||
| 368 | + /* The fingerprint points to static storage (!), don't free() it. */ | ||
| 369 | + fingerprint = libssh2_hostkey_hash (session, LIBSSH2_HOSTKEY_HASH_SHA1); | ||
| 370 | + if (fingerprint == NULL) | ||
| 371 | + return NULL; | ||
| 372 | + | ||
| 373 | + for (i = 0; i < SHA1_DIGEST_LENGTH && i * 3 < sizeof (result) - 1; i++) | ||
| 374 | + g_snprintf ((gchar *) (result + i * 3), 4, "%02x:", (guint8) fingerprint[i]); | ||
| 375 | + | ||
| 376 | + /* remove last ":" */ | ||
| 377 | + result[i * 3 - 1] = '\0'; | ||
| 378 | + | ||
| 379 | + return result; | ||
| 380 | +} | ||
| 381 | + | ||
| 382 | +/* --------------------------------------------------------------------------------------------- */ | ||
| 383 | + | ||
| 384 | /** | ||
| 385 | - * Recognize authenticaion types supported by remote side and filling internal 'super' structure by | ||
| 386 | + * Process host info found in ~/.ssh/known_hosts file. | ||
| 387 | + * | ||
| 388 | + * @param super connection data | ||
| 389 | + * @param mcerror pointer to the error handler | ||
| 390 | + * @return TRUE on success, FALSE otherwise | ||
| 391 | + * | ||
| 392 | + * Thanks the Curl project for the code used in this function. | ||
| 393 | + */ | ||
| 394 | +static gboolean | ||
| 395 | +sftpfs_process_known_host (struct vfs_s_super *super, GError ** mcerror) | ||
| 396 | +{ | ||
| 397 | + sftpfs_super_t *sftpfs_super = SFTP_SUPER (super); | ||
| 398 | + const char *remote_key; | ||
| 399 | + const char *key_type; | ||
| 400 | + const char *fingerprint_hash; | ||
| 401 | + size_t remote_key_len = 0; | ||
| 402 | + int remote_key_type = LIBSSH2_HOSTKEY_TYPE_UNKNOWN; | ||
| 403 | + int keybit = 0; | ||
| 404 | + struct libssh2_knownhost *host = NULL; | ||
| 405 | + int rc; | ||
| 406 | + char *msg = NULL; | ||
| 407 | + gboolean handle_query = FALSE; | ||
| 408 | + | ||
| 409 | + remote_key = libssh2_session_hostkey (sftpfs_super->session, &remote_key_len, &remote_key_type); | ||
| 410 | + if (remote_key == NULL || remote_key_len == 0 | ||
| 411 | + || remote_key_type == LIBSSH2_HOSTKEY_TYPE_UNKNOWN) | ||
| 412 | + { | ||
| 413 | + mc_propagate_error (mcerror, 0, "%s", _("sftp: cannot get the remote host key")); | ||
| 414 | + return FALSE; | ||
| 415 | + } | ||
| 416 | + | ||
| 417 | + switch (remote_key_type) | ||
| 418 | + { | ||
| 419 | + case LIBSSH2_HOSTKEY_TYPE_RSA: | ||
| 420 | + keybit = LIBSSH2_KNOWNHOST_KEY_SSHRSA; | ||
| 421 | + key_type = "RSA"; | ||
| 422 | + break; | ||
| 423 | + case LIBSSH2_HOSTKEY_TYPE_DSS: | ||
| 424 | + keybit = LIBSSH2_KNOWNHOST_KEY_SSHDSS; | ||
| 425 | + key_type = "DSS"; | ||
| 426 | + break; | ||
| 427 | +#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_256 | ||
| 428 | + case LIBSSH2_HOSTKEY_TYPE_ECDSA_256: | ||
| 429 | + keybit = LIBSSH2_KNOWNHOST_KEY_ECDSA_256; | ||
| 430 | + key_type = "ECDSA"; | ||
| 431 | + break; | ||
| 432 | +#endif | ||
| 433 | +#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_384 | ||
| 434 | + case LIBSSH2_HOSTKEY_TYPE_ECDSA_384: | ||
| 435 | + keybit = LIBSSH2_KNOWNHOST_KEY_ECDSA_384; | ||
| 436 | + key_type = "ECDSA"; | ||
| 437 | + break; | ||
| 438 | +#endif | ||
| 439 | +#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_521 | ||
| 440 | + case LIBSSH2_HOSTKEY_TYPE_ECDSA_521: | ||
| 441 | + keybit = LIBSSH2_KNOWNHOST_KEY_ECDSA_521; | ||
| 442 | + key_type = "ECDSA"; | ||
| 443 | + break; | ||
| 444 | +#endif | ||
| 445 | +#ifdef LIBSSH2_HOSTKEY_TYPE_ED25519 | ||
| 446 | + case LIBSSH2_HOSTKEY_TYPE_ED25519: | ||
| 447 | + keybit = LIBSSH2_KNOWNHOST_KEY_ED25519; | ||
| 448 | + key_type = "ED25519"; | ||
| 449 | + break; | ||
| 450 | +#endif | ||
| 451 | + default: | ||
| 452 | + mc_propagate_error (mcerror, 0, "%s", | ||
| 453 | + _("sftp: unsupported key type, can't check remote host key")); | ||
| 454 | + return FALSE; | ||
| 455 | + } | ||
| 456 | + | ||
| 457 | + fingerprint_hash = sftpfs_compute_fingerprint_hash (sftpfs_super->session); | ||
| 458 | + if (fingerprint_hash == NULL) | ||
| 459 | + { | ||
| 460 | + mc_propagate_error (mcerror, 0, "%s", _("sftp: can't compute host key fingerprint hash")); | ||
| 461 | + return FALSE; | ||
| 462 | + } | ||
| 463 | + | ||
| 464 | + rc = libssh2_knownhost_checkp (sftpfs_super->known_hosts, super->path_element->host, | ||
| 465 | + super->path_element->port, remote_key, remote_key_len, | ||
| 466 | + LIBSSH2_KNOWNHOST_TYPE_PLAIN | LIBSSH2_KNOWNHOST_KEYENC_RAW | | ||
| 467 | + keybit, &host); | ||
| 468 | + | ||
| 469 | + switch (rc) | ||
| 470 | + { | ||
| 471 | + default: | ||
| 472 | + case LIBSSH2_KNOWNHOST_CHECK_FAILURE: | ||
| 473 | + /* something prevented the check to be made */ | ||
| 474 | + goto err; | ||
| 475 | + | ||
| 476 | + case LIBSSH2_KNOWNHOST_CHECK_MATCH: | ||
| 477 | + /* host + key pair matched -- OK */ | ||
| 478 | + break; | ||
| 479 | + | ||
| 480 | + case LIBSSH2_KNOWNHOST_CHECK_NOTFOUND: | ||
| 481 | + /* no host match was found -- add it to the known_hosts file */ | ||
| 482 | + msg = g_strdup_printf (_("The authenticity of host\n%s (%s)\ncan't be established!\n" | ||
| 483 | + "%s key fingerprint hash is\nSHA1:%s.\n" | ||
| 484 | + "Do you want to add it to the list of known hosts and continue connecting?"), | ||
| 485 | + super->path_element->host, sftpfs_super->ip_address, | ||
| 486 | + key_type, fingerprint_hash); | ||
| 487 | + /* Select "No" initially */ | ||
| 488 | + query_set_sel (2); | ||
| 489 | + rc = query_dialog (_("Warning"), msg, D_NORMAL, 3, _("&Yes"), _("&Ignore"), _("&No")); | ||
| 490 | + g_free (msg); | ||
| 491 | + handle_query = TRUE; | ||
| 492 | + break; | ||
| 493 | + | ||
| 494 | + case LIBSSH2_KNOWNHOST_CHECK_MISMATCH: | ||
| 495 | + msg = g_strdup_printf (_("%s (%s)\nis found in the list of known hosts but\n" | ||
| 496 | + "KEYS DO NOT MATCH! THIS COULD BE A MITM ATTACK!\n" | ||
| 497 | + "Are you sure you want to add it to the list of known hosts and continue connecting?"), | ||
| 498 | + super->path_element->host, sftpfs_super->ip_address); | ||
| 499 | + /* Select "No" initially */ | ||
| 500 | + query_set_sel (2); | ||
| 501 | + rc = query_dialog (MSG_ERROR, msg, D_ERROR, 3, _("&Yes"), _("&Ignore"), _("&No")); | ||
| 502 | + g_free (msg); | ||
| 503 | + handle_query = TRUE; | ||
| 504 | + break; | ||
| 505 | + } | ||
| 506 | + | ||
| 507 | + if (handle_query) | ||
| 508 | + switch (rc) | ||
| 509 | + { | ||
| 510 | + case 0: | ||
| 511 | + /* Yes: add this host + key pair, continue connecting */ | ||
| 512 | + if (sftpfs_update_known_hosts (super, remote_key, remote_key_len, | ||
| 513 | + LIBSSH2_KNOWNHOST_TYPE_PLAIN | ||
| 514 | + | LIBSSH2_KNOWNHOST_KEYENC_RAW | keybit) < 0) | ||
| 515 | + goto err; | ||
| 516 | + break; | ||
| 517 | + case 1: | ||
| 518 | + /* Ignore: do not add this host + key pair, continue connecting anyway */ | ||
| 519 | + break; | ||
| 520 | + case 2: | ||
| 521 | + default: | ||
| 522 | + mc_propagate_error (mcerror, 0, "%s", _("sftp: host key verification failed")); | ||
| 523 | + /* No: abort connection */ | ||
| 524 | + goto err; | ||
| 525 | + } | ||
| 526 | + | ||
| 527 | + return TRUE; | ||
| 528 | + | ||
| 529 | + err: | ||
| 530 | + { | ||
| 531 | + int sftp_errno; | ||
| 532 | + | ||
| 533 | + sftp_errno = libssh2_session_last_errno (sftpfs_super->session); | ||
| 534 | + sftpfs_ssherror_to_gliberror (sftpfs_super, sftp_errno, mcerror); | ||
| 535 | + } | ||
| 536 | + | ||
| 537 | + return FALSE; | ||
| 538 | +} | ||
| 539 | + | ||
| 540 | +/* --------------------------------------------------------------------------------------------- */ | ||
| 541 | +/** | ||
| 542 | + * Recognize authentication types supported by remote side and filling internal 'super' structure by | ||
| 543 | * proper enum's values. | ||
| 544 | * | ||
| 545 | * @param super connection data | ||
| 546 | @@ -461,6 +867,9 @@ sftpfs_open_connection (struct vfs_s_super *super, GError ** mcerror) | ||
| 547 | if (sftpfs_super->session == NULL) | ||
| 548 | return (-1); | ||
| 549 | |||
| 550 | + if (!sftpfs_read_known_hosts (super, mcerror)) | ||
| 551 | + return (-1); | ||
| 552 | + | ||
| 553 | /* ... start it up. This will trade welcome banners, exchange keys, | ||
| 554 | * and setup crypto, compression, and MAC layers | ||
| 555 | */ | ||
| 556 | @@ -475,13 +884,8 @@ sftpfs_open_connection (struct vfs_s_super *super, GError ** mcerror) | ||
| 557 | return (-1); | ||
| 558 | } | ||
| 559 | |||
| 560 | - /* At this point we havn't yet authenticated. The first thing to do | ||
| 561 | - * is check the hostkey's fingerprint against our known hosts Your app | ||
| 562 | - * may have it hard coded, may go to a file, may present it to the | ||
| 563 | - * user, that's your call | ||
| 564 | - */ | ||
| 565 | - sftpfs_super->fingerprint = | ||
| 566 | - libssh2_hostkey_hash (sftpfs_super->session, LIBSSH2_HOSTKEY_HASH_SHA1); | ||
| 567 | + if (!sftpfs_process_known_host (super, mcerror)) | ||
| 568 | + return (-1); | ||
| 569 | |||
| 570 | if (!sftpfs_recognize_auth_types (super)) | ||
| 571 | { | ||
| 572 | @@ -538,7 +942,13 @@ sftpfs_close_connection (struct vfs_s_super *super, const char *shutdown_message | ||
| 573 | sftpfs_super->agent = NULL; | ||
| 574 | } | ||
| 575 | |||
| 576 | - sftpfs_super->fingerprint = NULL; | ||
| 577 | + if (sftpfs_super->known_hosts != NULL) | ||
| 578 | + { | ||
| 579 | + libssh2_knownhost_free (sftpfs_super->known_hosts); | ||
| 580 | + sftpfs_super->known_hosts = NULL; | ||
| 581 | + } | ||
| 582 | + | ||
| 583 | + MC_PTR_FREE (sftpfs_super->known_hosts_file); | ||
| 584 | |||
| 585 | if (sftpfs_super->session != NULL) | ||
| 586 | { | ||
| 587 | diff --git a/src/vfs/sftpfs/internal.h b/src/vfs/sftpfs/internal.h | ||
| 588 | index 5616fb8990..643ce5e3cc 100644 | ||
| 589 | --- a/src/vfs/sftpfs/internal.h | ||
| 590 | +++ b/src/vfs/sftpfs/internal.h | ||
| 591 | @@ -42,6 +42,9 @@ typedef struct | ||
| 592 | sftpfs_auth_type_t auth_type; | ||
| 593 | sftpfs_auth_type_t config_auth_type; | ||
| 594 | |||
| 595 | + LIBSSH2_KNOWNHOSTS *known_hosts; | ||
| 596 | + char *known_hosts_file; | ||
| 597 | + | ||
| 598 | LIBSSH2_SESSION *session; | ||
| 599 | LIBSSH2_SFTP *sftp_session; | ||
| 600 | |||
| 601 | @@ -51,7 +54,7 @@ typedef struct | ||
| 602 | char *privkey; | ||
| 603 | |||
| 604 | int socket_handle; | ||
| 605 | - const char *fingerprint; | ||
| 606 | + const char *ip_address; | ||
| 607 | vfs_path_element_t *original_connection_info; | ||
| 608 | } sftpfs_super_t; | ||
| 609 | |||
diff --git a/meta/recipes-extended/mc/mc_4.8.26.bb b/meta/recipes-extended/mc/mc_4.8.26.bb index 5c5e6790d8..6bc7e6e8e1 100644 --- a/meta/recipes-extended/mc/mc_4.8.26.bb +++ b/meta/recipes-extended/mc/mc_4.8.26.bb | |||
| @@ -11,6 +11,7 @@ RRECOMMENDS_${PN} = "ncurses-terminfo" | |||
| 11 | SRC_URI = "http://www.midnight-commander.org/downloads/${BPN}-${PV}.tar.bz2 \ | 11 | SRC_URI = "http://www.midnight-commander.org/downloads/${BPN}-${PV}.tar.bz2 \ |
| 12 | file://0001-mc-replace-perl-w-with-use-warnings.patch \ | 12 | file://0001-mc-replace-perl-w-with-use-warnings.patch \ |
| 13 | file://nomandate.patch \ | 13 | file://nomandate.patch \ |
| 14 | file://CVE-2021-36370.patch \ | ||
| 14 | " | 15 | " |
| 15 | SRC_URI[sha256sum] = "9d6358d0a351a455a1410aab57f33b6b48b0fcf31344b9a10b0ff497595979d1" | 16 | SRC_URI[sha256sum] = "9d6358d0a351a455a1410aab57f33b6b48b0fcf31344b9a10b0ff497595979d1" |
| 16 | 17 | ||
