Annotation of src/usr.bin/ssh/sshconnect.c, Revision 1.252
1.252 ! djm 1: /* $OpenBSD: sshconnect.c,v 1.251 2014/07/15 15:54:14 millert Exp $ */
1.1 deraadt 2: /*
1.39 deraadt 3: * Author: Tatu Ylonen <ylo@cs.hut.fi>
4: * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5: * All rights reserved
6: * Code to connect to a remote host, and to perform the client side of the
7: * login (authentication) dialog.
1.78 deraadt 8: *
9: * As far as I am concerned, the code I have written for this software
10: * can be used freely for any purpose. Any derived versions of this
11: * software must be clearly marked as such, and if the derived work is
12: * incompatible with the protocol description in the RFC file, it must be
13: * called by a name other than "ssh" or "Secure Shell".
1.39 deraadt 14: */
1.1 deraadt 15:
1.174 stevesk 16: #include <sys/types.h>
17: #include <sys/wait.h>
1.175 stevesk 18: #include <sys/stat.h>
1.187 stevesk 19: #include <sys/socket.h>
1.195 stevesk 20: #include <sys/time.h>
1.187 stevesk 21:
22: #include <netinet/in.h>
1.172 stevesk 23:
1.176 stevesk 24: #include <ctype.h>
1.190 stevesk 25: #include <errno.h>
1.216 dtucker 26: #include <fcntl.h>
1.191 stevesk 27: #include <netdb.h>
1.172 stevesk 28: #include <paths.h>
1.199 deraadt 29: #include <signal.h>
1.188 stevesk 30: #include <pwd.h>
1.198 stevesk 31: #include <stdio.h>
1.196 stevesk 32: #include <stdlib.h>
1.193 stevesk 33: #include <string.h>
1.192 stevesk 34: #include <unistd.h>
1.71 markus 35:
1.199 deraadt 36: #include "xmalloc.h"
1.91 markus 37: #include "ssh.h"
1.1 deraadt 38: #include "rsa.h"
1.59 markus 39: #include "buffer.h"
1.1 deraadt 40: #include "packet.h"
41: #include "uidswap.h"
1.21 markus 42: #include "compat.h"
1.58 markus 43: #include "key.h"
1.71 markus 44: #include "sshconnect.h"
1.58 markus 45: #include "hostfile.h"
1.91 markus 46: #include "log.h"
1.251 millert 47: #include "misc.h"
1.91 markus 48: #include "readconf.h"
49: #include "atomicio.h"
1.140 jakob 50: #include "dns.h"
1.214 andreas 51: #include "roaming.h"
1.239 djm 52: #include "monitor_fdpass.h"
1.219 djm 53: #include "ssh2.h"
1.186 stevesk 54: #include "version.h"
1.252 ! djm 55: #include "authfile.h"
! 56: #include "ssherr.h"
1.140 jakob 57:
1.70 markus 58: char *client_version_string = NULL;
59: char *server_version_string = NULL;
1.250 djm 60: Key *previous_host_key = NULL;
1.59 markus 61:
1.169 stevesk 62: static int matching_host_key_dns = 0;
1.145 jakob 63:
1.227 djm 64: static pid_t proxy_command_pid = 0;
65:
1.124 markus 66: /* import */
1.43 markus 67: extern Options options;
1.50 markus 68: extern char *__progname;
1.124 markus 69: extern uid_t original_real_uid;
70: extern uid_t original_effective_uid;
1.91 markus 71:
1.229 djm 72: static int show_other_keys(struct hostkeys *, Key *);
1.150 jakob 73: static void warn_changed_key(Key *);
1.132 markus 74:
1.239 djm 75: /* Expand a proxy command */
76: static char *
77: expand_proxy_command(const char *proxy_command, const char *user,
78: const char *host, int port)
79: {
80: char *tmp, *ret, strport[NI_MAXSERV];
81:
1.241 djm 82: snprintf(strport, sizeof strport, "%d", port);
1.239 djm 83: xasprintf(&tmp, "exec %s", proxy_command);
84: ret = percent_expand(tmp, "h", host, "p", strport,
85: "r", options.user, (char *)NULL);
86: free(tmp);
87: return ret;
88: }
89:
90: /*
91: * Connect to the given ssh server using a proxy command that passes a
92: * a connected fd back to us.
93: */
94: static int
95: ssh_proxy_fdpass_connect(const char *host, u_short port,
96: const char *proxy_command)
97: {
98: char *command_string;
99: int sp[2], sock;
100: pid_t pid;
101: char *shell;
102:
103: if ((shell = getenv("SHELL")) == NULL)
104: shell = _PATH_BSHELL;
105:
106: if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp) < 0)
107: fatal("Could not create socketpair to communicate with "
108: "proxy dialer: %.100s", strerror(errno));
109:
110: command_string = expand_proxy_command(proxy_command, options.user,
111: host, port);
112: debug("Executing proxy dialer command: %.500s", command_string);
113:
114: /* Fork and execute the proxy command. */
115: if ((pid = fork()) == 0) {
116: char *argv[10];
117:
118: /* Child. Permanently give up superuser privileges. */
119: permanently_drop_suid(original_real_uid);
120:
121: close(sp[1]);
122: /* Redirect stdin and stdout. */
123: if (sp[0] != 0) {
124: if (dup2(sp[0], 0) < 0)
125: perror("dup2 stdin");
126: }
127: if (sp[0] != 1) {
128: if (dup2(sp[0], 1) < 0)
129: perror("dup2 stdout");
130: }
131: if (sp[0] >= 2)
132: close(sp[0]);
133:
134: /*
135: * Stderr is left as it is so that error messages get
136: * printed on the user's terminal.
137: */
138: argv[0] = shell;
139: argv[1] = "-c";
140: argv[2] = command_string;
141: argv[3] = NULL;
142:
143: /*
144: * Execute the proxy command.
145: * Note that we gave up any extra privileges above.
146: */
147: execv(argv[0], argv);
148: perror(argv[0]);
149: exit(1);
150: }
151: /* Parent. */
152: if (pid < 0)
153: fatal("fork failed: %.100s", strerror(errno));
154: close(sp[0]);
155: free(command_string);
156:
157: if ((sock = mm_receive_fd(sp[1])) == -1)
158: fatal("proxy dialer did not pass back a connection");
159:
160: while (waitpid(pid, NULL, 0) == -1)
161: if (errno != EINTR)
162: fatal("Couldn't wait for child: %s", strerror(errno));
163:
164: /* Set the connection file descriptors. */
165: packet_set_connection(sock, sock);
166:
167: return 0;
168: }
169:
1.39 deraadt 170: /*
171: * Connect to the given ssh server using a proxy command.
172: */
1.109 itojun 173: static int
1.124 markus 174: ssh_proxy_connect(const char *host, u_short port, const char *proxy_command)
1.1 deraadt 175: {
1.239 djm 176: char *command_string;
1.38 markus 177: int pin[2], pout[2];
1.69 deraadt 178: pid_t pid;
1.239 djm 179: char *shell;
1.237 markus 180:
1.226 djm 181: if ((shell = getenv("SHELL")) == NULL || *shell == '\0')
1.201 djm 182: shell = _PATH_BSHELL;
1.38 markus 183:
184: /* Create pipes for communicating with the proxy. */
185: if (pipe(pin) < 0 || pipe(pout) < 0)
186: fatal("Could not create pipes to communicate with the proxy: %.100s",
1.118 deraadt 187: strerror(errno));
1.38 markus 188:
1.239 djm 189: command_string = expand_proxy_command(proxy_command, options.user,
190: host, port);
1.38 markus 191: debug("Executing proxy command: %.500s", command_string);
192:
193: /* Fork and execute the proxy command. */
194: if ((pid = fork()) == 0) {
195: char *argv[10];
196:
197: /* Child. Permanently give up superuser privileges. */
1.184 markus 198: permanently_drop_suid(original_real_uid);
1.38 markus 199:
200: /* Redirect stdin and stdout. */
201: close(pin[1]);
202: if (pin[0] != 0) {
203: if (dup2(pin[0], 0) < 0)
204: perror("dup2 stdin");
205: close(pin[0]);
206: }
207: close(pout[0]);
208: if (dup2(pout[1], 1) < 0)
209: perror("dup2 stdout");
210: /* Cannot be 1 because pin allocated two descriptors. */
211: close(pout[1]);
212:
213: /* Stderr is left as it is so that error messages get
214: printed on the user's terminal. */
1.201 djm 215: argv[0] = shell;
1.38 markus 216: argv[1] = "-c";
217: argv[2] = command_string;
218: argv[3] = NULL;
219:
220: /* Execute the proxy command. Note that we gave up any
221: extra privileges above. */
1.232 djm 222: signal(SIGPIPE, SIG_DFL);
1.89 markus 223: execv(argv[0], argv);
224: perror(argv[0]);
1.38 markus 225: exit(1);
226: }
227: /* Parent. */
228: if (pid < 0)
229: fatal("fork failed: %.100s", strerror(errno));
1.135 djm 230: else
231: proxy_command_pid = pid; /* save pid to clean up later */
1.38 markus 232:
233: /* Close child side of the descriptors. */
234: close(pin[0]);
235: close(pout[1]);
236:
237: /* Free the command name. */
1.238 djm 238: free(command_string);
1.38 markus 239:
240: /* Set the connection file descriptors. */
241: packet_set_connection(pout[0], pin[1]);
1.1 deraadt 242:
1.110 markus 243: /* Indicate OK return */
244: return 0;
1.227 djm 245: }
246:
247: void
248: ssh_kill_proxy_command(void)
249: {
250: /*
251: * Send SIGHUP to proxy command if used. We don't wait() in
252: * case it hangs and instead rely on init to reap the child
253: */
254: if (proxy_command_pid > 1)
1.228 djm 255: kill(proxy_command_pid, SIGHUP);
1.1 deraadt 256: }
257:
1.39 deraadt 258: /*
259: * Creates a (possibly privileged) socket for use as the ssh connection.
260: */
1.109 itojun 261: static int
1.139 markus 262: ssh_create_socket(int privileged, struct addrinfo *ai)
1.1 deraadt 263: {
1.240 djm 264: int sock, r, gaierr;
1.246 djm 265: struct addrinfo hints, *res = NULL;
1.1 deraadt 266:
1.217 dtucker 267: sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
1.216 dtucker 268: if (sock < 0) {
1.240 djm 269: error("socket: %s", strerror(errno));
1.216 dtucker 270: return -1;
271: }
272: fcntl(sock, F_SETFD, FD_CLOEXEC);
1.105 markus 273:
274: /* Bind the socket to an alternative local IP address */
1.240 djm 275: if (options.bind_address == NULL && !privileged)
1.105 markus 276: return sock;
277:
1.246 djm 278: if (options.bind_address) {
279: memset(&hints, 0, sizeof(hints));
280: hints.ai_family = ai->ai_family;
281: hints.ai_socktype = ai->ai_socktype;
282: hints.ai_protocol = ai->ai_protocol;
283: hints.ai_flags = AI_PASSIVE;
284: gaierr = getaddrinfo(options.bind_address, NULL, &hints, &res);
285: if (gaierr) {
286: error("getaddrinfo: %s: %s", options.bind_address,
287: ssh_gai_strerror(gaierr));
288: close(sock);
289: return -1;
290: }
1.105 markus 291: }
1.240 djm 292: /*
293: * If we are running as root and want to connect to a privileged
294: * port, bind our own socket to a privileged port.
295: */
296: if (privileged) {
297: PRIV_START;
1.246 djm 298: r = bindresvport_sa(sock, res ? res->ai_addr : NULL);
1.240 djm 299: PRIV_END;
300: if (r < 0) {
301: error("bindresvport_sa: af=%d %s", ai->ai_family,
302: strerror(errno));
303: goto fail;
304: }
305: } else {
306: if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
307: error("bind: %s: %s", options.bind_address,
308: strerror(errno));
309: fail:
310: close(sock);
311: freeaddrinfo(res);
312: return -1;
313: }
1.38 markus 314: }
1.246 djm 315: if (res != NULL)
316: freeaddrinfo(res);
1.38 markus 317: return sock;
1.1 deraadt 318: }
319:
1.141 djm 320: static int
321: timeout_connect(int sockfd, const struct sockaddr *serv_addr,
1.202 djm 322: socklen_t addrlen, int *timeoutp)
1.141 djm 323: {
324: fd_set *fdset;
1.202 djm 325: struct timeval tv, t_start;
1.141 djm 326: socklen_t optlen;
1.179 djm 327: int optval, rc, result = -1;
1.141 djm 328:
1.202 djm 329: gettimeofday(&t_start, NULL);
330:
331: if (*timeoutp <= 0) {
332: result = connect(sockfd, serv_addr, addrlen);
333: goto done;
334: }
1.141 djm 335:
1.156 djm 336: set_nonblock(sockfd);
1.141 djm 337: rc = connect(sockfd, serv_addr, addrlen);
1.156 djm 338: if (rc == 0) {
339: unset_nonblock(sockfd);
1.202 djm 340: result = 0;
341: goto done;
342: }
343: if (errno != EINPROGRESS) {
344: result = -1;
345: goto done;
1.156 djm 346: }
1.141 djm 347:
1.179 djm 348: fdset = (fd_set *)xcalloc(howmany(sockfd + 1, NFDBITS),
349: sizeof(fd_mask));
1.141 djm 350: FD_SET(sockfd, fdset);
1.202 djm 351: ms_to_timeval(&tv, *timeoutp);
1.141 djm 352:
1.162 deraadt 353: for (;;) {
1.141 djm 354: rc = select(sockfd + 1, NULL, fdset, NULL, &tv);
355: if (rc != -1 || errno != EINTR)
356: break;
357: }
358:
1.162 deraadt 359: switch (rc) {
1.141 djm 360: case 0:
361: /* Timed out */
362: errno = ETIMEDOUT;
1.142 djm 363: break;
1.141 djm 364: case -1:
365: /* Select error */
1.154 djm 366: debug("select: %s", strerror(errno));
1.142 djm 367: break;
1.141 djm 368: case 1:
369: /* Completed or failed */
370: optval = 0;
371: optlen = sizeof(optval);
1.154 djm 372: if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval,
1.148 markus 373: &optlen) == -1) {
1.154 djm 374: debug("getsockopt: %s", strerror(errno));
1.142 djm 375: break;
1.148 markus 376: }
1.141 djm 377: if (optval != 0) {
378: errno = optval;
1.142 djm 379: break;
1.141 djm 380: }
1.142 djm 381: result = 0;
1.156 djm 382: unset_nonblock(sockfd);
1.141 djm 383: break;
384: default:
385: /* Should not occur */
386: fatal("Bogus return (%d) from select()", rc);
387: }
388:
1.238 djm 389: free(fdset);
1.202 djm 390:
391: done:
392: if (result == 0 && *timeoutp > 0) {
393: ms_subtract_diff(&t_start, timeoutp);
394: if (*timeoutp <= 0) {
395: errno = ETIMEDOUT;
396: result = -1;
397: }
398: }
399:
1.142 djm 400: return (result);
1.141 djm 401: }
402:
1.39 deraadt 403: /*
1.49 markus 404: * Opens a TCP/IP connection to the remote server on the given host.
405: * The address of the remote host will be returned in hostaddr.
1.124 markus 406: * If port is 0, the default port will be used. If needpriv is true,
1.39 deraadt 407: * a privileged port will be allocated to make the connection.
1.124 markus 408: * This requires super-user privileges if needpriv is true.
1.39 deraadt 409: * Connection_attempts specifies the maximum number of tries (one per
410: * second). If proxy_command is non-NULL, it specifies the command (with %h
411: * and %p substituted for host and port, respectively) to use to contact
412: * the daemon.
413: */
1.241 djm 414: static int
415: ssh_connect_direct(const char *host, struct addrinfo *aitop,
416: struct sockaddr_storage *hostaddr, u_short port, int family,
417: int connection_attempts, int *timeout_ms, int want_keepalive, int needpriv)
1.1 deraadt 418: {
1.90 markus 419: int on = 1;
1.49 markus 420: int sock = -1, attempt;
1.90 markus 421: char ntop[NI_MAXHOST], strport[NI_MAXSERV];
1.241 djm 422: struct addrinfo *ai;
1.38 markus 423:
1.136 markus 424: debug2("ssh_connect: needpriv %d", needpriv);
1.38 markus 425:
1.181 markus 426: for (attempt = 0; attempt < connection_attempts; attempt++) {
1.200 markus 427: if (attempt > 0) {
428: /* Sleep a moment before retrying. */
429: sleep(1);
1.38 markus 430: debug("Trying again...");
1.200 markus 431: }
1.181 markus 432: /*
433: * Loop through addresses for this host, and try each one in
434: * sequence until the connection succeeds.
435: */
1.49 markus 436: for (ai = aitop; ai; ai = ai->ai_next) {
1.241 djm 437: if (ai->ai_family != AF_INET &&
438: ai->ai_family != AF_INET6)
1.49 markus 439: continue;
440: if (getnameinfo(ai->ai_addr, ai->ai_addrlen,
441: ntop, sizeof(ntop), strport, sizeof(strport),
442: NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
443: error("ssh_connect: getnameinfo failed");
444: continue;
445: }
446: debug("Connecting to %.200s [%.100s] port %s.",
447: host, ntop, strport);
448:
449: /* Create a socket for connecting. */
1.139 markus 450: sock = ssh_create_socket(needpriv, ai);
1.49 markus 451: if (sock < 0)
1.110 markus 452: /* Any error is already output */
1.49 markus 453: continue;
454:
1.141 djm 455: if (timeout_connect(sock, ai->ai_addr, ai->ai_addrlen,
1.202 djm 456: timeout_ms) >= 0) {
1.49 markus 457: /* Successful connection. */
1.102 markus 458: memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen);
1.38 markus 459: break;
1.49 markus 460: } else {
1.131 itojun 461: debug("connect to address %s port %s: %s",
462: ntop, strport, strerror(errno));
1.38 markus 463: close(sock);
1.181 markus 464: sock = -1;
1.38 markus 465: }
466: }
1.181 markus 467: if (sock != -1)
1.49 markus 468: break; /* Successful connection. */
1.38 markus 469: }
1.49 markus 470:
1.38 markus 471: /* Return failure if we didn't get a successful connection. */
1.181 markus 472: if (sock == -1) {
1.159 markus 473: error("ssh: connect to host %s port %s: %s",
1.130 itojun 474: host, strport, strerror(errno));
1.159 markus 475: return (-1);
1.130 itojun 476: }
1.38 markus 477:
478: debug("Connection established.");
1.90 markus 479:
1.155 markus 480: /* Set SO_KEEPALIVE if requested. */
1.202 djm 481: if (want_keepalive &&
1.90 markus 482: setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on,
483: sizeof(on)) < 0)
484: error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno));
1.38 markus 485:
486: /* Set the connection. */
487: packet_set_connection(sock, sock);
1.1 deraadt 488:
1.110 markus 489: return 0;
1.59 markus 490: }
491:
1.241 djm 492: int
493: ssh_connect(const char *host, struct addrinfo *addrs,
494: struct sockaddr_storage *hostaddr, u_short port, int family,
495: int connection_attempts, int *timeout_ms, int want_keepalive, int needpriv)
496: {
497: if (options.proxy_command == NULL) {
498: return ssh_connect_direct(host, addrs, hostaddr, port, family,
499: connection_attempts, timeout_ms, want_keepalive, needpriv);
500: } else if (strcmp(options.proxy_command, "-") == 0) {
501: packet_set_connection(STDIN_FILENO, STDOUT_FILENO);
502: return 0; /* Always succeeds */
503: } else if (options.proxy_use_fdpass) {
504: return ssh_proxy_fdpass_connect(host, port,
505: options.proxy_command);
506: }
507: return ssh_proxy_connect(host, port, options.proxy_command);
508: }
509:
1.235 djm 510: static void
511: send_client_banner(int connection_out, int minor1)
512: {
513: /* Send our own protocol version identification. */
514: if (compat20) {
515: xasprintf(&client_version_string, "SSH-%d.%d-%.100s\r\n",
516: PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_VERSION);
517: } else {
518: xasprintf(&client_version_string, "SSH-%d.%d-%.100s\n",
519: PROTOCOL_MAJOR_1, minor1, SSH_VERSION);
520: }
521: if (roaming_atomicio(vwrite, connection_out, client_version_string,
522: strlen(client_version_string)) != strlen(client_version_string))
523: fatal("write: %.100s", strerror(errno));
524: chop(client_version_string);
525: debug("Local version string %.100s", client_version_string);
526: }
527:
1.43 markus 528: /*
1.39 deraadt 529: * Waits for the server identification string, and sends our own
530: * identification string.
531: */
1.213 andreas 532: void
1.202 djm 533: ssh_exchange_identification(int timeout_ms)
1.1 deraadt 534: {
1.38 markus 535: char buf[256], remote_version[256]; /* must be same size! */
1.165 djm 536: int remote_major, remote_minor, mismatch;
1.38 markus 537: int connection_in = packet_get_connection_in();
538: int connection_out = packet_get_connection_out();
1.235 djm 539: int minor1 = PROTOCOL_MINOR_1, client_banner_sent = 0;
1.185 djm 540: u_int i, n;
1.202 djm 541: size_t len;
542: int fdsetsz, remaining, rc;
543: struct timeval t_start, t_remaining;
544: fd_set *fdset;
545:
546: fdsetsz = howmany(connection_in + 1, NFDBITS) * sizeof(fd_mask);
547: fdset = xcalloc(1, fdsetsz);
1.38 markus 548:
1.235 djm 549: /*
550: * If we are SSH2-only then we can send the banner immediately and
551: * save a round-trip.
552: */
553: if (options.protocol == SSH_PROTO_2) {
554: enable_compat20();
555: send_client_banner(connection_out, 0);
556: client_banner_sent = 1;
557: }
558:
1.163 avsm 559: /* Read other side's version identification. */
1.202 djm 560: remaining = timeout_ms;
1.185 djm 561: for (n = 0;;) {
1.75 markus 562: for (i = 0; i < sizeof(buf) - 1; i++) {
1.202 djm 563: if (timeout_ms > 0) {
564: gettimeofday(&t_start, NULL);
565: ms_to_timeval(&t_remaining, remaining);
566: FD_SET(connection_in, fdset);
567: rc = select(connection_in + 1, fdset, NULL,
568: fdset, &t_remaining);
569: ms_subtract_diff(&t_start, &remaining);
570: if (rc == 0 || remaining <= 0)
571: fatal("Connection timed out during "
572: "banner exchange");
573: if (rc == -1) {
574: if (errno == EINTR)
575: continue;
576: fatal("ssh_exchange_identification: "
577: "select: %s", strerror(errno));
578: }
579: }
580:
1.214 andreas 581: len = roaming_atomicio(read, connection_in, &buf[i], 1);
1.163 avsm 582:
1.167 djm 583: if (len != 1 && errno == EPIPE)
1.202 djm 584: fatal("ssh_exchange_identification: "
585: "Connection closed by remote host");
1.163 avsm 586: else if (len != 1)
1.202 djm 587: fatal("ssh_exchange_identification: "
588: "read: %.100s", strerror(errno));
1.75 markus 589: if (buf[i] == '\r') {
590: buf[i] = '\n';
591: buf[i + 1] = 0;
592: continue; /**XXX wait for \n */
593: }
594: if (buf[i] == '\n') {
595: buf[i + 1] = 0;
596: break;
597: }
1.185 djm 598: if (++n > 65536)
1.202 djm 599: fatal("ssh_exchange_identification: "
600: "No banner received");
1.38 markus 601: }
1.75 markus 602: buf[sizeof(buf) - 1] = 0;
1.76 markus 603: if (strncmp(buf, "SSH-", 4) == 0)
1.38 markus 604: break;
1.75 markus 605: debug("ssh_exchange_identification: %s", buf);
1.38 markus 606: }
1.59 markus 607: server_version_string = xstrdup(buf);
1.238 djm 608: free(fdset);
1.38 markus 609:
1.40 markus 610: /*
611: * Check that the versions match. In future this might accept
612: * several versions and set appropriate flags to handle them.
613: */
1.59 markus 614: if (sscanf(server_version_string, "SSH-%d.%d-%[^\n]\n",
615: &remote_major, &remote_minor, remote_version) != 3)
1.38 markus 616: fatal("Bad remote protocol version identification: '%.100s'", buf);
617: debug("Remote protocol version %d.%d, remote software version %.100s",
1.118 deraadt 618: remote_major, remote_minor, remote_version);
1.38 markus 619:
1.59 markus 620: compat_datafellows(remote_version);
1.64 markus 621: mismatch = 0;
1.59 markus 622:
1.116 deraadt 623: switch (remote_major) {
1.64 markus 624: case 1:
625: if (remote_minor == 99 &&
626: (options.protocol & SSH_PROTO_2) &&
627: !(options.protocol & SSH_PROTO_1_PREFERRED)) {
628: enable_compat20();
629: break;
630: }
631: if (!(options.protocol & SSH_PROTO_1)) {
632: mismatch = 1;
633: break;
634: }
635: if (remote_minor < 3) {
636: fatal("Remote machine has too old SSH software version.");
1.81 markus 637: } else if (remote_minor == 3 || remote_minor == 4) {
1.64 markus 638: /* We speak 1.3, too. */
639: enable_compat13();
1.81 markus 640: minor1 = 3;
1.64 markus 641: if (options.forward_agent) {
1.138 itojun 642: logit("Agent forwarding disabled for protocol 1.3");
1.64 markus 643: options.forward_agent = 0;
644: }
645: }
646: break;
647: case 2:
648: if (options.protocol & SSH_PROTO_2) {
649: enable_compat20();
650: break;
1.38 markus 651: }
1.64 markus 652: /* FALLTHROUGH */
1.68 markus 653: default:
1.64 markus 654: mismatch = 1;
655: break;
1.38 markus 656: }
1.64 markus 657: if (mismatch)
1.38 markus 658: fatal("Protocol major versions differ: %d vs. %d",
1.64 markus 659: (options.protocol & SSH_PROTO_2) ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
660: remote_major);
1.244 djm 661: if ((datafellows & SSH_BUG_DERIVEKEY) != 0)
662: fatal("Server version \"%.100s\" uses unsafe key agreement; "
663: "refusing connection", remote_version);
1.243 djm 664: if ((datafellows & SSH_BUG_RSASIGMD5) != 0)
665: logit("Server version \"%.100s\" uses unsafe RSA signature "
666: "scheme; disabling use of RSA keys", remote_version);
1.235 djm 667: if (!client_banner_sent)
668: send_client_banner(connection_out, minor1);
1.59 markus 669: chop(server_version_string);
1.1 deraadt 670: }
671:
1.96 markus 672: /* defaults to 'no' */
1.109 itojun 673: static int
1.112 markus 674: confirm(const char *prompt)
1.1 deraadt 675: {
1.119 markus 676: const char *msg, *again = "Please type 'yes' or 'no': ";
677: char *p;
678: int ret = -1;
1.96 markus 679:
680: if (options.batch_mode)
681: return 0;
1.119 markus 682: for (msg = prompt;;msg = again) {
683: p = read_passphrase(msg, RP_ECHO);
684: if (p == NULL ||
685: (p[0] == '\0') || (p[0] == '\n') ||
686: strncasecmp(p, "no", 2) == 0)
687: ret = 0;
1.127 markus 688: if (p && strncasecmp(p, "yes", 3) == 0)
1.119 markus 689: ret = 1;
1.238 djm 690: free(p);
1.119 markus 691: if (ret != -1)
692: return ret;
1.1 deraadt 693: }
694: }
695:
1.219 djm 696: static int
697: check_host_cert(const char *host, const Key *host_key)
698: {
699: const char *reason;
700:
701: if (key_cert_check_authority(host_key, 1, 0, host, &reason) != 0) {
702: error("%s", reason);
703: return 0;
704: }
1.249 djm 705: if (buffer_len(host_key->cert->critical) != 0) {
1.223 djm 706: error("Certificate for %s contains unsupported "
707: "critical options(s)", host);
1.219 djm 708: return 0;
709: }
710: return 1;
711: }
712:
1.229 djm 713: static int
714: sockaddr_is_local(struct sockaddr *hostaddr)
715: {
716: switch (hostaddr->sa_family) {
717: case AF_INET:
718: return (ntohl(((struct sockaddr_in *)hostaddr)->
719: sin_addr.s_addr) >> 24) == IN_LOOPBACKNET;
720: case AF_INET6:
721: return IN6_IS_ADDR_LOOPBACK(
722: &(((struct sockaddr_in6 *)hostaddr)->sin6_addr));
723: default:
724: return 0;
725: }
726: }
727:
728: /*
729: * Prepare the hostname and ip address strings that are used to lookup
730: * host keys in known_hosts files. These may have a port number appended.
731: */
732: void
733: get_hostfile_hostname_ipaddr(char *hostname, struct sockaddr *hostaddr,
734: u_short port, char **hostfile_hostname, char **hostfile_ipaddr)
735: {
736: char ntop[NI_MAXHOST];
737:
738: /*
739: * We don't have the remote ip-address for connections
740: * using a proxy command
741: */
742: if (hostfile_ipaddr != NULL) {
743: if (options.proxy_command == NULL) {
744: if (getnameinfo(hostaddr, hostaddr->sa_len,
745: ntop, sizeof(ntop), NULL, 0, NI_NUMERICHOST) != 0)
746: fatal("check_host_key: getnameinfo failed");
747: *hostfile_ipaddr = put_host_port(ntop, port);
748: } else {
749: *hostfile_ipaddr = xstrdup("<no hostip for proxy "
750: "command>");
751: }
752: }
753:
754: /*
755: * Allow the user to record the key under a different name or
756: * differentiate a non-standard port. This is useful for ssh
757: * tunneling over forwarded connections or if you run multiple
758: * sshd's on different ports on the same machine.
759: */
760: if (hostfile_hostname != NULL) {
761: if (options.host_key_alias != NULL) {
762: *hostfile_hostname = xstrdup(options.host_key_alias);
763: debug("using hostkeyalias: %s", *hostfile_hostname);
764: } else {
765: *hostfile_hostname = put_host_port(hostname, port);
766: }
767: }
768: }
769:
1.39 deraadt 770: /*
1.108 markus 771: * check whether the supplied host key is valid, return -1 if the key
1.234 djm 772: * is not valid. user_hostfile[0] will not be updated if 'readonly' is true.
1.39 deraadt 773: */
1.197 dtucker 774: #define RDRW 0
775: #define RDONLY 1
776: #define ROQUIET 2
1.109 itojun 777: static int
1.197 dtucker 778: check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
1.234 djm 779: Key *host_key, int readonly,
780: char **user_hostfiles, u_int num_user_hostfiles,
781: char **system_hostfiles, u_int num_system_hostfiles)
1.1 deraadt 782: {
1.234 djm 783: HostStatus host_status;
784: HostStatus ip_status;
1.229 djm 785: Key *raw_key = NULL;
1.189 dtucker 786: char *ip = NULL, *host = NULL;
1.204 grunk 787: char hostline[1000], *hostp, *fp, *ra;
1.119 markus 788: char msg[1024];
1.234 djm 789: const char *type;
790: const struct hostkey_entry *host_found, *ip_found;
1.229 djm 791: int len, cancelled_forwarding = 0;
1.234 djm 792: int local = sockaddr_is_local(hostaddr);
793: int r, want_cert = key_is_cert(host_key), host_ip_differ = 0;
1.229 djm 794: struct hostkeys *host_hostkeys, *ip_hostkeys;
1.234 djm 795: u_int i;
1.49 markus 796:
797: /*
798: * Force accepting of the host key for loopback/localhost. The
799: * problem is that if the home directory is NFS-mounted to multiple
800: * machines, localhost will refer to a different machine in each of
801: * them, and the user will get bogus HOST_CHANGED warnings. This
802: * essentially disables host authentication for localhost; however,
803: * this is probably not a real problem.
804: */
1.111 markus 805: if (options.no_host_authentication_for_localhost == 1 && local &&
806: options.host_key_alias == NULL) {
1.88 markus 807: debug("Forcing accepting of host key for "
808: "loopback/localhost.");
1.108 markus 809: return 0;
1.49 markus 810: }
1.42 markus 811:
812: /*
1.229 djm 813: * Prepare the hostname and address strings used for hostkey lookup.
814: * In some cases, these will have a port number appended.
1.42 markus 815: */
1.229 djm 816: get_hostfile_hostname_ipaddr(hostname, hostaddr, port, &host, &ip);
1.206 grunk 817:
818: /*
1.88 markus 819: * Turn off check_host_ip if the connection is to localhost, via proxy
820: * command or if we don't have a hostname to compare with
821: */
1.189 dtucker 822: if (options.check_host_ip && (local ||
823: strcmp(hostname, ip) == 0 || options.proxy_command != NULL))
1.88 markus 824: options.check_host_ip = 0;
1.86 markus 825:
1.229 djm 826: host_hostkeys = init_hostkeys();
1.234 djm 827: for (i = 0; i < num_user_hostfiles; i++)
828: load_hostkeys(host_hostkeys, host, user_hostfiles[i]);
829: for (i = 0; i < num_system_hostfiles; i++)
830: load_hostkeys(host_hostkeys, host, system_hostfiles[i]);
1.229 djm 831:
832: ip_hostkeys = NULL;
833: if (!want_cert && options.check_host_ip) {
834: ip_hostkeys = init_hostkeys();
1.234 djm 835: for (i = 0; i < num_user_hostfiles; i++)
836: load_hostkeys(ip_hostkeys, ip, user_hostfiles[i]);
837: for (i = 0; i < num_system_hostfiles; i++)
838: load_hostkeys(ip_hostkeys, ip, system_hostfiles[i]);
1.84 markus 839: }
1.38 markus 840:
1.219 djm 841: retry:
1.229 djm 842: /* Reload these as they may have changed on cert->key downgrade */
1.219 djm 843: want_cert = key_is_cert(host_key);
844: type = key_type(host_key);
845:
1.46 markus 846: /*
1.170 djm 847: * Check if the host key is present in the user's list of known
1.40 markus 848: * hosts or in the systemwide list.
849: */
1.229 djm 850: host_status = check_key_in_hostkeys(host_hostkeys, host_key,
851: &host_found);
852:
1.40 markus 853: /*
854: * Also perform check for the ip address, skip the check if we are
1.219 djm 855: * localhost, looking for a certificate, or the hostname was an ip
856: * address to begin with.
1.40 markus 857: */
1.229 djm 858: if (!want_cert && ip_hostkeys != NULL) {
859: ip_status = check_key_in_hostkeys(ip_hostkeys, host_key,
860: &ip_found);
1.38 markus 861: if (host_status == HOST_CHANGED &&
1.229 djm 862: (ip_status != HOST_CHANGED ||
863: (ip_found != NULL &&
864: !key_equal(ip_found->key, host_found->key))))
1.38 markus 865: host_ip_differ = 1;
866: } else
867: ip_status = host_status;
868:
869: switch (host_status) {
870: case HOST_OK:
871: /* The host is known and the key matches. */
1.219 djm 872: debug("Host '%.200s' is known and matches the %s host %s.",
873: host, type, want_cert ? "certificate" : "key");
1.229 djm 874: debug("Found %s in %s:%lu", want_cert ? "CA key" : "key",
875: host_found->file, host_found->line);
1.219 djm 876: if (want_cert && !check_host_cert(hostname, host_key))
877: goto fail;
1.88 markus 878: if (options.check_host_ip && ip_status == HOST_NEW) {
1.219 djm 879: if (readonly || want_cert)
1.138 itojun 880: logit("%s host key for IP address "
1.108 markus 881: "'%.128s' not in list of known hosts.",
882: type, ip);
1.234 djm 883: else if (!add_host_to_hostfile(user_hostfiles[0], ip,
1.160 djm 884: host_key, options.hash_known_hosts))
1.138 itojun 885: logit("Failed to add the %s host key for IP "
1.108 markus 886: "address '%.128s' to the list of known "
1.234 djm 887: "hosts (%.30s).", type, ip,
888: user_hostfiles[0]);
1.88 markus 889: else
1.138 itojun 890: logit("Warning: Permanently added the %s host "
1.108 markus 891: "key for IP address '%.128s' to the list "
892: "of known hosts.", type, ip);
1.209 grunk 893: } else if (options.visual_host_key) {
1.204 grunk 894: fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
895: ra = key_fingerprint(host_key, SSH_FP_MD5,
896: SSH_FP_RANDOMART);
897: logit("Host key fingerprint is %s\n%s\n", fp, ra);
1.238 djm 898: free(ra);
899: free(fp);
1.38 markus 900: }
901: break;
902: case HOST_NEW:
1.197 dtucker 903: if (options.host_key_alias == NULL && port != 0 &&
904: port != SSH_DEFAULT_PORT) {
905: debug("checking without port identifier");
1.212 stevesk 906: if (check_host_key(hostname, hostaddr, 0, host_key,
1.234 djm 907: ROQUIET, user_hostfiles, num_user_hostfiles,
908: system_hostfiles, num_system_hostfiles) == 0) {
1.197 dtucker 909: debug("found matching key w/out port");
910: break;
911: }
912: }
1.219 djm 913: if (readonly || want_cert)
1.108 markus 914: goto fail;
1.38 markus 915: /* The host is new. */
916: if (options.strict_host_key_checking == 1) {
1.108 markus 917: /*
918: * User has requested strict host key checking. We
919: * will not add the host key automatically. The only
920: * alternative left is to abort.
921: */
922: error("No %s host key is known for %.200s and you "
923: "have requested strict checking.", type, host);
924: goto fail;
1.38 markus 925: } else if (options.strict_host_key_checking == 2) {
1.145 jakob 926: char msg1[1024], msg2[1024];
927:
1.229 djm 928: if (show_other_keys(host_hostkeys, host_key))
1.145 jakob 929: snprintf(msg1, sizeof(msg1),
1.168 djm 930: "\nbut keys of different type are already"
931: " known for this host.");
1.145 jakob 932: else
933: snprintf(msg1, sizeof(msg1), ".");
1.38 markus 934: /* The default */
1.100 markus 935: fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
1.204 grunk 936: ra = key_fingerprint(host_key, SSH_FP_MD5,
937: SSH_FP_RANDOMART);
1.145 jakob 938: msg2[0] = '\0';
939: if (options.verify_host_key_dns) {
1.153 jakob 940: if (matching_host_key_dns)
1.145 jakob 941: snprintf(msg2, sizeof(msg2),
942: "Matching host key fingerprint"
943: " found in DNS.\n");
944: else
945: snprintf(msg2, sizeof(msg2),
946: "No matching host key fingerprint"
947: " found in DNS.\n");
948: }
1.119 markus 949: snprintf(msg, sizeof(msg),
1.108 markus 950: "The authenticity of host '%.200s (%s)' can't be "
1.132 markus 951: "established%s\n"
1.209 grunk 952: "%s key fingerprint is %s.%s%s\n%s"
1.108 markus 953: "Are you sure you want to continue connecting "
1.132 markus 954: "(yes/no)? ",
1.209 grunk 955: host, ip, msg1, type, fp,
956: options.visual_host_key ? "\n" : "",
957: options.visual_host_key ? ra : "",
958: msg2);
1.238 djm 959: free(ra);
960: free(fp);
1.119 markus 961: if (!confirm(msg))
1.108 markus 962: goto fail;
1.38 markus 963: }
1.161 djm 964: /*
965: * If not in strict mode, add the key automatically to the
966: * local known_hosts file.
967: */
1.88 markus 968: if (options.check_host_ip && ip_status == HOST_NEW) {
1.229 djm 969: snprintf(hostline, sizeof(hostline), "%s,%s", host, ip);
1.38 markus 970: hostp = hostline;
1.161 djm 971: if (options.hash_known_hosts) {
972: /* Add hash of host and IP separately */
1.234 djm 973: r = add_host_to_hostfile(user_hostfiles[0],
974: host, host_key, options.hash_known_hosts) &&
975: add_host_to_hostfile(user_hostfiles[0], ip,
1.161 djm 976: host_key, options.hash_known_hosts);
977: } else {
978: /* Add unhashed "host,ip" */
1.234 djm 979: r = add_host_to_hostfile(user_hostfiles[0],
1.161 djm 980: hostline, host_key,
981: options.hash_known_hosts);
982: }
983: } else {
1.234 djm 984: r = add_host_to_hostfile(user_hostfiles[0], host,
985: host_key, options.hash_known_hosts);
1.38 markus 986: hostp = host;
1.161 djm 987: }
1.38 markus 988:
1.161 djm 989: if (!r)
1.138 itojun 990: logit("Failed to add the host to the list of known "
1.234 djm 991: "hosts (%.500s).", user_hostfiles[0]);
1.38 markus 992: else
1.138 itojun 993: logit("Warning: Permanently added '%.200s' (%s) to the "
1.108 markus 994: "list of known hosts.", hostp, type);
1.38 markus 995: break;
1.220 djm 996: case HOST_REVOKED:
997: error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
998: error("@ WARNING: REVOKED HOST KEY DETECTED! @");
999: error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1000: error("The %s host key for %s is marked as revoked.", type, host);
1001: error("This could mean that a stolen key is being used to");
1002: error("impersonate this host.");
1003:
1004: /*
1005: * If strict host key checking is in use, the user will have
1006: * to edit the key manually and we can only abort.
1007: */
1008: if (options.strict_host_key_checking) {
1009: error("%s host key for %.200s was revoked and you have "
1010: "requested strict checking.", type, host);
1011: goto fail;
1012: }
1013: goto continue_unsafe;
1014:
1.38 markus 1015: case HOST_CHANGED:
1.219 djm 1016: if (want_cert) {
1017: /*
1018: * This is only a debug() since it is valid to have
1019: * CAs with wildcard DNS matches that don't match
1020: * all hosts that one might visit.
1021: */
1022: debug("Host certificate authority does not "
1.229 djm 1023: "match %s in %s:%lu", CA_MARKER,
1024: host_found->file, host_found->line);
1.219 djm 1025: goto fail;
1026: }
1.197 dtucker 1027: if (readonly == ROQUIET)
1028: goto fail;
1.38 markus 1029: if (options.check_host_ip && host_ip_differ) {
1.158 avsm 1030: char *key_msg;
1.38 markus 1031: if (ip_status == HOST_NEW)
1.158 avsm 1032: key_msg = "is unknown";
1.38 markus 1033: else if (ip_status == HOST_OK)
1.158 avsm 1034: key_msg = "is unchanged";
1.38 markus 1035: else
1.158 avsm 1036: key_msg = "has a different value";
1.38 markus 1037: error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1038: error("@ WARNING: POSSIBLE DNS SPOOFING DETECTED! @");
1039: error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1.72 markus 1040: error("The %s host key for %s has changed,", type, host);
1.208 ian 1041: error("and the key for the corresponding IP address %s", ip);
1.158 avsm 1042: error("%s. This could either mean that", key_msg);
1.38 markus 1043: error("DNS SPOOFING is happening or the IP address for the host");
1.85 markus 1044: error("and its host key have changed at the same time.");
1.88 markus 1045: if (ip_status != HOST_NEW)
1.229 djm 1046: error("Offending key for IP in %s:%lu",
1047: ip_found->file, ip_found->line);
1.38 markus 1048: }
1049: /* The host key has changed. */
1.150 jakob 1050: warn_changed_key(host_key);
1.38 markus 1051: error("Add correct host key in %.100s to get rid of this message.",
1.234 djm 1052: user_hostfiles[0]);
1.229 djm 1053: error("Offending %s key in %s:%lu", key_type(host_found->key),
1054: host_found->file, host_found->line);
1.38 markus 1055:
1.40 markus 1056: /*
1057: * If strict host key checking is in use, the user will have
1058: * to edit the key manually and we can only abort.
1059: */
1.108 markus 1060: if (options.strict_host_key_checking) {
1061: error("%s host key for %.200s has changed and you have "
1062: "requested strict checking.", type, host);
1063: goto fail;
1064: }
1.38 markus 1065:
1.220 djm 1066: continue_unsafe:
1.40 markus 1067: /*
1068: * If strict host key checking has not been requested, allow
1.144 djm 1069: * the connection but without MITM-able authentication or
1.194 stevesk 1070: * forwarding.
1.40 markus 1071: */
1.38 markus 1072: if (options.password_authentication) {
1.108 markus 1073: error("Password authentication is disabled to avoid "
1074: "man-in-the-middle attacks.");
1.38 markus 1075: options.password_authentication = 0;
1.210 dtucker 1076: cancelled_forwarding = 1;
1.144 djm 1077: }
1078: if (options.kbd_interactive_authentication) {
1079: error("Keyboard-interactive authentication is disabled"
1080: " to avoid man-in-the-middle attacks.");
1081: options.kbd_interactive_authentication = 0;
1082: options.challenge_response_authentication = 0;
1.210 dtucker 1083: cancelled_forwarding = 1;
1.144 djm 1084: }
1085: if (options.challenge_response_authentication) {
1086: error("Challenge/response authentication is disabled"
1087: " to avoid man-in-the-middle attacks.");
1088: options.challenge_response_authentication = 0;
1.210 dtucker 1089: cancelled_forwarding = 1;
1.38 markus 1090: }
1091: if (options.forward_agent) {
1.108 markus 1092: error("Agent forwarding is disabled to avoid "
1093: "man-in-the-middle attacks.");
1.38 markus 1094: options.forward_agent = 0;
1.210 dtucker 1095: cancelled_forwarding = 1;
1.83 markus 1096: }
1097: if (options.forward_x11) {
1.108 markus 1098: error("X11 forwarding is disabled to avoid "
1099: "man-in-the-middle attacks.");
1.83 markus 1100: options.forward_x11 = 0;
1.210 dtucker 1101: cancelled_forwarding = 1;
1.83 markus 1102: }
1.108 markus 1103: if (options.num_local_forwards > 0 ||
1104: options.num_remote_forwards > 0) {
1105: error("Port forwarding is disabled to avoid "
1106: "man-in-the-middle attacks.");
1107: options.num_local_forwards =
1.118 deraadt 1108: options.num_remote_forwards = 0;
1.210 dtucker 1109: cancelled_forwarding = 1;
1.194 stevesk 1110: }
1111: if (options.tun_open != SSH_TUNMODE_NO) {
1112: error("Tunnel forwarding is disabled to avoid "
1113: "man-in-the-middle attacks.");
1114: options.tun_open = SSH_TUNMODE_NO;
1.210 dtucker 1115: cancelled_forwarding = 1;
1.38 markus 1116: }
1.210 dtucker 1117: if (options.exit_on_forward_failure && cancelled_forwarding)
1118: fatal("Error: forwarding disabled due to host key "
1119: "check failure");
1120:
1.40 markus 1121: /*
1122: * XXX Should permit the user to change to use the new id.
1123: * This could be done by converting the host key to an
1124: * identifying sentence, tell that the host identifies itself
1.218 dtucker 1125: * by that sentence, and ask the user if he/she wishes to
1.40 markus 1126: * accept the authentication.
1127: */
1.38 markus 1128: break;
1.132 markus 1129: case HOST_FOUND:
1130: fatal("internal error");
1131: break;
1.88 markus 1132: }
1133:
1134: if (options.check_host_ip && host_status != HOST_CHANGED &&
1135: ip_status == HOST_CHANGED) {
1.119 markus 1136: snprintf(msg, sizeof(msg),
1137: "Warning: the %s host key for '%.200s' "
1138: "differs from the key for the IP address '%.128s'"
1.229 djm 1139: "\nOffending key for IP in %s:%lu",
1140: type, host, ip, ip_found->file, ip_found->line);
1.119 markus 1141: if (host_status == HOST_OK) {
1142: len = strlen(msg);
1143: snprintf(msg + len, sizeof(msg) - len,
1.229 djm 1144: "\nMatching host key in %s:%lu",
1145: host_found->file, host_found->line);
1.119 markus 1146: }
1.88 markus 1147: if (options.strict_host_key_checking == 1) {
1.143 djm 1148: logit("%s", msg);
1.108 markus 1149: error("Exiting, you have requested strict checking.");
1150: goto fail;
1.88 markus 1151: } else if (options.strict_host_key_checking == 2) {
1.119 markus 1152: strlcat(msg, "\nAre you sure you want "
1153: "to continue connecting (yes/no)? ", sizeof(msg));
1154: if (!confirm(msg))
1.108 markus 1155: goto fail;
1.119 markus 1156: } else {
1.143 djm 1157: logit("%s", msg);
1.88 markus 1158: }
1.38 markus 1159: }
1.82 provos 1160:
1.238 djm 1161: free(ip);
1162: free(host);
1.229 djm 1163: if (host_hostkeys != NULL)
1164: free_hostkeys(host_hostkeys);
1165: if (ip_hostkeys != NULL)
1166: free_hostkeys(ip_hostkeys);
1.108 markus 1167: return 0;
1168:
1169: fail:
1.220 djm 1170: if (want_cert && host_status != HOST_REVOKED) {
1.219 djm 1171: /*
1172: * No matching certificate. Downgrade cert to raw key and
1173: * search normally.
1174: */
1175: debug("No matching CA found. Retry with plain key");
1176: raw_key = key_from_private(host_key);
1177: if (key_drop_cert(raw_key) != 0)
1178: fatal("Couldn't drop certificate");
1179: host_key = raw_key;
1180: goto retry;
1181: }
1182: if (raw_key != NULL)
1183: key_free(raw_key);
1.238 djm 1184: free(ip);
1185: free(host);
1.229 djm 1186: if (host_hostkeys != NULL)
1187: free_hostkeys(host_hostkeys);
1188: if (ip_hostkeys != NULL)
1189: free_hostkeys(ip_hostkeys);
1.108 markus 1190: return -1;
1191: }
1192:
1.140 jakob 1193: /* returns 0 if key verifies or -1 if key does NOT verify */
1.108 markus 1194: int
1195: verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
1196: {
1.250 djm 1197: int r = -1, flags = 0;
1.252 ! djm 1198: char *fp = NULL;
! 1199: struct sshkey *plain = NULL;
1.229 djm 1200:
1.252 ! djm 1201: if ((fp = sshkey_fingerprint(host_key,
! 1202: SSH_FP_MD5, SSH_FP_HEX)) == NULL) {
! 1203: error("%s: fingerprint host key: %s", __func__, ssh_err(r));
! 1204: r = -1;
! 1205: goto out;
! 1206: }
! 1207:
! 1208: debug("Server host key: %s %s", sshkey_type(host_key), fp);
! 1209:
! 1210: if (sshkey_equal(previous_host_key, host_key)) {
! 1211: debug2("%s: server host key %s %s matches cached key",
! 1212: __func__, sshkey_type(host_key), fp);
! 1213: r = 0;
! 1214: goto out;
! 1215: }
! 1216:
! 1217: /* Check in RevokedHostKeys file if specified */
! 1218: if (options.revoked_host_keys != NULL) {
! 1219: r = sshkey_check_revoked(host_key, options.revoked_host_keys);
! 1220: switch (r) {
! 1221: case 0:
! 1222: break; /* not revoked */
! 1223: case SSH_ERR_KEY_REVOKED:
! 1224: error("Host key %s %s revoked by file %s",
! 1225: sshkey_type(host_key), fp,
! 1226: options.revoked_host_keys);
! 1227: r = -1;
! 1228: goto out;
! 1229: default:
! 1230: error("Error checking host key %s %s in "
! 1231: "revoked keys file %s: %s", sshkey_type(host_key),
! 1232: fp, options.revoked_host_keys, ssh_err(r));
! 1233: r = -1;
! 1234: goto out;
! 1235: }
1.250 djm 1236: }
1237:
1.247 djm 1238: if (options.verify_host_key_dns) {
1239: /*
1240: * XXX certs are not yet supported for DNS, so downgrade
1241: * them and try the plain key.
1242: */
1.252 ! djm 1243: if ((r = sshkey_from_private(host_key, &plain)) != 0)
! 1244: goto out;
! 1245: if (sshkey_is_cert(plain))
! 1246: sshkey_drop_cert(plain);
1.247 djm 1247: if (verify_host_key_dns(host, hostaddr, plain, &flags) == 0) {
1248: if (flags & DNS_VERIFY_FOUND) {
1249: if (options.verify_host_key_dns == 1 &&
1250: flags & DNS_VERIFY_MATCH &&
1251: flags & DNS_VERIFY_SECURE) {
1.250 djm 1252: r = 0;
1.252 ! djm 1253: goto out;
1.247 djm 1254: }
1255: if (flags & DNS_VERIFY_MATCH) {
1256: matching_host_key_dns = 1;
1257: } else {
1258: warn_changed_key(plain);
1259: error("Update the SSHFP RR in DNS "
1260: "with the new host key to get rid "
1261: "of this message.");
1262: }
1.153 jakob 1263: }
1.140 jakob 1264: }
1265: }
1.250 djm 1266: r = check_host_key(host, hostaddr, options.port, host_key, RDRW,
1.234 djm 1267: options.user_hostfiles, options.num_user_hostfiles,
1268: options.system_hostfiles, options.num_system_hostfiles);
1.250 djm 1269:
1.252 ! djm 1270: out:
! 1271: sshkey_free(plain);
! 1272: free(fp);
1.250 djm 1273: if (r == 0 && host_key != NULL) {
1274: key_free(previous_host_key);
1275: previous_host_key = key_from_private(host_key);
1276: }
1277:
1278: return r;
1.51 markus 1279: }
1.70 markus 1280:
1.51 markus 1281: /*
1282: * Starts a dialog with the server, and authenticates the current user on the
1283: * server. This does not need any extra privileges. The basic connection
1284: * to the server must already have been established before this is called.
1285: * If login fails, this function prints an error and never returns.
1286: * This function does not require super-user privileges.
1287: */
1288: void
1.120 markus 1289: ssh_login(Sensitive *sensitive, const char *orighost,
1.229 djm 1290: struct sockaddr *hostaddr, u_short port, struct passwd *pw, int timeout_ms)
1.51 markus 1291: {
1.241 djm 1292: char *host;
1.70 markus 1293: char *server_user, *local_user;
1294:
1295: local_user = xstrdup(pw->pw_name);
1296: server_user = options.user ? options.user : local_user;
1.51 markus 1297:
1298: /* Convert the user-supplied hostname into all lowercase. */
1299: host = xstrdup(orighost);
1.241 djm 1300: lowercase(host);
1.51 markus 1301:
1302: /* Exchange protocol version identification strings with the server. */
1.202 djm 1303: ssh_exchange_identification(timeout_ms);
1.51 markus 1304:
1305: /* Put the connection into non-blocking mode. */
1306: packet_set_nonblocking();
1307:
1308: /* key exchange */
1309: /* authenticate user */
1.59 markus 1310: if (compat20) {
1.229 djm 1311: ssh_kex2(host, hostaddr, port);
1.120 markus 1312: ssh_userauth2(local_user, server_user, host, sensitive);
1.59 markus 1313: } else {
1.248 markus 1314: #ifdef WITH_SSH1
1.59 markus 1315: ssh_kex(host, hostaddr);
1.120 markus 1316: ssh_userauth1(local_user, server_user, host, sensitive);
1.248 markus 1317: #else
1318: fatal("ssh1 is not unsupported");
1319: #endif
1.59 markus 1320: }
1.238 djm 1321: free(local_user);
1.97 markus 1322: }
1323:
1324: void
1325: ssh_put_password(char *password)
1326: {
1327: int size;
1328: char *padded;
1329:
1.99 deraadt 1330: if (datafellows & SSH_BUG_PASSWORDPAD) {
1.107 markus 1331: packet_put_cstring(password);
1.99 deraadt 1332: return;
1333: }
1.97 markus 1334: size = roundup(strlen(password) + 1, 32);
1.179 djm 1335: padded = xcalloc(1, size);
1.97 markus 1336: strlcpy(padded, password, size);
1337: packet_put_string(padded, size);
1.245 djm 1338: explicit_bzero(padded, size);
1.238 djm 1339: free(padded);
1.132 markus 1340: }
1341:
1342: /* print all known host keys for a given host, but skip keys of given type */
1343: static int
1.229 djm 1344: show_other_keys(struct hostkeys *hostkeys, Key *key)
1.132 markus 1345: {
1.242 djm 1346: int type[] = {
1347: KEY_RSA1,
1348: KEY_RSA,
1349: KEY_DSA,
1350: KEY_ECDSA,
1351: KEY_ED25519,
1352: -1
1353: };
1.229 djm 1354: int i, ret = 0;
1355: char *fp, *ra;
1356: const struct hostkey_entry *found;
1.132 markus 1357:
1358: for (i = 0; type[i] != -1; i++) {
1359: if (type[i] == key->type)
1360: continue;
1.229 djm 1361: if (!lookup_key_in_hostkeys_by_type(hostkeys, type[i], &found))
1.132 markus 1362: continue;
1.229 djm 1363: fp = key_fingerprint(found->key, SSH_FP_MD5, SSH_FP_HEX);
1364: ra = key_fingerprint(found->key, SSH_FP_MD5, SSH_FP_RANDOMART);
1365: logit("WARNING: %s key found for host %s\n"
1366: "in %s:%lu\n"
1367: "%s key fingerprint %s.",
1368: key_type(found->key),
1369: found->host, found->file, found->line,
1370: key_type(found->key), fp);
1371: if (options.visual_host_key)
1372: logit("%s", ra);
1.238 djm 1373: free(ra);
1374: free(fp);
1.229 djm 1375: ret = 1;
1.132 markus 1376: }
1.229 djm 1377: return ret;
1.150 jakob 1378: }
1379:
1380: static void
1381: warn_changed_key(Key *host_key)
1382: {
1383: char *fp;
1384:
1385: fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
1386:
1387: error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1388: error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @");
1389: error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1390: error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!");
1391: error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!");
1.230 markus 1392: error("It is also possible that a host key has just been changed.");
1.150 jakob 1393: error("The fingerprint for the %s key sent by the remote host is\n%s.",
1.230 markus 1394: key_type(host_key), fp);
1.150 jakob 1395: error("Please contact your system administrator.");
1396:
1.238 djm 1397: free(fp);
1.171 reyk 1398: }
1399:
1400: /*
1401: * Execute a local command
1402: */
1403: int
1404: ssh_local_cmd(const char *args)
1405: {
1406: char *shell;
1407: pid_t pid;
1408: int status;
1.231 djm 1409: void (*osighand)(int);
1.171 reyk 1410:
1411: if (!options.permit_local_command ||
1412: args == NULL || !*args)
1413: return (1);
1414:
1.226 djm 1415: if ((shell = getenv("SHELL")) == NULL || *shell == '\0')
1.171 reyk 1416: shell = _PATH_BSHELL;
1417:
1.231 djm 1418: osighand = signal(SIGCHLD, SIG_DFL);
1.171 reyk 1419: pid = fork();
1420: if (pid == 0) {
1.232 djm 1421: signal(SIGPIPE, SIG_DFL);
1.171 reyk 1422: debug3("Executing %s -c \"%s\"", shell, args);
1423: execl(shell, shell, "-c", args, (char *)NULL);
1424: error("Couldn't execute %s -c \"%s\": %s",
1425: shell, args, strerror(errno));
1426: _exit(1);
1427: } else if (pid == -1)
1428: fatal("fork failed: %.100s", strerror(errno));
1429: while (waitpid(pid, &status, 0) == -1)
1430: if (errno != EINTR)
1431: fatal("Couldn't wait for child: %s", strerror(errno));
1.231 djm 1432: signal(SIGCHLD, osighand);
1.171 reyk 1433:
1434: if (!WIFEXITED(status))
1435: return (1);
1436:
1437: return (WEXITSTATUS(status));
1.1 deraadt 1438: }