Commit message: None
CVE: CVE-2017-6542
CWE: CWE-119
Vulnerability description: The ssh_agent_channel_data function in PuTTY before 0.68 allows remote attackers to have unspecified impact via a large length value in an agent protocol message and leveraging the ability to connect to the Unix-domain socket representing the forwarded agent connection, which trigger a buffer overflow.

Project: tartarus

static int alloc_channel_id(Ssh ssh)
{
    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;
}

Project: tartarus

void bndebug(char *string, Bignum b)
{
    unsigned char *p;
    int i, len;
    p = ssh2_mpint_fmt(b, &len);
    debug(("%s", string));
    for (i = 0; i < len; i++)
	debug((" %02x", p[i]));
    debug(("\n"));
    sfree(p);
}

Project: tartarus

static void bomb_out(Ssh ssh, char *text)
{
    ssh_do_close(ssh, FALSE);
    logevent(text);
    connection_fatal(ssh->frontend, "%s", text);
    sfree(text);
}

Project: tartarus

static void c_write(Ssh ssh, const char *buf, int len)
{
    if (flags & FLAG_STDERR)
	c_write_stderr(1, buf, len);
    else
	from_backend(ssh->frontend, 1, buf, len);
}

Project: tartarus

static void c_write_stderr(int trusted, const char *buf, int len)
{
    int i;
    for (i = 0; i < len; i++)
	if (buf[i] != '\r' && (trusted || buf[i] == '\n' || (buf[i] & 0x60)))
	    fputc(buf[i], stderr);
}

Project: tartarus

static void c_write_str(Ssh ssh, const char *buf)
{
    c_write(ssh, buf, strlen(buf));
}

Project: tartarus

static const char *connect_to_host(Ssh ssh, const char *host, int port,
				   char **realhost, int nodelay, int keepalive)
{
    static const struct plug_function_table fn_table = {
	ssh_socket_log,
	ssh_closing,
	ssh_receive,
	ssh_sent,
	NULL
    };

    SockAddr addr;
    const char *err;
    char *loghost;
    int addressfamily, sshprot;

    ssh_hostport_setup(host, port, ssh->conf,
                       &ssh->savedhost, &ssh->savedport, &loghost);

    ssh->fn = &fn_table;               /* make 'ssh' usable as a Plug */

    /*
     * Try connection-sharing, in case that means we don't open a
     * socket after all. ssh_connection_sharing_init will connect to a
     * previously established upstream if it can, and failing that,
     * establish a listening socket for _us_ to be the upstream. In
     * the latter case it will return NULL just as if it had done
     * nothing, because here we only need to care if we're a
     * downstream and need to do our connection setup differently.
     */
    ssh->connshare = NULL;
    ssh->attempting_connshare = TRUE;  /* affects socket logging behaviour */
    ssh->s = ssh_connection_sharing_init(ssh->savedhost, ssh->savedport,
                                         ssh->conf, ssh, &ssh->connshare);
    ssh->attempting_connshare = FALSE;
    if (ssh->s != NULL) {
        /*
         * We are a downstream.
         */
        ssh->bare_connection = TRUE;
        ssh->do_ssh_init = do_ssh_connection_init;
        ssh->fullhostname = NULL;
        *realhost = dupstr(host);      /* best we can do */
    } else {
        /*
         * We're not a downstream, so open a normal socket.
         */
        ssh->do_ssh_init = do_ssh_init;

        /*
         * Try to find host.
         */
        addressfamily = conf_get_int(ssh->conf, CONF_addressfamily);
        addr = name_lookup(host, port, realhost, ssh->conf, addressfamily,
                           ssh->frontend, "SSH connection");
        if ((err = sk_addr_error(addr)) != NULL) {
            sk_addr_free(addr);
            return err;
        }
        ssh->fullhostname = dupstr(*realhost);   /* save in case of GSSAPI */

        ssh->s = new_connection(addr, *realhost, port,
                                0, 1, nodelay, keepalive,
                                (Plug) ssh, ssh->conf);
        if ((err = sk_socket_error(ssh->s)) != NULL) {
            ssh->s = NULL;
            notify_remote_exit(ssh->frontend);
            return err;
        }
    }

    /*
     * The SSH version number is always fixed (since we no longer support
     * fallback between versions), so set it now, and if it's SSH-2,
     * send the version string now too.
     */
    sshprot = conf_get_int(ssh->conf, CONF_sshprot);
    assert(sshprot == 0 || sshprot == 3);
    if (sshprot == 0)
	/* SSH-1 only */
	ssh->version = 1;
    if (sshprot == 3 && !ssh->bare_connection) {
	/* SSH-2 only */
	ssh->version = 2;
	ssh_send_verstring(ssh, "SSH-", NULL);
    }

    /*
     * loghost, if configured, overrides realhost.
     */
    if (*loghost) {
	sfree(*realhost);
	*realhost = dupstr(loghost);
    }

    return NULL;
}

Project: tartarus

static void defer_packet(Ssh ssh, int pkttype, ...)
{
    struct Packet *pkt;
    va_list ap;
    va_start(ap, pkttype);
    pkt = construct_packet(ssh, pkttype, ap);
    va_end(ap);
    s_wrpkt_defer(ssh, pkt);
}

Project: tartarus

static int do_ssh_connection_init(Ssh ssh, unsigned char c)
{
    /*
     * Ordinary SSH begins with the banner "SSH-x.y-...". This is just
     * the ssh-connection part, extracted and given a trivial binary
     * packet protocol, so we replace 'SSH-' at the start with a new
     * name. In proper SSH style (though of course this part of the
     * proper SSH protocol _isn't_ subject to this kind of
     * DNS-domain-based extension), we define the new name in our
     * extension space.
     */
    static const char protoname[] =
        "SSHCONNECTION@putty.projects.tartarus.org-";

    struct do_ssh_connection_init_state {
	int crLine;
	int vslen;
	char version[10];
	char *vstring;
	int vstrsize;
	int i;
    };
    crState(do_ssh_connection_init_state);
    
    crBeginState;

    /* Search for a line beginning with the protocol name prefix in
     * the input. */
    for (;;) {
        for (s->i = 0; protoname[s->i]; s->i++) {
            if ((char)c != protoname[s->i]) goto no;
            crReturn(1);
        }
	break;
      no:
	while (c != '\012')
	    crReturn(1);
	crReturn(1);
    }

    s->vstrsize = sizeof(protoname) + 16;
    s->vstring = snewn(s->vstrsize, char);
    strcpy(s->vstring, protoname);
    s->vslen = strlen(protoname);
    s->i = 0;
    while (1) {
	if (s->vslen >= s->vstrsize - 1) {
	    s->vstrsize += 16;
	    s->vstring = sresize(s->vstring, s->vstrsize, char);
	}
	s->vstring[s->vslen++] = c;
	if (s->i >= 0) {
	    if (c == '-') {
		s->version[s->i] = '\0';
		s->i = -1;
	    } else if (s->i < sizeof(s->version) - 1)
		s->version[s->i++] = c;
	} else if (c == '\012')
	    break;
	crReturn(1);		       /* get another char */
    }

    ssh->agentfwd_enabled = FALSE;
    ssh->rdpkt2_bare_state.incoming_sequence = 0;

    s->vstring[s->vslen] = 0;
    s->vstring[strcspn(s->vstring, "\015\012")] = '\0';/* remove EOL chars */
    logeventf(ssh, "Server version: %s", s->vstring);
    ssh_detect_bugs(ssh, s->vstring);

    /*
     * Decide which SSH protocol version to support. This is easy in
     * bare ssh-connection mode: only 2.0 is legal.
     */
    if (ssh_versioncmp(s->version, "2.0") < 0) {
	bombout(("Server announces compatibility with SSH-1 in bare ssh-connection protocol"));
        crStop(0);
    }
    if (conf_get_int(ssh->conf, CONF_sshprot) == 0) {
	bombout(("Bare ssh-connection protocol cannot be run in SSH-1-only mode"));
	crStop(0);
    }

    ssh->version = 2;

    logeventf(ssh, "Using bare ssh-connection protocol");

    /* Send the version string, if we haven't already */
    ssh_send_verstring(ssh, protoname, s->version);

    /*
     * Initialise bare connection protocol.
     */
    ssh->protocol = ssh2_bare_connection_protocol;
    ssh2_bare_connection_protocol_setup(ssh);
    ssh->s_rdpkt = ssh2_bare_connection_rdpkt;

    update_specials_menu(ssh->frontend);
    ssh->state = SSH_STATE_BEFORE_SIZE;
    ssh->pinger = pinger_new(ssh->conf, &ssh_backend, ssh);

    /*
     * Get authconn (really just conn) under way.
     */
    do_ssh2_authconn(ssh, NULL, 0, NULL);

    sfree(s->vstring);

    crFinish(0);
}

Project: tartarus

static int do_ssh_init(Ssh ssh, unsigned char c)
{
    static const char protoname[] = "SSH-";

    struct do_ssh_init_state {
	int crLine;
	int vslen;
	char version[10];
	char *vstring;
	int vstrsize;
	int i;
	int proto1, proto2;
    };
    crState(do_ssh_init_state);
    
    crBeginState;

    /* Search for a line beginning with the protocol name prefix in
     * the input. */
    for (;;) {
        for (s->i = 0; protoname[s->i]; s->i++) {
            if ((char)c != protoname[s->i]) goto no;
            crReturn(1);
        }
	break;
      no:
	while (c != '\012')
	    crReturn(1);
	crReturn(1);
    }

    ssh->session_started = TRUE;

    s->vstrsize = sizeof(protoname) + 16;
    s->vstring = snewn(s->vstrsize, char);
    strcpy(s->vstring, protoname);
    s->vslen = strlen(protoname);
    s->i = 0;
    while (1) {
	if (s->vslen >= s->vstrsize - 1) {
	    s->vstrsize += 16;
	    s->vstring = sresize(s->vstring, s->vstrsize, char);
	}
	s->vstring[s->vslen++] = c;
	if (s->i >= 0) {
	    if (c == '-') {
		s->version[s->i] = '\0';
		s->i = -1;
	    } else if (s->i < sizeof(s->version) - 1)
		s->version[s->i++] = c;
	} else if (c == '\012')
	    break;
	crReturn(1);		       /* get another char */
    }

    ssh->agentfwd_enabled = FALSE;
    ssh->rdpkt2_state.incoming_sequence = 0;

    s->vstring[s->vslen] = 0;
    s->vstring[strcspn(s->vstring, "\015\012")] = '\0';/* remove EOL chars */
    logeventf(ssh, "Server version: %s", s->vstring);
    ssh_detect_bugs(ssh, s->vstring);

    /*
     * Decide which SSH protocol version to support.
     */

    /* Anything strictly below "2.0" means protocol 1 is supported. */
    s->proto1 = ssh_versioncmp(s->version, "2.0") < 0;
    /* Anything greater or equal to "1.99" means protocol 2 is supported. */
    s->proto2 = ssh_versioncmp(s->version, "1.99") >= 0;

    if (conf_get_int(ssh->conf, CONF_sshprot) == 0) {
	if (!s->proto1) {
	    bombout(("SSH protocol version 1 required by our configuration "
		     "but not provided by server"));
	    crStop(0);
	}
    } else if (conf_get_int(ssh->conf, CONF_sshprot) == 3) {
	if (!s->proto2) {
	    bombout(("SSH protocol version 2 required by our configuration "
		     "but server only provides (old, insecure) SSH-1"));
	    crStop(0);
	}
    } else {
	/* No longer support values 1 or 2 for CONF_sshprot */
	assert(!"Unexpected value for CONF_sshprot");
    }

    if (s->proto2 && (conf_get_int(ssh->conf, CONF_sshprot) >= 2 || !s->proto1))
	ssh->version = 2;
    else
	ssh->version = 1;

    logeventf(ssh, "Using SSH protocol version %d", ssh->version);

    /* Send the version string, if we haven't already */
    if (conf_get_int(ssh->conf, CONF_sshprot) != 3)
	ssh_send_verstring(ssh, protoname, s->version);

    if (ssh->version == 2) {
	size_t len;
	/*
	 * Record their version string.
	 */
	len = strcspn(s->vstring, "\015\012");
	ssh->v_s = snewn(len + 1, char);
	memcpy(ssh->v_s, s->vstring, len);
	ssh->v_s[len] = 0;
	    
	/*
	 * Initialise SSH-2 protocol.
	 */
	ssh->protocol = ssh2_protocol;
	ssh2_protocol_setup(ssh);
	ssh->s_rdpkt = ssh2_rdpkt;
    } else {
	/*
	 * Initialise SSH-1 protocol.
	 */
	ssh->protocol = ssh1_protocol;
	ssh1_protocol_setup(ssh);
	ssh->s_rdpkt = ssh1_rdpkt;
    }
    if (ssh->version == 2)
	do_ssh2_transport(ssh, NULL, -1, NULL);

    update_specials_menu(ssh->frontend);
    ssh->state = SSH_STATE_BEFORE_SIZE;
    ssh->pinger = pinger_new(ssh->conf, &ssh_backend, ssh);

    sfree(s->vstring);

    crFinish(0);
}

Project: tartarus

static void free_rportfwd(struct ssh_rportfwd *pf)
{
    if (pf) {
        sfree(pf->sportdesc);
        sfree(pf->shost);
        sfree(pf->dhost);
        sfree(pf);
    }
}

Project: tartarus

static void hash_mpint(const struct ssh_hash *h, void *s, Bignum b)
{
    unsigned char *p;
    int len;
    p = ssh2_mpint_fmt(b, &len);
    hash_string(h, s, p, len);
    sfree(p);
}

Project: tartarus

static void hash_string(const struct ssh_hash *h, void *s, void *str, int len)
{
    unsigned char lenblk[4];
    PUT_32BIT(lenblk, len);
    h->bytes(s, lenblk, 4);
    h->bytes(s, str, len);
}

Project: tartarus

static void hash_uint32(const struct ssh_hash *h, void *s, unsigned i)
{
    unsigned char intblk[4];
    PUT_32BIT(intblk, i);
    h->bytes(s, intblk, 4);
}

Project: tartarus

static void logeventf(Ssh ssh, const char *fmt, ...)
{
    va_list ap;
    char *buf;

    va_start(ap, fmt);
    buf = dupvprintf(fmt, ap);
    va_end(ap);
    logevent(buf);
    sfree(buf);
}

Project: tartarus

static int nullstrcmp(const char *a, const char *b)
{
    if (a == NULL && b == NULL)
	return 0;
    if (a == NULL)
	return -1;
    if (b == NULL)
	return +1;
    return strcmp(a, b);
}

Project: tartarus

static void parse_ttymodes(Ssh ssh,
                           void (*do_mode)(void *data,
                                           const struct ssh_ttymode *mode,
                                           char *val),
			   void *data)
{
    int i;
    const struct ssh_ttymode *mode;
    char *val;
    char default_val[2];

    strcpy(default_val, "A");

    for (i = 0; i < lenof(ssh_ttymodes); i++) {
        mode = ssh_ttymodes + i;
        val = conf_get_str_str_opt(ssh->conf, CONF_ttymodes, mode->mode);
        if (!val)
            val = default_val;

	/*
	 * val[0] is either 'V', indicating that an explicit value
	 * follows it, or 'A' indicating that we should pass the
	 * value through from the local environment via get_ttymode.
	 */
	if (val[0] == 'A') {
	    val = get_ttymode(ssh->frontend, mode->mode);
	    if (val) {
		do_mode(data, mode, val);
		sfree(val);
	    }
	} else
            do_mode(data, mode, val + 1);              /* skip the 'V' */
    }
}

Project: tartarus

static void s_wrpkt(Ssh ssh, struct Packet *pkt)
{
    int len, backlog, offset;
    len = s_wrpkt_prepare(ssh, pkt, &offset);
    backlog = s_write(ssh, pkt->data + offset, len);
    if (backlog > SSH_MAX_BACKLOG)
	ssh_throttle_all(ssh, 1, backlog);
    ssh_free_packet(pkt);
}

Project: tartarus

static void s_wrpkt_defer(Ssh ssh, struct Packet *pkt)
{
    int len, offset;
    len = s_wrpkt_prepare(ssh, pkt, &offset);
    if (ssh->deferred_len + len > ssh->deferred_size) {
	ssh->deferred_size = ssh->deferred_len + len + 128;
	ssh->deferred_send_data = sresize(ssh->deferred_send_data,
					  ssh->deferred_size,
					  unsigned char);
    }
    memcpy(ssh->deferred_send_data + ssh->deferred_len,
	   pkt->data + offset, len);
    ssh->deferred_len += len;
    ssh_free_packet(pkt);
}

Project: tartarus

static int s_wrpkt_prepare(Ssh ssh, struct Packet *pkt, int *offset_p)
{
    int pad, biglen, i, pktoffs;
    unsigned long crc;
#ifdef __SC__
    /*
     * XXX various versions of SC (including 8.8.4) screw up the
     * register allocation in this function and use the same register
     * (D6) for len and as a temporary, with predictable results.  The
     * following sledgehammer prevents this.
     */
    volatile
#endif
    int len;

    if (ssh->logctx)
        ssh1_log_outgoing_packet(ssh, pkt);

    if (ssh->v1_compressing) {
	unsigned char *compblk;
	int complen;
	zlib_compress_block(ssh->cs_comp_ctx,
			    pkt->data + 12, pkt->length - 12,
			    &compblk, &complen);
	ssh_pkt_ensure(pkt, complen + 2);   /* just in case it's got bigger */
	memcpy(pkt->data + 12, compblk, complen);
	sfree(compblk);
	pkt->length = complen + 12;
    }

    ssh_pkt_ensure(pkt, pkt->length + 4); /* space for CRC */
    pkt->length += 4;
    len = pkt->length - 4 - 8;	/* len(type+data+CRC) */
    pad = 8 - (len % 8);
    pktoffs = 8 - pad;
    biglen = len + pad;		/* len(padding+type+data+CRC) */

    for (i = pktoffs; i < 4+8; i++)
	pkt->data[i] = random_byte();
    crc = crc32_compute(pkt->data + pktoffs + 4, biglen - 4); /* all ex len */
    PUT_32BIT(pkt->data + pktoffs + 4 + biglen - 4, crc);
    PUT_32BIT(pkt->data + pktoffs, len);

    if (ssh->cipher)
	ssh->cipher->encrypt(ssh->v1_cipher_ctx,
			     pkt->data + pktoffs + 4, biglen);

    if (offset_p) *offset_p = pktoffs;
    return biglen + 4;		/* len(length+padding+type+data+CRC) */
}

Project: tartarus

static void send_packet(Ssh ssh, int pkttype, ...)
{
    struct Packet *pkt;
    va_list ap;
    va_start(ap, pkttype);
    pkt = construct_packet(ssh, pkttype, ap);
    va_end(ap);
    s_wrpkt(ssh, pkt);
}

Project: tartarus

static void ssh1_log_incoming_packet(Ssh ssh, struct Packet *pkt)
{
    int nblanks = 0;
    struct logblank_t blanks[4];
    char *str;
    int slen;

    pkt->savedpos = 0;

    if (ssh->logomitdata &&
        (pkt->type == SSH1_SMSG_STDOUT_DATA ||
         pkt->type == SSH1_SMSG_STDERR_DATA ||
         pkt->type == SSH1_MSG_CHANNEL_DATA)) {
        /* "Session data" packets - omit the data string. */
        if (pkt->type == SSH1_MSG_CHANNEL_DATA)
            ssh_pkt_getuint32(pkt);    /* skip channel id */
        blanks[nblanks].offset = pkt->savedpos + 4;
        blanks[nblanks].type = PKTLOG_OMIT;
        ssh_pkt_getstring(pkt, &str, &slen);
        if (str) {
            blanks[nblanks].len = slen;
            nblanks++;
        }
    }
    log_packet(ssh->logctx, PKT_INCOMING, pkt->type,
               ssh1_pkt_type(pkt->type),
               pkt->body, pkt->length, nblanks, blanks, NULL,
               0, NULL);
}

Project: tartarus

static void ssh1_log_outgoing_packet(Ssh ssh, struct Packet *pkt)
{
    int nblanks = 0;
    struct logblank_t blanks[4];
    char *str;
    int slen;

    /*
     * For outgoing packets, pkt->length represents the length of the
     * whole packet starting at pkt->data (including some header), and
     * pkt->body refers to the point within that where the log-worthy
     * payload begins. However, incoming packets expect pkt->length to
     * represent only the payload length (that is, it's measured from
     * pkt->body not from pkt->data). Temporarily adjust our outgoing
     * packet to conform to the incoming-packet semantics, so that we
     * can analyse it with the ssh_pkt_get functions.
     */
    pkt->length -= (pkt->body - pkt->data);
    pkt->savedpos = 0;

    if (ssh->logomitdata &&
        (pkt->type == SSH1_CMSG_STDIN_DATA ||
         pkt->type == SSH1_MSG_CHANNEL_DATA)) {
        /* "Session data" packets - omit the data string. */
        if (pkt->type == SSH1_MSG_CHANNEL_DATA)
            ssh_pkt_getuint32(pkt);    /* skip channel id */
        blanks[nblanks].offset = pkt->savedpos + 4;
        blanks[nblanks].type = PKTLOG_OMIT;
        ssh_pkt_getstring(pkt, &str, &slen);
        if (str) {
            blanks[nblanks].len = slen;
            nblanks++;
        }
    }

    if ((pkt->type == SSH1_CMSG_AUTH_PASSWORD ||
         pkt->type == SSH1_CMSG_AUTH_TIS_RESPONSE ||
         pkt->type == SSH1_CMSG_AUTH_CCARD_RESPONSE) &&
        conf_get_int(ssh->conf, CONF_logomitpass)) {
        /* If this is a password or similar packet, blank the password(s). */
        blanks[nblanks].offset = 0;
        blanks[nblanks].len = pkt->length;
        blanks[nblanks].type = PKTLOG_BLANK;
        nblanks++;
    } else if (pkt->type == SSH1_CMSG_X11_REQUEST_FORWARDING &&
               conf_get_int(ssh->conf, CONF_logomitpass)) {
        /*
         * If this is an X forwarding request packet, blank the fake
         * auth data.
         *
         * 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.
         */
        pkt->savedpos = 0;
        ssh_pkt_getstring(pkt, &str, &slen);
        blanks[nblanks].offset = pkt->savedpos;
        blanks[nblanks].type = PKTLOG_BLANK;
        ssh_pkt_getstring(pkt, &str, &slen);
        if (str) {
            blanks[nblanks].len = pkt->savedpos - blanks[nblanks].offset;
            nblanks++;
        }
    }

    log_packet(ssh->logctx, PKT_OUTGOING, pkt->data[12],
               ssh1_pkt_type(pkt->data[12]),
               pkt->body, pkt->length,
               nblanks, blanks, NULL, 0, NULL);

    /*
     * Undo the above adjustment of pkt->length, to put the packet
     * back in the state we found it.
     */
    pkt->length += (pkt->body - pkt->data);
}

Project: tartarus

static Bignum ssh1_pkt_getmp(struct Packet *pkt)
{
    int j;
    Bignum b;

    j = ssh1_read_bignum(pkt->body + pkt->savedpos,
			 pkt->length - pkt->savedpos, &b);

    if (j < 0)
	return NULL;

    pkt->savedpos += j;
    return b;
}

Project: tartarus

static struct Packet *ssh1_pkt_init(int pkt_type)
{
    struct Packet *pkt = ssh_new_packet();
    pkt->length = 4 + 8;	    /* space for length + max padding */
    ssh_pkt_addbyte(pkt, pkt_type);
    pkt->body = pkt->data + pkt->length;
    pkt->type = pkt_type;
    pkt->downstream_id = 0;
    pkt->additional_log_text = NULL;
    return pkt;
}

Project: tartarus

static struct Packet *ssh1_rdpkt(Ssh ssh, const unsigned char **data,
                                 int *datalen)
{
    struct rdpkt1_state_tag *st = &ssh->rdpkt1_state;

    crBegin(ssh->ssh1_rdpkt_crstate);

    st->pktin = ssh_new_packet();

    st->pktin->type = 0;
    st->pktin->length = 0;

    for (st->i = st->len = 0; st->i < 4; st->i++) {
	while ((*datalen) == 0)
	    crReturn(NULL);
	st->len = (st->len << 8) + **data;
	(*data)++, (*datalen)--;
    }

    st->pad = 8 - (st->len % 8);
    st->biglen = st->len + st->pad;
    st->pktin->length = st->len - 5;

    if (st->biglen < 0) {
        bombout(("Extremely large packet length from server suggests"
		 " data stream corruption"));
	ssh_free_packet(st->pktin);
        crStop(NULL);
    }

    st->pktin->maxlen = st->biglen;
    st->pktin->data = snewn(st->biglen + APIEXTRA, unsigned char);

    st->to_read = st->biglen;
    st->p = st->pktin->data;
    while (st->to_read > 0) {
	st->chunk = st->to_read;
	while ((*datalen) == 0)
	    crReturn(NULL);
	if (st->chunk > (*datalen))
	    st->chunk = (*datalen);
	memcpy(st->p, *data, st->chunk);
	*data += st->chunk;
	*datalen -= st->chunk;
	st->p += st->chunk;
	st->to_read -= st->chunk;
    }

    if (ssh->cipher && detect_attack(ssh->crcda_ctx, st->pktin->data,
				     st->biglen, NULL)) {
        bombout(("Network attack (CRC compensation) detected!"));
	ssh_free_packet(st->pktin);
        crStop(NULL);
    }

    if (ssh->cipher)
	ssh->cipher->decrypt(ssh->v1_cipher_ctx, st->pktin->data, st->biglen);

    st->realcrc = crc32_compute(st->pktin->data, st->biglen - 4);
    st->gotcrc = GET_32BIT(st->pktin->data + st->biglen - 4);
    if (st->gotcrc != st->realcrc) {
	bombout(("Incorrect CRC received on packet"));
	ssh_free_packet(st->pktin);
	crStop(NULL);
    }

    st->pktin->body = st->pktin->data + st->pad + 1;

    if (ssh->v1_compressing) {
	unsigned char *decompblk;
	int decomplen;
	if (!zlib_decompress_block(ssh->sc_comp_ctx,
				   st->pktin->body - 1, st->pktin->length + 1,
				   &decompblk, &decomplen)) {
	    bombout(("Zlib decompression encountered invalid data"));
	    ssh_free_packet(st->pktin);
	    crStop(NULL);
	}

	if (st->pktin->maxlen < st->pad + decomplen) {
	    st->pktin->maxlen = st->pad + decomplen;
	    st->pktin->data = sresize(st->pktin->data,
				      st->pktin->maxlen + APIEXTRA,
				      unsigned char);
	    st->pktin->body = st->pktin->data + st->pad + 1;
	}

	memcpy(st->pktin->body - 1, decompblk, decomplen);
	sfree(decompblk);
	st->pktin->length = decomplen - 1;
    }

    st->pktin->type = st->pktin->body[-1];

    /*
     * Now pktin->body and pktin->length identify the semantic content
     * of the packet, excluding the initial type byte.
     */

    if (ssh->logctx)
        ssh1_log_incoming_packet(ssh, st->pktin);

    st->pktin->savedpos = 0;

    crFinish(st->pktin);
}

Project: tartarus

static void ssh2_add_sigblob(Ssh ssh, struct Packet *pkt,
			     void *pkblob_v, int pkblob_len,
			     void *sigblob_v, int sigblob_len)
{
    unsigned char *pkblob = (unsigned char *)pkblob_v;
    unsigned char *sigblob = (unsigned char *)sigblob_v;

    /* dmemdump(pkblob, pkblob_len); */
    /* dmemdump(sigblob, sigblob_len); */

    /*
     * See if this is in fact an ssh-rsa signature and a buggy
     * server; otherwise we can just do this the easy way.
     */
    if ((ssh->remote_bugs & BUG_SSH2_RSA_PADDING) && pkblob_len > 4+7+4 &&
	(GET_32BIT(pkblob) == 7 && !memcmp(pkblob+4, "ssh-rsa", 7))) {
	int pos, len, siglen;

	/*
	 * Find the byte length of the modulus.
	 */

	pos = 4+7;		       /* skip over "ssh-rsa" */
        len = toint(GET_32BIT(pkblob+pos)); /* get length of exponent */
        if (len < 0 || len > pkblob_len - pos - 4)
            goto give_up;
	pos += 4 + len;                /* skip over exponent */
        if (pkblob_len - pos < 4)
            goto give_up;
	len = toint(GET_32BIT(pkblob+pos)); /* find length of modulus */
        if (len < 0 || len > pkblob_len - pos - 4)
            goto give_up;
	pos += 4;		       /* find modulus itself */
	while (len > 0 && pkblob[pos] == 0)
	    len--, pos++;
	/* debug(("modulus length is %d\n", len)); */

	/*
	 * Now find the signature integer.
	 */
	pos = 4+7;		       /* skip over "ssh-rsa" */
        if (sigblob_len < pos+4)
            goto give_up;
	siglen = toint(GET_32BIT(sigblob+pos));
        if (siglen != sigblob_len - pos - 4)
            goto give_up;
	/* debug(("signature length is %d\n", siglen)); */

	if (len != siglen) {
	    unsigned char newlen[4];
	    ssh2_pkt_addstring_start(pkt);
	    ssh2_pkt_addstring_data(pkt, (char *)sigblob, pos);
	    /* dmemdump(sigblob, pos); */
	    pos += 4;		       /* point to start of actual sig */
	    PUT_32BIT(newlen, len);
	    ssh2_pkt_addstring_data(pkt, (char *)newlen, 4);
	    /* dmemdump(newlen, 4); */
	    newlen[0] = 0;
	    while (len-- > siglen) {
		ssh2_pkt_addstring_data(pkt, (char *)newlen, 1);
		/* dmemdump(newlen, 1); */
	    }
	    ssh2_pkt_addstring_data(pkt, (char *)(sigblob+pos), siglen);
	    /* dmemdump(sigblob+pos, siglen); */
	    return;
	}

	/* Otherwise fall through and do it the easy way. We also come
         * here as a fallback if we discover above that the key blob
         * is misformatted in some way. */
      give_up:;
    }

    ssh2_pkt_addstring_start(pkt);
    ssh2_pkt_addstring_data(pkt, (char *)sigblob, sigblob_len);
}

Project: tartarus

static struct Packet *ssh2_bare_connection_rdpkt(Ssh ssh,
                                                 const unsigned char **data,
                                                 int *datalen)
{
    struct rdpkt2_bare_state_tag *st = &ssh->rdpkt2_bare_state;

    crBegin(ssh->ssh2_bare_rdpkt_crstate);

    /*
     * Read the packet length field.
     */
    for (st->i = 0; st->i < 4; st->i++) {
        while ((*datalen) == 0)
            crReturn(NULL);
        st->length[st->i] = *(*data)++;
        (*datalen)--;
    }

    st->packetlen = toint(GET_32BIT_MSB_FIRST(st->length));
    if (st->packetlen <= 0 || st->packetlen >= OUR_V2_PACKETLIMIT) {
        bombout(("Invalid packet length received"));
        crStop(NULL);
    }

    st->pktin = ssh_new_packet();
    st->pktin->data = snewn(st->packetlen, unsigned char);

    st->pktin->encrypted_len = st->packetlen;

    st->pktin->sequence = st->incoming_sequence++;

    /*
     * Read the remainder of the packet.
     */
    for (st->i = 0; st->i < st->packetlen; st->i++) {
        while ((*datalen) == 0)
            crReturn(NULL);
        st->pktin->data[st->i] = *(*data)++;
        (*datalen)--;
    }

    /*
     * pktin->body and pktin->length should identify the semantic
     * content of the packet, excluding the initial type byte.
     */
    st->pktin->type = st->pktin->data[0];
    st->pktin->body = st->pktin->data + 1;
    st->pktin->length = st->packetlen - 1;

    /*
     * Log incoming packet, possibly omitting sensitive fields.
     */
    if (ssh->logctx)
        ssh2_log_incoming_packet(ssh, st->pktin);

    st->pktin->savedpos = 0;

    crFinish(st->pktin);
}

Project: tartarus

static void ssh2_log_incoming_packet(Ssh ssh, struct Packet *pkt)
{
    int nblanks = 0;
    struct logblank_t blanks[4];
    char *str;
    int slen;

    pkt->savedpos = 0;

    if (ssh->logomitdata &&
        (pkt->type == SSH2_MSG_CHANNEL_DATA ||
         pkt->type == SSH2_MSG_CHANNEL_EXTENDED_DATA)) {
        /* "Session data" packets - omit the data string. */
        ssh_pkt_getuint32(pkt);    /* skip channel id */
        if (pkt->type == SSH2_MSG_CHANNEL_EXTENDED_DATA)
            ssh_pkt_getuint32(pkt);    /* skip extended data type */
        blanks[nblanks].offset = pkt->savedpos + 4;
        blanks[nblanks].type = PKTLOG_OMIT;
        ssh_pkt_getstring(pkt, &str, &slen);
        if (str) {
            blanks[nblanks].len = slen;
            nblanks++;
        }
    }

    log_packet(ssh->logctx, PKT_INCOMING, pkt->type,
               ssh2_pkt_type(ssh->pkt_kctx, ssh->pkt_actx, pkt->type),
               pkt->body, pkt->length, nblanks, blanks, &pkt->sequence,
               0, NULL);
}

Project: tartarus

static void ssh2_log_outgoing_packet(Ssh ssh, struct Packet *pkt)
{
    int nblanks = 0;
    struct logblank_t blanks[4];
    char *str;
    int slen;

    /*
     * For outgoing packets, pkt->length represents the length of the
     * whole packet starting at pkt->data (including some header), and
     * pkt->body refers to the point within that where the log-worthy
     * payload begins. However, incoming packets expect pkt->length to
     * represent only the payload length (that is, it's measured from
     * pkt->body not from pkt->data). Temporarily adjust our outgoing
     * packet to conform to the incoming-packet semantics, so that we
     * can analyse it with the ssh_pkt_get functions.
     */
    pkt->length -= (pkt->body - pkt->data);
    pkt->savedpos = 0;

    if (ssh->logomitdata &&
        (pkt->type == SSH2_MSG_CHANNEL_DATA ||
         pkt->type == SSH2_MSG_CHANNEL_EXTENDED_DATA)) {
        /* "Session data" packets - omit the data string. */
        ssh_pkt_getuint32(pkt);    /* skip channel id */
        if (pkt->type == SSH2_MSG_CHANNEL_EXTENDED_DATA)
            ssh_pkt_getuint32(pkt);    /* skip extended data type */
        blanks[nblanks].offset = pkt->savedpos + 4;
        blanks[nblanks].type = PKTLOG_OMIT;
        ssh_pkt_getstring(pkt, &str, &slen);
        if (str) {
            blanks[nblanks].len = slen;
            nblanks++;
        }
    }

    if (pkt->type == SSH2_MSG_USERAUTH_REQUEST &&
        conf_get_int(ssh->conf, CONF_logomitpass)) {
        /* If this is a password packet, blank the password(s). */
        pkt->savedpos = 0;
        ssh_pkt_getstring(pkt, &str, &slen);
        ssh_pkt_getstring(pkt, &str, &slen);
        ssh_pkt_getstring(pkt, &str, &slen);
        if (slen == 8 && !memcmp(str, "password", 8)) {
            ssh2_pkt_getbool(pkt);
            /* Blank the password field. */
            blanks[nblanks].offset = pkt->savedpos;
            blanks[nblanks].type = PKTLOG_BLANK;
            ssh_pkt_getstring(pkt, &str, &slen);
            if (str) {
                blanks[nblanks].len = pkt->savedpos - blanks[nblanks].offset;
                nblanks++;
                /* If there's another password field beyond it (change of
                 * password), blank that too. */
                ssh_pkt_getstring(pkt, &str, &slen);
                if (str)
                    blanks[nblanks-1].len =
                        pkt->savedpos - blanks[nblanks].offset;
            }
        }
    } else if (ssh->pkt_actx == SSH2_PKTCTX_KBDINTER &&
               pkt->type == SSH2_MSG_USERAUTH_INFO_RESPONSE &&
               conf_get_int(ssh->conf, CONF_logomitpass)) {
        /* If this is a keyboard-interactive response packet, blank
         * the responses. */
        pkt->savedpos = 0;
        ssh_pkt_getuint32(pkt);
        blanks[nblanks].offset = pkt->savedpos;
        blanks[nblanks].type = PKTLOG_BLANK;
        while (1) {
            ssh_pkt_getstring(pkt, &str, &slen);
            if (!str)
                break;
        }
        blanks[nblanks].len = pkt->savedpos - blanks[nblanks].offset;
        nblanks++;
    } else if (pkt->type == SSH2_MSG_CHANNEL_REQUEST &&
               conf_get_int(ssh->conf, CONF_logomitpass)) {
        /*
         * If this is an X forwarding request packet, blank the fake
         * auth data.
         *
         * 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.
         */
        pkt->savedpos = 0;
        ssh_pkt_getuint32(pkt);
        ssh_pkt_getstring(pkt, &str, &slen);
        if (slen == 7 && !memcmp(str, "x11-req", 0)) {
            ssh2_pkt_getbool(pkt);
            ssh2_pkt_getbool(pkt);
            ssh_pkt_getstring(pkt, &str, &slen);
            blanks[nblanks].offset = pkt->savedpos;
            blanks[nblanks].type = PKTLOG_BLANK;
            ssh_pkt_getstring(pkt, &str, &slen);
            if (str) {
                blanks[nblanks].len = pkt->savedpos - blanks[nblanks].offset;
                nblanks++;
            }
        }
    }

    log_packet(ssh->logctx, PKT_OUTGOING, pkt->data[5],
               ssh2_pkt_type(ssh->pkt_kctx, ssh->pkt_actx, pkt->data[5]),
               pkt->body, pkt->length, nblanks, blanks,
               &ssh->v2_outgoing_sequence,
               pkt->downstream_id, pkt->additional_log_text);

    /*
     * Undo the above adjustment of pkt->length, to put the packet
     * back in the state we found it.
     */
    pkt->length += (pkt->body - pkt->data);
}

Project: tartarus

static unsigned char *ssh2_mpint_fmt(Bignum b, int *len)
{
    unsigned char *p;
    int i, n = (bignum_bitcount(b) + 7) / 8;
    p = snewn(n + 1, unsigned char);
    p[0] = 0;
    for (i = 1; i <= n; i++)
	p[i] = bignum_byte(b, n - i);
    i = 0;
    while (i <= n && p[i] == 0 && (p[i + 1] & 0x80) == 0)
	i++;
    memmove(p, p + i, n + 1 - i);
    *len = n + 1 - i;
    return p;
}

Project: tartarus

static void ssh2_pkt_addbool(struct Packet *pkt, unsigned char value)
{
    ssh_pkt_adddata(pkt, &value, 1);
}

Project: tartarus

static void ssh2_pkt_addmp(struct Packet *pkt, Bignum b)
{
    unsigned char *p;
    int len;
    p = ssh2_mpint_fmt(b, &len);
    ssh_pkt_addstring_start(pkt);
    ssh_pkt_addstring_data(pkt, (char *)p, len);
    sfree(p);
}

Project: tartarus

static int ssh2_pkt_construct(Ssh ssh, struct Packet *pkt)
{
    int cipherblk, maclen, padding, unencrypted_prefix, i;

    if (ssh->logctx)
        ssh2_log_outgoing_packet(ssh, pkt);

    if (ssh->bare_connection) {
        /*
         * Trivial packet construction for the bare connection
         * protocol.
         */
        PUT_32BIT(pkt->data + 1, pkt->length - 5);
        pkt->body = pkt->data + 1;
        ssh->v2_outgoing_sequence++;   /* only for diagnostics, really */
        return pkt->length - 1;
    }

    /*
     * Compress packet payload.
     */
    {
	unsigned char *newpayload;
	int newlen;
	if (ssh->cscomp &&
	    ssh->cscomp->compress(ssh->cs_comp_ctx, pkt->data + 5,
				  pkt->length - 5,
				  &newpayload, &newlen)) {
	    pkt->length = 5;
	    ssh2_pkt_adddata(pkt, newpayload, newlen);
	    sfree(newpayload);
	}
    }

    /*
     * Add padding. At least four bytes, and must also bring total
     * length (minus MAC) up to a multiple of the block size.
     * If pkt->forcepad is set, make sure the packet is at least that size
     * after padding.
     */
    cipherblk = ssh->cscipher ? ssh->cscipher->blksize : 8;  /* block size */
    cipherblk = cipherblk < 8 ? 8 : cipherblk;	/* or 8 if blksize < 8 */
    padding = 4;
    unencrypted_prefix = (ssh->csmac && ssh->csmac_etm) ? 4 : 0;
    if (pkt->length + padding < pkt->forcepad)
	padding = pkt->forcepad - pkt->length;
    padding +=
	(cipherblk - (pkt->length - unencrypted_prefix + padding) % cipherblk)
        % cipherblk;
    assert(padding <= 255);
    maclen = ssh->csmac ? ssh->csmac->len : 0;
    ssh2_pkt_ensure(pkt, pkt->length + padding + maclen);
    pkt->data[4] = padding;
    for (i = 0; i < padding; i++)
	pkt->data[pkt->length + i] = random_byte();
    PUT_32BIT(pkt->data, pkt->length + padding - 4);

    /* Encrypt length if the scheme requires it */
    if (ssh->cscipher && (ssh->cscipher->flags & SSH_CIPHER_SEPARATE_LENGTH)) {
        ssh->cscipher->encrypt_length(ssh->cs_cipher_ctx, pkt->data, 4,
                                      ssh->v2_outgoing_sequence);
    }

    if (ssh->csmac && ssh->csmac_etm) {
        /*
         * OpenSSH-defined encrypt-then-MAC protocol.
         */
        if (ssh->cscipher)
            ssh->cscipher->encrypt(ssh->cs_cipher_ctx,
                                   pkt->data + 4, pkt->length + padding - 4);
        ssh->csmac->generate(ssh->cs_mac_ctx, pkt->data,
                             pkt->length + padding,
                             ssh->v2_outgoing_sequence);
    } else {
        /*
         * SSH-2 standard protocol.
         */
        if (ssh->csmac)
            ssh->csmac->generate(ssh->cs_mac_ctx, pkt->data,
                                 pkt->length + padding,
                                 ssh->v2_outgoing_sequence);
        if (ssh->cscipher)
            ssh->cscipher->encrypt(ssh->cs_cipher_ctx,
                                   pkt->data, pkt->length + padding);
    }

    ssh->v2_outgoing_sequence++;       /* whether or not we MACed */
    pkt->encrypted_len = pkt->length + padding;

    /* Ready-to-send packet starts at pkt->data. We return length. */
    pkt->body = pkt->data;
    return pkt->length + padding + maclen;
}

Project: tartarus

static void ssh2_pkt_defer(Ssh ssh, struct Packet *pkt)
{
    if (ssh->queueing)
	ssh2_pkt_queue(ssh, pkt);
    else
	ssh2_pkt_defer_noqueue(ssh, pkt, FALSE);
}

Project: tartarus

static void ssh2_pkt_defer_noqueue(Ssh ssh, struct Packet *pkt, int noignore)
{
    int len;
    if (ssh->cscipher != NULL && (ssh->cscipher->flags & SSH_CIPHER_IS_CBC) &&
	ssh->deferred_len == 0 && !noignore &&
	!(ssh->remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE)) {
	/*
	 * Interpose an SSH_MSG_IGNORE to ensure that user data don't
	 * get encrypted with a known IV.
	 */
	struct Packet *ipkt = ssh2_pkt_init(SSH2_MSG_IGNORE);
	ssh2_pkt_addstring_start(ipkt);
	ssh2_pkt_defer_noqueue(ssh, ipkt, TRUE);
    }
    len = ssh2_pkt_construct(ssh, pkt);
    if (ssh->deferred_len + len > ssh->deferred_size) {
	ssh->deferred_size = ssh->deferred_len + len + 128;
	ssh->deferred_send_data = sresize(ssh->deferred_send_data,
					  ssh->deferred_size,
					  unsigned char);
    }
    memcpy(ssh->deferred_send_data + ssh->deferred_len, pkt->body, len);
    ssh->deferred_len += len;
    ssh->deferred_data_size += pkt->encrypted_len;
    ssh_free_packet(pkt);
}

Project: tartarus

static int ssh2_pkt_getbool(struct Packet *pkt)
{
    unsigned long value;
    if (pkt->length - pkt->savedpos < 1)
	return 0;		       /* arrgh, no way to decline (FIXME?) */
    value = pkt->body[pkt->savedpos] != 0;
    pkt->savedpos++;
    return value;
}

Project: tartarus

static struct Packet *ssh2_pkt_init(int pkt_type)
{
    struct Packet *pkt = ssh_new_packet();
    pkt->length = 5; /* space for packet length + padding length */
    pkt->forcepad = 0;
    pkt->type = pkt_type;
    ssh_pkt_addbyte(pkt, (unsigned char) pkt_type);
    pkt->body = pkt->data + pkt->length; /* after packet type */
    pkt->downstream_id = 0;
    pkt->additional_log_text = NULL;
    return pkt;
}

Project: tartarus

static void ssh2_pkt_queue(Ssh ssh, struct Packet *pkt)
{
    assert(ssh->queueing);

    if (ssh->queuelen >= ssh->queuesize) {
	ssh->queuesize = ssh->queuelen + 32;
	ssh->queue = sresize(ssh->queue, ssh->queuesize, struct Packet *);
    }

    ssh->queue[ssh->queuelen++] = pkt;
}

Project: tartarus

static void ssh2_pkt_queuesend(Ssh ssh)
{
    int i;

    assert(!ssh->queueing);

    for (i = 0; i < ssh->queuelen; i++)
	ssh2_pkt_defer_noqueue(ssh, ssh->queue[i], FALSE);
    ssh->queuelen = 0;

    ssh_pkt_defersend(ssh);
}

Project: tartarus

static void ssh2_pkt_send(Ssh ssh, struct Packet *pkt)
{
    if (ssh->queueing)
	ssh2_pkt_queue(ssh, pkt);
    else
	ssh2_pkt_send_noqueue(ssh, pkt);
}

Project: tartarus

static void ssh2_pkt_send_noqueue(Ssh ssh, struct Packet *pkt)
{
    int len;
    int backlog;
    if (ssh->cscipher != NULL && (ssh->cscipher->flags & SSH_CIPHER_IS_CBC)) {
	/* We need to send two packets, so use the deferral mechanism. */
	ssh2_pkt_defer_noqueue(ssh, pkt, FALSE);
	ssh_pkt_defersend(ssh);
	return;
    }
    len = ssh2_pkt_construct(ssh, pkt);
    backlog = s_write(ssh, pkt->body, len);
    if (backlog > SSH_MAX_BACKLOG)
	ssh_throttle_all(ssh, 1, backlog);

    ssh->outgoing_data_size += pkt->encrypted_len;
    if (!ssh->kex_in_progress &&
        !ssh->bare_connection &&
	ssh->max_data_size != 0 &&
	ssh->outgoing_data_size > ssh->max_data_size)
	do_ssh2_transport(ssh, "too much data sent", -1, NULL);

    ssh_free_packet(pkt);
}

Project: tartarus

static void ssh2_pkt_send_with_padding(Ssh ssh, struct Packet *pkt,
				       int padsize)
{
#if 0
    if (0) {
	/*
	 * The simplest way to do this is to adjust the
	 * variable-length padding field in the outgoing packet.
	 * 
	 * Currently compiled out, because some Cisco SSH servers
	 * don't like excessively padded packets (bah, why's it
	 * always Cisco?)
	 */
	pkt->forcepad = padsize;
	ssh2_pkt_send(ssh, pkt);
    } else
#endif
    {
	/*
	 * If we can't do that, however, an alternative approach is
	 * to use the pkt_defer mechanism to bundle the packet
	 * tightly together with an SSH_MSG_IGNORE such that their
	 * combined length is a constant. So first we construct the
	 * final form of this packet and defer its sending.
	 */
	ssh2_pkt_defer(ssh, pkt);

	/*
	 * Now construct an SSH_MSG_IGNORE which includes a string
	 * that's an exact multiple of the cipher block size. (If
	 * the cipher is NULL so that the block size is
	 * unavailable, we don't do this trick at all, because we
	 * gain nothing by it.)
	 */
	if (ssh->cscipher &&
	    !(ssh->remote_bugs & BUG_CHOKES_ON_SSH2_IGNORE)) {
	    int stringlen, i;

	    stringlen = (256 - ssh->deferred_len);
	    stringlen += ssh->cscipher->blksize - 1;
	    stringlen -= (stringlen % ssh->cscipher->blksize);
	    if (ssh->cscomp) {
		/*
		 * Temporarily disable actual compression, so we
		 * can guarantee to get this string exactly the
		 * length we want it. The compression-disabling
		 * routine should return an integer indicating how
		 * many bytes we should adjust our string length
		 * by.
		 */
		stringlen -=
		    ssh->cscomp->disable_compression(ssh->cs_comp_ctx);
	    }
	    pkt = ssh2_pkt_init(SSH2_MSG_IGNORE);
	    ssh2_pkt_addstring_start(pkt);
	    for (i = 0; i < stringlen; i++) {
		char c = (char) random_byte();
		ssh2_pkt_addstring_data(pkt, &c, 1);
	    }
	    ssh2_pkt_defer(ssh, pkt);
	}
	ssh_pkt_defersend(ssh);
    }
}

Project: tartarus

static const char *ssh2_pkt_type(Pkt_KCtx pkt_kctx, Pkt_ACtx pkt_actx,
                                 int type)
{
    translatea(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE,SSH2_PKTCTX_GSSAPI);
    translatea(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,SSH2_PKTCTX_GSSAPI);
    translatea(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE,SSH2_PKTCTX_GSSAPI);
    translatea(SSH2_MSG_USERAUTH_GSSAPI_ERROR,SSH2_PKTCTX_GSSAPI);
    translatea(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK,SSH2_PKTCTX_GSSAPI);
    translatea(SSH2_MSG_USERAUTH_GSSAPI_MIC, SSH2_PKTCTX_GSSAPI);
    translate(SSH2_MSG_DISCONNECT);
    translate(SSH2_MSG_IGNORE);
    translate(SSH2_MSG_UNIMPLEMENTED);
    translate(SSH2_MSG_DEBUG);
    translate(SSH2_MSG_SERVICE_REQUEST);
    translate(SSH2_MSG_SERVICE_ACCEPT);
    translate(SSH2_MSG_KEXINIT);
    translate(SSH2_MSG_NEWKEYS);
    translatek(SSH2_MSG_KEXDH_INIT, SSH2_PKTCTX_DHGROUP);
    translatek(SSH2_MSG_KEXDH_REPLY, SSH2_PKTCTX_DHGROUP);
    translatek(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD, SSH2_PKTCTX_DHGEX);
    translatek(SSH2_MSG_KEX_DH_GEX_REQUEST, SSH2_PKTCTX_DHGEX);
    translatek(SSH2_MSG_KEX_DH_GEX_GROUP, SSH2_PKTCTX_DHGEX);
    translatek(SSH2_MSG_KEX_DH_GEX_INIT, SSH2_PKTCTX_DHGEX);
    translatek(SSH2_MSG_KEX_DH_GEX_REPLY, SSH2_PKTCTX_DHGEX);
    translatek(SSH2_MSG_KEXRSA_PUBKEY, SSH2_PKTCTX_RSAKEX);
    translatek(SSH2_MSG_KEXRSA_SECRET, SSH2_PKTCTX_RSAKEX);
    translatek(SSH2_MSG_KEXRSA_DONE, SSH2_PKTCTX_RSAKEX);
    translatek(SSH2_MSG_KEX_ECDH_INIT, SSH2_PKTCTX_ECDHKEX);
    translatek(SSH2_MSG_KEX_ECDH_REPLY, SSH2_PKTCTX_ECDHKEX);
    translate(SSH2_MSG_USERAUTH_REQUEST);
    translate(SSH2_MSG_USERAUTH_FAILURE);
    translate(SSH2_MSG_USERAUTH_SUCCESS);
    translate(SSH2_MSG_USERAUTH_BANNER);
    translatea(SSH2_MSG_USERAUTH_PK_OK, SSH2_PKTCTX_PUBLICKEY);
    translatea(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, SSH2_PKTCTX_PASSWORD);
    translatea(SSH2_MSG_USERAUTH_INFO_REQUEST, SSH2_PKTCTX_KBDINTER);
    translatea(SSH2_MSG_USERAUTH_INFO_RESPONSE, SSH2_PKTCTX_KBDINTER);
    translate(SSH2_MSG_GLOBAL_REQUEST);
    translate(SSH2_MSG_REQUEST_SUCCESS);
    translate(SSH2_MSG_REQUEST_FAILURE);
    translate(SSH2_MSG_CHANNEL_OPEN);
    translate(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
    translate(SSH2_MSG_CHANNEL_OPEN_FAILURE);
    translate(SSH2_MSG_CHANNEL_WINDOW_ADJUST);
    translate(SSH2_MSG_CHANNEL_DATA);
    translate(SSH2_MSG_CHANNEL_EXTENDED_DATA);
    translate(SSH2_MSG_CHANNEL_EOF);
    translate(SSH2_MSG_CHANNEL_CLOSE);
    translate(SSH2_MSG_CHANNEL_REQUEST);
    translate(SSH2_MSG_CHANNEL_SUCCESS);
    translate(SSH2_MSG_CHANNEL_FAILURE);
    return "unknown";
}

Project: tartarus

static struct Packet *ssh2_rdpkt(Ssh ssh, const unsigned char **data,
                                 int *datalen)
{
    struct rdpkt2_state_tag *st = &ssh->rdpkt2_state;

    crBegin(ssh->ssh2_rdpkt_crstate);

    st->pktin = ssh_new_packet();

    st->pktin->type = 0;
    st->pktin->length = 0;
    if (ssh->sccipher)
	st->cipherblk = ssh->sccipher->blksize;
    else
	st->cipherblk = 8;
    if (st->cipherblk < 8)
	st->cipherblk = 8;
    st->maclen = ssh->scmac ? ssh->scmac->len : 0;

    if (ssh->sccipher && (ssh->sccipher->flags & SSH_CIPHER_IS_CBC) &&
	ssh->scmac && !ssh->scmac_etm) {
	/*
	 * When dealing with a CBC-mode cipher, we want to avoid the
	 * possibility of an attacker's tweaking the ciphertext stream
	 * so as to cause us to feed the same block to the block
	 * cipher more than once and thus leak information
	 * (VU#958563).  The way we do this is not to take any
	 * decisions on the basis of anything we've decrypted until
	 * we've verified it with a MAC.  That includes the packet
	 * length, so we just read data and check the MAC repeatedly,
	 * and when the MAC passes, see if the length we've got is
	 * plausible.
         *
         * This defence is unnecessary in OpenSSH ETM mode, because
         * the whole point of ETM mode is that the attacker can't
         * tweak the ciphertext stream at all without the MAC
         * detecting it before we decrypt anything.
	 */

	/* May as well allocate the whole lot now. */
	st->pktin->data = snewn(OUR_V2_PACKETLIMIT + st->maclen + APIEXTRA,
				unsigned char);

	/* Read an amount corresponding to the MAC. */
	for (st->i = 0; st->i < st->maclen; st->i++) {
	    while ((*datalen) == 0)
		crReturn(NULL);
	    st->pktin->data[st->i] = *(*data)++;
	    (*datalen)--;
	}

	st->packetlen = 0;
	{
	    unsigned char seq[4];
	    ssh->scmac->start(ssh->sc_mac_ctx);
	    PUT_32BIT(seq, st->incoming_sequence);
	    ssh->scmac->bytes(ssh->sc_mac_ctx, seq, 4);
	}

	for (;;) { /* Once around this loop per cipher block. */
	    /* Read another cipher-block's worth, and tack it onto the end. */
	    for (st->i = 0; st->i < st->cipherblk; st->i++) {
		while ((*datalen) == 0)
		    crReturn(NULL);
		st->pktin->data[st->packetlen+st->maclen+st->i] = *(*data)++;
		(*datalen)--;
	    }
	    /* Decrypt one more block (a little further back in the stream). */
	    ssh->sccipher->decrypt(ssh->sc_cipher_ctx,
				   st->pktin->data + st->packetlen,
				   st->cipherblk);
	    /* Feed that block to the MAC. */
	    ssh->scmac->bytes(ssh->sc_mac_ctx,
			      st->pktin->data + st->packetlen, st->cipherblk);
	    st->packetlen += st->cipherblk;
	    /* See if that gives us a valid packet. */
	    if (ssh->scmac->verresult(ssh->sc_mac_ctx,
				      st->pktin->data + st->packetlen) &&
		((st->len = toint(GET_32BIT(st->pktin->data))) ==
                 st->packetlen-4))
		    break;
	    if (st->packetlen >= OUR_V2_PACKETLIMIT) {
		bombout(("No valid incoming packet found"));
		ssh_free_packet(st->pktin);
		crStop(NULL);
	    }	    
	}
	st->pktin->maxlen = st->packetlen + st->maclen;
	st->pktin->data = sresize(st->pktin->data,
				  st->pktin->maxlen + APIEXTRA,
				  unsigned char);
    } else if (ssh->scmac && ssh->scmac_etm) {
	st->pktin->data = snewn(4 + APIEXTRA, unsigned char);

        /*
         * OpenSSH encrypt-then-MAC mode: the packet length is
         * unencrypted, unless the cipher supports length encryption.
         */
	for (st->i = st->len = 0; st->i < 4; st->i++) {
	    while ((*datalen) == 0)
		crReturn(NULL);
	    st->pktin->data[st->i] = *(*data)++;
	    (*datalen)--;
	}
        /* Cipher supports length decryption, so do it */
        if (ssh->sccipher && (ssh->sccipher->flags & SSH_CIPHER_SEPARATE_LENGTH)) {
            /* Keep the packet the same though, so the MAC passes */
            unsigned char len[4];
            memcpy(len, st->pktin->data, 4);
            ssh->sccipher->decrypt_length(ssh->sc_cipher_ctx, len, 4, st->incoming_sequence);
            st->len = toint(GET_32BIT(len));
        } else {
            st->len = toint(GET_32BIT(st->pktin->data));
        }

	/*
	 * _Completely_ silly lengths should be stomped on before they
	 * do us any more damage.
	 */
	if (st->len < 0 || st->len > OUR_V2_PACKETLIMIT ||
	    st->len % st->cipherblk != 0) {
	    bombout(("Incoming packet length field was garbled"));
	    ssh_free_packet(st->pktin);
	    crStop(NULL);
	}

	/*
	 * So now we can work out the total packet length.
	 */
	st->packetlen = st->len + 4;

	/*
	 * Allocate memory for the rest of the packet.
	 */
	st->pktin->maxlen = st->packetlen + st->maclen;
	st->pktin->data = sresize(st->pktin->data,
				  st->pktin->maxlen + APIEXTRA,
				  unsigned char);

	/*
	 * Read the remainder of the packet.
	 */
	for (st->i = 4; st->i < st->packetlen + st->maclen; st->i++) {
	    while ((*datalen) == 0)
		crReturn(NULL);
	    st->pktin->data[st->i] = *(*data)++;
	    (*datalen)--;
	}

	/*
	 * Check the MAC.
	 */
	if (ssh->scmac
	    && !ssh->scmac->verify(ssh->sc_mac_ctx, st->pktin->data,
				   st->len + 4, st->incoming_sequence)) {
	    bombout(("Incorrect MAC received on packet"));
	    ssh_free_packet(st->pktin);
	    crStop(NULL);
	}

	/* Decrypt everything between the length field and the MAC. */
	if (ssh->sccipher)
	    ssh->sccipher->decrypt(ssh->sc_cipher_ctx,
				   st->pktin->data + 4,
				   st->packetlen - 4);
    } else {
	st->pktin->data = snewn(st->cipherblk + APIEXTRA, unsigned char);

	/*
	 * Acquire and decrypt the first block of the packet. This will
	 * contain the length and padding details.
	 */
	for (st->i = st->len = 0; st->i < st->cipherblk; st->i++) {
	    while ((*datalen) == 0)
		crReturn(NULL);
	    st->pktin->data[st->i] = *(*data)++;
	    (*datalen)--;
	}

	if (ssh->sccipher)
	    ssh->sccipher->decrypt(ssh->sc_cipher_ctx,
				   st->pktin->data, st->cipherblk);

	/*
	 * Now get the length figure.
	 */
	st->len = toint(GET_32BIT(st->pktin->data));

	/*
	 * _Completely_ silly lengths should be stomped on before they
	 * do us any more damage.
	 */
	if (st->len < 0 || st->len > OUR_V2_PACKETLIMIT ||
	    (st->len + 4) % st->cipherblk != 0) {
	    bombout(("Incoming packet was garbled on decryption"));
	    ssh_free_packet(st->pktin);
	    crStop(NULL);
	}

	/*
	 * So now we can work out the total packet length.
	 */
	st->packetlen = st->len + 4;

	/*
	 * Allocate memory for the rest of the packet.
	 */
	st->pktin->maxlen = st->packetlen + st->maclen;
	st->pktin->data = sresize(st->pktin->data,
				  st->pktin->maxlen + APIEXTRA,
				  unsigned char);

	/*
	 * Read and decrypt the remainder of the packet.
	 */
	for (st->i = st->cipherblk; st->i < st->packetlen + st->maclen;
	     st->i++) {
	    while ((*datalen) == 0)
		crReturn(NULL);
	    st->pktin->data[st->i] = *(*data)++;
	    (*datalen)--;
	}
	/* Decrypt everything _except_ the MAC. */
	if (ssh->sccipher)
	    ssh->sccipher->decrypt(ssh->sc_cipher_ctx,
				   st->pktin->data + st->cipherblk,
				   st->packetlen - st->cipherblk);

	/*
	 * Check the MAC.
	 */
	if (ssh->scmac
	    && !ssh->scmac->verify(ssh->sc_mac_ctx, st->pktin->data,
				   st->len + 4, st->incoming_sequence)) {
	    bombout(("Incorrect MAC received on packet"));
	    ssh_free_packet(st->pktin);
	    crStop(NULL);
	}
    }
    /* Get and sanity-check the amount of random padding. */
    st->pad = st->pktin->data[4];
    if (st->pad < 4 || st->len - st->pad < 1) {
	bombout(("Invalid padding length on received packet"));
	ssh_free_packet(st->pktin);
	crStop(NULL);
    }
    /*
     * This enables us to deduce the payload length.
     */
    st->payload = st->len - st->pad - 1;

    st->pktin->length = st->payload + 5;
    st->pktin->encrypted_len = st->packetlen;

    st->pktin->sequence = st->incoming_sequence++;

    st->pktin->length = st->packetlen - st->pad;
    assert(st->pktin->length >= 0);

    /*
     * Decompress packet payload.
     */
    {
	unsigned char *newpayload;
	int newlen;
	if (ssh->sccomp &&
	    ssh->sccomp->decompress(ssh->sc_comp_ctx,
				    st->pktin->data + 5, st->pktin->length - 5,
				    &newpayload, &newlen)) {
	    if (st->pktin->maxlen < newlen + 5) {
		st->pktin->maxlen = newlen + 5;
		st->pktin->data = sresize(st->pktin->data,
					  st->pktin->maxlen + APIEXTRA,
					  unsigned char);
	    }
	    st->pktin->length = 5 + newlen;
	    memcpy(st->pktin->data + 5, newpayload, newlen);
	    sfree(newpayload);
	}
    }

    /*
     * RFC 4253 doesn't explicitly say that completely empty packets
     * with no type byte are forbidden, so treat them as deserving
     * an SSH_MSG_UNIMPLEMENTED.
     */
    if (st->pktin->length <= 5) { /* == 5 we hope, but robustness */
        ssh2_msg_something_unimplemented(ssh, st->pktin);
        crStop(NULL);
    }
    /*
     * pktin->body and pktin->length should identify the semantic
     * content of the packet, excluding the initial type byte.
     */
    st->pktin->type = st->pktin->data[5];
    st->pktin->body = st->pktin->data + 6;
    st->pktin->length -= 6;
    assert(st->pktin->length >= 0);    /* one last double-check */

    if (ssh->logctx)
        ssh2_log_incoming_packet(ssh, st->pktin);

    st->pktin->savedpos = 0;

    crFinish(st->pktin);
}

Project: tartarus

static int ssh_channelfind(void *av, void *bv)
{
    unsigned *a = (unsigned *) av;
    struct ssh_channel *b = (struct ssh_channel *) bv;
    if (*a < b->localid)
	return -1;
    if (*a > b->localid)
	return +1;
    return 0;
}

Project: tartarus

static int ssh_closing(Plug plug, const char *error_msg, int error_code,
		       int calling_back)
{
    Ssh ssh = (Ssh) plug;
    int need_notify = ssh_do_close(ssh, FALSE);

    if (!error_msg) {
	if (!ssh->close_expected)
	    error_msg = "Server unexpectedly closed network connection";
	else
	    error_msg = "Server closed network connection";
    }

    if (ssh->close_expected && ssh->clean_exit && ssh->exitcode < 0)
	ssh->exitcode = 0;

    if (need_notify)
        notify_remote_exit(ssh->frontend);

    if (error_msg)
	logevent(error_msg);
    if (!ssh->close_expected || !ssh->clean_exit)
	connection_fatal(ssh->frontend, "%s", error_msg);
    return 0;
}

Project: tartarus

static int ssh_comp_none_block(void *handle, unsigned char *block, int len,
			       unsigned char **outblock, int *outlen)
{
    return 0;
}

Project: tartarus

static void ssh_comp_none_cleanup(void *handle)
{
}

Project: tartarus

static int ssh_comp_none_disable(void *handle)
{
    return 0;
}

Project: tartarus

static void *ssh_comp_none_init(void)
{
    return NULL;
}

Project: tartarus

void ssh_connshare_log(Ssh ssh, int event, const char *logtext,
                       const char *ds_err, const char *us_err)
{
    if (event == SHARE_NONE) {
        /* In this case, 'logtext' is an error message indicating a
         * reason why connection sharing couldn't be set up _at all_.
         * Failing that, ds_err and us_err indicate why we couldn't be
         * a downstream and an upstream respectively. */
        if (logtext) {
            logeventf(ssh, "Could not set up connection sharing: %s", logtext);
        } else {
            if (ds_err)
                logeventf(ssh, "Could not set up connection sharing"
                          " as downstream: %s", ds_err);
            if (us_err)
                logeventf(ssh, "Could not set up connection sharing"
                          " as upstream: %s", us_err);
        }
    } else if (event == SHARE_DOWNSTREAM) {
        /* In this case, 'logtext' is a local endpoint address */
        logeventf(ssh, "Using existing shared connection at %s", logtext);
        /* Also we should mention this in the console window to avoid
         * confusing users as to why this window doesn't behave the
         * usual way. */
        if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE)) {
            c_write_str(ssh,"Reusing a shared connection to this server.\r\n");
        }
    } else if (event == SHARE_UPSTREAM) {
        /* In this case, 'logtext' is a local endpoint address too */
        logeventf(ssh, "Sharing this connection at %s", logtext);
    }
}

Project: tartarus

static void ssh_detect_bugs(Ssh ssh, char *vstring)
{
    char *imp;			       /* pointer to implementation part */
    imp = vstring;
    imp += strcspn(imp, "-");
    if (*imp) imp++;
    imp += strcspn(imp, "-");
    if (*imp) imp++;

    ssh->remote_bugs = 0;

    /*
     * General notes on server version strings:
     *  - Not all servers reporting "Cisco-1.25" have all the bugs listed
     *    here -- in particular, we've heard of one that's perfectly happy
     *    with SSH1_MSG_IGNOREs -- but this string never seems to change,
     *    so we can't distinguish them.
     */
    if (conf_get_int(ssh->conf, CONF_sshbug_ignore1) == FORCE_ON ||
	(conf_get_int(ssh->conf, CONF_sshbug_ignore1) == AUTO &&
	 (!strcmp(imp, "1.2.18") || !strcmp(imp, "1.2.19") ||
	  !strcmp(imp, "1.2.20") || !strcmp(imp, "1.2.21") ||
	  !strcmp(imp, "1.2.22") || !strcmp(imp, "Cisco-1.25") ||
	  !strcmp(imp, "OSU_1.4alpha3") || !strcmp(imp, "OSU_1.5alpha4")))) {
	/*
	 * These versions don't support SSH1_MSG_IGNORE, so we have
	 * to use a different defence against password length
	 * sniffing.
	 */
	ssh->remote_bugs |= BUG_CHOKES_ON_SSH1_IGNORE;
	logevent("We believe remote version has SSH-1 ignore bug");
    }

    if (conf_get_int(ssh->conf, CONF_sshbug_plainpw1) == FORCE_ON ||
	(conf_get_int(ssh->conf, CONF_sshbug_plainpw1) == AUTO &&
	 (!strcmp(imp, "Cisco-1.25") || !strcmp(imp, "OSU_1.4alpha3")))) {
	/*
	 * These versions need a plain password sent; they can't
	 * handle having a null and a random length of data after
	 * the password.
	 */
	ssh->remote_bugs |= BUG_NEEDS_SSH1_PLAIN_PASSWORD;
	logevent("We believe remote version needs a plain SSH-1 password");
    }

    if (conf_get_int(ssh->conf, CONF_sshbug_rsa1) == FORCE_ON ||
	(conf_get_int(ssh->conf, CONF_sshbug_rsa1) == AUTO &&
	 (!strcmp(imp, "Cisco-1.25")))) {
	/*
	 * These versions apparently have no clue whatever about
	 * RSA authentication and will panic and die if they see
	 * an AUTH_RSA message.
	 */
	ssh->remote_bugs |= BUG_CHOKES_ON_RSA;
	logevent("We believe remote version can't handle SSH-1 RSA authentication");
    }

    if (conf_get_int(ssh->conf, CONF_sshbug_hmac2) == FORCE_ON ||
	(conf_get_int(ssh->conf, CONF_sshbug_hmac2) == AUTO &&
	 !wc_match("* VShell", imp) &&
	 (wc_match("2.1.0*", imp) || wc_match("2.0.*", imp) ||
	  wc_match("2.2.0*", imp) || wc_match("2.3.0*", imp) ||
	  wc_match("2.1 *", imp)))) {
	/*
	 * These versions have the HMAC bug.
	 */
	ssh->remote_bugs |= BUG_SSH2_HMAC;
	logevent("We believe remote version has SSH-2 HMAC bug");
    }

    if (conf_get_int(ssh->conf, CONF_sshbug_derivekey2) == FORCE_ON ||
	(conf_get_int(ssh->conf, CONF_sshbug_derivekey2) == AUTO &&
	 !wc_match("* VShell", imp) &&
	 (wc_match("2.0.0*", imp) || wc_match("2.0.10*", imp) ))) {
	/*
	 * These versions have the key-derivation bug (failing to
	 * include the literal shared secret in the hashes that
	 * generate the keys).
	 */
	ssh->remote_bugs |= BUG_SSH2_DERIVEKEY;
	logevent("We believe remote version has SSH-2 key-derivation bug");
    }

    if (conf_get_int(ssh->conf, CONF_sshbug_rsapad2) == FORCE_ON ||
	(conf_get_int(ssh->conf, CONF_sshbug_rsapad2) == AUTO &&
	 (wc_match("OpenSSH_2.[5-9]*", imp) ||
	  wc_match("OpenSSH_3.[0-2]*", imp) ||
	  wc_match("mod_sftp/0.[0-8]*", imp) ||
	  wc_match("mod_sftp/0.9.[0-8]", imp)))) {
	/*
	 * These versions have the SSH-2 RSA padding bug.
	 */
	ssh->remote_bugs |= BUG_SSH2_RSA_PADDING;
	logevent("We believe remote version has SSH-2 RSA padding bug");
    }

    if (conf_get_int(ssh->conf, CONF_sshbug_pksessid2) == FORCE_ON ||
	(conf_get_int(ssh->conf, CONF_sshbug_pksessid2) == AUTO &&
	 wc_match("OpenSSH_2.[0-2]*", imp))) {
	/*
	 * These versions have the SSH-2 session-ID bug in
	 * public-key authentication.
	 */
	ssh->remote_bugs |= BUG_SSH2_PK_SESSIONID;
	logevent("We believe remote version has SSH-2 public-key-session-ID bug");
    }

    if (conf_get_int(ssh->conf, CONF_sshbug_rekey2) == FORCE_ON ||
	(conf_get_int(ssh->conf, CONF_sshbug_rekey2) == AUTO &&
	 (wc_match("DigiSSH_2.0", imp) ||
	  wc_match("OpenSSH_2.[0-4]*", imp) ||
	  wc_match("OpenSSH_2.5.[0-3]*", imp) ||
	  wc_match("Sun_SSH_1.0", imp) ||
	  wc_match("Sun_SSH_1.0.1", imp) ||
	  /* All versions <= 1.2.6 (they changed their format in 1.2.7) */
	  wc_match("WeOnlyDo-*", imp)))) {
	/*
	 * These versions have the SSH-2 rekey bug.
	 */
	ssh->remote_bugs |= BUG_SSH2_REKEY;
	logevent("We believe remote version has SSH-2 rekey bug");
    }

    if (conf_get_int(ssh->conf, CONF_sshbug_maxpkt2) == FORCE_ON ||
	(conf_get_int(ssh->conf, CONF_sshbug_maxpkt2) == AUTO &&
	 (wc_match("1.36_sshlib GlobalSCAPE", imp) ||
          wc_match("1.36 sshlib: GlobalScape", imp)))) {
	/*
	 * This version ignores our makpkt and needs to be throttled.
	 */
	ssh->remote_bugs |= BUG_SSH2_MAXPKT;
	logevent("We believe remote version ignores SSH-2 maximum packet size");
    }

    if (conf_get_int(ssh->conf, CONF_sshbug_ignore2) == FORCE_ON) {
	/*
	 * Servers that don't support SSH2_MSG_IGNORE. Currently,
	 * none detected automatically.
	 */
	ssh->remote_bugs |= BUG_CHOKES_ON_SSH2_IGNORE;
	logevent("We believe remote version has SSH-2 ignore bug");
    }

    if (conf_get_int(ssh->conf, CONF_sshbug_oldgex2) == FORCE_ON ||
	(conf_get_int(ssh->conf, CONF_sshbug_oldgex2) == AUTO &&
	 (wc_match("OpenSSH_2.[235]*", imp)))) {
	/*
	 * These versions only support the original (pre-RFC4419)
	 * SSH-2 GEX request, and disconnect with a protocol error if
	 * we use the newer version.
	 */
	ssh->remote_bugs |= BUG_SSH2_OLDGEX;
	logevent("We believe remote version has outdated SSH-2 GEX");
    }

    if (conf_get_int(ssh->conf, CONF_sshbug_winadj) == FORCE_ON) {
	/*
	 * Servers that don't support our winadj request for one
	 * reason or another. Currently, none detected automatically.
	 */
	ssh->remote_bugs |= BUG_CHOKES_ON_WINADJ;
	logevent("We believe remote version has winadj bug");
    }

    if (conf_get_int(ssh->conf, CONF_sshbug_chanreq) == FORCE_ON ||
	(conf_get_int(ssh->conf, CONF_sshbug_chanreq) == AUTO &&
	 (wc_match("OpenSSH_[2-5].*", imp) ||
	  wc_match("OpenSSH_6.[0-6]*", imp) ||
	  wc_match("dropbear_0.[2-4][0-9]*", imp) ||
	  wc_match("dropbear_0.5[01]*", imp)))) {
	/*
	 * These versions have the SSH-2 channel request bug.
	 * OpenSSH 6.7 and above do not:
	 * https://bugzilla.mindrot.org/show_bug.cgi?id=1818
	 * dropbear_0.52 and above do not:
	 * https://secure.ucc.asn.au/hg/dropbear/rev/cd02449b709c
	 */
	ssh->remote_bugs |= BUG_SENDS_LATE_REQUEST_REPLY;
	logevent("We believe remote version has SSH-2 channel request bug");
    }
}

Project: tartarus

static int ssh_do_close(Ssh ssh, int notify_exit)
{
    int ret = 0;
    struct ssh_channel *c;

    ssh->state = SSH_STATE_CLOSED;
    expire_timer_context(ssh);
    if (ssh->s) {
        sk_close(ssh->s);
        ssh->s = NULL;
        if (notify_exit)
            notify_remote_exit(ssh->frontend);
        else
            ret = 1;
    }
    /*
     * Now we must shut down any port- and X-forwarded channels going
     * through this connection.
     */
    if (ssh->channels) {
	while (NULL != (c = index234(ssh->channels, 0))) {
	    ssh_channel_close_local(c, NULL);
	    del234(ssh->channels, c); /* moving next one to index 0 */
	    if (ssh->version == 2)
		bufchain_clear(&c->v.v2.outbuffer);
	    sfree(c);
	}
    }
    /*
     * Go through port-forwardings, and close any associated
     * listening sockets.
     */
    if (ssh->portfwds) {
	struct ssh_portfwd *pf;
	while (NULL != (pf = index234(ssh->portfwds, 0))) {
	    /* Dispose of any listening socket. */
	    if (pf->local)
		pfl_terminate(pf->local);
	    del234(ssh->portfwds, pf); /* moving next one to index 0 */
	    free_portfwd(pf);
	}
	freetree234(ssh->portfwds);
	ssh->portfwds = NULL;
    }

    /*
     * Also stop attempting to connection-share.
     */
    if (ssh->connshare) {
        sharestate_free(ssh->connshare);
        ssh->connshare = NULL;
    }

    return ret;
}

Project: tartarus

static void ssh_fix_verstring(char *str)
{
    /* Eat "<protoversion>-". */
    while (*str && *str != '-') str++;
    assert(*str == '-'); str++;

    /* Convert minus signs and spaces in the remaining string into
     * underscores. */
    while (*str) {
        if (*str == '-' || *str == ' ')
            *str = '_';
        str++;
    }
}

Project: tartarus

static void ssh_free_packet(struct Packet *pkt)
{
    sfree(pkt->data);
    sfree(pkt);
}

Project: tartarus

static void ssh_gotdata(Ssh ssh, const unsigned char *data, int datalen)
{
    /* Log raw data, if we're in that mode. */
    if (ssh->logctx)
	log_packet(ssh->logctx, PKT_INCOMING, -1, NULL, data, datalen,
		   0, NULL, NULL, 0, NULL);

    crBegin(ssh->ssh_gotdata_crstate);

    /*
     * To begin with, feed the characters one by one to the
     * protocol initialisation / selection function do_ssh_init().
     * When that returns 0, we're done with the initial greeting
     * exchange and can move on to packet discipline.
     */
    while (1) {
	int ret;		       /* need not be kept across crReturn */
	if (datalen == 0)
	    crReturnV;		       /* more data please */
	ret = ssh->do_ssh_init(ssh, *data);
	data++;
	datalen--;
	if (ret == 0)
	    break;
    }

    /*
     * We emerge from that loop when the initial negotiation is
     * over and we have selected an s_rdpkt function. Now pass
     * everything to s_rdpkt, and then pass the resulting packets
     * to the proper protocol handler.
     */

    while (1) {
	while (bufchain_size(&ssh->queued_incoming_data) > 0 || datalen > 0) {
	    if (ssh->frozen) {
		ssh_queue_incoming_data(ssh, &data, &datalen);
		/* This uses up all data and cannot cause anything interesting
		 * to happen; indeed, for anything to happen at all, we must
		 * return, so break out. */
		break;
	    } else if (bufchain_size(&ssh->queued_incoming_data) > 0) {
		/* This uses up some or all data, and may freeze the
		 * session. */
		ssh_process_queued_incoming_data(ssh);
	    } else {
		/* This uses up some or all data, and may freeze the
		 * session. */
		ssh_process_incoming_data(ssh, &data, &datalen);
	    }
	    /* FIXME this is probably EBW. */
	    if (ssh->state == SSH_STATE_CLOSED)
		return;
	}
	/* We're out of data. Go and get some more. */
	crReturnV;
    }
    crFinishV;
}

Project: tartarus

static void ssh_hostport_setup(const char *host, int port, Conf *conf,
                               char **savedhost, int *savedport,
                               char **loghost_ret)
{
    char *loghost = conf_get_str(conf, CONF_loghost);
    if (loghost_ret)
        *loghost_ret = loghost;

    if (*loghost) {
	char *tmphost;
        char *colon;

        tmphost = dupstr(loghost);
	*savedport = 22;	       /* default ssh port */

	/*
	 * A colon suffix on the hostname string also lets us affect
	 * savedport. (Unless there are multiple colons, in which case
	 * we assume this is an unbracketed IPv6 literal.)
	 */
	colon = host_strrchr(tmphost, ':');
	if (colon && colon == host_strchr(tmphost, ':')) {
	    *colon++ = '\0';
	    if (*colon)
		*savedport = atoi(colon);
	}

        *savedhost = host_strduptrim(tmphost);
        sfree(tmphost);
    } else {
	*savedhost = host_strduptrim(host);
	if (port < 0)
	    port = 22;		       /* default ssh port */
	*savedport = port;
    }
}

Project: tartarus

static struct Packet *ssh_new_packet(void)
{
    struct Packet *pkt = snew(struct Packet);

    pkt->body = pkt->data = NULL;
    pkt->maxlen = 0;

    return pkt;
}

Project: tartarus

static void ssh_pkt_addstring(struct Packet *pkt, const char *data)
{
    ssh_pkt_addstring_start(pkt);
    ssh_pkt_addstring_str(pkt, data);
}

Project: tartarus

static void ssh_pkt_addstring_start(struct Packet *pkt)
{
    ssh_pkt_adduint32(pkt, 0);
    pkt->savedpos = pkt->length;
}

Project: tartarus

static void ssh_pkt_addstring_str(struct Packet *pkt, const char *data)
{
  ssh_pkt_addstring_data(pkt, data, strlen(data));
}

Project: tartarus

static void ssh_pkt_adduint32(struct Packet *pkt, unsigned long value)
{
    unsigned char x[4];
    PUT_32BIT(x, value);
    ssh_pkt_adddata(pkt, x, 4);
}

Project: tartarus

static void ssh_pkt_defersend(Ssh ssh)
{
    int backlog;
    backlog = s_write(ssh, ssh->deferred_send_data, ssh->deferred_len);
    ssh->deferred_len = ssh->deferred_size = 0;
    sfree(ssh->deferred_send_data);
    ssh->deferred_send_data = NULL;
    if (backlog > SSH_MAX_BACKLOG)
	ssh_throttle_all(ssh, 1, backlog);

    if (ssh->version == 2) {
	ssh->outgoing_data_size += ssh->deferred_data_size;
	ssh->deferred_data_size = 0;
	if (!ssh->kex_in_progress &&
	    !ssh->bare_connection &&
	    ssh->max_data_size != 0 &&
	    ssh->outgoing_data_size > ssh->max_data_size)
	    do_ssh2_transport(ssh, "too much data sent", -1, NULL);
    }
}

Project: tartarus

static void ssh_pkt_ensure(struct Packet *pkt, int length)
{
    if (pkt->maxlen < length) {
	unsigned char *body = pkt->body;
	int offset = body ? body - pkt->data : 0;
	pkt->maxlen = length + 256;
	pkt->data = sresize(pkt->data, pkt->maxlen + APIEXTRA, unsigned char);
	if (body) pkt->body = pkt->data + offset;
    }
}

Project: tartarus

static void ssh_pkt_getstring(struct Packet *pkt, char **p, int *length)
{
    int len;
    *p = NULL;
    *length = 0;
    if (pkt->length - pkt->savedpos < 4)
	return;
    len = toint(GET_32BIT(pkt->body + pkt->savedpos));
    if (len < 0)
	return;
    *length = len;
    pkt->savedpos += 4;
    if (pkt->length - pkt->savedpos < *length)
	return;
    *p = (char *)(pkt->body + pkt->savedpos);
    pkt->savedpos += *length;
}

Project: tartarus

static unsigned long ssh_pkt_getuint32(struct Packet *pkt)
{
    unsigned long value;
    if (pkt->length - pkt->savedpos < 4)
	return 0;		       /* arrgh, no way to decline (FIXME?) */
    value = GET_32BIT(pkt->body + pkt->savedpos);
    pkt->savedpos += 4;
    return value;
}

Project: tartarus

static const char *ssh_pkt_type(Ssh ssh, int type)
{
    if (ssh->version == 1)
	return ssh1_pkt_type(type);
    else
	return ssh2_pkt_type(ssh->pkt_kctx, ssh->pkt_actx, type);
}

Project: tartarus

static int ssh_portcmp(void *av, void *bv)
{
    struct ssh_portfwd *a = (struct ssh_portfwd *) av;
    struct ssh_portfwd *b = (struct ssh_portfwd *) bv;
    int i;
    if (a->type > b->type)
	return +1;
    if (a->type < b->type)
	return -1;
    if (a->addressfamily > b->addressfamily)
	return +1;
    if (a->addressfamily < b->addressfamily)
	return -1;
    if ( (i = nullstrcmp(a->saddr, b->saddr)) != 0)
	return i < 0 ? -1 : +1;
    if (a->sport > b->sport)
	return +1;
    if (a->sport < b->sport)
	return -1;
    if (a->type != 'D') {
	if ( (i = nullstrcmp(a->daddr, b->daddr)) != 0)
	    return i < 0 ? -1 : +1;
	if (a->dport > b->dport)
	    return +1;
	if (a->dport < b->dport)
	    return -1;
    }
    return 0;
}

Project: tartarus

static void ssh_process_incoming_data(Ssh ssh,
				      const unsigned char **data, int *datalen)
{
    struct Packet *pktin;

    pktin = ssh->s_rdpkt(ssh, data, datalen);
    if (pktin) {
	ssh->protocol(ssh, NULL, 0, pktin);
	ssh_free_packet(pktin);
    }
}

Project: tartarus

static void ssh_process_queued_incoming_data(Ssh ssh)
{
    void *vdata;
    const unsigned char *data;
    int len, origlen;

    while (!ssh->frozen && bufchain_size(&ssh->queued_incoming_data)) {
	bufchain_prefix(&ssh->queued_incoming_data, &vdata, &len);
	data = vdata;
	origlen = len;

	while (!ssh->frozen && len > 0)
	    ssh_process_incoming_data(ssh, &data, &len);

	if (origlen > len)
	    bufchain_consume(&ssh->queued_incoming_data, origlen - len);
    }
}

Project: tartarus

static void ssh_queue_incoming_data(Ssh ssh,
				    const unsigned char **data, int *datalen)
{
    bufchain_add(&ssh->queued_incoming_data, *data, *datalen);
    *data += *datalen;
    *datalen = 0;
}

Project: tartarus

static int ssh_receive(Plug plug, int urgent, char *data, int len)
{
    Ssh ssh = (Ssh) plug;
    ssh_gotdata(ssh, (unsigned char *)data, len);
    if (ssh->state == SSH_STATE_CLOSED) {
	ssh_do_close(ssh, TRUE);
	return 0;
    }
    return 1;
}

Project: tartarus

static int ssh_rportcmp_ssh1(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->dhost, b->dhost)) != 0)
	return i < 0 ? -1 : +1;
    if (a->dport > b->dport)
	return +1;
    if (a->dport < b->dport)
	return -1;
    return 0;
}

Project: tartarus

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)
	return -1;
    return 0;
}

Project: tartarus

static void ssh_send_verstring(Ssh ssh, const char *protoname, char *svers)
{
    char *verstring;

    if (ssh->version == 2) {
	/*
	 * Construct a v2 version string.
	 */
	verstring = dupprintf("%s2.0-%s\015\012", protoname, sshver);
    } else {
	/*
	 * Construct a v1 version string.
	 */
        assert(!strcmp(protoname, "SSH-")); /* no v1 bare connection protocol */
	verstring = dupprintf("SSH-%s-%s\012",
			      (ssh_versioncmp(svers, "1.5") <= 0 ?
			       svers : "1.5"),
			      sshver);
    }

    ssh_fix_verstring(verstring + strlen(protoname));
#ifdef FUZZING
    /* FUZZING make PuTTY insecure, so make live use difficult. */
    verstring[0] = 'I';
#endif

    if (ssh->version == 2) {
	size_t len;
	/*
	 * Record our version string.
	 */
	len = strcspn(verstring, "\015\012");
	ssh->v_c = snewn(len + 1, char);
	memcpy(ssh->v_c, verstring, len);
	ssh->v_c[len] = 0;
    }

    logeventf(ssh, "We claim version: %.*s",
	      strcspn(verstring, "\015\012"), verstring);
    s_write(ssh, verstring, strlen(verstring));
    sfree(verstring);
}

Project: tartarus

static void ssh_sent(Plug plug, int bufsize)
{
    Ssh ssh = (Ssh) plug;
    /*
     * If the send backlog on the SSH socket itself clears, we
     * should unthrottle the whole world if it was throttled.
     */
    if (bufsize < SSH_MAX_BACKLOG)
	ssh_throttle_all(ssh, 0, bufsize);
}

Project: tartarus

static void ssh_set_frozen(Ssh ssh, int frozen)
{
    if (ssh->s)
	sk_set_frozen(ssh->s, frozen);
    ssh->frozen = frozen;
}

Project: tartarus

static int ssh_test_for_upstream(const char *host, int port, Conf *conf)
{
    char *savedhost;
    int savedport;
    int ret;

    random_ref(); /* platform may need this to determine share socket name */
    ssh_hostport_setup(host, port, conf, &savedhost, &savedport, NULL);
    ret = ssh_share_test_for_upstream(savedhost, savedport, conf);
    sfree(savedhost);
    random_unref();

    return ret;
}

Project: tartarus

static void ssh_throttle_conn(Ssh ssh, int adjust)
{
    int old_count = ssh->conn_throttle_count;
    ssh->conn_throttle_count += adjust;
    assert(ssh->conn_throttle_count >= 0);
    if (ssh->conn_throttle_count && !old_count) {
     }
 }

Project: tartarus

static unsigned int ssh_tty_parse_specchar(char *s)
{
    unsigned int ret;
    if (*s) {
	char *next = NULL;
	ret = ctrlparse(s, &next);
	if (!next) ret = s[0];
    } else {
	ret = 255; /* special value meaning "don't set" */
    }
    return ret;
}

Project: tartarus

int agent_exists(void)
{
    HWND hwnd;
    hwnd = FindWindow("Pageant", "Pageant");
    if (!hwnd)
	return FALSE;
    else
	return TRUE;
}