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