summaryrefslogtreecommitdiff
path: root/hostfile.c
diff options
context:
space:
mode:
authorColin Watson <cjwatson@debian.org>2010-03-31 10:46:28 +0100
committerColin Watson <cjwatson@debian.org>2010-03-31 10:46:28 +0100
commitefd3d4522636ae029488c2e9730b60c88e257d2e (patch)
tree31e02ac3f16090ce8c53448677356b2b7f423683 /hostfile.c
parentbbec4db36d464ea1d464a707625125f9fd5c7b5e (diff)
parentd1a87e462e1db89f19cd960588d0c6b287cb5ccc (diff)
* New upstream release (LP: #535029).
- After a transition period of about 10 years, this release disables SSH protocol 1 by default. Clients and servers that need to use the legacy protocol must explicitly enable it in ssh_config / sshd_config or on the command-line. - Remove the libsectok/OpenSC-based smartcard code and add support for PKCS#11 tokens. This support is enabled by default in the Debian packaging, since it now doesn't involve additional library dependencies (closes: #231472, LP: #16918). - Add support for certificate authentication of users and hosts using a new, minimal OpenSSH certificate format (closes: #482806). - Added a 'netcat mode' to ssh(1): "ssh -W host:port ...". - Add the ability to revoke keys in sshd(8) and ssh(1). (For the Debian package, this overlaps with the key blacklisting facility added in openssh 1:4.7p1-9, but with different file formats and slightly different scopes; for the moment, I've roughly merged the two.) - Various multiplexing improvements, including support for requesting port-forwardings via the multiplex protocol (closes: #360151). - Allow setting an explicit umask on the sftp-server(8) commandline to override whatever default the user has (closes: #496843). - Many sftp client improvements, including tab-completion, more options, and recursive transfer support for get/put (LP: #33378). The old mget/mput commands never worked properly and have been removed (closes: #270399, #428082). - Do not prompt for a passphrase if we fail to open a keyfile, and log the reason why the open failed to debug (closes: #431538). - Prevent sftp from crashing when given a "-" without a command. Also, allow whitespace to follow a "-" (closes: #531561).
Diffstat (limited to 'hostfile.c')
-rw-r--r--hostfile.c101
1 files changed, 92 insertions, 9 deletions
diff --git a/hostfile.c b/hostfile.c
index 2cceb352a..afab6dad1 100644
--- a/hostfile.c
+++ b/hostfile.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: hostfile.c,v 1.45 2006/08/03 03:34:42 deraadt Exp $ */ 1/* $OpenBSD: hostfile.c,v 1.48 2010/03/04 10:36:03 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -183,6 +183,41 @@ hostfile_check_key(int bits, const Key *key, const char *host, const char *filen
183 return 1; 183 return 1;
184} 184}
185 185
186static enum { MRK_ERROR, MRK_NONE, MRK_REVOKE, MRK_CA }
187check_markers(char **cpp)
188{
189 char marker[32], *sp, *cp = *cpp;
190 int ret = MRK_NONE;
191
192 while (*cp == '@') {
193 /* Only one marker is allowed */
194 if (ret != MRK_NONE)
195 return MRK_ERROR;
196 /* Markers are terminated by whitespace */
197 if ((sp = strchr(cp, ' ')) == NULL &&
198 (sp = strchr(cp, '\t')) == NULL)
199 return MRK_ERROR;
200 /* Extract marker for comparison */
201 if (sp <= cp + 1 || sp >= cp + sizeof(marker))
202 return MRK_ERROR;
203 memcpy(marker, cp, sp - cp);
204 marker[sp - cp] = '\0';
205 if (strcmp(marker, CA_MARKER) == 0)
206 ret = MRK_CA;
207 else if (strcmp(marker, REVOKE_MARKER) == 0)
208 ret = MRK_REVOKE;
209 else
210 return MRK_ERROR;
211
212 /* Skip past marker and any whitespace that follows it */
213 cp = sp;
214 for (; *cp == ' ' || *cp == '\t'; cp++)
215 ;
216 }
217 *cpp = cp;
218 return ret;
219}
220
186/* 221/*
187 * Checks whether the given host (which must be in all lowercase) is already 222 * Checks whether the given host (which must be in all lowercase) is already
188 * in the list of our known hosts. Returns HOST_OK if the host is known and 223 * in the list of our known hosts. Returns HOST_OK if the host is known and
@@ -195,16 +230,20 @@ hostfile_check_key(int bits, const Key *key, const char *host, const char *filen
195 230
196static HostStatus 231static HostStatus
197check_host_in_hostfile_by_key_or_type(const char *filename, 232check_host_in_hostfile_by_key_or_type(const char *filename,
198 const char *host, const Key *key, int keytype, Key *found, int *numret) 233 const char *host, const Key *key, int keytype, Key *found,
234 int want_revocation, int *numret)
199{ 235{
200 FILE *f; 236 FILE *f;
201 char line[8192]; 237 char line[8192];
202 int linenum = 0; 238 int want, have, linenum = 0, want_cert = key_is_cert(key);
203 u_int kbits; 239 u_int kbits;
204 char *cp, *cp2, *hashed_host; 240 char *cp, *cp2, *hashed_host;
205 HostStatus end_return; 241 HostStatus end_return;
206 242
207 debug3("check_host_in_hostfile: filename %s", filename); 243 debug3("check_host_in_hostfile: host %s filename %s", host, filename);
244
245 if (want_revocation && (key == NULL || keytype != 0 || found != NULL))
246 fatal("%s: invalid arguments", __func__);
208 247
209 /* Open the file containing the list of known hosts. */ 248 /* Open the file containing the list of known hosts. */
210 f = fopen(filename, "r"); 249 f = fopen(filename, "r");
@@ -229,6 +268,20 @@ check_host_in_hostfile_by_key_or_type(const char *filename,
229 if (!*cp || *cp == '#' || *cp == '\n') 268 if (!*cp || *cp == '#' || *cp == '\n')
230 continue; 269 continue;
231 270
271 if (want_revocation)
272 want = MRK_REVOKE;
273 else if (want_cert)
274 want = MRK_CA;
275 else
276 want = MRK_NONE;
277
278 if ((have = check_markers(&cp)) == MRK_ERROR) {
279 verbose("%s: invalid marker at %s:%d",
280 __func__, filename, linenum);
281 continue;
282 } else if (want != have)
283 continue;
284
232 /* Find the end of the host name portion. */ 285 /* Find the end of the host name portion. */
233 for (cp2 = cp; *cp2 && *cp2 != ' ' && *cp2 != '\t'; cp2++) 286 for (cp2 = cp; *cp2 && *cp2 != ' ' && *cp2 != '\t'; cp2++)
234 ; 287 ;
@@ -250,6 +303,9 @@ check_host_in_hostfile_by_key_or_type(const char *filename,
250 /* Got a match. Skip host name. */ 303 /* Got a match. Skip host name. */
251 cp = cp2; 304 cp = cp2;
252 305
306 if (want_revocation)
307 found = key_new(KEY_UNSPEC);
308
253 /* 309 /*
254 * Extract the key from the line. This will skip any leading 310 * Extract the key from the line. This will skip any leading
255 * whitespace. Ignore badly formatted lines. 311 * whitespace. Ignore badly formatted lines.
@@ -272,9 +328,33 @@ check_host_in_hostfile_by_key_or_type(const char *filename,
272 if (!hostfile_check_key(kbits, found, host, filename, linenum)) 328 if (!hostfile_check_key(kbits, found, host, filename, linenum))
273 continue; 329 continue;
274 330
331 if (want_revocation) {
332 if (key_is_cert(key) &&
333 key_equal_public(key->cert->signature_key, found)) {
334 verbose("check_host_in_hostfile: revoked CA "
335 "line %d", linenum);
336 key_free(found);
337 return HOST_REVOKED;
338 }
339 if (key_equal_public(key, found)) {
340 verbose("check_host_in_hostfile: revoked key "
341 "line %d", linenum);
342 key_free(found);
343 return HOST_REVOKED;
344 }
345 key_free(found);
346 continue;
347 }
348
275 /* Check if the current key is the same as the given key. */ 349 /* Check if the current key is the same as the given key. */
276 if (key_equal(key, found)) { 350 if (want_cert && key_equal(key->cert->signature_key, found)) {
277 /* Ok, they match. */ 351 /* Found CA cert for key */
352 debug3("check_host_in_hostfile: CA match line %d",
353 linenum);
354 fclose(f);
355 return HOST_OK;
356 } else if (!want_cert && key_equal(key, found)) {
357 /* Found identical key */
278 debug3("check_host_in_hostfile: match line %d", linenum); 358 debug3("check_host_in_hostfile: match line %d", linenum);
279 fclose(f); 359 fclose(f);
280 return HOST_OK; 360 return HOST_OK;
@@ -302,8 +382,11 @@ check_host_in_hostfile(const char *filename, const char *host, const Key *key,
302{ 382{
303 if (key == NULL) 383 if (key == NULL)
304 fatal("no key to look up"); 384 fatal("no key to look up");
305 return (check_host_in_hostfile_by_key_or_type(filename, host, key, 0, 385 if (check_host_in_hostfile_by_key_or_type(filename, host,
306 found, numret)); 386 key, 0, NULL, 1, NULL) == HOST_REVOKED)
387 return HOST_REVOKED;
388 return check_host_in_hostfile_by_key_or_type(filename, host, key, 0,
389 found, 0, numret);
307} 390}
308 391
309int 392int
@@ -311,7 +394,7 @@ lookup_key_in_hostfile_by_type(const char *filename, const char *host,
311 int keytype, Key *found, int *numret) 394 int keytype, Key *found, int *numret)
312{ 395{
313 return (check_host_in_hostfile_by_key_or_type(filename, host, NULL, 396 return (check_host_in_hostfile_by_key_or_type(filename, host, NULL,
314 keytype, found, numret) == HOST_FOUND); 397 keytype, found, 0, numret) == HOST_FOUND);
315} 398}
316 399
317/* 400/*