[BACK]Return to ssh-keyscan.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Diff for /src/usr.bin/ssh/ssh-keyscan.c between version 1.16.2.4 and 1.16.2.5

version 1.16.2.4, 2001/05/07 21:09:36 version 1.16.2.5, 2001/09/27 00:15:42
Line 3 
Line 3 
  *   *
  * Modification and redistribution in source and binary forms is   * Modification and redistribution in source and binary forms is
  * permitted provided that due credit is given to the author and the   * permitted provided that due credit is given to the author and the
  * OpenBSD project (for instance by leaving this copyright notice   * OpenBSD project by leaving this copyright notice intact.
  * intact).  
  */   */
   
 #include "includes.h"  #include "includes.h"
Line 15 
Line 14 
   
 #include <openssl/bn.h>  #include <openssl/bn.h>
   
   #include <setjmp.h>
 #include "xmalloc.h"  #include "xmalloc.h"
 #include "ssh.h"  #include "ssh.h"
 #include "ssh1.h"  #include "ssh1.h"
 #include "key.h"  #include "key.h"
   #include "kex.h"
   #include "compat.h"
   #include "myproposal.h"
   #include "packet.h"
   #include "dispatch.h"
 #include "buffer.h"  #include "buffer.h"
 #include "bufaux.h"  #include "bufaux.h"
 #include "log.h"  #include "log.h"
 #include "atomicio.h"  #include "atomicio.h"
   #include "misc.h"
   
 static int argno = 1;           /* Number of argument currently being parsed */  /* Flag indicating whether IPv4 or IPv6.  This can be set on the command line.
      Default value is AF_UNSPEC means both IPv4 and IPv6. */
   #ifdef IPV4_DEFAULT
   int IPv4or6 = AF_INET;
   #else
   int IPv4or6 = AF_UNSPEC;
   #endif
   
 int family = AF_UNSPEC;         /* IPv4, IPv6 or both */  int ssh_port = SSH_DEFAULT_PORT;
   
   #define KT_RSA1 1
   #define KT_DSA  2
   #define KT_RSA  4
   
   int get_keytypes = KT_RSA1;     /* Get only RSA1 keys by default */
   
 #define MAXMAXFD 256  #define MAXMAXFD 256
   
 /* The number of seconds after which to give up on a TCP connection */  /* The number of seconds after which to give up on a TCP connection */
Line 40 
Line 58 
 fd_set *read_wait;  fd_set *read_wait;
 size_t read_wait_size;  size_t read_wait_size;
 int ncon;  int ncon;
   int nonfatal_fatal = 0;
   jmp_buf kexjmp;
   Key *kexjmp_key;
   
 /*  /*
  * Keep a connection structure for each file descriptor.  The state   * Keep a connection structure for each file descriptor.  The state
Line 55 
Line 76 
         int c_plen;             /* Packet length field for ssh packet */          int c_plen;             /* Packet length field for ssh packet */
         int c_len;              /* Total bytes which must be read. */          int c_len;              /* Total bytes which must be read. */
         int c_off;              /* Length of data read so far. */          int c_off;              /* Length of data read so far. */
           int c_keytype;          /* Only one of KT_RSA1, KT_DSA, or KT_RSA */
         char *c_namebase;       /* Address to free for c_name and c_namelist */          char *c_namebase;       /* Address to free for c_name and c_namelist */
         char *c_name;           /* Hostname of connection for errors */          char *c_name;           /* Hostname of connection for errors */
         char *c_namelist;       /* Pointer to other possible addresses */          char *c_namelist;       /* Pointer to other possible addresses */
         char *c_output_name;    /* Hostname of connection for output */          char *c_output_name;    /* Hostname of connection for output */
         char *c_data;           /* Data read from this fd */          char *c_data;           /* Data read from this fd */
           Kex *c_kex;             /* The key-exchange struct for ssh2 */
         struct timeval c_tv;    /* Time at which connection gets aborted */          struct timeval c_tv;    /* Time at which connection gets aborted */
         TAILQ_ENTRY(Connection) c_link; /* List of connections in timeout order. */          TAILQ_ENTRY(Connection) c_link; /* List of connections in timeout order. */
 } con;  } con;
Line 83 
Line 106 
         void (*errfun) (const char *,...);          void (*errfun) (const char *,...);
 } Linebuf;  } Linebuf;
   
 Linebuf *  static Linebuf *
 Linebuf_alloc(const char *filename, void (*errfun) (const char *,...))  Linebuf_alloc(const char *filename, void (*errfun) (const char *,...))
 {  {
         Linebuf *lb;          Linebuf *lb;
Line 117 
Line 140 
         return (lb);          return (lb);
 }  }
   
 void  static void
 Linebuf_free(Linebuf * lb)  Linebuf_free(Linebuf * lb)
 {  {
         fclose(lb->stream);          fclose(lb->stream);
Line 125 
Line 148 
         xfree(lb);          xfree(lb);
 }  }
   
 void  #if 0
   static void
 Linebuf_restart(Linebuf * lb)  Linebuf_restart(Linebuf * lb)
 {  {
         clearerr(lb->stream);          clearerr(lb->stream);
Line 133 
Line 157 
         lb->lineno = 0;          lb->lineno = 0;
 }  }
   
 int  static int
 Linebuf_lineno(Linebuf * lb)  Linebuf_lineno(Linebuf * lb)
 {  {
         return (lb->lineno);          return (lb->lineno);
 }  }
   #endif
   
 char *  static char *
 Linebuf_getline(Linebuf * lb)  Linebuf_getline(Linebuf * lb)
 {  {
         int n = 0;          int n = 0;
Line 176 
Line 201 
         }          }
 }  }
   
 int  static int
 fdlim_get(int hard)  fdlim_get(int hard)
 {  {
         struct rlimit rlfd;          struct rlimit rlfd;
Line 189 
Line 214 
                 return hard ? rlfd.rlim_max : rlfd.rlim_cur;                  return hard ? rlfd.rlim_max : rlfd.rlim_cur;
 }  }
   
 int  static int
 fdlim_set(int lim)  fdlim_set(int lim)
 {  {
         struct rlimit rlfd;          struct rlimit rlfd;
Line 208 
Line 233 
  * separators.  This is the same as the 4.4BSD strsep, but different from the   * separators.  This is the same as the 4.4BSD strsep, but different from the
  * one in the GNU libc.   * one in the GNU libc.
  */   */
 char *  static char *
 xstrsep(char **str, const char *delim)  xstrsep(char **str, const char *delim)
 {  {
         char *s, *e;          char *s, *e;
Line 230 
Line 255 
  * Get the next non-null token (like GNU strsep).  Strsep() will return a   * Get the next non-null token (like GNU strsep).  Strsep() will return a
  * null token for two adjacent separators, so we may have to loop.   * null token for two adjacent separators, so we may have to loop.
  */   */
 char *  static char *
 strnnsep(char **stringp, char *delim)  strnnsep(char **stringp, char *delim)
 {  {
         char *tok;          char *tok;
Line 241 
Line 266 
         return (tok);          return (tok);
 }  }
   
 void  static Key *
 keyprint(char *host, char *output_name, char *kd, int len)  keygrab_ssh1(con *c)
 {  {
         static Key *rsa;          static Key *rsa;
         static Buffer msg;          static Buffer msg;
Line 251 
Line 276 
                 buffer_init(&msg);                  buffer_init(&msg);
                 rsa = key_new(KEY_RSA1);                  rsa = key_new(KEY_RSA1);
         }          }
         buffer_append(&msg, kd, len);          buffer_append(&msg, c->c_data, c->c_plen);
         buffer_consume(&msg, 8 - (len & 7));    /* padding */          buffer_consume(&msg, 8 - (c->c_plen & 7));      /* padding */
         if (buffer_get_char(&msg) != (int) SSH_SMSG_PUBLIC_KEY) {          if (buffer_get_char(&msg) != (int) SSH_SMSG_PUBLIC_KEY) {
                 error("%s: invalid packet type", host);                  error("%s: invalid packet type", c->c_name);
                 buffer_clear(&msg);                  buffer_clear(&msg);
                 return;                  return NULL;
         }          }
         buffer_consume(&msg, 8);                /* cookie */          buffer_consume(&msg, 8);                /* cookie */
   
Line 269 
Line 294 
         (void) buffer_get_int(&msg);          (void) buffer_get_int(&msg);
         buffer_get_bignum(&msg, rsa->rsa->e);          buffer_get_bignum(&msg, rsa->rsa->e);
         buffer_get_bignum(&msg, rsa->rsa->n);          buffer_get_bignum(&msg, rsa->rsa->n);
   
         buffer_clear(&msg);          buffer_clear(&msg);
   
         fprintf(stdout, "%s ", output_name ? output_name : host);          return (rsa);
         key_write(rsa, stdout);  }
   
   static int
   hostjump(Key *hostkey)
   {
           kexjmp_key = hostkey;
           longjmp(kexjmp, 1);
   }
   
   static int
   ssh2_capable(int remote_major, int remote_minor)
   {
           switch (remote_major) {
           case 1:
                   if (remote_minor == 99)
                           return 1;
                   break;
           case 2:
                   return 1;
           default:
                   break;
           }
           return 0;
   }
   
   static Key *
   keygrab_ssh2(con *c)
   {
           int j;
   
           packet_set_connection(c->c_fd, c->c_fd);
           enable_compat20();
           myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = c->c_keytype == KT_DSA?
               "ssh-dss": "ssh-rsa";
           c->c_kex = kex_setup(myproposal);
           c->c_kex->verify_host_key = hostjump;
   
           if (!(j = setjmp(kexjmp))) {
                   nonfatal_fatal = 1;
                   dispatch_run(DISPATCH_BLOCK, &c->c_kex->done, c->c_kex);
                   fprintf(stderr, "Impossible! dispatch_run() returned!\n");
                   exit(1);
           }
           nonfatal_fatal = 0;
           xfree(c->c_kex);
           c->c_kex = NULL;
           packet_close();
   
           return j < 0? NULL : kexjmp_key;
   }
   
   static void
   keyprint(con *c, Key *key)
   {
           if (!key)
                   return;
   
           fprintf(stdout, "%s ", c->c_output_name ? c->c_output_name : c->c_name);
           key_write(key, stdout);
         fputs("\n", stdout);          fputs("\n", stdout);
 }  }
   
 int  static int
 tcpconnect(char *host)  tcpconnect(char *host)
 {  {
         struct addrinfo hints, *ai, *aitop;          struct addrinfo hints, *ai, *aitop;
         char strport[NI_MAXSERV];          char strport[NI_MAXSERV];
         int gaierr, s = -1;          int gaierr, s = -1;
   
         snprintf(strport, sizeof strport, "%d", SSH_DEFAULT_PORT);          snprintf(strport, sizeof strport, "%d", ssh_port);
         memset(&hints, 0, sizeof(hints));          memset(&hints, 0, sizeof(hints));
         hints.ai_family = family;          hints.ai_family = IPv4or6;
         hints.ai_socktype = SOCK_STREAM;          hints.ai_socktype = SOCK_STREAM;
         if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0)          if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0)
                 fatal("getaddrinfo %s: %s", host, gai_strerror(gaierr));                  fatal("getaddrinfo %s: %s", host, gai_strerror(gaierr));
Line 309 
Line 393 
         return s;          return s;
 }  }
   
 int  static int
 conalloc(char *iname, char *oname)  conalloc(char *iname, char *oname, int keytype)
 {  {
         int s;          int s;
         char *namebase, *name, *namelist;          char *namebase, *name, *namelist;
Line 339 
Line 423 
         fdcon[s].c_data = (char *) &fdcon[s].c_plen;          fdcon[s].c_data = (char *) &fdcon[s].c_plen;
         fdcon[s].c_len = 4;          fdcon[s].c_len = 4;
         fdcon[s].c_off = 0;          fdcon[s].c_off = 0;
           fdcon[s].c_keytype = keytype;
         gettimeofday(&fdcon[s].c_tv, NULL);          gettimeofday(&fdcon[s].c_tv, NULL);
         fdcon[s].c_tv.tv_sec += timeout;          fdcon[s].c_tv.tv_sec += timeout;
         TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link);          TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link);
Line 347 
Line 432 
         return (s);          return (s);
 }  }
   
 void  static void
 confree(int s)  confree(int s)
 {  {
         if (s >= maxfd || fdcon[s].c_status == CS_UNUSED)          if (s >= maxfd || fdcon[s].c_status == CS_UNUSED)
Line 358 
Line 443 
         if (fdcon[s].c_status == CS_KEYS)          if (fdcon[s].c_status == CS_KEYS)
                 xfree(fdcon[s].c_data);                  xfree(fdcon[s].c_data);
         fdcon[s].c_status = CS_UNUSED;          fdcon[s].c_status = CS_UNUSED;
           fdcon[s].c_keytype = 0;
         TAILQ_REMOVE(&tq, &fdcon[s], c_link);          TAILQ_REMOVE(&tq, &fdcon[s], c_link);
         FD_CLR(s, read_wait);          FD_CLR(s, read_wait);
         ncon--;          ncon--;
 }  }
   
 void  static void
 contouch(int s)  contouch(int s)
 {  {
         TAILQ_REMOVE(&tq, &fdcon[s], c_link);          TAILQ_REMOVE(&tq, &fdcon[s], c_link);
Line 372 
Line 458 
         TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link);          TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link);
 }  }
   
 int  static int
 conrecycle(int s)  conrecycle(int s)
 {  {
         int ret;          int ret;
         con *c = &fdcon[s];          con *c = &fdcon[s];
         char *iname, *oname;  
   
         iname = xstrdup(c->c_namelist);          ret = conalloc(c->c_namelist, c->c_output_name, c->c_keytype);
         oname = xstrdup(c->c_output_name);  
         confree(s);          confree(s);
         ret = conalloc(iname, oname);  
         xfree(iname);  
         xfree(oname);  
         return (ret);          return (ret);
 }  }
   
 void  static void
 congreet(int s)  congreet(int s)
 {  {
         char buf[80], *cp;          char buf[256], *cp;
         size_t bufsiz;          size_t bufsiz;
         int n = 0;          int n = 0;
         con *c = &fdcon[s];          con *c = &fdcon[s];
   
         bufsiz = sizeof(buf);          bufsiz = sizeof(buf);
         cp = buf;          cp = buf;
         while (bufsiz-- && (n = read(s, cp, 1)) == 1 && *cp != '\n' && *cp != '\r')          while (bufsiz-- && (n = read(s, cp, 1)) == 1 && *cp != '\n') {
                   if (*cp == '\r')
                           *cp = '\n';
                 cp++;                  cp++;
           }
         if (n < 0) {          if (n < 0) {
                 if (errno != ECONNREFUSED)                  if (errno != ECONNREFUSED)
                         error("read (%s): %s", c->c_name, strerror(errno));                          error("read (%s): %s", c->c_name, strerror(errno));
Line 412 
Line 496 
                 return;                  return;
         }          }
         *cp = '\0';          *cp = '\0';
         fprintf(stderr, "# %s %s\n", c->c_name, buf);          if (c->c_keytype != KT_RSA1) {
         n = snprintf(buf, sizeof buf, "SSH-1.5-OpenSSH-keyscan\r\n");                  int remote_major, remote_minor;
                   char remote_version[sizeof buf];
   
                   if (sscanf(buf, "SSH-%d.%d-%[^\n]\n",
                       &remote_major, &remote_minor, remote_version) == 3)
                           compat_datafellows(remote_version);
                   else
                           datafellows = 0;
                   if (!ssh2_capable(remote_major, remote_minor)) {
                           debug("%s doesn't support ssh2", c->c_name);
                           confree(s);
                           return;
                   }
           }
           fprintf(stderr, "# %s %s\n", c->c_name, chop(buf));
           n = snprintf(buf, sizeof buf, "SSH-%d.%d-OpenSSH-keyscan\r\n",
               c->c_keytype == KT_RSA1? PROTOCOL_MAJOR_1 : PROTOCOL_MAJOR_2,
               c->c_keytype == KT_RSA1? PROTOCOL_MINOR_1 : PROTOCOL_MINOR_2);
         if (atomicio(write, s, buf, n) != n) {          if (atomicio(write, s, buf, n) != n) {
                 error("write (%s): %s", c->c_name, strerror(errno));                  error("write (%s): %s", c->c_name, strerror(errno));
                 confree(s);                  confree(s);
                 return;                  return;
         }          }
           if (c->c_keytype != KT_RSA1) {
                   keyprint(c, keygrab_ssh2(c));
                   confree(s);
                   return;
           }
         c->c_status = CS_SIZE;          c->c_status = CS_SIZE;
         contouch(s);          contouch(s);
 }  }
   
 void  static void
 conread(int s)  conread(int s)
 {  {
         int n;          int n;
Line 451 
Line 557 
                         c->c_status = CS_KEYS;                          c->c_status = CS_KEYS;
                         break;                          break;
                 case CS_KEYS:                  case CS_KEYS:
                         keyprint(c->c_name, c->c_output_name, c->c_data, c->c_plen);                          keyprint(c, keygrab_ssh1(c));
                         confree(s);                          confree(s);
                         return;                          return;
                         break;                          break;
Line 463 
Line 569 
         contouch(s);          contouch(s);
 }  }
   
 void  static void
 conloop(void)  conloop(void)
 {  {
         fd_set *r, *e;          fd_set *r, *e;
Line 515 
Line 621 
         }          }
 }  }
   
 char *  static void
 nexthost(int argc, char **argv)  do_host(char *host)
 {  {
         static Linebuf *lb;          char *name = strnnsep(&host, " \t\n");
           int j;
   
         for (;;) {          for (j = KT_RSA1; j <= KT_RSA; j *= 2) {
                 if (!lb) {                  if (get_keytypes & j) {
                         if (argno >= argc)                          while (ncon >= MAXCON)
                                 return (NULL);                                  conloop();
                         if (argv[argno][0] != '-')                          conalloc(name, *host ? host : name, j);
                                 return (argv[argno++]);  
                         if (!strcmp(argv[argno], "--")) {  
                                 if (++argno >= argc)  
                                         return (NULL);  
                                 return (argv[argno++]);  
                         } else if (!strncmp(argv[argno], "-f", 2)) {  
                                 char *fname;  
   
                                 if (argv[argno][2])  
                                         fname = &argv[argno++][2];  
                                 else if (++argno >= argc) {  
                                         error("missing filename for `-f'");  
                                         return (NULL);  
                                 } else  
                                         fname = argv[argno++];  
                                 if (!strcmp(fname, "-"))  
                                         fname = NULL;  
                                 lb = Linebuf_alloc(fname, error);  
                         } else  
                                 error("ignoring invalid/misplaced option `%s'",  
                                     argv[argno++]);  
                 } else {  
                         char *line;  
   
                         line = Linebuf_getline(lb);  
                         if (line)  
                                 return (line);  
                         Linebuf_free(lb);  
                         lb = NULL;  
                 }                  }
         }          }
 }  }
   
 void  static void
   fatal_callback(void *arg)
   {
           if (nonfatal_fatal)
                   longjmp(kexjmp, -1);
   }
   
   static void
 usage(void)  usage(void)
 {  {
         fatal("usage: %s [-t timeout] { [--] host | -f file } ...", __progname);          fprintf(stderr, "Usage: %s [options] host ...\n",
         return;              __progname);
           fprintf(stderr, "Options:\n");
           fprintf(stderr, "  -f file     Read hosts or addresses from file.\n");
           fprintf(stderr, "  -p port     Connect to the specified port.\n");
           fprintf(stderr, "  -t keytype  Specify the host key type.\n");
           fprintf(stderr, "  -T timeout  Set connection timeout.\n");
           fprintf(stderr, "  -v          Verbose; display verbose debugging messages.\n");
           fprintf(stderr, "  -4          Use IPv4 only.\n");
           fprintf(stderr, "  -6          Use IPv6 only.\n");
           exit(1);
 }  }
   
 int  int
 main(int argc, char **argv)  main(int argc, char **argv)
 {  {
         char *host = NULL;          int debug_flag = 0, log_level = SYSLOG_LEVEL_INFO;
           int opt, fopt_count = 0;
           char *tname;
   
           extern int optind;
           extern char *optarg;
   
         TAILQ_INIT(&tq);          TAILQ_INIT(&tq);
   
         if (argc <= argno)          if (argc <= 1)
                 usage();                  usage();
   
         if (argv[1][0] == '-' && argv[1][1] == 't') {          while ((opt = getopt(argc, argv, "v46p:T:t:f:")) != -1) {
                 argno++;                  switch (opt) {
                 if (argv[1][2])                  case 'p':
                         timeout = atoi(&argv[1][2]);                          ssh_port = a2port(optarg);
                 else {                          if (ssh_port == 0) {
                         if (argno >= argc)                                  fprintf(stderr, "Bad port '%s'\n", optarg);
                                   exit(1);
                           }
                           break;
                   case 'T':
                           timeout = atoi(optarg);
                           if (timeout <= 0)
                                 usage();                                  usage();
                         timeout = atoi(argv[argno++]);                          break;
                 }                  case 'v':
                 if (timeout <= 0)                          if (!debug_flag) {
                                   debug_flag = 1;
                                   log_level = SYSLOG_LEVEL_DEBUG1;
                           }
                           else if (log_level < SYSLOG_LEVEL_DEBUG3)
                                   log_level++;
                           else
                                   fatal("Too high debugging level.");
                           break;
                   case 'f':
                           if (strcmp(optarg, "-") == 0)
                                   optarg = NULL;
                           argv[fopt_count++] = optarg;
                           break;
                   case 't':
                           get_keytypes = 0;
                           tname = strtok(optarg, ",");
                           while (tname) {
                                   int type = key_type_from_name(tname);
                                   switch (type) {
                                   case KEY_RSA1:
                                           get_keytypes |= KT_RSA1;
                                           break;
                                   case KEY_DSA:
                                           get_keytypes |= KT_DSA;
                                           break;
                                   case KEY_RSA:
                                           get_keytypes |= KT_RSA;
                                           break;
                                   case KEY_UNSPEC:
                                           fatal("unknown key type %s\n", tname);
                                   }
                                   tname = strtok(NULL, ",");
                           }
                           break;
                   case '4':
                           IPv4or6 = AF_INET;
                           break;
                   case '6':
                           IPv4or6 = AF_INET6;
                           break;
                   case '?':
                   default:
                         usage();                          usage();
                   }
         }          }
         if (argc <= argno)          if (optind == argc && !fopt_count)
                 usage();                  usage();
   
           log_init("ssh-keyscan", log_level, SYSLOG_FACILITY_USER, 1);
           fatal_add_cleanup(fatal_callback, NULL);
   
         maxfd = fdlim_get(1);          maxfd = fdlim_get(1);
         if (maxfd < 0)          if (maxfd < 0)
                 fatal("%s: fdlim_get: bad value", __progname);                  fatal("%s: fdlim_get: bad value", __progname);
Line 606 
Line 757 
         read_wait = xmalloc(read_wait_size);          read_wait = xmalloc(read_wait_size);
         memset(read_wait, 0, read_wait_size);          memset(read_wait, 0, read_wait_size);
   
         do {          if (fopt_count) {
                 while (ncon < MAXCON) {                  Linebuf *lb;
                         char *name;                  char *line;
                   int j;
   
                         host = nexthost(argc, argv);                  for (j = 0; j < fopt_count; j++) {
                         if (host == NULL)                          lb = Linebuf_alloc(argv[j], error);
                                 break;                          if (!lb)
                         name = strnnsep(&host, " \t\n");                                  continue;
                         conalloc(name, *host ? host : name);                          while ((line = Linebuf_getline(lb)) != NULL)
                                   do_host(line);
                           Linebuf_free(lb);
                 }                  }
                 conloop();          }
         } while (host);  
           while (optind < argc)
                   do_host(argv[optind++]);
   
         while (ncon > 0)          while (ncon > 0)
                 conloop();                  conloop();
   

Legend:
Removed from v.1.16.2.4  
changed lines
  Added in v.1.16.2.5