diff options
Diffstat (limited to 'hostfile.c')
-rw-r--r-- | hostfile.c | 147 |
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 | |||
67 | static int | 70 | static int |
68 | extract_salt(const char *s, u_int l, u_char *salt, size_t salt_len) | 71 | extract_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 | |||
507 | static int | ||
508 | match_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 | |||
525 | int | ||
526 | hostkeys_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 | } | ||