version 1.353, 2020/10/14 00:55:17 |
version 1.354, 2020/10/18 11:32:01 |
|
|
} else if (channel_still_open(ssh)) { |
} else if (channel_still_open(ssh)) { |
/* some client connections are still open */ |
/* some client connections are still open */ |
if (control_persist_exit_time > 0) |
if (control_persist_exit_time > 0) |
debug2("%s: cancel scheduled exit", __func__); |
debug2_f("cancel scheduled exit"); |
control_persist_exit_time = 0; |
control_persist_exit_time = 0; |
} else if (control_persist_exit_time <= 0) { |
} else if (control_persist_exit_time <= 0) { |
/* a client connection has recently closed */ |
/* a client connection has recently closed */ |
control_persist_exit_time = monotime() + |
control_persist_exit_time = monotime() + |
(time_t)options.control_persist_timeout; |
(time_t)options.control_persist_timeout; |
debug2("%s: schedule exit in %d seconds", __func__, |
debug2_f("schedule exit in %d seconds", |
options.control_persist_timeout); |
options.control_persist_timeout); |
} |
} |
/* else we are already counting down to the timeout */ |
/* else we are already counting down to the timeout */ |
|
|
if ((r = snprintf(xdisplay, sizeof(xdisplay), "unix:%s", |
if ((r = snprintf(xdisplay, sizeof(xdisplay), "unix:%s", |
display + 10)) < 0 || |
display + 10)) < 0 || |
(size_t)r >= sizeof(xdisplay)) { |
(size_t)r >= sizeof(xdisplay)) { |
error("%s: display name too long", __func__); |
error_f("display name too long"); |
return -1; |
return -1; |
} |
} |
display = xdisplay; |
display = xdisplay; |
|
|
*/ |
*/ |
mktemp_proto(xauthdir, sizeof(xauthdir)); |
mktemp_proto(xauthdir, sizeof(xauthdir)); |
if (mkdtemp(xauthdir) == NULL) { |
if (mkdtemp(xauthdir) == NULL) { |
error("%s: mkdtemp: %s", |
error_f("mkdtemp: %s", strerror(errno)); |
__func__, strerror(errno)); |
|
return -1; |
return -1; |
} |
} |
do_unlink = 1; |
do_unlink = 1; |
if ((r = snprintf(xauthfile, sizeof(xauthfile), |
if ((r = snprintf(xauthfile, sizeof(xauthfile), |
"%s/xauthfile", xauthdir)) < 0 || |
"%s/xauthfile", xauthdir)) < 0 || |
(size_t)r >= sizeof(xauthfile)) { |
(size_t)r >= sizeof(xauthfile)) { |
error("%s: xauthfile path too long", __func__); |
error_f("xauthfile path too long"); |
rmdir(xauthdir); |
rmdir(xauthdir); |
return -1; |
return -1; |
} |
} |
|
|
SSH_X11_PROTO, x11_timeout_real, |
SSH_X11_PROTO, x11_timeout_real, |
_PATH_DEVNULL); |
_PATH_DEVNULL); |
} |
} |
debug2("%s: xauth command: %s", __func__, cmd); |
debug2_f("xauth command: %s", cmd); |
|
|
if (timeout != 0 && x11_refuse_time == 0) { |
if (timeout != 0 && x11_refuse_time == 0) { |
now = monotime() + 1; |
now = monotime() + 1; |
|
|
if (!received_window_change_signal) |
if (!received_window_change_signal) |
return; |
return; |
received_window_change_signal = 0; |
received_window_change_signal = 0; |
debug2("%s: changed", __func__); |
debug2_f("changed"); |
channel_send_window_changes(ssh); |
channel_send_window_changes(ssh); |
} |
} |
|
|
|
|
(r = sshpkt_put_cstring(ssh, "keepalive@openssh.com")) != 0 || |
(r = sshpkt_put_cstring(ssh, "keepalive@openssh.com")) != 0 || |
(r = sshpkt_put_u8(ssh, 1)) != 0 || /* boolean: want reply */ |
(r = sshpkt_put_u8(ssh, 1)) != 0 || /* boolean: want reply */ |
(r = sshpkt_send(ssh)) != 0) |
(r = sshpkt_send(ssh)) != 0) |
fatal("%s: send packet: %s", __func__, ssh_err(r)); |
fatal_fr(r, "send packet"); |
/* Insert an empty placeholder to maintain ordering */ |
/* Insert an empty placeholder to maintain ordering */ |
client_register_global_confirm(NULL, NULL); |
client_register_global_confirm(NULL, NULL); |
schedule_server_alive_check(); |
schedule_server_alive_check(); |
|
|
/* Note: we might still have data in the buffers. */ |
/* Note: we might still have data in the buffers. */ |
if ((r = sshbuf_putf(stderr_buffer, |
if ((r = sshbuf_putf(stderr_buffer, |
"select: %s\r\n", strerror(errno))) != 0) |
"select: %s\r\n", strerror(errno))) != 0) |
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
fatal_fr(r, "sshbuf_putf"); |
quit_pending = 1; |
quit_pending = 1; |
} else if (options.server_alive_interval > 0 && !FD_ISSET(connection_in, |
} else if (options.server_alive_interval > 0 && !FD_ISSET(connection_in, |
*readsetp) && monotime() >= server_alive_time) |
*readsetp) && monotime() >= server_alive_time) |
|
|
if ((r = sshbuf_putf(stderr_buffer, |
if ((r = sshbuf_putf(stderr_buffer, |
"Connection to %.300s closed by remote host.\r\n", |
"Connection to %.300s closed by remote host.\r\n", |
host)) != 0) |
host)) != 0) |
fatal("%s: buffer error: %s", |
fatal_fr(r, "sshbuf_putf"); |
__func__, ssh_err(r)); |
|
quit_pending = 1; |
quit_pending = 1; |
return; |
return; |
} |
} |
|
|
if ((r = sshbuf_putf(stderr_buffer, |
if ((r = sshbuf_putf(stderr_buffer, |
"Read from remote host %.300s: %.100s\r\n", |
"Read from remote host %.300s: %.100s\r\n", |
host, strerror(errno))) != 0) |
host, strerror(errno))) != 0) |
fatal("%s: buffer error: %s", |
fatal_fr(r, "sshbuf_putf"); |
__func__, ssh_err(r)); |
|
quit_pending = 1; |
quit_pending = 1; |
return; |
return; |
} |
} |
|
|
if (tochan) { |
if (tochan) { |
if ((r = sshbuf_put(c->extended, errmsg, |
if ((r = sshbuf_put(c->extended, errmsg, |
strlen(errmsg))) != 0) |
strlen(errmsg))) != 0) |
fatal("%s: buffer error %s", __func__, |
fatal_fr(r, "sshbuf_put"); |
ssh_err(r)); |
|
} else |
} else |
error("%s", errmsg); |
error("%s", errmsg); |
if (cr->action == CONFIRM_TTY) { |
if (cr->action == CONFIRM_TTY) { |
|
|
last_gc = TAILQ_LAST(&global_confirms, global_confirms); |
last_gc = TAILQ_LAST(&global_confirms, global_confirms); |
if (last_gc && last_gc->cb == cb && last_gc->ctx == ctx) { |
if (last_gc && last_gc->cb == cb && last_gc->ctx == ctx) { |
if (++last_gc->ref_count >= INT_MAX) |
if (++last_gc->ref_count >= INT_MAX) |
fatal("%s: last_gc->ref_count = %d", |
fatal_f("last_gc->ref_count = %d", |
__func__, last_gc->ref_count); |
last_gc->ref_count); |
return; |
return; |
} |
} |
|
|
|
|
|
|
if ((r = sshbuf_putf(b, |
if ((r = sshbuf_putf(b, |
"%c?\r\nSupported escape sequences:\r\n", escape_char)) != 0) |
"%c?\r\nSupported escape sequences:\r\n", escape_char)) != 0) |
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
fatal_fr(r, "sshbuf_putf"); |
|
|
suppress_flags = |
suppress_flags = |
(mux_client ? SUPPRESS_MUXCLIENT : 0) | |
(mux_client ? SUPPRESS_MUXCLIENT : 0) | |
|
|
continue; |
continue; |
if ((r = sshbuf_putf(b, " %c%-3s - %s\r\n", |
if ((r = sshbuf_putf(b, " %c%-3s - %s\r\n", |
escape_char, esc_txt[i].cmd, esc_txt[i].text)) != 0) |
escape_char, esc_txt[i].cmd, esc_txt[i].text)) != 0) |
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
fatal_fr(r, "sshbuf_putf"); |
} |
} |
|
|
if ((r = sshbuf_putf(b, |
if ((r = sshbuf_putf(b, |
" %c%c - send the escape character by typing it twice\r\n" |
" %c%c - send the escape character by typing it twice\r\n" |
"(Note that escapes are only recognized immediately after " |
"(Note that escapes are only recognized immediately after " |
"newline.)\r\n", escape_char, escape_char)) != 0) |
"newline.)\r\n", escape_char, escape_char)) != 0) |
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
fatal_fr(r, "sshbuf_putf"); |
} |
} |
|
|
/* |
/* |
|
|
/* Terminate the connection. */ |
/* Terminate the connection. */ |
if ((r = sshbuf_putf(berr, "%c.\r\n", |
if ((r = sshbuf_putf(berr, "%c.\r\n", |
efc->escape_char)) != 0) |
efc->escape_char)) != 0) |
fatal("%s: buffer error: %s", |
fatal_fr(r, "sshbuf_putf"); |
__func__, ssh_err(r)); |
|
if (c && c->ctl_chan != -1) { |
if (c && c->ctl_chan != -1) { |
chan_read_failed(ssh, c); |
chan_read_failed(ssh, c); |
chan_write_failed(ssh, c); |
chan_write_failed(ssh, c); |
|
|
"%c%s escape not available to " |
"%c%s escape not available to " |
"multiplexed sessions\r\n", |
"multiplexed sessions\r\n", |
efc->escape_char, b)) != 0) |
efc->escape_char, b)) != 0) |
fatal("%s: buffer error: %s", |
fatal_fr(r, "sshbuf_putf"); |
__func__, ssh_err(r)); |
|
continue; |
continue; |
} |
} |
/* Suspend the program. Inform the user */ |
/* Suspend the program. Inform the user */ |
if ((r = sshbuf_putf(berr, |
if ((r = sshbuf_putf(berr, |
"%c^Z [suspend ssh]\r\n", |
"%c^Z [suspend ssh]\r\n", |
efc->escape_char)) != 0) |
efc->escape_char)) != 0) |
fatal("%s: buffer error: %s", |
fatal_fr(r, "sshbuf_putf"); |
__func__, ssh_err(r)); |
|
|
|
/* Restore terminal modes and suspend. */ |
/* Restore terminal modes and suspend. */ |
client_suspend_self(bin, bout, berr); |
client_suspend_self(bin, bout, berr); |
|
|
case 'B': |
case 'B': |
if ((r = sshbuf_putf(berr, |
if ((r = sshbuf_putf(berr, |
"%cB\r\n", efc->escape_char)) != 0) |
"%cB\r\n", efc->escape_char)) != 0) |
fatal("%s: buffer error: %s", |
fatal_fr(r, "sshbuf_putf"); |
__func__, ssh_err(r)); |
|
channel_request_start(ssh, c->self, "break", 0); |
channel_request_start(ssh, c->self, "break", 0); |
if ((r = sshpkt_put_u32(ssh, 1000)) != 0 || |
if ((r = sshpkt_put_u32(ssh, 1000)) != 0 || |
(r = sshpkt_send(ssh)) != 0) |
(r = sshpkt_send(ssh)) != 0) |
fatal("%s: send packet: %s", __func__, |
fatal_fr(r, "send packet"); |
ssh_err(r)); |
|
continue; |
continue; |
|
|
case 'R': |
case 'R': |
|
|
if ((r = sshbuf_putf(berr, |
if ((r = sshbuf_putf(berr, |
"%c%c [Logging to syslog]\r\n", |
"%c%c [Logging to syslog]\r\n", |
efc->escape_char, ch)) != 0) |
efc->escape_char, ch)) != 0) |
fatal("%s: buffer error: %s", |
fatal_fr(r, "sshbuf_putf"); |
__func__, ssh_err(r)); |
|
continue; |
continue; |
} |
} |
if (ch == 'V' && options.log_level > |
if (ch == 'V' && options.log_level > |
|
|
"%c%c [LogLevel %s]\r\n", |
"%c%c [LogLevel %s]\r\n", |
efc->escape_char, ch, |
efc->escape_char, ch, |
log_level_name(options.log_level))) != 0) |
log_level_name(options.log_level))) != 0) |
fatal("%s: buffer error: %s", |
fatal_fr(r, "sshbuf_putf"); |
__func__, ssh_err(r)); |
|
continue; |
continue; |
|
|
case '&': |
case '&': |
|
|
/* Stop listening for new connections. */ |
/* Stop listening for new connections. */ |
channel_stop_listening(ssh); |
channel_stop_listening(ssh); |
|
|
if ((r = sshbuf_putf(berr, |
if ((r = sshbuf_putf(berr, "%c& " |
"%c& [backgrounded]\n", efc->escape_char)) |
"[backgrounded]\n", efc->escape_char)) != 0) |
!= 0) |
fatal_fr(r, "sshbuf_putf"); |
fatal("%s: buffer error: %s", |
|
__func__, ssh_err(r)); |
|
|
|
/* Fork into background. */ |
/* Fork into background. */ |
pid = fork(); |
pid = fork(); |
|
|
/* The child continues serving connections. */ |
/* The child continues serving connections. */ |
/* fake EOF on stdin */ |
/* fake EOF on stdin */ |
if ((r = sshbuf_put_u8(bin, 4)) != 0) |
if ((r = sshbuf_put_u8(bin, 4)) != 0) |
fatal("%s: buffer error: %s", |
fatal_fr(r, "sshbuf_put_u8"); |
__func__, ssh_err(r)); |
|
return -1; |
return -1; |
case '?': |
case '?': |
print_escape_help(berr, efc->escape_char, |
print_escape_help(berr, efc->escape_char, |
|
|
case '#': |
case '#': |
if ((r = sshbuf_putf(berr, "%c#\r\n", |
if ((r = sshbuf_putf(berr, "%c#\r\n", |
efc->escape_char)) != 0) |
efc->escape_char)) != 0) |
fatal("%s: buffer error: %s", |
fatal_fr(r, "sshbuf_putf"); |
__func__, ssh_err(r)); |
|
s = channel_open_message(ssh); |
s = channel_open_message(ssh); |
if ((r = sshbuf_put(berr, s, strlen(s))) != 0) |
if ((r = sshbuf_put(berr, s, strlen(s))) != 0) |
fatal("%s: buffer error: %s", |
fatal_fr(r, "sshbuf_put"); |
__func__, ssh_err(r)); |
|
free(s); |
free(s); |
continue; |
continue; |
|
|
|
|
if (ch != efc->escape_char) { |
if (ch != efc->escape_char) { |
if ((r = sshbuf_put_u8(bin, |
if ((r = sshbuf_put_u8(bin, |
efc->escape_char)) != 0) |
efc->escape_char)) != 0) |
fatal("%s: buffer error: %s", |
fatal_fr(r, "sshbuf_put_u8"); |
__func__, ssh_err(r)); |
|
bytes++; |
bytes++; |
} |
} |
/* Escaped characters fall through here */ |
/* Escaped characters fall through here */ |
|
|
*/ |
*/ |
last_was_cr = (ch == '\r' || ch == '\n'); |
last_was_cr = (ch == '\r' || ch == '\n'); |
if ((r = sshbuf_put_u8(bin, ch)) != 0) |
if ((r = sshbuf_put_u8(bin, ch)) != 0) |
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
fatal_fr(r, "sshbuf_put_u8"); |
bytes++; |
bytes++; |
} |
} |
return bytes; |
return bytes; |
|
|
debug("pledge: id"); |
debug("pledge: id"); |
if (pledge("stdio rpath wpath cpath unix inet dns recvfd sendfd proc exec id tty", |
if (pledge("stdio rpath wpath cpath unix inet dns recvfd sendfd proc exec id tty", |
NULL) == -1) |
NULL) == -1) |
fatal("%s pledge(): %s", __func__, strerror(errno)); |
fatal_f("pledge(): %s", strerror(errno)); |
|
|
} else if (options.forward_x11 || options.permit_local_command) { |
} else if (options.forward_x11 || options.permit_local_command) { |
debug("pledge: exec"); |
debug("pledge: exec"); |
if (pledge("stdio rpath wpath cpath unix inet dns proc exec tty", |
if (pledge("stdio rpath wpath cpath unix inet dns proc exec tty", |
NULL) == -1) |
NULL) == -1) |
fatal("%s pledge(): %s", __func__, strerror(errno)); |
fatal_f("pledge(): %s", strerror(errno)); |
|
|
} else if (options.update_hostkeys) { |
} else if (options.update_hostkeys) { |
debug("pledge: filesystem full"); |
debug("pledge: filesystem full"); |
if (pledge("stdio rpath wpath cpath unix inet dns proc tty", |
if (pledge("stdio rpath wpath cpath unix inet dns proc tty", |
NULL) == -1) |
NULL) == -1) |
fatal("%s pledge(): %s", __func__, strerror(errno)); |
fatal_f("pledge(): %s", strerror(errno)); |
|
|
} else if (!option_clear_or_none(options.proxy_command) || |
} else if (!option_clear_or_none(options.proxy_command) || |
fork_after_authentication_flag) { |
fork_after_authentication_flag) { |
debug("pledge: proc"); |
debug("pledge: proc"); |
if (pledge("stdio cpath unix inet dns proc tty", NULL) == -1) |
if (pledge("stdio cpath unix inet dns proc tty", NULL) == -1) |
fatal("%s pledge(): %s", __func__, strerror(errno)); |
fatal_f("pledge(): %s", strerror(errno)); |
|
|
} else { |
} else { |
debug("pledge: network"); |
debug("pledge: network"); |
if (pledge("stdio unix inet dns proc tty", NULL) == -1) |
if (pledge("stdio unix inet dns proc tty", NULL) == -1) |
fatal("%s pledge(): %s", __func__, strerror(errno)); |
fatal_f("pledge(): %s", strerror(errno)); |
} |
} |
|
|
start_time = monotime_double(); |
start_time = monotime_double(); |
|
|
|
|
/* Initialize buffer. */ |
/* Initialize buffer. */ |
if ((stderr_buffer = sshbuf_new()) == NULL) |
if ((stderr_buffer = sshbuf_new()) == NULL) |
fatal("%s: sshbuf_new failed", __func__); |
fatal_f("sshbuf_new failed"); |
|
|
client_init_dispatch(ssh); |
client_init_dispatch(ssh); |
|
|
|
|
/* manual rekey request */ |
/* manual rekey request */ |
debug("need rekeying"); |
debug("need rekeying"); |
if ((r = kex_start_rekex(ssh)) != 0) |
if ((r = kex_start_rekex(ssh)) != 0) |
fatal("%s: kex_start_rekex: %s", __func__, |
fatal_fr(r, "kex_start_rekex"); |
ssh_err(r)); |
|
need_rekeying = 0; |
need_rekeying = 0; |
} else { |
} else { |
/* |
/* |
|
|
(r = sshpkt_put_cstring(ssh, "")) != 0 || /* language tag */ |
(r = sshpkt_put_cstring(ssh, "")) != 0 || /* language tag */ |
(r = sshpkt_send(ssh)) != 0 || |
(r = sshpkt_send(ssh)) != 0 || |
(r = ssh_packet_write_wait(ssh)) != 0) |
(r = ssh_packet_write_wait(ssh)) != 0) |
fatal("%s: send disconnect: %s", __func__, ssh_err(r)); |
fatal_fr(r, "send disconnect"); |
|
|
channel_free_all(ssh); |
channel_free_all(ssh); |
|
|
|
|
if (have_pty && options.log_level != SYSLOG_LEVEL_QUIET) { |
if (have_pty && options.log_level != SYSLOG_LEVEL_QUIET) { |
if ((r = sshbuf_putf(stderr_buffer, |
if ((r = sshbuf_putf(stderr_buffer, |
"Connection to %.64s closed.\r\n", host)) != 0) |
"Connection to %.64s closed.\r\n", host)) != 0) |
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
fatal_fr(r, "sshbuf_putf"); |
} |
} |
|
|
/* Output any buffered data for stderr. */ |
/* Output any buffered data for stderr. */ |
|
|
if (len < 0 || (u_int)len != sshbuf_len(stderr_buffer)) |
if (len < 0 || (u_int)len != sshbuf_len(stderr_buffer)) |
error("Write failed flushing stderr buffer."); |
error("Write failed flushing stderr buffer."); |
else if ((r = sshbuf_consume(stderr_buffer, len)) != 0) |
else if ((r = sshbuf_consume(stderr_buffer, len)) != 0) |
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
fatal_fr(r, "sshbuf_consume"); |
} |
} |
|
|
/* Clear and free any buffers. */ |
/* Clear and free any buffers. */ |
|
|
(r = sshpkt_get_cstring(ssh, &originator_address, NULL)) != 0 || |
(r = sshpkt_get_cstring(ssh, &originator_address, NULL)) != 0 || |
(r = sshpkt_get_u32(ssh, &originator_port)) != 0 || |
(r = sshpkt_get_u32(ssh, &originator_port)) != 0 || |
(r = sshpkt_get_end(ssh)) != 0) |
(r = sshpkt_get_end(ssh)) != 0) |
fatal("%s: parse packet: %s", __func__, ssh_err(r)); |
fatal_fr(r, "parse packet"); |
|
|
debug("%s: listen %s port %d, originator %s port %d", __func__, |
debug_f("listen %s port %d, originator %s port %d", |
listen_address, listen_port, originator_address, originator_port); |
listen_address, listen_port, originator_address, originator_port); |
|
|
if (listen_port > 0xffff) |
if (listen_port > 0xffff) |
error("%s: invalid listen port", __func__); |
error_f("invalid listen port"); |
else if (originator_port > 0xffff) |
else if (originator_port > 0xffff) |
error("%s: invalid originator port", __func__); |
error_f("invalid originator port"); |
else { |
else { |
c = channel_connect_by_listen_address(ssh, |
c = channel_connect_by_listen_address(ssh, |
listen_address, listen_port, "forwarded-tcpip", |
listen_address, listen_port, "forwarded-tcpip", |
|
|
|
|
if (c != NULL && c->type == SSH_CHANNEL_MUX_CLIENT) { |
if (c != NULL && c->type == SSH_CHANNEL_MUX_CLIENT) { |
if ((b = sshbuf_new()) == NULL) { |
if ((b = sshbuf_new()) == NULL) { |
error("%s: alloc reply", __func__); |
error_f("alloc reply"); |
goto out; |
goto out; |
} |
} |
/* reconstruct and send to muxclient */ |
/* reconstruct and send to muxclient */ |
|
|
(r = sshbuf_put_cstring(b, originator_address)) != 0 || |
(r = sshbuf_put_cstring(b, originator_address)) != 0 || |
(r = sshbuf_put_u32(b, originator_port)) != 0 || |
(r = sshbuf_put_u32(b, originator_port)) != 0 || |
(r = sshbuf_put_stringb(c->output, b)) != 0) { |
(r = sshbuf_put_stringb(c->output, b)) != 0) { |
error("%s: compose for muxclient %s", __func__, |
error_fr(r, "compose for muxclient"); |
ssh_err(r)); |
|
goto out; |
goto out; |
} |
} |
} |
} |
|
|
if ((r = sshpkt_get_cstring(ssh, &listen_path, NULL)) != 0 || |
if ((r = sshpkt_get_cstring(ssh, &listen_path, NULL)) != 0 || |
(r = sshpkt_get_string(ssh, NULL, NULL)) != 0 || /* reserved */ |
(r = sshpkt_get_string(ssh, NULL, NULL)) != 0 || /* reserved */ |
(r = sshpkt_get_end(ssh)) != 0) |
(r = sshpkt_get_end(ssh)) != 0) |
fatal("%s: parse packet: %s", __func__, ssh_err(r)); |
fatal_fr(r, "parse packet"); |
|
|
debug("%s: request: %s", __func__, listen_path); |
debug_f("request: %s", listen_path); |
|
|
c = channel_connect_by_listen_path(ssh, listen_path, |
c = channel_connect_by_listen_path(ssh, listen_path, |
"forwarded-streamlocal@openssh.com", "forwarded-streamlocal"); |
"forwarded-streamlocal@openssh.com", "forwarded-streamlocal"); |
|
|
if ((r = sshpkt_get_cstring(ssh, &originator, NULL)) != 0 || |
if ((r = sshpkt_get_cstring(ssh, &originator, NULL)) != 0 || |
(r = sshpkt_get_u32(ssh, &originator_port)) != 0 || |
(r = sshpkt_get_u32(ssh, &originator_port)) != 0 || |
(r = sshpkt_get_end(ssh)) != 0) |
(r = sshpkt_get_end(ssh)) != 0) |
fatal("%s: parse packet: %s", __func__, ssh_err(r)); |
fatal_fr(r, "parse packet"); |
/* XXX check permission */ |
/* XXX check permission */ |
/* XXX range check originator port? */ |
/* XXX range check originator port? */ |
debug("client_request_x11: request from %s %u", originator, |
debug("client_request_x11: request from %s %u", originator, |
|
|
} |
} |
if (r != 0) { |
if (r != 0) { |
if (r != SSH_ERR_AGENT_NOT_PRESENT) |
if (r != SSH_ERR_AGENT_NOT_PRESENT) |
debug("%s: ssh_get_authentication_socket: %s", |
debug_fr(r, "ssh_get_authentication_socket"); |
__func__, ssh_err(r)); |
|
return NULL; |
return NULL; |
} |
} |
c = channel_new(ssh, "authentication agent connection", |
c = channel_new(ssh, "authentication agent connection", |
|
|
exit_status = exitval; |
exit_status = exitval; |
} else { |
} else { |
/* Probably for a mux channel that has already closed */ |
/* Probably for a mux channel that has already closed */ |
debug("%s: no sink for exit-status on channel %d", |
debug_f("no sink for exit-status on channel %d", |
__func__, id); |
id); |
} |
} |
if ((r = sshpkt_get_end(ssh)) != 0) |
if ((r = sshpkt_get_end(ssh)) != 0) |
goto out; |
goto out; |
} |
} |
if (reply && c != NULL && !(c->flags & CHAN_CLOSE_SENT)) { |
if (reply && c != NULL && !(c->flags & CHAN_CLOSE_SENT)) { |
if (!c->have_remote_id) |
if (!c->have_remote_id) |
fatal("%s: channel %d: no remote_id", |
fatal_f("channel %d: no remote_id", c->self); |
__func__, c->self); |
|
if ((r = sshpkt_start(ssh, success ? |
if ((r = sshpkt_start(ssh, success ? |
SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE)) != 0 || |
SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE)) != 0 || |
(r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || |
(r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || |
|
|
for (i = 0; i < ctx->nkeys; i++) { |
for (i = 0; i < ctx->nkeys; i++) { |
if (sshkey_equal(l->key, ctx->keys[i])) { |
if (sshkey_equal(l->key, ctx->keys[i])) { |
ctx->other_name_seen = 1; |
ctx->other_name_seen = 1; |
debug3("%s: found %s key under different " |
debug3_f("found %s key under different " |
"name/addr at %s:%ld", __func__, |
"name/addr at %s:%ld", |
sshkey_ssh_name(ctx->keys[i]), |
sshkey_ssh_name(ctx->keys[i]), |
l->path, l->linenum); |
l->path, l->linenum); |
return 0; |
return 0; |
|
|
/* Don't proceed if revocation or CA markers are present */ |
/* Don't proceed if revocation or CA markers are present */ |
/* XXX relax this */ |
/* XXX relax this */ |
if (l->marker != MRK_NONE) { |
if (l->marker != MRK_NONE) { |
debug3("%s: hostkeys file %s:%ld has CA/revocation marker", |
debug3_f("hostkeys file %s:%ld has CA/revocation marker", |
__func__, l->path, l->linenum); |
l->path, l->linenum); |
ctx->complex_hostspec = 1; |
ctx->complex_hostspec = 1; |
return 0; |
return 0; |
} |
} |
|
|
if (ctx->ip_str != NULL && (l->match & HKF_MATCH_HOST) == 0 && |
if (ctx->ip_str != NULL && (l->match & HKF_MATCH_HOST) == 0 && |
strchr(l->hosts, ',') != NULL) { |
strchr(l->hosts, ',') != NULL) { |
ctx->other_name_seen = 1; |
ctx->other_name_seen = 1; |
debug3("%s: found address %s against different hostname at " |
debug3_f("found address %s against different hostname at " |
"%s:%ld", __func__, ctx->ip_str, l->path, l->linenum); |
"%s:%ld", ctx->ip_str, l->path, l->linenum); |
return 0; |
return 0; |
} |
} |
|
|
|
|
* that contain more than two entries (ssh never writes these). |
* that contain more than two entries (ssh never writes these). |
*/ |
*/ |
if (hostspec_is_complex(l->hosts)) { |
if (hostspec_is_complex(l->hosts)) { |
debug3("%s: hostkeys file %s:%ld complex host specification", |
debug3_f("hostkeys file %s:%ld complex host specification", |
__func__, l->path, l->linenum); |
l->path, l->linenum); |
ctx->complex_hostspec = 1; |
ctx->complex_hostspec = 1; |
return 0; |
return 0; |
} |
} |
|
|
for (i = 0; i < ctx->nkeys; i++) { |
for (i = 0; i < ctx->nkeys; i++) { |
if (!sshkey_equal(l->key, ctx->keys[i])) |
if (!sshkey_equal(l->key, ctx->keys[i])) |
continue; |
continue; |
debug3("%s: found %s key at %s:%ld", __func__, |
debug3_f("found %s key at %s:%ld", |
sshkey_ssh_name(ctx->keys[i]), l->path, l->linenum); |
sshkey_ssh_name(ctx->keys[i]), l->path, l->linenum); |
ctx->keys_match[i] |= l->match; |
ctx->keys_match[i] |= l->match; |
return 0; |
return 0; |
} |
} |
/* This line contained a key that not offered by the server */ |
/* This line contained a key that not offered by the server */ |
debug3("%s: deprecated %s key at %s:%ld", __func__, |
debug3_f("deprecated %s key at %s:%ld", sshkey_ssh_name(l->key), |
sshkey_ssh_name(l->key), l->path, l->linenum); |
l->path, l->linenum); |
if ((tmp = recallocarray(ctx->old_keys, ctx->nold, ctx->nold + 1, |
if ((tmp = recallocarray(ctx->old_keys, ctx->nold, ctx->nold + 1, |
sizeof(*ctx->old_keys))) == NULL) |
sizeof(*ctx->old_keys))) == NULL) |
fatal("%s: recallocarray failed nold = %zu", |
fatal_f("recallocarray failed nold = %zu", ctx->nold); |
__func__, ctx->nold); |
|
ctx->old_keys = tmp; |
ctx->old_keys = tmp; |
ctx->old_keys[ctx->nold++] = l->key; |
ctx->old_keys[ctx->nold++] = l->key; |
l->key = NULL; |
l->key = NULL; |
|
|
for (i = 0; i < ctx->nold; i++) { |
for (i = 0; i < ctx->nold; i++) { |
if (!sshkey_equal(l->key, ctx->old_keys[i])) |
if (!sshkey_equal(l->key, ctx->old_keys[i])) |
continue; |
continue; |
debug3("%s: found deprecated %s key at %s:%ld as %s", __func__, |
debug3_f("found deprecated %s key at %s:%ld as %s", |
sshkey_ssh_name(ctx->keys[i]), l->path, l->linenum, |
sshkey_ssh_name(ctx->keys[i]), l->path, l->linenum, |
hashed ? "[HASHED]" : l->hosts); |
hashed ? "[HASHED]" : l->hosts); |
ctx->old_key_seen = 1; |
ctx->old_key_seen = 1; |
|
|
size_t i; |
size_t i; |
int r; |
int r; |
|
|
debug2("%s: checking for %zu deprecated keys", __func__, ctx->nold); |
debug2_f("checking for %zu deprecated keys", ctx->nold); |
for (i = 0; i < options.num_user_hostfiles; i++) { |
for (i = 0; i < options.num_user_hostfiles; i++) { |
debug3("%s: searching %s for %s / %s", __func__, |
debug3_f("searching %s for %s / %s", |
options.user_hostfiles[i], ctx->host_str, |
options.user_hostfiles[i], ctx->host_str, |
ctx->ip_str ? ctx->ip_str : "(none)"); |
ctx->ip_str ? ctx->ip_str : "(none)"); |
if ((r = hostkeys_foreach(options.user_hostfiles[i], |
if ((r = hostkeys_foreach(options.user_hostfiles[i], |
hostkeys_check_old, ctx, ctx->host_str, ctx->ip_str, |
hostkeys_check_old, ctx, ctx->host_str, ctx->ip_str, |
HKF_WANT_PARSE_KEY)) != 0) { |
HKF_WANT_PARSE_KEY)) != 0) { |
if (r == SSH_ERR_SYSTEM_ERROR && errno == ENOENT) { |
if (r == SSH_ERR_SYSTEM_ERROR && errno == ENOENT) { |
debug("%s: hostkeys file %s does not exist", |
debug_f("hostkeys file %s does not exist", |
__func__, options.user_hostfiles[i]); |
options.user_hostfiles[i]); |
continue; |
continue; |
} |
} |
error("%s: hostkeys_foreach failed for %s: %s", |
error_fr(r, "hostkeys_foreach failed for %s", |
__func__, options.user_hostfiles[i], ssh_err(r)); |
options.user_hostfiles[i]); |
return -1; |
return -1; |
} |
} |
} |
} |
|
|
continue; |
continue; |
if ((fp = sshkey_fingerprint(ctx->keys[i], |
if ((fp = sshkey_fingerprint(ctx->keys[i], |
options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) |
options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) |
fatal("%s: sshkey_fingerprint failed", __func__); |
fatal_f("sshkey_fingerprint failed"); |
if (first && asking) |
if (first && asking) |
hostkey_change_preamble(loglevel); |
hostkey_change_preamble(loglevel); |
do_log2(loglevel, "Learned new hostkey: %s %s", |
do_log2(loglevel, "Learned new hostkey: %s %s", |
|
|
for (i = 0; i < ctx->nold; i++) { |
for (i = 0; i < ctx->nold; i++) { |
if ((fp = sshkey_fingerprint(ctx->old_keys[i], |
if ((fp = sshkey_fingerprint(ctx->old_keys[i], |
options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) |
options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) |
fatal("%s: sshkey_fingerprint failed", __func__); |
fatal_f("sshkey_fingerprint failed"); |
if (first && asking) |
if (first && asking) |
hostkey_change_preamble(loglevel); |
hostkey_change_preamble(loglevel); |
do_log2(loglevel, "Deprecating obsolete hostkey: %s %s", |
do_log2(loglevel, "Deprecating obsolete hostkey: %s %s", |
|
|
*/ |
*/ |
if (stat(options.user_hostfiles[i], &sb) != 0) { |
if (stat(options.user_hostfiles[i], &sb) != 0) { |
if (errno == ENOENT) { |
if (errno == ENOENT) { |
debug("%s: known hosts file %s does not exist", |
debug_f("known hosts file %s does not " |
__func__, strerror(errno)); |
"exist", options.user_hostfiles[i]); |
} else { |
} else { |
error("%s: known hosts file %s inaccessible", |
error_f("known hosts file %s " |
__func__, strerror(errno)); |
"inaccessible: %s", |
|
options.user_hostfiles[i], strerror(errno)); |
} |
} |
continue; |
continue; |
} |
} |
|
|
i == 0 ? ctx->keys : NULL, i == 0 ? ctx->nkeys : 0, |
i == 0 ? ctx->keys : NULL, i == 0 ? ctx->nkeys : 0, |
options.hash_known_hosts, 0, |
options.hash_known_hosts, 0, |
options.fingerprint_hash)) != 0) { |
options.fingerprint_hash)) != 0) { |
error("%s: hostfile_replace_entries failed for %s: %s", |
error_fr(r, "hostfile_replace_entries failed for %s", |
__func__, options.user_hostfiles[i], ssh_err(r)); |
options.user_hostfiles[i]); |
} |
} |
} |
} |
} |
} |
|
|
size_t siglen; |
size_t siglen; |
|
|
if (ctx->nnew == 0) |
if (ctx->nnew == 0) |
fatal("%s: ctx->nnew == 0", __func__); /* sanity */ |
fatal_f("ctx->nnew == 0"); /* sanity */ |
if (type != SSH2_MSG_REQUEST_SUCCESS) { |
if (type != SSH2_MSG_REQUEST_SUCCESS) { |
error("Server failed to confirm ownership of " |
error("Server failed to confirm ownership of " |
"private host keys"); |
"private host keys"); |
|
|
sshkey_type_from_name(ssh->kex->hostkey_alg)); |
sshkey_type_from_name(ssh->kex->hostkey_alg)); |
|
|
if ((signdata = sshbuf_new()) == NULL) |
if ((signdata = sshbuf_new()) == NULL) |
fatal("%s: sshbuf_new failed", __func__); |
fatal_f("sshbuf_new failed"); |
/* Don't want to accidentally accept an unbound signature */ |
/* Don't want to accidentally accept an unbound signature */ |
if (ssh->kex->session_id_len == 0) |
if (ssh->kex->session_id_len == 0) |
fatal("%s: ssh->kex->session_id_len == 0", __func__); |
fatal_f("ssh->kex->session_id_len == 0"); |
/* |
/* |
* Expect a signature for each of the ctx->nnew private keys we |
* Expect a signature for each of the ctx->nnew private keys we |
* haven't seen before. They will be in the same order as the |
* haven't seen before. They will be in the same order as the |
|
|
(r = sshbuf_put_string(signdata, ssh->kex->session_id, |
(r = sshbuf_put_string(signdata, ssh->kex->session_id, |
ssh->kex->session_id_len)) != 0 || |
ssh->kex->session_id_len)) != 0 || |
(r = sshkey_puts(ctx->keys[i], signdata)) != 0) |
(r = sshkey_puts(ctx->keys[i], signdata)) != 0) |
fatal("%s: failed to prepare signature: %s", |
fatal_fr(r, "compose signdata"); |
__func__, ssh_err(r)); |
|
/* Extract and verify signature */ |
/* Extract and verify signature */ |
if ((r = sshpkt_get_string_direct(ssh, &sig, &siglen)) != 0) { |
if ((r = sshpkt_get_string_direct(ssh, &sig, &siglen)) != 0) { |
error("%s: couldn't parse message: %s", |
error_fr(r, "parse sig"); |
__func__, ssh_err(r)); |
|
goto out; |
goto out; |
} |
} |
/* |
/* |
|
|
sshbuf_ptr(signdata), sshbuf_len(signdata), |
sshbuf_ptr(signdata), sshbuf_len(signdata), |
use_kexsigtype ? ssh->kex->hostkey_alg : NULL, 0, |
use_kexsigtype ? ssh->kex->hostkey_alg : NULL, 0, |
NULL)) != 0) { |
NULL)) != 0) { |
error("%s: server gave bad signature for %s key %zu", |
error_f("server gave bad signature for %s key %zu", |
__func__, sshkey_type(ctx->keys[i]), i); |
sshkey_type(ctx->keys[i]), i); |
goto out; |
goto out; |
} |
} |
/* Key is good. Mark it as 'seen' */ |
/* Key is good. Mark it as 'seen' */ |
ctx->keys_verified[i] = 1; |
ctx->keys_verified[i] = 1; |
ndone++; |
ndone++; |
} |
} |
|
/* Shouldn't happen */ |
if (ndone != ctx->nnew) |
if (ndone != ctx->nnew) |
fatal("%s: ndone != ctx->nnew (%zu / %zu)", __func__, |
fatal_f("ndone != ctx->nnew (%zu / %zu)", ndone, ctx->nnew); |
ndone, ctx->nnew); /* Shouldn't happen */ |
|
if ((r = sshpkt_get_end(ssh)) != 0) { |
if ((r = sshpkt_get_end(ssh)) != 0) { |
error("%s: protocol error", __func__); |
error_f("protocol error"); |
goto out; |
goto out; |
} |
} |
|
|
|
|
u_int want; |
u_int want; |
|
|
if (hostkeys_seen) |
if (hostkeys_seen) |
fatal("%s: server already sent hostkeys", __func__); |
fatal_f("server already sent hostkeys"); |
if (options.update_hostkeys == SSH_UPDATE_HOSTKEYS_ASK && |
if (options.update_hostkeys == SSH_UPDATE_HOSTKEYS_ASK && |
options.batch_mode) |
options.batch_mode) |
return 1; /* won't ask in batchmode, so don't even try */ |
return 1; /* won't ask in batchmode, so don't even try */ |
|
|
sshkey_free(key); |
sshkey_free(key); |
key = NULL; |
key = NULL; |
if ((r = sshpkt_get_string_direct(ssh, &blob, &len)) != 0) { |
if ((r = sshpkt_get_string_direct(ssh, &blob, &len)) != 0) { |
error("%s: couldn't parse message: %s", |
error_fr(r, "parse key"); |
__func__, ssh_err(r)); |
|
goto out; |
goto out; |
} |
} |
if ((r = sshkey_from_blob(blob, len, &key)) != 0) { |
if ((r = sshkey_from_blob(blob, len, &key)) != 0) { |
do_log2(r == SSH_ERR_KEY_TYPE_UNKNOWN ? |
do_log2_fr(r, r == SSH_ERR_KEY_TYPE_UNKNOWN ? |
SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_ERROR, |
SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_ERROR, |
"%s: parse key: %s", __func__, ssh_err(r)); |
"convert key"); |
continue; |
continue; |
} |
} |
fp = sshkey_fingerprint(key, options.fingerprint_hash, |
fp = sshkey_fingerprint(key, options.fingerprint_hash, |
SSH_FP_DEFAULT); |
SSH_FP_DEFAULT); |
debug3("%s: received %s key %s", __func__, |
debug3_f("received %s key %s", sshkey_type(key), fp); |
sshkey_type(key), fp); |
|
free(fp); |
free(fp); |
|
|
if (!key_accepted_by_hostkeyalgs(key)) { |
if (!key_accepted_by_hostkeyalgs(key)) { |
debug3("%s: %s key not permitted by HostkeyAlgorithms", |
debug3_f("%s key not permitted by " |
__func__, sshkey_ssh_name(key)); |
"HostkeyAlgorithms", sshkey_ssh_name(key)); |
continue; |
continue; |
} |
} |
/* Skip certs */ |
/* Skip certs */ |
if (sshkey_is_cert(key)) { |
if (sshkey_is_cert(key)) { |
debug3("%s: %s key is a certificate; skipping", |
debug3_f("%s key is a certificate; skipping", |
__func__, sshkey_ssh_name(key)); |
sshkey_ssh_name(key)); |
continue; |
continue; |
} |
} |
/* Ensure keys are unique */ |
/* Ensure keys are unique */ |
for (i = 0; i < ctx->nkeys; i++) { |
for (i = 0; i < ctx->nkeys; i++) { |
if (sshkey_equal(key, ctx->keys[i])) { |
if (sshkey_equal(key, ctx->keys[i])) { |
error("%s: received duplicated %s host key", |
error_f("received duplicated %s host key", |
__func__, sshkey_ssh_name(key)); |
sshkey_ssh_name(key)); |
goto out; |
goto out; |
} |
} |
} |
} |
/* Key is good, record it */ |
/* Key is good, record it */ |
if ((tmp = recallocarray(ctx->keys, ctx->nkeys, ctx->nkeys + 1, |
if ((tmp = recallocarray(ctx->keys, ctx->nkeys, ctx->nkeys + 1, |
sizeof(*ctx->keys))) == NULL) |
sizeof(*ctx->keys))) == NULL) |
fatal("%s: recallocarray failed nkeys = %zu", |
fatal_f("recallocarray failed nkeys = %zu", |
__func__, ctx->nkeys); |
ctx->nkeys); |
ctx->keys = tmp; |
ctx->keys = tmp; |
ctx->keys[ctx->nkeys++] = key; |
ctx->keys[ctx->nkeys++] = key; |
key = NULL; |
key = NULL; |
} |
} |
|
|
if (ctx->nkeys == 0) { |
if (ctx->nkeys == 0) { |
debug("%s: server sent no hostkeys", __func__); |
debug_f("server sent no hostkeys"); |
goto out; |
goto out; |
} |
} |
|
|
|
|
sizeof(*ctx->keys_match))) == NULL || |
sizeof(*ctx->keys_match))) == NULL || |
(ctx->keys_verified = calloc(ctx->nkeys, |
(ctx->keys_verified = calloc(ctx->nkeys, |
sizeof(*ctx->keys_verified))) == NULL) |
sizeof(*ctx->keys_verified))) == NULL) |
fatal("%s: calloc failed", __func__); |
fatal_f("calloc failed"); |
|
|
get_hostfile_hostname_ipaddr(host, |
get_hostfile_hostname_ipaddr(host, |
options.check_host_ip ? (struct sockaddr *)&hostaddr : NULL, |
options.check_host_ip ? (struct sockaddr *)&hostaddr : NULL, |
|
|
|
|
/* Find which keys we already know about. */ |
/* Find which keys we already know about. */ |
for (i = 0; i < options.num_user_hostfiles; i++) { |
for (i = 0; i < options.num_user_hostfiles; i++) { |
debug("%s: searching %s for %s / %s", __func__, |
debug_f("searching %s for %s / %s", |
options.user_hostfiles[i], ctx->host_str, |
options.user_hostfiles[i], ctx->host_str, |
ctx->ip_str ? ctx->ip_str : "(none)"); |
ctx->ip_str ? ctx->ip_str : "(none)"); |
if ((r = hostkeys_foreach(options.user_hostfiles[i], |
if ((r = hostkeys_foreach(options.user_hostfiles[i], |
hostkeys_find, ctx, ctx->host_str, ctx->ip_str, |
hostkeys_find, ctx, ctx->host_str, ctx->ip_str, |
HKF_WANT_PARSE_KEY|HKF_WANT_MATCH)) != 0) { |
HKF_WANT_PARSE_KEY|HKF_WANT_MATCH)) != 0) { |
if (r == SSH_ERR_SYSTEM_ERROR && errno == ENOENT) { |
if (r == SSH_ERR_SYSTEM_ERROR && errno == ENOENT) { |
debug("%s: hostkeys file %s does not exist", |
debug_f("hostkeys file %s does not exist", |
__func__, options.user_hostfiles[i]); |
options.user_hostfiles[i]); |
continue; |
continue; |
} |
} |
error("%s: hostkeys_foreach failed for %s: %s", |
error_fr(r, "hostkeys_foreach failed for %s", |
__func__, options.user_hostfiles[i], ssh_err(r)); |
options.user_hostfiles[i]); |
goto out; |
goto out; |
} |
} |
} |
} |
|
|
ctx->nincomplete++; |
ctx->nincomplete++; |
} |
} |
|
|
debug3("%s: %zu server keys: %zu new, %zu retained, " |
debug3_f("%zu server keys: %zu new, %zu retained, " |
"%zu incomplete match. %zu to remove", __func__, ctx->nkeys, |
"%zu incomplete match. %zu to remove", ctx->nkeys, ctx->nnew, |
ctx->nnew, ctx->nkeys - ctx->nnew - ctx->nincomplete, |
ctx->nkeys - ctx->nnew - ctx->nincomplete, |
ctx->nincomplete, ctx->nold); |
ctx->nincomplete, ctx->nold); |
|
|
if (ctx->nnew == 0 && ctx->nold == 0) { |
if (ctx->nnew == 0 && ctx->nold == 0) { |
debug("%s: no new or deprecated keys from server", __func__); |
debug_f("no new or deprecated keys from server"); |
goto out; |
goto out; |
} |
} |
|
|
/* Various reasons why we cannot proceed with the update */ |
/* Various reasons why we cannot proceed with the update */ |
if (ctx->complex_hostspec) { |
if (ctx->complex_hostspec) { |
debug("%s: CA/revocation marker, manual host list or wildcard " |
debug_f("CA/revocation marker, manual host list or wildcard " |
"host pattern found, skipping UserKnownHostsFile update", |
"host pattern found, skipping UserKnownHostsFile update"); |
__func__); |
|
goto out; |
goto out; |
} |
} |
if (ctx->other_name_seen) { |
if (ctx->other_name_seen) { |
debug("%s: host key found matching a different name/address, " |
debug_f("host key found matching a different name/address, " |
"skipping UserKnownHostsFile update", __func__); |
"skipping UserKnownHostsFile update"); |
goto out; |
goto out; |
} |
} |
/* |
/* |
|
|
if (check_old_keys_othernames(ctx) != 0) |
if (check_old_keys_othernames(ctx) != 0) |
goto out; /* error already logged */ |
goto out; /* error already logged */ |
if (ctx->old_key_seen) { |
if (ctx->old_key_seen) { |
debug("%s: key(s) for %s%s%s exist under other names; " |
debug_f("key(s) for %s%s%s exist under other names; " |
"skipping UserKnownHostsFile update", __func__, |
"skipping UserKnownHostsFile update", |
ctx->host_str, ctx->ip_str == NULL ? "" : ",", |
ctx->host_str, ctx->ip_str == NULL ? "" : ",", |
ctx->ip_str == NULL ? "" : ctx->ip_str); |
ctx->ip_str == NULL ? "" : ctx->ip_str); |
goto out; |
goto out; |
|
|
* We have received previously-unseen keys from the server. |
* We have received previously-unseen keys from the server. |
* Ask the server to confirm ownership of the private halves. |
* Ask the server to confirm ownership of the private halves. |
*/ |
*/ |
debug3("%s: asking server to prove ownership for %zu keys", |
debug3_f("asking server to prove ownership for %zu keys", ctx->nnew); |
__func__, ctx->nnew); |
|
if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 || |
if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 || |
(r = sshpkt_put_cstring(ssh, |
(r = sshpkt_put_cstring(ssh, |
"hostkeys-prove-00@openssh.com")) != 0 || |
"hostkeys-prove-00@openssh.com")) != 0 || |
(r = sshpkt_put_u8(ssh, 1)) != 0) /* bool: want reply */ |
(r = sshpkt_put_u8(ssh, 1)) != 0) /* bool: want reply */ |
fatal("%s: prepare hostkeys-prove: %s", __func__, ssh_err(r)); |
fatal_fr(r, "prepare hostkeys-prove"); |
if ((buf = sshbuf_new()) == NULL) |
if ((buf = sshbuf_new()) == NULL) |
fatal("%s: sshbuf_new", __func__); |
fatal_f("sshbuf_new"); |
for (i = 0; i < ctx->nkeys; i++) { |
for (i = 0; i < ctx->nkeys; i++) { |
if (ctx->keys_match[i]) |
if (ctx->keys_match[i]) |
continue; |
continue; |
sshbuf_reset(buf); |
sshbuf_reset(buf); |
if ((r = sshkey_putb(ctx->keys[i], buf)) != 0 || |
if ((r = sshkey_putb(ctx->keys[i], buf)) != 0 || |
(r = sshpkt_put_stringb(ssh, buf)) != 0) { |
(r = sshpkt_put_stringb(ssh, buf)) != 0) |
fatal("%s: assemble hostkeys-prove: %s", |
fatal_fr(r, "assemble hostkeys-prove"); |
__func__, ssh_err(r)); |
|
} |
|
} |
} |
if ((r = sshpkt_send(ssh)) != 0) |
if ((r = sshpkt_send(ssh)) != 0) |
fatal("%s: sshpkt_send: %s", __func__, ssh_err(r)); |
fatal_fr(r, "send hostkeys-prove"); |
client_register_global_confirm( |
client_register_global_confirm( |
client_global_hostkeys_private_confirm, ctx); |
client_global_hostkeys_private_confirm, ctx); |
ctx = NULL; /* will be freed in callback */ |
ctx = NULL; /* will be freed in callback */ |
|
|
return r; |
return r; |
} |
} |
|
|
|
static void |
|
client_send_env(struct ssh *ssh, int id, const char *name, const char *val) |
|
{ |
|
int r; |
|
|
|
debug("channel %d: setting env %s = \"%s\"", id, name, val); |
|
channel_request_start(ssh, id, "env", 0); |
|
if ((r = sshpkt_put_cstring(ssh, name)) != 0 || |
|
(r = sshpkt_put_cstring(ssh, val)) != 0 || |
|
(r = sshpkt_send(ssh)) != 0) |
|
fatal_fr(r, "send setenv"); |
|
} |
|
|
void |
void |
client_session2_setup(struct ssh *ssh, int id, int want_tty, int want_subsystem, |
client_session2_setup(struct ssh *ssh, int id, int want_tty, int want_subsystem, |
const char *term, struct termios *tiop, int in_fd, struct sshbuf *cmd, |
const char *term, struct termios *tiop, int in_fd, struct sshbuf *cmd, |
|
|
char *name, *val; |
char *name, *val; |
Channel *c = NULL; |
Channel *c = NULL; |
|
|
debug2("%s: id %d", __func__, id); |
debug2_f("id %d", id); |
|
|
if ((c = channel_lookup(ssh, id)) == NULL) |
if ((c = channel_lookup(ssh, id)) == NULL) |
fatal("%s: channel %d: unknown channel", __func__, id); |
fatal_f("channel %d: unknown channel", id); |
|
|
ssh_packet_set_interactive(ssh, want_tty, |
ssh_packet_set_interactive(ssh, want_tty, |
options.ip_qos_interactive, options.ip_qos_bulk); |
options.ip_qos_interactive, options.ip_qos_bulk); |
|
|
(r = sshpkt_put_u32(ssh, (u_int)ws.ws_row)) != 0 || |
(r = sshpkt_put_u32(ssh, (u_int)ws.ws_row)) != 0 || |
(r = sshpkt_put_u32(ssh, (u_int)ws.ws_xpixel)) != 0 || |
(r = sshpkt_put_u32(ssh, (u_int)ws.ws_xpixel)) != 0 || |
(r = sshpkt_put_u32(ssh, (u_int)ws.ws_ypixel)) != 0) |
(r = sshpkt_put_u32(ssh, (u_int)ws.ws_ypixel)) != 0) |
fatal("%s: build packet: %s", __func__, ssh_err(r)); |
fatal_fr(r, "build pty-req"); |
if (tiop == NULL) |
if (tiop == NULL) |
tiop = get_saved_tio(); |
tiop = get_saved_tio(); |
ssh_tty_make_modes(ssh, -1, tiop); |
ssh_tty_make_modes(ssh, -1, tiop); |
if ((r = sshpkt_send(ssh)) != 0) |
if ((r = sshpkt_send(ssh)) != 0) |
fatal("%s: send packet: %s", __func__, ssh_err(r)); |
fatal_fr(r, "send pty-req"); |
/* XXX wait for reply */ |
/* XXX wait for reply */ |
c->client_tty = 1; |
c->client_tty = 1; |
} |
} |
|
|
free(name); |
free(name); |
continue; |
continue; |
} |
} |
|
client_send_env(ssh, id, name, val); |
debug("Sending env %s = %s", name, val); |
|
channel_request_start(ssh, id, "env", 0); |
|
if ((r = sshpkt_put_cstring(ssh, name)) != 0 || |
|
(r = sshpkt_put_cstring(ssh, val)) != 0 || |
|
(r = sshpkt_send(ssh)) != 0) { |
|
fatal("%s: send packet: %s", |
|
__func__, ssh_err(r)); |
|
} |
|
free(name); |
free(name); |
} |
} |
} |
} |
|
|
continue; |
continue; |
} |
} |
*val++ = '\0'; |
*val++ = '\0'; |
|
client_send_env(ssh, id, name, val); |
debug("Setting env %s = %s", name, val); |
|
channel_request_start(ssh, id, "env", 0); |
|
if ((r = sshpkt_put_cstring(ssh, name)) != 0 || |
|
(r = sshpkt_put_cstring(ssh, val)) != 0 || |
|
(r = sshpkt_send(ssh)) != 0) |
|
fatal("%s: send packet: %s", __func__, ssh_err(r)); |
|
free(name); |
free(name); |
} |
} |
|
|
|
|
} |
} |
if ((r = sshpkt_put_stringb(ssh, cmd)) != 0 || |
if ((r = sshpkt_put_stringb(ssh, cmd)) != 0 || |
(r = sshpkt_send(ssh)) != 0) |
(r = sshpkt_send(ssh)) != 0) |
fatal("%s: send command: %s", __func__, ssh_err(r)); |
fatal_fr(r, "send command"); |
} else { |
} else { |
channel_request_start(ssh, id, "shell", 1); |
channel_request_start(ssh, id, "shell", 1); |
client_expect_confirm(ssh, id, "shell", CONFIRM_CLOSE); |
client_expect_confirm(ssh, id, "shell", CONFIRM_CLOSE); |
if ((r = sshpkt_send(ssh)) != 0) { |
if ((r = sshpkt_send(ssh)) != 0) |
fatal("%s: send shell request: %s", |
fatal_fr(r, "send shell"); |
__func__, ssh_err(r)); |
|
} |
|
} |
} |
} |
} |
|
|