#define TRUE 1
#endif
+/* uncomment this for packet level debugging */
+/* #define DUMP_PACKETS */
+
#define logevent(s) { logevent(s); \
if ((flags & FLAG_STDERR) && (flags & FLAG_VERBOSE)) \
- fprintf(stderr, "%s\n", s); }
+ { fprintf(stderr, "%s\n", s); fflush(stderr); } }
#define bombout(msg) ( ssh_state = SSH_STATE_CLOSED, \
(s ? sk_close(s), s = NULL : 0), \
return 0;
}
+static int alloc_channel_id(void) {
+ const unsigned CHANNEL_NUMBER_OFFSET = 256;
+ unsigned low, high, mid;
+ int tsize;
+ struct ssh_channel *c;
+
+ /*
+ * First-fit allocation of channel numbers: always pick the
+ * lowest unused one. To do this, binary-search using the
+ * counted B-tree to find the largest channel ID which is in a
+ * contiguous sequence from the beginning. (Precisely
+ * everything in that sequence must have ID equal to its tree
+ * index plus CHANNEL_NUMBER_OFFSET.)
+ */
+ tsize = count234(ssh_channels);
+
+ low = -1; high = tsize;
+ while (high - low > 1) {
+ mid = (high + low) / 2;
+ c = index234(ssh_channels, mid);
+ if (c->localid == mid + CHANNEL_NUMBER_OFFSET)
+ low = mid; /* this one is fine */
+ else
+ high = mid; /* this one is past it */
+ }
+ /*
+ * Now low points to either -1, or the tree index of the
+ * largest ID in the initial sequence.
+ */
+ {
+ unsigned i = low + 1 + CHANNEL_NUMBER_OFFSET;
+ assert(NULL == find234(ssh_channels, &i, ssh_channelfind));
+ }
+ return low + 1 + CHANNEL_NUMBER_OFFSET;
+}
+
static void c_write (char *buf, int len) {
if ((flags & FLAG_STDERR)) {
int i;
if (cipher)
cipher->decrypt(pktin.data, st->biglen);
-#if 0
- debug(("Got packet len=%d pad=%d\r\n", st->len, st->pad));
- for (st->i = 0; st->i < st->biglen; st->i++)
- debug((" %02x", (unsigned char)pktin.data[st->i]));
- debug(("\r\n"));
+#ifdef DUMP_PACKETS
+ debug(("Got packet len=%d pad=%d\n", st->len, st->pad));
+ dmemdump(pktin.data, st->biglen);
#endif
st->realcrc = crc32(pktin.data, st->biglen-4);
if (ssh1_compressing) {
unsigned char *decompblk;
int decomplen;
-#if 0
- {
- int i;
- debug(("Packet payload pre-decompression:\n"));
- for (i = -1; i < pktin.length; i++)
- debug((" %02x", (unsigned char)pktin.body[i]));
- debug(("\r\n"));
- }
+#ifdef DUMP_PACKETS
+ debug(("Packet payload pre-decompression:\n"));
+ dmemdump(pktin.body-1, pktin.length+1);
#endif
zlib_decompress_block(pktin.body-1, pktin.length+1,
&decompblk, &decomplen);
memcpy(pktin.body-1, decompblk, decomplen);
sfree(decompblk);
pktin.length = decomplen-1;
-#if 0
- {
- int i;
- debug(("Packet payload post-decompression:\n"));
- for (i = -1; i < pktin.length; i++)
- debug((" %02x", (unsigned char)pktin.body[i]));
- debug(("\r\n"));
- }
+#ifdef DUMP_PACKETS
+ debug(("Packet payload post-decompression:\n"));
+ dmemdump(pktin.body-1, pktin.length+1);
#endif
}
if (pktin.type == SSH1_MSG_DISCONNECT) {
/* log reason code in disconnect message */
char buf[256];
- int msglen = GET_32BIT(pktin.body);
- int nowlen;
+ unsigned msglen = GET_32BIT(pktin.body);
+ unsigned nowlen;
strcpy(buf, "Remote sent disconnect: ");
nowlen = strlen(buf);
if (msglen > sizeof(buf)-nowlen-1)
sccipher->decrypt(pktin.data + st->cipherblk,
st->packetlen - st->cipherblk);
-#if 0
- debug(("Got packet len=%d pad=%d\r\n", st->len, st->pad));
- for (st->i = 0; st->i < st->packetlen; st->i++)
- debug((" %02x", (unsigned char)pktin.data[st->i]));
- debug(("\r\n"));
+#ifdef DUMP_PACKETS
+ debug(("Got packet len=%d pad=%d\n", st->len, st->pad));
+ dmemdump(pktin.data, st->packetlen);
#endif
/*
}
pktin.length = 5 + newlen;
memcpy(pktin.data+5, newpayload, newlen);
-#if 0
- debug(("Post-decompression payload:\r\n"));
- for (st->i = 0; st->i < newlen; st->i++)
- debug((" %02x", (unsigned char)pktin.data[5+st->i]));
- debug(("\r\n"));
+#ifdef DUMP_PACKETS
+ debug(("Post-decompression payload:\n"));
+ dmemdump(pktin.data+5, newlen);
#endif
sfree(newpayload);
/* log reason code in disconnect message */
char buf[256];
int reason = GET_32BIT(pktin.data+6);
- int msglen = GET_32BIT(pktin.data+10);
- int nowlen;
+ unsigned msglen = GET_32BIT(pktin.data+10);
+ unsigned nowlen;
if (reason > 0 && reason < lenof(ssh2_disconnect_reasons)) {
sprintf(buf, "Received disconnect message (%s)",
ssh2_disconnect_reasons[reason]);
pktout.body[-1] = pktout.type;
-#if 0
+#ifdef DUMP_PACKETS
debug(("Packet payload pre-compression:\n"));
- for (i = -1; i < pktout.length; i++)
- debug((" %02x", (unsigned char)pktout.body[i]));
- debug(("\r\n"));
+ dmemdump(pktout.body-1, pktout.length+1);
#endif
if (ssh1_compressing) {
ssh1_pktout_size(complen-1);
memcpy(pktout.body-1, compblk, complen);
sfree(compblk);
-#if 0
+#ifdef DUMP_PACKETS
debug(("Packet payload post-compression:\n"));
- for (i = -1; i < pktout.length; i++)
- debug((" %02x", (unsigned char)pktout.body[i]));
- debug(("\r\n"));
+ dmemdump(pktout.body-1, pktout.length+1);
#endif
}
PUT_32BIT(pktout.data+biglen, crc);
PUT_32BIT(pktout.data, len);
-#if 0
- debug(("Sending packet len=%d\r\n", biglen+4));
- for (i = 0; i < biglen+4; i++)
- debug((" %02x", (unsigned char)pktout.data[i]));
- debug(("\r\n"));
+#ifdef DUMP_PACKETS
+ debug(("Sending packet len=%d\n", biglen+4));
+ dmemdump(pktout.data, biglen+4);
#endif
if (cipher)
cipher->encrypt(pktout.data+4, biglen);
}
static char *ssh2_mpint_fmt(Bignum b, int *len) {
unsigned char *p;
- int i, n = (ssh1_bignum_bitcount(b)+7)/8;
+ int i, n = (bignum_bitcount(b)+7)/8;
p = smalloc(n + 1);
if (!p)
fatalbox("out of memory");
/*
* Compress packet payload.
*/
-#if 0
- debug(("Pre-compression payload:\r\n"));
- for (i = 5; i < pktout.length; i++)
- debug((" %02x", (unsigned char)pktout.data[i]));
- debug(("\r\n"));
+#ifdef DUMP_PACKETS
+ debug(("Pre-compression payload:\n"));
+ dmemdump(pktout.data+5, pktout.length-5);
#endif
{
unsigned char *newpayload;
outgoing_sequence);
outgoing_sequence++; /* whether or not we MACed */
-#if 0
- debug(("Sending packet len=%d\r\n", pktout.length+padding));
- for (i = 0; i < pktout.length+padding; i++)
- debug((" %02x", (unsigned char)pktout.data[i]));
- debug(("\r\n"));
+#ifdef DUMP_PACKETS
+ debug(("Sending packet len=%d\n", pktout.length+padding));
+ dmemdump(pktout.data, pktout.length+padding);
#endif
if (cscipher)
debug(("%s", string));
for (i = 0; i < len; i++)
debug((" %02x", p[i]));
- debug(("\r\n"));
+ debug(("\n"));
sfree(p);
}
#endif
PUT_32BIT(agentreq, len);
q = agentreq + 4;
*q++ = SSH1_AGENTC_RSA_CHALLENGE;
- PUT_32BIT(q, ssh1_bignum_bitcount(key.modulus));
+ PUT_32BIT(q, bignum_bitcount(key.modulus));
q += 4;
q += ssh1_write_bignum(q, key.exponent);
q += ssh1_write_bignum(q, key.modulus);
} else if (pktin.type == SSH1_SMSG_X11_OPEN) {
/* Remote side is trying to open a channel to talk to our
* X-Server. Give them back a local channel number. */
- unsigned i;
- struct ssh_channel *c, *d;
- enum234 e;
+ struct ssh_channel *c;
logevent("Received X11 connect request");
/* Refuse if X11 forwarding is disabled. */
PKT_END);
} else {
logevent("opening X11 forward connection succeeded");
- for (i=1, d = first234(ssh_channels, &e); d; d = next234(&e)) {
- if (d->localid > i)
- break; /* found a free number */
- i = d->localid + 1;
- }
c->remoteid = GET_32BIT(pktin.body);
- c->localid = i;
+ c->localid = alloc_channel_id();
c->closes = 0;
c->type = CHAN_X11; /* identify channel type */
add234(ssh_channels, c);
} else if (pktin.type == SSH1_SMSG_AGENT_OPEN) {
/* Remote side is trying to open a channel to talk to our
* agent. Give them back a local channel number. */
- unsigned i;
struct ssh_channel *c;
- enum234 e;
/* Refuse if agent forwarding is disabled. */
if (!ssh_agentfwd_enabled) {
PKT_INT, GET_32BIT(pktin.body),
PKT_END);
} else {
- i = 1;
- for (c = first234(ssh_channels, &e); c; c = next234(&e)) {
- if (c->localid > i)
- break; /* found a free number */
- i = c->localid + 1;
- }
c = smalloc(sizeof(struct ssh_channel));
c->remoteid = GET_32BIT(pktin.body);
- c->localid = i;
+ c->localid = alloc_channel_id();
c->closes = 0;
c->type = CHAN_AGENT; /* identify channel type */
c->u.a.lensofar = 0;
dh_cleanup();
#if 0
- debug(("Exchange hash is:\r\n"));
- for (i = 0; i < 20; i++)
- debug((" %02x", exchange_hash[i]));
- debug(("\r\n"));
+ debug(("Exchange hash is:\n"));
+ dmemdump(exchange_hash, 20);
#endif
hkey = hostkey->newkey(hostkeydata, hostkeylen);
method = 0;
- if (!method && can_pubkey && agent_exists && !tried_agent) {
+ if (!method && can_pubkey && agent_exists() && !tried_agent) {
/*
* Attempt public-key authentication using Pageant.
*/
/*
* So now create a channel with a session in it.
*/
+ ssh_channels = newtree234(ssh_channelcmp);
mainchan = smalloc(sizeof(struct ssh_channel));
- mainchan->localid = 100; /* as good as any */
+ mainchan->localid = alloc_channel_id();
ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN);
ssh2_pkt_addstring("session");
ssh2_pkt_adduint32(mainchan->localid);
mainchan->v2.remmaxpkt = ssh2_pkt_getuint32();
mainchan->v2.outbuffer = NULL;
mainchan->v2.outbuflen = mainchan->v2.outbufsize = 0;
- ssh_channels = newtree234(ssh_channelcmp);
add234(ssh_channels, mainchan);
logevent("Opened channel for session");
} else if (pktin.type == SSH2_MSG_CHANNEL_CLOSE) {
unsigned i = ssh2_pkt_getuint32();
struct ssh_channel *c;
- enum234 e;
c = find234(ssh_channels, &i, ssh_channelfind);
if (!c)
/*
* See if that was the last channel left open.
*/
- c = first234(ssh_channels, &e);
- if (!c) {
+ if (count234(ssh_channels) == 0) {
logevent("All channels closed. Disconnecting");
ssh2_pkt_init(SSH2_MSG_DISCONNECT);
ssh2_pkt_adduint32(SSH2_DISCONNECT_BY_APPLICATION);
ssh2_pkt_send();
sfree(c);
} else {
- struct ssh_channel *d;
- unsigned i;
- enum234 e;
-
- for (i=1, d = first234(ssh_channels, &e); d;
- d = next234(&e)) {
- if (d->localid > i)
- break; /* found a free number */
- i = d->localid + 1;
- }
- c->localid = i;
+ c->localid = alloc_channel_id();
c->closes = 0;
c->v2.remwindow = ssh2_pkt_getuint32();
c->v2.remmaxpkt = ssh2_pkt_getuint32();
try_send = TRUE;
}
if (try_send) {
- enum234 e;
+ int i;
struct ssh_channel *c;
/*
* Try to send data on all channels if we can.
*/
- for (c = first234(ssh_channels, &e); c; c = next234(&e))
+ for (i = 0; NULL != (c = index234(ssh_channels, i)); i++)
ssh2_try_send(c);
}
}