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 }