⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ssh.c

📁 一个支持FTP,SFTP的客户端程序
💻 C
📖 第 1 页 / 共 5 页
字号:
	return i < 0 ? -1 : +1;
    if (a->dport > b->dport)
	return +1;
    if (a->dport < b->dport)
	return -1;
    return 0;
}

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;

    if (a->sport > b->sport)
	return +1;
    if (a->sport < b->sport)
	return -1;
    return 0;
}

/*
 * Special form of strcmp which can cope with NULL inputs. NULL is
 * defined to sort before even the empty string.
 */
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);
}

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;
}

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;
}

static void c_write(Ssh ssh, const char *buf, int len)
{
    if ((flags & FLAG_STDERR)) {
	int i;
	for (i = 0; i < len; i++)
	    if (buf[i] != '\r')
		fputc(buf[i], stderr);
	return;
    }
    from_backend(ssh->frontend, 1, buf, len);
}

static void c_write_untrusted(Ssh ssh, const char *buf, int len)
{
    int i;
    for (i = 0; i < len; i++) {
	if (buf[i] == '\n')
	    c_write(ssh, "\r\n", 2);
	else if ((buf[i] & 0x60) || (buf[i] == '\r'))
	    c_write(ssh, buf + i, 1);
    }
}

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

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

    pkt->data = NULL;
    pkt->maxlen = 0;
    pkt->logmode = PKTLOG_EMIT;
    pkt->nblanks = 0;
    pkt->blanks = NULL;

    return pkt;
}

/*
 * Collect incoming data in the incoming packet buffer.
 * Decipher and verify the packet when it is completely read.
 * Drop SSH1_MSG_DEBUG and SSH1_MSG_IGNORE packets.
 * Update the *data and *datalen variables.
 * Return a Packet structure when a packet is completed.
 */
static struct Packet *ssh1_rdpkt(Ssh ssh, 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;
    st->pktin->savedpos = 0;

    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];

    /* Not used in FileZilla
    /*
     * Log incoming packet, possibly omitting sensitive fields.
     *//*
    if (ssh->logctx) {
	int nblanks = 0;
	struct logblank_t blank;
	if (ssh->cfg.logomitdata) {
	    int do_blank = FALSE, blank_prefix = 0;
	    /* "Session data" packets - omit the data field *//*
	    if ((st->pktin->type == SSH1_SMSG_STDOUT_DATA) ||
		(st->pktin->type == SSH1_SMSG_STDERR_DATA)) {
		do_blank = TRUE; blank_prefix = 0;
	    } else if (st->pktin->type == SSH1_MSG_CHANNEL_DATA) {
		do_blank = TRUE; blank_prefix = 4;
	    }
	    if (do_blank) {
		blank.offset = blank_prefix;
		blank.len = st->pktin->length;
		blank.type = PKTLOG_OMIT;
		nblanks = 1;
	    }
	}
	log_packet(ssh->logctx,
		   PKT_INCOMING, st->pktin->type,
		   ssh1_pkt_type(st->pktin->type),
		   st->pktin->body, st->pktin->length,
		   nblanks, &blank);
    }*/

    crFinish(st->pktin);
}

static struct Packet *ssh2_rdpkt(Ssh ssh, 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->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 and padding figures.
     */
    st->len = GET_32BIT(st->pktin->data);
    st->pad = st->pktin->data[4];

    /*
     * _Completely_ silly lengths should be stomped on before they
     * do us any more damage.
     */
    if (st->len < 0 || st->pad < 0 || st->len + st->pad < 0) {
	bombout(("Incoming packet was garbled on decryption"));
	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;

    /*
     * So now we can work out the total packet length.
     */
    st->packetlen = st->len + 4;
    st->maclen = ssh->scmac ? ssh->scmac->len : 0;

    /*
     * 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);

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

    /*
     * 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);
    }

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

    /*
     * 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);
	}
    }

    st->pktin->savedpos = 6;
    st->pktin->body = st->pktin->data;
    st->pktin->type = st->pktin->data[5];

    /* Not used in FileZilla
    /*
     * Log incoming packet, possibly omitting sensitive fields.
     *//*
    if (ssh->logctx) {
	int nblanks = 0;
	struct logblank_t blank;
	if (ssh->cfg.logomitdata) {
	    int do_blank = FALSE, blank_prefix = 0;
	    /* "Session data" packets - omit the data field *//*
	    if (st->pktin->type == SSH2_MSG_CHANNEL_DATA) {
		do_blank = TRUE; blank_prefix = 4;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -