*/
#include "includes.h"
-RCSID("$OpenBSD: clientloop.c,v 1.126 2004/06/17 14:52:48 djm Exp $");
+RCSID("$OpenBSD: clientloop.c,v 1.136 2005/03/10 22:01:05 deraadt Exp $");
#include "ssh.h"
#include "ssh1.h"
*/
static void
client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp,
- int *maxfdp, int *nallocp, int rekeying)
+ int *maxfdp, u_int *nallocp, int rekeying)
{
struct timeval tv, *tvp;
int ret;
if (options.server_alive_interval == 0 || !compat20)
tvp = NULL;
- else {
+ else {
tv.tv_sec = options.server_alive_interval;
tv.tv_usec = 0;
tvp = &tv;
static void
client_suspend_self(Buffer *bin, Buffer *bout, Buffer *berr)
{
- struct winsize oldws, newws;
-
/* Flush stdout and stderr buffers. */
if (buffer_len(bout) > 0)
atomicio(vwrite, fileno(stdout), buffer_ptr(bout), buffer_len(bout));
buffer_free(bout);
buffer_free(berr);
- /* Save old window size. */
- ioctl(fileno(stdin), TIOCGWINSZ, &oldws);
-
/* Send the suspend signal to the program itself. */
kill(getpid(), SIGTSTP);
- /* Check if the window size has changed. */
- if (ioctl(fileno(stdin), TIOCGWINSZ, &newws) >= 0 &&
- (oldws.ws_row != newws.ws_row ||
- oldws.ws_col != newws.ws_col ||
- oldws.ws_xpixel != newws.ws_xpixel ||
- oldws.ws_ypixel != newws.ws_ypixel))
- received_window_change_signal = 1;
+ /* Reset window sizes in case they have changed */
+ received_window_change_signal = 1;
/* OK, we have been continued by the user. Reinitialize buffers. */
buffer_init(bin);
{
int id;
Channel *c;
-
+
id = packet_get_int();
packet_check_eom();
struct confirm_ctx *cctx = arg;
Channel *c;
int i;
-
+
if (cctx == NULL)
fatal("%s: cctx == NULL", __func__);
if ((c = channel_lookup(id)) == NULL)
fatal("%s: no channel for id %d", __func__, id);
- client_session2_setup(id, cctx->want_tty, cctx->want_subsys,
+ client_session2_setup(id, cctx->want_tty, cctx->want_subsys,
cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env,
client_subsystem_reply);
-
+
c->confirm_ctx = NULL;
buffer_free(&cctx->cmd);
xfree(cctx->term);
for (i = 0; cctx->env[i] != NULL; i++)
xfree(cctx->env[i]);
xfree(cctx->env);
- }
+ }
xfree(cctx);
}
{
Buffer m;
Channel *c;
- int client_fd, new_fd[3], ver, i;
+ int client_fd, new_fd[3], ver, i, allowed;
socklen_t addrlen;
struct sockaddr_storage addr;
struct confirm_ctx *cctx;
char *cmd;
- u_int len, env_len;
+ u_int len, env_len, command, flags;
uid_t euid;
gid_t egid;
close(client_fd);
return;
}
- /* XXX: implement use of ssh-askpass to confirm additional channels */
unset_nonblock(client_fd);
+ /* Read command */
buffer_init(&m);
+ if (ssh_msg_recv(client_fd, &m) == -1) {
+ error("%s: client msg_recv failed", __func__);
+ close(client_fd);
+ buffer_free(&m);
+ return;
+ }
+ if ((ver = buffer_get_char(&m)) != 1) {
+ error("%s: wrong client version %d", __func__, ver);
+ buffer_free(&m);
+ close(client_fd);
+ return;
+ }
+
+ allowed = 1;
+ command = buffer_get_int(&m);
+ flags = buffer_get_int(&m);
+
+ buffer_clear(&m);
+ switch (command) {
+ case SSHMUX_COMMAND_OPEN:
+ if (options.control_master == 2)
+ allowed = ask_permission("Allow shared connection "
+ "to %s? ", host);
+ /* continue below */
+ break;
+ case SSHMUX_COMMAND_TERMINATE:
+ if (options.control_master == 2)
+ allowed = ask_permission("Terminate shared connection "
+ "to %s? ", host);
+ if (allowed)
+ quit_pending = 1;
+ /* FALLTHROUGH */
+ case SSHMUX_COMMAND_ALIVE_CHECK:
+ /* Reply for SSHMUX_COMMAND_TERMINATE and ALIVE_CHECK */
+ buffer_clear(&m);
+ buffer_put_int(&m, allowed);
+ buffer_put_int(&m, getpid());
+ if (ssh_msg_send(client_fd, /* version */1, &m) == -1) {
+ error("%s: client msg_send failed", __func__);
+ close(client_fd);
+ buffer_free(&m);
+ return;
+ }
+ buffer_free(&m);
+ close(client_fd);
+ return;
+ default:
+ error("Unsupported command %d", command);
+ buffer_free(&m);
+ close(client_fd);
+ return;
+ }
+
+ /* Reply for SSHMUX_COMMAND_OPEN */
+ buffer_clear(&m);
+ buffer_put_int(&m, allowed);
buffer_put_int(&m, getpid());
- if (ssh_msg_send(client_fd, /* version */0, &m) == -1) {
+ if (ssh_msg_send(client_fd, /* version */1, &m) == -1) {
error("%s: client msg_send failed", __func__);
close(client_fd);
+ buffer_free(&m);
return;
}
- buffer_clear(&m);
+ if (!allowed) {
+ error("Refused control connection");
+ close(client_fd);
+ buffer_free(&m);
+ return;
+ }
+
+ buffer_clear(&m);
if (ssh_msg_recv(client_fd, &m) == -1) {
error("%s: client msg_recv failed", __func__);
close(client_fd);
+ buffer_free(&m);
return;
}
-
- if ((ver = buffer_get_char(&m)) != 0) {
+ if ((ver = buffer_get_char(&m)) != 1) {
error("%s: wrong client version %d", __func__, ver);
buffer_free(&m);
close(client_fd);
cctx = xmalloc(sizeof(*cctx));
memset(cctx, 0, sizeof(*cctx));
-
- cctx->want_tty = buffer_get_int(&m);
- cctx->want_subsys = buffer_get_int(&m);
+ cctx->want_tty = (flags & SSHMUX_FLAG_TTY) != 0;
+ cctx->want_subsys = (flags & SSHMUX_FLAG_SUBSYS) != 0;
cctx->term = buffer_get_string(&m, &len);
cmd = buffer_get_string(&m, &len);
if (cctx->want_tty && tcgetattr(new_fd[0], &cctx->tio) == -1)
error("%s: tcgetattr: %s", __func__, strerror(errno));
+ /* This roundtrip is just for synchronisation of ttymodes */
buffer_clear(&m);
- if (ssh_msg_send(client_fd, /* version */0, &m) == -1) {
+ if (ssh_msg_send(client_fd, /* version */1, &m) == -1) {
error("%s: client msg_send failed", __func__);
close(client_fd);
close(new_fd[0]);
close(new_fd[1]);
close(new_fd[2]);
+ buffer_free(&m);
+ xfree(cctx->term);
+ if (env_len != 0) {
+ for (i = 0; i < env_len; i++)
+ xfree(cctx->env[i]);
+ xfree(cctx->env);
+ }
return;
}
buffer_free(&m);
set_nonblock(client_fd);
- c = channel_new("session", SSH_CHANNEL_OPENING,
+ c = channel_new("session", SSH_CHANNEL_OPENING,
new_fd[0], new_fd[1], new_fd[2],
CHAN_SES_WINDOW_DEFAULT, CHAN_SES_PACKET_DEFAULT,
CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0);
process_cmdline(void)
{
void (*handler)(int);
- char *s, *cmd;
- u_short fwd_port, fwd_host_port;
- char buf[1024], sfwd_port[6], sfwd_host_port[6];
+ char *s, *cmd, *cancel_host;
int delete = 0;
int local = 0;
+ u_short cancel_port;
+ Forward fwd;
leave_raw_mode();
handler = signal(SIGINT, SIG_IGN);
s++;
if (delete) {
- if (sscanf(s, "%5[0-9]", sfwd_host_port) != 1) {
- logit("Bad forwarding specification.");
- goto out;
+ cancel_port = 0;
+ cancel_host = hpdelim(&s); /* may be NULL */
+ if (s != NULL) {
+ cancel_port = a2port(s);
+ cancel_host = cleanhostname(cancel_host);
+ } else {
+ cancel_port = a2port(cancel_host);
+ cancel_host = NULL;
}
- if ((fwd_host_port = a2port(sfwd_host_port)) == 0) {
- logit("Bad forwarding port(s).");
+ if (cancel_port == 0) {
+ logit("Bad forwarding close port");
goto out;
}
- channel_request_rforward_cancel(fwd_host_port);
+ channel_request_rforward_cancel(cancel_host, cancel_port);
} else {
- if (sscanf(s, "%5[0-9]:%255[^:]:%5[0-9]",
- sfwd_port, buf, sfwd_host_port) != 3 &&
- sscanf(s, "%5[0-9]/%255[^/]/%5[0-9]",
- sfwd_port, buf, sfwd_host_port) != 3) {
+ if (!parse_forward(&fwd, s)) {
logit("Bad forwarding specification.");
goto out;
}
- if ((fwd_port = a2port(sfwd_port)) == 0 ||
- (fwd_host_port = a2port(sfwd_host_port)) == 0) {
- logit("Bad forwarding port(s).");
- goto out;
- }
if (local) {
- if (channel_setup_local_fwd_listener(fwd_port, buf,
- fwd_host_port, options.gateway_ports) < 0) {
+ if (channel_setup_local_fwd_listener(fwd.listen_host,
+ fwd.listen_port, fwd.connect_host,
+ fwd.connect_port, options.gateway_ports) < 0) {
logit("Port forwarding failed.");
goto out;
}
- } else
- channel_request_remote_forwarding(fwd_port, buf,
- fwd_host_port);
+ } else {
+ channel_request_remote_forwarding(fwd.listen_host,
+ fwd.listen_port, fwd.connect_host,
+ fwd.connect_port);
+ }
+
logit("Forwarding port.");
}
{
fd_set *readset = NULL, *writeset = NULL;
double start_time, total_time;
- int max_fd = 0, max_fd2 = 0, len, rekeying = 0, nalloc = 0;
+ int max_fd = 0, max_fd2 = 0, len, rekeying = 0;
+ u_int nalloc = 0;
char buf[100];
debug("Entering interactive session.");
* Set signal handlers, (e.g. to restore non-blocking mode)
* but don't overwrite SIG_IGN, matches behaviour from rsh(1)
*/
+ if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
+ signal(SIGHUP, signal_handler);
if (signal(SIGINT, SIG_IGN) != SIG_IGN)
signal(SIGINT, signal_handler);
if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
signal(SIGQUIT, signal_handler);
if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
signal(SIGTERM, signal_handler);
- if (have_pty)
- signal(SIGWINCH, window_change_handler);
+ signal(SIGWINCH, window_change_handler);
if (have_pty)
enter_raw_mode();
/* Terminate the session. */
/* Stop watching for window change. */
- if (have_pty)
- signal(SIGWINCH, SIG_DFL);
+ signal(SIGWINCH, SIG_DFL);
channel_free_all();
debug("client_input_channel_req: channel %d rtype %s reply %d",
id, rtype, reply);
- c = channel_lookup(id);
- if (c == NULL) {
+ if (id == -1) {
+ error("client_input_channel_req: request for channel -1");
+ } else if ((c = channel_lookup(id)) == NULL) {
error("client_input_channel_req: channel %d: unknown channel", id);
} else if (strcmp(rtype, "exit-status") == 0) {
exitval = packet_get_int();
if (reply) {
packet_start(success ?
SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);
- packet_put_int(c->remote_id);
+ packet_put_int(id);
packet_send();
}
xfree(rtype);
}
void
-client_session2_setup(int id, int want_tty, int want_subsystem,
+client_session2_setup(int id, int want_tty, int want_subsystem,
const char *term, struct termios *tiop, int in_fd, Buffer *cmd, char **env,
dispatch_fn *subsys_repl)
{
int len;
+ Channel *c = NULL;
debug2("%s: id %d", __func__, id);
+ if ((c = channel_lookup(id)) == NULL)
+ fatal("client_session2_setup: channel %d: unknown channel", id);
+
if (want_tty) {
struct winsize ws;
struct termios tio;
tty_make_modes(-1, tiop != NULL ? tiop : &tio);
packet_send();
/* XXX wait for reply */
+ c->client_tty = 1;
}
/* Transfer any environment variables from client to server */