]> asedeno.scripts.mit.edu Git - PuTTY_svn.git/blobdiff - ssh.c
Replace the hacky 'OSSocket' type with a closure.
[PuTTY_svn.git] / ssh.c
diff --git a/ssh.c b/ssh.c
index 7fabb8394bff3d6c59c3452e7408109031a2c624..cc4f7467ba9c97992ac8e7b406d952f5dd47fadb 100644 (file)
--- a/ssh.c
+++ b/ssh.c
 #define TRUE 1
 #endif
 
-#define SSH1_MSG_DISCONNECT                       1    /* 0x1 */
-#define SSH1_SMSG_PUBLIC_KEY                      2    /* 0x2 */
-#define SSH1_CMSG_SESSION_KEY                     3    /* 0x3 */
-#define SSH1_CMSG_USER                            4    /* 0x4 */
-#define SSH1_CMSG_AUTH_RSA                        6    /* 0x6 */
-#define SSH1_SMSG_AUTH_RSA_CHALLENGE              7    /* 0x7 */
-#define SSH1_CMSG_AUTH_RSA_RESPONSE               8    /* 0x8 */
-#define SSH1_CMSG_AUTH_PASSWORD                   9    /* 0x9 */
-#define SSH1_CMSG_REQUEST_PTY                     10   /* 0xa */
-#define SSH1_CMSG_WINDOW_SIZE                     11   /* 0xb */
-#define SSH1_CMSG_EXEC_SHELL                      12   /* 0xc */
-#define SSH1_CMSG_EXEC_CMD                        13   /* 0xd */
-#define SSH1_SMSG_SUCCESS                         14   /* 0xe */
-#define SSH1_SMSG_FAILURE                         15   /* 0xf */
-#define SSH1_CMSG_STDIN_DATA                      16   /* 0x10 */
-#define SSH1_SMSG_STDOUT_DATA                     17   /* 0x11 */
-#define SSH1_SMSG_STDERR_DATA                     18   /* 0x12 */
-#define SSH1_CMSG_EOF                             19   /* 0x13 */
-#define SSH1_SMSG_EXIT_STATUS                     20   /* 0x14 */
-#define SSH1_MSG_CHANNEL_OPEN_CONFIRMATION        21   /* 0x15 */
-#define SSH1_MSG_CHANNEL_OPEN_FAILURE             22   /* 0x16 */
-#define SSH1_MSG_CHANNEL_DATA                     23   /* 0x17 */
-#define SSH1_MSG_CHANNEL_CLOSE                    24   /* 0x18 */
-#define SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION       25   /* 0x19 */
-#define SSH1_SMSG_X11_OPEN                        27   /* 0x1b */
-#define SSH1_CMSG_PORT_FORWARD_REQUEST            28   /* 0x1c */
-#define SSH1_MSG_PORT_OPEN                        29   /* 0x1d */
-#define SSH1_CMSG_AGENT_REQUEST_FORWARDING        30   /* 0x1e */
-#define SSH1_SMSG_AGENT_OPEN                      31   /* 0x1f */
-#define SSH1_MSG_IGNORE                           32   /* 0x20 */
-#define SSH1_CMSG_EXIT_CONFIRMATION               33   /* 0x21 */
-#define SSH1_CMSG_X11_REQUEST_FORWARDING          34   /* 0x22 */
-#define SSH1_CMSG_AUTH_RHOSTS_RSA                 35   /* 0x23 */
-#define SSH1_MSG_DEBUG                            36   /* 0x24 */
-#define SSH1_CMSG_REQUEST_COMPRESSION             37   /* 0x25 */
-#define SSH1_CMSG_AUTH_TIS                        39   /* 0x27 */
-#define SSH1_SMSG_AUTH_TIS_CHALLENGE              40   /* 0x28 */
-#define SSH1_CMSG_AUTH_TIS_RESPONSE               41   /* 0x29 */
-#define SSH1_CMSG_AUTH_CCARD                      70   /* 0x46 */
-#define SSH1_SMSG_AUTH_CCARD_CHALLENGE            71   /* 0x47 */
-#define SSH1_CMSG_AUTH_CCARD_RESPONSE             72   /* 0x48 */
-
-#define SSH1_AUTH_RHOSTS                          1    /* 0x1 */
-#define SSH1_AUTH_RSA                             2    /* 0x2 */
-#define SSH1_AUTH_PASSWORD                        3    /* 0x3 */
-#define SSH1_AUTH_RHOSTS_RSA                      4    /* 0x4 */
-#define SSH1_AUTH_TIS                             5    /* 0x5 */
-#define SSH1_AUTH_CCARD                           16   /* 0x10 */
-
-#define SSH1_PROTOFLAG_SCREEN_NUMBER              1    /* 0x1 */
-/* Mask for protoflags we will echo back to server if seen */
-#define SSH1_PROTOFLAGS_SUPPORTED                 0    /* 0x1 */
-
-#define SSH2_MSG_DISCONNECT                       1    /* 0x1 */
-#define SSH2_MSG_IGNORE                           2    /* 0x2 */
-#define SSH2_MSG_UNIMPLEMENTED                    3    /* 0x3 */
-#define SSH2_MSG_DEBUG                            4    /* 0x4 */
-#define SSH2_MSG_SERVICE_REQUEST                  5    /* 0x5 */
-#define SSH2_MSG_SERVICE_ACCEPT                   6    /* 0x6 */
-#define SSH2_MSG_KEXINIT                          20   /* 0x14 */
-#define SSH2_MSG_NEWKEYS                          21   /* 0x15 */
-#define SSH2_MSG_KEXDH_INIT                       30   /* 0x1e */
-#define SSH2_MSG_KEXDH_REPLY                      31   /* 0x1f */
-#define SSH2_MSG_KEX_DH_GEX_REQUEST               30   /* 0x1e */
-#define SSH2_MSG_KEX_DH_GEX_GROUP                 31   /* 0x1f */
-#define SSH2_MSG_KEX_DH_GEX_INIT                  32   /* 0x20 */
-#define SSH2_MSG_KEX_DH_GEX_REPLY                 33   /* 0x21 */
-#define SSH2_MSG_KEXRSA_PUBKEY                    30    /* 0x1e */
-#define SSH2_MSG_KEXRSA_SECRET                    31    /* 0x1f */
-#define SSH2_MSG_KEXRSA_DONE                      32    /* 0x20 */
-#define SSH2_MSG_USERAUTH_REQUEST                 50   /* 0x32 */
-#define SSH2_MSG_USERAUTH_FAILURE                 51   /* 0x33 */
-#define SSH2_MSG_USERAUTH_SUCCESS                 52   /* 0x34 */
-#define SSH2_MSG_USERAUTH_BANNER                  53   /* 0x35 */
-#define SSH2_MSG_USERAUTH_PK_OK                   60   /* 0x3c */
-#define SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ        60   /* 0x3c */
-#define SSH2_MSG_USERAUTH_INFO_REQUEST            60   /* 0x3c */
-#define SSH2_MSG_USERAUTH_INFO_RESPONSE           61   /* 0x3d */
-#define SSH2_MSG_GLOBAL_REQUEST                   80   /* 0x50 */
-#define SSH2_MSG_REQUEST_SUCCESS                  81   /* 0x51 */
-#define SSH2_MSG_REQUEST_FAILURE                  82   /* 0x52 */
-#define SSH2_MSG_CHANNEL_OPEN                     90   /* 0x5a */
-#define SSH2_MSG_CHANNEL_OPEN_CONFIRMATION        91   /* 0x5b */
-#define SSH2_MSG_CHANNEL_OPEN_FAILURE             92   /* 0x5c */
-#define SSH2_MSG_CHANNEL_WINDOW_ADJUST            93   /* 0x5d */
-#define SSH2_MSG_CHANNEL_DATA                     94   /* 0x5e */
-#define SSH2_MSG_CHANNEL_EXTENDED_DATA            95   /* 0x5f */
-#define SSH2_MSG_CHANNEL_EOF                      96   /* 0x60 */
-#define SSH2_MSG_CHANNEL_CLOSE                    97   /* 0x61 */
-#define SSH2_MSG_CHANNEL_REQUEST                  98   /* 0x62 */
-#define SSH2_MSG_CHANNEL_SUCCESS                  99   /* 0x63 */
-#define SSH2_MSG_CHANNEL_FAILURE                  100  /* 0x64 */
-#define SSH2_MSG_USERAUTH_GSSAPI_RESPONSE               60
-#define SSH2_MSG_USERAUTH_GSSAPI_TOKEN                  61
-#define SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE      63
-#define SSH2_MSG_USERAUTH_GSSAPI_ERROR                  64
-#define SSH2_MSG_USERAUTH_GSSAPI_ERRTOK                 65
-#define SSH2_MSG_USERAUTH_GSSAPI_MIC                    66
-
 /*
  * Packet type contexts, so that ssh2_pkt_type can correctly decode
  * the ambiguous type numbers back into the correct type strings.
@@ -141,22 +42,6 @@ typedef enum {
     SSH2_PKTCTX_KBDINTER
 } Pkt_ACtx;
 
-#define SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT 1  /* 0x1 */
-#define SSH2_DISCONNECT_PROTOCOL_ERROR            2    /* 0x2 */
-#define SSH2_DISCONNECT_KEY_EXCHANGE_FAILED       3    /* 0x3 */
-#define SSH2_DISCONNECT_HOST_AUTHENTICATION_FAILED 4   /* 0x4 */
-#define SSH2_DISCONNECT_MAC_ERROR                 5    /* 0x5 */
-#define SSH2_DISCONNECT_COMPRESSION_ERROR         6    /* 0x6 */
-#define SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE     7    /* 0x7 */
-#define SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED 8       /* 0x8 */
-#define SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE   9    /* 0x9 */
-#define SSH2_DISCONNECT_CONNECTION_LOST           10   /* 0xa */
-#define SSH2_DISCONNECT_BY_APPLICATION            11   /* 0xb */
-#define SSH2_DISCONNECT_TOO_MANY_CONNECTIONS      12   /* 0xc */
-#define SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER    13   /* 0xd */
-#define SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE 14      /* 0xe */
-#define SSH2_DISCONNECT_ILLEGAL_USER_NAME         15   /* 0xf */
-
 static const char *const ssh2_disconnect_reasons[] = {
     NULL,
     "host not allowed to connect",
@@ -176,13 +61,6 @@ static const char *const ssh2_disconnect_reasons[] = {
     "illegal user name",
 };
 
-#define SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED     1    /* 0x1 */
-#define SSH2_OPEN_CONNECT_FAILED                  2    /* 0x2 */
-#define SSH2_OPEN_UNKNOWN_CHANNEL_TYPE            3    /* 0x3 */
-#define SSH2_OPEN_RESOURCE_SHORTAGE               4    /* 0x4 */
-
-#define SSH2_EXTENDED_DATA_STDERR                 1    /* 0x1 */
-
 /*
  * Various remote-bug flags.
  */
@@ -708,12 +586,20 @@ struct ssh_portfwd; /* forward declaration */
 
 struct ssh_rportfwd {
     unsigned sport, dport;
-    char dhost[256];
+    char *shost, *dhost;
     char *sportdesc;
     struct ssh_portfwd *pfrec;
 };
-#define free_rportfwd(pf) ( \
-    ((pf) ? (sfree((pf)->sportdesc)) : (void)0 ), sfree(pf) )
+
+static void free_rportfwd(struct ssh_rportfwd *pf)
+{
+    if (pf) {
+        sfree(pf->sportdesc);
+        sfree(pf->shost);
+        sfree(pf->dhost);
+        sfree(pf);
+    }
+}
 
 /*
  * Separately to the rportfwd tree (which is for looking up port
@@ -1107,7 +993,9 @@ static int ssh_rportcmp_ssh2(void *av, void *bv)
 {
     struct ssh_rportfwd *a = (struct ssh_rportfwd *) av;
     struct ssh_rportfwd *b = (struct ssh_rportfwd *) bv;
-
+    int i;
+    if ( (i = strcmp(a->shost, b->shost)) != 0)
+       return i < 0 ? -1 : +1;
     if (a->sport > b->sport)
        return +1;
     if (a->sport < b->sport)
@@ -4322,6 +4210,7 @@ void sshfwd_unclean_close(struct ssh_channel *c, const char *err)
         break;
     }
     c->type = CHAN_ZOMBIE;
+    c->pending_eof = FALSE;   /* this will confuse a zombie channel */
 
     ssh2_channel_check_close(c);
 }
@@ -4724,9 +4613,15 @@ static void ssh_setup_portfwd(Ssh ssh, Conf *conf)
                }
 
                pf = snew(struct ssh_rportfwd);
-               strncpy(pf->dhost, epf->daddr, lenof(pf->dhost)-1);
-               pf->dhost[lenof(pf->dhost)-1] = '\0';
+                pf->dhost = dupstr(epf->daddr);
                pf->dport = epf->dport;
+                if (epf->saddr) {
+                    pf->shost = dupstr(epf->saddr);
+                } else if (conf_get_int(conf, CONF_rport_acceptall)) {
+                    pf->shost = dupstr("");
+                } else {
+                    pf->shost = dupstr("localhost");
+                }
                pf->sport = epf->sport;
                if (add234(ssh->rportfwds, pf) != pf) {
                    logeventf(ssh, "Duplicate remote port forwarding to %s:%d",
@@ -4755,14 +4650,8 @@ static void ssh_setup_portfwd(Ssh ssh, Conf *conf)
                        pktout = ssh2_pkt_init(SSH2_MSG_GLOBAL_REQUEST);
                        ssh2_pkt_addstring(pktout, "tcpip-forward");
                        ssh2_pkt_addbool(pktout, 1);/* want reply */
-                       if (epf->saddr) {
-                           ssh2_pkt_addstring(pktout, epf->saddr);
-                       } else if (conf_get_int(conf, CONF_rport_acceptall)) {
-                           ssh2_pkt_addstring(pktout, "");
-                       } else {
-                           ssh2_pkt_addstring(pktout, "localhost");
-                       }
-                       ssh2_pkt_adduint32(pktout, epf->sport);
+                       ssh2_pkt_addstring(pktout, pf->shost);
+                       ssh2_pkt_adduint32(pktout, pf->sport);
                        ssh2_pkt_send(ssh, pktout);
 
                        ssh_queue_handler(ssh, SSH2_MSG_REQUEST_SUCCESS,
@@ -4882,10 +4771,7 @@ static void ssh1_msg_port_open(Ssh ssh, struct Packet *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.dhost = dupprintf(".*s", hostsize, host);
     pf.dport = port;
     pfp = find234(ssh->rportfwds, &pf, NULL);
 
@@ -4922,6 +4808,8 @@ static void ssh1_msg_port_open(Ssh ssh, struct Packet *pktin)
            logevent("Forwarded port opened successfully");
        }
     }
+
+    sfree(pf.dhost);
 }
 
 static void ssh1_msg_channel_open_confirmation(Ssh ssh, struct Packet *pktin)
@@ -7018,6 +6906,15 @@ static void ssh2_channel_check_close(struct ssh_channel *c)
     Ssh ssh = c->ssh;
     struct Packet *pktout;
 
+    if (c->halfopen) {
+        /*
+         * If we've sent out our own CHANNEL_OPEN but not yet seen
+         * either OPEN_CONFIRMATION or OPEN_FAILURE in response, then
+         * it's too early to be sending close messages of any kind.
+         */
+        return;
+    }
+
     if ((!((CLOSES_SENT_EOF | CLOSES_RCVD_EOF) & ~c->closes) ||
         c->type == CHAN_ZOMBIE) &&
        !c->v.v2.chanreq_head &&
@@ -7159,17 +7056,42 @@ static void ssh2_msg_channel_open_confirmation(Ssh ssh, struct Packet *pktin)
     c = ssh2_channel_msg(ssh, pktin);
     if (!c)
        return;
-    if (c->type != CHAN_SOCKDATA_DORMANT)
-       return;                        /* dunno why they're confirming this */
+    assert(c->halfopen); /* ssh2_channel_msg will have enforced this */
     c->remoteid = ssh_pkt_getuint32(pktin);
     c->halfopen = FALSE;
-    c->type = CHAN_SOCKDATA;
     c->v.v2.remwindow = ssh_pkt_getuint32(pktin);
     c->v.v2.remmaxpkt = ssh_pkt_getuint32(pktin);
-    if (c->u.pfd.s)
-       pfd_confirm(c->u.pfd.s);
+
+    if (c->type == CHAN_SOCKDATA_DORMANT) {
+        c->type = CHAN_SOCKDATA;
+        if (c->u.pfd.s)
+            pfd_confirm(c->u.pfd.s);
+    } else if (c->type == CHAN_ZOMBIE) {
+        /*
+         * This case can occur if a local socket error occurred
+         * between us sending out CHANNEL_OPEN and receiving
+         * OPEN_CONFIRMATION. In this case, all we can do is
+         * immediately initiate close proceedings now that we know the
+         * server's id to put in the close message.
+         */
+        ssh2_channel_check_close(c);
+    } else {
+        /*
+         * We never expect to receive OPEN_CONFIRMATION for any
+         * *other* channel type (since only local-to-remote port
+         * forwardings cause us to send CHANNEL_OPEN after the main
+         * channel is live - all other auxiliary channel types are
+         * initiated from the server end). It's safe to enforce this
+         * by assertion rather than by ssh_disconnect, because the
+         * real point is that we never constructed a half-open channel
+         * structure in the first place with any type other than the
+         * above.
+         */
+        assert(!"Funny channel type in ssh2_msg_channel_open_confirmation");
+    }
+
     if (c->pending_eof)
-        ssh_channel_try_eof(c);
+        ssh_channel_try_eof(c);        /* in case we had a pending EOF */
 }
 
 static void ssh2_msg_channel_open_failure(Ssh ssh, struct Packet *pktin)
@@ -7185,20 +7107,41 @@ static void ssh2_msg_channel_open_failure(Ssh ssh, struct Packet *pktin)
     char *reason_string;
     int reason_length;
     struct ssh_channel *c;
+
     c = ssh2_channel_msg(ssh, pktin);
     if (!c)
        return;
-    if (c->type != CHAN_SOCKDATA_DORMANT)
-       return;                        /* dunno why they're failing this */
+    assert(c->halfopen); /* ssh2_channel_msg will have enforced this */
 
-    reason_code = ssh_pkt_getuint32(pktin);
-    if (reason_code >= lenof(reasons))
-       reason_code = 0; /* ensure reasons[reason_code] in range */
-    ssh_pkt_getstring(pktin, &reason_string, &reason_length);
-    logeventf(ssh, "Forwarded connection refused by server: %s [%.*s]",
-             reasons[reason_code], reason_length, reason_string);
+    if (c->type == CHAN_SOCKDATA_DORMANT) {
+        reason_code = ssh_pkt_getuint32(pktin);
+        if (reason_code >= lenof(reasons))
+            reason_code = 0; /* ensure reasons[reason_code] in range */
+        ssh_pkt_getstring(pktin, &reason_string, &reason_length);
+        logeventf(ssh, "Forwarded connection refused by server: %s [%.*s]",
+                  reasons[reason_code], reason_length, reason_string);
 
-    pfd_close(c->u.pfd.s);
+        pfd_close(c->u.pfd.s);
+    } else if (c->type == CHAN_ZOMBIE) {
+        /*
+         * This case can occur if a local socket error occurred
+         * between us sending out CHANNEL_OPEN and receiving
+         * OPEN_FAILURE. In this case, we need do nothing except allow
+         * the code below to throw the half-open channel away.
+         */
+    } else {
+        /*
+         * We never expect to receive OPEN_FAILURE for any *other*
+         * channel type (since only local-to-remote port forwardings
+         * cause us to send CHANNEL_OPEN after the main channel is
+         * live - all other auxiliary channel types are initiated from
+         * the server end). It's safe to enforce this by assertion
+         * rather than by ssh_disconnect, because the real point is
+         * that we never constructed a half-open channel structure in
+         * the first place with any type other than the above.
+         */
+        assert(!"Funny channel type in ssh2_msg_channel_open_failure");
+    }
 
     del234(ssh->channels, c);
     sfree(c);
@@ -7455,15 +7398,18 @@ static void ssh2_msg_channel_open(Ssh ssh, struct Packet *pktin)
     } else if (typelen == 15 &&
               !memcmp(type, "forwarded-tcpip", 15)) {
        struct ssh_rportfwd pf, *realpf;
-       char *dummy;
-       int dummylen;
-       ssh_pkt_getstring(pktin, &dummy, &dummylen);/* skip address */
+       char *shost;
+       int shostlen;
+       ssh_pkt_getstring(pktin, &shost, &shostlen);/* skip address */
+        pf.shost = dupprintf("%.*s", shostlen, shost);
        pf.sport = ssh_pkt_getuint32(pktin);
        ssh_pkt_getstring(pktin, &peeraddr, &peeraddrlen);
        peerport = ssh_pkt_getuint32(pktin);
        realpf = find234(ssh->rportfwds, &pf, NULL);
-       logeventf(ssh, "Received remote port %d open request "
-                 "from %s:%d", pf.sport, peeraddr, peerport);
+       logeventf(ssh, "Received remote port %s:%d open request "
+                 "from %s:%d", pf.shost, pf.sport, peeraddr, peerport);
+        sfree(pf.shost);
+
        if (realpf == NULL) {
            error = "Remote port is not recognised";
        } else {