X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=ssh.c;h=ad9ccae4235c6e38c5794e8bd803629dfaaea0a2;hb=3fa95b2a7fa8082ad0109959d601c9e664ecdf84;hp=4de58f9f2fc9661a9c34a430ac43263a252ff424;hpb=ab6d966f91ce694bbb66e73f50b6e869672f9e05;p=PuTTY.git diff --git a/ssh.c b/ssh.c index 4de58f9f..ad9ccae4 100644 --- a/ssh.c +++ b/ssh.c @@ -439,6 +439,8 @@ enum { #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__:;\ @@ -4244,6 +4246,7 @@ static void ssh_channel_try_eof(struct ssh_channel *c) 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); @@ -4254,17 +4257,8 @@ static void ssh_channel_try_eof(struct ssh_channel *c) 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) @@ -6599,6 +6593,7 @@ static void ssh2_queue_chanreq_handler(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; @@ -6609,6 +6604,33 @@ static void ssh2_queue_chanreq_handler(struct ssh_channel *c, 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. */ @@ -6658,15 +6680,12 @@ static void ssh2_set_window(struct ssh_channel *c, int newwin) */ 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 { @@ -6893,8 +6912,10 @@ static void ssh_channel_destroy(struct ssh_channel *c) } 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); /* @@ -6929,7 +6950,7 @@ static void ssh2_channel_check_close(struct ssh_channel *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. */ @@ -6940,6 +6961,7 @@ static void ssh2_channel_check_close(struct ssh_channel *c) } 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. @@ -7447,7 +7469,6 @@ static void ssh2_send_ttymode(void *data, char *mode, char *val) 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) { @@ -7467,10 +7488,8 @@ static void ssh2_maybe_setup_x11(struct ssh_channel *c, struct Packet *pktin, (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); /* @@ -7486,18 +7505,17 @@ static void ssh2_maybe_setup_x11(struct ssh_channel *c, struct Packet *pktin, 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) { - logevent("X11 forwarding enabled"); - ssh->X11_fwd_enabled = TRUE; - } else - logevent("X11 forwarding refused"); + 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, @@ -7514,24 +7532,21 @@ 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) { - logevent("Agent forwarding enabled"); - ssh->agentfwd_enabled = TRUE; - } else - logevent("Agent forwarding refused"); + 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, @@ -7552,10 +7567,8 @@ 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); @@ -7571,23 +7584,22 @@ static void ssh2_maybe_setup_pty(struct ssh_channel *c, struct Packet *pktin, 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) { - 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; + 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; + } } } else { ssh->editing = ssh->echoing = 1; } - sfree(s); - crFinishV; + crFinishFreeV(s); } static void ssh2_setup_env(struct ssh_channel *c, struct Packet *pktin, @@ -7616,14 +7628,10 @@ 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++; } @@ -7637,6 +7645,7 @@ static void ssh2_setup_env(struct ssh_channel *c, struct Packet *pktin, while (s->env_left > 0) { crWaitUntilV(pktin); + if (!pktin) goto out; if (pktin->type == SSH2_MSG_CHANNEL_SUCCESS) s->env_ok++; s->env_left--; @@ -7653,8 +7662,8 @@ static void ssh2_setup_env(struct ssh_channel *c, struct Packet *pktin, c_write_str(ssh, "Server refused to set all environment variables\r\n"); } } - sfree(s); - crFinishV; + out:; + crFinishFreeV(s); } /* @@ -9217,10 +9226,9 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, * 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); } @@ -9271,22 +9279,19 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, 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); @@ -9727,6 +9732,17 @@ static void ssh_free(void *handle) 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); @@ -9912,10 +9928,8 @@ static void ssh_size(void *handle, int width, int height) 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); @@ -10051,10 +10065,7 @@ static void ssh_special(void *handle, Telnet_Special code) 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); } @@ -10079,10 +10090,7 @@ static void ssh_special(void *handle, Telnet_Special code) 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);