Mercurial > dropbear
comparison cli-kex.c @ 436:7282370416a0
Improve known_hosts checking.
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Thu, 22 Feb 2007 15:29:32 +0000 |
parents | ab57ba0cb667 |
children | 91939c8c2572 |
comparison
equal
deleted
inserted
replaced
435:337c45621e81 | 436:7282370416a0 |
---|---|
144 } | 144 } |
145 | 145 |
146 dropbear_exit("Didn't validate host key"); | 146 dropbear_exit("Didn't validate host key"); |
147 } | 147 } |
148 | 148 |
149 static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) { | 149 static FILE* open_known_hosts_file(int * readonly) |
150 | 150 { |
151 FILE * hostsfile = NULL; | |
151 char * filename = NULL; | 152 char * filename = NULL; |
152 FILE *hostsfile = NULL; | |
153 int readonly = 0; | |
154 struct passwd *pw = NULL; | |
155 char * homedir = NULL; | 153 char * homedir = NULL; |
156 unsigned int hostlen, algolen; | |
157 unsigned long len; | |
158 const char *algoname = NULL; | |
159 buffer * line = NULL; | |
160 int ret; | |
161 | 154 |
162 homedir = getenv("HOME"); | 155 homedir = getenv("HOME"); |
163 | 156 |
164 if (!homedir) { | 157 if (!homedir) { |
158 struct passwd * pw = NULL; | |
165 pw = getpwuid(getuid()); | 159 pw = getpwuid(getuid()); |
166 if (pw) { | 160 if (pw) { |
167 homedir = pw->pw_dir; | 161 homedir = pw->pw_dir; |
168 } | 162 } |
169 pw = NULL; | |
170 } | 163 } |
171 | 164 |
172 if (homedir) { | 165 if (homedir) { |
173 | 166 unsigned int len; |
174 len = strlen(homedir); | 167 len = strlen(homedir); |
175 filename = m_malloc(len + 18); /* "/.ssh/known_hosts" and null-terminator*/ | 168 filename = m_malloc(len + 18); /* "/.ssh/known_hosts" and null-terminator*/ |
176 | 169 |
177 snprintf(filename, len+18, "%s/.ssh", homedir); | 170 snprintf(filename, len+18, "%s/.ssh", homedir); |
178 /* Check that ~/.ssh exists - easiest way is just to mkdir */ | 171 /* Check that ~/.ssh exists - easiest way is just to mkdir */ |
179 if (mkdir(filename, S_IRWXU) != 0) { | 172 if (mkdir(filename, S_IRWXU) != 0) { |
180 if (errno != EEXIST) { | 173 if (errno != EEXIST) { |
181 dropbear_log(LOG_INFO, "Warning: failed creating %s/.ssh: %s", | 174 dropbear_log(LOG_INFO, "Warning: failed creating %s/.ssh: %s", |
182 homedir, strerror(errno)); | 175 homedir, strerror(errno)); |
183 TRACE(("mkdir didn't work: %s", strerror(errno))) | 176 TRACE(("mkdir didn't work: %s", strerror(errno))) |
184 ask_to_confirm(keyblob, keybloblen); | 177 goto out; |
185 goto out; /* only get here on success */ | |
186 } | 178 } |
187 } | 179 } |
188 | 180 |
189 snprintf(filename, len+18, "%s/.ssh/known_hosts", homedir); | 181 snprintf(filename, len+18, "%s/.ssh/known_hosts", homedir); |
190 hostsfile = fopen(filename, "a+"); | 182 hostsfile = fopen(filename, "a+"); |
191 | 183 |
192 if (hostsfile != NULL) { | 184 if (hostsfile != NULL) { |
185 *readonly = 0; | |
193 fseek(hostsfile, 0, SEEK_SET); | 186 fseek(hostsfile, 0, SEEK_SET); |
194 } else { | 187 } else { |
195 /* We mightn't have been able to open it if it was read-only */ | 188 /* We mightn't have been able to open it if it was read-only */ |
196 if (errno == EACCES || errno == EROFS) { | 189 if (errno == EACCES || errno == EROFS) { |
197 TRACE(("trying readonly: %s", strerror(errno))) | 190 TRACE(("trying readonly: %s", strerror(errno))) |
198 readonly = 1; | 191 *readonly = 1; |
199 hostsfile = fopen(filename, "r"); | 192 hostsfile = fopen(filename, "r"); |
200 } | 193 } |
201 } | 194 } |
202 } | 195 } |
203 | 196 |
204 if (hostsfile == NULL) { | 197 if (hostsfile == NULL) { |
205 TRACE(("hostsfile didn't open: %s", strerror(errno))) | 198 TRACE(("hostsfile didn't open: %s", strerror(errno))) |
206 dropbear_log(LOG_WARNING, "Failed to open %s/.ssh/known_hosts", | 199 dropbear_log(LOG_WARNING, "Failed to open %s/.ssh/known_hosts", |
207 homedir); | 200 homedir); |
201 goto out; | |
202 } | |
203 | |
204 out: | |
205 m_free(filename); | |
206 return hostsfile; | |
207 } | |
208 | |
209 static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) { | |
210 | |
211 FILE *hostsfile = NULL; | |
212 int readonly = 0; | |
213 unsigned int hostlen, algolen; | |
214 unsigned long len; | |
215 const char *algoname = NULL; | |
216 char * fingerprint = NULL; | |
217 buffer * line = NULL; | |
218 int ret; | |
219 | |
220 hostsfile = open_known_hosts_file(&readonly); | |
221 if (!hostsfile) { | |
208 ask_to_confirm(keyblob, keybloblen); | 222 ask_to_confirm(keyblob, keybloblen); |
209 goto out; /* We only get here on success */ | 223 /* ask_to_confirm will exit upon failure */ |
210 } | 224 return; |
211 | 225 } |
226 | |
212 line = buf_new(MAX_KNOWNHOSTS_LINE); | 227 line = buf_new(MAX_KNOWNHOSTS_LINE); |
213 hostlen = strlen(cli_opts.remotehost); | 228 hostlen = strlen(cli_opts.remotehost); |
214 algoname = signkey_name_from_type(ses.newkeys->algo_hostkey, &algolen); | 229 algoname = signkey_name_from_type(ses.newkeys->algo_hostkey, &algolen); |
215 | 230 |
216 do { | 231 do { |
240 /* there wasn't a space after the hostname, something dodgy */ | 255 /* there wasn't a space after the hostname, something dodgy */ |
241 TRACE(("missing space afte matching hostname")) | 256 TRACE(("missing space afte matching hostname")) |
242 continue; | 257 continue; |
243 } | 258 } |
244 | 259 |
245 if ( strncmp(buf_getptr(line, algolen), algoname, algolen) != 0) { | 260 if (strncmp(buf_getptr(line, algolen), algoname, algolen) != 0) { |
246 TRACE(("algo doesn't match")) | 261 TRACE(("algo doesn't match")) |
247 continue; | 262 continue; |
248 } | 263 } |
249 | 264 |
250 buf_incrpos(line, algolen); | 265 buf_incrpos(line, algolen); |
252 TRACE(("missing space after algo")) | 267 TRACE(("missing space after algo")) |
253 continue; | 268 continue; |
254 } | 269 } |
255 | 270 |
256 /* Now we're at the interesting hostkey */ | 271 /* Now we're at the interesting hostkey */ |
257 ret = cmp_base64_key(keyblob, keybloblen, algoname, algolen, line); | 272 ret = cmp_base64_key(keyblob, keybloblen, algoname, algolen, |
273 line, &fingerprint); | |
258 | 274 |
259 if (ret == DROPBEAR_SUCCESS) { | 275 if (ret == DROPBEAR_SUCCESS) { |
260 /* Good matching key */ | 276 /* Good matching key */ |
261 TRACE(("good matching key")) | 277 TRACE(("good matching key")) |
262 goto out; | 278 goto out; |
263 } | 279 } |
264 | 280 |
265 /* The keys didn't match. eep. */ | 281 /* The keys didn't match. eep. Note that we're "leaking" |
282 the fingerprint strings here, but we're exiting anyway */ | |
283 dropbear_exit("\n\nHost key mismatch for %s !\n" | |
284 "Fingerprint is %s\n" | |
285 "Expected %s\n" | |
286 "If you know that the host key is correct you can\nremove the bad entry from ~/.ssh/known_hosts", | |
287 cli_opts.remotehost, | |
288 sign_key_fingerprint(keyblob, keybloblen), | |
289 fingerprint ? fingerprint : "UNKNOWN"); | |
266 } while (1); /* keep going 'til something happens */ | 290 } while (1); /* keep going 'til something happens */ |
267 | 291 |
268 /* Key doesn't exist yet */ | 292 /* Key doesn't exist yet */ |
269 ask_to_confirm(keyblob, keybloblen); | 293 ask_to_confirm(keyblob, keybloblen); |
270 | 294 |
298 | 322 |
299 out: | 323 out: |
300 if (hostsfile != NULL) { | 324 if (hostsfile != NULL) { |
301 fclose(hostsfile); | 325 fclose(hostsfile); |
302 } | 326 } |
303 m_free(filename); | |
304 if (line != NULL) { | 327 if (line != NULL) { |
305 buf_free(line); | 328 buf_free(line); |
306 } | 329 } |
307 } | 330 } |