Factor out some common code for constructing SSH2_CHANNEL_OPEN.
[sgt/putty] / ssh.c
diff --git a/ssh.c b/ssh.c
index 8b73da4..b4d3884 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -589,14 +589,6 @@ struct outstanding_channel_request {
 };
 
 /*
- * little structure to keep track of outstanding WINDOW_ADJUSTs
- */
-struct winadj {
-    struct winadj *next;
-    unsigned size;
-};
-
-/*
  * 2-3-4 tree storing channels.
  */
 struct ssh_channel {
@@ -6580,6 +6572,21 @@ static void ssh2_channel_init(struct ssh_channel *c)
 }
 
 /*
+ * Construct the common parts of a CHANNEL_OPEN.
+ */
+static struct Packet *ssh2_chanopen_init(struct ssh_channel *c, char *type)
+{
+    struct Packet *pktout;
+
+    pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN);
+    ssh2_pkt_addstring(pktout, type);
+    ssh2_pkt_adduint32(pktout, c->localid);
+    ssh2_pkt_adduint32(pktout, c->v.v2.locwindow);/* our window size */
+    ssh2_pkt_adduint32(pktout, OUR_V2_MAXPKT);      /* our max pkt size */
+    return 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.
@@ -7468,136 +7475,126 @@ static void ssh2_send_ttymode(void *data, char *mode, char *val)
     ssh2_pkt_adduint32(pktout, arg);
 }
 
-static void ssh2_maybe_setup_x11(struct ssh_channel *c, struct Packet *pktin,
-                                void *ctx)
+static void ssh2_setup_x11(struct ssh_channel *c, struct Packet *pktin,
+                           void *ctx)
 {
-    struct ssh2_maybe_setup_x11_state {
+    struct ssh2_setup_x11_state {
        int crLine;
     };
     Ssh ssh = c->ssh;
     struct Packet *pktout;
-    crStateP(ssh2_maybe_setup_x11_state, ctx);
+    crStateP(ssh2_setup_x11_state, ctx);
 
     crBeginState;
 
+    logevent("Requesting X11 forwarding");
+    pktout = ssh2_chanreq_init(ssh->mainchan, "x11-req",
+                               ssh2_setup_x11, s);
+    ssh2_pkt_addbool(pktout, 0);              /* many connections */
+    ssh2_pkt_addstring(pktout, ssh->x11disp->remoteauthprotoname);
     /*
-     * Potentially enable X11 forwarding.
+     * 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.
      */
-    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_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);
-       /*
-        * 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);
+    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);
 
-       crWaitUntilV(pktin);
+    crWaitUntilV(pktin);
 
-       if (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");
     }
+
     crFinishFreeV;
 }
 
-static void ssh2_maybe_setup_agent(struct ssh_channel *c, struct Packet *pktin,
+static void ssh2_setup_agent(struct ssh_channel *c, struct Packet *pktin,
                                   void *ctx)
 {
-    struct ssh2_maybe_setup_agent_state {
+    struct ssh2_setup_agent_state {
        int crLine;
     };
     Ssh ssh = c->ssh;
     struct Packet *pktout;
-    crStateP(ssh2_maybe_setup_agent_state, ctx);
+    crStateP(ssh2_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_chanreq_init(ssh->mainchan, "auth-agent-req@openssh.com",
-                                  ssh2_maybe_setup_agent, s);
-       ssh2_pkt_send(ssh, pktout);
+    logevent("Requesting OpenSSH-style agent forwarding");
+    pktout = ssh2_chanreq_init(ssh->mainchan, "auth-agent-req@openssh.com",
+                               ssh2_setup_agent, s);
+    ssh2_pkt_send(ssh, pktout);
 
-       crWaitUntilV(pktin);
+    crWaitUntilV(pktin);
 
-       if (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");
     }
+
     crFinishFreeV;
 }
 
-static void ssh2_maybe_setup_pty(struct ssh_channel *c, struct Packet *pktin,
+static void ssh2_setup_pty(struct ssh_channel *c, struct Packet *pktin,
                                 void *ctx)
 {
-    struct ssh2_maybe_setup_pty_state {
+    struct ssh2_setup_pty_state {
        int crLine;
     };
     Ssh ssh = c->ssh;
     struct Packet *pktout;
-    crStateP(ssh2_maybe_setup_pty_state, ctx);
+    crStateP(ssh2_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_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_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;
+    /* 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_chanreq_init(ssh->mainchan, "pty-req",
+                               ssh2_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_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;
 
-       crWaitUntilV(pktin);
+    crWaitUntilV(pktin);
 
-       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;
+    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;
+        }
     }
+
     crFinishFreeV;
 }
 
@@ -7621,7 +7618,7 @@ static void ssh2_setup_env(struct ssh_channel *c, struct Packet *pktin,
      * 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);
@@ -9131,11 +9128,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
                  "Opening direct-tcpip channel to %s:%d in place of session",
                  conf_get_str(ssh->conf, CONF_ssh_nc_host),
                  conf_get_int(ssh->conf, CONF_ssh_nc_port));
-       s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN);
-       ssh2_pkt_addstring(s->pktout, "direct-tcpip");
-       ssh2_pkt_adduint32(s->pktout, ssh->mainchan->localid);
-       ssh2_pkt_adduint32(s->pktout, ssh->mainchan->v.v2.locwindow);/* our window size */
-       ssh2_pkt_adduint32(s->pktout, OUR_V2_MAXPKT);      /* our max pkt size */
+       s->pktout = ssh2_chanopen_init(ssh->mainchan, "direct-tcpip");
        ssh2_pkt_addstring(s->pktout, conf_get_str(ssh->conf, CONF_ssh_nc_host));
        ssh2_pkt_adduint32(s->pktout, conf_get_int(ssh->conf, CONF_ssh_nc_port));
        /*
@@ -9170,11 +9163,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
        ssh->mainchan = snew(struct ssh_channel);
        ssh->mainchan->ssh = ssh;
        ssh2_channel_init(ssh->mainchan);
-       s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN);
-       ssh2_pkt_addstring(s->pktout, "session");
-       ssh2_pkt_adduint32(s->pktout, ssh->mainchan->localid);
-       ssh2_pkt_adduint32(s->pktout, ssh->mainchan->v.v2.locwindow);/* our window size */
-       ssh2_pkt_adduint32(s->pktout, OUR_V2_MAXPKT);    /* our max pkt size */
+       s->pktout = ssh2_chanopen_init(ssh->mainchan, "session");
        ssh2_pkt_send(ssh, s->pktout);
        crWaitUntilV(pktin);
        if (pktin->type != SSH2_MSG_CHANNEL_OPEN_CONFIRMATION) {
@@ -9236,88 +9225,92 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
      */
     ssh_setup_portfwd(ssh, ssh->conf);
 
-    /*
-     * Send the CHANNEL_REQUESTS for the main channel.  Each one is
-     * handled by its own little asynchronous co-routine.
-     */
+    if (ssh->mainchan && !ssh->ncmode) {
+       /*
+        * Send the CHANNEL_REQUESTS for the main session channel.
+        * Each one is handled by its own little asynchronous
+        * co-routine.
+        */
 
-    /*
-     * Potentially enable X11 forwarding.
-     */
-    ssh2_maybe_setup_x11(ssh->mainchan, NULL, NULL);
+       /* Potentially enable X11 forwarding. */
+       if (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)))
+           ssh2_setup_x11(ssh->mainchan, NULL, NULL);
 
-    /*
-     * Potentially enable agent forwarding.
-     */
-    ssh2_maybe_setup_agent(ssh->mainchan, NULL, NULL);
+       /* Potentially enable agent forwarding. */
+       if (conf_get_int(ssh->conf, CONF_agentfwd) && agent_exists())
+           ssh2_setup_agent(ssh->mainchan, NULL, NULL);
 
-    /*
-     * Now allocate a pty for the session.
-     */
-    ssh2_maybe_setup_pty(ssh->mainchan, NULL, NULL);
+       /* Now allocate a pty for the session. */
+       if (!conf_get_int(ssh->conf, CONF_nopty))
+           ssh2_setup_pty(ssh->mainchan, NULL, NULL);
 
-    /*
-     * Send environment variables.
-     */
-    ssh2_setup_env(ssh->mainchan, NULL, NULL);
+       /* Send environment variables. */
+       ssh2_setup_env(ssh->mainchan, NULL, NULL);
 
-    /*
-     * Start a shell or a remote command. We may have to attempt
-     * this twice if the config data has provided a second choice
-     * of command.
-     */
-    if (ssh->mainchan && !ssh->ncmode) while (1) {
-       int subsys;
-       char *cmd;
+       /*
+        * Start a shell or a remote command. We may have to attempt
+        * this twice if the config data has provided a second choice
+        * of command.
+        */
+       while (1) {
+           int subsys;
+           char *cmd;
 
-       if (ssh->fallback_cmd) {
-           subsys = conf_get_int(ssh->conf, CONF_ssh_subsys2);
-           cmd = conf_get_str(ssh->conf, CONF_remote_cmd2);
-       } else {
-           subsys = conf_get_int(ssh->conf, CONF_ssh_subsys);
-           cmd = conf_get_str(ssh->conf, CONF_remote_cmd);
-       }
+           if (ssh->fallback_cmd) {
+               subsys = conf_get_int(ssh->conf, CONF_ssh_subsys2);
+               cmd = conf_get_str(ssh->conf, CONF_remote_cmd2);
+           } else {
+               subsys = conf_get_int(ssh->conf, CONF_ssh_subsys);
+               cmd = conf_get_str(ssh->conf, CONF_remote_cmd);
+           }
 
-       if (subsys) {
-           s->pktout = ssh2_chanreq_init(ssh->mainchan, "subsystem",
-                                         ssh2_response_authconn, NULL);
-           ssh2_pkt_addstring(s->pktout, cmd);
-       } else if (*cmd) {
-           s->pktout = ssh2_chanreq_init(ssh->mainchan, "exec",
-                                         ssh2_response_authconn, NULL);
-           ssh2_pkt_addstring(s->pktout, cmd);
-       } else {
-           s->pktout = ssh2_chanreq_init(ssh->mainchan, "shell",
-                                         ssh2_response_authconn, NULL);
-       }
-       ssh2_pkt_send(ssh, s->pktout);
+           if (subsys) {
+               s->pktout = ssh2_chanreq_init(ssh->mainchan, "subsystem",
+                                             ssh2_response_authconn, NULL);
+               ssh2_pkt_addstring(s->pktout, cmd);
+           } else if (*cmd) {
+               s->pktout = ssh2_chanreq_init(ssh->mainchan, "exec",
+                                             ssh2_response_authconn, NULL);
+               ssh2_pkt_addstring(s->pktout, cmd);
+           } else {
+               s->pktout = ssh2_chanreq_init(ssh->mainchan, "shell",
+                                             ssh2_response_authconn, NULL);
+           }
+           ssh2_pkt_send(ssh, s->pktout);
 
-       crWaitUntilV(pktin);
+           crWaitUntilV(pktin);
 
-       if (pktin->type != SSH2_MSG_CHANNEL_SUCCESS) {
-           if (pktin->type != SSH2_MSG_CHANNEL_FAILURE) {
-               bombout(("Unexpected response to shell/command request:"
-                        " packet type %d", pktin->type));
+           if (pktin->type != SSH2_MSG_CHANNEL_SUCCESS) {
+               if (pktin->type != SSH2_MSG_CHANNEL_FAILURE) {
+                   bombout(("Unexpected response to shell/command request:"
+                            " packet type %d", pktin->type));
+                   crStopV;
+               }
+               /*
+                * We failed to start the command. If this is the
+                * fallback command, we really are finished; if it's
+                * not, and if the fallback command exists, try falling
+                * back to it before complaining.
+                */
+               if (!ssh->fallback_cmd &&
+                   *conf_get_str(ssh->conf, CONF_remote_cmd2)) {
+                   logevent("Primary command failed; attempting fallback");
+                   ssh->fallback_cmd = TRUE;
+                   continue;
+               }
+               bombout(("Server refused to start a shell/command"));
                crStopV;
+           } else {
+               logevent("Started a shell/command");
            }
-           /*
-            * We failed to start the command. If this is the
-            * fallback command, we really are finished; if it's
-            * not, and if the fallback command exists, try falling
-            * back to it before complaining.
-            */
-           if (!ssh->fallback_cmd &&
-               *conf_get_str(ssh->conf, CONF_remote_cmd2)) {
-               logevent("Primary command failed; attempting fallback");
-               ssh->fallback_cmd = TRUE;
-               continue;
-           }
-           bombout(("Server refused to start a shell/command"));
-           crStopV;
-       } else {
-           logevent("Started a shell/command");
+           break;
        }
-       break;
+    } else {
+       ssh->editing = ssh->echoing = TRUE;
     }
 
     ssh->state = SSH_STATE_SESSION;
@@ -9327,13 +9320,6 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
        ssh_special(ssh, TS_EOF);
 
     /*
-     * All the initial channel requests are done, so install the default
-     * response handler.
-     */
-    ssh->packet_dispatch[SSH2_MSG_CHANNEL_SUCCESS] = ssh2_msg_channel_response;
-    ssh->packet_dispatch[SSH2_MSG_CHANNEL_FAILURE] = ssh2_msg_channel_response;
-
-    /*
      * Transfer data!
      */
     if (ssh->ldisc)
@@ -10168,11 +10154,7 @@ void ssh_send_port_open(void *channel, char *hostname, int port, char *org)
                    /* PKT_STR, <org:orgport>, */
                    PKT_END);
     } else {
-       pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN);
-       ssh2_pkt_addstring(pktout, "direct-tcpip");
-       ssh2_pkt_adduint32(pktout, c->localid);
-       ssh2_pkt_adduint32(pktout, c->v.v2.locwindow);/* our window size */
-       ssh2_pkt_adduint32(pktout, OUR_V2_MAXPKT);      /* our max pkt size */
+       pktout = ssh2_chanopen_init(c, "direct-tcpip");
        ssh2_pkt_addstring(pktout, hostname);
        ssh2_pkt_adduint32(pktout, port);
        /*