summaryrefslogtreecommitdiff
path: root/sshconnect.c
diff options
context:
space:
mode:
Diffstat (limited to 'sshconnect.c')
-rw-r--r--sshconnect.c197
1 files changed, 158 insertions, 39 deletions
diff --git a/sshconnect.c b/sshconnect.c
index 3280b310d..15d8b807e 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sshconnect.c,v 1.287 2017/09/14 04:32:21 djm Exp $ */ 1/* $OpenBSD: sshconnect.c,v 1.297 2018/02/23 15:58:38 markus Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -23,6 +23,7 @@
23# include <sys/time.h> 23# include <sys/time.h>
24#endif 24#endif
25 25
26#include <net/if.h>
26#include <netinet/in.h> 27#include <netinet/in.h>
27#include <arpa/inet.h> 28#include <arpa/inet.h>
28 29
@@ -43,6 +44,9 @@
43#include <stdlib.h> 44#include <stdlib.h>
44#include <string.h> 45#include <string.h>
45#include <unistd.h> 46#include <unistd.h>
47#ifdef HAVE_IFADDRS_H
48# include <ifaddrs.h>
49#endif
46 50
47#include "xmalloc.h" 51#include "xmalloc.h"
48#include "key.h" 52#include "key.h"
@@ -270,14 +274,83 @@ ssh_kill_proxy_command(void)
270 kill(proxy_command_pid, SIGHUP); 274 kill(proxy_command_pid, SIGHUP);
271} 275}
272 276
277#ifdef HAVE_IFADDRS_H
278/*
279 * Search a interface address list (returned from getifaddrs(3)) for an
280 * address that matches the desired address family on the specifed interface.
281 * Returns 0 and fills in *resultp and *rlenp on success. Returns -1 on failure.
282 */
283static int
284check_ifaddrs(const char *ifname, int af, const struct ifaddrs *ifaddrs,
285 struct sockaddr_storage *resultp, socklen_t *rlenp)
286{
287 struct sockaddr_in6 *sa6;
288 struct sockaddr_in *sa;
289 struct in6_addr *v6addr;
290 const struct ifaddrs *ifa;
291 int allow_local;
292
293 /*
294 * Prefer addresses that are not loopback or linklocal, but use them
295 * if nothing else matches.
296 */
297 for (allow_local = 0; allow_local < 2; allow_local++) {
298 for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
299 if (ifa->ifa_addr == NULL || ifa->ifa_name == NULL ||
300 (ifa->ifa_flags & IFF_UP) == 0 ||
301 ifa->ifa_addr->sa_family != af ||
302 strcmp(ifa->ifa_name, options.bind_interface) != 0)
303 continue;
304 switch (ifa->ifa_addr->sa_family) {
305 case AF_INET:
306 sa = (struct sockaddr_in *)ifa->ifa_addr;
307 if (!allow_local && sa->sin_addr.s_addr ==
308 htonl(INADDR_LOOPBACK))
309 continue;
310 if (*rlenp < sizeof(struct sockaddr_in)) {
311 error("%s: v4 addr doesn't fit",
312 __func__);
313 return -1;
314 }
315 *rlenp = sizeof(struct sockaddr_in);
316 memcpy(resultp, sa, *rlenp);
317 return 0;
318 case AF_INET6:
319 sa6 = (struct sockaddr_in6 *)ifa->ifa_addr;
320 v6addr = &sa6->sin6_addr;
321 if (!allow_local &&
322 (IN6_IS_ADDR_LINKLOCAL(v6addr) ||
323 IN6_IS_ADDR_LOOPBACK(v6addr)))
324 continue;
325 if (*rlenp < sizeof(struct sockaddr_in6)) {
326 error("%s: v6 addr doesn't fit",
327 __func__);
328 return -1;
329 }
330 *rlenp = sizeof(struct sockaddr_in6);
331 memcpy(resultp, sa6, *rlenp);
332 return 0;
333 }
334 }
335 }
336 return -1;
337}
338#endif
339
273/* 340/*
274 * Creates a (possibly privileged) socket for use as the ssh connection. 341 * Creates a (possibly privileged) socket for use as the ssh connection.
275 */ 342 */
276static int 343static int
277ssh_create_socket(int privileged, struct addrinfo *ai) 344ssh_create_socket(int privileged, struct addrinfo *ai)
278{ 345{
279 int sock, r, gaierr; 346 int sock, r, oerrno;
347 struct sockaddr_storage bindaddr;
348 socklen_t bindaddrlen = 0;
280 struct addrinfo hints, *res = NULL; 349 struct addrinfo hints, *res = NULL;
350#ifdef HAVE_IFADDRS_H
351 struct ifaddrs *ifaddrs = NULL;
352#endif
353 char ntop[NI_MAXHOST];
281 354
282 sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); 355 sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
283 if (sock < 0) { 356 if (sock < 0) {
@@ -287,22 +360,55 @@ ssh_create_socket(int privileged, struct addrinfo *ai)
287 fcntl(sock, F_SETFD, FD_CLOEXEC); 360 fcntl(sock, F_SETFD, FD_CLOEXEC);
288 361
289 /* Bind the socket to an alternative local IP address */ 362 /* Bind the socket to an alternative local IP address */
290 if (options.bind_address == NULL && !privileged) 363 if (options.bind_address == NULL && options.bind_interface == NULL &&
364 !privileged)
291 return sock; 365 return sock;
292 366
293 if (options.bind_address) { 367 if (options.bind_address != NULL) {
294 memset(&hints, 0, sizeof(hints)); 368 memset(&hints, 0, sizeof(hints));
295 hints.ai_family = ai->ai_family; 369 hints.ai_family = ai->ai_family;
296 hints.ai_socktype = ai->ai_socktype; 370 hints.ai_socktype = ai->ai_socktype;
297 hints.ai_protocol = ai->ai_protocol; 371 hints.ai_protocol = ai->ai_protocol;
298 hints.ai_flags = AI_PASSIVE; 372 hints.ai_flags = AI_PASSIVE;
299 gaierr = getaddrinfo(options.bind_address, NULL, &hints, &res); 373 if ((r = getaddrinfo(options.bind_address, NULL,
300 if (gaierr) { 374 &hints, &res)) != 0) {
301 error("getaddrinfo: %s: %s", options.bind_address, 375 error("getaddrinfo: %s: %s", options.bind_address,
302 ssh_gai_strerror(gaierr)); 376 ssh_gai_strerror(r));
303 close(sock); 377 goto fail;
304 return -1; 378 }
379 if (res == NULL) {
380 error("getaddrinfo: no addrs");
381 goto fail;
305 } 382 }
383 if (res->ai_addrlen > sizeof(bindaddr)) {
384 error("%s: addr doesn't fit", __func__);
385 goto fail;
386 }
387 memcpy(&bindaddr, res->ai_addr, res->ai_addrlen);
388 bindaddrlen = res->ai_addrlen;
389 } else if (options.bind_interface != NULL) {
390#ifdef HAVE_IFADDRS_H
391 if ((r = getifaddrs(&ifaddrs)) != 0) {
392 error("getifaddrs: %s: %s", options.bind_interface,
393 strerror(errno));
394 goto fail;
395 }
396 bindaddrlen = sizeof(bindaddr);
397 if (check_ifaddrs(options.bind_interface, ai->ai_family,
398 ifaddrs, &bindaddr, &bindaddrlen) != 0) {
399 logit("getifaddrs: %s: no suitable addresses",
400 options.bind_interface);
401 goto fail;
402 }
403#else
404 error("BindInterface not supported on this platform.");
405#endif
406 }
407 if ((r = getnameinfo((struct sockaddr *)&bindaddr, bindaddrlen,
408 ntop, sizeof(ntop), NULL, 0, NI_NUMERICHOST)) != 0) {
409 error("%s: getnameinfo failed: %s", __func__,
410 ssh_gai_strerror(r));
411 goto fail;
306 } 412 }
307 /* 413 /*
308 * If we are running as root and want to connect to a privileged 414 * If we are running as root and want to connect to a privileged
@@ -310,25 +416,32 @@ ssh_create_socket(int privileged, struct addrinfo *ai)
310 */ 416 */
311 if (privileged) { 417 if (privileged) {
312 PRIV_START; 418 PRIV_START;
313 r = bindresvport_sa(sock, res ? res->ai_addr : NULL); 419 r = bindresvport_sa(sock,
420 bindaddrlen == 0 ? NULL : (struct sockaddr *)&bindaddr);
421 oerrno = errno;
314 PRIV_END; 422 PRIV_END;
315 if (r < 0) { 423 if (r < 0) {
316 error("bindresvport_sa: af=%d %s", ai->ai_family, 424 error("bindresvport_sa %s: %s", ntop,
317 strerror(errno)); 425 strerror(oerrno));
318 goto fail; 426 goto fail;
319 } 427 }
320 } else { 428 } else if (bind(sock, (struct sockaddr *)&bindaddr, bindaddrlen) != 0) {
321 if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) { 429 error("bind %s: %s", ntop, strerror(errno));
322 error("bind: %s: %s", options.bind_address, 430 goto fail;
323 strerror(errno));
324 fail:
325 close(sock);
326 freeaddrinfo(res);
327 return -1;
328 }
329 } 431 }
432 debug("%s: bound to %s", __func__, ntop);
433 /* success */
434 goto out;
435fail:
436 close(sock);
437 sock = -1;
438 out:
330 if (res != NULL) 439 if (res != NULL)
331 freeaddrinfo(res); 440 freeaddrinfo(res);
441#ifdef HAVE_IFADDRS_H
442 if (ifaddrs != NULL)
443 freeifaddrs(ifaddrs);
444#endif
332 return sock; 445 return sock;
333} 446}
334 447
@@ -344,7 +457,7 @@ waitrfd(int fd, int *timeoutp)
344 struct timeval t_start; 457 struct timeval t_start;
345 int oerrno, r; 458 int oerrno, r;
346 459
347 gettimeofday(&t_start, NULL); 460 monotime_tv(&t_start);
348 pfd.fd = fd; 461 pfd.fd = fd;
349 pfd.events = POLLIN; 462 pfd.events = POLLIN;
350 for (; *timeoutp >= 0;) { 463 for (; *timeoutp >= 0;) {
@@ -416,7 +529,7 @@ ssh_connect_direct(struct ssh *ssh, const char *host, struct addrinfo *aitop,
416 int connection_attempts, int *timeout_ms, int want_keepalive, int needpriv) 529 int connection_attempts, int *timeout_ms, int want_keepalive, int needpriv)
417{ 530{
418 int on = 1; 531 int on = 1;
419 int sock = -1, attempt; 532 int oerrno, sock = -1, attempt;
420 char ntop[NI_MAXHOST], strport[NI_MAXSERV]; 533 char ntop[NI_MAXHOST], strport[NI_MAXSERV];
421 struct addrinfo *ai; 534 struct addrinfo *ai;
422 535
@@ -436,12 +549,16 @@ ssh_connect_direct(struct ssh *ssh, const char *host, struct addrinfo *aitop,
436 */ 549 */
437 for (ai = aitop; ai; ai = ai->ai_next) { 550 for (ai = aitop; ai; ai = ai->ai_next) {
438 if (ai->ai_family != AF_INET && 551 if (ai->ai_family != AF_INET &&
439 ai->ai_family != AF_INET6) 552 ai->ai_family != AF_INET6) {
553 errno = EAFNOSUPPORT;
440 continue; 554 continue;
555 }
441 if (getnameinfo(ai->ai_addr, ai->ai_addrlen, 556 if (getnameinfo(ai->ai_addr, ai->ai_addrlen,
442 ntop, sizeof(ntop), strport, sizeof(strport), 557 ntop, sizeof(ntop), strport, sizeof(strport),
443 NI_NUMERICHOST|NI_NUMERICSERV) != 0) { 558 NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
559 oerrno = errno;
444 error("%s: getnameinfo failed", __func__); 560 error("%s: getnameinfo failed", __func__);
561 errno = oerrno;
445 continue; 562 continue;
446 } 563 }
447 debug("Connecting to %.200s [%.100s] port %s.", 564 debug("Connecting to %.200s [%.100s] port %s.",
@@ -449,9 +566,11 @@ ssh_connect_direct(struct ssh *ssh, const char *host, struct addrinfo *aitop,
449 566
450 /* Create a socket for connecting. */ 567 /* Create a socket for connecting. */
451 sock = ssh_create_socket(needpriv, ai); 568 sock = ssh_create_socket(needpriv, ai);
452 if (sock < 0) 569 if (sock < 0) {
453 /* Any error is already output */ 570 /* Any error is already output */
571 errno = 0;
454 continue; 572 continue;
573 }
455 574
456 if (timeout_connect(sock, ai->ai_addr, ai->ai_addrlen, 575 if (timeout_connect(sock, ai->ai_addr, ai->ai_addrlen,
457 timeout_ms) >= 0) { 576 timeout_ms) >= 0) {
@@ -459,10 +578,12 @@ ssh_connect_direct(struct ssh *ssh, const char *host, struct addrinfo *aitop,
459 memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen); 578 memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen);
460 break; 579 break;
461 } else { 580 } else {
581 oerrno = errno;
462 debug("connect to address %s port %s: %s", 582 debug("connect to address %s port %s: %s",
463 ntop, strport, strerror(errno)); 583 ntop, strport, strerror(errno));
464 close(sock); 584 close(sock);
465 sock = -1; 585 sock = -1;
586 errno = oerrno;
466 } 587 }
467 } 588 }
468 if (sock != -1) 589 if (sock != -1)
@@ -472,8 +593,8 @@ ssh_connect_direct(struct ssh *ssh, const char *host, struct addrinfo *aitop,
472 /* Return failure if we didn't get a successful connection. */ 593 /* Return failure if we didn't get a successful connection. */
473 if (sock == -1) { 594 if (sock == -1) {
474 error("ssh: connect to host %s port %s: %s", 595 error("ssh: connect to host %s port %s: %s",
475 host, strport, strerror(errno)); 596 host, strport, errno == 0 ? "failure" : strerror(errno));
476 return (-1); 597 return -1;
477 } 598 }
478 599
479 debug("Connection established."); 600 debug("Connection established.");
@@ -610,9 +731,6 @@ ssh_exchange_identification(int timeout_ms)
610 if (mismatch) 731 if (mismatch)
611 fatal("Protocol major versions differ: %d vs. %d", 732 fatal("Protocol major versions differ: %d vs. %d",
612 PROTOCOL_MAJOR_2, remote_major); 733 PROTOCOL_MAJOR_2, remote_major);
613 if ((datafellows & SSH_BUG_DERIVEKEY) != 0)
614 fatal("Server version \"%.100s\" uses unsafe key agreement; "
615 "refusing connection", remote_version);
616 if ((datafellows & SSH_BUG_RSASIGMD5) != 0) 734 if ((datafellows & SSH_BUG_RSASIGMD5) != 0)
617 logit("Server version \"%.100s\" uses unsafe RSA signature " 735 logit("Server version \"%.100s\" uses unsafe RSA signature "
618 "scheme; disabling use of RSA keys", remote_version); 736 "scheme; disabling use of RSA keys", remote_version);
@@ -631,11 +749,12 @@ confirm(const char *prompt)
631 return 0; 749 return 0;
632 for (msg = prompt;;msg = again) { 750 for (msg = prompt;;msg = again) {
633 p = read_passphrase(msg, RP_ECHO); 751 p = read_passphrase(msg, RP_ECHO);
634 if (p == NULL || 752 if (p == NULL)
635 (p[0] == '\0') || (p[0] == '\n') || 753 return 0;
636 strncasecmp(p, "no", 2) == 0) 754 p[strcspn(p, "\n")] = '\0';
755 if (p[0] == '\0' || strcasecmp(p, "no") == 0)
637 ret = 0; 756 ret = 0;
638 if (p && strncasecmp(p, "yes", 3) == 0) 757 else if (strcasecmp(p, "yes") == 0)
639 ret = 1; 758 ret = 1;
640 free(p); 759 free(p);
641 if (ret != -1) 760 if (ret != -1)
@@ -1178,8 +1297,7 @@ fail:
1178 host_key = raw_key; 1297 host_key = raw_key;
1179 goto retry; 1298 goto retry;
1180 } 1299 }
1181 if (raw_key != NULL) 1300 sshkey_free(raw_key);
1182 sshkey_free(raw_key);
1183 free(ip); 1301 free(ip);
1184 free(host); 1302 free(host);
1185 if (host_hostkeys != NULL) 1303 if (host_hostkeys != NULL)
@@ -1364,6 +1482,7 @@ show_other_keys(struct hostkeys *hostkeys, struct sshkey *key)
1364 KEY_DSA, 1482 KEY_DSA,
1365 KEY_ECDSA, 1483 KEY_ECDSA,
1366 KEY_ED25519, 1484 KEY_ED25519,
1485 KEY_XMSS,
1367 -1 1486 -1
1368 }; 1487 };
1369 int i, ret = 0; 1488 int i, ret = 0;
@@ -1460,8 +1579,8 @@ ssh_local_cmd(const char *args)
1460} 1579}
1461 1580
1462void 1581void
1463maybe_add_key_to_agent(char *authfile, struct sshkey *private, char *comment, 1582maybe_add_key_to_agent(char *authfile, const struct sshkey *private,
1464 char *passphrase) 1583 char *comment, char *passphrase)
1465{ 1584{
1466 int auth_sock = -1, r; 1585 int auth_sock = -1, r;
1467 1586
@@ -1481,7 +1600,7 @@ maybe_add_key_to_agent(char *authfile, struct sshkey *private, char *comment,
1481 } 1600 }
1482 1601
1483 if ((r = ssh_add_identity_constrained(auth_sock, private, comment, 0, 1602 if ((r = ssh_add_identity_constrained(auth_sock, private, comment, 0,
1484 (options.add_keys_to_agent == 3))) == 0) 1603 (options.add_keys_to_agent == 3), 0)) == 0)
1485 debug("identity added to agent: %s", authfile); 1604 debug("identity added to agent: %s", authfile);
1486 else 1605 else
1487 debug("could not add identity to agent: %s (%d)", authfile, r); 1606 debug("could not add identity to agent: %s (%d)", authfile, r);