version 1.383, 2022/11/28 01:37:36 |
version 1.384, 2022/11/28 01:38:22 |
|
|
static int session_closed; /* In SSH2: login session closed. */ |
static int session_closed; /* In SSH2: login session closed. */ |
static u_int x11_refuse_time; /* If >0, refuse x11 opens after this time. */ |
static u_int x11_refuse_time; /* If >0, refuse x11 opens after this time. */ |
static time_t server_alive_time; /* Time to do server_alive_check */ |
static time_t server_alive_time; /* Time to do server_alive_check */ |
|
static int hostkeys_update_complete; |
|
static int session_setup_complete; |
|
|
static void client_init_dispatch(struct ssh *ssh); |
static void client_init_dispatch(struct ssh *ssh); |
int session_ident = -1; |
int session_ident = -1; |
|
|
TAILQ_INSERT_TAIL(&global_confirms, gc, entry); |
TAILQ_INSERT_TAIL(&global_confirms, gc, entry); |
} |
} |
|
|
|
/* |
|
* Returns non-zero if the client is able to handle a hostkeys-00@openssh.com |
|
* hostkey update request. |
|
*/ |
|
static int |
|
can_update_hostkeys(void) |
|
{ |
|
if (hostkeys_update_complete) |
|
return 0; |
|
if (options.update_hostkeys == SSH_UPDATE_HOSTKEYS_ASK && |
|
options.batch_mode) |
|
return 0; /* won't ask in batchmode, so don't even try */ |
|
if (!options.update_hostkeys || options.num_user_hostfiles <= 0) |
|
return 0; |
|
return 1; |
|
} |
|
|
|
void |
|
client_repledge() |
|
{ |
|
debug3_f("enter"); |
|
|
|
/* Might be able to tighten pledge now that session is established */ |
|
if (options.control_master || options.control_path != NULL || |
|
options.forward_x11 || options.fork_after_authentication || |
|
can_update_hostkeys() || |
|
(session_ident != -1 && !session_setup_complete)) { |
|
/* Can't tighten */ |
|
return; |
|
} |
|
/* |
|
* LocalCommand and UpdateHostkeys have finished, so can get rid of |
|
* filesystem. |
|
* |
|
* XXX protocol allows a server can to change hostkeys during the |
|
* connection at rekey time that could trigger a hostkeys update |
|
* but AFAIK no implementations support this. Could improve by |
|
* forcing known_hosts to be read-only or via unveil(2). |
|
*/ |
|
if (options.num_local_forwards != 0 || |
|
options.num_remote_forwards != 0 || |
|
options.num_permitted_remote_opens != 0 || |
|
options.enable_escape_commandline != 0) { |
|
/* rfwd needs inet */ |
|
debug("pledge: network"); |
|
if (pledge("stdio unix inet dns proc tty", NULL) == -1) |
|
fatal_f("pledge(): %s", strerror(errno)); |
|
} else if (options.forward_agent != 0) { |
|
/* agent forwarding needs to open $SSH_AUTH_SOCK at will */ |
|
debug("pledge: agent"); |
|
if (pledge("stdio unix proc tty", NULL) == -1) |
|
fatal_f("pledge(): %s", strerror(errno)); |
|
} else { |
|
debug("pledge: fork"); |
|
if (pledge("stdio proc tty", NULL) == -1) |
|
fatal_f("pledge(): %s", strerror(errno)); |
|
} |
|
/* XXX further things to do: |
|
* |
|
* - might be able to get rid of proc if we kill ~^Z |
|
* - ssh -N (no session) |
|
* - stdio forwarding |
|
* - sessions without tty |
|
*/ |
|
} |
|
|
static void |
static void |
process_cmdline(struct ssh *ssh) |
process_cmdline(struct ssh *ssh) |
{ |
{ |
|
|
int conn_in_ready, conn_out_ready; |
int conn_in_ready, conn_out_ready; |
|
|
debug("Entering interactive session."); |
debug("Entering interactive session."); |
|
session_ident = ssh2_chan_id; |
|
|
if (options.control_master && |
if (options.control_master && |
!option_clear_or_none(options.control_path)) { |
!option_clear_or_none(options.control_path)) { |
|
|
fatal_f("pledge(): %s", strerror(errno)); |
fatal_f("pledge(): %s", strerror(errno)); |
} |
} |
|
|
|
/* might be able to tighten now */ |
|
client_repledge(); |
|
|
start_time = monotime_double(); |
start_time = monotime_double(); |
|
|
/* Initialize variables. */ |
/* Initialize variables. */ |
|
|
if (have_pty) |
if (have_pty) |
enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE); |
enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE); |
|
|
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(ssh, session_ident, |
channel_register_filter(ssh, session_ident, |
|
|
update_known_hosts(ctx); |
update_known_hosts(ctx); |
out: |
out: |
hostkeys_update_ctx_free(ctx); |
hostkeys_update_ctx_free(ctx); |
|
hostkeys_update_complete = 1; |
|
client_repledge(); |
} |
} |
|
|
/* |
/* |
|
|
size_t i, len = 0; |
size_t i, len = 0; |
struct sshbuf *buf = NULL; |
struct sshbuf *buf = NULL; |
struct sshkey *key = NULL, **tmp; |
struct sshkey *key = NULL, **tmp; |
int r; |
int r, prove_sent = 0; |
char *fp; |
char *fp; |
static int hostkeys_seen = 0; /* XXX use struct ssh */ |
static int hostkeys_seen = 0; /* XXX use struct ssh */ |
extern struct sockaddr_storage hostaddr; /* XXX from ssh.c */ |
extern struct sockaddr_storage hostaddr; /* XXX from ssh.c */ |
|
|
|
|
if (hostkeys_seen) |
if (hostkeys_seen) |
fatal_f("server already sent hostkeys"); |
fatal_f("server already sent hostkeys"); |
if (options.update_hostkeys == SSH_UPDATE_HOSTKEYS_ASK && |
if (!can_update_hostkeys()) |
options.batch_mode) |
|
return 1; /* won't ask in batchmode, so don't even try */ |
|
if (!options.update_hostkeys || options.num_user_hostfiles <= 0) |
|
return 1; |
return 1; |
|
hostkeys_seen = 1; |
|
|
ctx = xcalloc(1, sizeof(*ctx)); |
ctx = xcalloc(1, sizeof(*ctx)); |
while (ssh_packet_remaining(ssh) > 0) { |
while (ssh_packet_remaining(ssh) > 0) { |
|
|
client_register_global_confirm( |
client_register_global_confirm( |
client_global_hostkeys_prove_confirm, ctx); |
client_global_hostkeys_prove_confirm, ctx); |
ctx = NULL; /* will be freed in callback */ |
ctx = NULL; /* will be freed in callback */ |
|
prove_sent = 1; |
|
|
/* Success */ |
/* Success */ |
out: |
out: |
hostkeys_update_ctx_free(ctx); |
hostkeys_update_ctx_free(ctx); |
sshkey_free(key); |
sshkey_free(key); |
sshbuf_free(buf); |
sshbuf_free(buf); |
|
if (!prove_sent) { |
|
/* UpdateHostkeys handling completed */ |
|
hostkeys_update_complete = 1; |
|
client_repledge(); |
|
} |
/* |
/* |
* NB. Return success for all cases. The server doesn't need to know |
* NB. Return success for all cases. The server doesn't need to know |
* what the client does with its hosts file. |
* what the client does with its hosts file. |
|
|
if ((r = sshpkt_send(ssh)) != 0) |
if ((r = sshpkt_send(ssh)) != 0) |
fatal_fr(r, "send shell"); |
fatal_fr(r, "send shell"); |
} |
} |
|
|
|
session_setup_complete = 1; |
|
client_repledge(); |
} |
} |
|
|
static void |
static void |