📄 ssh-keyscan.c
字号:
/* * Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>. * * Modification and redistribution in source and binary forms is * permitted provided that due credit is given to the author and the * OpenBSD project by leaving this copyright notice intact. */#include "includes.h"RCSID("$OpenBSD: ssh-keyscan.c,v 1.36 2002/06/16 21:30:58 itojun Exp $");#include "openbsd-compat/fake-queue.h"#include <openssl/bn.h>#include <setjmp.h>#include "xmalloc.h"#include "ssh.h"#include "ssh1.h"#include "key.h"#include "kex.h"#include "compat.h"#include "myproposal.h"#include "packet.h"#include "dispatch.h"#include "buffer.h"#include "bufaux.h"#include "log.h"#include "atomicio.h"#include "misc.h"/* 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_DEFAULTint IPv4or6 = AF_INET;#elseint IPv4or6 = AF_UNSPEC;#endifint ssh_port = SSH_DEFAULT_PORT;#define KT_RSA1 1#define KT_DSA 2#define KT_RSA 4int get_keytypes = KT_RSA1; /* Get only RSA1 keys by default */#define MAXMAXFD 256/* The number of seconds after which to give up on a TCP connection */int timeout = 5;int maxfd;#define MAXCON (maxfd - 10)#ifdef HAVE___PROGNAMEextern char *__progname;#elsechar *__progname;#endiffd_set *read_wait;size_t read_wait_size;int ncon;int nonfatal_fatal = 0;jmp_buf kexjmp;Key *kexjmp_key;/* * Keep a connection structure for each file descriptor. The state * associated with file descriptor n is held in fdcon[n]. */typedef struct Connection { u_char c_status; /* State of connection on this file desc. */#define CS_UNUSED 0 /* File descriptor unused */#define CS_CON 1 /* Waiting to connect/read greeting */#define CS_SIZE 2 /* Waiting to read initial packet size */#define CS_KEYS 3 /* Waiting to read public key packet */ int c_fd; /* Quick lookup: c->c_fd == c - fdcon */ int c_plen; /* Packet length field for ssh packet */ int c_len; /* Total bytes which must be read. */ 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_name; /* Hostname of connection for errors */ char *c_namelist; /* Pointer to other possible addresses */ char *c_output_name; /* Hostname of connection for output */ 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 */ TAILQ_ENTRY(Connection) c_link; /* List of connections in timeout order. */} con;TAILQ_HEAD(conlist, Connection) tq; /* Timeout Queue */con *fdcon;/* * This is just a wrapper around fgets() to make it usable. *//* Stress-test. Increase this later. */#define LINEBUF_SIZE 16typedef struct { char *buf; u_int size; int lineno; const char *filename; FILE *stream; void (*errfun) (const char *,...);} Linebuf;static Linebuf *Linebuf_alloc(const char *filename, void (*errfun) (const char *,...)){ Linebuf *lb; if (!(lb = malloc(sizeof(*lb)))) { if (errfun) (*errfun) ("linebuf (%s): malloc failed\n", lb->filename); return (NULL); } if (filename) { lb->filename = filename; if (!(lb->stream = fopen(filename, "r"))) { xfree(lb); if (errfun) (*errfun) ("%s: %s\n", filename, strerror(errno)); return (NULL); } } else { lb->filename = "(stdin)"; lb->stream = stdin; } if (!(lb->buf = malloc(lb->size = LINEBUF_SIZE))) { if (errfun) (*errfun) ("linebuf (%s): malloc failed\n", lb->filename); xfree(lb); return (NULL); } lb->errfun = errfun; lb->lineno = 0; return (lb);}static voidLinebuf_free(Linebuf * lb){ fclose(lb->stream); xfree(lb->buf); xfree(lb);}#if 0static voidLinebuf_restart(Linebuf * lb){ clearerr(lb->stream); rewind(lb->stream); lb->lineno = 0;}static intLinebuf_lineno(Linebuf * lb){ return (lb->lineno);}#endifstatic char *Linebuf_getline(Linebuf * lb){ int n = 0; lb->lineno++; for (;;) { /* Read a line */ if (!fgets(&lb->buf[n], lb->size - n, lb->stream)) { if (ferror(lb->stream) && lb->errfun) (*lb->errfun) ("%s: %s\n", lb->filename, strerror(errno)); return (NULL); } n = strlen(lb->buf); /* Return it or an error if it fits */ if (n > 0 && lb->buf[n - 1] == '\n') { lb->buf[n - 1] = '\0'; return (lb->buf); } if (n != lb->size - 1) { if (lb->errfun) (*lb->errfun) ("%s: skipping incomplete last line\n", lb->filename); return (NULL); } /* Double the buffer if we need more space */ if (!(lb->buf = realloc(lb->buf, (lb->size *= 2)))) { if (lb->errfun) (*lb->errfun) ("linebuf (%s): realloc failed\n", lb->filename); return (NULL); } }}static intfdlim_get(int hard){#if defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE) struct rlimit rlfd; if (getrlimit(RLIMIT_NOFILE, &rlfd) < 0) return (-1); if ((hard ? rlfd.rlim_max : rlfd.rlim_cur) == RLIM_INFINITY) return 10000; else return hard ? rlfd.rlim_max : rlfd.rlim_cur;#elif defined (HAVE_SYSCONF) return sysconf (_SC_OPEN_MAX);#else return 10000;#endif}static intfdlim_set(int lim){#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE) struct rlimit rlfd;#endif if (lim <= 0) return (-1);#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE) if (getrlimit(RLIMIT_NOFILE, &rlfd) < 0) return (-1); rlfd.rlim_cur = lim; if (setrlimit(RLIMIT_NOFILE, &rlfd) < 0) return (-1);#elif defined (HAVE_SETDTABLESIZE) setdtablesize(lim);#endif return (0);}/* * This is an strsep function that returns a null field for adjacent * separators. This is the same as the 4.4BSD strsep, but different from the * one in the GNU libc. */static char *xstrsep(char **str, const char *delim){ char *s, *e; if (!**str) return (NULL); s = *str; e = s + strcspn(s, delim); if (*e != '\0') *e++ = '\0'; *str = e; return (s);}/* * 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. */static char *strnnsep(char **stringp, char *delim){ char *tok; do { tok = xstrsep(stringp, delim); } while (tok && *tok == '\0'); return (tok);}static Key *keygrab_ssh1(con *c){ static Key *rsa; static Buffer msg; if (rsa == NULL) { buffer_init(&msg); rsa = key_new(KEY_RSA1); } buffer_append(&msg, c->c_data, c->c_plen); buffer_consume(&msg, 8 - (c->c_plen & 7)); /* padding */ if (buffer_get_char(&msg) != (int) SSH_SMSG_PUBLIC_KEY) { error("%s: invalid packet type", c->c_name); buffer_clear(&msg); return NULL; } buffer_consume(&msg, 8); /* cookie */ /* server key */ (void) buffer_get_int(&msg); buffer_get_bignum(&msg, rsa->rsa->e); buffer_get_bignum(&msg, rsa->rsa->n); /* host key */ (void) buffer_get_int(&msg); buffer_get_bignum(&msg, rsa->rsa->e); buffer_get_bignum(&msg, rsa->rsa->n); buffer_clear(&msg); return (rsa);}static inthostjump(Key *hostkey){ kexjmp_key = hostkey; longjmp(kexjmp, 1);}static intssh2_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 voidkeyprint(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);}static inttcpconnect(char *host){ struct addrinfo hints, *ai, *aitop; char strport[NI_MAXSERV]; int gaierr, s = -1; snprintf(strport, sizeof strport, "%d", ssh_port); memset(&hints, 0, sizeof(hints)); hints.ai_family = IPv4or6; hints.ai_socktype = SOCK_STREAM; if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) fatal("getaddrinfo %s: %s", host, gai_strerror(gaierr)); for (ai = aitop; ai; ai = ai->ai_next) { s = socket(ai->ai_family, SOCK_STREAM, 0); if (s < 0) { error("socket: %s", strerror(errno)); continue; } if (fcntl(s, F_SETFL, O_NONBLOCK) < 0) fatal("F_SETFL: %s", strerror(errno)); if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0 && errno != EINPROGRESS) error("connect (`%s'): %s", host, strerror(errno)); else break; close(s); s = -1; } freeaddrinfo(aitop); return s;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -