Annotation of src/usr.bin/ssh/hostfile.c, Revision 1.19
1.1 deraadt 1: /*
1.16 markus 2: *
1.8 deraadt 3: * hostfile.c
1.16 markus 4: *
1.8 deraadt 5: * Author: Tatu Ylonen <ylo@cs.hut.fi>
1.16 markus 6: *
1.8 deraadt 7: * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8: * All rights reserved
1.16 markus 9: *
1.8 deraadt 10: * Created: Thu Jun 29 07:10:56 1995 ylo
1.16 markus 11: *
1.8 deraadt 12: * Functions for manipulating the known hosts files.
1.16 markus 13: *
1.8 deraadt 14: */
1.1 deraadt 15:
16: #include "includes.h"
1.19 ! markus 17: RCSID("$OpenBSD: hostfile.c,v 1.18 2000/04/29 18:11:52 markus Exp $");
1.1 deraadt 18:
19: #include "packet.h"
1.14 markus 20: #include "match.h"
1.1 deraadt 21: #include "ssh.h"
1.15 markus 22: #include <openssl/rsa.h>
23: #include <openssl/dsa.h>
1.14 markus 24: #include "key.h"
25: #include "hostfile.h"
1.1 deraadt 26:
1.9 markus 27: /*
1.14 markus 28: * Parses an RSA (number of bits, e, n) or DSA key from a string. Moves the
29: * pointer over the key. Skips any whitespace at the beginning and at end.
1.9 markus 30: */
1.1 deraadt 31:
1.2 provos 32: int
1.14 markus 33: hostfile_read_key(char **cpp, unsigned int *bitsp, Key *ret)
1.1 deraadt 34: {
1.7 markus 35: unsigned int bits;
36: char *cp;
37:
38: /* Skip leading whitespace. */
1.9 markus 39: for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++)
40: ;
1.1 deraadt 41:
1.17 markus 42: bits = key_read(ret, &cp);
43: if (bits == 0)
1.7 markus 44: return 0;
45:
46: /* Skip trailing whitespace. */
1.9 markus 47: for (; *cp == ' ' || *cp == '\t'; cp++)
48: ;
1.7 markus 49:
50: /* Return results. */
51: *cpp = cp;
52: *bitsp = bits;
53: return 1;
1.1 deraadt 54: }
55:
1.14 markus 56: int
57: auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n)
58: {
59: Key *k = key_new(KEY_RSA);
60: int ret = hostfile_read_key(cpp, bitsp, k);
61: BN_copy(e, k->rsa->e);
62: BN_copy(n, k->rsa->n);
63: key_free(k);
64: return ret;
65: }
1.1 deraadt 66:
1.2 provos 67: int
1.14 markus 68: hostfile_check_key(int bits, Key *key, const char *host, const char *filename, int linenum)
1.1 deraadt 69: {
1.14 markus 70: if (key == NULL || key->type != KEY_RSA || key->rsa == NULL)
71: return 1;
72: if (bits != BN_num_bits(key->rsa->n)) {
1.18 markus 73: log("Warning: %s, line %d: keysize mismatch for host %s: "
1.14 markus 74: "actual %d vs. announced %d.",
75: filename, linenum, host, BN_num_bits(key->rsa->n), bits);
1.18 markus 76: log("Warning: replace %d with %d in %s, line %d.",
1.14 markus 77: bits, BN_num_bits(key->rsa->n), filename, linenum);
1.1 deraadt 78: }
1.14 markus 79: return 1;
1.1 deraadt 80: }
81:
1.9 markus 82: /*
83: * Checks whether the given host (which must be in all lowercase) is already
84: * in the list of our known hosts. Returns HOST_OK if the host is known and
85: * has the specified key, HOST_NEW if the host is not known, and HOST_CHANGED
86: * if the host is known but used to have a different host key.
87: */
1.1 deraadt 88:
1.2 provos 89: HostStatus
1.14 markus 90: check_host_in_hostfile(const char *filename, const char *host, Key *key, Key *found)
1.1 deraadt 91: {
1.7 markus 92: FILE *f;
93: char line[8192];
94: int linenum = 0;
1.12 markus 95: unsigned int kbits, hostlen;
1.7 markus 96: char *cp, *cp2;
97: HostStatus end_return;
98:
1.14 markus 99: if (key == NULL)
100: fatal("no key to look up");
1.7 markus 101: /* Open the file containing the list of known hosts. */
102: f = fopen(filename, "r");
103: if (!f)
104: return HOST_NEW;
105:
106: /* Cache the length of the host name. */
107: hostlen = strlen(host);
108:
1.9 markus 109: /*
110: * Return value when the loop terminates. This is set to
111: * HOST_CHANGED if we have seen a different key for the host and have
112: * not found the proper one.
113: */
1.7 markus 114: end_return = HOST_NEW;
115:
116: /* Go trough the file. */
117: while (fgets(line, sizeof(line), f)) {
118: cp = line;
119: linenum++;
120:
1.9 markus 121: /* Skip any leading whitespace, comments and empty lines. */
122: for (; *cp == ' ' || *cp == '\t'; cp++)
123: ;
1.7 markus 124: if (!*cp || *cp == '#' || *cp == '\n')
125: continue;
126:
127: /* Find the end of the host name portion. */
1.9 markus 128: for (cp2 = cp; *cp2 && *cp2 != ' ' && *cp2 != '\t'; cp2++)
129: ;
1.7 markus 130:
131: /* Check if the host name matches. */
1.19 ! markus 132: if (match_hostname(host, cp, (unsigned int) (cp2 - cp)) != 1)
1.7 markus 133: continue;
134:
135: /* Got a match. Skip host name. */
136: cp = cp2;
137:
1.9 markus 138: /*
139: * Extract the key from the line. This will skip any leading
140: * whitespace. Ignore badly formatted lines.
141: */
1.14 markus 142: if (!hostfile_read_key(&cp, &kbits, found))
143: continue;
144: if (!hostfile_check_key(kbits, found, host, filename, linenum))
1.7 markus 145: continue;
146:
147: /* Check if the current key is the same as the given key. */
1.14 markus 148: if (key_equal(key, found)) {
1.7 markus 149: /* Ok, they match. */
150: fclose(f);
151: return HOST_OK;
152: }
1.9 markus 153: /*
154: * They do not match. We will continue to go through the
155: * file; however, we note that we will not return that it is
156: * new.
157: */
1.7 markus 158: end_return = HOST_CHANGED;
1.1 deraadt 159: }
1.7 markus 160: /* Clear variables and close the file. */
161: fclose(f);
162:
1.9 markus 163: /*
164: * Return either HOST_NEW or HOST_CHANGED, depending on whether we
165: * saw a different key for the host.
166: */
1.7 markus 167: return end_return;
1.1 deraadt 168: }
169:
1.9 markus 170: /*
171: * Appends an entry to the host file. Returns false if the entry could not
172: * be appended.
173: */
1.1 deraadt 174:
1.2 provos 175: int
1.14 markus 176: add_host_to_hostfile(const char *filename, const char *host, Key *key)
1.1 deraadt 177: {
1.7 markus 178: FILE *f;
1.14 markus 179: int success = 0;
180: if (key == NULL)
1.17 markus 181: return 1; /* XXX ? */
1.7 markus 182: f = fopen(filename, "a");
183: if (!f)
184: return 0;
1.14 markus 185: fprintf(f, "%s ", host);
186: if (key_write(key, f)) {
187: success = 1;
188: } else {
1.17 markus 189: error("add_host_to_hostfile: saving key in %s failed", filename);
1.7 markus 190: }
1.17 markus 191: fprintf(f, "\n");
1.7 markus 192: fclose(f);
1.14 markus 193: return success;
1.1 deraadt 194: }