+ }
+ }
+ sfree(sportdesc);
+ sfree(dportdesc);
+ }
+}
+
+static void ssh1_smsg_stdout_stderr_data(Ssh ssh, struct Packet *pktin)
+{
+ char *string;
+ int stringlen, bufsize;
+
+ ssh_pkt_getstring(pktin, &string, &stringlen);
+ if (string == NULL) {
+ bombout(("Incoming terminal data packet was badly formed"));
+ return;
+ }
+
+ bufsize = from_backend(ssh->frontend, pktin->type == SSH1_SMSG_STDERR_DATA,
+ string, stringlen);
+ if (!ssh->v1_stdout_throttling && bufsize > SSH1_BUFFER_LIMIT) {
+ ssh->v1_stdout_throttling = 1;
+ ssh1_throttle(ssh, +1);
+ }
+}
+
+static void ssh1_smsg_x11_open(Ssh ssh, struct Packet *pktin)
+{
+ /* Remote side is trying to open a channel to talk to our
+ * X-Server. Give them back a local channel number. */
+ struct ssh_channel *c;
+ int remoteid = ssh_pkt_getuint32(pktin);
+
+ logevent("Received X11 connect request");
+ /* Refuse if X11 forwarding is disabled. */
+ if (!ssh->X11_fwd_enabled) {
+ send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE,
+ PKT_INT, remoteid, PKT_END);
+ logevent("Rejected X11 connect request");
+ } else {
+ c = snew(struct ssh_channel);
+ c->ssh = ssh;
+
+ if (x11_init(&c->u.x11.s, ssh->cfg.x11_display, c,
+ ssh->x11auth, NULL, -1, &ssh->cfg) != NULL) {
+ logevent("Opening X11 forward connection failed");
+ sfree(c);
+ send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE,
+ PKT_INT, remoteid, PKT_END);
+ } else {
+ logevent
+ ("Opening X11 forward connection succeeded");
+ c->remoteid = remoteid;
+ c->localid = alloc_channel_id(ssh);
+ c->closes = 0;
+ c->v.v1.throttling = 0;
+ c->type = CHAN_X11; /* identify channel type */
+ add234(ssh->channels, c);
+ send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION,
+ PKT_INT, c->remoteid, PKT_INT,
+ c->localid, PKT_END);
+ logevent("Opened X11 forward channel");
+ }
+ }
+}
+
+static void ssh1_smsg_agent_open(Ssh ssh, struct Packet *pktin)
+{
+ /* Remote side is trying to open a channel to talk to our
+ * agent. Give them back a local channel number. */
+ struct ssh_channel *c;
+ int remoteid = ssh_pkt_getuint32(pktin);
+
+ /* Refuse if agent forwarding is disabled. */
+ if (!ssh->agentfwd_enabled) {
+ send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE,
+ PKT_INT, remoteid, PKT_END);
+ } else {
+ c = snew(struct ssh_channel);
+ c->ssh = ssh;
+ c->remoteid = remoteid;
+ c->localid = alloc_channel_id(ssh);
+ c->closes = 0;
+ c->v.v1.throttling = 0;
+ c->type = CHAN_AGENT; /* identify channel type */
+ c->u.a.lensofar = 0;
+ add234(ssh->channels, c);
+ send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION,
+ PKT_INT, c->remoteid, PKT_INT, c->localid,
+ PKT_END);
+ }
+}
+
+static void ssh1_msg_port_open(Ssh ssh, struct Packet *pktin)
+{
+ /* Remote side is trying to open a channel to talk to a
+ * forwarded port. Give them back a local channel number. */
+ struct ssh_channel *c;
+ struct ssh_rportfwd pf, *pfp;
+ int remoteid;
+ int hostsize, port;
+ char *host, buf[1024];
+ const char *e;
+ c = snew(struct ssh_channel);
+ c->ssh = ssh;
+
+ remoteid = ssh_pkt_getuint32(pktin);
+ ssh_pkt_getstring(pktin, &host, &hostsize);
+ port = ssh_pkt_getuint32(pktin);
+
+ if (hostsize >= lenof(pf.dhost))
+ hostsize = lenof(pf.dhost)-1;
+ memcpy(pf.dhost, host, hostsize);
+ pf.dhost[hostsize] = '\0';
+ pf.dport = port;
+ pfp = find234(ssh->rportfwds, &pf, NULL);
+
+ if (pfp == NULL) {
+ sprintf(buf, "Rejected remote port open request for %s:%d",
+ pf.dhost, port);
+ logevent(buf);
+ send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE,
+ PKT_INT, remoteid, PKT_END);
+ } else {
+ sprintf(buf, "Received remote port open request for %s:%d",
+ pf.dhost, port);
+ logevent(buf);
+ e = pfd_newconnect(&c->u.pfd.s, pf.dhost, port,
+ c, &ssh->cfg, pfp->pfrec->addressfamily);
+ if (e != NULL) {
+ char buf[256];
+ sprintf(buf, "Port open failed: %s", e);
+ logevent(buf);
+ sfree(c);
+ send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE,
+ PKT_INT, remoteid, PKT_END);
+ } else {
+ c->remoteid = remoteid;
+ c->localid = alloc_channel_id(ssh);
+ c->closes = 0;
+ c->v.v1.throttling = 0;
+ c->type = CHAN_SOCKDATA; /* identify channel type */
+ add234(ssh->channels, c);
+ send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION,
+ PKT_INT, c->remoteid, PKT_INT,
+ c->localid, PKT_END);
+ logevent("Forwarded port opened successfully");
+ }
+ }
+}
+
+static void ssh1_msg_channel_open_confirmation(Ssh ssh, struct Packet *pktin)
+{
+ unsigned int remoteid = ssh_pkt_getuint32(pktin);
+ unsigned int localid = ssh_pkt_getuint32(pktin);
+ struct ssh_channel *c;
+
+ c = find234(ssh->channels, &remoteid, ssh_channelfind);
+ if (c && c->type == CHAN_SOCKDATA_DORMANT) {
+ c->remoteid = localid;
+ c->type = CHAN_SOCKDATA;
+ c->v.v1.throttling = 0;
+ pfd_confirm(c->u.pfd.s);
+ }
+
+ if (c && c->closes) {
+ /*
+ * We have a pending close on this channel,
+ * which we decided on before the server acked
+ * the channel open. So now we know the
+ * remoteid, we can close it again.
+ */
+ send_packet(ssh, SSH1_MSG_CHANNEL_CLOSE,
+ PKT_INT, c->remoteid, PKT_END);
+ }
+}
+
+static void ssh1_msg_channel_open_failure(Ssh ssh, struct Packet *pktin)
+{
+ unsigned int remoteid = ssh_pkt_getuint32(pktin);
+ struct ssh_channel *c;
+
+ c = find234(ssh->channels, &remoteid, ssh_channelfind);
+ if (c && c->type == CHAN_SOCKDATA_DORMANT) {
+ logevent("Forwarded connection refused by server");
+ pfd_close(c->u.pfd.s);
+ del234(ssh->channels, c);
+ sfree(c);
+ }
+}
+
+static void ssh1_msg_channel_close(Ssh ssh, struct Packet *pktin)
+{
+ /* Remote side closes a channel. */
+ unsigned i = ssh_pkt_getuint32(pktin);
+ struct ssh_channel *c;
+ c = find234(ssh->channels, &i, ssh_channelfind);
+ if (c && ((int)c->remoteid) != -1) {
+ int closetype;
+ closetype =
+ (pktin->type == SSH1_MSG_CHANNEL_CLOSE ? 1 : 2);
+
+ if ((c->closes == 0) && (c->type == CHAN_X11)) {
+ logevent("Forwarded X11 connection terminated");
+ assert(c->u.x11.s != NULL);
+ x11_close(c->u.x11.s);
+ c->u.x11.s = NULL;
+ }
+ if ((c->closes == 0) && (c->type == CHAN_SOCKDATA)) {
+ logevent("Forwarded port closed");
+ assert(c->u.pfd.s != NULL);
+ pfd_close(c->u.pfd.s);
+ c->u.pfd.s = NULL;
+ }
+
+ c->closes |= (closetype << 2); /* seen this message */
+ if (!(c->closes & closetype)) {
+ send_packet(ssh, pktin->type, PKT_INT, c->remoteid,
+ PKT_END);
+ c->closes |= closetype; /* sent it too */
+ }
+
+ if (c->closes == 15) {
+ del234(ssh->channels, c);
+ sfree(c);
+ }
+ } else {
+ bombout(("Received CHANNEL_CLOSE%s for %s channel %d\n",
+ pktin->type == SSH1_MSG_CHANNEL_CLOSE ? "" :
+ "_CONFIRMATION", c ? "half-open" : "nonexistent",
+ i));
+ }
+}
+
+static void ssh1_msg_channel_data(Ssh ssh, struct Packet *pktin)
+{
+ /* Data sent down one of our channels. */
+ int i = ssh_pkt_getuint32(pktin);
+ char *p;
+ unsigned int len;
+ struct ssh_channel *c;
+
+ ssh_pkt_getstring(pktin, &p, &len);
+
+ c = find234(ssh->channels, &i, ssh_channelfind);
+ if (c) {
+ int bufsize = 0;
+ switch (c->type) {
+ case CHAN_X11:
+ bufsize = x11_send(c->u.x11.s, p, len);
+ break;
+ case CHAN_SOCKDATA:
+ bufsize = pfd_send(c->u.pfd.s, p, len);
+ break;
+ case CHAN_AGENT:
+ /* Data for an agent message. Buffer it. */
+ while (len > 0) {
+ if (c->u.a.lensofar < 4) {
+ unsigned int l = min(4 - c->u.a.lensofar, len);
+ memcpy(c->u.a.msglen + c->u.a.lensofar, p,
+ l);
+ p += l;
+ len -= l;
+ c->u.a.lensofar += l;
+ }
+ if (c->u.a.lensofar == 4) {
+ c->u.a.totallen =
+ 4 + GET_32BIT(c->u.a.msglen);
+ c->u.a.message = snewn(c->u.a.totallen,
+ unsigned char);
+ memcpy(c->u.a.message, c->u.a.msglen, 4);
+ }
+ if (c->u.a.lensofar >= 4 && len > 0) {
+ unsigned int l =
+ min(c->u.a.totallen - c->u.a.lensofar,
+ len);
+ memcpy(c->u.a.message + c->u.a.lensofar, p,
+ l);
+ p += l;
+ len -= l;
+ c->u.a.lensofar += l;
+ }
+ if (c->u.a.lensofar == c->u.a.totallen) {
+ void *reply;
+ int replylen;
+ if (agent_query(c->u.a.message,
+ c->u.a.totallen,
+ &reply, &replylen,
+ ssh_agentf_callback, c))
+ ssh_agentf_callback(c, reply, replylen);
+ sfree(c->u.a.message);