summaryrefslogtreecommitdiff
path: root/hostfile.c
diff options
context:
space:
mode:
Diffstat (limited to 'hostfile.c')
-rw-r--r--hostfile.c147
1 files changed, 145 insertions, 2 deletions
diff --git a/hostfile.c b/hostfile.c
index 40dbbd478..5f0366310 100644
--- a/hostfile.c
+++ b/hostfile.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: hostfile.c,v 1.59 2015/01/15 09:40:00 djm Exp $ */ 1/* $OpenBSD: hostfile.c,v 1.60 2015/01/18 21:40:23 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -42,6 +42,7 @@
42 42
43#include <netinet/in.h> 43#include <netinet/in.h>
44 44
45#include <errno.h>
45#include <resolv.h> 46#include <resolv.h>
46#include <stdarg.h> 47#include <stdarg.h>
47#include <stdio.h> 48#include <stdio.h>
@@ -64,6 +65,8 @@ struct hostkeys {
64 u_int num_entries; 65 u_int num_entries;
65}; 66};
66 67
68/* XXX hmac is too easy to dictionary attack; use bcrypt? */
69
67static int 70static int
68extract_salt(const char *s, u_int l, u_char *salt, size_t salt_len) 71extract_salt(const char *s, u_int l, u_char *salt, size_t salt_len)
69{ 72{
@@ -496,7 +499,147 @@ add_host_to_hostfile(const char *filename, const char *host,
496 __func__, filename, ssh_err(r)); 499 __func__, filename, ssh_err(r));
497 } else 500 } else
498 success = 1; 501 success = 1;
499 fputs("\n", f); 502 fputc('\n', f);
500 fclose(f); 503 fclose(f);
501 return success; 504 return success;
502} 505}
506
507static int
508match_maybe_hashed(const char *host, const char *names, int *was_hashed)
509{
510 int hashed = *names == HASH_DELIM;
511 const char *hashed_host;
512 size_t nlen = strlen(names);
513
514 if (was_hashed != NULL)
515 *was_hashed = hashed;
516 if (hashed) {
517 if ((hashed_host = host_hash(host, names, nlen)) == NULL)
518 return -1;
519 return nlen == strlen(hashed_host) &&
520 strncmp(hashed_host, names, nlen) == 0;
521 }
522 return match_hostname(host, names, nlen) == 1;
523}
524
525int
526hostkeys_foreach(const char *path, hostkeys_foreach_fn *callback, void *ctx,
527 const char *host, u_int options)
528{
529 FILE *f;
530 char line[8192], oline[8192];
531 u_long linenum = 0;
532 char *cp, *cp2;
533 u_int kbits;
534 int s, r = 0;
535 struct hostkey_foreach_line lineinfo;
536
537 memset(&lineinfo, 0, sizeof(lineinfo));
538 if (host == NULL && (options & HKF_WANT_MATCH_HOST) != 0)
539 return SSH_ERR_INVALID_ARGUMENT;
540 if ((f = fopen(path, "r")) == NULL)
541 return SSH_ERR_SYSTEM_ERROR;
542
543 debug3("%s: reading file \"%s\"", __func__, path);
544 while (read_keyfile_line(f, path, line, sizeof(line), &linenum) == 0) {
545 line[strcspn(line, "\n")] = '\0';
546 strlcpy(oline, line, sizeof(oline));
547
548 sshkey_free(lineinfo.key);
549 memset(&lineinfo, 0, sizeof(lineinfo));
550 lineinfo.path = path;
551 lineinfo.linenum = linenum;
552 lineinfo.line = oline;
553 lineinfo.status = HKF_STATUS_OK;
554
555 /* Skip any leading whitespace, comments and empty lines. */
556 for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
557 ;
558 if (!*cp || *cp == '#' || *cp == '\n') {
559 if ((options & HKF_WANT_MATCH_HOST) == 0) {
560 lineinfo.status = HKF_STATUS_COMMENT;
561 if ((r = callback(&lineinfo, ctx)) != 0)
562 break;
563 }
564 continue;
565 }
566
567 if ((lineinfo.marker = check_markers(&cp)) == MRK_ERROR) {
568 verbose("%s: invalid marker at %s:%lu",
569 __func__, path, linenum);
570 if ((options & HKF_WANT_MATCH_HOST) == 0)
571 goto bad;
572 continue;
573 }
574
575 /* Find the end of the host name portion. */
576 for (cp2 = cp; *cp2 && *cp2 != ' ' && *cp2 != '\t'; cp2++)
577 ;
578 lineinfo.hosts = cp;
579 *cp2++ = '\0';
580
581 /* Check if the host name matches. */
582 if (host != NULL) {
583 s = match_maybe_hashed(host, lineinfo.hosts,
584 &lineinfo.was_hashed);
585 if (s == 1)
586 lineinfo.status = HKF_STATUS_HOST_MATCHED;
587 else if ((options & HKF_WANT_MATCH_HOST) != 0)
588 continue;
589 else if (s == -1) {
590 debug2("%s: %s:%ld: bad host hash \"%.32s\"",
591 __func__, path, linenum, lineinfo.hosts);
592 goto bad;
593 }
594 }
595
596 /* Got a match. Skip host name and any following whitespace */
597 for (; *cp2 == ' ' || *cp2 == '\t'; cp2++)
598 ;
599 if (*cp2 == '\0' || *cp2 == '#') {
600 debug2("%s:%ld: truncated before key", path, linenum);
601 goto bad;
602 }
603 lineinfo.rawkey = cp = cp2;
604
605 if ((options & HKF_WANT_PARSE_KEY) != 0) {
606 /*
607 * Extract the key from the line. This will skip
608 * any leading whitespace. Ignore badly formatted
609 * lines.
610 */
611 if ((lineinfo.key = sshkey_new(KEY_UNSPEC)) == NULL) {
612 error("%s: sshkey_new failed", __func__);
613 return SSH_ERR_ALLOC_FAIL;
614 }
615 if (!hostfile_read_key(&cp, &kbits, lineinfo.key)) {
616#ifdef WITH_SSH1
617 sshkey_free(lineinfo.key);
618 lineinfo.key = sshkey_new(KEY_RSA1);
619 if (lineinfo.key == NULL) {
620 error("%s: sshkey_new fail", __func__);
621 return SSH_ERR_ALLOC_FAIL;
622 }
623 if (!hostfile_read_key(&cp, &kbits,
624 lineinfo.key))
625 goto bad;
626#else
627 goto bad;
628#endif
629 }
630 if (!hostfile_check_key(kbits, lineinfo.key, host,
631 path, linenum)) {
632 bad:
633 lineinfo.status = HKF_STATUS_INVALID;
634 if ((r = callback(&lineinfo, ctx)) != 0)
635 break;
636 continue;
637 }
638 }
639 if ((r = callback(&lineinfo, ctx)) != 0)
640 break;
641 }
642 sshkey_free(lineinfo.key);
643 fclose(f);
644 return r;
645}