Skip to content

Commit

Permalink
- djm@cvs.openbsd.org 2008/05/08 13:06:11
Browse files Browse the repository at this point in the history
     [clientloop.c clientloop.h ssh.c]
     Use new channel status confirmation callback system to properly deal
     with "important" channel requests that fail, in particular command exec,
     shell and subsystem requests. Previously we would optimistically assume
     that the requests would always succeed, which could cause hangs if they
     did not (e.g. when the server runs out of fds) or were unimplemented by
     the server (bz #1384)
     Also, properly report failing multiplex channel requests via the mux
     client stderr (subject to LogLevel in the mux master) - better than
     silently failing.
     most bits ok markus@ (as part of a larger diff)
  • Loading branch information
djmdjm committed May 19, 2008
1 parent 7207f64 commit 5771ed7
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 53 deletions.
14 changes: 13 additions & 1 deletion ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,18 @@
sending channel errors instead of than exiting with fatal().
bz#1090; MaxSessions config bits and manpage from junyer AT gmail.com
ok markus@
- djm@cvs.openbsd.org 2008/05/08 13:06:11
[clientloop.c clientloop.h ssh.c]
Use new channel status confirmation callback system to properly deal
with "important" channel requests that fail, in particular command exec,
shell and subsystem requests. Previously we would optimistically assume
that the requests would always succeed, which could cause hangs if they
did not (e.g. when the server runs out of fds) or were unimplemented by
the server (bz #1384)
Also, properly report failing multiplex channel requests via the mux
client stderr (subject to LogLevel in the mux master) - better than
silently failing.
most bits ok markus@ (as part of a larger diff)

20080403
- (djm) [openbsd-compat/bsd-poll.c] Include stdlib.h to avoid compile-
Expand Down Expand Up @@ -3952,4 +3964,4 @@
OpenServer 6 and add osr5bigcrypt support so when someone migrates
passwords between UnixWare and OpenServer they will still work. OK dtucker@

$Id: ChangeLog,v 1.4923 2008/05/19 05:34:50 djm Exp $
$Id: ChangeLog,v 1.4924 2008/05/19 05:36:08 djm Exp $
106 changes: 73 additions & 33 deletions clientloop.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* $OpenBSD: clientloop.c,v 1.189 2008/05/08 12:02:23 djm Exp $ */
/* $OpenBSD: clientloop.c,v 1.190 2008/05/08 13:06:10 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
Expand Down Expand Up @@ -173,6 +173,11 @@ struct confirm_ctx {
char **env;
};

struct channel_reply_ctx {
const char *request_type;
int id, do_close;
};

/*XXX*/
extern Kex *xxx_kex;

Expand Down Expand Up @@ -645,25 +650,60 @@ client_process_net_input(fd_set *readset)
}

static void
client_subsystem_reply(int type, u_int32_t seq, void *ctxt)
client_status_confirm(int type, Channel *c, void *ctx)
{
int id;
Channel *c;
struct channel_reply_ctx *cr = (struct channel_reply_ctx *)ctx;
char errmsg[256];
int tochan;

/* XXX supress on mux _client_ quietmode */
tochan = options.log_level >= SYSLOG_LEVEL_ERROR &&
c->ctl_fd != -1 && c->extended_usage == CHAN_EXTENDED_WRITE;

if (type == SSH2_MSG_CHANNEL_SUCCESS) {
debug2("%s request accepted on channel %d",
cr->request_type, c->self);
} else if (type == SSH2_MSG_CHANNEL_FAILURE) {
if (tochan) {
snprintf(errmsg, sizeof(errmsg),
"%s request failed\r\n", cr->request_type);
} else {
snprintf(errmsg, sizeof(errmsg),
"%s request failed on channel %d",
cr->request_type, c->self);
}
/* If error occurred on primary session channel, then exit */
if (cr->do_close && c->self == session_ident)
fatal("%s", errmsg);
/* If error occurred on mux client, append to their stderr */
if (tochan)
buffer_append(&c->extended, errmsg, strlen(errmsg));
else
error("%s", errmsg);
if (cr->do_close) {
chan_read_failed(c);
chan_write_failed(c);
}
}
xfree(cr);
}

id = packet_get_int();
packet_check_eom();
static void
client_abandon_status_confirm(Channel *c, void *ctx)
{
xfree(ctx);
}

if ((c = channel_lookup(id)) == NULL) {
error("%s: no channel for id %d", __func__, id);
return;
}
static void
client_expect_confirm(int id, const char *request, int do_close)
{
struct channel_reply_ctx *cr = xmalloc(sizeof(*cr));

if (type == SSH2_MSG_CHANNEL_SUCCESS)
debug2("Request suceeded on channel %d", id);
else if (type == SSH2_MSG_CHANNEL_FAILURE) {
error("Request failed on channel %d", id);
channel_free(c);
}
cr->request_type = request;
cr->do_close = do_close;

channel_register_status_confirm(id, client_status_confirm,
client_abandon_status_confirm, cr);
}

static void
Expand Down Expand Up @@ -698,8 +738,7 @@ client_extra_session2_setup(int id, void *arg)
}

client_session2_setup(id, cctx->want_tty, cctx->want_subsys,
cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env,
client_subsystem_reply);
cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env);

c->open_confirm_ctx = NULL;
buffer_free(&cctx->cmd);
Expand Down Expand Up @@ -1366,7 +1405,9 @@ client_process_buffered_input_packets(void)
static int
simple_escape_filter(Channel *c, char *buf, int len)
{
/* XXX we assume c->extended is writeable */
if (c->extended_usage != CHAN_EXTENDED_WRITE)
return 0;

return process_escapes(&c->input, &c->output, &c->extended, buf, len);
}

Expand Down Expand Up @@ -1962,8 +2003,7 @@ client_input_global_request(int type, u_int32_t seq, void *ctxt)

void
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)
const char *term, struct termios *tiop, int in_fd, Buffer *cmd, char **env)
{
int len;
Channel *c = NULL;
Expand All @@ -1981,7 +2021,8 @@ client_session2_setup(int id, int want_tty, int want_subsystem,
if (ioctl(in_fd, TIOCGWINSZ, &ws) < 0)
memset(&ws, 0, sizeof(ws));

channel_request_start(id, "pty-req", 0);
channel_request_start(id, "pty-req", 1);
client_expect_confirm(id, "PTY allocation", 0);
packet_put_cstring(term != NULL ? term : "");
packet_put_int((u_int)ws.ws_col);
packet_put_int((u_int)ws.ws_row);
Expand Down Expand Up @@ -2036,22 +2077,21 @@ client_session2_setup(int id, int want_tty, int want_subsystem,
if (len > 900)
len = 900;
if (want_subsystem) {
debug("Sending subsystem: %.*s", len, (u_char*)buffer_ptr(cmd));
channel_request_start(id, "subsystem", subsys_repl != NULL);
if (subsys_repl != NULL) {
/* register callback for reply */
/* XXX we assume that client_loop has already been called */
dispatch_set(SSH2_MSG_CHANNEL_FAILURE, subsys_repl);
dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, subsys_repl);
}
debug("Sending subsystem: %.*s",
len, (u_char*)buffer_ptr(cmd));
channel_request_start(id, "subsystem", 1);
client_expect_confirm(id, "subsystem", 1);
} else {
debug("Sending command: %.*s", len, (u_char*)buffer_ptr(cmd));
channel_request_start(id, "exec", 0);
debug("Sending command: %.*s",
len, (u_char*)buffer_ptr(cmd));
channel_request_start(id, "exec", 1);
client_expect_confirm(id, "exec", 1);
}
packet_put_string(buffer_ptr(cmd), buffer_len(cmd));
packet_send();
} else {
channel_request_start(id, "shell", 0);
channel_request_start(id, "shell", 1);
client_expect_confirm(id, "shell", 1);
packet_send();
}
}
Expand Down
4 changes: 2 additions & 2 deletions clientloop.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* $OpenBSD: clientloop.h,v 1.17 2007/08/07 07:32:53 djm Exp $ */
/* $OpenBSD: clientloop.h,v 1.18 2008/05/08 13:06:11 djm Exp $ */

/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
Expand Down Expand Up @@ -43,7 +43,7 @@ void client_x11_get_proto(const char *, const char *, u_int,
char **, char **);
void client_global_request_reply_fwd(int, u_int32_t, void *);
void client_session2_setup(int, int, int, const char *, struct termios *,
int, Buffer *, char **, dispatch_fn *);
int, Buffer *, char **);
int client_request_tun_fwd(int, int, int);

/* Multiplexing protocol version */
Expand Down
19 changes: 2 additions & 17 deletions ssh.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* $OpenBSD: ssh.c,v 1.310 2008/05/08 12:02:23 djm Exp $ */
/* $OpenBSD: ssh.c,v 1.311 2008/05/08 13:06:11 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
Expand Down Expand Up @@ -1039,21 +1039,6 @@ ssh_session(void)
options.escape_char : SSH_ESCAPECHAR_NONE, 0);
}

static void
ssh_subsystem_reply(int type, u_int32_t seq, void *ctxt)
{
int id, len;

id = packet_get_int();
len = buffer_len(&command);
if (len > 900)
len = 900;
packet_check_eom();
if (type == SSH2_MSG_CHANNEL_FAILURE)
fatal("Request for subsystem '%.*s' failed on channel %d",
len, (u_char *)buffer_ptr(&command), id);
}

void
client_global_request_reply_fwd(int type, u_int32_t seq, void *ctxt)
{
Expand Down Expand Up @@ -1150,7 +1135,7 @@ ssh_session2_setup(int id, void *arg)
}

client_session2_setup(id, tty_flag, subsystem_flag, getenv("TERM"),
NULL, fileno(stdin), &command, environ, &ssh_subsystem_reply);
NULL, fileno(stdin), &command, environ);

packet_set_interactive(interactive);
}
Expand Down

0 comments on commit 5771ed7

Please sign in to comment.