source: trunk/third/openssh/sshconnect.c @ 18759

Revision 18759, 26.2 KB checked in by zacheiss, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18758, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * Author: Tatu Ylonen <ylo@cs.hut.fi>
3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4 *                    All rights reserved
5 * Code to connect to a remote host, and to perform the client side of the
6 * login (authentication) dialog.
7 *
8 * As far as I am concerned, the code I have written for this software
9 * can be used freely for any purpose.  Any derived versions of this
10 * software must be clearly marked as such, and if the derived work is
11 * incompatible with the protocol description in the RFC file, it must be
12 * called by a name other than "ssh" or "Secure Shell".
13 */
14
15#include "includes.h"
16RCSID("$OpenBSD: sshconnect.c,v 1.135 2002/09/19 01:58:18 djm Exp $");
17
18#include <openssl/bn.h>
19
20#include "ssh.h"
21#include "xmalloc.h"
22#include "rsa.h"
23#include "buffer.h"
24#include "packet.h"
25#include "uidswap.h"
26#include "compat.h"
27#include "key.h"
28#include "sshconnect.h"
29#include "hostfile.h"
30#include "log.h"
31#include "readconf.h"
32#include "atomicio.h"
33#include "misc.h"
34#include "readpass.h"
35
36char *client_version_string = NULL;
37char *server_version_string = NULL;
38
39/* import */
40extern Options options;
41extern char *__progname;
42extern uid_t original_real_uid;
43extern uid_t original_effective_uid;
44extern pid_t proxy_command_pid;
45
46#ifndef INET6_ADDRSTRLEN                /* for non IPv6 machines */
47#define INET6_ADDRSTRLEN 46
48#endif
49
50static int show_other_keys(const char *, Key *);
51
52/*
53 * Connect to the given ssh server using a proxy command.
54 */
55static int
56ssh_proxy_connect(const char *host, u_short port, const char *proxy_command)
57{
58        Buffer command;
59        const char *cp;
60        char *command_string;
61        int pin[2], pout[2];
62        pid_t pid;
63        char strport[NI_MAXSERV];
64
65        /* Convert the port number into a string. */
66        snprintf(strport, sizeof strport, "%hu", port);
67
68        /*
69         * Build the final command string in the buffer by making the
70         * appropriate substitutions to the given proxy command.
71         *
72         * Use "exec" to avoid "sh -c" processes on some platforms
73         * (e.g. Solaris)
74         */
75        buffer_init(&command);
76        buffer_append(&command, "exec ", 5);
77
78        for (cp = proxy_command; *cp; cp++) {
79                if (cp[0] == '%' && cp[1] == '%') {
80                        buffer_append(&command, "%", 1);
81                        cp++;
82                        continue;
83                }
84                if (cp[0] == '%' && cp[1] == 'h') {
85                        buffer_append(&command, host, strlen(host));
86                        cp++;
87                        continue;
88                }
89                if (cp[0] == '%' && cp[1] == 'p') {
90                        buffer_append(&command, strport, strlen(strport));
91                        cp++;
92                        continue;
93                }
94                buffer_append(&command, cp, 1);
95        }
96        buffer_append(&command, "\0", 1);
97
98        /* Get the final command string. */
99        command_string = buffer_ptr(&command);
100
101        /* Create pipes for communicating with the proxy. */
102        if (pipe(pin) < 0 || pipe(pout) < 0)
103                fatal("Could not create pipes to communicate with the proxy: %.100s",
104                    strerror(errno));
105
106        debug("Executing proxy command: %.500s", command_string);
107
108        /* Fork and execute the proxy command. */
109        if ((pid = fork()) == 0) {
110                char *argv[10];
111
112                /* Child.  Permanently give up superuser privileges. */
113                seteuid(original_real_uid);
114                setuid(original_real_uid);
115
116                /* Redirect stdin and stdout. */
117                close(pin[1]);
118                if (pin[0] != 0) {
119                        if (dup2(pin[0], 0) < 0)
120                                perror("dup2 stdin");
121                        close(pin[0]);
122                }
123                close(pout[0]);
124                if (dup2(pout[1], 1) < 0)
125                        perror("dup2 stdout");
126                /* Cannot be 1 because pin allocated two descriptors. */
127                close(pout[1]);
128
129                /* Stderr is left as it is so that error messages get
130                   printed on the user's terminal. */
131                argv[0] = _PATH_BSHELL;
132                argv[1] = "-c";
133                argv[2] = command_string;
134                argv[3] = NULL;
135
136                /* Execute the proxy command.  Note that we gave up any
137                   extra privileges above. */
138                execv(argv[0], argv);
139                perror(argv[0]);
140                exit(1);
141        }
142        /* Parent. */
143        if (pid < 0)
144                fatal("fork failed: %.100s", strerror(errno));
145        else
146                proxy_command_pid = pid; /* save pid to clean up later */
147
148        /* Close child side of the descriptors. */
149        close(pin[0]);
150        close(pout[1]);
151
152        /* Free the command name. */
153        buffer_free(&command);
154
155        /* Set the connection file descriptors. */
156        packet_set_connection(pout[0], pin[1]);
157
158        /* Indicate OK return */
159        return 0;
160}
161
162/*
163 * Creates a (possibly privileged) socket for use as the ssh connection.
164 */
165static int
166ssh_create_socket(int privileged, int family)
167{
168        int sock, gaierr;
169        struct addrinfo hints, *res;
170
171        /*
172         * If we are running as root and want to connect to a privileged
173         * port, bind our own socket to a privileged port.
174         */
175        if (privileged) {
176                int p = IPPORT_RESERVED - 1;
177                PRIV_START;
178                sock = rresvport_af(&p, family);
179                PRIV_END;
180                if (sock < 0)
181                        error("rresvport: af=%d %.100s", family, strerror(errno));
182                else
183                        debug("Allocated local port %d.", p);
184                return sock;
185        }
186        sock = socket(family, SOCK_STREAM, 0);
187        if (sock < 0)
188                error("socket: %.100s", strerror(errno));
189
190        /* Bind the socket to an alternative local IP address */
191        if (options.bind_address == NULL)
192                return sock;
193
194        memset(&hints, 0, sizeof(hints));
195        hints.ai_family = family;
196        hints.ai_socktype = SOCK_STREAM;
197        hints.ai_flags = AI_PASSIVE;
198        gaierr = getaddrinfo(options.bind_address, "0", &hints, &res);
199        if (gaierr) {
200                error("getaddrinfo: %s: %s", options.bind_address,
201                    gai_strerror(gaierr));
202                close(sock);
203                return -1;
204        }
205        if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
206                error("bind: %s: %s", options.bind_address, strerror(errno));
207                close(sock);
208                freeaddrinfo(res);
209                return -1;
210        }
211        freeaddrinfo(res);
212        return sock;
213}
214
215/*
216 * Opens a TCP/IP connection to the remote server on the given host.
217 * The address of the remote host will be returned in hostaddr.
218 * If port is 0, the default port will be used.  If needpriv is true,
219 * a privileged port will be allocated to make the connection.
220 * This requires super-user privileges if needpriv is true.
221 * Connection_attempts specifies the maximum number of tries (one per
222 * second).  If proxy_command is non-NULL, it specifies the command (with %h
223 * and %p substituted for host and port, respectively) to use to contact
224 * the daemon.
225 * Return values:
226 *    0 for OK
227 *    ECONNREFUSED if we got a "Connection Refused" by the peer on any address
228 *    ECONNABORTED if we failed without a "Connection refused"
229 * Suitable error messages for the connection failure will already have been
230 * printed.
231 */
232int
233ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
234    u_short port, int family, int connection_attempts,
235    int needpriv, const char *proxy_command)
236{
237        int gaierr;
238        int on = 1;
239        int sock = -1, attempt;
240        char ntop[NI_MAXHOST], strport[NI_MAXSERV];
241        struct addrinfo hints, *ai, *aitop;
242        struct servent *sp;
243        /*
244         * Did we get only other errors than "Connection refused" (which
245         * should block fallback to rsh and similar), or did we get at least
246         * one "Connection refused"?
247         */
248        int full_failure = 1;
249
250        debug("ssh_connect: needpriv %d", needpriv);
251
252        /* Get default port if port has not been set. */
253        if (port == 0) {
254                sp = getservbyname(SSH_SERVICE_NAME, "tcp");
255                if (sp)
256                        port = ntohs(sp->s_port);
257                else
258                        port = SSH_DEFAULT_PORT;
259        }
260        /* If a proxy command is given, connect using it. */
261        if (proxy_command != NULL)
262                return ssh_proxy_connect(host, port, proxy_command);
263
264        /* No proxy command. */
265
266        memset(&hints, 0, sizeof(hints));
267        hints.ai_family = family;
268        hints.ai_socktype = SOCK_STREAM;
269        snprintf(strport, sizeof strport, "%u", port);
270        if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0)
271                fatal("%s: %.100s: %s", __progname, host,
272                    gai_strerror(gaierr));
273
274        /*
275         * Try to connect several times.  On some machines, the first time
276         * will sometimes fail.  In general socket code appears to behave
277         * quite magically on many machines.
278                 */
279        for (attempt = 0; ;) {
280                if (attempt > 0)
281                        debug("Trying again...");
282
283                /* Loop through addresses for this host, and try each one in
284                   sequence until the connection succeeds. */
285                for (ai = aitop; ai; ai = ai->ai_next) {
286                        if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
287                                continue;
288                        if (getnameinfo(ai->ai_addr, ai->ai_addrlen,
289                            ntop, sizeof(ntop), strport, sizeof(strport),
290                            NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
291                                error("ssh_connect: getnameinfo failed");
292                                continue;
293                        }
294                        debug("Connecting to %.200s [%.100s] port %s.",
295                                host, ntop, strport);
296
297                        /* Create a socket for connecting. */
298                        sock = ssh_create_socket(needpriv, ai->ai_family);
299                        if (sock < 0)
300                                /* Any error is already output */
301                                continue;
302
303                        if (connect(sock, ai->ai_addr, ai->ai_addrlen) >= 0) {
304                                /* Successful connection. */
305                                memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen);
306                                break;
307                        } else {
308                                if (errno == ECONNREFUSED)
309                                        full_failure = 0;
310                                debug("connect to address %s port %s: %s",
311                                    ntop, strport, strerror(errno));
312                                /*
313                                 * Close the failed socket; there appear to
314                                 * be some problems when reusing a socket for
315                                 * which connect() has already returned an
316                                 * error.
317                                 */
318                                close(sock);
319                        }
320                }
321                if (ai)
322                        break;  /* Successful connection. */
323
324                attempt++;
325                if (attempt >= connection_attempts)
326                        break;
327                /* Sleep a moment before retrying. */
328                sleep(1);
329        }
330
331        freeaddrinfo(aitop);
332
333        /* Return failure if we didn't get a successful connection. */
334        if (attempt >= connection_attempts) {
335                log("ssh: connect to host %s port %s: %s",
336                    host, strport, strerror(errno));
337                return full_failure ? ECONNABORTED : ECONNREFUSED;
338        }
339
340        debug("Connection established.");
341
342        /* Set keepalives if requested. */
343        if (options.keepalives &&
344            setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on,
345            sizeof(on)) < 0)
346                error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno));
347
348        /* Set the connection. */
349        packet_set_connection(sock, sock);
350
351        return 0;
352}
353
354/*
355 * Waits for the server identification string, and sends our own
356 * identification string.
357 */
358static void
359ssh_exchange_identification(void)
360{
361        char buf[256], remote_version[256];     /* must be same size! */
362        int remote_major, remote_minor, i, mismatch;
363        int connection_in = packet_get_connection_in();
364        int connection_out = packet_get_connection_out();
365        int minor1 = PROTOCOL_MINOR_1;
366
367        /* Read other side\'s version identification. */
368        for (;;) {
369                for (i = 0; i < sizeof(buf) - 1; i++) {
370                        int len = atomicio(read, connection_in, &buf[i], 1);
371                        if (len < 0)
372                                fatal("ssh_exchange_identification: read: %.100s", strerror(errno));
373                        if (len != 1)
374                                fatal("ssh_exchange_identification: Connection closed by remote host");
375                        if (buf[i] == '\r') {
376                                buf[i] = '\n';
377                                buf[i + 1] = 0;
378                                continue;               /**XXX wait for \n */
379                        }
380                        if (buf[i] == '\n') {
381                                buf[i + 1] = 0;
382                                break;
383                        }
384                }
385                buf[sizeof(buf) - 1] = 0;
386                if (strncmp(buf, "SSH-", 4) == 0)
387                        break;
388                debug("ssh_exchange_identification: %s", buf);
389        }
390        server_version_string = xstrdup(buf);
391
392        /*
393         * Check that the versions match.  In future this might accept
394         * several versions and set appropriate flags to handle them.
395         */
396        if (sscanf(server_version_string, "SSH-%d.%d-%[^\n]\n",
397            &remote_major, &remote_minor, remote_version) != 3)
398                fatal("Bad remote protocol version identification: '%.100s'", buf);
399        debug("Remote protocol version %d.%d, remote software version %.100s",
400            remote_major, remote_minor, remote_version);
401
402        compat_datafellows(remote_version);
403        mismatch = 0;
404
405        switch (remote_major) {
406        case 1:
407                if (remote_minor == 99 &&
408                    (options.protocol & SSH_PROTO_2) &&
409                    !(options.protocol & SSH_PROTO_1_PREFERRED)) {
410                        enable_compat20();
411                        break;
412                }
413                if (!(options.protocol & SSH_PROTO_1)) {
414                        mismatch = 1;
415                        break;
416                }
417                if (remote_minor < 3) {
418                        fatal("Remote machine has too old SSH software version.");
419                } else if (remote_minor == 3 || remote_minor == 4) {
420                        /* We speak 1.3, too. */
421                        enable_compat13();
422                        minor1 = 3;
423                        if (options.forward_agent) {
424                                log("Agent forwarding disabled for protocol 1.3");
425                                options.forward_agent = 0;
426                        }
427                }
428                break;
429        case 2:
430                if (options.protocol & SSH_PROTO_2) {
431                        enable_compat20();
432                        break;
433                }
434                /* FALLTHROUGH */
435        default:
436                mismatch = 1;
437                break;
438        }
439        if (mismatch)
440                fatal("Protocol major versions differ: %d vs. %d",
441                    (options.protocol & SSH_PROTO_2) ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
442                    remote_major);
443        /* Send our own protocol version identification. */
444        snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n",
445            compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
446            compat20 ? PROTOCOL_MINOR_2 : minor1,
447            SSH_VERSION);
448        if (atomicio(write, connection_out, buf, strlen(buf)) != strlen(buf))
449                fatal("write: %.100s", strerror(errno));
450        client_version_string = xstrdup(buf);
451        chop(client_version_string);
452        chop(server_version_string);
453        debug("Local version string %.100s", client_version_string);
454}
455
456/* defaults to 'no' */
457static int
458confirm(const char *prompt)
459{
460        const char *msg, *again = "Please type 'yes' or 'no': ";
461        char *p;
462        int ret = -1;
463
464        if (options.batch_mode)
465                return 0;
466        for (msg = prompt;;msg = again) {
467                p = read_passphrase(msg, RP_ECHO);
468                if (p == NULL ||
469                    (p[0] == '\0') || (p[0] == '\n') ||
470                    strncasecmp(p, "no", 2) == 0)
471                        ret = 0;
472                if (p && strncasecmp(p, "yes", 3) == 0)
473                        ret = 1;
474                if (p)
475                        xfree(p);
476                if (ret != -1)
477                        return ret;
478        }
479}
480
481/*
482 * check whether the supplied host key is valid, return -1 if the key
483 * is not valid. the user_hostfile will not be updated if 'readonly' is true.
484 */
485static int
486check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
487    int readonly, const char *user_hostfile, const char *system_hostfile)
488{
489        Key *file_key;
490        char *type = key_type(host_key);
491        char *ip = NULL;
492        char hostline[1000], *hostp, *fp;
493        HostStatus host_status;
494        HostStatus ip_status;
495        int local = 0, host_ip_differ = 0;
496        int salen;
497        char ntop[NI_MAXHOST];
498        char msg[1024];
499        int len, host_line, ip_line, has_keys;
500        const char *host_file = NULL, *ip_file = NULL;
501
502        /*
503         * Force accepting of the host key for loopback/localhost. The
504         * problem is that if the home directory is NFS-mounted to multiple
505         * machines, localhost will refer to a different machine in each of
506         * them, and the user will get bogus HOST_CHANGED warnings.  This
507         * essentially disables host authentication for localhost; however,
508         * this is probably not a real problem.
509         */
510        /**  hostaddr == 0! */
511        switch (hostaddr->sa_family) {
512        case AF_INET:
513                local = (ntohl(((struct sockaddr_in *)hostaddr)->
514                   sin_addr.s_addr) >> 24) == IN_LOOPBACKNET;
515                salen = sizeof(struct sockaddr_in);
516                break;
517        case AF_INET6:
518                local = IN6_IS_ADDR_LOOPBACK(
519                    &(((struct sockaddr_in6 *)hostaddr)->sin6_addr));
520                salen = sizeof(struct sockaddr_in6);
521                break;
522        default:
523                local = 0;
524                salen = sizeof(struct sockaddr_storage);
525                break;
526        }
527        if (options.no_host_authentication_for_localhost == 1 && local &&
528            options.host_key_alias == NULL) {
529                debug("Forcing accepting of host key for "
530                    "loopback/localhost.");
531                return 0;
532        }
533
534        /*
535         * We don't have the remote ip-address for connections
536         * using a proxy command
537         */
538        if (options.proxy_command == NULL) {
539                if (getnameinfo(hostaddr, salen, ntop, sizeof(ntop),
540                    NULL, 0, NI_NUMERICHOST) != 0)
541                        fatal("check_host_key: getnameinfo failed");
542                ip = xstrdup(ntop);
543        } else {
544                ip = xstrdup("<no hostip for proxy command>");
545        }
546        /*
547         * Turn off check_host_ip if the connection is to localhost, via proxy
548         * command or if we don't have a hostname to compare with
549         */
550        if (options.check_host_ip &&
551            (local || strcmp(host, ip) == 0 || options.proxy_command != NULL))
552                options.check_host_ip = 0;
553
554        /*
555         * Allow the user to record the key under a different name. This is
556         * useful for ssh tunneling over forwarded connections or if you run
557         * multiple sshd's on different ports on the same machine.
558         */
559        if (options.host_key_alias != NULL) {
560                host = options.host_key_alias;
561                debug("using hostkeyalias: %s", host);
562        }
563
564        /*
565         * Store the host key from the known host file in here so that we can
566         * compare it with the key for the IP address.
567         */
568        file_key = key_new(host_key->type);
569
570        /*
571         * Check if the host key is present in the user\'s list of known
572         * hosts or in the systemwide list.
573         */
574        host_file = user_hostfile;
575        host_status = check_host_in_hostfile(host_file, host, host_key,
576            file_key, &host_line);
577        if (host_status == HOST_NEW) {
578                host_file = system_hostfile;
579                host_status = check_host_in_hostfile(host_file, host, host_key,
580                    file_key, &host_line);
581        }
582        /*
583         * Also perform check for the ip address, skip the check if we are
584         * localhost or the hostname was an ip address to begin with
585         */
586        if (options.check_host_ip) {
587                Key *ip_key = key_new(host_key->type);
588
589                ip_file = user_hostfile;
590                ip_status = check_host_in_hostfile(ip_file, ip, host_key,
591                    ip_key, &ip_line);
592                if (ip_status == HOST_NEW) {
593                        ip_file = system_hostfile;
594                        ip_status = check_host_in_hostfile(ip_file, ip,
595                            host_key, ip_key, &ip_line);
596                }
597                if (host_status == HOST_CHANGED &&
598                    (ip_status != HOST_CHANGED || !key_equal(ip_key, file_key)))
599                        host_ip_differ = 1;
600
601                key_free(ip_key);
602        } else
603                ip_status = host_status;
604
605        key_free(file_key);
606
607        switch (host_status) {
608        case HOST_OK:
609                /* The host is known and the key matches. */
610                debug("Host '%.200s' is known and matches the %s host key.",
611                    host, type);
612                debug("Found key in %s:%d", host_file, host_line);
613                if (options.check_host_ip && ip_status == HOST_NEW) {
614                        if (readonly)
615                                log("%s host key for IP address "
616                                    "'%.128s' not in list of known hosts.",
617                                    type, ip);
618                        else if (!add_host_to_hostfile(user_hostfile, ip,
619                            host_key))
620                                log("Failed to add the %s host key for IP "
621                                    "address '%.128s' to the list of known "
622                                    "hosts (%.30s).", type, ip, user_hostfile);
623                        else
624                                log("Warning: Permanently added the %s host "
625                                    "key for IP address '%.128s' to the list "
626                                    "of known hosts.", type, ip);
627                }
628                break;
629        case HOST_NEW:
630                if (readonly)
631                        goto fail;
632                /* The host is new. */
633                if (options.strict_host_key_checking == 1) {
634                        /*
635                         * User has requested strict host key checking.  We
636                         * will not add the host key automatically.  The only
637                         * alternative left is to abort.
638                         */
639                        error("No %s host key is known for %.200s and you "
640                            "have requested strict checking.", type, host);
641                        goto fail;
642                } else if (options.strict_host_key_checking == 2) {
643                        has_keys = show_other_keys(host, host_key);
644                        /* The default */
645                        fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
646                        snprintf(msg, sizeof(msg),
647                            "The authenticity of host '%.200s (%s)' can't be "
648                            "established%s\n"
649                            "%s key fingerprint is %s.\n"
650                            "Are you sure you want to continue connecting "
651                            "(yes/no)? ",
652                             host, ip,
653                             has_keys ? ",\nbut keys of different type are already "
654                             "known for this host." : ".",
655                             type, fp);
656                        xfree(fp);
657                        if (!confirm(msg))
658                                goto fail;
659                }
660                if (options.check_host_ip && ip_status == HOST_NEW) {
661                        snprintf(hostline, sizeof(hostline), "%s,%s", host, ip);
662                        hostp = hostline;
663                } else
664                        hostp = host;
665
666                /*
667                 * If not in strict mode, add the key automatically to the
668                 * local known_hosts file.
669                 */
670                if (!add_host_to_hostfile(user_hostfile, hostp, host_key))
671                        log("Failed to add the host to the list of known "
672                            "hosts (%.500s).", user_hostfile);
673                else
674                        log("Warning: Permanently added '%.200s' (%s) to the "
675                            "list of known hosts.", hostp, type);
676                break;
677        case HOST_CHANGED:
678                if (options.check_host_ip && host_ip_differ) {
679                        char *msg;
680                        if (ip_status == HOST_NEW)
681                                msg = "is unknown";
682                        else if (ip_status == HOST_OK)
683                                msg = "is unchanged";
684                        else
685                                msg = "has a different value";
686                        error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
687                        error("@       WARNING: POSSIBLE DNS SPOOFING DETECTED!          @");
688                        error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
689                        error("The %s host key for %s has changed,", type, host);
690                        error("and the key for the according IP address %s", ip);
691                        error("%s. This could either mean that", msg);
692                        error("DNS SPOOFING is happening or the IP address for the host");
693                        error("and its host key have changed at the same time.");
694                        if (ip_status != HOST_NEW)
695                                error("Offending key for IP in %s:%d", ip_file, ip_line);
696                }
697                /* The host key has changed. */
698                fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
699                error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
700                error("@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @");
701                error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
702                error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!");
703                error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!");
704                error("It is also possible that the %s host key has just been changed.", type);
705                error("The fingerprint for the %s key sent by the remote host is\n%s.",
706                    type, fp);
707                error("Please contact your system administrator.");
708                error("Add correct host key in %.100s to get rid of this message.",
709                    user_hostfile);
710                error("Offending key in %s:%d", host_file, host_line);
711                xfree(fp);
712
713                /*
714                 * If strict host key checking is in use, the user will have
715                 * to edit the key manually and we can only abort.
716                 */
717                if (options.strict_host_key_checking) {
718                        error("%s host key for %.200s has changed and you have "
719                            "requested strict checking.", type, host);
720                        goto fail;
721                }
722
723                /*
724                 * If strict host key checking has not been requested, allow
725                 * the connection but without password authentication or
726                 * agent forwarding.
727                 */
728                if (options.password_authentication) {
729                        error("Password authentication is disabled to avoid "
730                            "man-in-the-middle attacks.");
731                        options.password_authentication = 0;
732                }
733                if (options.forward_agent) {
734                        error("Agent forwarding is disabled to avoid "
735                            "man-in-the-middle attacks.");
736                        options.forward_agent = 0;
737                }
738                if (options.forward_x11) {
739                        error("X11 forwarding is disabled to avoid "
740                            "man-in-the-middle attacks.");
741                        options.forward_x11 = 0;
742                }
743                if (options.num_local_forwards > 0 ||
744                    options.num_remote_forwards > 0) {
745                        error("Port forwarding is disabled to avoid "
746                            "man-in-the-middle attacks.");
747                        options.num_local_forwards =
748                            options.num_remote_forwards = 0;
749                }
750                /*
751                 * XXX Should permit the user to change to use the new id.
752                 * This could be done by converting the host key to an
753                 * identifying sentence, tell that the host identifies itself
754                 * by that sentence, and ask the user if he/she whishes to
755                 * accept the authentication.
756                 */
757                break;
758        case HOST_FOUND:
759                fatal("internal error");
760                break;
761        }
762
763        if (options.check_host_ip && host_status != HOST_CHANGED &&
764            ip_status == HOST_CHANGED) {
765                snprintf(msg, sizeof(msg),
766                    "Warning: the %s host key for '%.200s' "
767                    "differs from the key for the IP address '%.128s'"
768                    "\nOffending key for IP in %s:%d",
769                    type, host, ip, ip_file, ip_line);
770                if (host_status == HOST_OK) {
771                        len = strlen(msg);
772                        snprintf(msg + len, sizeof(msg) - len,
773                            "\nMatching host key in %s:%d",
774                            host_file, host_line);
775                }
776                if (options.strict_host_key_checking == 1) {
777                        log(msg);
778                        error("Exiting, you have requested strict checking.");
779                        goto fail;
780                } else if (options.strict_host_key_checking == 2) {
781                        strlcat(msg, "\nAre you sure you want "
782                            "to continue connecting (yes/no)? ", sizeof(msg));
783                        if (!confirm(msg))
784                                goto fail;
785                } else {
786                        log(msg);
787                }
788        }
789
790        xfree(ip);
791        return 0;
792
793fail:
794        xfree(ip);
795        return -1;
796}
797
798int
799verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
800{
801        struct stat st;
802
803        /* return ok if the key can be found in an old keyfile */
804        if (stat(options.system_hostfile2, &st) == 0 ||
805            stat(options.user_hostfile2, &st) == 0) {
806                if (check_host_key(host, hostaddr, host_key, /*readonly*/ 1,
807                    options.user_hostfile2, options.system_hostfile2) == 0)
808                        return 0;
809        }
810        return check_host_key(host, hostaddr, host_key, /*readonly*/ 0,
811            options.user_hostfile, options.system_hostfile);
812}
813
814/*
815 * Starts a dialog with the server, and authenticates the current user on the
816 * server.  This does not need any extra privileges.  The basic connection
817 * to the server must already have been established before this is called.
818 * If login fails, this function prints an error and never returns.
819 * This function does not require super-user privileges.
820 */
821void
822ssh_login(Sensitive *sensitive, const char *orighost,
823    struct sockaddr *hostaddr, struct passwd *pw)
824{
825        char *host, *cp;
826        char *server_user, *local_user;
827
828        local_user = xstrdup(pw->pw_name);
829        server_user = options.user ? options.user : local_user;
830
831        /* Convert the user-supplied hostname into all lowercase. */
832        host = xstrdup(orighost);
833        for (cp = host; *cp; cp++)
834                if (isupper(*cp))
835                        *cp = tolower(*cp);
836
837        /* Exchange protocol version identification strings with the server. */
838        ssh_exchange_identification();
839
840        /* Put the connection into non-blocking mode. */
841        packet_set_nonblocking();
842
843        /* key exchange */
844        /* authenticate user */
845        if (compat20) {
846                ssh_kex2(host, hostaddr);
847                ssh_userauth2(local_user, server_user, host, sensitive);
848        } else {
849                ssh_kex(host, hostaddr);
850                ssh_userauth1(local_user, server_user, host, sensitive);
851        }
852}
853
854void
855ssh_put_password(char *password)
856{
857        int size;
858        char *padded;
859
860        if (datafellows & SSH_BUG_PASSWORDPAD) {
861                packet_put_cstring(password);
862                return;
863        }
864        size = roundup(strlen(password) + 1, 32);
865        padded = xmalloc(size);
866        memset(padded, 0, size);
867        strlcpy(padded, password, size);
868        packet_put_string(padded, size);
869        memset(padded, 0, size);
870        xfree(padded);
871}
872
873static int
874show_key_from_file(const char *file, const char *host, int keytype)
875{
876        Key *found;
877        char *fp;
878        int line, ret;
879
880        found = key_new(keytype);
881        if ((ret = lookup_key_in_hostfile_by_type(file, host,
882            keytype, found, &line))) {
883                fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
884                log("WARNING: %s key found for host %s\n"
885                    "in %s:%d\n"
886                    "%s key fingerprint %s.",
887                    key_type(found), host, file, line,
888                    key_type(found), fp);
889                xfree(fp);
890        }
891        key_free(found);
892        return (ret);
893}
894
895/* print all known host keys for a given host, but skip keys of given type */
896static int
897show_other_keys(const char *host, Key *key)
898{
899        int type[] = { KEY_RSA1, KEY_RSA, KEY_DSA, -1};
900        int i, found = 0;
901
902        for (i = 0; type[i] != -1; i++) {
903                if (type[i] == key->type)
904                        continue;
905                if (type[i] != KEY_RSA1 &&
906                    show_key_from_file(options.user_hostfile2, host, type[i])) {
907                        found = 1;
908                        continue;
909                }
910                if (type[i] != KEY_RSA1 &&
911                    show_key_from_file(options.system_hostfile2, host, type[i])) {
912                        found = 1;
913                        continue;
914                }
915                if (show_key_from_file(options.user_hostfile, host, type[i])) {
916                        found = 1;
917                        continue;
918                }
919                if (show_key_from_file(options.system_hostfile, host, type[i])) {
920                        found = 1;
921                        continue;
922                }
923                debug2("no key of type %d for host %s", type[i], host);
924        }
925        return (found);
926}
Note: See TracBrowser for help on using the repository browser.