version 1.158, 2004/06/21 17:36:31 |
version 1.158.2.3, 2005/09/02 03:45:01 |
|
|
static int |
static int |
ssh_proxy_connect(const char *host, u_short port, const char *proxy_command) |
ssh_proxy_connect(const char *host, u_short port, const char *proxy_command) |
{ |
{ |
Buffer command; |
char *command_string, *tmp; |
const char *cp; |
|
char *command_string; |
|
int pin[2], pout[2]; |
int pin[2], pout[2]; |
pid_t pid; |
pid_t pid; |
char strport[NI_MAXSERV]; |
char strport[NI_MAXSERV]; |
|
size_t len; |
|
|
/* Convert the port number into a string. */ |
/* Convert the port number into a string. */ |
snprintf(strport, sizeof strport, "%hu", port); |
snprintf(strport, sizeof strport, "%hu", port); |
|
|
* Use "exec" to avoid "sh -c" processes on some platforms |
* Use "exec" to avoid "sh -c" processes on some platforms |
* (e.g. Solaris) |
* (e.g. Solaris) |
*/ |
*/ |
buffer_init(&command); |
len = strlen(proxy_command) + 6; |
buffer_append(&command, "exec ", 5); |
tmp = xmalloc(len); |
|
strlcpy(tmp, "exec ", len); |
|
strlcat(tmp, proxy_command, len); |
|
command_string = percent_expand(tmp, "h", host, |
|
"p", strport, (char *)NULL); |
|
xfree(tmp); |
|
|
for (cp = proxy_command; *cp; cp++) { |
|
if (cp[0] == '%' && cp[1] == '%') { |
|
buffer_append(&command, "%", 1); |
|
cp++; |
|
continue; |
|
} |
|
if (cp[0] == '%' && cp[1] == 'h') { |
|
buffer_append(&command, host, strlen(host)); |
|
cp++; |
|
continue; |
|
} |
|
if (cp[0] == '%' && cp[1] == 'p') { |
|
buffer_append(&command, strport, strlen(strport)); |
|
cp++; |
|
continue; |
|
} |
|
buffer_append(&command, cp, 1); |
|
} |
|
buffer_append(&command, "\0", 1); |
|
|
|
/* Get the final command string. */ |
|
command_string = buffer_ptr(&command); |
|
|
|
/* Create pipes for communicating with the proxy. */ |
/* Create pipes for communicating with the proxy. */ |
if (pipe(pin) < 0 || pipe(pout) < 0) |
if (pipe(pin) < 0 || pipe(pout) < 0) |
fatal("Could not create pipes to communicate with the proxy: %.100s", |
fatal("Could not create pipes to communicate with the proxy: %.100s", |
|
|
close(pout[1]); |
close(pout[1]); |
|
|
/* Free the command name. */ |
/* Free the command name. */ |
buffer_free(&command); |
xfree(command_string); |
|
|
/* Set the connection file descriptors. */ |
/* Set the connection file descriptors. */ |
packet_set_connection(pout[0], pin[1]); |
packet_set_connection(pout[0], pin[1]); |
|
|
tv.tv_sec = timeout; |
tv.tv_sec = timeout; |
tv.tv_usec = 0; |
tv.tv_usec = 0; |
|
|
for(;;) { |
for (;;) { |
rc = select(sockfd + 1, NULL, fdset, NULL, &tv); |
rc = select(sockfd + 1, NULL, fdset, NULL, &tv); |
if (rc != -1 || errno != EINTR) |
if (rc != -1 || errno != EINTR) |
break; |
break; |
} |
} |
|
|
switch(rc) { |
switch (rc) { |
case 0: |
case 0: |
/* Timed out */ |
/* Timed out */ |
errno = ETIMEDOUT; |
errno = ETIMEDOUT; |
|
|
* second). If proxy_command is non-NULL, it specifies the command (with %h |
* second). If proxy_command is non-NULL, it specifies the command (with %h |
* and %p substituted for host and port, respectively) to use to contact |
* and %p substituted for host and port, respectively) to use to contact |
* the daemon. |
* the daemon. |
* Return values: |
|
* 0 for OK |
|
* ECONNREFUSED if we got a "Connection Refused" by the peer on any address |
|
* ECONNABORTED if we failed without a "Connection refused" |
|
* Suitable error messages for the connection failure will already have been |
|
* printed. |
|
*/ |
*/ |
int |
int |
ssh_connect(const char *host, struct sockaddr_storage * hostaddr, |
ssh_connect(const char *host, struct sockaddr_storage * hostaddr, |
|
|
int sock = -1, attempt; |
int sock = -1, attempt; |
char ntop[NI_MAXHOST], strport[NI_MAXSERV]; |
char ntop[NI_MAXHOST], strport[NI_MAXSERV]; |
struct addrinfo hints, *ai, *aitop; |
struct addrinfo hints, *ai, *aitop; |
struct servent *sp; |
|
/* |
|
* Did we get only other errors than "Connection refused" (which |
|
* should block fallback to rsh and similar), or did we get at least |
|
* one "Connection refused"? |
|
*/ |
|
int full_failure = 1; |
|
|
|
debug2("ssh_connect: needpriv %d", needpriv); |
debug2("ssh_connect: needpriv %d", needpriv); |
|
|
/* Get default port if port has not been set. */ |
|
if (port == 0) { |
|
sp = getservbyname(SSH_SERVICE_NAME, "tcp"); |
|
if (sp) |
|
port = ntohs(sp->s_port); |
|
else |
|
port = SSH_DEFAULT_PORT; |
|
} |
|
/* If a proxy command is given, connect using it. */ |
/* If a proxy command is given, connect using it. */ |
if (proxy_command != NULL) |
if (proxy_command != NULL) |
return ssh_proxy_connect(host, port, proxy_command); |
return ssh_proxy_connect(host, port, proxy_command); |
|
|
memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen); |
memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen); |
break; |
break; |
} else { |
} else { |
if (errno == ECONNREFUSED) |
|
full_failure = 0; |
|
debug("connect to address %s port %s: %s", |
debug("connect to address %s port %s: %s", |
ntop, strport, strerror(errno)); |
ntop, strport, strerror(errno)); |
/* |
/* |
|
|
|
|
/* Return failure if we didn't get a successful connection. */ |
/* Return failure if we didn't get a successful connection. */ |
if (attempt >= connection_attempts) { |
if (attempt >= connection_attempts) { |
logit("ssh: connect to host %s port %s: %s", |
error("ssh: connect to host %s port %s: %s", |
host, strport, strerror(errno)); |
host, strport, strerror(errno)); |
return full_failure ? ECONNABORTED : ECONNREFUSED; |
return (-1); |
} |
} |
|
|
debug("Connection established."); |
debug("Connection established."); |
|
|
ssh_exchange_identification(void) |
ssh_exchange_identification(void) |
{ |
{ |
char buf[256], remote_version[256]; /* must be same size! */ |
char buf[256], remote_version[256]; /* must be same size! */ |
int remote_major, remote_minor, i, mismatch; |
int remote_major, remote_minor, mismatch; |
int connection_in = packet_get_connection_in(); |
int connection_in = packet_get_connection_in(); |
int connection_out = packet_get_connection_out(); |
int connection_out = packet_get_connection_out(); |
int minor1 = PROTOCOL_MINOR_1; |
int minor1 = PROTOCOL_MINOR_1; |
|
u_int i; |
|
|
/* Read other side\'s version identification. */ |
/* Read other side's version identification. */ |
for (;;) { |
for (;;) { |
for (i = 0; i < sizeof(buf) - 1; i++) { |
for (i = 0; i < sizeof(buf) - 1; i++) { |
int len = atomicio(read, connection_in, &buf[i], 1); |
size_t len = atomicio(read, connection_in, &buf[i], 1); |
if (len < 0) |
|
fatal("ssh_exchange_identification: read: %.100s", strerror(errno)); |
if (len != 1 && errno == EPIPE) |
if (len != 1) |
|
fatal("ssh_exchange_identification: Connection closed by remote host"); |
fatal("ssh_exchange_identification: Connection closed by remote host"); |
|
else if (len != 1) |
|
fatal("ssh_exchange_identification: read: %.100s", strerror(errno)); |
if (buf[i] == '\r') { |
if (buf[i] == '\r') { |
buf[i] = '\n'; |
buf[i] = '\n'; |
buf[i + 1] = 0; |
buf[i + 1] = 0; |
|
|
char hostline[1000], *hostp, *fp; |
char hostline[1000], *hostp, *fp; |
HostStatus host_status; |
HostStatus host_status; |
HostStatus ip_status; |
HostStatus ip_status; |
int local = 0, host_ip_differ = 0; |
int r, 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; |
int len, host_line, ip_line; |
|
|
switch (hostaddr->sa_family) { |
switch (hostaddr->sa_family) { |
case AF_INET: |
case AF_INET: |
local = (ntohl(((struct sockaddr_in *)hostaddr)-> |
local = (ntohl(((struct sockaddr_in *)hostaddr)-> |
sin_addr.s_addr) >> 24) == IN_LOOPBACKNET; |
sin_addr.s_addr) >> 24) == IN_LOOPBACKNET; |
break; |
break; |
case AF_INET6: |
case AF_INET6: |
local = IN6_IS_ADDR_LOOPBACK( |
local = IN6_IS_ADDR_LOOPBACK( |
|
|
"'%.128s' not in list of known hosts.", |
"'%.128s' not in list of known hosts.", |
type, ip); |
type, ip); |
else if (!add_host_to_hostfile(user_hostfile, ip, |
else if (!add_host_to_hostfile(user_hostfile, ip, |
host_key)) |
host_key, options.hash_known_hosts)) |
logit("Failed to add the %s host key for IP " |
logit("Failed to add the %s host key for IP " |
"address '%.128s' to the list of known " |
"address '%.128s' to the list of known " |
"hosts (%.30s).", type, ip, user_hostfile); |
"hosts (%.30s).", type, ip, user_hostfile); |
|
|
|
|
if (show_other_keys(host, host_key)) |
if (show_other_keys(host, host_key)) |
snprintf(msg1, sizeof(msg1), |
snprintf(msg1, sizeof(msg1), |
"\nbut keys of different type are already" |
"\nbut keys of different type are already" |
" known for this host."); |
" known for this host."); |
else |
else |
snprintf(msg1, sizeof(msg1), "."); |
snprintf(msg1, sizeof(msg1), "."); |
/* The default */ |
/* The default */ |
|
|
if (!confirm(msg)) |
if (!confirm(msg)) |
goto fail; |
goto fail; |
} |
} |
if (options.check_host_ip && ip_status == HOST_NEW) { |
|
snprintf(hostline, sizeof(hostline), "%s,%s", host, ip); |
|
hostp = hostline; |
|
} else |
|
hostp = host; |
|
|
|
/* |
/* |
* If not in strict mode, add the key automatically to the |
* If not in strict mode, add the key automatically to the |
* local known_hosts file. |
* local known_hosts file. |
*/ |
*/ |
if (!add_host_to_hostfile(user_hostfile, hostp, host_key)) |
if (options.check_host_ip && ip_status == HOST_NEW) { |
|
snprintf(hostline, sizeof(hostline), "%s,%s", |
|
host, ip); |
|
hostp = hostline; |
|
if (options.hash_known_hosts) { |
|
/* Add hash of host and IP separately */ |
|
r = add_host_to_hostfile(user_hostfile, host, |
|
host_key, options.hash_known_hosts) && |
|
add_host_to_hostfile(user_hostfile, ip, |
|
host_key, options.hash_known_hosts); |
|
} else { |
|
/* Add unhashed "host,ip" */ |
|
r = add_host_to_hostfile(user_hostfile, |
|
hostline, host_key, |
|
options.hash_known_hosts); |
|
} |
|
} else { |
|
r = add_host_to_hostfile(user_hostfile, host, host_key, |
|
options.hash_known_hosts); |
|
hostp = host; |
|
} |
|
|
|
if (!r) |
logit("Failed to add the host to the list of known " |
logit("Failed to add the host to the list of known " |
"hosts (%.500s).", user_hostfile); |
"hosts (%.500s).", user_hostfile); |
else |
else |