static int choose_hostkeyalg(struct kex *k, char *client, char *server) { char *hostkeyalg = match_list(client, server, NULL); if (hostkeyalg == NULL) return SSH_ERR_NO_HOSTKEY_ALG_MATCH; k->hostkey_type = sshkey_type_from_name(hostkeyalg); if (k->hostkey_type == KEY_UNSPEC) return SSH_ERR_INTERNAL_ERROR; free(hostkeyalg); return 0; }
static int choose_hostkeyalg(struct kex *k, char *client, char *server) { k->hostkey_alg = match_list(client, server, NULL); debug("kex: host key algorithm: %s", k->hostkey_alg ? k->hostkey_alg : "(no match)"); if (k->hostkey_alg == NULL) return SSH_ERR_NO_HOSTKEY_ALG_MATCH; k->hostkey_type = sshkey_type_from_name(k->hostkey_alg); if (k->hostkey_type == KEY_UNSPEC) return SSH_ERR_INTERNAL_ERROR; k->hostkey_nid = sshkey_ecdsa_nid_from_name(k->hostkey_alg); return 0; }
int main(int argc, char **argv) { int debug_flag = 0, log_level = SYSLOG_LEVEL_INFO; int opt, fopt_count = 0, j; char *tname, *cp, line[NI_MAXHOST]; FILE *fp; u_long linenum; extern int optind; extern char *optarg; __progname = ssh_get_progname(argv[0]); seed_rng(); TAILQ_INIT(&tq); /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ sanitise_stdfd(); if (argc <= 1) usage(); while ((opt = getopt(argc, argv, "cHv46p:T:t:f:")) != -1) { switch (opt) { case 'H': hash_hosts = 1; break; case 'c': get_cert = 1; break; case 'p': ssh_port = a2port(optarg); if (ssh_port <= 0) { fprintf(stderr, "Bad port '%s'\n", optarg); exit(1); } break; case 'T': timeout = convtime(optarg); if (timeout == -1 || timeout == 0) { fprintf(stderr, "Bad timeout '%s'\n", optarg); usage(); } break; case 'v': 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 = sshkey_type_from_name(tname); switch (type) { case KEY_RSA1: get_keytypes |= KT_RSA1; break; case KEY_DSA: get_keytypes |= KT_DSA; break; case KEY_ECDSA: get_keytypes |= KT_ECDSA; break; case KEY_RSA: get_keytypes |= KT_RSA; break; case KEY_ED25519: get_keytypes |= KT_ED25519; break; case KEY_UNSPEC: fatal("unknown key type %s", tname); } tname = strtok(NULL, ","); } break; case '4': IPv4or6 = AF_INET; break; case '6': IPv4or6 = AF_INET6; break; case '?': default: usage(); } } if (optind == argc && !fopt_count) usage(); log_init("ssh-keyscan", log_level, SYSLOG_FACILITY_USER, 1); maxfd = fdlim_get(1); if (maxfd < 0) fatal("%s: fdlim_get: bad value", __progname); if (maxfd > MAXMAXFD) maxfd = MAXMAXFD; if (MAXCON <= 0) fatal("%s: not enough file descriptors", __progname); if (maxfd > fdlim_get(0)) fdlim_set(maxfd); fdcon = xcalloc(maxfd, sizeof(con)); read_wait_nfdset = howmany(maxfd, NFDBITS); read_wait = xcalloc(read_wait_nfdset, sizeof(fd_mask)); for (j = 0; j < fopt_count; j++) { if (argv[j] == NULL) fp = stdin; else if ((fp = fopen(argv[j], "r")) == NULL) fatal("%s: %s: %s", __progname, argv[j], strerror(errno)); linenum = 0; while (read_keyfile_line(fp, argv[j] == NULL ? "(stdin)" : argv[j], line, sizeof(line), &linenum) != -1) { /* Chomp off trailing whitespace and comments */ if ((cp = strchr(line, '#')) == NULL) cp = line + strlen(line) - 1; while (cp >= line) { if (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '#') *cp-- = '\0'; else break; } /* Skip empty lines */ if (*line == '\0') continue; do_host(line); } if (ferror(fp)) fatal("%s: %s: %s", __progname, argv[j], strerror(errno)); fclose(fp); } while (optind < argc) do_host(argv[optind++]); while (ncon > 0) conloop(); return (0); }
int hostkeys_foreach(const char *path, hostkeys_foreach_fn *callback, void *ctx, const char *host, const char *ip, u_int options) { FILE *f; char line[8192], oline[8192], ktype[128]; u_long linenum = 0; char *cp, *cp2; u_int kbits; int hashed; int s, r = 0; struct hostkey_foreach_line lineinfo; size_t l; memset(&lineinfo, 0, sizeof(lineinfo)); if (host == NULL && (options & HKF_WANT_MATCH) != 0) return SSH_ERR_INVALID_ARGUMENT; if ((f = fopen(path, "r")) == NULL) return SSH_ERR_SYSTEM_ERROR; debug3("%s: reading file \"%s\"", __func__, path); while (read_keyfile_line(f, path, line, sizeof(line), &linenum) == 0) { line[strcspn(line, "\n")] = '\0'; strlcpy(oline, line, sizeof(oline)); sshkey_free(lineinfo.key); memset(&lineinfo, 0, sizeof(lineinfo)); lineinfo.path = path; lineinfo.linenum = linenum; lineinfo.line = oline; lineinfo.marker = MRK_NONE; lineinfo.status = HKF_STATUS_OK; lineinfo.keytype = KEY_UNSPEC; /* Skip any leading whitespace, comments and empty lines. */ for (cp = line; *cp == ' ' || *cp == '\t'; cp++) ; if (!*cp || *cp == '#' || *cp == '\n') { if ((options & HKF_WANT_MATCH) == 0) { lineinfo.status = HKF_STATUS_COMMENT; if ((r = callback(&lineinfo, ctx)) != 0) break; } continue; } if ((lineinfo.marker = check_markers(&cp)) == MRK_ERROR) { verbose("%s: invalid marker at %s:%lu", __func__, path, linenum); if ((options & HKF_WANT_MATCH) == 0) goto bad; continue; } /* Find the end of the host name portion. */ for (cp2 = cp; *cp2 && *cp2 != ' ' && *cp2 != '\t'; cp2++) ; lineinfo.hosts = cp; *cp2++ = '\0'; /* Check if the host name matches. */ if (host != NULL) { if ((s = match_maybe_hashed(host, lineinfo.hosts, &hashed)) == -1) { debug2("%s: %s:%ld: bad host hash \"%.32s\"", __func__, path, linenum, lineinfo.hosts); goto bad; } if (s == 1) { lineinfo.status = HKF_STATUS_MATCHED; lineinfo.match |= HKF_MATCH_HOST | (hashed ? HKF_MATCH_HOST_HASHED : 0); } /* Try matching IP address if supplied */ if (ip != NULL) { if ((s = match_maybe_hashed(ip, lineinfo.hosts, &hashed)) == -1) { debug2("%s: %s:%ld: bad ip hash " "\"%.32s\"", __func__, path, linenum, lineinfo.hosts); goto bad; } if (s == 1) { lineinfo.status = HKF_STATUS_MATCHED; lineinfo.match |= HKF_MATCH_IP | (hashed ? HKF_MATCH_IP_HASHED : 0); } } /* * Skip this line if host matching requested and * neither host nor address matched. */ if ((options & HKF_WANT_MATCH) != 0 && lineinfo.status != HKF_STATUS_MATCHED) continue; } /* Got a match. Skip host name and any following whitespace */ for (; *cp2 == ' ' || *cp2 == '\t'; cp2++) ; if (*cp2 == '\0' || *cp2 == '#') { debug2("%s:%ld: truncated before key type", path, linenum); goto bad; } lineinfo.rawkey = cp = cp2; if ((options & HKF_WANT_PARSE_KEY) != 0) { /* * Extract the key from the line. This will skip * any leading whitespace. Ignore badly formatted * lines. */ if ((lineinfo.key = sshkey_new(KEY_UNSPEC)) == NULL) { error("%s: sshkey_new failed", __func__); r = SSH_ERR_ALLOC_FAIL; break; } if (!hostfile_read_key(&cp, &kbits, lineinfo.key)) { #ifdef WITH_SSH1 sshkey_free(lineinfo.key); lineinfo.key = sshkey_new(KEY_RSA1); if (lineinfo.key == NULL) { error("%s: sshkey_new fail", __func__); r = SSH_ERR_ALLOC_FAIL; break; } if (!hostfile_read_key(&cp, &kbits, lineinfo.key)) goto bad; #else goto bad; #endif } lineinfo.keytype = lineinfo.key->type; lineinfo.comment = cp; } else { /* Extract and parse key type */ l = strcspn(lineinfo.rawkey, " \t"); if (l <= 1 || l >= sizeof(ktype) || lineinfo.rawkey[l] == '\0') goto bad; memcpy(ktype, lineinfo.rawkey, l); ktype[l] = '\0'; lineinfo.keytype = sshkey_type_from_name(ktype); /* * Assume RSA1 if the first component is a short * decimal number. */ if (lineinfo.keytype == KEY_UNSPEC && l < 8 && strspn(ktype, "0123456789") == l) lineinfo.keytype = KEY_RSA1; /* * Check that something other than whitespace follows * the key type. This won't catch all corruption, but * it does catch trivial truncation. */ cp2 += l; /* Skip past key type */ for (; *cp2 == ' ' || *cp2 == '\t'; cp2++) ; if (*cp2 == '\0' || *cp2 == '#') { debug2("%s:%ld: truncated after key type", path, linenum); lineinfo.keytype = KEY_UNSPEC; } if (lineinfo.keytype == KEY_UNSPEC) { bad: sshkey_free(lineinfo.key); lineinfo.key = NULL; lineinfo.status = HKF_STATUS_INVALID; if ((r = callback(&lineinfo, ctx)) != 0) break; continue; } } if ((r = callback(&lineinfo, ctx)) != 0) break; } sshkey_free(lineinfo.key); fclose(f); return r; }
static int userauth_hostbased(struct ssh *ssh) { Authctxt *authctxt = ssh->authctxt; struct sshbuf *b; struct sshkey *key = NULL; char *pkalg, *cuser, *chost; u_char *pkblob, *sig; size_t alen, blen, slen; int r, pktype, authenticated = 0; if (!authctxt->valid) { debug2("%s: disabled because of invalid user", __func__); return 0; } /* XXX use sshkey_froms() */ if ((r = sshpkt_get_cstring(ssh, &pkalg, &alen)) != 0 || (r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0 || (r = sshpkt_get_cstring(ssh, &chost, NULL)) != 0 || (r = sshpkt_get_cstring(ssh, &cuser, NULL)) != 0 || (r = sshpkt_get_string(ssh, &sig, &slen)) != 0) fatal("%s: packet parsing: %s", __func__, ssh_err(r)); debug("%s: cuser %s chost %s pkalg %s slen %zu", __func__, cuser, chost, pkalg, slen); #ifdef DEBUG_PK debug("signature:"); sshbuf_dump_data(sig, siglen, stderr); #endif pktype = sshkey_type_from_name(pkalg); if (pktype == KEY_UNSPEC) { /* this is perfectly legal */ logit("%s: unsupported public key algorithm: %s", __func__, pkalg); goto done; } if ((r = sshkey_from_blob(pkblob, blen, &key)) != 0) { error("%s: key_from_blob: %s", __func__, ssh_err(r)); goto done; } if (key == NULL) { error("%s: cannot decode key: %s", __func__, pkalg); goto done; } if (key->type != pktype) { error("%s: type mismatch for decoded key " "(received %d, expected %d)", __func__, key->type, pktype); goto done; } if (sshkey_type_plain(key->type) == KEY_RSA && (ssh->compat & SSH_BUG_RSASIGMD5) != 0) { error("Refusing RSA key because peer uses unsafe " "signature format"); goto done; } if (match_pattern_list(sshkey_ssh_name(key), options.hostbased_key_types, 0) != 1) { logit("%s: key type %s not in HostbasedAcceptedKeyTypes", __func__, sshkey_type(key)); goto done; } if ((b = sshbuf_new()) == NULL) fatal("%s: sshbuf_new failed", __func__); /* reconstruct packet */ if ((r = sshbuf_put_string(b, session_id2, session_id2_len)) != 0 || (r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 || (r = sshbuf_put_cstring(b, authctxt->user)) != 0 || (r = sshbuf_put_cstring(b, authctxt->service)) != 0 || (r = sshbuf_put_cstring(b, "hostbased")) != 0 || (r = sshbuf_put_string(b, pkalg, alen)) != 0 || (r = sshbuf_put_string(b, pkblob, blen)) != 0 || (r = sshbuf_put_cstring(b, chost)) != 0 || (r = sshbuf_put_cstring(b, cuser)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); #ifdef DEBUG_PK sshbuf_dump(b, stderr); #endif auth2_record_info(authctxt, "client user \"%.100s\", client host \"%.100s\"", cuser, chost); /* test for allowed key and correct signature */ authenticated = 0; if (PRIVSEP(hostbased_key_allowed(authctxt->pw, cuser, chost, key)) && PRIVSEP(sshkey_verify(key, sig, slen, sshbuf_ptr(b), sshbuf_len(b), pkalg, ssh->compat)) == 0) authenticated = 1; auth2_record_key(authctxt, authenticated, key); sshbuf_free(b); done: debug2("%s: authenticated %d", __func__, authenticated); sshkey_free(key); free(pkalg); free(pkblob); free(cuser); free(chost); free(sig); return authenticated; }
static int valid_request(struct passwd *pw, char *host, struct sshkey **ret, u_char *data, size_t datalen) { struct sshbuf *b; struct sshkey *key = NULL; u_char type, *pkblob; char *p; size_t blen, len; char *pkalg, *luser; int r, pktype, fail; if (ret != NULL) *ret = NULL; fail = 0; if ((b = sshbuf_from(data, datalen)) == NULL) fatal("%s: sshbuf_from failed", __func__); /* session id, currently limited to SHA1 (20 bytes) or SHA256 (32) */ if ((r = sshbuf_get_string(b, NULL, &len)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (len != 20 && len != 32) fail++; if ((r = sshbuf_get_u8(b, &type)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (type != SSH2_MSG_USERAUTH_REQUEST) fail++; /* server user */ if ((r = sshbuf_skip_string(b)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); /* service */ if ((r = sshbuf_get_cstring(b, &p, NULL)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (strcmp("ssh-connection", p) != 0) fail++; free(p); /* method */ if ((r = sshbuf_get_cstring(b, &p, NULL)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (strcmp("hostbased", p) != 0) fail++; free(p); /* pubkey */ if ((r = sshbuf_get_cstring(b, &pkalg, NULL)) != 0 || (r = sshbuf_get_string(b, &pkblob, &blen)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); pktype = sshkey_type_from_name(pkalg); if (pktype == KEY_UNSPEC) fail++; else if ((r = sshkey_from_blob(pkblob, blen, &key)) != 0) { error("%s: bad key blob: %s", __func__, ssh_err(r)); fail++; } else if (key->type != pktype) fail++; free(pkalg); free(pkblob); /* client host name, handle trailing dot */ if ((r = sshbuf_get_cstring(b, &p, &len)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); debug2("%s: check expect chost %s got %s", __func__, host, p); if (strlen(host) != len - 1) fail++; else if (p[len - 1] != '.') fail++; else if (strncasecmp(host, p, len - 1) != 0) fail++; free(p); /* local user */ if ((r = sshbuf_get_cstring(b, &luser, NULL)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (strcmp(pw->pw_name, luser) != 0) fail++; free(luser); /* end of message */ if (sshbuf_len(b) != 0) fail++; sshbuf_free(b); debug3("%s: fail %d", __func__, fail); if (fail && key != NULL) sshkey_free(key); else if (ret != NULL) *ret = key; return (fail ? -1 : 0); }