version 1.107, 2001/06/07 20:23:05 |
version 1.108, 2001/06/23 02:34:31 |
|
|
while (1) { |
while (1) { |
fprintf(stderr, "%s", prompt); |
fprintf(stderr, "%s", prompt); |
if (fgets(buf, sizeof(buf), f) == NULL) { |
if (fgets(buf, sizeof(buf), f) == NULL) { |
/* Print a newline (the prompt probably didn\'t have one). */ |
/* |
|
* Print a newline (the prompt probably didn\'t have |
|
* one). |
|
*/ |
fprintf(stderr, "\n"); |
fprintf(stderr, "\n"); |
strlcpy(buf, "no", sizeof buf); |
strlcpy(buf, "no", sizeof buf); |
} |
} |
|
|
} |
} |
|
|
/* |
/* |
* check whether the supplied host key is valid, return only if ok. |
* 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. |
*/ |
*/ |
|
|
void |
int |
check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key, |
check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key, |
const char *user_hostfile, const char *system_hostfile) |
int readonly, const char *user_hostfile, const char *system_hostfile) |
{ |
{ |
Key *file_key; |
Key *file_key; |
char *type = key_type(host_key); |
char *type = key_type(host_key); |
|
|
/** hostaddr == 0! */ |
/** hostaddr == 0! */ |
switch (hostaddr->sa_family) { |
switch (hostaddr->sa_family) { |
case AF_INET: |
case AF_INET: |
local = (ntohl(((struct sockaddr_in *)hostaddr)->sin_addr.s_addr) >> 24) == IN_LOOPBACKNET; |
local = (ntohl(((struct sockaddr_in *)hostaddr)-> |
|
sin_addr.s_addr) >> 24) == IN_LOOPBACKNET; |
break; |
break; |
case AF_INET6: |
case AF_INET6: |
local = IN6_IS_ADDR_LOOPBACK(&(((struct sockaddr_in6 *)hostaddr)->sin6_addr)); |
local = IN6_IS_ADDR_LOOPBACK( |
|
&(((struct sockaddr_in6 *)hostaddr)->sin6_addr)); |
break; |
break; |
default: |
default: |
local = 0; |
local = 0; |
|
|
if (local && options.host_key_alias == NULL) { |
if (local && options.host_key_alias == NULL) { |
debug("Forcing accepting of host key for " |
debug("Forcing accepting of host key for " |
"loopback/localhost."); |
"loopback/localhost."); |
return; |
return 0; |
} |
} |
|
|
/* |
/* |
|
|
* hosts or in the systemwide list. |
* hosts or in the systemwide list. |
*/ |
*/ |
host_file = user_hostfile; |
host_file = user_hostfile; |
host_status = check_host_in_hostfile(host_file, host, host_key, file_key, &host_line); |
host_status = check_host_in_hostfile(host_file, host, host_key, |
|
file_key, &host_line); |
if (host_status == HOST_NEW) { |
if (host_status == HOST_NEW) { |
host_file = system_hostfile; |
host_file = system_hostfile; |
host_status = check_host_in_hostfile(host_file, host, host_key, file_key, &host_line); |
host_status = check_host_in_hostfile(host_file, host, host_key, |
|
file_key, &host_line); |
} |
} |
/* |
/* |
* 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 |
|
|
Key *ip_key = key_new(host_key->type); |
Key *ip_key = key_new(host_key->type); |
|
|
ip_file = user_hostfile; |
ip_file = user_hostfile; |
ip_status = check_host_in_hostfile(ip_file, ip, host_key, ip_key, &ip_line); |
ip_status = check_host_in_hostfile(ip_file, ip, host_key, |
|
ip_key, &ip_line); |
if (ip_status == HOST_NEW) { |
if (ip_status == HOST_NEW) { |
ip_file = system_hostfile; |
ip_file = system_hostfile; |
ip_status = check_host_in_hostfile(ip_file, ip, host_key, ip_key, &ip_line); |
ip_status = check_host_in_hostfile(ip_file, ip, |
|
host_key, ip_key, &ip_line); |
} |
} |
if (host_status == HOST_CHANGED && |
if (host_status == HOST_CHANGED && |
(ip_status != HOST_CHANGED || !key_equal(ip_key, file_key))) |
(ip_status != HOST_CHANGED || !key_equal(ip_key, file_key))) |
|
|
host, type); |
host, type); |
debug("Found key in %s:%d", host_file, host_line); |
debug("Found key in %s:%d", host_file, host_line); |
if (options.check_host_ip && ip_status == HOST_NEW) { |
if (options.check_host_ip && ip_status == HOST_NEW) { |
if (!add_host_to_hostfile(user_hostfile, ip, host_key)) |
if (readonly) |
log("Failed to add the %s host key for IP address '%.128s' to the list of known hosts (%.30s).", |
log("%s host key for IP address " |
type, ip, user_hostfile); |
"'%.128s' not in list of known hosts.", |
else |
|
log("Warning: Permanently added the %s host key for IP address '%.128s' to the list of known hosts.", |
|
type, ip); |
type, ip); |
|
else if (!add_host_to_hostfile(user_hostfile, ip, |
|
host_key)) |
|
log("Failed to add the %s host key for IP " |
|
"address '%.128s' to the list of known " |
|
"hosts (%.30s).", type, ip, user_hostfile); |
|
else |
|
log("Warning: Permanently added the %s host " |
|
"key for IP address '%.128s' to the list " |
|
"of known hosts.", type, ip); |
} |
} |
break; |
break; |
case HOST_NEW: |
case HOST_NEW: |
|
if (readonly) |
|
goto fail; |
/* The host is new. */ |
/* The host is new. */ |
if (options.strict_host_key_checking == 1) { |
if (options.strict_host_key_checking == 1) { |
/* User has requested strict host key checking. We will not add the host key |
/* |
automatically. The only alternative left is to abort. */ |
* User has requested strict host key checking. We |
fatal("No %s host key is known for %.200s and you have requested strict checking.", type, host); |
* will not add the host key automatically. The only |
|
* alternative left is to abort. |
|
*/ |
|
error("No %s host key is known for %.200s and you " |
|
"have requested strict checking.", type, host); |
|
goto fail; |
} else if (options.strict_host_key_checking == 2) { |
} else if (options.strict_host_key_checking == 2) { |
/* The default */ |
/* The default */ |
char prompt[1024]; |
char prompt[1024]; |
fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); |
fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); |
snprintf(prompt, sizeof(prompt), |
snprintf(prompt, sizeof(prompt), |
"The authenticity of host '%.200s (%s)' can't be established.\n" |
"The authenticity of host '%.200s (%s)' can't be " |
|
"established.\n" |
"%s key fingerprint is %s.\n" |
"%s key fingerprint is %s.\n" |
"Are you sure you want to continue connecting (yes/no)? ", |
"Are you sure you want to continue connecting " |
host, ip, type, fp); |
"(yes/no)? ", host, ip, type, fp); |
xfree(fp); |
xfree(fp); |
if (!read_yes_or_no(prompt, -1)) |
if (!read_yes_or_no(prompt, -1)) { |
fatal("Aborted by user!"); |
log("Aborted by user!"); |
|
goto fail; |
|
} |
} |
} |
if (options.check_host_ip && ip_status == HOST_NEW) { |
if (options.check_host_ip && ip_status == HOST_NEW) { |
snprintf(hostline, sizeof(hostline), "%s,%s", host, ip); |
snprintf(hostline, sizeof(hostline), "%s,%s", host, ip); |
|
|
} else |
} else |
hostp = host; |
hostp = host; |
|
|
/* If not in strict mode, add the key automatically to the local known_hosts file. */ |
/* |
|
* If not in strict mode, add the key automatically to the |
|
* local known_hosts file. |
|
*/ |
if (!add_host_to_hostfile(user_hostfile, hostp, host_key)) |
if (!add_host_to_hostfile(user_hostfile, hostp, host_key)) |
log("Failed to add the host to the list of known hosts (%.500s).", |
log("Failed to add the host to the list of known " |
user_hostfile); |
"hosts (%.500s).", user_hostfile); |
else |
else |
log("Warning: Permanently added '%.200s' (%s) to the list of known hosts.", |
log("Warning: Permanently added '%.200s' (%s) to the " |
hostp, type); |
"list of known hosts.", hostp, type); |
break; |
break; |
case HOST_CHANGED: |
case HOST_CHANGED: |
if (options.check_host_ip && host_ip_differ) { |
if (options.check_host_ip && host_ip_differ) { |
|
|
* If strict host key checking is in use, the user will have |
* If strict host key checking is in use, the user will have |
* to edit the key manually and we can only abort. |
* to edit the key manually and we can only abort. |
*/ |
*/ |
if (options.strict_host_key_checking) |
if (options.strict_host_key_checking) { |
fatal("%s host key for %.200s has changed and you have requested strict checking.", type, host); |
error("%s host key for %.200s has changed and you have " |
|
"requested strict checking.", type, host); |
|
goto fail; |
|
} |
|
|
/* |
/* |
* If strict host key checking has not been requested, allow |
* If strict host key checking has not been requested, allow |
|
|
* agent forwarding. |
* agent forwarding. |
*/ |
*/ |
if (options.password_authentication) { |
if (options.password_authentication) { |
error("Password authentication is disabled to avoid trojan horses."); |
error("Password authentication is disabled to avoid " |
|
"man-in-the-middle attacks."); |
options.password_authentication = 0; |
options.password_authentication = 0; |
} |
} |
if (options.forward_agent) { |
if (options.forward_agent) { |
error("Agent forwarding is disabled to avoid trojan horses."); |
error("Agent forwarding is disabled to avoid " |
|
"man-in-the-middle attacks."); |
options.forward_agent = 0; |
options.forward_agent = 0; |
} |
} |
if (options.forward_x11) { |
if (options.forward_x11) { |
error("X11 forwarding is disabled to avoid trojan horses."); |
error("X11 forwarding is disabled to avoid " |
|
"man-in-the-middle attacks."); |
options.forward_x11 = 0; |
options.forward_x11 = 0; |
} |
} |
if (options.num_local_forwards > 0 || options.num_remote_forwards > 0) { |
if (options.num_local_forwards > 0 || |
error("Port forwarding is disabled to avoid trojan horses."); |
options.num_remote_forwards > 0) { |
options.num_local_forwards = options.num_remote_forwards = 0; |
error("Port forwarding is disabled to avoid " |
|
"man-in-the-middle attacks."); |
|
options.num_local_forwards = |
|
options.num_remote_forwards = 0; |
} |
} |
/* |
/* |
* XXX Should permit the user to change to use the new id. |
* XXX Should permit the user to change to use the new id. |
|
|
log("Matching host key in %s:%d", host_file, host_line); |
log("Matching host key in %s:%d", host_file, host_line); |
log("Offending key for IP in %s:%d", ip_file, ip_line); |
log("Offending key for IP in %s:%d", ip_file, ip_line); |
if (options.strict_host_key_checking == 1) { |
if (options.strict_host_key_checking == 1) { |
fatal("Exiting, you have requested strict checking."); |
error("Exiting, you have requested strict checking."); |
|
goto fail; |
} else if (options.strict_host_key_checking == 2) { |
} else if (options.strict_host_key_checking == 2) { |
if (!read_yes_or_no("Are you sure you want " \ |
if (!read_yes_or_no("Are you sure you want " |
"to continue connecting (yes/no)? ", -1)) |
"to continue connecting (yes/no)? ", -1)) { |
fatal("Aborted by user!"); |
log("Aborted by user!"); |
|
goto fail; |
|
} |
} |
} |
} |
} |
|
|
xfree(ip); |
xfree(ip); |
|
return 0; |
|
|
|
fail: |
|
xfree(ip); |
|
return -1; |
|
} |
|
|
|
int |
|
verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) |
|
{ |
|
struct stat st; |
|
|
|
/* return ok if the key can be found in an old keyfile */ |
|
if (stat(options.system_hostfile2, &st) == 0 || |
|
stat(options.user_hostfile2, &st) == 0) { |
|
if (check_host_key(host, hostaddr, host_key, /*readonly*/ 1, |
|
options.user_hostfile2, options.system_hostfile2) == 0) |
|
return 0; |
|
} |
|
return check_host_key(host, hostaddr, host_key, /*readonly*/ 0, |
|
options.user_hostfile, options.system_hostfile); |
} |
} |
|
|
/* |
/* |