Put the \001 prefix back on scp error messages when they're sent to
[u/mdw/putty] / ssh.c
diff --git a/ssh.c b/ssh.c
index e6b0bcc..f48d142 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -17,7 +17,7 @@
 
 #define logevent(s) { logevent(s); \
                       if ((flags & FLAG_STDERR) && (flags & FLAG_VERBOSE)) \
-                      fprintf(stderr, "%s\n", s); }
+                      { fprintf(stderr, "%s\n", s); fflush(stderr); } }
 
 #define bombout(msg) ( ssh_state = SSH_STATE_CLOSED, \
                           (s ? sk_close(s), s = NULL : 0), \
@@ -365,6 +365,42 @@ static int ssh_channelfind(void *av, void *bv) {
     return 0;
 }
 
+static int alloc_channel_id(void) {
+    const unsigned CHANNEL_NUMBER_OFFSET = 256;
+    unsigned low, high, mid;
+    int tsize;
+    struct ssh_channel *c;
+
+    /*
+     * First-fit allocation of channel numbers: always pick the
+     * lowest unused one. To do this, binary-search using the
+     * counted B-tree to find the largest channel ID which is in a
+     * contiguous sequence from the beginning. (Precisely
+     * everything in that sequence must have ID equal to its tree
+     * index plus CHANNEL_NUMBER_OFFSET.)
+     */
+    tsize = count234(ssh_channels);
+
+    low = -1; high = tsize;
+    while (high - low > 1) {
+       mid = (high + low) / 2;
+       c = index234(ssh_channels, mid);
+       if (c->localid == mid + CHANNEL_NUMBER_OFFSET)
+           low = mid;                 /* this one is fine */
+       else
+           high = mid;                /* this one is past it */
+    }
+    /*
+     * Now low points to either -1, or the tree index of the
+     * largest ID in the initial sequence.
+     */
+    {
+       unsigned i = low + 1 + CHANNEL_NUMBER_OFFSET;
+       assert(NULL == find234(ssh_channels, &i, ssh_channelfind));
+    }
+    return low + 1 + CHANNEL_NUMBER_OFFSET;
+}
+
 static void c_write (char *buf, int len) {
     if ((flags & FLAG_STDERR)) {
         int i;
@@ -536,8 +572,8 @@ next_packet:
     if (pktin.type == SSH1_MSG_DISCONNECT) {
        /* log reason code in disconnect message */
        char buf[256];
-       int msglen = GET_32BIT(pktin.body);
-       int nowlen;
+       unsigned msglen = GET_32BIT(pktin.body);
+       unsigned nowlen;
        strcpy(buf, "Remote sent disconnect: ");
        nowlen = strlen(buf);
        if (msglen > sizeof(buf)-nowlen-1)
@@ -690,8 +726,8 @@ next_packet:
        /* log reason code in disconnect message */
        char buf[256];
        int reason = GET_32BIT(pktin.data+6);
-       int msglen = GET_32BIT(pktin.data+10);
-       int nowlen;
+       unsigned msglen = GET_32BIT(pktin.data+10);
+       unsigned nowlen;
        if (reason > 0 && reason < lenof(ssh2_disconnect_reasons)) {
            sprintf(buf, "Received disconnect message (%s)",
                    ssh2_disconnect_reasons[reason]);
@@ -987,7 +1023,7 @@ static void ssh2_pkt_addstring(char *data) {
 }
 static char *ssh2_mpint_fmt(Bignum b, int *len) {
     unsigned char *p;
-    int i, n = (ssh1_bignum_bitcount(b)+7)/8;
+    int i, n = (bignum_bitcount(b)+7)/8;
     p = smalloc(n + 1);
     if (!p)
         fatalbox("out of memory");
@@ -1753,7 +1789,7 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt)
                         PUT_32BIT(agentreq, len);
                         q = agentreq + 4;
                         *q++ = SSH1_AGENTC_RSA_CHALLENGE;
-                        PUT_32BIT(q, ssh1_bignum_bitcount(key.modulus));
+                        PUT_32BIT(q, bignum_bitcount(key.modulus));
                         q += 4;
                         q += ssh1_write_bignum(q, key.exponent);
                         q += ssh1_write_bignum(q, key.modulus);
@@ -2234,9 +2270,7 @@ static void ssh1_protocol(unsigned char *in, int inlen, int ispkt) {
             } else if (pktin.type == SSH1_SMSG_X11_OPEN) {
                 /* Remote side is trying to open a channel to talk to our
                  * X-Server. Give them back a local channel number. */
-                unsigned i;
-                struct ssh_channel *c, *d;
-                enum234 e;
+                struct ssh_channel *c;
 
                logevent("Received X11 connect request");
                /* Refuse if X11 forwarding is disabled. */
@@ -2256,13 +2290,8 @@ static void ssh1_protocol(unsigned char *in, int inlen, int ispkt) {
                                  PKT_END);
                    } else {
                      logevent("opening X11 forward connection succeeded");
-                     for (i=1, d = first234(ssh_channels, &e); d; d = next234(&e)) {
-                          if (d->localid > i)
-                              break;     /* found a free number */
-                          i = d->localid + 1;
-                     }
                      c->remoteid = GET_32BIT(pktin.body);
-                     c->localid = i;
+                     c->localid = alloc_channel_id();
                      c->closes = 0;
                      c->type = CHAN_X11;   /* identify channel type */
                      add234(ssh_channels, c);
@@ -2275,9 +2304,7 @@ static void ssh1_protocol(unsigned char *in, int inlen, int ispkt) {
             } else if (pktin.type == SSH1_SMSG_AGENT_OPEN) {
                 /* Remote side is trying to open a channel to talk to our
                  * agent. Give them back a local channel number. */
-                unsigned i;
                 struct ssh_channel *c;
-                enum234 e;
 
                /* Refuse if agent forwarding is disabled. */
                if (!ssh_agentfwd_enabled) {
@@ -2285,15 +2312,9 @@ static void ssh1_protocol(unsigned char *in, int inlen, int ispkt) {
                                PKT_INT, GET_32BIT(pktin.body),
                                PKT_END);
                } else {
-                   i = 1;
-                   for (c = first234(ssh_channels, &e); c; c = next234(&e)) {
-                       if (c->localid > i)
-                           break;     /* found a free number */
-                       i = c->localid + 1;
-                   }
                    c = smalloc(sizeof(struct ssh_channel));
                    c->remoteid = GET_32BIT(pktin.body);
-                   c->localid = i;
+                   c->localid = alloc_channel_id();
                    c->closes = 0;
                    c->type = CHAN_AGENT;   /* identify channel type */
                    c->u.a.lensofar = 0;
@@ -3143,7 +3164,7 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
 
            method = 0;
 
-           if (!method && can_pubkey && agent_exists && !tried_agent) {
+           if (!method && can_pubkey && agent_exists() && !tried_agent) {
                /*
                 * Attempt public-key authentication using Pageant.
                 */
@@ -3512,8 +3533,9 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
     /*
      * So now create a channel with a session in it.
      */
+    ssh_channels = newtree234(ssh_channelcmp);
     mainchan = smalloc(sizeof(struct ssh_channel));
-    mainchan->localid = 100;           /* as good as any */
+    mainchan->localid = alloc_channel_id();
     ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN);
     ssh2_pkt_addstring("session");
     ssh2_pkt_adduint32(mainchan->localid);
@@ -3537,7 +3559,6 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
     mainchan->v2.remmaxpkt = ssh2_pkt_getuint32();
     mainchan->v2.outbuffer = NULL;
     mainchan->v2.outbuflen = mainchan->v2.outbufsize = 0;
-    ssh_channels = newtree234(ssh_channelcmp);
     add234(ssh_channels, mainchan);
     logevent("Opened channel for session");
 
@@ -3816,7 +3837,6 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
            } else if (pktin.type == SSH2_MSG_CHANNEL_CLOSE) {
                 unsigned i = ssh2_pkt_getuint32();
                 struct ssh_channel *c;
-                enum234 e;
 
                 c = find234(ssh_channels, &i, ssh_channelfind);
                 if (!c)
@@ -3842,8 +3862,7 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
                 /*
                  * See if that was the last channel left open.
                  */
-                c = first234(ssh_channels, &e);
-                if (!c) {
+                if (count234(ssh_channels) == 0) {
                     logevent("All channels closed. Disconnecting");
                     ssh2_pkt_init(SSH2_MSG_DISCONNECT);
                     ssh2_pkt_adduint32(SSH2_DISCONNECT_BY_APPLICATION);
@@ -3900,17 +3919,7 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
                     ssh2_pkt_send();
                     sfree(c);
                 } else {
-                    struct ssh_channel *d;
-                    unsigned i;
-                    enum234 e;
-
-                    for (i=1, d = first234(ssh_channels, &e); d;
-                         d = next234(&e)) {
-                       if (d->localid > i)
-                            break;     /* found a free number */
-                       i = d->localid + 1;
-                    }
-                    c->localid = i;
+                    c->localid = alloc_channel_id();
                     c->closes = 0;
                     c->v2.remwindow = ssh2_pkt_getuint32();
                     c->v2.remmaxpkt = ssh2_pkt_getuint32();
@@ -3936,12 +3945,12 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
             try_send = TRUE;
        }
         if (try_send) {
-            enum234 e;
+            int i;
             struct ssh_channel *c;
             /*
              * Try to send data on all channels if we can.
              */
-            for (c = first234(ssh_channels, &e); c; c = next234(&e))
+            for (i = 0; NULL != (c = index234(ssh_channels, i)); i++)
                 ssh2_try_send(c);
         }
     }