version 1.291, 2017/03/10 05:01:13 |
version 1.292, 2017/04/30 23:13:25 |
|
|
} |
} |
} |
} |
|
|
/* Puts stdin terminal in non-blocking mode. */ |
|
|
|
static void |
|
enter_non_blocking(void) |
|
{ |
|
in_non_blocking_mode = 1; |
|
set_nonblock(fileno(stdin)); |
|
} |
|
|
|
/* |
/* |
* Signal handler for the window change signal (SIGWINCH). This just sets a |
* Signal handler for the window change signal (SIGWINCH). This just sets a |
* flag indicating that the window has changed. |
* flag indicating that the window has changed. |
|
|
} |
} |
|
|
/* |
/* |
* This is called when the interactive is entered. This checks if there is |
|
* an EOF coming on stdin. We must check this explicitly, as select() does |
|
* not appear to wake up when redirecting from /dev/null. |
|
*/ |
|
|
|
static void |
|
client_check_initial_eof_on_stdin(void) |
|
{ |
|
int len; |
|
char buf[1]; |
|
|
|
/* |
|
* If standard input is to be "redirected from /dev/null", we simply |
|
* mark that we have seen an EOF and send an EOF message to the |
|
* server. Otherwise, we try to read a single character; it appears |
|
* that for some files, such /dev/null, select() never wakes up for |
|
* read for this descriptor, which means that we never get EOF. This |
|
* way we will get the EOF if stdin comes from /dev/null or similar. |
|
*/ |
|
if (stdin_null_flag) { |
|
/* Fake EOF on stdin. */ |
|
debug("Sending eof."); |
|
stdin_eof = 1; |
|
packet_start(SSH_CMSG_EOF); |
|
packet_send(); |
|
} else { |
|
enter_non_blocking(); |
|
|
|
/* Check for immediate EOF on stdin. */ |
|
len = read(fileno(stdin), buf, 1); |
|
if (len == 0) { |
|
/* |
|
* EOF. Record that we have seen it and send |
|
* EOF to server. |
|
*/ |
|
debug("Sending eof."); |
|
stdin_eof = 1; |
|
packet_start(SSH_CMSG_EOF); |
|
packet_send(); |
|
} else if (len > 0) { |
|
/* |
|
* Got data. We must store the data in the buffer, |
|
* and also process it as an escape character if |
|
* appropriate. |
|
*/ |
|
if ((u_char) buf[0] == escape_char1) |
|
escape_pending1 = 1; |
|
else |
|
buffer_append(&stdin_buffer, buf, 1); |
|
} |
|
leave_non_blocking(); |
|
} |
|
} |
|
|
|
|
|
/* |
|
* Make packets from buffered stdin data, and buffer them for sending to the |
|
* connection. |
|
*/ |
|
|
|
static void |
|
client_make_packets_from_stdin_data(void) |
|
{ |
|
u_int len; |
|
|
|
/* Send buffered stdin data to the server. */ |
|
while (buffer_len(&stdin_buffer) > 0 && |
|
packet_not_very_much_data_to_write()) { |
|
len = buffer_len(&stdin_buffer); |
|
/* Keep the packets at reasonable size. */ |
|
if (len > packet_get_maxsize()) |
|
len = packet_get_maxsize(); |
|
packet_start(SSH_CMSG_STDIN_DATA); |
|
packet_put_string(buffer_ptr(&stdin_buffer), len); |
|
packet_send(); |
|
buffer_consume(&stdin_buffer, len); |
|
/* If we have a pending EOF, send it now. */ |
|
if (stdin_eof && buffer_len(&stdin_buffer) == 0) { |
|
packet_start(SSH_CMSG_EOF); |
|
packet_send(); |
|
} |
|
} |
|
} |
|
|
|
/* |
|
* Checks if the client window has changed, and sends a packet about it to |
* Checks if the client window has changed, and sends a packet about it to |
* the server if so. The actual change is detected elsewhere (by a software |
* the server if so. The actual change is detected elsewhere (by a software |
* interrupt on Unix); this just checks the flag and sends a message if |
* interrupt on Unix); this just checks the flag and sends a message if |
|
|
static void |
static void |
client_check_window_change(void) |
client_check_window_change(void) |
{ |
{ |
struct winsize ws; |
if (!received_window_change_signal) |
|
|
if (! received_window_change_signal) |
|
return; |
return; |
/** XXX race */ |
/** XXX race */ |
received_window_change_signal = 0; |
received_window_change_signal = 0; |
|
|
debug2("client_check_window_change: changed"); |
debug2("%s: changed", __func__); |
|
|
if (compat20) { |
channel_send_window_changes(); |
channel_send_window_changes(); |
|
} else { |
|
if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0) |
|
return; |
|
packet_start(SSH_CMSG_WINDOW_SIZE); |
|
packet_put_int((u_int)ws.ws_row); |
|
packet_put_int((u_int)ws.ws_col); |
|
packet_put_int((u_int)ws.ws_xpixel); |
|
packet_put_int((u_int)ws.ws_ypixel); |
|
packet_send(); |
|
} |
|
} |
} |
|
|
static int |
static int |
|
|
channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, |
channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, |
&minwait_secs, rekeying); |
&minwait_secs, rekeying); |
|
|
if (!compat20) { |
/* channel_prepare_select could have closed the last channel */ |
/* Read from the connection, unless our buffers are full. */ |
if (session_closed && !channel_still_open() && |
if (buffer_len(&stdout_buffer) < buffer_high && |
!packet_have_data_to_write()) { |
buffer_len(&stderr_buffer) < buffer_high && |
/* clear mask since we did not call select() */ |
channel_not_very_much_buffered_data()) |
memset(*readsetp, 0, *nallocp); |
FD_SET(connection_in, *readsetp); |
memset(*writesetp, 0, *nallocp); |
/* |
return; |
* Read from stdin, unless we have seen EOF or have very much |
|
* buffered data to send to the server. |
|
*/ |
|
if (!stdin_eof && packet_not_very_much_data_to_write()) |
|
FD_SET(fileno(stdin), *readsetp); |
|
|
|
/* Select stdout/stderr if have data in buffer. */ |
|
if (buffer_len(&stdout_buffer) > 0) |
|
FD_SET(fileno(stdout), *writesetp); |
|
if (buffer_len(&stderr_buffer) > 0) |
|
FD_SET(fileno(stderr), *writesetp); |
|
} else { |
} else { |
/* channel_prepare_select could have closed the last channel */ |
FD_SET(connection_in, *readsetp); |
if (session_closed && !channel_still_open() && |
|
!packet_have_data_to_write()) { |
|
/* clear mask since we did not call select() */ |
|
memset(*readsetp, 0, *nallocp); |
|
memset(*writesetp, 0, *nallocp); |
|
return; |
|
} else { |
|
FD_SET(connection_in, *readsetp); |
|
} |
|
} |
} |
|
|
/* Select server connection if have data to write to the server. */ |
/* Select server connection if have data to write to the server. */ |
|
|
*/ |
*/ |
|
|
timeout_secs = INT_MAX; /* we use INT_MAX to mean no timeout */ |
timeout_secs = INT_MAX; /* we use INT_MAX to mean no timeout */ |
if (options.server_alive_interval > 0 && compat20) { |
if (options.server_alive_interval > 0) { |
timeout_secs = options.server_alive_interval; |
timeout_secs = options.server_alive_interval; |
server_alive_time = now + options.server_alive_interval; |
server_alive_time = now + options.server_alive_interval; |
} |
} |
if (options.rekey_interval > 0 && compat20 && !rekeying) |
if (options.rekey_interval > 0 && !rekeying) |
timeout_secs = MINIMUM(timeout_secs, packet_get_rekey_timeout()); |
timeout_secs = MINIMUM(timeout_secs, packet_get_rekey_timeout()); |
set_control_persist_exit_time(); |
set_control_persist_exit_time(); |
if (control_persist_exit_time > 0) { |
if (control_persist_exit_time > 0) { |
|
|
goto out; |
goto out; |
} |
} |
|
|
if (delete && !compat20) { |
|
logit("Not supported for SSH protocol version 1."); |
|
goto out; |
|
} |
|
|
|
while (isspace((u_char)*++s)) |
while (isspace((u_char)*++s)) |
; |
; |
|
|
|
|
|
|
/* reasons to suppress output of an escape command in help output */ |
/* reasons to suppress output of an escape command in help output */ |
#define SUPPRESS_NEVER 0 /* never suppress, always show */ |
#define SUPPRESS_NEVER 0 /* never suppress, always show */ |
#define SUPPRESS_PROTO1 1 /* don't show in protocol 1 sessions */ |
#define SUPPRESS_MUXCLIENT 1 /* don't show in mux client sessions */ |
#define SUPPRESS_MUXCLIENT 2 /* don't show in mux client sessions */ |
#define SUPPRESS_MUXMASTER 2 /* don't show in mux master sessions */ |
#define SUPPRESS_MUXMASTER 4 /* don't show in mux master sessions */ |
#define SUPPRESS_SYSLOG 4 /* don't show when logging to syslog */ |
#define SUPPRESS_SYSLOG 8 /* don't show when logging to syslog */ |
|
struct escape_help_text { |
struct escape_help_text { |
const char *cmd; |
const char *cmd; |
const char *text; |
const char *text; |
|
|
{".", "terminate session", SUPPRESS_MUXMASTER}, |
{".", "terminate session", SUPPRESS_MUXMASTER}, |
{".", "terminate connection (and any multiplexed sessions)", |
{".", "terminate connection (and any multiplexed sessions)", |
SUPPRESS_MUXCLIENT}, |
SUPPRESS_MUXCLIENT}, |
{"B", "send a BREAK to the remote system", SUPPRESS_PROTO1}, |
{"B", "send a BREAK to the remote system", SUPPRESS_NEVER}, |
{"C", "open a command line", SUPPRESS_MUXCLIENT}, |
{"C", "open a command line", SUPPRESS_MUXCLIENT}, |
{"R", "request rekey", SUPPRESS_PROTO1}, |
{"R", "request rekey", SUPPRESS_NEVER}, |
{"V/v", "decrease/increase verbosity (LogLevel)", SUPPRESS_MUXCLIENT}, |
{"V/v", "decrease/increase verbosity (LogLevel)", SUPPRESS_MUXCLIENT}, |
{"^Z", "suspend ssh", SUPPRESS_MUXCLIENT}, |
{"^Z", "suspend ssh", SUPPRESS_MUXCLIENT}, |
{"#", "list forwarded connections", SUPPRESS_NEVER}, |
{"#", "list forwarded connections", SUPPRESS_NEVER}, |
|
|
}; |
}; |
|
|
static void |
static void |
print_escape_help(Buffer *b, int escape_char, int protocol2, int mux_client, |
print_escape_help(Buffer *b, int escape_char, int mux_client, int using_stderr) |
int using_stderr) |
|
{ |
{ |
unsigned int i, suppress_flags; |
unsigned int i, suppress_flags; |
char string[1024]; |
char string[1024]; |
|
|
"Supported escape sequences:\r\n", escape_char); |
"Supported escape sequences:\r\n", escape_char); |
buffer_append(b, string, strlen(string)); |
buffer_append(b, string, strlen(string)); |
|
|
suppress_flags = (protocol2 ? 0 : SUPPRESS_PROTO1) | |
suppress_flags = |
(mux_client ? SUPPRESS_MUXCLIENT : 0) | |
(mux_client ? SUPPRESS_MUXCLIENT : 0) | |
(mux_client ? 0 : SUPPRESS_MUXMASTER) | |
(mux_client ? 0 : SUPPRESS_MUXMASTER) | |
(using_stderr ? 0 : SUPPRESS_SYSLOG); |
(using_stderr ? 0 : SUPPRESS_SYSLOG); |
|
|
continue; |
continue; |
|
|
case 'B': |
case 'B': |
if (compat20) { |
snprintf(string, sizeof string, |
snprintf(string, sizeof string, |
"%cB\r\n", escape_char); |
"%cB\r\n", escape_char); |
buffer_append(berr, string, strlen(string)); |
buffer_append(berr, string, |
channel_request_start(c->self, "break", 0); |
strlen(string)); |
packet_put_int(1000); |
channel_request_start(c->self, |
packet_send(); |
"break", 0); |
|
packet_put_int(1000); |
|
packet_send(); |
|
} |
|
continue; |
continue; |
|
|
case 'R': |
case 'R': |
if (compat20) { |
if (datafellows & SSH_BUG_NOREKEY) |
if (datafellows & SSH_BUG_NOREKEY) |
logit("Server does not " |
logit("Server does not " |
"support re-keying"); |
"support re-keying"); |
else |
else |
need_rekeying = 1; |
need_rekeying = 1; |
|
} |
|
continue; |
continue; |
|
|
case 'V': |
case 'V': |
|
|
exit(0); |
exit(0); |
} |
} |
/* The child continues serving connections. */ |
/* The child continues serving connections. */ |
if (compat20) { |
buffer_append(bin, "\004", 1); |
buffer_append(bin, "\004", 1); |
/* fake EOF on stdin */ |
/* fake EOF on stdin */ |
return -1; |
return -1; |
|
} else if (!stdin_eof) { |
|
/* |
|
* Sending SSH_CMSG_EOF alone does not |
|
* always appear to be enough. So we |
|
* try to send an EOF character first. |
|
*/ |
|
packet_start(SSH_CMSG_STDIN_DATA); |
|
packet_put_string("\004", 1); |
|
packet_send(); |
|
/* Close stdin. */ |
|
stdin_eof = 1; |
|
if (buffer_len(bin) == 0) { |
|
packet_start(SSH_CMSG_EOF); |
|
packet_send(); |
|
} |
|
} |
|
continue; |
|
|
|
case '?': |
case '?': |
print_escape_help(berr, escape_char, compat20, |
print_escape_help(berr, escape_char, |
(c && c->ctl_chan != -1), |
(c && c->ctl_chan != -1), |
log_is_on_stderr()); |
log_is_on_stderr()); |
continue; |
continue; |
|
|
return bytes; |
return bytes; |
} |
} |
|
|
static void |
|
client_process_input(fd_set *readset) |
|
{ |
|
int len; |
|
char buf[8192]; |
|
|
|
/* Read input from stdin. */ |
|
if (FD_ISSET(fileno(stdin), readset)) { |
|
/* Read as much as possible. */ |
|
len = read(fileno(stdin), buf, sizeof(buf)); |
|
if (len < 0 && (errno == EAGAIN || errno == EINTR)) |
|
return; /* we'll try again later */ |
|
if (len <= 0) { |
|
/* |
|
* Received EOF or error. They are treated |
|
* similarly, except that an error message is printed |
|
* if it was an error condition. |
|
*/ |
|
if (len < 0) { |
|
snprintf(buf, sizeof buf, "read: %.100s\r\n", |
|
strerror(errno)); |
|
buffer_append(&stderr_buffer, buf, strlen(buf)); |
|
} |
|
/* Mark that we have seen EOF. */ |
|
stdin_eof = 1; |
|
/* |
|
* Send an EOF message to the server unless there is |
|
* data in the buffer. If there is data in the |
|
* buffer, no message will be sent now. Code |
|
* elsewhere will send the EOF when the buffer |
|
* becomes empty if stdin_eof is set. |
|
*/ |
|
if (buffer_len(&stdin_buffer) == 0) { |
|
packet_start(SSH_CMSG_EOF); |
|
packet_send(); |
|
} |
|
} else if (escape_char1 == SSH_ESCAPECHAR_NONE) { |
|
/* |
|
* Normal successful read, and no escape character. |
|
* Just append the data to buffer. |
|
*/ |
|
buffer_append(&stdin_buffer, buf, len); |
|
} else { |
|
/* |
|
* Normal, successful read. But we have an escape |
|
* character and have to process the characters one |
|
* by one. |
|
*/ |
|
if (process_escapes(NULL, &stdin_buffer, |
|
&stdout_buffer, &stderr_buffer, buf, len) == -1) |
|
return; |
|
} |
|
} |
|
} |
|
|
|
static void |
|
client_process_output(fd_set *writeset) |
|
{ |
|
int len; |
|
char buf[100]; |
|
|
|
/* Write buffered output to stdout. */ |
|
if (FD_ISSET(fileno(stdout), writeset)) { |
|
/* Write as much data as possible. */ |
|
len = write(fileno(stdout), buffer_ptr(&stdout_buffer), |
|
buffer_len(&stdout_buffer)); |
|
if (len <= 0) { |
|
if (errno == EINTR || errno == EAGAIN) |
|
len = 0; |
|
else { |
|
/* |
|
* An error or EOF was encountered. Put an |
|
* error message to stderr buffer. |
|
*/ |
|
snprintf(buf, sizeof buf, |
|
"write stdout: %.50s\r\n", strerror(errno)); |
|
buffer_append(&stderr_buffer, buf, strlen(buf)); |
|
quit_pending = 1; |
|
return; |
|
} |
|
} |
|
/* Consume printed data from the buffer. */ |
|
buffer_consume(&stdout_buffer, len); |
|
} |
|
/* Write buffered output to stderr. */ |
|
if (FD_ISSET(fileno(stderr), writeset)) { |
|
/* Write as much data as possible. */ |
|
len = write(fileno(stderr), buffer_ptr(&stderr_buffer), |
|
buffer_len(&stderr_buffer)); |
|
if (len <= 0) { |
|
if (errno == EINTR || errno == EAGAIN) |
|
len = 0; |
|
else { |
|
/* |
|
* EOF or error, but can't even print |
|
* error message. |
|
*/ |
|
quit_pending = 1; |
|
return; |
|
} |
|
} |
|
/* Consume printed characters from the buffer. */ |
|
buffer_consume(&stderr_buffer, len); |
|
} |
|
} |
|
|
|
/* |
/* |
* Get packets from the connection input buffer, and process them as long as |
* Get packets from the connection input buffer, and process them as long as |
* there are packets available. |
* there are packets available. |
|
|
connection_out = packet_get_connection_out(); |
connection_out = packet_get_connection_out(); |
max_fd = MAXIMUM(connection_in, connection_out); |
max_fd = MAXIMUM(connection_in, connection_out); |
|
|
if (!compat20) { |
|
/* enable nonblocking unless tty */ |
|
if (!isatty(fileno(stdin))) |
|
set_nonblock(fileno(stdin)); |
|
if (!isatty(fileno(stdout))) |
|
set_nonblock(fileno(stdout)); |
|
if (!isatty(fileno(stderr))) |
|
set_nonblock(fileno(stderr)); |
|
max_fd = MAXIMUM(max_fd, fileno(stdin)); |
|
max_fd = MAXIMUM(max_fd, fileno(stdout)); |
|
max_fd = MAXIMUM(max_fd, fileno(stderr)); |
|
} |
|
quit_pending = 0; |
quit_pending = 0; |
escape_char1 = escape_char_arg; |
escape_char1 = escape_char_arg; |
|
|
|
|
if (have_pty) |
if (have_pty) |
enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE); |
enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE); |
|
|
if (compat20) { |
session_ident = ssh2_chan_id; |
session_ident = ssh2_chan_id; |
if (session_ident != -1) { |
if (session_ident != -1) { |
if (escape_char_arg != SSH_ESCAPECHAR_NONE) { |
if (escape_char_arg != SSH_ESCAPECHAR_NONE) { |
channel_register_filter(session_ident, |
channel_register_filter(session_ident, |
client_simple_escape_filter, NULL, |
client_simple_escape_filter, NULL, |
client_filter_cleanup, |
client_filter_cleanup, |
client_new_escape_filter_ctx( |
client_new_escape_filter_ctx( |
escape_char_arg)); |
escape_char_arg)); |
|
} |
|
channel_register_cleanup(session_ident, |
|
client_channel_closed, 0); |
|
} |
} |
} else { |
channel_register_cleanup(session_ident, |
/* Check if we should immediately send eof on stdin. */ |
client_channel_closed, 0); |
client_check_initial_eof_on_stdin(); |
|
} |
} |
|
|
/* Main loop of the client for the interactive session mode. */ |
/* Main loop of the client for the interactive session mode. */ |
|
|
/* Process buffered packets sent by the server. */ |
/* Process buffered packets sent by the server. */ |
client_process_buffered_input_packets(); |
client_process_buffered_input_packets(); |
|
|
if (compat20 && session_closed && !channel_still_open()) |
if (session_closed && !channel_still_open()) |
break; |
break; |
|
|
if (ssh_packet_is_rekeying(active_state)) { |
if (ssh_packet_is_rekeying(active_state)) { |
|
|
need_rekeying = 0; |
need_rekeying = 0; |
} else { |
} else { |
/* |
/* |
* Make packets of buffered stdin data, and buffer |
|
* them for sending to the server. |
|
*/ |
|
if (!compat20) |
|
client_make_packets_from_stdin_data(); |
|
|
|
/* |
|
* Make packets from buffered channel data, and |
* Make packets from buffered channel data, and |
* enqueue them for sending to the server. |
* enqueue them for sending to the server. |
*/ |
*/ |
|
|
if (quit_pending) |
if (quit_pending) |
break; |
break; |
|
|
if (!compat20) { |
|
/* Buffer data from stdin */ |
|
client_process_input(readset); |
|
/* |
|
* Process output to stdout and stderr. Output to |
|
* the connection is processed elsewhere (above). |
|
*/ |
|
client_process_output(writeset); |
|
} |
|
|
|
/* |
/* |
* Send as much buffered packet data as possible to the |
* Send as much buffered packet data as possible to the |
* sender. |
* sender. |
|
|
/* Stop watching for window change. */ |
/* Stop watching for window change. */ |
signal(SIGWINCH, SIG_DFL); |
signal(SIGWINCH, SIG_DFL); |
|
|
if (compat20) { |
packet_start(SSH2_MSG_DISCONNECT); |
packet_start(SSH2_MSG_DISCONNECT); |
packet_put_int(SSH2_DISCONNECT_BY_APPLICATION); |
packet_put_int(SSH2_DISCONNECT_BY_APPLICATION); |
packet_put_cstring("disconnected by user"); |
packet_put_cstring("disconnected by user"); |
packet_put_cstring(""); /* language tag */ |
packet_put_cstring(""); /* language tag */ |
packet_send(); |
packet_send(); |
packet_write_wait(); |
packet_write_wait(); |
|
} |
|
|
|
channel_free_all(); |
channel_free_all(); |
|
|
|
|
|
|
/*********/ |
/*********/ |
|
|
static int |
|
client_input_stdout_data(int type, u_int32_t seq, void *ctxt) |
|
{ |
|
u_int data_len; |
|
char *data = packet_get_string(&data_len); |
|
packet_check_eom(); |
|
buffer_append(&stdout_buffer, data, data_len); |
|
explicit_bzero(data, data_len); |
|
free(data); |
|
return 0; |
|
} |
|
static int |
|
client_input_stderr_data(int type, u_int32_t seq, void *ctxt) |
|
{ |
|
u_int data_len; |
|
char *data = packet_get_string(&data_len); |
|
packet_check_eom(); |
|
buffer_append(&stderr_buffer, data, data_len); |
|
explicit_bzero(data, data_len); |
|
free(data); |
|
return 0; |
|
} |
|
static int |
|
client_input_exit_status(int type, u_int32_t seq, void *ctxt) |
|
{ |
|
exit_status = packet_get_int(); |
|
packet_check_eom(); |
|
/* Acknowledge the exit. */ |
|
packet_start(SSH_CMSG_EXIT_CONFIRMATION); |
|
packet_send(); |
|
/* |
|
* Must wait for packet to be sent since we are |
|
* exiting the loop. |
|
*/ |
|
packet_write_wait(); |
|
/* Flag that we want to exit. */ |
|
quit_pending = 1; |
|
return 0; |
|
} |
|
|
|
static int |
|
client_input_agent_open(int type, u_int32_t seq, void *ctxt) |
|
{ |
|
Channel *c = NULL; |
|
int r, remote_id, sock; |
|
|
|
/* Read the remote channel number from the message. */ |
|
remote_id = packet_get_int(); |
|
packet_check_eom(); |
|
|
|
/* |
|
* Get a connection to the local authentication agent (this may again |
|
* get forwarded). |
|
*/ |
|
if ((r = ssh_get_authentication_socket(&sock)) != 0 && |
|
r != SSH_ERR_AGENT_NOT_PRESENT) |
|
debug("%s: ssh_get_authentication_socket: %s", |
|
__func__, ssh_err(r)); |
|
|
|
|
|
/* |
|
* If we could not connect the agent, send an error message back to |
|
* the server. This should never happen unless the agent dies, |
|
* because authentication forwarding is only enabled if we have an |
|
* agent. |
|
*/ |
|
if (sock >= 0) { |
|
c = channel_new("", SSH_CHANNEL_OPEN, sock, sock, |
|
-1, 0, 0, 0, "authentication agent connection", 1); |
|
c->remote_id = remote_id; |
|
c->force_drain = 1; |
|
} |
|
if (c == NULL) { |
|
packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); |
|
packet_put_int(remote_id); |
|
} else { |
|
/* Send a confirmation to the remote host. */ |
|
debug("Forwarding authentication connection."); |
|
packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); |
|
packet_put_int(remote_id); |
|
packet_put_int(c->self); |
|
} |
|
packet_send(); |
|
return 0; |
|
} |
|
|
|
static Channel * |
static Channel * |
client_request_forwarded_tcpip(const char *request_type, int rchan, |
client_request_forwarded_tcpip(const char *request_type, int rchan, |
u_int rwindow, u_int rmaxpack) |
u_int rwindow, u_int rmaxpack) |
|
|
if (tun_mode == SSH_TUNMODE_NO) |
if (tun_mode == SSH_TUNMODE_NO) |
return 0; |
return 0; |
|
|
if (!compat20) { |
|
error("Tunnel forwarding is not supported for protocol 1"); |
|
return -1; |
|
} |
|
|
|
debug("Requesting tun unit %d in mode %d", local_tun, tun_mode); |
debug("Requesting tun unit %d in mode %d", local_tun, tun_mode); |
|
|
/* Open local tunnel device */ |
/* Open local tunnel device */ |
|
|
} |
} |
|
|
static void |
static void |
client_init_dispatch_20(void) |
client_init_dispatch(void) |
{ |
{ |
dispatch_init(&dispatch_protocol_error); |
dispatch_init(&dispatch_protocol_error); |
|
|
|
|
/* global request reply messages */ |
/* global request reply messages */ |
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 |
|
client_init_dispatch_13(void) |
|
{ |
|
dispatch_init(NULL); |
|
dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_close); |
|
dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_close_confirmation); |
|
dispatch_set(SSH_MSG_CHANNEL_DATA, &channel_input_data); |
|
dispatch_set(SSH_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation); |
|
dispatch_set(SSH_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure); |
|
dispatch_set(SSH_MSG_PORT_OPEN, &channel_input_port_open); |
|
dispatch_set(SSH_SMSG_EXITSTATUS, &client_input_exit_status); |
|
dispatch_set(SSH_SMSG_STDERR_DATA, &client_input_stderr_data); |
|
dispatch_set(SSH_SMSG_STDOUT_DATA, &client_input_stdout_data); |
|
|
|
dispatch_set(SSH_SMSG_AGENT_OPEN, options.forward_agent ? |
|
&client_input_agent_open : &deny_input_open); |
|
dispatch_set(SSH_SMSG_X11_OPEN, options.forward_x11 ? |
|
&x11_input_open : &deny_input_open); |
|
} |
|
|
|
static void |
|
client_init_dispatch_15(void) |
|
{ |
|
client_init_dispatch_13(); |
|
dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_ieof); |
|
dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, & channel_input_oclose); |
|
} |
|
|
|
static void |
|
client_init_dispatch(void) |
|
{ |
|
if (compat20) |
|
client_init_dispatch_20(); |
|
else if (compat13) |
|
client_init_dispatch_13(); |
|
else |
|
client_init_dispatch_15(); |
|
} |
} |
|
|
void |
void |