📄 ssh.c
字号:
ssh->pktout.maxlen = biglen;#ifdef MSCRYPTOAPI /* Allocate enough buffer space for extra block * for MS CryptEncrypt() */ ssh->pktout.data = sresize(ssh->pktout.data, biglen + 12, unsigned char);#else ssh->pktout.data = sresize(ssh->pktout.data, biglen + 4, unsigned char);#endif } ssh->pktout.body = ssh->pktout.data + 4 + pad + 1;}static void s_wrpkt_start(Ssh ssh, int type, int len){ ssh1_pktout_size(ssh, len); ssh->pktout.type = type; /* Initialise log omission state */ ssh->pktout_nblanks = 0; ssh->pktout_blanks = NULL;}static int s_wrpkt_prepare(Ssh ssh){ int pad, biglen, i; 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; ssh->pktout.body[-1] = ssh->pktout.type; if (ssh->logctx) log_packet(ssh->logctx, PKT_OUTGOING, ssh->pktout.type, ssh1_pkt_type(ssh->pktout.type), ssh->pktout.body, ssh->pktout.length, ssh->pktout_nblanks, ssh->pktout_blanks); sfree(ssh->pktout_blanks); ssh->pktout_blanks = NULL; ssh->pktout_nblanks = 0; if (ssh->v1_compressing) { unsigned char *compblk; int complen; zlib_compress_block(ssh->cs_comp_ctx, ssh->pktout.body - 1, ssh->pktout.length + 1, &compblk, &complen); ssh1_pktout_size(ssh, complen - 1); memcpy(ssh->pktout.body - 1, compblk, complen); sfree(compblk); } len = ssh->pktout.length + 5; /* type and CRC */ pad = 8 - (len % 8); biglen = len + pad; for (i = 0; i < pad; i++) ssh->pktout.data[i + 4] = random_byte(); crc = crc32_compute(ssh->pktout.data + 4, biglen - 4); PUT_32BIT(ssh->pktout.data + biglen, crc); PUT_32BIT(ssh->pktout.data, len); if (ssh->cipher) ssh->cipher->encrypt(ssh->v1_cipher_ctx, ssh->pktout.data + 4, biglen); return biglen + 4;}static void s_wrpkt(Ssh ssh){ int len, backlog; len = s_wrpkt_prepare(ssh); backlog = sk_write(ssh->s, (char *)ssh->pktout.data, len); if (backlog > SSH_MAX_BACKLOG) ssh_throttle_all(ssh, 1, backlog);}static void s_wrpkt_defer(Ssh ssh){ int len; len = s_wrpkt_prepare(ssh); 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, ssh->pktout.data, len); ssh->deferred_len += len;}/* * Construct a packet with the specified contents. */static void construct_packet(Ssh ssh, int pkttype, va_list ap1, va_list ap2){ unsigned char *p, *argp, argchar; unsigned long argint; int pktlen, argtype, arglen; Bignum bn; pktlen = 0; while ((argtype = va_arg(ap1, int)) != PKT_END) { switch (argtype) { case PKT_INT: (void) va_arg(ap1, int); pktlen += 4; break; case PKT_CHAR: (void) va_arg(ap1, int); pktlen++; break; case PKT_DATA: (void) va_arg(ap1, unsigned char *); arglen = va_arg(ap1, int); pktlen += arglen; break; case PKT_STR: argp = va_arg(ap1, unsigned char *); arglen = strlen((char *)argp); pktlen += 4 + arglen; break; case PKT_BIGNUM: bn = va_arg(ap1, Bignum); pktlen += ssh1_bignum_length(bn); break; case PKTT_PASSWORD: case PKTT_DATA: case PKTT_OTHER: /* ignore this pass */ break; default: assert(0); } } s_wrpkt_start(ssh, pkttype, pktlen); p = ssh->pktout.body; while ((argtype = va_arg(ap2, int)) != PKT_END) { int offset = p - ssh->pktout.body, len = 0; switch (argtype) { /* Actual fields in the packet */ case PKT_INT: argint = va_arg(ap2, int); PUT_32BIT(p, argint); len = 4; break; case PKT_CHAR: argchar = (unsigned char) va_arg(ap2, int); *p = argchar; len = 1; break; case PKT_DATA: argp = va_arg(ap2, unsigned char *); arglen = va_arg(ap2, int); memcpy(p, argp, arglen); len = arglen; break; case PKT_STR: argp = va_arg(ap2, unsigned char *); arglen = strlen((char *)argp); PUT_32BIT(p, arglen); memcpy(p + 4, argp, arglen); len = arglen + 4; break; case PKT_BIGNUM: bn = va_arg(ap2, Bignum); len = ssh1_write_bignum(p, bn); break; /* Tokens for modifications to packet logging */ case PKTT_PASSWORD: dont_log_password(ssh, PKTLOG_BLANK); break; case PKTT_DATA: dont_log_data(ssh, PKTLOG_OMIT); break; case PKTT_OTHER: end_log_omission(ssh); break; } p += len; /* Deal with logfile omission, if required. */ if (len && (ssh->pktout_logmode != PKTLOG_EMIT)) { ssh->pktout_nblanks++; ssh->pktout_blanks = sresize(ssh->pktout_blanks, ssh->pktout_nblanks, struct logblank_t); ssh->pktout_blanks[ssh->pktout_nblanks-1].offset = offset; ssh->pktout_blanks[ssh->pktout_nblanks-1].len = len; ssh->pktout_blanks[ssh->pktout_nblanks-1].type = ssh->pktout_logmode; } }}static void send_packet(Ssh ssh, int pkttype, ...){ va_list ap1, ap2; va_start(ap1, pkttype); va_start(ap2, pkttype); construct_packet(ssh, pkttype, ap1, ap2); s_wrpkt(ssh);}static void defer_packet(Ssh ssh, int pkttype, ...){ va_list ap1, ap2; va_start(ap1, pkttype); va_start(ap2, pkttype); construct_packet(ssh, pkttype, ap1, ap2); s_wrpkt_defer(ssh);}static int ssh_versioncmp(char *a, char *b){ char *ae, *be; unsigned long av, bv; av = strtoul(a, &ae, 10); bv = strtoul(b, &be, 10); if (av != bv) return (av < bv ? -1 : +1); if (*ae == '.') ae++; if (*be == '.') be++; av = strtoul(ae, &ae, 10); bv = strtoul(be, &be, 10); if (av != bv) return (av < bv ? -1 : +1); return 0;}/* * Utility routines for putting an SSH-protocol `string' and * `uint32' into a SHA state. */#include <stdio.h>static void sha_string(SHA_State * s, void *str, int len){ unsigned char lenblk[4]; PUT_32BIT(lenblk, len); SHA_Bytes(s, lenblk, 4); SHA_Bytes(s, str, len);}static void sha_uint32(SHA_State * s, unsigned i){ unsigned char intblk[4]; PUT_32BIT(intblk, i); SHA_Bytes(s, intblk, 4);}/* * SSH2 packet construction functions. */static void ssh2_pkt_ensure(Ssh ssh, int length){ if (ssh->pktout.maxlen < length) { ssh->pktout.maxlen = length + 256; ssh->pktout.data = sresize(ssh->pktout.data, ssh->pktout.maxlen + APIEXTRA, unsigned char); if (!ssh->pktout.data) fatalbox("Out of memory"); }}static void ssh2_pkt_adddata(Ssh ssh, void *data, int len){ if (ssh->pktout_logmode != PKTLOG_EMIT) { ssh->pktout_nblanks++; ssh->pktout_blanks = sresize(ssh->pktout_blanks, ssh->pktout_nblanks, struct logblank_t); ssh->pktout_blanks[ssh->pktout_nblanks-1].offset = ssh->pktout.length - 6; ssh->pktout_blanks[ssh->pktout_nblanks-1].len = len; ssh->pktout_blanks[ssh->pktout_nblanks-1].type = ssh->pktout_logmode; } ssh->pktout.length += len; ssh2_pkt_ensure(ssh, ssh->pktout.length); memcpy(ssh->pktout.data + ssh->pktout.length - len, data, len);}static void ssh2_pkt_addbyte(Ssh ssh, unsigned char byte){ ssh2_pkt_adddata(ssh, &byte, 1);}static void ssh2_pkt_init(Ssh ssh, int pkt_type){ ssh->pktout.length = 5; ssh->pktout_nblanks = 0; ssh->pktout_blanks = NULL; ssh2_pkt_addbyte(ssh, (unsigned char) pkt_type);}static void ssh2_pkt_addbool(Ssh ssh, unsigned char value){ ssh2_pkt_adddata(ssh, &value, 1);}static void ssh2_pkt_adduint32(Ssh ssh, unsigned long value){ unsigned char x[4]; PUT_32BIT(x, value); ssh2_pkt_adddata(ssh, x, 4);}static void ssh2_pkt_addstring_start(Ssh ssh){ ssh2_pkt_adduint32(ssh, 0); ssh->pktout.savedpos = ssh->pktout.length;}static void ssh2_pkt_addstring_str(Ssh ssh, char *data){ ssh2_pkt_adddata(ssh, data, strlen(data)); PUT_32BIT(ssh->pktout.data + ssh->pktout.savedpos - 4, ssh->pktout.length - ssh->pktout.savedpos);}static void ssh2_pkt_addstring_data(Ssh ssh, char *data, int len){ ssh2_pkt_adddata(ssh, data, len); PUT_32BIT(ssh->pktout.data + ssh->pktout.savedpos - 4, ssh->pktout.length - ssh->pktout.savedpos);}static void ssh2_pkt_addstring(Ssh ssh, char *data){ ssh2_pkt_addstring_start(ssh); ssh2_pkt_addstring_str(ssh, data);}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); if (!p) fatalbox("out of memory"); 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;}static void ssh2_pkt_addmp(Ssh ssh, Bignum b){ unsigned char *p; int len; p = ssh2_mpint_fmt(b, &len); ssh2_pkt_addstring_start(ssh); ssh2_pkt_addstring_data(ssh, (char *)p, len); sfree(p);}/* * Construct an SSH2 final-form packet: compress it, encrypt it, * put the MAC on it. Final packet, ready to be sent, is stored in * ssh->pktout.data. Total length is returned. */static int ssh2_pkt_construct(Ssh ssh){ int cipherblk, maclen, padding, i; if (ssh->logctx) log_packet(ssh->logctx, PKT_OUTGOING, ssh->pktout.data[5], ssh2_pkt_type(ssh->pkt_ctx, ssh->pktout.data[5]), ssh->pktout.data + 6, ssh->pktout.length - 6, ssh->pktout_nblanks, ssh->pktout_blanks); sfree(ssh->pktout_blanks); ssh->pktout_blanks = NULL; ssh->pktout_nblanks = 0; /* * Compress packet payload. */ { unsigned char *newpayload; int newlen; if (ssh->cscomp && ssh->cscomp->compress(ssh->cs_comp_ctx, ssh->pktout.data + 5, ssh->pktout.length - 5, &newpayload, &newlen)) { ssh->pktout.length = 5; ssh2_pkt_adddata(ssh, 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. */ cipherblk = ssh->cscipher ? ssh->cscipher->blksize : 8; /* block size */ cipherblk = cipherblk < 8 ? 8 : cipherblk; /* or 8 if blksize < 8 */ padding = 4; padding += (cipherblk - (ssh->pktout.length + padding) % cipherblk) % cipherblk; maclen = ssh->csmac ? ssh->csmac->len : 0; ssh2_pkt_ensure(ssh, ssh->pktout.length + padding + maclen); ssh->pktout.data[4] = padding; for (i = 0; i < padding; i++) ssh->pktout.data[ssh->pktout.length + i] = random_byte(); PUT_32BIT(ssh->pktout.data, ssh->pktout.length + padding - 4); if (ssh->csmac) ssh->csmac->generate(ssh->cs_mac_ctx, ssh->pktout.data, ssh->pktout.length + padding, ssh->v2_outgoing_sequence); ssh->v2_outgoing_sequence++; /* whether or not we MACed */ if (ssh->cscipher) ssh->cscipher->encrypt(ssh->cs_cipher_ctx, ssh->pktout.data, ssh->pktout.length + padding); /* Ready-to-send packet starts at ssh->pktout.data. We return length. */ return ssh->pktout.length + padding + maclen;}/* * Construct and send an SSH2 packet immediately. */static void ssh2_pkt_send(Ssh ssh){ int len; int backlog; len = ssh2_pkt_construct(ssh); backlog = sk_write(ssh->s, (char *)ssh->pktout.data, len); if (backlog > SSH_MAX_BACKLOG) ssh_throttle_all(ssh, 1, backlog);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -