LCOV - code coverage report
Current view: top level - openssh-6.6p1 - ssh-keyscan.c (source / functions) Hit Total Coverage
Test: lcov_coverage_final.info Lines: 252 374 67.4 %
Date: 2014-08-01 Functions: 16 19 84.2 %
Branches: 118 257 45.9 %

           Branch data     Line data    Source code
       1                 :            : /* $OpenBSD: ssh-keyscan.c,v 1.89 2013/12/06 13:39:49 markus Exp $ */
       2                 :            : /*
       3                 :            :  * Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>.
       4                 :            :  *
       5                 :            :  * Modification and redistribution in source and binary forms is
       6                 :            :  * permitted provided that due credit is given to the author and the
       7                 :            :  * OpenBSD project by leaving this copyright notice intact.
       8                 :            :  */
       9                 :            : 
      10                 :            : #include "includes.h"
      11                 :            :  
      12                 :            : #include "openbsd-compat/sys-queue.h"
      13                 :            : #include <sys/resource.h>
      14                 :            : #ifdef HAVE_SYS_TIME_H
      15                 :            : # include <sys/time.h>
      16                 :            : #endif
      17                 :            : 
      18                 :            : #include <netinet/in.h>
      19                 :            : #include <arpa/inet.h>
      20                 :            : 
      21                 :            : #include <openssl/bn.h>
      22                 :            : 
      23                 :            : #include <netdb.h>
      24                 :            : #include <errno.h>
      25                 :            : #include <setjmp.h>
      26                 :            : #include <stdarg.h>
      27                 :            : #include <stdio.h>
      28                 :            : #include <stdlib.h>
      29                 :            : #include <signal.h>
      30                 :            : #include <string.h>
      31                 :            : #include <unistd.h>
      32                 :            : 
      33                 :            : #include "xmalloc.h"
      34                 :            : #include "ssh.h"
      35                 :            : #include "ssh1.h"
      36                 :            : #include "buffer.h"
      37                 :            : #include "key.h"
      38                 :            : #include "cipher.h"
      39                 :            : #include "kex.h"
      40                 :            : #include "compat.h"
      41                 :            : #include "myproposal.h"
      42                 :            : #include "packet.h"
      43                 :            : #include "dispatch.h"
      44                 :            : #include "log.h"
      45                 :            : #include "atomicio.h"
      46                 :            : #include "misc.h"
      47                 :            : #include "hostfile.h"
      48                 :            : 
      49                 :            : /* Flag indicating whether IPv4 or IPv6.  This can be set on the command line.
      50                 :            :    Default value is AF_UNSPEC means both IPv4 and IPv6. */
      51                 :            : int IPv4or6 = AF_UNSPEC;
      52                 :            : 
      53                 :            : int ssh_port = SSH_DEFAULT_PORT;
      54                 :            : 
      55                 :            : #define KT_RSA1         1
      56                 :            : #define KT_DSA          2
      57                 :            : #define KT_RSA          4
      58                 :            : #define KT_ECDSA        8
      59                 :            : #define KT_ED25519      16
      60                 :            : 
      61                 :            : int get_keytypes = KT_RSA|KT_ECDSA;/* Get RSA and ECDSA keys by default */
      62                 :            : 
      63                 :            : int hash_hosts = 0;             /* Hash hostname on output */
      64                 :            : 
      65                 :            : #define MAXMAXFD 256
      66                 :            : 
      67                 :            : /* The number of seconds after which to give up on a TCP connection */
      68                 :            : int timeout = 5;
      69                 :            : 
      70                 :            : int maxfd;
      71                 :            : #define MAXCON (maxfd - 10)
      72                 :            : 
      73                 :            : extern char *__progname;
      74                 :            : fd_set *read_wait;
      75                 :            : size_t read_wait_nfdset;
      76                 :            : int ncon;
      77                 :            : int nonfatal_fatal = 0;
      78                 :            : jmp_buf kexjmp;
      79                 :            : Key *kexjmp_key;
      80                 :            : 
      81                 :            : /*
      82                 :            :  * Keep a connection structure for each file descriptor.  The state
      83                 :            :  * associated with file descriptor n is held in fdcon[n].
      84                 :            :  */
      85                 :            : typedef struct Connection {
      86                 :            :         u_char c_status;        /* State of connection on this file desc. */
      87                 :            : #define CS_UNUSED 0             /* File descriptor unused */
      88                 :            : #define CS_CON 1                /* Waiting to connect/read greeting */
      89                 :            : #define CS_SIZE 2               /* Waiting to read initial packet size */
      90                 :            : #define CS_KEYS 3               /* Waiting to read public key packet */
      91                 :            :         int c_fd;               /* Quick lookup: c->c_fd == c - fdcon */
      92                 :            :         int c_plen;             /* Packet length field for ssh packet */
      93                 :            :         int c_len;              /* Total bytes which must be read. */
      94                 :            :         int c_off;              /* Length of data read so far. */
      95                 :            :         int c_keytype;          /* Only one of KT_RSA1, KT_DSA, or KT_RSA */
      96                 :            :         char *c_namebase;       /* Address to free for c_name and c_namelist */
      97                 :            :         char *c_name;           /* Hostname of connection for errors */
      98                 :            :         char *c_namelist;       /* Pointer to other possible addresses */
      99                 :            :         char *c_output_name;    /* Hostname of connection for output */
     100                 :            :         char *c_data;           /* Data read from this fd */
     101                 :            :         Kex *c_kex;             /* The key-exchange struct for ssh2 */
     102                 :            :         struct timeval c_tv;    /* Time at which connection gets aborted */
     103                 :            :         TAILQ_ENTRY(Connection) c_link; /* List of connections in timeout order. */
     104                 :            : } con;
     105                 :            : 
     106                 :            : TAILQ_HEAD(conlist, Connection) tq;     /* Timeout Queue */
     107                 :            : con *fdcon;
     108                 :            : 
     109                 :            : static int
     110                 :          6 : fdlim_get(int hard)
     111                 :            : {
     112                 :            : #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE)
     113                 :            :         struct rlimit rlfd;
     114                 :            : 
     115         [ +  - ]:          6 :         if (getrlimit(RLIMIT_NOFILE, &rlfd) < 0)
     116                 :            :                 return (-1);
     117 [ +  + ][ -  + ]:          6 :         if ((hard ? rlfd.rlim_max : rlfd.rlim_cur) == RLIM_INFINITY)
     118                 :          0 :                 return SSH_SYSFDMAX;
     119                 :            :         else
     120         [ +  + ]:          6 :                 return hard ? rlfd.rlim_max : rlfd.rlim_cur;
     121                 :            : #else
     122                 :            :         return SSH_SYSFDMAX;
     123                 :            : #endif
     124                 :            : }
     125                 :            : 
     126                 :            : static int
     127                 :          0 : fdlim_set(int lim)
     128                 :            : {
     129                 :            : #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
     130                 :            :         struct rlimit rlfd;
     131                 :            : #endif
     132                 :            : 
     133         [ #  # ]:          0 :         if (lim <= 0)
     134                 :            :                 return (-1);
     135                 :            : #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
     136         [ #  # ]:          0 :         if (getrlimit(RLIMIT_NOFILE, &rlfd) < 0)
     137                 :            :                 return (-1);
     138                 :          0 :         rlfd.rlim_cur = lim;
     139         [ #  # ]:          0 :         if (setrlimit(RLIMIT_NOFILE, &rlfd) < 0)
     140                 :            :                 return (-1);
     141                 :            : #elif defined (HAVE_SETDTABLESIZE)
     142                 :            :         setdtablesize(lim);
     143                 :            : #endif
     144                 :          0 :         return (0);
     145                 :            : }
     146                 :            : 
     147                 :            : /*
     148                 :            :  * This is an strsep function that returns a null field for adjacent
     149                 :            :  * separators.  This is the same as the 4.4BSD strsep, but different from the
     150                 :            :  * one in the GNU libc.
     151                 :            :  */
     152                 :            : static char *
     153                 :         18 : xstrsep(char **str, const char *delim)
     154                 :            : {
     155                 :            :         char *s, *e;
     156                 :            : 
     157         [ +  - ]:         18 :         if (!**str)
     158                 :            :                 return (NULL);
     159                 :            : 
     160                 :         18 :         s = *str;
     161                 :         18 :         e = s + strcspn(s, delim);
     162                 :            : 
     163         [ -  + ]:         18 :         if (*e != '\0')
     164                 :          0 :                 *e++ = '\0';
     165                 :         18 :         *str = e;
     166                 :            : 
     167                 :         18 :         return (s);
     168                 :            : }
     169                 :            : 
     170                 :            : /*
     171                 :            :  * Get the next non-null token (like GNU strsep).  Strsep() will return a
     172                 :            :  * null token for two adjacent separators, so we may have to loop.
     173                 :            :  */
     174                 :            : static char *
     175                 :            : strnnsep(char **stringp, char *delim)
     176                 :            : {
     177                 :            :         char *tok;
     178                 :            : 
     179                 :            :         do {
     180                 :          9 :                 tok = xstrsep(stringp, delim);
     181 [ +  - ][ -  + ]:          9 :         } while (tok && *tok == '\0');
     182                 :            :         return (tok);
     183                 :            : }
     184                 :            : 
     185                 :            : static Key *
     186                 :          3 : keygrab_ssh1(con *c)
     187                 :            : {
     188                 :            :         static Key *rsa;
     189                 :            :         static Buffer msg;
     190                 :            : 
     191         [ +  + ]:          3 :         if (rsa == NULL) {
     192                 :          1 :                 buffer_init(&msg);
     193                 :          1 :                 rsa = key_new(KEY_RSA1);
     194                 :            :         }
     195                 :          3 :         buffer_append(&msg, c->c_data, c->c_plen);
     196                 :          3 :         buffer_consume(&msg, 8 - (c->c_plen & 7));   /* padding */
     197         [ -  + ]:          3 :         if (buffer_get_char(&msg) != (int) SSH_SMSG_PUBLIC_KEY) {
     198                 :          0 :                 error("%s: invalid packet type", c->c_name);
     199                 :          0 :                 buffer_clear(&msg);
     200                 :          0 :                 return NULL;
     201                 :            :         }
     202                 :          3 :         buffer_consume(&msg, 8);            /* cookie */
     203                 :            : 
     204                 :            :         /* server key */
     205                 :          3 :         (void) buffer_get_int(&msg);
     206                 :          3 :         buffer_get_bignum(&msg, rsa->rsa->e);
     207                 :          3 :         buffer_get_bignum(&msg, rsa->rsa->n);
     208                 :            : 
     209                 :            :         /* host key */
     210                 :          3 :         (void) buffer_get_int(&msg);
     211                 :          3 :         buffer_get_bignum(&msg, rsa->rsa->e);
     212                 :          3 :         buffer_get_bignum(&msg, rsa->rsa->n);
     213                 :            : 
     214                 :          3 :         buffer_clear(&msg);
     215                 :            : 
     216                 :          3 :         return (rsa);
     217                 :            : }
     218                 :            : 
     219                 :            : static int
     220                 :          3 : hostjump(Key *hostkey)
     221                 :            : {
     222                 :          3 :         kexjmp_key = hostkey;
     223                 :          3 :         longjmp(kexjmp, 1);
     224                 :            : }
     225                 :            : 
     226                 :            : static int
     227                 :            : ssh2_capable(int remote_major, int remote_minor)
     228                 :            : {
     229      [ +  -  - ]:          6 :         switch (remote_major) {
     230                 :            :         case 1:
     231         [ -  + ]:          6 :                 if (remote_minor == 99)
     232                 :            :                         return 1;
     233                 :            :                 break;
     234                 :            :         case 2:
     235                 :            :                 return 1;
     236                 :            :         default:
     237                 :            :                 break;
     238                 :            :         }
     239                 :            :         return 0;
     240                 :            : }
     241                 :            : 
     242                 :            : static Key *
     243                 :          6 : keygrab_ssh2(con *c)
     244                 :            : {
     245                 :            :         int j;
     246                 :            : 
     247                 :          6 :         packet_set_connection(c->c_fd, c->c_fd);
     248                 :          6 :         enable_compat20();
     249                 :          6 :         myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
     250         [ +  + ]:          6 :             c->c_keytype == KT_DSA ?  "ssh-dss" :
     251         [ -  + ]:          3 :             (c->c_keytype == KT_RSA ? "ssh-rsa" :
     252         [ #  # ]:          3 :             (c->c_keytype == KT_ED25519 ? "ssh-ed25519" :
     253                 :            :             "ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521"));
     254                 :          6 :         c->c_kex = kex_setup(myproposal);
     255                 :          6 :         c->c_kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client;
     256                 :          6 :         c->c_kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client;
     257                 :          6 :         c->c_kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
     258                 :          6 :         c->c_kex->kex[KEX_DH_GEX_SHA256] = kexgex_client;
     259                 :          6 :         c->c_kex->kex[KEX_ECDH_SHA2] = kexecdh_client;
     260                 :          6 :         c->c_kex->kex[KEX_C25519_SHA256] = kexc25519_client;
     261                 :          6 :         c->c_kex->verify_host_key = hostjump;
     262                 :            : 
     263         [ +  + ]:          6 :         if (!(j = setjmp(kexjmp))) {
     264                 :          6 :                 nonfatal_fatal = 1;
     265                 :          6 :                 dispatch_run(DISPATCH_BLOCK, &c->c_kex->done, c->c_kex);
     266                 :          0 :                 fprintf(stderr, "Impossible! dispatch_run() returned!\n");
     267                 :          0 :                 exit(1);
     268                 :            :         }
     269                 :          6 :         nonfatal_fatal = 0;
     270                 :          6 :         free(c->c_kex);
     271                 :          6 :         c->c_kex = NULL;
     272                 :          6 :         packet_close();
     273                 :            : 
     274         [ +  + ]:          6 :         return j < 0? NULL : kexjmp_key;
     275                 :            : }
     276                 :            : 
     277                 :            : static void
     278                 :         18 : keyprint(con *c, Key *key)
     279                 :            : {
     280         [ -  + ]:          9 :         char *host = c->c_output_name ? c->c_output_name : c->c_name;
     281                 :            : 
     282         [ +  + ]:          9 :         if (!key)
     283                 :          9 :                 return;
     284 [ -  + ][ #  # ]:          6 :         if (hash_hosts && (host = host_hash(host, NULL, 0)) == NULL)
     285                 :          0 :                 fatal("host_hash failed");
     286                 :            : 
     287                 :          6 :         fprintf(stdout, "%s ", host);
     288                 :          6 :         key_write(key, stdout);
     289                 :          6 :         fputs("\n", stdout);
     290                 :            : }
     291                 :            : 
     292                 :            : static int
     293                 :          9 : tcpconnect(char *host)
     294                 :            : {
     295                 :            :         struct addrinfo hints, *ai, *aitop;
     296                 :            :         char strport[NI_MAXSERV];
     297                 :          9 :         int gaierr, s = -1;
     298                 :            : 
     299                 :          9 :         snprintf(strport, sizeof strport, "%d", ssh_port);
     300                 :            :         memset(&hints, 0, sizeof(hints));
     301                 :          9 :         hints.ai_family = IPv4or6;
     302                 :          9 :         hints.ai_socktype = SOCK_STREAM;
     303         [ -  + ]:          9 :         if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0)
     304                 :          0 :                 fatal("getaddrinfo %s: %s", host, ssh_gai_strerror(gaierr));
     305         [ +  - ]:          9 :         for (ai = aitop; ai; ai = ai->ai_next) {
     306                 :          9 :                 s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
     307         [ -  + ]:          9 :                 if (s < 0) {
     308                 :          0 :                         error("socket: %s", strerror(errno));
     309                 :          0 :                         continue;
     310                 :            :                 }
     311         [ -  + ]:          9 :                 if (set_nonblock(s) == -1)
     312                 :          0 :                         fatal("%s: set_nonblock(%d)", __func__, s);
     313   [ +  -  -  + ]:         18 :                 if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0 &&
     314                 :          9 :                     errno != EINPROGRESS)
     315                 :          0 :                         error("connect (`%s'): %s", host, strerror(errno));
     316                 :            :                 else
     317                 :            :                         break;
     318                 :          0 :                 close(s);
     319                 :          0 :                 s = -1;
     320                 :            :         }
     321                 :          9 :         freeaddrinfo(aitop);
     322                 :          9 :         return s;
     323                 :            : }
     324                 :            : 
     325                 :            : static int
     326                 :          9 : conalloc(char *iname, char *oname, int keytype)
     327                 :            : {
     328                 :            :         char *namebase, *name, *namelist;
     329                 :            :         int s;
     330                 :            : 
     331                 :          9 :         namebase = namelist = xstrdup(iname);
     332                 :            : 
     333                 :            :         do {
     334                 :          9 :                 name = xstrsep(&namelist, ",");
     335         [ -  + ]:          9 :                 if (!name) {
     336                 :          0 :                         free(namebase);
     337                 :          0 :                         return (-1);
     338                 :            :                 }
     339         [ -  + ]:          9 :         } while ((s = tcpconnect(name)) < 0);
     340                 :            : 
     341         [ -  + ]:          9 :         if (s >= maxfd)
     342                 :          0 :                 fatal("conalloc: fdno %d too high", s);
     343         [ -  + ]:          9 :         if (fdcon[s].c_status)
     344                 :          0 :                 fatal("conalloc: attempt to reuse fdno %d", s);
     345                 :            : 
     346                 :          9 :         fdcon[s].c_fd = s;
     347                 :          9 :         fdcon[s].c_status = CS_CON;
     348                 :          9 :         fdcon[s].c_namebase = namebase;
     349                 :          9 :         fdcon[s].c_name = name;
     350                 :          9 :         fdcon[s].c_namelist = namelist;
     351                 :          9 :         fdcon[s].c_output_name = xstrdup(oname);
     352                 :          9 :         fdcon[s].c_data = (char *) &fdcon[s].c_plen;
     353                 :          9 :         fdcon[s].c_len = 4;
     354                 :          9 :         fdcon[s].c_off = 0;
     355                 :          9 :         fdcon[s].c_keytype = keytype;
     356                 :          9 :         gettimeofday(&fdcon[s].c_tv, NULL);
     357                 :          9 :         fdcon[s].c_tv.tv_sec += timeout;
     358                 :          9 :         TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link);
     359 [ -  + ][ #  # ]:          9 :         FD_SET(s, read_wait);
     360                 :          9 :         ncon++;
     361                 :          9 :         return (s);
     362                 :            : }
     363                 :            : 
     364                 :            : static void
     365                 :          9 : confree(int s)
     366                 :            : {
     367 [ +  - ][ -  + ]:          9 :         if (s >= maxfd || fdcon[s].c_status == CS_UNUSED)
     368                 :          0 :                 fatal("confree: attempt to free bad fdno %d", s);
     369                 :          9 :         close(s);
     370                 :          9 :         free(fdcon[s].c_namebase);
     371                 :          9 :         free(fdcon[s].c_output_name);
     372         [ +  + ]:          9 :         if (fdcon[s].c_status == CS_KEYS)
     373                 :          3 :                 free(fdcon[s].c_data);
     374                 :          9 :         fdcon[s].c_status = CS_UNUSED;
     375                 :          9 :         fdcon[s].c_keytype = 0;
     376         [ +  + ]:          9 :         TAILQ_REMOVE(&tq, &fdcon[s], c_link);
     377 [ -  + ][ #  # ]:          9 :         FD_CLR(s, read_wait);
     378                 :          9 :         ncon--;
     379                 :          9 : }
     380                 :            : 
     381                 :            : static void
     382                 :          6 : contouch(int s)
     383                 :            : {
     384         [ +  + ]:          6 :         TAILQ_REMOVE(&tq, &fdcon[s], c_link);
     385                 :          6 :         gettimeofday(&fdcon[s].c_tv, NULL);
     386                 :          6 :         fdcon[s].c_tv.tv_sec += timeout;
     387                 :          6 :         TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link);
     388                 :          6 : }
     389                 :            : 
     390                 :            : static int
     391                 :          0 : conrecycle(int s)
     392                 :            : {
     393                 :          0 :         con *c = &fdcon[s];
     394                 :            :         int ret;
     395                 :            : 
     396                 :          0 :         ret = conalloc(c->c_namelist, c->c_output_name, c->c_keytype);
     397                 :          0 :         confree(s);
     398                 :          0 :         return (ret);
     399                 :            : }
     400                 :            : 
     401                 :            : static void
     402                 :          9 : congreet(int s)
     403                 :            : {
     404                 :          9 :         int n = 0, remote_major = 0, remote_minor = 0;
     405                 :            :         char buf[256], *cp;
     406                 :            :         char remote_version[sizeof buf];
     407                 :            :         size_t bufsiz;
     408                 :          9 :         con *c = &fdcon[s];
     409                 :            : 
     410                 :            :         for (;;) {
     411                 :            :                 memset(buf, '\0', sizeof(buf));
     412                 :          9 :                 bufsiz = sizeof(buf);
     413                 :          9 :                 cp = buf;
     414   [ +  -  +  - ]:        378 :                 while (bufsiz-- &&
     415         [ +  + ]:        378 :                     (n = atomicio(read, s, cp, 1)) == 1 && *cp != '\n') {
     416         [ -  + ]:        180 :                         if (*cp == '\r')
     417                 :          0 :                                 *cp = '\n';
     418                 :        180 :                         cp++;
     419                 :            :                 }
     420 [ +  - ][ -  + ]:          9 :                 if (n != 1 || strncmp(buf, "SSH-", 4) == 0)
     421                 :            :                         break;
     422                 :            :         }
     423         [ -  + ]:          9 :         if (n == 0) {
     424      [ #  #  # ]:          0 :                 switch (errno) {
     425                 :            :                 case EPIPE:
     426                 :          0 :                         error("%s: Connection closed by remote host", c->c_name);
     427                 :          0 :                         break;
     428                 :            :                 case ECONNREFUSED:
     429                 :            :                         break;
     430                 :            :                 default:
     431                 :          0 :                         error("read (%s): %s", c->c_name, strerror(errno));
     432                 :          0 :                         break;
     433                 :            :                 }
     434                 :          0 :                 conrecycle(s);
     435                 :          6 :                 return;
     436                 :            :         }
     437         [ -  + ]:          9 :         if (*cp != '\n' && *cp != '\r') {
     438                 :          0 :                 error("%s: bad greeting", c->c_name);
     439                 :          0 :                 confree(s);
     440                 :          0 :                 return;
     441                 :            :         }
     442                 :          9 :         *cp = '\0';
     443         [ +  - ]:          9 :         if (sscanf(buf, "SSH-%d.%d-%[^\n]\n",
     444                 :            :             &remote_major, &remote_minor, remote_version) == 3)
     445                 :          9 :                 compat_datafellows(remote_version);
     446                 :            :         else
     447                 :          0 :                 datafellows = 0;
     448         [ +  + ]:          9 :         if (c->c_keytype != KT_RSA1) {
     449         [ -  + ]:          6 :                 if (!ssh2_capable(remote_major, remote_minor)) {
     450                 :          0 :                         debug("%s doesn't support ssh2", c->c_name);
     451                 :          0 :                         confree(s);
     452                 :          0 :                         return;
     453                 :            :                 }
     454         [ -  + ]:          3 :         } else if (remote_major != 1) {
     455                 :          0 :                 debug("%s doesn't support ssh1", c->c_name);
     456                 :          0 :                 confree(s);
     457                 :          0 :                 return;
     458                 :            :         }
     459                 :          9 :         fprintf(stderr, "# %s %s\n", c->c_name, chop(buf));
     460 [ +  + ][ +  + ]:          9 :         n = snprintf(buf, sizeof buf, "SSH-%d.%d-OpenSSH-keyscan\r\n",
     461                 :            :             c->c_keytype == KT_RSA1? PROTOCOL_MAJOR_1 : PROTOCOL_MAJOR_2,
     462                 :          9 :             c->c_keytype == KT_RSA1? PROTOCOL_MINOR_1 : PROTOCOL_MINOR_2);
     463         [ -  + ]:          9 :         if (n < 0 || (size_t)n >= sizeof(buf)) {
     464                 :          0 :                 error("snprintf: buffer too small");
     465                 :          0 :                 confree(s);
     466                 :          0 :                 return;
     467                 :            :         }
     468         [ -  + ]:          9 :         if (atomicio(vwrite, s, buf, n) != (size_t)n) {
     469                 :          0 :                 error("write (%s): %s", c->c_name, strerror(errno));
     470                 :          0 :                 confree(s);
     471                 :          0 :                 return;
     472                 :            :         }
     473         [ +  + ]:          9 :         if (c->c_keytype != KT_RSA1) {
     474                 :          6 :                 keyprint(c, keygrab_ssh2(c));
     475                 :          6 :                 confree(s);
     476                 :          6 :                 return;
     477                 :            :         }
     478                 :          3 :         c->c_status = CS_SIZE;
     479                 :          3 :         contouch(s);
     480                 :            : }
     481                 :            : 
     482                 :            : static void
     483                 :         15 : conread(int s)
     484                 :            : {
     485                 :         21 :         con *c = &fdcon[s];
     486                 :            :         size_t n;
     487                 :            : 
     488         [ +  + ]:         15 :         if (c->c_status == CS_CON) {
     489                 :          9 :                 congreet(s);
     490                 :          9 :                 return;
     491                 :            :         }
     492                 :          6 :         n = atomicio(read, s, c->c_data + c->c_off, c->c_len - c->c_off);
     493         [ -  + ]:          6 :         if (n == 0) {
     494                 :          0 :                 error("read (%s): %s", c->c_name, strerror(errno));
     495                 :          0 :                 confree(s);
     496                 :          0 :                 return;
     497                 :            :         }
     498                 :          6 :         c->c_off += n;
     499                 :            : 
     500         [ +  - ]:          6 :         if (c->c_off == c->c_len)
     501      [ +  +  - ]:          6 :                 switch (c->c_status) {
     502                 :            :                 case CS_SIZE:
     503                 :          6 :                         c->c_plen = htonl(c->c_plen);
     504                 :          3 :                         c->c_len = c->c_plen + 8 - (c->c_plen & 7);
     505                 :          3 :                         c->c_off = 0;
     506                 :          3 :                         c->c_data = xmalloc(c->c_len);
     507                 :          3 :                         c->c_status = CS_KEYS;
     508                 :          3 :                         break;
     509                 :            :                 case CS_KEYS:
     510                 :          3 :                         keyprint(c, keygrab_ssh1(c));
     511                 :          3 :                         confree(s);
     512                 :          3 :                         return;
     513                 :            :                 default:
     514                 :          0 :                         fatal("conread: invalid status %d", c->c_status);
     515                 :            :                         break;
     516                 :            :                 }
     517                 :            : 
     518                 :          3 :         contouch(s);
     519                 :            : }
     520                 :            : 
     521                 :            : static void
     522                 :         14 : conloop(void)
     523                 :            : {
     524                 :            :         struct timeval seltime, now;
     525                 :            :         fd_set *r, *e;
     526                 :            :         con *c;
     527                 :            :         int i;
     528                 :            : 
     529                 :         14 :         gettimeofday(&now, NULL);
     530                 :         14 :         c = TAILQ_FIRST(&tq);
     531                 :            : 
     532 [ +  - ][ -  + ]:         14 :         if (c && (c->c_tv.tv_sec > now.tv_sec ||
                 [ #  # ]
     533         [ #  # ]:          0 :             (c->c_tv.tv_sec == now.tv_sec && c->c_tv.tv_usec > now.tv_usec))) {
     534                 :         14 :                 seltime = c->c_tv;
     535                 :         14 :                 seltime.tv_sec -= now.tv_sec;
     536                 :         14 :                 seltime.tv_usec -= now.tv_usec;
     537         [ +  - ]:         14 :                 if (seltime.tv_usec < 0) {
     538                 :         14 :                         seltime.tv_usec += 1000000;
     539                 :         14 :                         seltime.tv_sec--;
     540                 :            :                 }
     541                 :            :         } else
     542                 :          0 :                 timerclear(&seltime);
     543                 :            : 
     544                 :         14 :         r = xcalloc(read_wait_nfdset, sizeof(fd_mask));
     545                 :         14 :         e = xcalloc(read_wait_nfdset, sizeof(fd_mask));
     546                 :         14 :         memcpy(r, read_wait, read_wait_nfdset * sizeof(fd_mask));
     547                 :         14 :         memcpy(e, read_wait, read_wait_nfdset * sizeof(fd_mask));
     548                 :            : 
     549   [ -  +  #  # ]:         14 :         while (select(maxfd, r, NULL, e, &seltime) == -1 &&
     550         [ #  # ]:         14 :             (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK))
     551                 :            :                 ;
     552                 :            : 
     553         [ +  + ]:       3598 :         for (i = 0; i < maxfd; i++) {
     554 [ -  + ][ #  # ]:       3584 :                 if (FD_ISSET(i, e)) {
                 [ -  + ]
     555                 :          0 :                         error("%s: exception!", fdcon[i].c_name);
     556                 :          0 :                         confree(i);
     557 [ -  + ][ #  # ]:       3584 :                 } else if (FD_ISSET(i, r))
                 [ +  + ]
     558                 :         15 :                         conread(i);
     559                 :            :         }
     560                 :         14 :         free(r);
     561                 :         14 :         free(e);
     562                 :            : 
     563                 :         14 :         c = TAILQ_FIRST(&tq);
     564 [ +  + ][ -  + ]:         14 :         while (c && (c->c_tv.tv_sec < now.tv_sec ||
                 [ -  + ]
     565         [ #  # ]:          0 :             (c->c_tv.tv_sec == now.tv_sec && c->c_tv.tv_usec < now.tv_usec))) {
     566                 :          0 :                 int s = c->c_fd;
     567                 :            : 
     568                 :          0 :                 c = TAILQ_NEXT(c, c_link);
     569                 :          0 :                 conrecycle(s);
     570                 :            :         }
     571                 :         14 : }
     572                 :            : 
     573                 :            : static void
     574                 :         18 : do_host(char *host)
     575                 :            : {
     576                 :          9 :         char *name = strnnsep(&host, " \t\n");
     577                 :            :         int j;
     578                 :            : 
     579         [ +  - ]:          9 :         if (name == NULL)
     580                 :          9 :                 return;
     581         [ +  + ]:         54 :         for (j = KT_RSA1; j <= KT_ED25519; j *= 2) {
     582         [ +  + ]:         45 :                 if (get_keytypes & j) {
     583         [ -  + ]:          9 :                         while (ncon >= MAXCON)
     584                 :          0 :                                 conloop();
     585         [ +  - ]:          9 :                         conalloc(name, *host ? host : name, j);
     586                 :            :                 }
     587                 :            :         }
     588                 :            : }
     589                 :            : 
     590                 :            : void
     591                 :          3 : fatal(const char *fmt,...)
     592                 :            : {
     593                 :            :         va_list args;
     594                 :            : 
     595                 :          3 :         va_start(args, fmt);
     596                 :          3 :         do_log(SYSLOG_LEVEL_FATAL, fmt, args);
     597                 :          3 :         va_end(args);
     598         [ +  - ]:          3 :         if (nonfatal_fatal)
     599                 :          3 :                 longjmp(kexjmp, -1);
     600                 :            :         else
     601                 :          0 :                 exit(255);
     602                 :            : }
     603                 :            : 
     604                 :            : static void
     605                 :          0 : usage(void)
     606                 :            : {
     607                 :          0 :         fprintf(stderr,
     608                 :            :             "usage: %s [-46Hv] [-f file] [-p port] [-T timeout] [-t type]\n"
     609                 :            :             "\t\t   [host | addrlist namelist] ...\n",
     610                 :            :             __progname);
     611                 :          0 :         exit(1);
     612                 :            : }
     613                 :            : 
     614                 :            : int
     615                 :          3 : main(int argc, char **argv)
     616                 :            : {
     617                 :          3 :         int debug_flag = 0, log_level = SYSLOG_LEVEL_INFO;
     618                 :          3 :         int opt, fopt_count = 0, j;
     619                 :            :         char *tname, *cp, line[NI_MAXHOST];
     620                 :            :         FILE *fp;
     621                 :            :         u_long linenum;
     622                 :            : 
     623                 :            :         extern int optind;
     624                 :            :         extern char *optarg;
     625                 :            : 
     626                 :          3 :         __progname = ssh_get_progname(argv[0]);
     627                 :          3 :         seed_rng();
     628                 :          3 :         TAILQ_INIT(&tq);
     629                 :            : 
     630                 :            :         /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
     631                 :          3 :         sanitise_stdfd();
     632                 :            : 
     633         [ +  - ]:          3 :         if (argc <= 1)
     634                 :          0 :                 usage();
     635                 :            : 
     636         [ +  + ]:          9 :         while ((opt = getopt(argc, argv, "Hv46p:T:t:f:")) != -1) {
     637   [ -  +  -  -  :          6 :                 switch (opt) {
             -  +  -  -  
                      - ]
     638                 :            :                 case 'H':
     639                 :          0 :                         hash_hosts = 1;
     640                 :          0 :                         break;
     641                 :            :                 case 'p':
     642                 :          3 :                         ssh_port = a2port(optarg);
     643         [ -  + ]:          3 :                         if (ssh_port <= 0) {
     644                 :          0 :                                 fprintf(stderr, "Bad port '%s'\n", optarg);
     645                 :          0 :                                 exit(1);
     646                 :            :                         }
     647                 :            :                         break;
     648                 :            :                 case 'T':
     649                 :          0 :                         timeout = convtime(optarg);
     650         [ #  # ]:          0 :                         if (timeout == -1 || timeout == 0) {
     651                 :          0 :                                 fprintf(stderr, "Bad timeout '%s'\n", optarg);
     652                 :          0 :                                 usage();
     653                 :            :                         }
     654                 :            :                         break;
     655                 :            :                 case 'v':
     656         [ #  # ]:          0 :                         if (!debug_flag) {
     657                 :            :                                 debug_flag = 1;
     658                 :            :                                 log_level = SYSLOG_LEVEL_DEBUG1;
     659                 :            :                         }
     660         [ #  # ]:          0 :                         else if (log_level < SYSLOG_LEVEL_DEBUG3)
     661                 :          0 :                                 log_level++;
     662                 :            :                         else
     663                 :          0 :                                 fatal("Too high debugging level.");
     664                 :            :                         break;
     665                 :            :                 case 'f':
     666 [ #  # ][ #  # ]:          0 :                         if (strcmp(optarg, "-") == 0)
     667                 :          0 :                                 optarg = NULL;
     668                 :          0 :                         argv[fopt_count++] = optarg;
     669                 :          0 :                         break;
     670                 :            :                 case 't':
     671                 :          3 :                         get_keytypes = 0;
     672                 :          3 :                         tname = strtok(optarg, ",");
     673         [ +  + ]:          6 :                         while (tname) {
     674                 :          3 :                                 int type = key_type_from_name(tname);
     675   [ +  +  -  +  :          3 :                                 switch (type) {
                -  -  - ]
     676                 :            :                                 case KEY_RSA1:
     677                 :          1 :                                         get_keytypes |= KT_RSA1;
     678                 :          1 :                                         break;
     679                 :            :                                 case KEY_DSA:
     680                 :          1 :                                         get_keytypes |= KT_DSA;
     681                 :          1 :                                         break;
     682                 :            :                                 case KEY_ECDSA:
     683                 :          0 :                                         get_keytypes |= KT_ECDSA;
     684                 :          0 :                                         break;
     685                 :            :                                 case KEY_RSA:
     686                 :          1 :                                         get_keytypes |= KT_RSA;
     687                 :          1 :                                         break;
     688                 :            :                                 case KEY_ED25519:
     689                 :          0 :                                         get_keytypes |= KT_ED25519;
     690                 :          0 :                                         break;
     691                 :            :                                 case KEY_UNSPEC:
     692                 :          0 :                                         fatal("unknown key type %s", tname);
     693                 :            :                                 }
     694                 :          3 :                                 tname = strtok(NULL, ",");
     695                 :            :                         }
     696                 :            :                         break;
     697                 :            :                 case '4':
     698                 :          0 :                         IPv4or6 = AF_INET;
     699                 :          0 :                         break;
     700                 :            :                 case '6':
     701                 :          0 :                         IPv4or6 = AF_INET6;
     702                 :          0 :                         break;
     703                 :            :                 case '?':
     704                 :            :                 default:
     705                 :          6 :                         usage();
     706                 :            :                 }
     707                 :            :         }
     708 [ -  + ][ #  # ]:          3 :         if (optind == argc && !fopt_count)
     709                 :          0 :                 usage();
     710                 :            : 
     711                 :          3 :         log_init("ssh-keyscan", log_level, SYSLOG_FACILITY_USER, 1);
     712                 :            : 
     713                 :          3 :         maxfd = fdlim_get(1);
     714         [ -  + ]:          3 :         if (maxfd < 0)
     715                 :          0 :                 fatal("%s: fdlim_get: bad value", __progname);
     716         [ +  - ]:          3 :         if (maxfd > MAXMAXFD)
     717                 :          3 :                 maxfd = MAXMAXFD;
     718         [ -  + ]:          3 :         if (MAXCON <= 0)
     719                 :          0 :                 fatal("%s: not enough file descriptors", __progname);
     720         [ -  + ]:          3 :         if (maxfd > fdlim_get(0))
     721                 :          0 :                 fdlim_set(maxfd);
     722                 :          3 :         fdcon = xcalloc(maxfd, sizeof(con));
     723                 :            : 
     724                 :          3 :         read_wait_nfdset = howmany(maxfd, NFDBITS);
     725                 :          3 :         read_wait = xcalloc(read_wait_nfdset, sizeof(fd_mask));
     726                 :            : 
     727         [ -  + ]:          3 :         for (j = 0; j < fopt_count; j++) {
     728         [ #  # ]:          0 :                 if (argv[j] == NULL)
     729                 :          0 :                         fp = stdin;
     730         [ #  # ]:          0 :                 else if ((fp = fopen(argv[j], "r")) == NULL)
     731                 :          0 :                         fatal("%s: %s: %s", __progname, argv[j],
     732                 :          0 :                             strerror(errno));
     733                 :          0 :                 linenum = 0;
     734                 :            : 
     735 [ #  # ][ #  # ]:          0 :                 while (read_keyfile_line(fp,
     736                 :          0 :                     argv[j] == NULL ? "(stdin)" : argv[j], line, sizeof(line),
     737                 :            :                     &linenum) != -1) {
     738                 :            :                         /* Chomp off trailing whitespace and comments */
     739         [ #  # ]:          0 :                         if ((cp = strchr(line, '#')) == NULL)
     740                 :          0 :                                 cp = line + strlen(line) - 1;
     741         [ #  # ]:          0 :                         while (cp >= line) {
     742 [ #  # ][ #  # ]:          0 :                                 if (*cp == ' ' || *cp == '\t' ||
     743         [ #  # ]:          0 :                                     *cp == '\n' || *cp == '#')
     744                 :          0 :                                         *cp-- = '\0';
     745                 :            :                                 else
     746                 :            :                                         break;
     747                 :            :                         }
     748                 :            : 
     749                 :            :                         /* Skip empty lines */
     750         [ #  # ]:          0 :                         if (*line == '\0')
     751                 :          0 :                                 continue;
     752                 :            : 
     753                 :          0 :                         do_host(line);
     754                 :            :                 }
     755                 :            : 
     756         [ #  # ]:          0 :                 if (ferror(fp))
     757                 :          0 :                         fatal("%s: %s: %s", __progname, argv[j],
     758                 :          0 :                             strerror(errno));
     759                 :            : 
     760                 :          0 :                 fclose(fp);
     761                 :            :         }
     762                 :            : 
     763         [ +  + ]:         12 :         while (optind < argc)
     764                 :          9 :                 do_host(argv[optind++]);
     765                 :            : 
     766         [ +  + ]:         17 :         while (ncon > 0)
     767                 :         14 :                 conloop();
     768                 :            : 
     769                 :          3 :         return (0);
     770                 :            : }

Generated by: LCOV version 1.9