LCOV - code coverage report
Current view: top level - openssh-6.6p1 - sshconnect.c (source / functions) Hit Total Coverage
Test: lcov_coverage_final.info Lines: 242 612 39.5 %
Date: 2014-08-01 Functions: 16 21 76.2 %
Branches: 132 444 29.7 %

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

Generated by: LCOV version 1.9