version 1.218, 2010/01/13 00:19:04 |
version 1.219, 2010/02/26 20:29:54 |
|
|
#include "misc.h" |
#include "misc.h" |
#include "dns.h" |
#include "dns.h" |
#include "roaming.h" |
#include "roaming.h" |
|
#include "ssh2.h" |
#include "version.h" |
#include "version.h" |
|
|
char *client_version_string = NULL; |
char *client_version_string = NULL; |
|
|
} |
} |
} |
} |
|
|
|
static int |
|
check_host_cert(const char *host, const Key *host_key) |
|
{ |
|
const char *reason; |
|
|
|
if (key_cert_check_authority(host_key, 1, 0, host, &reason) != 0) { |
|
error("%s", reason); |
|
return 0; |
|
} |
|
if (buffer_len(&host_key->cert->constraints) != 0) { |
|
error("Certificate for %s contains unsupported constraint(s)", |
|
host); |
|
return 0; |
|
} |
|
return 1; |
|
} |
|
|
/* |
/* |
* check whether the supplied host key is valid, return -1 if the key |
* check whether the supplied host key is valid, return -1 if the key |
* is not valid. the user_hostfile will not be updated if 'readonly' is true. |
* is not valid. the user_hostfile will not be updated if 'readonly' is true. |
|
|
Key *host_key, int readonly, const char *user_hostfile, |
Key *host_key, int readonly, const char *user_hostfile, |
const char *system_hostfile) |
const char *system_hostfile) |
{ |
{ |
Key *file_key; |
Key *file_key, *raw_key = NULL; |
const char *type = key_type(host_key); |
const char *type; |
char *ip = NULL, *host = NULL; |
char *ip = NULL, *host = NULL; |
char hostline[1000], *hostp, *fp, *ra; |
char hostline[1000], *hostp, *fp, *ra; |
HostStatus host_status; |
HostStatus host_status; |
HostStatus ip_status; |
HostStatus ip_status; |
int r, local = 0, host_ip_differ = 0; |
int r, want_cert, local = 0, host_ip_differ = 0; |
char ntop[NI_MAXHOST]; |
char ntop[NI_MAXHOST]; |
char msg[1024]; |
char msg[1024]; |
int len, host_line, ip_line, cancelled_forwarding = 0; |
int len, host_line, ip_line, cancelled_forwarding = 0; |
|
|
host = put_host_port(hostname, port); |
host = put_host_port(hostname, port); |
} |
} |
|
|
|
retry: |
|
want_cert = key_is_cert(host_key); |
|
type = key_type(host_key); |
|
|
/* |
/* |
* Store the host key from the known host file in here so that we can |
* Store the host key from the known host file in here so that we can |
* compare it with the key for the IP address. |
* compare it with the key for the IP address. |
*/ |
*/ |
file_key = key_new(host_key->type); |
file_key = key_new(key_is_cert(host_key) ? KEY_UNSPEC : host_key->type); |
|
|
/* |
/* |
* Check if the host key is present in the user's list of known |
* Check if the host key is present in the user's list of known |
|
|
} |
} |
/* |
/* |
* Also perform check for the ip address, skip the check if we are |
* Also perform check for the ip address, skip the check if we are |
* localhost or the hostname was an ip address to begin with |
* localhost, looking for a certificate, or the hostname was an ip |
|
* address to begin with. |
*/ |
*/ |
if (options.check_host_ip) { |
if (!want_cert && options.check_host_ip) { |
Key *ip_key = key_new(host_key->type); |
Key *ip_key = key_new(host_key->type); |
|
|
ip_file = user_hostfile; |
ip_file = user_hostfile; |
|
|
switch (host_status) { |
switch (host_status) { |
case HOST_OK: |
case HOST_OK: |
/* The host is known and the key matches. */ |
/* The host is known and the key matches. */ |
debug("Host '%.200s' is known and matches the %s host key.", |
debug("Host '%.200s' is known and matches the %s host %s.", |
host, type); |
host, type, want_cert ? "certificate" : "key"); |
debug("Found key in %s:%d", host_file, host_line); |
debug("Found %s in %s:%d", |
|
want_cert ? "certificate" : "key", host_file, host_line); |
|
if (want_cert && !check_host_cert(hostname, host_key)) |
|
goto fail; |
if (options.check_host_ip && ip_status == HOST_NEW) { |
if (options.check_host_ip && ip_status == HOST_NEW) { |
if (readonly) |
if (readonly || want_cert) |
logit("%s host key for IP address " |
logit("%s host key for IP address " |
"'%.128s' not in list of known hosts.", |
"'%.128s' not in list of known hosts.", |
type, ip); |
type, ip); |
|
|
break; |
break; |
} |
} |
} |
} |
if (readonly) |
if (readonly || want_cert) |
goto fail; |
goto fail; |
/* The host is new. */ |
/* The host is new. */ |
if (options.strict_host_key_checking == 1) { |
if (options.strict_host_key_checking == 1) { |
|
|
"list of known hosts.", hostp, type); |
"list of known hosts.", hostp, type); |
break; |
break; |
case HOST_CHANGED: |
case HOST_CHANGED: |
|
if (want_cert) { |
|
/* |
|
* This is only a debug() since it is valid to have |
|
* CAs with wildcard DNS matches that don't match |
|
* all hosts that one might visit. |
|
*/ |
|
debug("Host certificate authority does not " |
|
"match %s in %s:%d", CA_MARKER, |
|
host_file, host_line); |
|
goto fail; |
|
} |
if (readonly == ROQUIET) |
if (readonly == ROQUIET) |
goto fail; |
goto fail; |
if (options.check_host_ip && host_ip_differ) { |
if (options.check_host_ip && host_ip_differ) { |
|
|
return 0; |
return 0; |
|
|
fail: |
fail: |
|
if (want_cert) { |
|
/* |
|
* No matching certificate. Downgrade cert to raw key and |
|
* search normally. |
|
*/ |
|
debug("No matching CA found. Retry with plain key"); |
|
raw_key = key_from_private(host_key); |
|
if (key_drop_cert(raw_key) != 0) |
|
fatal("Couldn't drop certificate"); |
|
host_key = raw_key; |
|
goto retry; |
|
} |
|
if (raw_key != NULL) |
|
key_free(raw_key); |
xfree(ip); |
xfree(ip); |
xfree(host); |
xfree(host); |
return -1; |
return -1; |
|
|
struct stat st; |
struct stat st; |
int flags = 0; |
int flags = 0; |
|
|
if (options.verify_host_key_dns && |
/* XXX certs are not yet supported for DNS */ |
|
if (!key_is_cert(host_key) && options.verify_host_key_dns && |
verify_host_key_dns(host, hostaddr, host_key, &flags) == 0) { |
verify_host_key_dns(host, hostaddr, host_key, &flags) == 0) { |
|
|
if (flags & DNS_VERIFY_FOUND) { |
if (flags & DNS_VERIFY_FOUND) { |