diff options
Diffstat (limited to 'hostfile.c')
-rw-r--r-- | hostfile.c | 123 |
1 files changed, 117 insertions, 6 deletions
diff --git a/hostfile.c b/hostfile.c index 88c054912..2e1c8bcd0 100644 --- a/hostfile.c +++ b/hostfile.c | |||
@@ -36,13 +36,102 @@ | |||
36 | */ | 36 | */ |
37 | 37 | ||
38 | #include "includes.h" | 38 | #include "includes.h" |
39 | RCSID("$OpenBSD: hostfile.c,v 1.32 2003/11/10 16:23:41 jakob Exp $"); | 39 | RCSID("$OpenBSD: hostfile.c,v 1.33 2005/03/01 10:40:26 djm Exp $"); |
40 | |||
41 | #include <resolv.h> | ||
42 | #include <openssl/hmac.h> | ||
43 | #include <openssl/sha.h> | ||
40 | 44 | ||
41 | #include "packet.h" | 45 | #include "packet.h" |
42 | #include "match.h" | 46 | #include "match.h" |
43 | #include "key.h" | 47 | #include "key.h" |
44 | #include "hostfile.h" | 48 | #include "hostfile.h" |
45 | #include "log.h" | 49 | #include "log.h" |
50 | #include "xmalloc.h" | ||
51 | |||
52 | static int | ||
53 | extract_salt(const char *s, u_int l, char *salt, size_t salt_len) | ||
54 | { | ||
55 | char *p, *b64salt; | ||
56 | u_int b64len; | ||
57 | int ret; | ||
58 | |||
59 | if (l < sizeof(HASH_MAGIC) - 1) { | ||
60 | debug2("extract_salt: string too short"); | ||
61 | return (-1); | ||
62 | } | ||
63 | if (strncmp(s, HASH_MAGIC, sizeof(HASH_MAGIC) - 1) != 0) { | ||
64 | debug2("extract_salt: invalid magic identifier"); | ||
65 | return (-1); | ||
66 | } | ||
67 | s += sizeof(HASH_MAGIC) - 1; | ||
68 | l -= sizeof(HASH_MAGIC) - 1; | ||
69 | if ((p = memchr(s, HASH_DELIM, l)) == NULL) { | ||
70 | debug2("extract_salt: missing salt termination character"); | ||
71 | return (-1); | ||
72 | } | ||
73 | |||
74 | b64len = p - s; | ||
75 | /* Sanity check */ | ||
76 | if (b64len == 0 || b64len > 1024) { | ||
77 | debug2("extract_salt: bad encoded salt length %u", b64len); | ||
78 | return (-1); | ||
79 | } | ||
80 | b64salt = xmalloc(1 + b64len); | ||
81 | memcpy(b64salt, s, b64len); | ||
82 | b64salt[b64len] = '\0'; | ||
83 | |||
84 | ret = __b64_pton(b64salt, salt, salt_len); | ||
85 | xfree(b64salt); | ||
86 | if (ret == -1) { | ||
87 | debug2("extract_salt: salt decode error"); | ||
88 | return (-1); | ||
89 | } | ||
90 | if (ret != SHA_DIGEST_LENGTH) { | ||
91 | debug2("extract_salt: expected salt len %u, got %u", | ||
92 | salt_len, ret); | ||
93 | return (-1); | ||
94 | } | ||
95 | |||
96 | return (0); | ||
97 | } | ||
98 | |||
99 | char * | ||
100 | host_hash(const char *host, const char *name_from_hostfile, u_int src_len) | ||
101 | { | ||
102 | const EVP_MD *md = EVP_sha1(); | ||
103 | HMAC_CTX mac_ctx; | ||
104 | char salt[256], result[256], uu_salt[512], uu_result[512]; | ||
105 | static char encoded[1024]; | ||
106 | u_int i, len; | ||
107 | |||
108 | len = EVP_MD_size(md); | ||
109 | |||
110 | if (name_from_hostfile == NULL) { | ||
111 | /* Create new salt */ | ||
112 | for (i = 0; i < len; i++) | ||
113 | salt[i] = arc4random(); | ||
114 | } else { | ||
115 | /* Extract salt from known host entry */ | ||
116 | if (extract_salt(name_from_hostfile, src_len, salt, | ||
117 | sizeof(salt)) == -1) | ||
118 | return (NULL); | ||
119 | } | ||
120 | |||
121 | HMAC_Init(&mac_ctx, salt, len, md); | ||
122 | HMAC_Update(&mac_ctx, host, strlen(host)); | ||
123 | HMAC_Final(&mac_ctx, result, NULL); | ||
124 | HMAC_cleanup(&mac_ctx); | ||
125 | |||
126 | if (__b64_ntop(salt, len, uu_salt, sizeof(uu_salt)) == -1 || | ||
127 | __b64_ntop(result, len, uu_result, sizeof(uu_result)) == -1) | ||
128 | fatal("host_hash: __b64_ntop failed"); | ||
129 | |||
130 | snprintf(encoded, sizeof(encoded), "%s%s%c%s", HASH_MAGIC, uu_salt, | ||
131 | HASH_DELIM, uu_result); | ||
132 | |||
133 | return (encoded); | ||
134 | } | ||
46 | 135 | ||
47 | /* | 136 | /* |
48 | * Parses an RSA (number of bits, e, n) or DSA key from a string. Moves the | 137 | * Parses an RSA (number of bits, e, n) or DSA key from a string. Moves the |
@@ -104,7 +193,7 @@ check_host_in_hostfile_by_key_or_type(const char *filename, | |||
104 | char line[8192]; | 193 | char line[8192]; |
105 | int linenum = 0; | 194 | int linenum = 0; |
106 | u_int kbits; | 195 | u_int kbits; |
107 | char *cp, *cp2; | 196 | char *cp, *cp2, *hashed_host; |
108 | HostStatus end_return; | 197 | HostStatus end_return; |
109 | 198 | ||
110 | debug3("check_host_in_hostfile: filename %s", filename); | 199 | debug3("check_host_in_hostfile: filename %s", filename); |
@@ -137,8 +226,18 @@ check_host_in_hostfile_by_key_or_type(const char *filename, | |||
137 | ; | 226 | ; |
138 | 227 | ||
139 | /* Check if the host name matches. */ | 228 | /* Check if the host name matches. */ |
140 | if (match_hostname(host, cp, (u_int) (cp2 - cp)) != 1) | 229 | if (match_hostname(host, cp, (u_int) (cp2 - cp)) != 1) { |
141 | continue; | 230 | if (*cp != HASH_DELIM) |
231 | continue; | ||
232 | hashed_host = host_hash(host, cp, (u_int) (cp2 - cp)); | ||
233 | if (hashed_host == NULL) { | ||
234 | debug("Invalid hashed host line %d of %s", | ||
235 | linenum, filename); | ||
236 | continue; | ||
237 | } | ||
238 | if (strncmp(hashed_host, cp, (u_int) (cp2 - cp)) != 0) | ||
239 | continue; | ||
240 | } | ||
142 | 241 | ||
143 | /* Got a match. Skip host name. */ | 242 | /* Got a match. Skip host name. */ |
144 | cp = cp2; | 243 | cp = cp2; |
@@ -211,16 +310,28 @@ lookup_key_in_hostfile_by_type(const char *filename, const char *host, | |||
211 | */ | 310 | */ |
212 | 311 | ||
213 | int | 312 | int |
214 | add_host_to_hostfile(const char *filename, const char *host, const Key *key) | 313 | add_host_to_hostfile(const char *filename, const char *host, const Key *key, |
314 | int store_hash) | ||
215 | { | 315 | { |
216 | FILE *f; | 316 | FILE *f; |
217 | int success = 0; | 317 | int success = 0; |
318 | char *hashed_host; | ||
319 | |||
218 | if (key == NULL) | 320 | if (key == NULL) |
219 | return 1; /* XXX ? */ | 321 | return 1; /* XXX ? */ |
220 | f = fopen(filename, "a"); | 322 | f = fopen(filename, "a"); |
221 | if (!f) | 323 | if (!f) |
222 | return 0; | 324 | return 0; |
223 | fprintf(f, "%s ", host); | 325 | |
326 | if (store_hash) { | ||
327 | if ((hashed_host = host_hash(host, NULL, 0)) == NULL) { | ||
328 | error("add_host_to_hostfile: host_hash failed"); | ||
329 | fclose(f); | ||
330 | return 0; | ||
331 | } | ||
332 | } | ||
333 | fprintf(f, "%s ", store_hash ? hashed_host : host); | ||
334 | |||
224 | if (key_write(key, f)) { | 335 | if (key_write(key, f)) { |
225 | success = 1; | 336 | success = 1; |
226 | } else { | 337 | } else { |