diff options
author | Colin Watson <cjwatson@debian.org> | 2010-03-31 10:46:28 +0100 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2010-03-31 10:46:28 +0100 |
commit | efd3d4522636ae029488c2e9730b60c88e257d2e (patch) | |
tree | 31e02ac3f16090ce8c53448677356b2b7f423683 /hostfile.c | |
parent | bbec4db36d464ea1d464a707625125f9fd5c7b5e (diff) | |
parent | d1a87e462e1db89f19cd960588d0c6b287cb5ccc (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.c | 101 |
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 | ||
186 | static enum { MRK_ERROR, MRK_NONE, MRK_REVOKE, MRK_CA } | ||
187 | check_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 | ||
196 | static HostStatus | 231 | static HostStatus |
197 | check_host_in_hostfile_by_key_or_type(const char *filename, | 232 | check_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 | ||
309 | int | 392 | int |
@@ -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 | /* |