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

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