#define crState(t) crStateP(t, ssh->t)
#define crFinish(z) } *crLine = 0; return (z); }
#define crFinishV } *crLine = 0; return; }
+#define crFinishFree(z, s) } *crLine = 0; sfree(s); return (z); }
+#define crFinishFreeV(s) } *crLine = 0; sfree(s); return; }
#define crReturn(z) \
do {\
*crLine =__LINE__; return (z); case __LINE__:;\
if (ssh->version == 2 && bufchain_size(&c->v.v2.outbuffer) > 0)
return; /* can't send EOF: pending outgoing data */
+ c->pending_eof = FALSE; /* we're about to send it */
if (ssh->version == 1) {
send_packet(ssh, SSH1_MSG_CHANNEL_CLOSE, PKT_INT, c->remoteid,
PKT_END);
ssh2_pkt_adduint32(pktout, c->remoteid);
ssh2_pkt_send(ssh, pktout);
c->closes |= CLOSES_SENT_EOF;
- if (!((CLOSES_SENT_EOF | CLOSES_RCVD_EOF) & ~c->closes)) {
- /*
- * Also send MSG_CLOSE.
- */
- pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_CLOSE);
- ssh2_pkt_adduint32(pktout, c->remoteid);
- ssh2_pkt_send(ssh, pktout);
- c->closes |= CLOSES_SENT_CLOSE;
- }
+ ssh2_channel_check_close(c);
}
- c->pending_eof = FALSE; /* we've sent it now */
}
void sshfwd_write_eof(struct ssh_channel *c)
struct outstanding_channel_request *ocr =
snew(struct outstanding_channel_request);
+ assert(!(c->closes & (CLOSES_SENT_CLOSE | CLOSES_RCVD_CLOSE)));
ocr->handler = handler;
ocr->ctx = ctx;
ocr->next = NULL;
c->v.v2.chanreq_tail = ocr;
}
+/*
+ * Construct the common parts of a CHANNEL_REQUEST. If handler is not
+ * NULL then a reply will be requested and the handler will be called
+ * when it arrives. The returned packet is ready to have any
+ * request-specific data added and be sent. Note that if a handler is
+ * provided, it's essential that the request actually be sent.
+ *
+ * The handler will usually be passed the response packet in pktin.
+ * If pktin is NULL, this means that no reply will ever be forthcoming
+ * (e.g. because the entire connection is being destroyed) and the
+ * handler should free any storage it's holding.
+ */
+static struct Packet *ssh2_chanreq_init(struct ssh_channel *c, char *type,
+ cchandler_fn_t handler, void *ctx)
+{
+ struct Packet *pktout;
+
+ assert(!(c->closes & (CLOSES_SENT_CLOSE | CLOSES_RCVD_CLOSE)));
+ pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);
+ ssh2_pkt_adduint32(pktout, c->remoteid);
+ ssh2_pkt_addstring(pktout, type);
+ ssh2_pkt_addbool(pktout, handler != NULL);
+ if (handler != NULL)
+ ssh2_queue_chanreq_handler(c, handler, ctx);
+ return pktout;
+}
+
/*
* Potentially enlarge the window on an SSH-2 channel.
*/
*/
if (newwin == c->v.v2.locmaxwin &&
!(ssh->remote_bugs & BUG_CHOKES_ON_WINADJ)) {
- pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);
- ssh2_pkt_adduint32(pktout, c->remoteid);
- ssh2_pkt_addstring(pktout, "winadj@putty.projects.tartarus.org");
- ssh2_pkt_addbool(pktout, TRUE);
- ssh2_pkt_send(ssh, pktout);
-
up = snew(unsigned);
*up = newwin - c->v.v2.locwindow;
- ssh2_queue_chanreq_handler(c, ssh2_handle_winadj_response, up);
+ pktout = ssh2_chanreq_init(c, "winadj@putty.projects.tartarus.org",
+ ssh2_handle_winadj_response, up);
+ ssh2_pkt_send(ssh, pktout);
+
if (c->v.v2.throttle_state != UNTHROTTLED)
c->v.v2.throttle_state = UNTHROTTLING;
} else {
}
del234(ssh->channels, c);
- if (ssh->version == 2)
+ if (ssh->version == 2) {
bufchain_clear(&c->v.v2.outbuffer);
+ assert(c->v.v2.chanreq_head == NULL);
+ }
sfree(c);
/*
== (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
+ * outstanding channel requests, which means the
* channel is in final wind-up. But we haven't sent CLOSE, so
* let's do so now.
*/
}
if (!((CLOSES_SENT_CLOSE | CLOSES_RCVD_CLOSE) & ~c->closes)) {
+ assert(c->v.v2.chanreq_head == NULL);
/*
* We have both sent and received CLOSE, which means we're
* completely done with the channel.
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)
{
(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 */
+ pktout = ssh2_chanreq_init(ssh->mainchan, "x11-req",
+ ssh2_maybe_setup_x11, s);
ssh2_pkt_addbool(pktout, 0); /* many connections */
ssh2_pkt_addstring(pktout, ssh->x11disp->remoteauthprotoname);
/*
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;
+ if (pktin) {
+ if (pktin->type == SSH2_MSG_CHANNEL_SUCCESS) {
+ logevent("X11 forwarding enabled");
+ ssh->X11_fwd_enabled = TRUE;
+ } else
+ logevent("X11 forwarding refused");
}
}
- sfree(s);
- crFinishV;
+ crFinishFreeV(s);
}
static void ssh2_maybe_setup_agent(struct ssh_channel *c, struct Packet *pktin,
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 */
+ pktout = ssh2_chanreq_init(ssh->mainchan, "auth-agent-req@openssh.com",
+ ssh2_maybe_setup_agent, s);
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;
+ if (pktin) {
+ if (pktin->type == SSH2_MSG_CHANNEL_SUCCESS) {
+ logevent("Agent forwarding enabled");
+ ssh->agentfwd_enabled = TRUE;
+ } else
+ logevent("Agent forwarding refused");
}
}
- sfree(s);
- crFinishV;
+ crFinishFreeV(s);
}
static void ssh2_maybe_setup_pty(struct ssh_channel *c, struct Packet *pktin,
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 */
+ pktout = ssh2_chanreq_init(ssh->mainchan, "pty-req",
+ ssh2_maybe_setup_pty, s);
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_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;
+ if (pktin) {
+ if (pktin->type == SSH2_MSG_CHANNEL_SUCCESS) {
+ logeventf(ssh, "Allocated pty (ospeed %dbps, ispeed %dbps)",
+ ssh->ospeed, ssh->ispeed);
+ ssh->got_pty = TRUE;
+ } else {
+ c_write_str(ssh, "Server refused to allocate pty\r\n");
+ ssh->editing = ssh->echoing = 1;
}
- 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;
+ crFinishFreeV(s);
}
static void ssh2_setup_env(struct ssh_channel *c, struct Packet *pktin,
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 */
+ pktout = ssh2_chanreq_init(ssh->mainchan, "env", ssh2_setup_env, s);
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++;
}
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 {
+ if (!pktin) goto out;
+ if (pktin->type == SSH2_MSG_CHANNEL_SUCCESS)
s->env_ok++;
- }
-
s->env_left--;
}
c_write_str(ssh, "Server refused to set all environment variables\r\n");
}
}
- sfree(s);
- crFinishV;
+ out:;
+ crFinishFreeV(s);
}
/*
* this one, so it's safe for it to advertise a very large
* window and leave the flow control to TCP.
*/
- s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);
- ssh2_pkt_adduint32(s->pktout, ssh->mainchan->remoteid);
- ssh2_pkt_addstring(s->pktout, "simple@putty.projects.tartarus.org");
- ssh2_pkt_addbool(s->pktout, 0); /* no reply */
+ s->pktout = ssh2_chanreq_init(ssh->mainchan,
+ "simple@putty.projects.tartarus.org",
+ NULL, NULL);
ssh2_pkt_send(ssh, s->pktout);
}
cmd = conf_get_str(ssh->conf, CONF_remote_cmd);
}
- s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);
- ssh2_pkt_adduint32(s->pktout, ssh->mainchan->remoteid); /* recipient channel */
if (subsys) {
- ssh2_pkt_addstring(s->pktout, "subsystem");
- ssh2_pkt_addbool(s->pktout, 1); /* want reply */
+ s->pktout = ssh2_chanreq_init(ssh->mainchan, "subsystem",
+ ssh2_response_authconn, NULL);
ssh2_pkt_addstring(s->pktout, cmd);
} else if (*cmd) {
- ssh2_pkt_addstring(s->pktout, "exec");
- ssh2_pkt_addbool(s->pktout, 1); /* want reply */
+ s->pktout = ssh2_chanreq_init(ssh->mainchan, "exec",
+ ssh2_response_authconn, NULL);
ssh2_pkt_addstring(s->pktout, cmd);
} else {
- ssh2_pkt_addstring(s->pktout, "shell");
- ssh2_pkt_addbool(s->pktout, 1); /* want reply */
+ s->pktout = ssh2_chanreq_init(ssh->mainchan, "shell",
+ ssh2_response_authconn, NULL);
}
ssh2_pkt_send(ssh, s->pktout);
- ssh2_queue_chanreq_handler(ssh->mainchan, ssh2_response_authconn, NULL);
crWaitUntilV(pktin);
pfd_close(c->u.pfd.s);
break;
}
+ if (ssh->version == 2) {
+ struct outstanding_channel_request *ocr, *nocr;
+ ocr = c->v.v2.chanreq_head;
+ while (ocr) {
+ ocr->handler(c, NULL, ocr->ctx);
+ nocr = ocr->next;
+ sfree(ocr);
+ ocr = nocr;
+ }
+ bufchain_clear(&c->v.v2.outbuffer);
+ }
sfree(c);
}
freetree234(ssh->channels);
PKT_INT, ssh->term_width,
PKT_INT, 0, PKT_INT, 0, PKT_END);
} else if (ssh->mainchan) {
- pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);
- ssh2_pkt_adduint32(pktout, ssh->mainchan->remoteid);
- ssh2_pkt_addstring(pktout, "window-change");
- ssh2_pkt_addbool(pktout, 0);
+ pktout = ssh2_chanreq_init(ssh->mainchan, "window-change",
+ NULL, NULL);
ssh2_pkt_adduint32(pktout, ssh->term_width);
ssh2_pkt_adduint32(pktout, ssh->term_height);
ssh2_pkt_adduint32(pktout, 0);
if (ssh->version == 1) {
logevent("Unable to send BREAK signal in SSH-1");
} else if (ssh->mainchan) {
- pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);
- ssh2_pkt_adduint32(pktout, ssh->mainchan->remoteid);
- ssh2_pkt_addstring(pktout, "break");
- ssh2_pkt_addbool(pktout, 0);
+ pktout = ssh2_chanreq_init(ssh->mainchan, "break", NULL, NULL);
ssh2_pkt_adduint32(pktout, 0); /* default break length */
ssh2_pkt_send(ssh, pktout);
}
if (signame) {
/* It's a signal. */
if (ssh->version == 2 && ssh->mainchan) {
- pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);
- ssh2_pkt_adduint32(pktout, ssh->mainchan->remoteid);
- ssh2_pkt_addstring(pktout, "signal");
- ssh2_pkt_addbool(pktout, 0);
+ pktout = ssh2_chanreq_init(ssh->mainchan, "signal", NULL, NULL);
ssh2_pkt_addstring(pktout, signame);
ssh2_pkt_send(ssh, pktout);
logeventf(ssh, "Sent signal SIG%s", signame);