Annotation of src/usr.bin/ssh/hostfile.c, Revision 1.8
1.1 deraadt 1: /*
1.8 ! deraadt 2: *
! 3: * hostfile.c
! 4: *
! 5: * Author: Tatu Ylonen <ylo@cs.hut.fi>
! 6: *
! 7: * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
! 8: * All rights reserved
! 9: *
! 10: * Created: Thu Jun 29 07:10:56 1995 ylo
! 11: *
! 12: * Functions for manipulating the known hosts files.
! 13: *
! 14: */
1.1 deraadt 15:
16: #include "includes.h"
1.8 ! deraadt 17: RCSID("$Id: hostfile.c,v 1.7 1999/11/23 22:25:53 markus Exp $");
1.1 deraadt 18:
19: #include "packet.h"
20: #include "ssh.h"
21:
22: /* Reads a multiple-precision integer in hex from the buffer, and advances the
23: pointer. The integer must already be initialized. This function is
24: permitted to modify the buffer. This leaves *cpp to point just beyond
25: the last processed (and maybe modified) character. Note that this may
26: modify the buffer containing the number. */
27:
1.2 provos 28: int
1.7 markus 29: auth_rsa_read_bignum(char **cpp, BIGNUM * value)
1.1 deraadt 30: {
1.7 markus 31: char *cp = *cpp;
32: int len, old;
1.1 deraadt 33:
1.7 markus 34: /* Skip any leading whitespace. */
35: for (; *cp == ' ' || *cp == '\t'; cp++);
36:
37: /* Check that it begins with a hex digit. */
38: if (*cp < '0' || *cp > '9')
39: return 0;
40:
41: /* Save starting position. */
42: *cpp = cp;
43:
44: /* Move forward until all hex digits skipped. */
45: for (; *cp >= '0' && *cp <= '9'; cp++);
46:
47: /* Compute the length of the hex number. */
48: len = cp - *cpp;
49:
50: /* Save the old terminating character, and replace it by \0. */
51: old = *cp;
52: *cp = 0;
53:
54:
55: /* Parse the number. */
56: if (BN_dec2bn(&value, *cpp) == 0)
57: return 0;
58:
59: /* Restore old terminating character. */
60: *cp = old;
61:
62: /* Move beyond the number and return success. */
63: *cpp = cp;
64: return 1;
1.1 deraadt 65: }
66:
67: /* Parses an RSA key (number of bits, e, n) from a string. Moves the pointer
68: over the key. Skips any whitespace at the beginning and at end. */
69:
1.2 provos 70: int
1.7 markus 71: auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n)
1.1 deraadt 72: {
1.7 markus 73: unsigned int bits;
74: char *cp;
75:
76: /* Skip leading whitespace. */
77: for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++);
1.1 deraadt 78:
1.7 markus 79: /* Get number of bits. */
80: if (*cp < '0' || *cp > '9')
81: return 0; /* Bad bit count... */
82: for (bits = 0; *cp >= '0' && *cp <= '9'; cp++)
83: bits = 10 * bits + *cp - '0';
84:
85: /* Get public exponent. */
86: if (!auth_rsa_read_bignum(&cp, e))
87: return 0;
88:
89: /* Get public modulus. */
90: if (!auth_rsa_read_bignum(&cp, n))
91: return 0;
92:
93: /* Skip trailing whitespace. */
94: for (; *cp == ' ' || *cp == '\t'; cp++);
95:
96: /* Return results. */
97: *cpp = cp;
98: *bitsp = bits;
99: return 1;
1.1 deraadt 100: }
101:
102: /* Tries to match the host name (which must be in all lowercase) against the
1.7 markus 103: comma-separated sequence of subpatterns (each possibly preceded by ! to
1.1 deraadt 104: indicate negation). Returns true if there is a positive match; zero
105: otherwise. */
106:
1.2 provos 107: int
108: match_hostname(const char *host, const char *pattern, unsigned int len)
1.1 deraadt 109: {
1.7 markus 110: char sub[1024];
111: int negated;
112: int got_positive;
113: unsigned int i, subi;
114:
115: got_positive = 0;
116: for (i = 0; i < len;) {
117: /* Check if the subpattern is negated. */
118: if (pattern[i] == '!') {
119: negated = 1;
120: i++;
121: } else
122: negated = 0;
123:
124: /* Extract the subpattern up to a comma or end. Convert
125: the subpattern to lowercase. */
126: for (subi = 0;
127: i < len && subi < sizeof(sub) - 1 && pattern[i] != ',';
128: subi++, i++)
129: sub[subi] = isupper(pattern[i]) ? tolower(pattern[i]) : pattern[i];
130: /* If subpattern too long, return failure (no match). */
131: if (subi >= sizeof(sub) - 1)
132: return 0;
133:
134: /* If the subpattern was terminated by a comma, skip the
135: comma. */
136: if (i < len && pattern[i] == ',')
137: i++;
138:
139: /* Null-terminate the subpattern. */
140: sub[subi] = '\0';
141:
142: /* Try to match the subpattern against the host name. */
143: if (match_pattern(host, sub)) {
144: if (negated)
145: return 0; /* Fail if host matches
146: any negated subpattern. */
147: else
148: got_positive = 1;
149: }
1.1 deraadt 150: }
1.7 markus 151:
152: /* Return success if got a positive match. If there was a
153: negative match, we have already returned zero and never get
154: here. */
155: return got_positive;
1.1 deraadt 156: }
157:
1.7 markus 158: /* Checks whether the given host (which must be in all lowercase) is
1.1 deraadt 159: already in the list of our known hosts.
160: Returns HOST_OK if the host is known and has the specified key,
161: HOST_NEW if the host is not known, and HOST_CHANGED if the host is known
162: but used to have a different host key. */
163:
1.2 provos 164: HostStatus
1.5 markus 165: check_host_in_hostfile(const char *filename, const char *host,
1.7 markus 166: BIGNUM * e, BIGNUM * n, BIGNUM * ke, BIGNUM * kn)
1.1 deraadt 167: {
1.7 markus 168: FILE *f;
169: char line[8192];
170: int linenum = 0;
171: unsigned int bits, kbits, hostlen;
172: char *cp, *cp2;
173: HostStatus end_return;
174:
175: /* Open the file containing the list of known hosts. */
176: f = fopen(filename, "r");
177: if (!f)
178: return HOST_NEW;
179:
180: /* Cache the length of the host name. */
181: hostlen = strlen(host);
182:
183: /* Return value when the loop terminates. This is set to
184: HOST_CHANGED if we have seen a different key for the host and
185: have not found the proper one. */
186: end_return = HOST_NEW;
187:
188: /* size of modulus 'n' */
189: bits = BN_num_bits(n);
190:
191: /* Go trough the file. */
192: while (fgets(line, sizeof(line), f)) {
193: cp = line;
194: linenum++;
195:
196: /* Skip any leading whitespace. */
197: for (; *cp == ' ' || *cp == '\t'; cp++);
198:
199: /* Ignore comment lines and empty lines. */
200: if (!*cp || *cp == '#' || *cp == '\n')
201: continue;
202:
203: /* Find the end of the host name portion. */
204: for (cp2 = cp; *cp2 && *cp2 != ' ' && *cp2 != '\t'; cp2++);
205:
206: /* Check if the host name matches. */
207: if (!match_hostname(host, cp, (unsigned int) (cp2 - cp)))
208: continue;
209:
210: /* Got a match. Skip host name. */
211: cp = cp2;
212:
213: /* Extract the key from the line. This will skip any
214: leading whitespace. Ignore badly formatted lines. */
215: if (!auth_rsa_read_key(&cp, &kbits, ke, kn))
216: continue;
217:
218: if (kbits != BN_num_bits(kn)) {
219: error("Warning: error in %s, line %d: keysize mismatch for host %s: "
220: "actual size %d vs. announced %d.",
221: filename, linenum, host, BN_num_bits(kn), kbits);
222: error("Warning: replace %d with %d in %s, line %d.",
223: kbits, BN_num_bits(kn), filename, linenum);
224: }
225: /* Check if the current key is the same as the given key. */
226: if (BN_cmp(ke, e) == 0 && BN_cmp(kn, n) == 0) {
227: /* Ok, they match. */
228: fclose(f);
229: return HOST_OK;
230: }
231: /* They do not match. We will continue to go through the
232: file; however, we note that we will not return that it
233: is new. */
234: end_return = HOST_CHANGED;
1.1 deraadt 235: }
1.7 markus 236: /* Clear variables and close the file. */
237: fclose(f);
238:
239: /* Return either HOST_NEW or HOST_CHANGED, depending on whether we
240: saw a different key for the host. */
241: return end_return;
1.1 deraadt 242: }
243:
244: /* Appends an entry to the host file. Returns false if the entry
245: could not be appended. */
246:
1.2 provos 247: int
248: add_host_to_hostfile(const char *filename, const char *host,
1.7 markus 249: BIGNUM * e, BIGNUM * n)
1.1 deraadt 250: {
1.7 markus 251: FILE *f;
252: char *buf;
253: unsigned int bits;
254:
255: /* Open the file for appending. */
256: f = fopen(filename, "a");
257: if (!f)
258: return 0;
259:
260: /* size of modulus 'n' */
261: bits = BN_num_bits(n);
262:
263: /* Print the host name and key to the file. */
264: fprintf(f, "%s %u ", host, bits);
265: buf = BN_bn2dec(e);
266: if (buf == NULL) {
267: error("add_host_to_hostfile: BN_bn2dec(e) failed");
268: fclose(f);
269: return 0;
270: }
271: fprintf(f, "%s ", buf);
272: free(buf);
273: buf = BN_bn2dec(n);
274: if (buf == NULL) {
275: error("add_host_to_hostfile: BN_bn2dec(n) failed");
276: fclose(f);
277: return 0;
278: }
279: fprintf(f, "%s\n", buf);
280: free(buf);
281:
282: /* Close the file. */
283: fclose(f);
284: return 1;
1.1 deraadt 285: }