Mercurial > dropbear
comparison cli-kex.c @ 511:582cb38e4eb5 insecure-nocrypto
propagate from branch 'au.asn.ucc.matt.dropbear' (head cdcc3c729e29544e8b98a408e2dc60e4483dfd2a)
to branch 'au.asn.ucc.matt.dropbear.insecure-nocrypto' (head 0ca38a1cf349f7426ac9de34ebe4c3e3735effab)
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Thu, 06 Nov 2008 13:16:55 +0000 |
parents | 91939c8c2572 |
children | 9e51707cd6f2 76097ec1a29a |
comparison
equal
deleted
inserted
replaced
361:461c4b1fb35f | 511:582cb38e4eb5 |
---|---|
117 char* fp = NULL; | 117 char* fp = NULL; |
118 FILE *tty = NULL; | 118 FILE *tty = NULL; |
119 char response = 'z'; | 119 char response = 'z'; |
120 | 120 |
121 fp = sign_key_fingerprint(keyblob, keybloblen); | 121 fp = sign_key_fingerprint(keyblob, keybloblen); |
122 fprintf(stderr, "\nHost '%s' is not in the trusted hosts file.\n(fingerprint %s)\nDo you want to continue connecting? (y/n)\n", | 122 if (cli_opts.always_accept_key) { |
123 fprintf(stderr, "\nHost '%s' key accepted unconditionally.\n(fingerprint %s)\n", | |
124 cli_opts.remotehost, | |
125 fp); | |
126 m_free(fp); | |
127 return; | |
128 } | |
129 fprintf(stderr, "\nHost '%s' is not in the trusted hosts file.\n(fingerprint %s)\nDo you want to continue connecting? (y/n) ", | |
123 cli_opts.remotehost, | 130 cli_opts.remotehost, |
124 fp); | 131 fp); |
132 m_free(fp); | |
125 | 133 |
126 tty = fopen(_PATH_TTY, "r"); | 134 tty = fopen(_PATH_TTY, "r"); |
127 if (tty) { | 135 if (tty) { |
128 response = getc(tty); | 136 response = getc(tty); |
129 fclose(tty); | 137 fclose(tty); |
130 } else { | 138 } else { |
131 response = getc(stdin); | 139 response = getc(stdin); |
132 } | 140 } |
133 | 141 |
134 if (response == 'y') { | 142 if (response == 'y') { |
135 m_free(fp); | |
136 return; | 143 return; |
137 } | 144 } |
138 | 145 |
139 dropbear_exit("Didn't validate host key"); | 146 dropbear_exit("Didn't validate host key"); |
140 } | 147 } |
141 | 148 |
149 static FILE* open_known_hosts_file(int * readonly) | |
150 { | |
151 FILE * hostsfile = NULL; | |
152 char * filename = NULL; | |
153 char * homedir = NULL; | |
154 | |
155 homedir = getenv("HOME"); | |
156 | |
157 if (!homedir) { | |
158 struct passwd * pw = NULL; | |
159 pw = getpwuid(getuid()); | |
160 if (pw) { | |
161 homedir = pw->pw_dir; | |
162 } | |
163 } | |
164 | |
165 if (homedir) { | |
166 unsigned int len; | |
167 len = strlen(homedir); | |
168 filename = m_malloc(len + 18); /* "/.ssh/known_hosts" and null-terminator*/ | |
169 | |
170 snprintf(filename, len+18, "%s/.ssh", homedir); | |
171 /* Check that ~/.ssh exists - easiest way is just to mkdir */ | |
172 if (mkdir(filename, S_IRWXU) != 0) { | |
173 if (errno != EEXIST) { | |
174 dropbear_log(LOG_INFO, "Warning: failed creating %s/.ssh: %s", | |
175 homedir, strerror(errno)); | |
176 TRACE(("mkdir didn't work: %s", strerror(errno))) | |
177 goto out; | |
178 } | |
179 } | |
180 | |
181 snprintf(filename, len+18, "%s/.ssh/known_hosts", homedir); | |
182 hostsfile = fopen(filename, "a+"); | |
183 | |
184 if (hostsfile != NULL) { | |
185 *readonly = 0; | |
186 fseek(hostsfile, 0, SEEK_SET); | |
187 } else { | |
188 /* We mightn't have been able to open it if it was read-only */ | |
189 if (errno == EACCES || errno == EROFS) { | |
190 TRACE(("trying readonly: %s", strerror(errno))) | |
191 *readonly = 1; | |
192 hostsfile = fopen(filename, "r"); | |
193 } | |
194 } | |
195 } | |
196 | |
197 if (hostsfile == NULL) { | |
198 TRACE(("hostsfile didn't open: %s", strerror(errno))) | |
199 dropbear_log(LOG_WARNING, "Failed to open %s/.ssh/known_hosts", | |
200 homedir); | |
201 goto out; | |
202 } | |
203 | |
204 out: | |
205 m_free(filename); | |
206 return hostsfile; | |
207 } | |
208 | |
142 static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) { | 209 static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) { |
143 | 210 |
144 char * filename = NULL; | |
145 FILE *hostsfile = NULL; | 211 FILE *hostsfile = NULL; |
146 int readonly = 0; | 212 int readonly = 0; |
147 struct passwd *pw = NULL; | |
148 unsigned int hostlen, algolen; | 213 unsigned int hostlen, algolen; |
149 unsigned long len; | 214 unsigned long len; |
150 const char *algoname = NULL; | 215 const char *algoname = NULL; |
216 char * fingerprint = NULL; | |
151 buffer * line = NULL; | 217 buffer * line = NULL; |
152 int ret; | 218 int ret; |
219 | |
220 hostsfile = open_known_hosts_file(&readonly); | |
221 if (!hostsfile) { | |
222 ask_to_confirm(keyblob, keybloblen); | |
223 /* ask_to_confirm will exit upon failure */ | |
224 return; | |
225 } | |
153 | 226 |
154 pw = getpwuid(getuid()); | |
155 | |
156 if (pw == NULL) { | |
157 dropbear_exit("Failed to get homedir"); | |
158 } | |
159 | |
160 len = strlen(pw->pw_dir); | |
161 filename = m_malloc(len + 18); /* "/.ssh/known_hosts" and null-terminator*/ | |
162 | |
163 snprintf(filename, len+18, "%s/.ssh", pw->pw_dir); | |
164 /* Check that ~/.ssh exists - easiest way is just to mkdir */ | |
165 if (mkdir(filename, S_IRWXU) != 0) { | |
166 if (errno != EEXIST) { | |
167 dropbear_log(LOG_INFO, "Warning: failed creating ~/.ssh: %s", | |
168 strerror(errno)); | |
169 TRACE(("mkdir didn't work: %s", strerror(errno))) | |
170 ask_to_confirm(keyblob, keybloblen); | |
171 goto out; /* only get here on success */ | |
172 } | |
173 } | |
174 | |
175 snprintf(filename, len+18, "%s/.ssh/known_hosts", pw->pw_dir); | |
176 hostsfile = fopen(filename, "a+"); | |
177 | |
178 if (hostsfile != NULL) { | |
179 fseek(hostsfile, 0, SEEK_SET); | |
180 } else { | |
181 /* We mightn't have been able to open it if it was read-only */ | |
182 if (errno == EACCES || errno == EROFS) { | |
183 TRACE(("trying readonly: %s", strerror(errno))) | |
184 readonly = 1; | |
185 hostsfile = fopen(filename, "r"); | |
186 } | |
187 } | |
188 | |
189 if (hostsfile == NULL) { | |
190 TRACE(("hostsfile didn't open: %s", strerror(errno))) | |
191 ask_to_confirm(keyblob, keybloblen); | |
192 goto out; /* We only get here on success */ | |
193 } | |
194 | |
195 line = buf_new(MAX_KNOWNHOSTS_LINE); | 227 line = buf_new(MAX_KNOWNHOSTS_LINE); |
196 hostlen = strlen(cli_opts.remotehost); | 228 hostlen = strlen(cli_opts.remotehost); |
197 algoname = signkey_name_from_type(ses.newkeys->algo_hostkey, &algolen); | 229 algoname = signkey_name_from_type(ses.newkeys->algo_hostkey, &algolen); |
198 | 230 |
199 do { | 231 do { |
223 /* there wasn't a space after the hostname, something dodgy */ | 255 /* there wasn't a space after the hostname, something dodgy */ |
224 TRACE(("missing space afte matching hostname")) | 256 TRACE(("missing space afte matching hostname")) |
225 continue; | 257 continue; |
226 } | 258 } |
227 | 259 |
228 if ( strncmp(buf_getptr(line, algolen), algoname, algolen) != 0) { | 260 if (strncmp(buf_getptr(line, algolen), algoname, algolen) != 0) { |
229 TRACE(("algo doesn't match")) | 261 TRACE(("algo doesn't match")) |
230 continue; | 262 continue; |
231 } | 263 } |
232 | 264 |
233 buf_incrpos(line, algolen); | 265 buf_incrpos(line, algolen); |
235 TRACE(("missing space after algo")) | 267 TRACE(("missing space after algo")) |
236 continue; | 268 continue; |
237 } | 269 } |
238 | 270 |
239 /* Now we're at the interesting hostkey */ | 271 /* Now we're at the interesting hostkey */ |
240 ret = cmp_base64_key(keyblob, keybloblen, algoname, algolen, line); | 272 ret = cmp_base64_key(keyblob, keybloblen, algoname, algolen, |
273 line, &fingerprint); | |
241 | 274 |
242 if (ret == DROPBEAR_SUCCESS) { | 275 if (ret == DROPBEAR_SUCCESS) { |
243 /* Good matching key */ | 276 /* Good matching key */ |
244 TRACE(("good matching key")) | 277 TRACE(("good matching key")) |
245 goto out; | 278 goto out; |
246 } | 279 } |
247 | 280 |
248 /* 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"); | |
249 } while (1); /* keep going 'til something happens */ | 290 } while (1); /* keep going 'til something happens */ |
250 | 291 |
251 /* Key doesn't exist yet */ | 292 /* Key doesn't exist yet */ |
252 ask_to_confirm(keyblob, keybloblen); | 293 ask_to_confirm(keyblob, keybloblen); |
253 | 294 |
256 if (readonly) { | 297 if (readonly) { |
257 TRACE(("readonly")) | 298 TRACE(("readonly")) |
258 goto out; | 299 goto out; |
259 } | 300 } |
260 | 301 |
261 /* put the new entry in the file */ | 302 if (!cli_opts.always_accept_key) { |
262 fseek(hostsfile, 0, SEEK_END); /* In case it wasn't opened append */ | 303 /* put the new entry in the file */ |
263 buf_setpos(line, 0); | 304 fseek(hostsfile, 0, SEEK_END); /* In case it wasn't opened append */ |
264 buf_setlen(line, 0); | 305 buf_setpos(line, 0); |
265 buf_putbytes(line, ses.remotehost, hostlen); | 306 buf_setlen(line, 0); |
266 buf_putbyte(line, ' '); | 307 buf_putbytes(line, ses.remotehost, hostlen); |
267 buf_putbytes(line, algoname, algolen); | 308 buf_putbyte(line, ' '); |
268 buf_putbyte(line, ' '); | 309 buf_putbytes(line, algoname, algolen); |
269 len = line->size - line->pos; | 310 buf_putbyte(line, ' '); |
270 TRACE(("keybloblen %d, len %d", keybloblen, len)) | 311 len = line->size - line->pos; |
271 /* The only failure with base64 is buffer_overflow, but buf_getwriteptr | 312 TRACE(("keybloblen %d, len %d", keybloblen, len)) |
272 * will die horribly in the case anyway */ | 313 /* The only failure with base64 is buffer_overflow, but buf_getwriteptr |
273 base64_encode(keyblob, keybloblen, buf_getwriteptr(line, len), &len); | 314 * will die horribly in the case anyway */ |
274 buf_incrwritepos(line, len); | 315 base64_encode(keyblob, keybloblen, buf_getwriteptr(line, len), &len); |
275 buf_putbyte(line, '\n'); | 316 buf_incrwritepos(line, len); |
276 buf_setpos(line, 0); | 317 buf_putbyte(line, '\n'); |
277 fwrite(buf_getptr(line, line->len), line->len, 1, hostsfile); | 318 buf_setpos(line, 0); |
278 /* We ignore errors, since there's not much we can do about them */ | 319 fwrite(buf_getptr(line, line->len), line->len, 1, hostsfile); |
320 /* We ignore errors, since there's not much we can do about them */ | |
321 } | |
279 | 322 |
280 out: | 323 out: |
281 if (hostsfile != NULL) { | 324 if (hostsfile != NULL) { |
282 fclose(hostsfile); | 325 fclose(hostsfile); |
283 } | 326 } |
284 m_free(filename); | |
285 if (line != NULL) { | 327 if (line != NULL) { |
286 buf_free(line); | 328 buf_free(line); |
287 } | 329 } |
288 } | 330 } |