#define TRUE 1
#endif
-#define SSH1_MSG_DISCONNECT 1 /* 0x1 */
-#define SSH1_SMSG_PUBLIC_KEY 2 /* 0x2 */
-#define SSH1_CMSG_SESSION_KEY 3 /* 0x3 */
-#define SSH1_CMSG_USER 4 /* 0x4 */
-#define SSH1_CMSG_AUTH_RSA 6 /* 0x6 */
-#define SSH1_SMSG_AUTH_RSA_CHALLENGE 7 /* 0x7 */
-#define SSH1_CMSG_AUTH_RSA_RESPONSE 8 /* 0x8 */
-#define SSH1_CMSG_AUTH_PASSWORD 9 /* 0x9 */
-#define SSH1_CMSG_REQUEST_PTY 10 /* 0xa */
-#define SSH1_CMSG_WINDOW_SIZE 11 /* 0xb */
-#define SSH1_CMSG_EXEC_SHELL 12 /* 0xc */
-#define SSH1_CMSG_EXEC_CMD 13 /* 0xd */
-#define SSH1_SMSG_SUCCESS 14 /* 0xe */
-#define SSH1_SMSG_FAILURE 15 /* 0xf */
-#define SSH1_CMSG_STDIN_DATA 16 /* 0x10 */
-#define SSH1_SMSG_STDOUT_DATA 17 /* 0x11 */
-#define SSH1_SMSG_STDERR_DATA 18 /* 0x12 */
-#define SSH1_CMSG_EOF 19 /* 0x13 */
-#define SSH1_SMSG_EXIT_STATUS 20 /* 0x14 */
-#define SSH1_MSG_CHANNEL_OPEN_CONFIRMATION 21 /* 0x15 */
-#define SSH1_MSG_CHANNEL_OPEN_FAILURE 22 /* 0x16 */
-#define SSH1_MSG_CHANNEL_DATA 23 /* 0x17 */
-#define SSH1_MSG_CHANNEL_CLOSE 24 /* 0x18 */
-#define SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION 25 /* 0x19 */
-#define SSH1_SMSG_X11_OPEN 27 /* 0x1b */
-#define SSH1_CMSG_PORT_FORWARD_REQUEST 28 /* 0x1c */
-#define SSH1_MSG_PORT_OPEN 29 /* 0x1d */
-#define SSH1_CMSG_AGENT_REQUEST_FORWARDING 30 /* 0x1e */
-#define SSH1_SMSG_AGENT_OPEN 31 /* 0x1f */
-#define SSH1_MSG_IGNORE 32 /* 0x20 */
-#define SSH1_CMSG_EXIT_CONFIRMATION 33 /* 0x21 */
-#define SSH1_CMSG_X11_REQUEST_FORWARDING 34 /* 0x22 */
-#define SSH1_CMSG_AUTH_RHOSTS_RSA 35 /* 0x23 */
-#define SSH1_MSG_DEBUG 36 /* 0x24 */
-#define SSH1_CMSG_REQUEST_COMPRESSION 37 /* 0x25 */
-#define SSH1_CMSG_AUTH_TIS 39 /* 0x27 */
-#define SSH1_SMSG_AUTH_TIS_CHALLENGE 40 /* 0x28 */
-#define SSH1_CMSG_AUTH_TIS_RESPONSE 41 /* 0x29 */
-#define SSH1_CMSG_AUTH_CCARD 70 /* 0x46 */
-#define SSH1_SMSG_AUTH_CCARD_CHALLENGE 71 /* 0x47 */
-#define SSH1_CMSG_AUTH_CCARD_RESPONSE 72 /* 0x48 */
-
-#define SSH1_AUTH_RHOSTS 1 /* 0x1 */
-#define SSH1_AUTH_RSA 2 /* 0x2 */
-#define SSH1_AUTH_PASSWORD 3 /* 0x3 */
-#define SSH1_AUTH_RHOSTS_RSA 4 /* 0x4 */
-#define SSH1_AUTH_TIS 5 /* 0x5 */
-#define SSH1_AUTH_CCARD 16 /* 0x10 */
-
-#define SSH1_PROTOFLAG_SCREEN_NUMBER 1 /* 0x1 */
-/* Mask for protoflags we will echo back to server if seen */
-#define SSH1_PROTOFLAGS_SUPPORTED 0 /* 0x1 */
-
-#define SSH2_MSG_DISCONNECT 1 /* 0x1 */
-#define SSH2_MSG_IGNORE 2 /* 0x2 */
-#define SSH2_MSG_UNIMPLEMENTED 3 /* 0x3 */
-#define SSH2_MSG_DEBUG 4 /* 0x4 */
-#define SSH2_MSG_SERVICE_REQUEST 5 /* 0x5 */
-#define SSH2_MSG_SERVICE_ACCEPT 6 /* 0x6 */
-#define SSH2_MSG_KEXINIT 20 /* 0x14 */
-#define SSH2_MSG_NEWKEYS 21 /* 0x15 */
-#define SSH2_MSG_KEXDH_INIT 30 /* 0x1e */
-#define SSH2_MSG_KEXDH_REPLY 31 /* 0x1f */
-#define SSH2_MSG_KEX_DH_GEX_REQUEST 30 /* 0x1e */
-#define SSH2_MSG_KEX_DH_GEX_GROUP 31 /* 0x1f */
-#define SSH2_MSG_KEX_DH_GEX_INIT 32 /* 0x20 */
-#define SSH2_MSG_KEX_DH_GEX_REPLY 33 /* 0x21 */
-#define SSH2_MSG_KEXRSA_PUBKEY 30 /* 0x1e */
-#define SSH2_MSG_KEXRSA_SECRET 31 /* 0x1f */
-#define SSH2_MSG_KEXRSA_DONE 32 /* 0x20 */
-#define SSH2_MSG_USERAUTH_REQUEST 50 /* 0x32 */
-#define SSH2_MSG_USERAUTH_FAILURE 51 /* 0x33 */
-#define SSH2_MSG_USERAUTH_SUCCESS 52 /* 0x34 */
-#define SSH2_MSG_USERAUTH_BANNER 53 /* 0x35 */
-#define SSH2_MSG_USERAUTH_PK_OK 60 /* 0x3c */
-#define SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ 60 /* 0x3c */
-#define SSH2_MSG_USERAUTH_INFO_REQUEST 60 /* 0x3c */
-#define SSH2_MSG_USERAUTH_INFO_RESPONSE 61 /* 0x3d */
-#define SSH2_MSG_GLOBAL_REQUEST 80 /* 0x50 */
-#define SSH2_MSG_REQUEST_SUCCESS 81 /* 0x51 */
-#define SSH2_MSG_REQUEST_FAILURE 82 /* 0x52 */
-#define SSH2_MSG_CHANNEL_OPEN 90 /* 0x5a */
-#define SSH2_MSG_CHANNEL_OPEN_CONFIRMATION 91 /* 0x5b */
-#define SSH2_MSG_CHANNEL_OPEN_FAILURE 92 /* 0x5c */
-#define SSH2_MSG_CHANNEL_WINDOW_ADJUST 93 /* 0x5d */
-#define SSH2_MSG_CHANNEL_DATA 94 /* 0x5e */
-#define SSH2_MSG_CHANNEL_EXTENDED_DATA 95 /* 0x5f */
-#define SSH2_MSG_CHANNEL_EOF 96 /* 0x60 */
-#define SSH2_MSG_CHANNEL_CLOSE 97 /* 0x61 */
-#define SSH2_MSG_CHANNEL_REQUEST 98 /* 0x62 */
-#define SSH2_MSG_CHANNEL_SUCCESS 99 /* 0x63 */
-#define SSH2_MSG_CHANNEL_FAILURE 100 /* 0x64 */
-#define SSH2_MSG_USERAUTH_GSSAPI_RESPONSE 60
-#define SSH2_MSG_USERAUTH_GSSAPI_TOKEN 61
-#define SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE 63
-#define SSH2_MSG_USERAUTH_GSSAPI_ERROR 64
-#define SSH2_MSG_USERAUTH_GSSAPI_ERRTOK 65
-#define SSH2_MSG_USERAUTH_GSSAPI_MIC 66
-
/*
* Packet type contexts, so that ssh2_pkt_type can correctly decode
* the ambiguous type numbers back into the correct type strings.
SSH2_PKTCTX_KBDINTER
} Pkt_ACtx;
-#define SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT 1 /* 0x1 */
-#define SSH2_DISCONNECT_PROTOCOL_ERROR 2 /* 0x2 */
-#define SSH2_DISCONNECT_KEY_EXCHANGE_FAILED 3 /* 0x3 */
-#define SSH2_DISCONNECT_HOST_AUTHENTICATION_FAILED 4 /* 0x4 */
-#define SSH2_DISCONNECT_MAC_ERROR 5 /* 0x5 */
-#define SSH2_DISCONNECT_COMPRESSION_ERROR 6 /* 0x6 */
-#define SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE 7 /* 0x7 */
-#define SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED 8 /* 0x8 */
-#define SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE 9 /* 0x9 */
-#define SSH2_DISCONNECT_CONNECTION_LOST 10 /* 0xa */
-#define SSH2_DISCONNECT_BY_APPLICATION 11 /* 0xb */
-#define SSH2_DISCONNECT_TOO_MANY_CONNECTIONS 12 /* 0xc */
-#define SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER 13 /* 0xd */
-#define SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE 14 /* 0xe */
-#define SSH2_DISCONNECT_ILLEGAL_USER_NAME 15 /* 0xf */
-
static const char *const ssh2_disconnect_reasons[] = {
NULL,
"host not allowed to connect",
"illegal user name",
};
-#define SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED 1 /* 0x1 */
-#define SSH2_OPEN_CONNECT_FAILED 2 /* 0x2 */
-#define SSH2_OPEN_UNKNOWN_CHANNEL_TYPE 3 /* 0x3 */
-#define SSH2_OPEN_RESOURCE_SHORTAGE 4 /* 0x4 */
-
-#define SSH2_EXTENDED_DATA_STDERR 1 /* 0x1 */
-
/*
* Various remote-bug flags.
*/
/* Enumeration values for fields in SSH-1 packets */
enum {
PKT_END, PKT_INT, PKT_CHAR, PKT_DATA, PKT_STR, PKT_BIGNUM,
- /* These values are for communicating relevant semantics of
- * fields to the packet logging code. */
- PKTT_OTHER, PKTT_PASSWORD, PKTT_DATA
};
/*
int outstanding_requests;
} a;
struct ssh_x11_channel {
- Socket s;
+ struct X11Connection *xconn;
} x11;
struct ssh_pfd_channel {
- Socket s;
+ struct PortForwarding *pf;
} pfd;
} u;
};
struct ssh_rportfwd {
unsigned sport, dport;
- char dhost[256];
+ char *shost, *dhost;
char *sportdesc;
struct ssh_portfwd *pfrec;
};
-#define free_rportfwd(pf) ( \
- ((pf) ? (sfree((pf)->sportdesc)) : (void)0 ), sfree(pf) )
+
+static void free_rportfwd(struct ssh_rportfwd *pf)
+{
+ if (pf) {
+ sfree(pf->sportdesc);
+ sfree(pf->shost);
+ sfree(pf->dhost);
+ sfree(pf);
+ }
+}
/*
* Separately to the rportfwd tree (which is for looking up port
char *sserv, *dserv;
struct ssh_rportfwd *remote;
int addressfamily;
- void *local;
+ struct PortListener *local;
};
#define free_portfwd(pf) ( \
((pf) ? (sfree((pf)->saddr), sfree((pf)->daddr), \
sfree((pf)->sserv), sfree((pf)->dserv)) : (void)0 ), sfree(pf) )
struct Packet {
- long length; /* length of `data' actually used */
+ long length; /* length of packet: see below */
long forcepad; /* SSH-2: force padding to at least this length */
int type; /* only used for incoming packets */
unsigned long sequence; /* SSH-2 incoming sequence number */
unsigned char *data; /* allocated storage */
unsigned char *body; /* offset of payload within `data' */
- long savedpos; /* temporary index into `data' (for strings) */
+ long savedpos; /* dual-purpose saved packet position: see below */
long maxlen; /* amount of storage allocated for `data' */
long encrypted_len; /* for SSH-2 total-size counting */
/*
- * State associated with packet logging
+ * A note on the 'length' and 'savedpos' fields above.
+ *
+ * Incoming packets are set up so that pkt->length is measured
+ * relative to pkt->body, which itself points to a few bytes after
+ * pkt->data (skipping some uninteresting header fields including
+ * the packet type code). The ssh_pkt_get* functions all expect
+ * this setup, and they also use pkt->savedpos to indicate how far
+ * through the packet being decoded they've got - and that, too,
+ * is an offset from pkt->body rather than pkt->data.
+ *
+ * During construction of an outgoing packet, however, pkt->length
+ * is measured relative to the base pointer pkt->data, and
+ * pkt->body is not really used for anything until the packet is
+ * ready for sending. In this mode, pkt->savedpos is reused as a
+ * temporary variable by the addstring functions, which write out
+ * a string length field and then keep going back and updating it
+ * as more data is appended to the subsequent string data field;
+ * pkt->savedpos stores the offset (again relative to pkt->data)
+ * of the start of the string data field.
*/
- int logmode;
- int nblanks;
- struct logblank_t *blanks;
};
static void ssh1_protocol(Ssh ssh, void *vin, int inlen,
#define bombout(msg) bomb_out(ssh, dupprintf msg)
-/* Functions to leave bits out of the SSH packet log file. */
-
-static void dont_log_password(Ssh ssh, struct Packet *pkt, int blanktype)
-{
- if (conf_get_int(ssh->conf, CONF_logomitpass))
- pkt->logmode = blanktype;
-}
-
-static void dont_log_data(Ssh ssh, struct Packet *pkt, int blanktype)
-{
- if (ssh->logomitdata)
- pkt->logmode = blanktype;
-}
-
-static void end_log_omission(Ssh ssh, struct Packet *pkt)
-{
- pkt->logmode = PKTLOG_EMIT;
-}
-
/* Helper function for common bits of parsing ttymodes. */
static void parse_ttymodes(Ssh ssh,
void (*do_mode)(void *data, char *mode, char *val),
{
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)
pkt->body = pkt->data = NULL;
pkt->maxlen = 0;
- pkt->logmode = PKTLOG_EMIT;
- pkt->nblanks = 0;
- pkt->blanks = NULL;
return pkt;
}
+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);
+}
+
+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);
+
+ /*
+ * Undo the above adjustment of pkt->length, to put the packet
+ * back in the state we found it.
+ */
+ pkt->length += (pkt->body - pkt->data);
+}
+
/*
* Collect incoming data in the incoming packet buffer.
* Decipher and verify the packet when it is completely read.
}
st->pktin->body = st->pktin->data + st->pad + 1;
- st->pktin->savedpos = 0;
if (ssh->v1_compressing) {
unsigned char *decompblk;
st->pktin->type = st->pktin->body[-1];
/*
- * Log incoming packet, possibly omitting sensitive fields.
+ * Now pktin->body and pktin->length identify the semantic content
+ * of the packet, excluding the initial type byte.
*/
- if (ssh->logctx) {
- int nblanks = 0;
- struct logblank_t blank;
- if (ssh->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 = 4;
- } else if (st->pktin->type == SSH1_MSG_CHANNEL_DATA) {
- do_blank = TRUE; blank_prefix = 8;
- }
- 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, NULL);
- }
+
+ if (ssh->logctx)
+ ssh1_log_incoming_packet(ssh, st->pktin);
+
+ st->pktin->savedpos = 0;
crFinish(st->pktin);
}
+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);
+}
+
+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);
+
+ /*
+ * Undo the above adjustment of pkt->length, to put the packet
+ * back in the state we found it.
+ */
+ pkt->length += (pkt->body - pkt->data);
+}
+
static struct Packet *ssh2_rdpkt(Ssh ssh, unsigned char **data, int *datalen)
{
struct rdpkt2_state_tag *st = &ssh->rdpkt2_state;
}
}
- st->pktin->savedpos = 6;
- st->pktin->body = st->pktin->data;
- st->pktin->type = st->pktin->data[5];
-
/*
- * Log incoming packet, possibly omitting sensitive fields.
+ * pktin->body and pktin->length should identify the semantic
+ * content of the packet, excluding the initial type byte.
*/
- if (ssh->logctx) {
- int nblanks = 0;
- struct logblank_t blank;
- if (ssh->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 = 8;
- } else if (st->pktin->type == SSH2_MSG_CHANNEL_EXTENDED_DATA) {
- do_blank = TRUE; blank_prefix = 12;
- }
- if (do_blank) {
- blank.offset = blank_prefix;
- blank.len = (st->pktin->length-6) - blank_prefix;
- blank.type = PKTLOG_OMIT;
- nblanks = 1;
- }
- }
- log_packet(ssh->logctx, PKT_INCOMING, st->pktin->type,
- ssh2_pkt_type(ssh->pkt_kctx, ssh->pkt_actx,
- st->pktin->type),
- st->pktin->data+6, st->pktin->length-6,
- nblanks, &blank, &st->pktin->sequence);
- }
+ st->pktin->type = st->pktin->data[5];
+ st->pktin->body = st->pktin->data + 6;
+ st->pktin->length = st->packetlen - 6 - st->pad;
+ 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);
}
int len;
if (ssh->logctx)
- log_packet(ssh->logctx, PKT_OUTGOING, pkt->data[12],
- ssh1_pkt_type(pkt->data[12]),
- pkt->body, pkt->length - (pkt->body - pkt->data),
- pkt->nblanks, pkt->blanks, NULL);
- sfree(pkt->blanks); pkt->blanks = NULL;
- pkt->nblanks = 0;
+ ssh1_log_outgoing_packet(ssh, pkt);
if (ssh->v1_compressing) {
unsigned char *compblk;
bn = va_arg(ap, Bignum);
ssh1_pkt_addmp(pkt, bn);
break;
- /* Tokens for modifications to packet logging */
- case PKTT_PASSWORD:
- dont_log_password(ssh, pkt, PKTLOG_BLANK);
- break;
- case PKTT_DATA:
- dont_log_data(ssh, pkt, PKTLOG_OMIT);
- break;
- case PKTT_OTHER:
- end_log_omission(ssh, pkt);
- break;
}
}
}
static void ssh_pkt_adddata(struct Packet *pkt, const void *data, int len)
{
- if (pkt->logmode != PKTLOG_EMIT) {
- pkt->nblanks++;
- pkt->blanks = sresize(pkt->blanks, pkt->nblanks, struct logblank_t);
- assert(pkt->body);
- pkt->blanks[pkt->nblanks-1].offset = pkt->length -
- (pkt->body - pkt->data);
- pkt->blanks[pkt->nblanks-1].len = len;
- pkt->blanks[pkt->nblanks-1].type = pkt->logmode;
- }
pkt->length += len;
ssh_pkt_ensure(pkt, pkt->length);
memcpy(pkt->data + pkt->length - len, data, len);
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;
return pkt;
}
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 */
return pkt;
int cipherblk, maclen, padding, i;
if (ssh->logctx)
- 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 - (pkt->body - pkt->data),
- pkt->nblanks, pkt->blanks, &ssh->v2_outgoing_sequence);
- sfree(pkt->blanks); pkt->blanks = NULL;
- pkt->nblanks = 0;
+ ssh2_log_outgoing_packet(ssh, pkt);
/*
* Compress packet payload.
while (NULL != (c = index234(ssh->channels, 0))) {
switch (c->type) {
case CHAN_X11:
- x11_close(c->u.x11.s);
+ x11_close(c->u.x11.xconn);
break;
case CHAN_SOCKDATA:
case CHAN_SOCKDATA_DORMANT:
- pfd_close(c->u.pfd.s);
+ pfd_close(c->u.pfd.pf);
break;
}
del234(ssh->channels, c); /* moving next one to index 0 */
while (NULL != (pf = index234(ssh->portfwds, 0))) {
/* Dispose of any listening socket. */
if (pf->local)
- pfd_terminate(pf->local);
+ pfl_terminate(pf->local);
del234(ssh->portfwds, pf); /* moving next one to index 0 */
free_portfwd(pf);
}
*/
break;
case CHAN_X11:
- x11_override_throttle(c->u.x11.s, enable);
+ x11_override_throttle(c->u.x11.xconn, enable);
break;
case CHAN_AGENT:
/* Agent channels require no buffer management. */
break;
case CHAN_SOCKDATA:
- pfd_override_throttle(c->u.pfd.s, enable);
+ pfd_override_throttle(c->u.pfd.pf, enable);
break;
}
}
send_packet(ssh, SSH1_MSG_CHANNEL_DATA,
PKT_INT, c->remoteid,
PKT_INT, replylen,
- PKTT_DATA,
PKT_DATA, sentreply, replylen,
- PKTT_OTHER,
PKT_END);
}
if (reply)
for (i = bottom; i <= top; i++) {
if (i == pwlen) {
defer_packet(ssh, s->pwpkt_type,
- PKTT_PASSWORD, PKT_STR,
- s->cur_prompt->prompts[0]->result,
- PKTT_OTHER, PKT_END);
+ PKT_STR,s->cur_prompt->prompts[0]->result,
+ PKT_END);
} else {
for (j = 0; j < i; j++) {
do {
ss = s->cur_prompt->prompts[0]->result;
}
logevent("Sending length-padded password");
- send_packet(ssh, s->pwpkt_type, PKTT_PASSWORD,
+ send_packet(ssh, s->pwpkt_type,
PKT_INT, len, PKT_DATA, ss, len,
- PKTT_OTHER, PKT_END);
+ PKT_END);
} else {
/*
* The server is believed unable to cope with
len = strlen(s->cur_prompt->prompts[0]->result);
logevent("Sending unpadded password");
send_packet(ssh, s->pwpkt_type,
- PKTT_PASSWORD, PKT_INT, len,
+ PKT_INT, len,
PKT_DATA, s->cur_prompt->prompts[0]->result, len,
- PKTT_OTHER, PKT_END);
+ PKT_END);
}
} else {
- send_packet(ssh, s->pwpkt_type, PKTT_PASSWORD,
+ send_packet(ssh, s->pwpkt_type,
PKT_STR, s->cur_prompt->prompts[0]->result,
- PKTT_OTHER, PKT_END);
+ PKT_END);
}
logevent("Sent password");
free_prompts(s->cur_prompt);
switch (c->type) {
case CHAN_X11:
- x11_close(c->u.x11.s);
+ x11_close(c->u.x11.xconn);
logeventf(ssh, "Forwarded X11 connection terminated due to local "
"error: %s", err);
break;
case CHAN_SOCKDATA:
case CHAN_SOCKDATA_DORMANT:
- pfd_close(c->u.pfd.s);
+ pfd_close(c->u.pfd.pf);
logeventf(ssh, "Forwarded port closed due to local error: %s", err);
break;
}
c->type = CHAN_ZOMBIE;
+ c->pending_eof = FALSE; /* this will confuse a zombie channel */
ssh2_channel_check_close(c);
}
if (ssh->version == 1) {
send_packet(ssh, SSH1_MSG_CHANNEL_DATA,
PKT_INT, c->remoteid,
- PKT_INT, len, PKTT_DATA, PKT_DATA, buf, len,
- PKTT_OTHER, PKT_END);
+ PKT_INT, len, PKT_DATA, buf, len,
+ PKT_END);
/*
* In SSH-1 we can return 0 here - implying that forwarded
* connections are never individually throttled - because
del234(ssh->rportfwds, rpf);
free_rportfwd(rpf);
} else if (epf->local) {
- pfd_terminate(epf->local);
+ pfl_terminate(epf->local);
}
delpos234(ssh->portfwds, i);
}
if (epf->type == 'L') {
- const char *err = pfd_addforward(epf->daddr, epf->dport,
- epf->saddr, epf->sport,
- ssh, conf,
- &epf->local,
- epf->addressfamily);
+ char *err = pfl_listen(epf->daddr, epf->dport,
+ epf->saddr, epf->sport,
+ ssh, conf, &epf->local,
+ epf->addressfamily);
logeventf(ssh, "Local %sport %s forwarding to %s%s%s",
epf->addressfamily == ADDRTYPE_IPV4 ? "IPv4 " :
epf->addressfamily == ADDRTYPE_IPV6 ? "IPv6 " : "",
sportdesc, dportdesc,
err ? " failed: " : "", err ? err : "");
+ if (err)
+ sfree(err);
} else if (epf->type == 'D') {
- const char *err = pfd_addforward(NULL, -1,
- epf->saddr, epf->sport,
- ssh, conf,
- &epf->local,
- epf->addressfamily);
+ char *err = pfl_listen(NULL, -1, epf->saddr, epf->sport,
+ ssh, conf, &epf->local,
+ epf->addressfamily);
logeventf(ssh, "Local %sport %s SOCKS dynamic forwarding%s%s",
epf->addressfamily == ADDRTYPE_IPV4 ? "IPv4 " :
epf->addressfamily == ADDRTYPE_IPV6 ? "IPv6 " : "",
sportdesc,
err ? " failed: " : "", err ? err : "");
+
+ if (err)
+ sfree(err);
} else {
struct ssh_rportfwd *pf;
}
pf = snew(struct ssh_rportfwd);
- strncpy(pf->dhost, epf->daddr, lenof(pf->dhost)-1);
- pf->dhost[lenof(pf->dhost)-1] = '\0';
+ pf->dhost = dupstr(epf->daddr);
pf->dport = epf->dport;
+ if (epf->saddr) {
+ pf->shost = dupstr(epf->saddr);
+ } else if (conf_get_int(conf, CONF_rport_acceptall)) {
+ pf->shost = dupstr("");
+ } else {
+ pf->shost = dupstr("localhost");
+ }
pf->sport = epf->sport;
if (add234(ssh->rportfwds, pf) != pf) {
logeventf(ssh, "Duplicate remote port forwarding to %s:%d",
pktout = ssh2_pkt_init(SSH2_MSG_GLOBAL_REQUEST);
ssh2_pkt_addstring(pktout, "tcpip-forward");
ssh2_pkt_addbool(pktout, 1);/* want reply */
- if (epf->saddr) {
- ssh2_pkt_addstring(pktout, epf->saddr);
- } else if (conf_get_int(conf, CONF_rport_acceptall)) {
- ssh2_pkt_addstring(pktout, "");
- } else {
- ssh2_pkt_addstring(pktout, "localhost");
- }
- ssh2_pkt_adduint32(pktout, epf->sport);
+ ssh2_pkt_addstring(pktout, pf->shost);
+ ssh2_pkt_adduint32(pktout, pf->sport);
ssh2_pkt_send(ssh, pktout);
ssh_queue_handler(ssh, SSH2_MSG_REQUEST_SUCCESS,
PKT_INT, remoteid, PKT_END);
logevent("Rejected X11 connect request");
} else {
+ char *err;
+
c = snew(struct ssh_channel);
c->ssh = ssh;
- if (x11_init(&c->u.x11.s, ssh->x11disp, c,
- NULL, -1, ssh->conf) != NULL) {
- logevent("Opening X11 forward connection failed");
+ if ((err = x11_init(&c->u.x11.xconn, ssh->x11disp, c,
+ NULL, -1, ssh->conf)) != NULL) {
+ logeventf(ssh, "Opening X11 forward connection failed: %s", err);
+ sfree(err);
sfree(c);
send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE,
PKT_INT, remoteid, PKT_END);
int remoteid;
int hostsize, port;
char *host;
- const char *e;
+ char *err;
remoteid = ssh_pkt_getuint32(pktin);
ssh_pkt_getstring(pktin, &host, &hostsize);
port = ssh_pkt_getuint32(pktin);
- if (hostsize >= lenof(pf.dhost))
- hostsize = lenof(pf.dhost)-1;
- memcpy(pf.dhost, host, hostsize);
- pf.dhost[hostsize] = '\0';
+ pf.dhost = dupprintf(".*s", hostsize, host);
pf.dport = port;
pfp = find234(ssh->rportfwds, &pf, NULL);
logeventf(ssh, "Received remote port open request for %s:%d",
pf.dhost, port);
- e = pfd_newconnect(&c->u.pfd.s, pf.dhost, port,
- c, ssh->conf, pfp->pfrec->addressfamily);
- if (e != NULL) {
- logeventf(ssh, "Port open failed: %s", e);
+ err = pfd_connect(&c->u.pfd.pf, pf.dhost, port,
+ c, ssh->conf, pfp->pfrec->addressfamily);
+ if (err != NULL) {
+ logeventf(ssh, "Port open failed: %s", err);
+ sfree(err);
sfree(c);
send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE,
PKT_INT, remoteid, PKT_END);
logevent("Forwarded port opened successfully");
}
}
+
+ sfree(pf.dhost);
}
static void ssh1_msg_channel_open_confirmation(Ssh ssh, struct Packet *pktin)
c->halfopen = FALSE;
c->type = CHAN_SOCKDATA;
c->throttling_conn = 0;
- pfd_confirm(c->u.pfd.s);
+ pfd_confirm(c->u.pfd.pf);
}
if (c && c->pending_eof) {
c = find234(ssh->channels, &remoteid, ssh_channelfind);
if (c && c->type == CHAN_SOCKDATA_DORMANT) {
logevent("Forwarded connection refused by server");
- pfd_close(c->u.pfd.s);
+ pfd_close(c->u.pfd.pf);
del234(ssh->channels, c);
sfree(c);
}
switch (c->type) {
case CHAN_X11:
- if (c->u.x11.s)
- x11_send_eof(c->u.x11.s);
+ if (c->u.x11.xconn)
+ x11_send_eof(c->u.x11.xconn);
else
send_close = TRUE;
break;
case CHAN_SOCKDATA:
- if (c->u.pfd.s)
- pfd_send_eof(c->u.pfd.s);
+ if (c->u.pfd.pf)
+ pfd_send_eof(c->u.pfd.pf);
else
send_close = TRUE;
break;
int bufsize = 0;
switch (c->type) {
case CHAN_X11:
- bufsize = x11_send(c->u.x11.s, p, len);
+ bufsize = x11_send(c->u.x11.xconn, p, len);
break;
case CHAN_SOCKDATA:
- bufsize = pfd_send(c->u.pfd.s, p, len);
+ bufsize = pfd_send(c->u.pfd.pf, p, len);
break;
case CHAN_AGENT:
/* Data for an agent message. Buffer it. */
(ssh->x11disp = x11_setup_display(conf_get_str(ssh->conf, CONF_x11_display),
conf_get_int(ssh->conf, CONF_x11_auth), ssh->conf))) {
logevent("Requesting X11 forwarding");
- /*
- * 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.
- */
if (ssh->v1_local_protoflags & SSH1_PROTOFLAG_SCREEN_NUMBER) {
send_packet(ssh, SSH1_CMSG_X11_REQUEST_FORWARDING,
PKT_STR, ssh->x11disp->remoteauthprotoname,
- PKTT_PASSWORD,
PKT_STR, ssh->x11disp->remoteauthdatastring,
- PKTT_OTHER,
PKT_INT, ssh->x11disp->screennum,
PKT_END);
} else {
send_packet(ssh, SSH1_CMSG_X11_REQUEST_FORWARDING,
PKT_STR, ssh->x11disp->remoteauthprotoname,
- PKTT_PASSWORD,
PKT_STR, ssh->x11disp->remoteauthdatastring,
- PKTT_OTHER,
PKT_END);
}
do {
while (inlen > 0) {
int len = min(inlen, 512);
send_packet(ssh, SSH1_CMSG_STDIN_DATA,
- PKT_INT, len, PKTT_DATA, PKT_DATA, in, len,
- PKTT_OTHER, PKT_END);
+ PKT_INT, len, PKT_DATA, in, len,
+ PKT_END);
in += len;
inlen -= len;
}
hash_string(ssh->kex->hash, ssh->exhash,
s->our_kexinit, s->our_kexinitlen);
sfree(s->our_kexinit);
- if (pktin->length > 5)
- hash_string(ssh->kex->hash, ssh->exhash,
- pktin->data + 5, pktin->length - 5);
+ /* Include the type byte in the hash of server's KEXINIT */
+ hash_string(ssh->kex->hash, ssh->exhash,
+ pktin->body - 1, pktin->length + 1);
if (s->warn_kex) {
ssh_set_frozen(ssh, 1);
pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_DATA);
ssh2_pkt_adduint32(pktout, c->remoteid);
ssh2_pkt_addstring_start(pktout);
- dont_log_data(ssh, pktout, PKTLOG_OMIT);
ssh2_pkt_addstring_data(pktout, data, len);
- end_log_omission(ssh, pktout);
ssh2_pkt_send(ssh, pktout);
bufchain_consume(&c->v.v2.outbuffer, len);
c->v.v2.remwindow -= len;
* notification since it will be polled */
break;
case CHAN_X11:
- x11_unthrottle(c->u.x11.s);
+ x11_unthrottle(c->u.x11.xconn);
break;
case CHAN_AGENT:
/* agent sockets are request/response and need no
* buffer management */
break;
case CHAN_SOCKDATA:
- pfd_unthrottle(c->u.pfd.s);
+ pfd_unthrottle(c->u.pfd.pf);
break;
}
}
data, length);
break;
case CHAN_X11:
- bufsize = x11_send(c->u.x11.s, data, length);
+ bufsize = x11_send(c->u.x11.xconn, data, length);
break;
case CHAN_SOCKDATA:
- bufsize = pfd_send(c->u.pfd.s, data, length);
+ bufsize = pfd_send(c->u.pfd.pf, data, length);
break;
case CHAN_AGENT:
while (length > 0) {
update_specials_menu(ssh->frontend);
break;
case CHAN_X11:
- if (c->u.x11.s != NULL)
- x11_close(c->u.x11.s);
+ if (c->u.x11.xconn != NULL)
+ x11_close(c->u.x11.xconn);
logevent("Forwarded X11 connection terminated");
break;
case CHAN_AGENT:
sfree(c->u.a.message);
break;
case CHAN_SOCKDATA:
- if (c->u.pfd.s != NULL)
- pfd_close(c->u.pfd.s);
+ if (c->u.pfd.pf != NULL)
+ pfd_close(c->u.pfd.pf);
logevent("Forwarded port closed");
break;
}
Ssh ssh = c->ssh;
struct Packet *pktout;
+ if (c->halfopen) {
+ /*
+ * If we've sent out our own CHANNEL_OPEN but not yet seen
+ * either OPEN_CONFIRMATION or OPEN_FAILURE in response, then
+ * it's too early to be sending close messages of any kind.
+ */
+ return;
+ }
+
if ((!((CLOSES_SENT_EOF | CLOSES_RCVD_EOF) & ~c->closes) ||
c->type == CHAN_ZOMBIE) &&
!c->v.v2.chanreq_head &&
c->closes |= CLOSES_RCVD_EOF;
if (c->type == CHAN_X11) {
- x11_send_eof(c->u.x11.s);
+ x11_send_eof(c->u.x11.xconn);
} else if (c->type == CHAN_AGENT) {
if (c->u.a.outstanding_requests == 0) {
/* Manufacture an outgoing EOF in response to the incoming one. */
sshfwd_write_eof(c);
}
} else if (c->type == CHAN_SOCKDATA) {
- pfd_send_eof(c->u.pfd.s);
+ pfd_send_eof(c->u.pfd.pf);
} else if (c->type == CHAN_MAINSESSION) {
Ssh ssh = c->ssh;
ssh->send_ok = 0; /* stop trying to read from stdin */
break;
case CHAN_X11:
- x11_override_throttle(c->u.x11.s, 1);
+ x11_override_throttle(c->u.x11.xconn, 1);
break;
case CHAN_SOCKDATA:
- pfd_override_throttle(c->u.pfd.s, 1);
+ pfd_override_throttle(c->u.pfd.pf, 1);
break;
}
c = ssh2_channel_msg(ssh, pktin);
if (!c)
return;
- if (c->type != CHAN_SOCKDATA_DORMANT)
- return; /* dunno why they're confirming this */
+ assert(c->halfopen); /* ssh2_channel_msg will have enforced this */
c->remoteid = ssh_pkt_getuint32(pktin);
c->halfopen = FALSE;
- c->type = CHAN_SOCKDATA;
c->v.v2.remwindow = ssh_pkt_getuint32(pktin);
c->v.v2.remmaxpkt = ssh_pkt_getuint32(pktin);
- if (c->u.pfd.s)
- pfd_confirm(c->u.pfd.s);
+
+ if (c->type == CHAN_SOCKDATA_DORMANT) {
+ c->type = CHAN_SOCKDATA;
+ if (c->u.pfd.pf)
+ pfd_confirm(c->u.pfd.pf);
+ } else if (c->type == CHAN_ZOMBIE) {
+ /*
+ * This case can occur if a local socket error occurred
+ * between us sending out CHANNEL_OPEN and receiving
+ * OPEN_CONFIRMATION. In this case, all we can do is
+ * immediately initiate close proceedings now that we know the
+ * server's id to put in the close message.
+ */
+ ssh2_channel_check_close(c);
+ } else {
+ /*
+ * We never expect to receive OPEN_CONFIRMATION for any
+ * *other* channel type (since only local-to-remote port
+ * forwardings cause us to send CHANNEL_OPEN after the main
+ * channel is live - all other auxiliary channel types are
+ * initiated from the server end). It's safe to enforce this
+ * by assertion rather than by ssh_disconnect, because the
+ * real point is that we never constructed a half-open channel
+ * structure in the first place with any type other than the
+ * above.
+ */
+ assert(!"Funny channel type in ssh2_msg_channel_open_confirmation");
+ }
+
if (c->pending_eof)
- ssh_channel_try_eof(c);
+ ssh_channel_try_eof(c); /* in case we had a pending EOF */
}
static void ssh2_msg_channel_open_failure(Ssh ssh, struct Packet *pktin)
char *reason_string;
int reason_length;
struct ssh_channel *c;
+
c = ssh2_channel_msg(ssh, pktin);
if (!c)
return;
- if (c->type != CHAN_SOCKDATA_DORMANT)
- return; /* dunno why they're failing this */
-
- reason_code = ssh_pkt_getuint32(pktin);
- if (reason_code >= lenof(reasons))
- reason_code = 0; /* ensure reasons[reason_code] in range */
- ssh_pkt_getstring(pktin, &reason_string, &reason_length);
- logeventf(ssh, "Forwarded connection refused by server: %s [%.*s]",
- reasons[reason_code], reason_length, reason_string);
-
- pfd_close(c->u.pfd.s);
+ assert(c->halfopen); /* ssh2_channel_msg will have enforced this */
+
+ if (c->type == CHAN_SOCKDATA_DORMANT) {
+ reason_code = ssh_pkt_getuint32(pktin);
+ if (reason_code >= lenof(reasons))
+ reason_code = 0; /* ensure reasons[reason_code] in range */
+ ssh_pkt_getstring(pktin, &reason_string, &reason_length);
+ logeventf(ssh, "Forwarded connection refused by server: %s [%.*s]",
+ reasons[reason_code], reason_length, reason_string);
+
+ pfd_close(c->u.pfd.pf);
+ } else if (c->type == CHAN_ZOMBIE) {
+ /*
+ * This case can occur if a local socket error occurred
+ * between us sending out CHANNEL_OPEN and receiving
+ * OPEN_FAILURE. In this case, we need do nothing except allow
+ * the code below to throw the half-open channel away.
+ */
+ } else {
+ /*
+ * We never expect to receive OPEN_FAILURE for any *other*
+ * channel type (since only local-to-remote port forwardings
+ * cause us to send CHANNEL_OPEN after the main channel is
+ * live - all other auxiliary channel types are initiated from
+ * the server end). It's safe to enforce this by assertion
+ * rather than by ssh_disconnect, because the real point is
+ * that we never constructed a half-open channel structure in
+ * the first place with any type other than the above.
+ */
+ assert(!"Funny channel type in ssh2_msg_channel_open_failure");
+ }
del234(ssh->channels, c);
sfree(c);
if (typelen == 3 && !memcmp(type, "x11", 3)) {
char *addrstr;
- const char *x11err;
+ char *x11err;
ssh_pkt_getstring(pktin, &peeraddr, &peeraddrlen);
addrstr = snewn(peeraddrlen+1, char);
if (!ssh->X11_fwd_enabled)
error = "X11 forwarding is not enabled";
- else if ((x11err = x11_init(&c->u.x11.s, ssh->x11disp, c,
+ else if ((x11err = x11_init(&c->u.x11.xconn, ssh->x11disp, c,
addrstr, peerport, ssh->conf)) != NULL) {
logeventf(ssh, "Local X11 connection failed: %s", x11err);
+ sfree(x11err);
error = "Unable to open an X11 connection";
} else {
logevent("Opening X11 forward connection succeeded");
} else if (typelen == 15 &&
!memcmp(type, "forwarded-tcpip", 15)) {
struct ssh_rportfwd pf, *realpf;
- char *dummy;
- int dummylen;
- ssh_pkt_getstring(pktin, &dummy, &dummylen);/* skip address */
+ char *shost;
+ int shostlen;
+ ssh_pkt_getstring(pktin, &shost, &shostlen);/* skip address */
+ pf.shost = dupprintf("%.*s", shostlen, shost);
pf.sport = ssh_pkt_getuint32(pktin);
ssh_pkt_getstring(pktin, &peeraddr, &peeraddrlen);
peerport = ssh_pkt_getuint32(pktin);
realpf = find234(ssh->rportfwds, &pf, NULL);
- logeventf(ssh, "Received remote port %d open request "
- "from %s:%d", pf.sport, peeraddr, peerport);
+ logeventf(ssh, "Received remote port %s:%d open request "
+ "from %s:%d", pf.shost, pf.sport, peeraddr, peerport);
+ sfree(pf.shost);
+
if (realpf == NULL) {
error = "Remote port is not recognised";
} else {
- const char *e = pfd_newconnect(&c->u.pfd.s,
- realpf->dhost,
- realpf->dport, c,
- ssh->conf,
- realpf->pfrec->addressfamily);
+ char *err = pfd_connect(&c->u.pfd.pf,
+ realpf->dhost,
+ realpf->dport, c,
+ ssh->conf,
+ realpf->pfrec->addressfamily);
logeventf(ssh, "Attempting to forward remote port to "
"%s:%d", realpf->dhost, realpf->dport);
- if (e != NULL) {
- logeventf(ssh, "Port open failed: %s", e);
+ if (err != NULL) {
+ logeventf(ssh, "Port open failed: %s", err);
+ sfree(err);
error = "Port open failed";
} else {
logevent("Forwarded port opened successfully");
ssh2_setup_x11, s);
ssh2_pkt_addbool(pktout, 0); /* many connections */
ssh2_pkt_addstring(pktout, ssh->x11disp->remoteauthprotoname);
- /*
- * 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.
- */
- dont_log_password(ssh, pktout, PKTLOG_BLANK);
ssh2_pkt_addstring(pktout, ssh->x11disp->remoteauthdatastring);
- end_log_omission(ssh, pktout);
ssh2_pkt_adduint32(pktout, ssh->x11disp->screennum);
ssh2_pkt_send(ssh, pktout);
s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_INFO_RESPONSE);
ssh2_pkt_adduint32(s->pktout, s->num_prompts);
for (i=0; i < s->num_prompts; i++) {
- dont_log_password(ssh, s->pktout, PKTLOG_BLANK);
ssh2_pkt_addstring(s->pktout,
s->cur_prompt->prompts[i]->result);
- end_log_omission(ssh, s->pktout);
}
ssh2_pkt_send_with_padding(ssh, s->pktout, 256);
/* service requested */
ssh2_pkt_addstring(s->pktout, "password");
ssh2_pkt_addbool(s->pktout, FALSE);
- dont_log_password(ssh, s->pktout, PKTLOG_BLANK);
ssh2_pkt_addstring(s->pktout, s->password);
- end_log_omission(ssh, s->pktout);
ssh2_pkt_send_with_padding(ssh, s->pktout, 256);
logevent("Sent password");
s->type = AUTH_TYPE_PASSWORD;
/* service requested */
ssh2_pkt_addstring(s->pktout, "password");
ssh2_pkt_addbool(s->pktout, TRUE);
- dont_log_password(ssh, s->pktout, PKTLOG_BLANK);
ssh2_pkt_addstring(s->pktout, s->password);
ssh2_pkt_addstring(s->pktout,
s->cur_prompt->prompts[1]->result);
free_prompts(s->cur_prompt);
- end_log_omission(ssh, s->pktout);
ssh2_pkt_send_with_padding(ssh, s->pktout, 256);
logevent("Sent new password");
while ((c = delpos234(ssh->channels, 0)) != NULL) {
switch (c->type) {
case CHAN_X11:
- if (c->u.x11.s != NULL)
- x11_close(c->u.x11.s);
+ if (c->u.x11.xconn != NULL)
+ x11_close(c->u.x11.xconn);
break;
case CHAN_SOCKDATA:
case CHAN_SOCKDATA_DORMANT:
- if (c->u.pfd.s != NULL)
- pfd_close(c->u.pfd.s);
+ if (c->u.pfd.pf != NULL)
+ pfd_close(c->u.pfd.pf);
break;
}
if (ssh->version == 2) {
}
}
-void *new_sock_channel(void *handle, Socket s)
+void *new_sock_channel(void *handle, struct PortForwarding *pf)
{
Ssh ssh = (Ssh) handle;
struct ssh_channel *c;
ssh2_channel_init(c);
c->halfopen = TRUE;
c->type = CHAN_SOCKDATA_DORMANT;/* identify channel type */
- c->u.pfd.s = s;
+ c->u.pfd.pf = pf;
add234(ssh->channels, c);
return c;
}