version 1.196, 2008/06/12 04:06:00 |
version 1.197, 2008/06/12 04:17:47 |
|
|
static int escape_char1; /* Escape character. (proto1 only) */ |
static int escape_char1; /* Escape character. (proto1 only) */ |
static int escape_pending1; /* Last character was an escape (proto1 only) */ |
static int escape_pending1; /* Last character was an escape (proto1 only) */ |
static int last_was_cr; /* Last character was a newline. */ |
static int last_was_cr; /* Last character was a newline. */ |
static int exit_status; /* Used to store the exit status of the command. */ |
static int exit_status; /* Used to store the command exit status. */ |
static int stdin_eof; /* EOF has been encountered on standard error. */ |
static int stdin_eof; /* EOF has been encountered on stderr. */ |
static Buffer stdin_buffer; /* Buffer for stdin data. */ |
static Buffer stdin_buffer; /* Buffer for stdin data. */ |
static Buffer stdout_buffer; /* Buffer for stdout data. */ |
static Buffer stdout_buffer; /* Buffer for stdout data. */ |
static Buffer stderr_buffer; /* Buffer for stderr data. */ |
static Buffer stderr_buffer; /* Buffer for stderr data. */ |
|
|
/* Check for immediate EOF on stdin. */ |
/* Check for immediate EOF on stdin. */ |
len = read(fileno(stdin), buf, 1); |
len = read(fileno(stdin), buf, 1); |
if (len == 0) { |
if (len == 0) { |
/* EOF. Record that we have seen it and send EOF to server. */ |
/* |
|
* EOF. Record that we have seen it and send |
|
* EOF to server. |
|
*/ |
debug("Sending eof."); |
debug("Sending eof."); |
stdin_eof = 1; |
stdin_eof = 1; |
packet_start(SSH_CMSG_EOF); |
packet_start(SSH_CMSG_EOF); |
|
|
{ |
{ |
/* Flush stdout and stderr buffers. */ |
/* Flush stdout and stderr buffers. */ |
if (buffer_len(bout) > 0) |
if (buffer_len(bout) > 0) |
atomicio(vwrite, fileno(stdout), buffer_ptr(bout), buffer_len(bout)); |
atomicio(vwrite, fileno(stdout), buffer_ptr(bout), |
|
buffer_len(bout)); |
if (buffer_len(berr) > 0) |
if (buffer_len(berr) > 0) |
atomicio(vwrite, fileno(stderr), buffer_ptr(berr), buffer_len(berr)); |
atomicio(vwrite, fileno(stderr), buffer_ptr(berr), |
|
buffer_len(berr)); |
|
|
leave_raw_mode(); |
leave_raw_mode(); |
|
|
|
|
/* Read as much as possible. */ |
/* Read as much as possible. */ |
len = read(connection_in, buf, sizeof(buf)); |
len = read(connection_in, buf, sizeof(buf)); |
if (len == 0) { |
if (len == 0) { |
/* Received EOF. The remote host has closed the connection. */ |
/* |
snprintf(buf, sizeof buf, "Connection to %.300s closed by remote host.\r\n", |
* Received EOF. The remote host has closed the |
host); |
* connection. |
|
*/ |
|
snprintf(buf, sizeof buf, |
|
"Connection to %.300s closed by remote host.\r\n", |
|
host); |
buffer_append(&stderr_buffer, buf, strlen(buf)); |
buffer_append(&stderr_buffer, buf, strlen(buf)); |
quit_pending = 1; |
quit_pending = 1; |
return; |
return; |
|
|
len = 0; |
len = 0; |
|
|
if (len < 0) { |
if (len < 0) { |
/* An error has encountered. Perhaps there is a network problem. */ |
/* |
snprintf(buf, sizeof buf, "Read from remote host %.300s: %.100s\r\n", |
* An error has encountered. Perhaps there is a |
host, strerror(errno)); |
* network problem. |
|
*/ |
|
snprintf(buf, sizeof buf, |
|
"Read from remote host %.300s: %.100s\r\n", |
|
host, strerror(errno)); |
buffer_append(&stderr_buffer, buf, strlen(buf)); |
buffer_append(&stderr_buffer, buf, strlen(buf)); |
quit_pending = 1; |
quit_pending = 1; |
return; |
return; |
|
|
strlen(string)); |
strlen(string)); |
continue; |
continue; |
} |
} |
/* Suspend the program. */ |
/* Suspend the program. Inform the user */ |
/* Print a message to that effect to the user. */ |
|
snprintf(string, sizeof string, |
snprintf(string, sizeof string, |
"%c^Z [suspend ssh]\r\n", escape_char); |
"%c^Z [suspend ssh]\r\n", escape_char); |
buffer_append(berr, string, strlen(string)); |
buffer_append(berr, string, strlen(string)); |
|
|
case 'R': |
case 'R': |
if (compat20) { |
if (compat20) { |
if (datafellows & SSH_BUG_NOREKEY) |
if (datafellows & SSH_BUG_NOREKEY) |
logit("Server does not support re-keying"); |
logit("Server does not " |
|
"support re-keying"); |
else |
else |
need_rekeying = 1; |
need_rekeying = 1; |
} |
} |
|
|
if (c && c->ctl_fd != -1) |
if (c && c->ctl_fd != -1) |
goto noescape; |
goto noescape; |
/* |
/* |
* Detach the program (continue to serve connections, |
* Detach the program (continue to serve |
* but put in background and no more new connections). |
* connections, but put in background and no |
|
* more new connections). |
*/ |
*/ |
/* Restore tty modes. */ |
/* Restore tty modes. */ |
leave_raw_mode(); |
leave_raw_mode(); |
|
|
return -1; |
return -1; |
} else if (!stdin_eof) { |
} else if (!stdin_eof) { |
/* |
/* |
* Sending SSH_CMSG_EOF alone does not always appear |
* Sending SSH_CMSG_EOF alone does not |
* to be enough. So we try to send an EOF character |
* always appear to be enough. So we |
* first. |
* try to send an EOF character first. |
*/ |
*/ |
packet_start(SSH_CMSG_STDIN_DATA); |
packet_start(SSH_CMSG_STDIN_DATA); |
packet_put_string("\004", 1); |
packet_put_string("\004", 1); |
|
|
} |
} |
} else { |
} else { |
/* |
/* |
* The previous character was not an escape char. Check if this |
* The previous character was not an escape char. |
* is an escape. |
* Check if this is an escape. |
*/ |
*/ |
if (last_was_cr && ch == escape_char) { |
if (last_was_cr && ch == escape_char) { |
/* It is. Set the flag and continue to next character. */ |
/* |
|
* It is. Set the flag and continue to |
|
* next character. |
|
*/ |
*escape_pendingp = 1; |
*escape_pendingp = 1; |
continue; |
continue; |
} |
} |
|
|
* if it was an error condition. |
* if it was an error condition. |
*/ |
*/ |
if (len < 0) { |
if (len < 0) { |
snprintf(buf, sizeof buf, "read: %.100s\r\n", strerror(errno)); |
snprintf(buf, sizeof buf, "read: %.100s\r\n", |
|
strerror(errno)); |
buffer_append(&stderr_buffer, buf, strlen(buf)); |
buffer_append(&stderr_buffer, buf, strlen(buf)); |
} |
} |
/* Mark that we have seen EOF. */ |
/* Mark that we have seen EOF. */ |
|
|
buffer_append(&stdin_buffer, buf, len); |
buffer_append(&stdin_buffer, buf, len); |
} else { |
} else { |
/* |
/* |
* Normal, successful read. But we have an escape character |
* Normal, successful read. But we have an escape |
* and have to process the characters one by one. |
* character and have to process the characters one |
|
* by one. |
*/ |
*/ |
if (process_escapes(NULL, &stdin_buffer, |
if (process_escapes(NULL, &stdin_buffer, |
&stdout_buffer, &stderr_buffer, buf, len) == -1) |
&stdout_buffer, &stderr_buffer, buf, len) == -1) |
|
|
* An error or EOF was encountered. Put an |
* An error or EOF was encountered. Put an |
* error message to stderr buffer. |
* error message to stderr buffer. |
*/ |
*/ |
snprintf(buf, sizeof buf, "write stdout: %.50s\r\n", strerror(errno)); |
snprintf(buf, sizeof buf, |
|
"write stdout: %.50s\r\n", strerror(errno)); |
buffer_append(&stderr_buffer, buf, strlen(buf)); |
buffer_append(&stderr_buffer, buf, strlen(buf)); |
quit_pending = 1; |
quit_pending = 1; |
return; |
return; |
|
|
if (errno == EINTR || errno == EAGAIN) |
if (errno == EINTR || errno == EAGAIN) |
len = 0; |
len = 0; |
else { |
else { |
/* EOF or error, but can't even print error message. */ |
/* |
|
* EOF or error, but can't even print |
|
* error message. |
|
*/ |
quit_pending = 1; |
quit_pending = 1; |
return; |
return; |
} |
} |
|
|
static void |
static void |
client_process_buffered_input_packets(void) |
client_process_buffered_input_packets(void) |
{ |
{ |
dispatch_run(DISPATCH_NONBLOCK, &quit_pending, compat20 ? xxx_kex : NULL); |
dispatch_run(DISPATCH_NONBLOCK, &quit_pending, |
|
compat20 ? xxx_kex : NULL); |
} |
} |
|
|
/* scan buf[] for '~' before sending data to the peer */ |
/* scan buf[] for '~' before sending data to the peer */ |
|
|
client_process_output(writeset); |
client_process_output(writeset); |
} |
} |
|
|
/* Send as much buffered packet data as possible to the sender. */ |
/* |
|
* Send as much buffered packet data as possible to the |
|
* sender. |
|
*/ |
if (FD_ISSET(connection_out, writeset)) |
if (FD_ISSET(connection_out, writeset)) |
packet_write_poll(); |
packet_write_poll(); |
} |
} |
|
|
* that the connection has been closed. |
* that the connection has been closed. |
*/ |
*/ |
if (have_pty && options.log_level != SYSLOG_LEVEL_QUIET) { |
if (have_pty && options.log_level != SYSLOG_LEVEL_QUIET) { |
snprintf(buf, sizeof buf, "Connection to %.64s closed.\r\n", host); |
snprintf(buf, sizeof buf, |
|
"Connection to %.64s closed.\r\n", host); |
buffer_append(&stderr_buffer, buf, strlen(buf)); |
buffer_append(&stderr_buffer, buf, strlen(buf)); |
} |
} |
|
|
|
|
|
|
/* Report bytes transferred, and transfer rates. */ |
/* Report bytes transferred, and transfer rates. */ |
total_time = get_current_time() - start_time; |
total_time = get_current_time() - start_time; |
debug("Transferred: stdin %lu, stdout %lu, stderr %lu bytes in %.1f seconds", |
debug("Transferred: stdin %lu, stdout %lu, stderr %lu bytes in %.1f " |
stdin_bytes, stdout_bytes, stderr_bytes, total_time); |
"seconds", stdin_bytes, stdout_bytes, stderr_bytes, total_time); |
if (total_time > 0) |
if (total_time > 0) |
debug("Bytes per second: stdin %.1f, stdout %.1f, stderr %.1f", |
debug("Bytes per second: stdin %.1f, stdout %.1f, stderr %.1f", |
stdin_bytes / total_time, stdout_bytes / total_time, |
stdin_bytes / total_time, stdout_bytes / total_time, |
|
|
|
|
if (!options.forward_x11) { |
if (!options.forward_x11) { |
error("Warning: ssh server tried X11 forwarding."); |
error("Warning: ssh server tried X11 forwarding."); |
error("Warning: this is probably a break-in attempt by a malicious server."); |
error("Warning: this is probably a break-in attempt by a " |
|
"malicious server."); |
return NULL; |
return NULL; |
} |
} |
originator = packet_get_string(NULL); |
originator = packet_get_string(NULL); |
|
|
|
|
if (!options.forward_agent) { |
if (!options.forward_agent) { |
error("Warning: ssh server tried agent forwarding."); |
error("Warning: ssh server tried agent forwarding."); |
error("Warning: this is probably a break-in attempt by a malicious server."); |
error("Warning: this is probably a break-in attempt by a " |
|
"malicious server."); |
return NULL; |
return NULL; |
} |
} |
sock = ssh_get_authentication_socket(); |
sock = ssh_get_authentication_socket(); |
|
|
if (id == -1) { |
if (id == -1) { |
error("client_input_channel_req: request for channel -1"); |
error("client_input_channel_req: request for channel -1"); |
} else if ((c = channel_lookup(id)) == NULL) { |
} else if ((c = channel_lookup(id)) == NULL) { |
error("client_input_channel_req: channel %d: unknown channel", id); |
error("client_input_channel_req: channel %d: " |
|
"unknown channel", id); |
} else if (strcmp(rtype, "eow@openssh.com") == 0) { |
} else if (strcmp(rtype, "eow@openssh.com") == 0) { |
packet_check_eom(); |
packet_check_eom(); |
chan_rcvd_eow(c); |
chan_rcvd_eow(c); |
|
|
dispatch_set(SSH2_MSG_REQUEST_FAILURE, &client_global_request_reply); |
dispatch_set(SSH2_MSG_REQUEST_FAILURE, &client_global_request_reply); |
dispatch_set(SSH2_MSG_REQUEST_SUCCESS, &client_global_request_reply); |
dispatch_set(SSH2_MSG_REQUEST_SUCCESS, &client_global_request_reply); |
} |
} |
|
|
static void |
static void |
client_init_dispatch_13(void) |
client_init_dispatch_13(void) |
{ |
{ |
|
|
dispatch_set(SSH_SMSG_X11_OPEN, options.forward_x11 ? |
dispatch_set(SSH_SMSG_X11_OPEN, options.forward_x11 ? |
&x11_input_open : &deny_input_open); |
&x11_input_open : &deny_input_open); |
} |
} |
|
|
static void |
static void |
client_init_dispatch_15(void) |
client_init_dispatch_15(void) |
{ |
{ |
|
|
dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_ieof); |
dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_ieof); |
dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, & channel_input_oclose); |
dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, & channel_input_oclose); |
} |
} |
|
|
static void |
static void |
client_init_dispatch(void) |
client_init_dispatch(void) |
{ |
{ |