CHAN_ZOMBIE
};
+typedef void (*handler_fn_t)(Ssh ssh, struct Packet *pktin);
+typedef void (*chandler_fn_t)(Ssh ssh, struct Packet *pktin, void *ctx);
+typedef void (*cchandler_fn_t)(struct ssh_channel *, struct Packet *, void *);
+
+/*
+ * Each channel has a queue of outstanding CHANNEL_REQUESTS and their
+ * handlers.
+ */
+struct outstanding_channel_request {
+ cchandler_fn_t handler;
+ void *ctx;
+ struct outstanding_channel_request *next;
+};
+
/*
* little structure to keep track of outstanding WINDOW_ADJUSTs
*/
*/
int remlocwin;
/*
- * These store the list of window adjusts that haven't
+ * These store the list of channel requests that haven't
* been acked.
*/
- struct winadj *winadj_head, *winadj_tail;
+ struct outstanding_channel_request *chanreq_head, *chanreq_tail;
enum { THROTTLED, UNTHROTTLING, UNTHROTTLED } throttle_state;
} v2;
} v;
static void ssh2_timer(void *ctx, long now);
static int do_ssh2_transport(Ssh ssh, void *vin, int inlen,
struct Packet *pktin);
+static void ssh2_msg_unexpected(Ssh ssh, struct Packet *pktin);
struct rdpkt1_state_tag {
long len, pad, biglen, to_read;
struct Packet *pktin;
};
-typedef void (*handler_fn_t)(Ssh ssh, struct Packet *pktin);
-typedef void (*chandler_fn_t)(Ssh ssh, struct Packet *pktin, void *ctx);
-
struct queued_handler;
struct queued_handler {
int msg1, msg2;
c->throttling_conn = FALSE;
c->v.v2.locwindow = c->v.v2.locmaxwin = c->v.v2.remlocwin =
conf_get_int(ssh->conf, CONF_ssh_simple) ? OUR_V2_BIGWIN : OUR_V2_WINSIZE;
- c->v.v2.winadj_head = c->v.v2.winadj_tail = NULL;
+ c->v.v2.chanreq_head = NULL;
c->v.v2.throttle_state = UNTHROTTLED;
bufchain_init(&c->v.v2.outbuffer);
}
/*
+ * CHANNEL_FAILURE doesn't come with any indication of what message
+ * caused it, so we have to keep track of the outstanding
+ * CHANNEL_REQUESTs ourselves.
+ */
+static void ssh2_queue_chanreq_handler(struct ssh_channel *c,
+ cchandler_fn_t handler, void *ctx)
+{
+ struct outstanding_channel_request *ocr =
+ snew(struct outstanding_channel_request);
+
+ ocr->handler = handler;
+ ocr->ctx = ctx;
+ ocr->next = NULL;
+ if (!c->v.v2.chanreq_head)
+ c->v.v2.chanreq_head = ocr;
+ else
+ c->v.v2.chanreq_tail->next = ocr;
+ c->v.v2.chanreq_tail = ocr;
+}
+
+/*
* Potentially enlarge the window on an SSH-2 channel.
*/
+static void ssh2_handle_winadj_response(struct ssh_channel *, struct Packet *,
+ void *);
static void ssh2_set_window(struct ssh_channel *c, int newwin)
{
Ssh ssh = c->ssh;
*/
if (newwin / 2 >= c->v.v2.locwindow) {
struct Packet *pktout;
- struct winadj *wa;
+ unsigned *up;
/*
* In order to keep track of how much window the client
* This is only necessary if we're opening the window wide.
* If we're not, then throughput is being constrained by
* something other than the maximum window size anyway.
- *
- * We also only send this if the main channel has finished its
- * initial CHANNEL_REQUESTs and installed the default
- * CHANNEL_FAILURE handler, so as not to risk giving it
- * unexpected CHANNEL_FAILUREs.
*/
if (newwin == c->v.v2.locmaxwin &&
- ssh->packet_dispatch[SSH2_MSG_CHANNEL_FAILURE] &&
!(ssh->remote_bugs & BUG_CHOKES_ON_WINADJ)) {
pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);
ssh2_pkt_adduint32(pktout, c->remoteid);
ssh2_pkt_addbool(pktout, TRUE);
ssh2_pkt_send(ssh, pktout);
- /*
- * CHANNEL_FAILURE doesn't come with any indication of
- * what message caused it, so we have to keep track of the
- * outstanding CHANNEL_REQUESTs ourselves.
- */
- wa = snew(struct winadj);
- wa->size = newwin - c->v.v2.locwindow;
- wa->next = NULL;
- if (!c->v.v2.winadj_head)
- c->v.v2.winadj_head = wa;
- else
- c->v.v2.winadj_tail->next = wa;
- c->v.v2.winadj_tail = wa;
+ up = snew(unsigned);
+ *up = newwin - c->v.v2.locwindow;
+ ssh2_queue_chanreq_handler(c, ssh2_handle_winadj_response, up);
if (c->v.v2.throttle_state != UNTHROTTLED)
c->v.v2.throttle_state = UNTHROTTLING;
} else {
return c;
}
-static int ssh2_handle_winadj_response(struct ssh_channel *c)
+static void ssh2_handle_winadj_response(struct ssh_channel *c,
+ struct Packet *pktin, void *ctx)
{
- struct winadj *wa = c->v.v2.winadj_head;
- if (!wa)
- return FALSE;
- c->v.v2.winadj_head = wa->next;
- c->v.v2.remlocwin += wa->size;
- sfree(wa);
+ unsigned *sizep = ctx;
+
+ /*
+ * Winadj responses should always be failures. However, at least
+ * one server ("boks_sshd") is known to return SUCCESS for channel
+ * requests it's never heard of, such as "winadj@putty". Raised
+ * with foxt.com as bug 090916-090424, but for the sake of a quiet
+ * life, we don't worry about what kind of response we got.
+ */
+
+ c->v.v2.remlocwin += *sizep;
+ sfree(sizep);
/*
* winadj messages are only sent when the window is fully open, so
* if we get an ack of one, we know any pending unthrottle is
*/
if (c->v.v2.throttle_state == UNTHROTTLING)
c->v.v2.throttle_state = UNTHROTTLED;
- /*
- * We may now initiate channel-closing procedures, if that winadj
- * was the last thing outstanding before we send CHANNEL_CLOSE.
- */
- ssh2_channel_check_close(c);
- return TRUE;
}
-static void ssh2_msg_channel_success(Ssh ssh, struct Packet *pktin)
+static void ssh2_msg_channel_response(Ssh ssh, struct Packet *pktin)
{
- /*
- * This should never get called. All channel requests are either
- * sent with want_reply false, are sent before this handler gets
- * installed, or are "winadj@putty" requests, which servers should
- * never respond to with success.
- *
- * However, at least one server ("boks_sshd") is known to return
- * SUCCESS for channel requests it's never heard of, such as
- * "winadj@putty". Raised with foxt.com as bug 090916-090424, but
- * for the sake of a quiet life, we handle it just the same as the
- * expected FAILURE.
- */
- struct ssh_channel *c;
+ struct ssh_channel *c = ssh2_channel_msg(ssh, pktin);
+ struct outstanding_channel_request *ocr;
- c = ssh2_channel_msg(ssh, pktin);
- if (!c)
+ if (!c) return;
+ ocr = c->v.v2.chanreq_head;
+ if (!ocr) {
+ ssh2_msg_unexpected(ssh, pktin);
return;
- if (!ssh2_handle_winadj_response(c))
- ssh_disconnect(ssh, NULL,
- "Received unsolicited SSH_MSG_CHANNEL_SUCCESS",
- SSH2_DISCONNECT_PROTOCOL_ERROR, FALSE);
-}
-
-static void ssh2_msg_channel_failure(Ssh ssh, struct Packet *pktin)
-{
+ }
+ ocr->handler(c, pktin, ocr->ctx);
+ c->v.v2.chanreq_head = ocr->next;
+ sfree(ocr);
/*
- * The only time this should get called is for "winadj@putty"
- * messages sent above. All other channel requests are either
- * sent with want_reply false or are sent before this handler gets
- * installed.
+ * We may now initiate channel-closing procedures, if that
+ * CHANNEL_REQUEST was the last thing outstanding before we send
+ * CHANNEL_CLOSE.
*/
- struct ssh_channel *c;
-
- c = ssh2_channel_msg(ssh, pktin);
- if (!c)
- return;
- if (!ssh2_handle_winadj_response(c))
- ssh_disconnect(ssh, NULL,
- "Received unsolicited SSH_MSG_CHANNEL_FAILURE",
- SSH2_DISCONNECT_PROTOCOL_ERROR, FALSE);
+ ssh2_channel_check_close(c);
}
static void ssh2_msg_channel_window_adjust(Ssh ssh, struct Packet *pktin)
struct Packet *pktout;
if ((c->closes & (CLOSES_SENT_EOF | CLOSES_RCVD_EOF | CLOSES_SENT_CLOSE))
- == (CLOSES_SENT_EOF | CLOSES_RCVD_EOF) && !c->v.v2.winadj_head) {
+ == (CLOSES_SENT_EOF | CLOSES_RCVD_EOF) && !c->v.v2.chanreq_head) {
/*
* We have both sent and received EOF, and we have no
* outstanding winadj channel requests, which means the
ssh2_pkt_adduint32(pktout, arg);
}
+static void ssh2_msg_authconn(Ssh ssh, struct Packet *pktin);
+static void ssh2_maybe_setup_x11(struct ssh_channel *c, struct Packet *pktin,
+ void *ctx)
+{
+ struct ssh2_maybe_setup_x11_state {
+ int crLine;
+ };
+ Ssh ssh = c->ssh;
+ struct Packet *pktout;
+ crStateP(ssh2_maybe_setup_x11_state, ctx);
+
+ crBeginState;
+
+ /*
+ * Potentially enable X11 forwarding.
+ */
+ if (ssh->mainchan && !ssh->ncmode && conf_get_int(ssh->conf, CONF_x11_forward) &&
+ (ssh->x11disp = x11_setup_display(conf_get_str(ssh->conf, CONF_x11_display),
+ conf_get_int(ssh->conf, CONF_x11_auth), ssh->conf))) {
+ logevent("Requesting X11 forwarding");
+ pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);
+ ssh2_pkt_adduint32(pktout, ssh->mainchan->remoteid);
+ ssh2_pkt_addstring(pktout, "x11-req");
+ ssh2_pkt_addbool(pktout, 1); /* want reply */
+ ssh2_pkt_addbool(pktout, 0); /* many connections */
+ ssh2_pkt_addstring(pktout, ssh->x11disp->remoteauthprotoname);
+ /*
+ * Note that while we blank the X authentication data here, we don't
+ * take any special action to blank the start of an X11 channel,
+ * so using MIT-MAGIC-COOKIE-1 and actually opening an X connection
+ * without having session blanking enabled is likely to leak your
+ * cookie into the log.
+ */
+ dont_log_password(ssh, pktout, PKTLOG_BLANK);
+ ssh2_pkt_addstring(pktout, ssh->x11disp->remoteauthdatastring);
+ end_log_omission(ssh, pktout);
+ ssh2_pkt_adduint32(pktout, ssh->x11disp->screennum);
+ ssh2_pkt_send(ssh, pktout);
+
+ ssh2_queue_chanreq_handler(ssh->mainchan, ssh2_maybe_setup_x11, s);
+
+ crWaitUntilV(pktin);
+
+ if (pktin->type != SSH2_MSG_CHANNEL_SUCCESS) {
+ if (pktin->type != SSH2_MSG_CHANNEL_FAILURE) {
+ bombout(("Unexpected response to X11 forwarding request:"
+ " packet type %d", pktin->type));
+ sfree(s);
+ crStopV;
+ }
+ logevent("X11 forwarding refused");
+ } else {
+ logevent("X11 forwarding enabled");
+ ssh->X11_fwd_enabled = TRUE;
+ }
+ }
+ sfree(s);
+ crFinishV;
+}
+
+static void ssh2_maybe_setup_agent(struct ssh_channel *c, struct Packet *pktin,
+ void *ctx)
+{
+ struct ssh2_maybe_setup_agent_state {
+ int crLine;
+ };
+ Ssh ssh = c->ssh;
+ struct Packet *pktout;
+ crStateP(ssh2_maybe_setup_agent_state, ctx);
+
+ crBeginState;
+
+ if (ssh->mainchan && !ssh->ncmode && conf_get_int(ssh->conf, CONF_agentfwd) && agent_exists()) {
+ logevent("Requesting OpenSSH-style agent forwarding");
+ pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);
+ ssh2_pkt_adduint32(pktout, ssh->mainchan->remoteid);
+ ssh2_pkt_addstring(pktout, "auth-agent-req@openssh.com");
+ ssh2_pkt_addbool(pktout, 1); /* want reply */
+ ssh2_pkt_send(ssh, pktout);
+
+ ssh2_queue_chanreq_handler(ssh->mainchan, ssh2_maybe_setup_agent, s);
+
+ crWaitUntilV(pktin);
+
+ if (pktin->type != SSH2_MSG_CHANNEL_SUCCESS) {
+ if (pktin->type != SSH2_MSG_CHANNEL_FAILURE) {
+ bombout(("Unexpected response to agent forwarding request:"
+ " packet type %d", pktin->type));
+ crStopV;
+ }
+ logevent("Agent forwarding refused");
+ } else {
+ logevent("Agent forwarding enabled");
+ ssh->agentfwd_enabled = TRUE;
+ }
+ }
+ sfree(s);
+ crFinishV;
+}
+
+static void ssh2_maybe_setup_pty(struct ssh_channel *c, struct Packet *pktin,
+ void *ctx)
+{
+ struct ssh2_maybe_setup_pty_state {
+ int crLine;
+ };
+ Ssh ssh = c->ssh;
+ struct Packet *pktout;
+ crStateP(ssh2_maybe_setup_pty_state, ctx);
+
+ crBeginState;
+
+ if (ssh->mainchan && !ssh->ncmode && !conf_get_int(ssh->conf, CONF_nopty)) {
+ /* Unpick the terminal-speed string. */
+ /* XXX perhaps we should allow no speeds to be sent. */
+ ssh->ospeed = 38400; ssh->ispeed = 38400; /* last-resort defaults */
+ sscanf(conf_get_str(ssh->conf, CONF_termspeed), "%d,%d", &ssh->ospeed, &ssh->ispeed);
+ /* Build the pty request. */
+ pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);
+ ssh2_pkt_adduint32(pktout, ssh->mainchan->remoteid); /* recipient channel */
+ ssh2_pkt_addstring(pktout, "pty-req");
+ ssh2_pkt_addbool(pktout, 1); /* want reply */
+ ssh2_pkt_addstring(pktout, conf_get_str(ssh->conf, CONF_termtype));
+ ssh2_pkt_adduint32(pktout, ssh->term_width);
+ ssh2_pkt_adduint32(pktout, ssh->term_height);
+ ssh2_pkt_adduint32(pktout, 0); /* pixel width */
+ ssh2_pkt_adduint32(pktout, 0); /* pixel height */
+ ssh2_pkt_addstring_start(pktout);
+ parse_ttymodes(ssh, ssh2_send_ttymode, (void *)pktout);
+ ssh2_pkt_addbyte(pktout, SSH2_TTY_OP_ISPEED);
+ ssh2_pkt_adduint32(pktout, ssh->ispeed);
+ ssh2_pkt_addbyte(pktout, SSH2_TTY_OP_OSPEED);
+ ssh2_pkt_adduint32(pktout, ssh->ospeed);
+ ssh2_pkt_addstring_data(pktout, "\0", 1); /* TTY_OP_END */
+ ssh2_pkt_send(ssh, pktout);
+ ssh->state = SSH_STATE_INTERMED;
+
+ ssh2_queue_chanreq_handler(ssh->mainchan, ssh2_maybe_setup_pty, s);
+
+ crWaitUntilV(pktin);
+
+ if (pktin->type != SSH2_MSG_CHANNEL_SUCCESS) {
+ if (pktin->type != SSH2_MSG_CHANNEL_FAILURE) {
+ bombout(("Unexpected response to pty request:"
+ " packet type %d", pktin->type));
+ crStopV;
+ }
+ c_write_str(ssh, "Server refused to allocate pty\r\n");
+ ssh->editing = ssh->echoing = 1;
+ } else {
+ logeventf(ssh, "Allocated pty (ospeed %dbps, ispeed %dbps)",
+ ssh->ospeed, ssh->ispeed);
+ ssh->got_pty = TRUE;
+ }
+ } else {
+ ssh->editing = ssh->echoing = 1;
+ }
+ sfree(s);
+ crFinishV;
+}
+
+static void ssh2_setup_env(struct ssh_channel *c, struct Packet *pktin,
+ void *ctx)
+{
+ struct ssh2_setup_env_state {
+ int crLine;
+ int num_env, env_left, env_ok;
+ };
+ Ssh ssh = c->ssh;
+ struct Packet *pktout;
+ crStateP(ssh2_setup_env_state, ctx);
+
+ crBeginState;
+
+ /*
+ * Send environment variables.
+ *
+ * Simplest thing here is to send all the requests at once, and
+ * then wait for a whole bunch of successes or failures.
+ */
+ s->num_env = 0;
+ if (ssh->mainchan && !ssh->ncmode) {
+ char *key, *val;
+
+ for (val = conf_get_str_strs(ssh->conf, CONF_environmt, NULL, &key);
+ val != NULL;
+ val = conf_get_str_strs(ssh->conf, CONF_environmt, key, &key)) {
+ pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);
+ ssh2_pkt_adduint32(pktout, ssh->mainchan->remoteid);
+ ssh2_pkt_addstring(pktout, "env");
+ ssh2_pkt_addbool(pktout, 1); /* want reply */
+ ssh2_pkt_addstring(pktout, key);
+ ssh2_pkt_addstring(pktout, val);
+ ssh2_pkt_send(ssh, pktout);
+ ssh2_queue_chanreq_handler(ssh->mainchan, ssh2_setup_env, s);
+
+ s->num_env++;
+ }
+ if (s->num_env)
+ logeventf(ssh, "Sent %d environment variables", s->num_env);
+ }
+
+ if (s->num_env) {
+ s->env_ok = 0;
+ s->env_left = s->num_env;
+
+ while (s->env_left > 0) {
+ crWaitUntilV(pktin);
+
+ if (pktin->type != SSH2_MSG_CHANNEL_SUCCESS) {
+ if (pktin->type != SSH2_MSG_CHANNEL_FAILURE) {
+ bombout(("Unexpected response to environment request:"
+ " packet type %d", pktin->type));
+ crStopV;
+ }
+ } else {
+ s->env_ok++;
+ }
+
+ s->env_left--;
+ }
+
+ if (s->env_ok == s->num_env) {
+ logevent("All environment variables successfully set");
+ } else if (s->env_ok == 0) {
+ logevent("All environment variables refused");
+ c_write_str(ssh, "Server refused to set environment variables\r\n");
+ } else {
+ logeventf(ssh, "%d environment variables refused",
+ s->num_env - s->env_ok);
+ c_write_str(ssh, "Server refused to set all environment variables\r\n");
+ }
+ }
+ sfree(s);
+ crFinishV;
+}
+
/*
* Handle the SSH-2 userauth and connection layers.
*/
do_ssh2_authconn(ssh, NULL, 0, pktin);
}
+static void ssh2_response_authconn(struct ssh_channel *c, struct Packet *pktin,
+ void *ctx)
+{
+ do_ssh2_authconn(c->ssh, NULL, 0, pktin);
+}
+
static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
struct Packet *pktin)
{
int siglen, retlen, len;
char *q, *agentreq, *ret;
int try_send;
- int requested_x11;
- int requested_agent;
- int requested_tty;
- int num_env, env_left, env_ok;
struct Packet *pktout;
Filename *keyfile;
#ifndef NO_GSSAPI
ssh->packet_dispatch[SSH2_MSG_CHANNEL_EXTENDED_DATA] = ssh2_msg_authconn;
ssh->packet_dispatch[SSH2_MSG_CHANNEL_EOF] = ssh2_msg_authconn;
ssh->packet_dispatch[SSH2_MSG_CHANNEL_CLOSE] = ssh2_msg_authconn;
- ssh->packet_dispatch[SSH2_MSG_CHANNEL_REQUEST] = ssh2_msg_authconn;
- ssh->packet_dispatch[SSH2_MSG_CHANNEL_SUCCESS] = ssh2_msg_authconn;
- ssh->packet_dispatch[SSH2_MSG_CHANNEL_FAILURE] = ssh2_msg_authconn;
s->done_service_req = FALSE;
s->we_are_in = s->userauth_success = FALSE;
ssh2_msg_channel_request;
ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN] =
ssh2_msg_channel_open;
+ ssh->packet_dispatch[SSH2_MSG_CHANNEL_SUCCESS] = ssh2_msg_channel_response;
+ ssh->packet_dispatch[SSH2_MSG_CHANNEL_FAILURE] = ssh2_msg_channel_response;
+
if (ssh->mainchan && conf_get_int(ssh->conf, CONF_ssh_simple)) {
/*
ssh_setup_portfwd(ssh, ssh->conf);
/*
- * Send the CHANNEL_REQUESTS for the main channel. We send them all
- * and then start looking for responses, so it's important that the
- * sending and receiving code below it is kept in sync.
+ * Send the CHANNEL_REQUESTS for the main channel. Each one is
+ * handled by its own little asynchronous co-routine.
*/
/*
* Potentially enable X11 forwarding.
*/
- if (ssh->mainchan && !ssh->ncmode && conf_get_int(ssh->conf, CONF_x11_forward) &&
- (ssh->x11disp = x11_setup_display(conf_get_str(ssh->conf, CONF_x11_display),
- conf_get_int(ssh->conf, CONF_x11_auth), ssh->conf))) {
- logevent("Requesting X11 forwarding");
- s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);
- ssh2_pkt_adduint32(s->pktout, ssh->mainchan->remoteid);
- ssh2_pkt_addstring(s->pktout, "x11-req");
- ssh2_pkt_addbool(s->pktout, 1); /* want reply */
- ssh2_pkt_addbool(s->pktout, 0); /* many connections */
- ssh2_pkt_addstring(s->pktout, ssh->x11disp->remoteauthprotoname);
- /*
- * Note that while we blank the X authentication data here, we don't
- * take any special action to blank the start of an X11 channel,
- * so using MIT-MAGIC-COOKIE-1 and actually opening an X connection
- * without having session blanking enabled is likely to leak your
- * cookie into the log.
- */
- dont_log_password(ssh, s->pktout, PKTLOG_BLANK);
- ssh2_pkt_addstring(s->pktout, ssh->x11disp->remoteauthdatastring);
- end_log_omission(ssh, s->pktout);
- ssh2_pkt_adduint32(s->pktout, ssh->x11disp->screennum);
- ssh2_pkt_send(ssh, s->pktout);
- s->requested_x11 = TRUE;
- } else
- s->requested_x11 = FALSE;
+ ssh2_maybe_setup_x11(ssh->mainchan, NULL, NULL);
/*
* Potentially enable agent forwarding.
*/
- if (ssh->mainchan && !ssh->ncmode && conf_get_int(ssh->conf, CONF_agentfwd) && agent_exists()) {
- logevent("Requesting OpenSSH-style agent forwarding");
- s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);
- ssh2_pkt_adduint32(s->pktout, ssh->mainchan->remoteid);
- ssh2_pkt_addstring(s->pktout, "auth-agent-req@openssh.com");
- ssh2_pkt_addbool(s->pktout, 1); /* want reply */
- ssh2_pkt_send(ssh, s->pktout);
- s->requested_agent = TRUE;
- } else
- s->requested_agent = FALSE;
+ ssh2_maybe_setup_agent(ssh->mainchan, NULL, NULL);
/*
* Now allocate a pty for the session.
*/
- if (ssh->mainchan && !ssh->ncmode && !conf_get_int(ssh->conf, CONF_nopty)) {
- /* Unpick the terminal-speed string. */
- /* XXX perhaps we should allow no speeds to be sent. */
- ssh->ospeed = 38400; ssh->ispeed = 38400; /* last-resort defaults */
- sscanf(conf_get_str(ssh->conf, CONF_termspeed), "%d,%d", &ssh->ospeed, &ssh->ispeed);
- /* Build the pty request. */
- s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);
- ssh2_pkt_adduint32(s->pktout, ssh->mainchan->remoteid); /* recipient channel */
- ssh2_pkt_addstring(s->pktout, "pty-req");
- ssh2_pkt_addbool(s->pktout, 1); /* want reply */
- ssh2_pkt_addstring(s->pktout, conf_get_str(ssh->conf, CONF_termtype));
- ssh2_pkt_adduint32(s->pktout, ssh->term_width);
- ssh2_pkt_adduint32(s->pktout, ssh->term_height);
- ssh2_pkt_adduint32(s->pktout, 0); /* pixel width */
- ssh2_pkt_adduint32(s->pktout, 0); /* pixel height */
- ssh2_pkt_addstring_start(s->pktout);
- parse_ttymodes(ssh, ssh2_send_ttymode, (void *)s->pktout);
- ssh2_pkt_addbyte(s->pktout, SSH2_TTY_OP_ISPEED);
- ssh2_pkt_adduint32(s->pktout, ssh->ispeed);
- ssh2_pkt_addbyte(s->pktout, SSH2_TTY_OP_OSPEED);
- ssh2_pkt_adduint32(s->pktout, ssh->ospeed);
- ssh2_pkt_addstring_data(s->pktout, "\0", 1); /* TTY_OP_END */
- ssh2_pkt_send(ssh, s->pktout);
- ssh->state = SSH_STATE_INTERMED;
- s->requested_tty = TRUE;
- } else
- s->requested_tty = FALSE;
+ ssh2_maybe_setup_pty(ssh->mainchan, NULL, NULL);
/*
* Send environment variables.
- *
- * Simplest thing here is to send all the requests at once, and
- * then wait for a whole bunch of successes or failures.
- */
- s->num_env = 0;
- if (ssh->mainchan && !ssh->ncmode) {
- char *key, *val;
-
- for (val = conf_get_str_strs(ssh->conf, CONF_environmt, NULL, &key);
- val != NULL;
- val = conf_get_str_strs(ssh->conf, CONF_environmt, key, &key)) {
- s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);
- ssh2_pkt_adduint32(s->pktout, ssh->mainchan->remoteid);
- ssh2_pkt_addstring(s->pktout, "env");
- ssh2_pkt_addbool(s->pktout, 1); /* want reply */
- ssh2_pkt_addstring(s->pktout, key);
- ssh2_pkt_addstring(s->pktout, val);
- ssh2_pkt_send(ssh, s->pktout);
-
- s->num_env++;
- }
- if (s->num_env)
- logeventf(ssh, "Sent %d environment variables", s->num_env);
- }
-
- /*
- * All CHANNEL_REQUESTs sent. Now collect up the replies. These
- * must be in precisely the same order as the requests.
*/
-
- if (s->requested_x11) {
- crWaitUntilV(pktin);
-
- if (pktin->type != SSH2_MSG_CHANNEL_SUCCESS) {
- if (pktin->type != SSH2_MSG_CHANNEL_FAILURE) {
- bombout(("Unexpected response to X11 forwarding request:"
- " packet type %d", pktin->type));
- crStopV;
- }
- logevent("X11 forwarding refused");
- } else {
- logevent("X11 forwarding enabled");
- ssh->X11_fwd_enabled = TRUE;
- }
- }
-
- if (s->requested_agent) {
- crWaitUntilV(pktin);
-
- if (pktin->type != SSH2_MSG_CHANNEL_SUCCESS) {
- if (pktin->type != SSH2_MSG_CHANNEL_FAILURE) {
- bombout(("Unexpected response to agent forwarding request:"
- " packet type %d", pktin->type));
- crStopV;
- }
- logevent("Agent forwarding refused");
- } else {
- logevent("Agent forwarding enabled");
- ssh->agentfwd_enabled = TRUE;
- }
- }
-
- if (s->requested_tty) {
- crWaitUntilV(pktin);
-
- if (pktin->type != SSH2_MSG_CHANNEL_SUCCESS) {
- if (pktin->type != SSH2_MSG_CHANNEL_FAILURE) {
- bombout(("Unexpected response to pty request:"
- " packet type %d", pktin->type));
- crStopV;
- }
- c_write_str(ssh, "Server refused to allocate pty\r\n");
- ssh->editing = ssh->echoing = 1;
- } else {
- logeventf(ssh, "Allocated pty (ospeed %dbps, ispeed %dbps)",
- ssh->ospeed, ssh->ispeed);
- ssh->got_pty = TRUE;
- }
- } else {
- ssh->editing = ssh->echoing = 1;
- }
-
- if (s->num_env) {
- s->env_ok = 0;
- s->env_left = s->num_env;
-
- while (s->env_left > 0) {
- crWaitUntilV(pktin);
-
- if (pktin->type != SSH2_MSG_CHANNEL_SUCCESS) {
- if (pktin->type != SSH2_MSG_CHANNEL_FAILURE) {
- bombout(("Unexpected response to environment request:"
- " packet type %d", pktin->type));
- crStopV;
- }
- } else {
- s->env_ok++;
- }
-
- s->env_left--;
- }
-
- if (s->env_ok == s->num_env) {
- logevent("All environment variables successfully set");
- } else if (s->env_ok == 0) {
- logevent("All environment variables refused");
- c_write_str(ssh, "Server refused to set environment variables\r\n");
- } else {
- logeventf(ssh, "%d environment variables refused",
- s->num_env - s->env_ok);
- c_write_str(ssh, "Server refused to set all environment variables\r\n");
- }
- }
+ ssh2_setup_env(ssh->mainchan, NULL, NULL);
/*
* Start a shell or a remote command. We may have to attempt
ssh2_pkt_addbool(s->pktout, 1); /* want reply */
}
ssh2_pkt_send(ssh, s->pktout);
+ ssh2_queue_chanreq_handler(ssh->mainchan, ssh2_response_authconn, NULL);
crWaitUntilV(pktin);
/*
* All the initial channel requests are done, so install the default
- * failure handler.
+ * response handler.
*/
- ssh->packet_dispatch[SSH2_MSG_CHANNEL_SUCCESS] = ssh2_msg_channel_success;
- ssh->packet_dispatch[SSH2_MSG_CHANNEL_FAILURE] = ssh2_msg_channel_failure;
+ ssh->packet_dispatch[SSH2_MSG_CHANNEL_SUCCESS] = ssh2_msg_channel_response;
+ ssh->packet_dispatch[SSH2_MSG_CHANNEL_FAILURE] = ssh2_msg_channel_response;
/*
* Transfer data!