#include "putty.h"
#include "tree234.h"
#include "ssh.h"
+#ifndef NO_GSSAPI
#include "sshgss.h"
+#endif
#ifndef FALSE
#define FALSE 0
*
* - OUR_V2_BIGWIN is the window size we advertise for the only
* channel in a simple connection. It must be <= INT_MAX.
+ *
+ * - OUR_V2_MAXPKT is the official "maximum packet size" we send
+ * to the remote side. This actually has nothing to do with the
+ * size of the _packet_, but is instead a limit on the amount
+ * of data we're willing to receive in a single SSH2 channel
+ * data message.
+ *
+ * - OUR_V2_PACKETLIMIT is actually the maximum size of SSH
+ * _packet_ we're prepared to cope with. It must be a multiple
+ * of the cipher block size, and must be at least 35000.
*/
#define SSH1_BUFFER_LIMIT 32768
#define OUR_V2_WINSIZE 16384
#define OUR_V2_BIGWIN 0x7fffffff
#define OUR_V2_MAXPKT 0x4000UL
+#define OUR_V2_PACKETLIMIT 0x9000UL
/* Maximum length of passwords/passphrases (arbitrary) */
#define SSH_MAX_PASSWORD_LEN 100
Pkt_KCtx pkt_kctx;
Pkt_ACtx pkt_actx;
- void *x11auth;
+ struct X11Display *x11disp;
int version;
int conn_throttle_count;
st->cipherblk = 8;
if (st->cipherblk < 8)
st->cipherblk = 8;
+ st->maclen = ssh->scmac ? ssh->scmac->len : 0;
- st->pktin->data = snewn(st->cipherblk + APIEXTRA, unsigned char);
+ if (ssh->sccipher && (ssh->sccipher->flags & SSH_CIPHER_IS_CBC) &&
+ ssh->scmac) {
+ /*
+ * 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.
+ */
- /*
- * 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)--;
- }
+ /* May as well allocate the whole lot now. */
+ st->pktin->data = snewn(OUR_V2_PACKETLIMIT + st->maclen + APIEXTRA,
+ unsigned char);
- if (ssh->sccipher)
- ssh->sccipher->decrypt(ssh->sc_cipher_ctx,
- st->pktin->data, st->cipherblk);
+ /* 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)--;
+ }
- /*
- * Now get the length and padding figures.
- */
- st->len = GET_32BIT(st->pktin->data);
- st->pad = st->pktin->data[4];
+ 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);
+ }
- /*
- * _Completely_ silly lengths should be stomped on before they
- * do us any more damage.
- */
- if (st->len < 0 || st->len > 35000 || st->pad < 4 ||
- st->len - st->pad < 1 || (st->len + 4) % st->cipherblk != 0) {
- bombout(("Incoming packet was garbled on decryption"));
- ssh_free_packet(st->pktin);
- crStop(NULL);
- }
+ 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 = GET_32BIT(st->pktin->data)) + 4 == st->packetlen)
+ 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 {
+ st->pktin->data = snewn(st->cipherblk + APIEXTRA, unsigned char);
- /*
- * This enables us to deduce the payload length.
- */
- st->payload = st->len - st->pad - 1;
+ /*
+ * 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)--;
+ }
- st->pktin->length = st->payload + 5;
+ if (ssh->sccipher)
+ ssh->sccipher->decrypt(ssh->sc_cipher_ctx,
+ st->pktin->data, st->cipherblk);
- /*
- * So now we can work out the total packet length.
- */
- st->packetlen = st->len + 4;
- st->maclen = ssh->scmac ? ssh->scmac->len : 0;
+ /*
+ * Now get the length figure.
+ */
+ st->len = GET_32BIT(st->pktin->data);
- /*
- * 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);
+ /*
+ * _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);
+ }
- /*
- * 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);
+ /*
+ * So now we can work out the total packet length.
+ */
+ st->packetlen = st->len + 4;
- st->pktin->encrypted_len = st->packetlen;
+ /*
+ * 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);
- /*
- * 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"));
+ /*
+ * 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++;
fflush(stdout); /* FIXME eh? */
{
- if (!*ssh->cfg.username) {
+ if (!get_remote_username(&ssh->cfg, s->username,
+ sizeof(s->username))) {
int ret; /* need not be kept over crReturn */
s->cur_prompt = new_prompts(ssh->frontend);
s->cur_prompt->to_server = TRUE;
memcpy(s->username, s->cur_prompt->prompts[0]->result,
lenof(s->username));
free_prompts(s->cur_prompt);
- } else {
- strncpy(s->username, ssh->cfg.username, sizeof(s->username));
- s->username[sizeof(s->username)-1] = '\0';
}
send_packet(ssh, SSH1_CMSG_USER, PKT_STR, s->username, PKT_END);
c = snew(struct ssh_channel);
c->ssh = ssh;
- if (x11_init(&c->u.x11.s, ssh->cfg.x11_display, c,
- ssh->x11auth, NULL, -1, &ssh->cfg) != NULL) {
+ if (x11_init(&c->u.x11.s, ssh->x11disp, c,
+ NULL, -1, &ssh->cfg) != NULL) {
logevent("Opening X11 forward connection failed");
sfree(c);
send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE,
}
}
- if (ssh->cfg.x11_forward) {
- char proto[20], data[64];
+ if (ssh->cfg.x11_forward &&
+ (ssh->x11disp = x11_setup_display(ssh->cfg.x11_display,
+ ssh->cfg.x11_auth, &ssh->cfg))) {
logevent("Requesting X11 forwarding");
- ssh->x11auth = x11_invent_auth(proto, sizeof(proto),
- data, sizeof(data), ssh->cfg.x11_auth);
- x11_get_real_auth(ssh->x11auth, ssh->cfg.x11_display);
/*
* 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,
*/
if (ssh->v1_local_protoflags & SSH1_PROTOFLAG_SCREEN_NUMBER) {
send_packet(ssh, SSH1_CMSG_X11_REQUEST_FORWARDING,
- PKT_STR, proto,
- PKTT_PASSWORD, PKT_STR, data, PKTT_OTHER,
- PKT_INT, x11_get_screen_number(ssh->cfg.x11_display),
+ 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, proto,
- PKTT_PASSWORD, PKT_STR, data, PKTT_OTHER, PKT_END);
+ PKT_STR, ssh->x11disp->remoteauthprotoname,
+ PKTT_PASSWORD,
+ PKT_STR, ssh->x11disp->remoteauthdatastring,
+ PKTT_OTHER,
+ PKT_END);
}
do {
crReturnV;
if (typelen == 3 && !memcmp(type, "x11", 3)) {
char *addrstr;
+ const 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 (x11_init(&c->u.x11.s, ssh->cfg.x11_display, c,
- ssh->x11auth, addrstr, peerport,
- &ssh->cfg) != NULL) {
+ else if ((x11err = x11_init(&c->u.x11.s, ssh->x11disp, c,
+ addrstr, peerport, &ssh->cfg)) != NULL) {
+ logeventf(ssh, "Local X11 connection failed: %s", x11err);
error = "Unable to open an X11 connection";
} else {
logevent("Opening X11 forward connection succeeded");
int done_service_req;
int gotit, need_pw, can_pubkey, can_passwd, can_keyb_inter;
int tried_pubkey_config, done_agent;
+#ifndef NO_GSSAPI
int can_gssapi;
int tried_gssapi;
+#endif
int kbd_inter_refused;
int we_are_in;
prompts_t *cur_prompt;
int try_send;
int num_env, env_left, env_ok;
struct Packet *pktout;
+#ifndef NO_GSSAPI
Ssh_gss_ctx gss_ctx;
Ssh_gss_buf gss_buf;
Ssh_gss_buf gss_rcvtok, gss_sndtok;
Ssh_gss_name gss_srv_name;
Ssh_gss_stat gss_stat;
+#endif
};
crState(do_ssh2_authconn_state);
s->done_service_req = FALSE;
s->we_are_in = FALSE;
+#ifndef NO_GSSAPI
s->tried_gssapi = FALSE;
+#endif
if (!ssh->cfg.ssh_no_userauth) {
/*
* with change_username turned off we don't try to get
* it again.
*/
- } else if (!*ssh->cfg.username) {
+ } else if (!get_remote_username(&ssh->cfg, s->username,
+ sizeof(s->username))) {
int ret; /* need not be kept over crReturn */
s->cur_prompt = new_prompts(ssh->frontend);
s->cur_prompt->to_server = TRUE;
free_prompts(s->cur_prompt);
} else {
char *stuff;
- strncpy(s->username, ssh->cfg.username, sizeof(s->username));
- s->username[sizeof(s->username)-1] = '\0';
if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE)) {
stuff = dupprintf("Using username \"%s\".\r\n", s->username);
c_write_str(ssh, stuff);
/* GSSAPI Authentication */
- int micoffset;
+ int micoffset, len;
+ char *data;
Ssh_gss_buf mic;
s->type = AUTH_TYPE_GSSAPI;
s->tried_gssapi = TRUE;
ssh2_pkt_adduint32(s->pktout,1);
/* length of OID + 2 */
- ssh2_pkt_adduint32(s->pktout, s->gss_buf.len + 2);
+ ssh2_pkt_adduint32(s->pktout, s->gss_buf.length + 2);
ssh2_pkt_addbyte(s->pktout, SSH2_GSS_OIDTYPE);
/* length of OID */
- ssh2_pkt_addbyte(s->pktout, (unsigned char) s->gss_buf.len);
+ ssh2_pkt_addbyte(s->pktout, (unsigned char) s->gss_buf.length);
- ssh_pkt_adddata(s->pktout, s->gss_buf.data, s->gss_buf.len);
+ ssh_pkt_adddata(s->pktout, s->gss_buf.value,
+ s->gss_buf.length);
ssh2_pkt_send(ssh, s->pktout);
crWaitUntilV(pktin);
if (pktin->type != SSH2_MSG_USERAUTH_GSSAPI_RESPONSE) {
/* check returned packet ... */
- ssh_pkt_getstring(pktin,&s->gss_rcvtok.data,&s->gss_rcvtok.len);
- if (s->gss_rcvtok.len != s->gss_buf.len + 2 ||
- s->gss_rcvtok.data[0] != SSH2_GSS_OIDTYPE ||
- s->gss_rcvtok.data[1] != s->gss_buf.len ||
- memcmp(s->gss_rcvtok.data+2,s->gss_buf.data,s->gss_buf.len) ) {
+ ssh_pkt_getstring(pktin, &data, &len);
+ s->gss_rcvtok.value = data;
+ s->gss_rcvtok.length = len;
+ if (s->gss_rcvtok.length != s->gss_buf.length + 2 ||
+ ((char *)s->gss_rcvtok.value)[0] != SSH2_GSS_OIDTYPE ||
+ ((char *)s->gss_rcvtok.value)[1] != s->gss_buf.length ||
+ memcmp((char *)s->gss_rcvtok.value + 2,
+ s->gss_buf.value,s->gss_buf.length) ) {
logevent("GSSAPI authentication - wrong response from server");
continue;
}
}
/* initial tokens are empty */
- s->gss_rcvtok.len = s->gss_sndtok.len = 0;
- s->gss_rcvtok.data = s->gss_sndtok.data = NULL;
+ SSH_GSS_CLEAR_BUF(&s->gss_rcvtok);
+ SSH_GSS_CLEAR_BUF(&s->gss_sndtok);
/* now enter the loop */
do {
logevent("GSSAPI authentication initialisation failed");
if (ssh_gss_display_status(s->gss_ctx,&s->gss_buf) == SSH_GSS_OK) {
- logevent(s->gss_buf.data);
- sfree(s->gss_buf.data);
+ logevent(s->gss_buf.value);
+ sfree(s->gss_buf.value);
}
break;
/* Client and server now exchange tokens until GSSAPI
* no longer says CONTINUE_NEEDED */
- if (s->gss_sndtok.len != 0) {
+ if (s->gss_sndtok.length != 0) {
s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
ssh_pkt_addstring_start(s->pktout);
- ssh_pkt_addstring_data(s->pktout,s->gss_sndtok.data,s->gss_sndtok.len);
+ ssh_pkt_addstring_data(s->pktout,s->gss_sndtok.value,s->gss_sndtok.length);
ssh2_pkt_send(ssh, s->pktout);
ssh_gss_free_tok(&s->gss_sndtok);
}
s->gss_stat = SSH_GSS_FAILURE;
break;
}
- ssh_pkt_getstring(pktin,&s->gss_rcvtok.data,&s->gss_rcvtok.len);
+ ssh_pkt_getstring(pktin, &data, &len);
+ s->gss_rcvtok.value = data;
+ s->gss_rcvtok.length = len;
}
} while (s-> gss_stat == SSH_GSS_S_CONTINUE_NEEDED);
ssh_pkt_addstring(s->pktout, "ssh-connection");
ssh_pkt_addstring(s->pktout, "gssapi-with-mic");
- s->gss_buf.data = (char *)s->pktout->data + micoffset;
- s->gss_buf.len = s->pktout->length - micoffset;
+ s->gss_buf.value = (char *)s->pktout->data + micoffset;
+ s->gss_buf.length = s->pktout->length - micoffset;
ssh_gss_get_mic(s->gss_ctx, &s->gss_buf, &mic);
s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_GSSAPI_MIC);
ssh_pkt_addstring_start(s->pktout);
- ssh_pkt_addstring_data(s->pktout, mic.data, mic.len);
+ ssh_pkt_addstring_data(s->pktout, mic.value, mic.length);
ssh2_pkt_send(ssh, s->pktout);
ssh_gss_free_mic(&mic);
ssh_pkt_getstring(pktin, &lang, &lang_len);
s->cur_prompt = new_prompts(ssh->frontend);
s->cur_prompt->to_server = TRUE;
- if (name_len) {
- /* FIXME: better prefix to distinguish from
- * local prompts? */
- s->cur_prompt->name =
- dupprintf("SSH server: %.*s", name_len, name);
- s->cur_prompt->name_reqd = TRUE;
- } else {
- s->cur_prompt->name =
- dupstr("SSH server authentication");
- s->cur_prompt->name_reqd = FALSE;
- }
- /* FIXME: ugly to print "Using..." in prompt _every_
- * time round. Can this be done more subtly? */
- s->cur_prompt->instruction =
- dupprintf("Using keyboard-interactive authentication.%s%.*s",
- inst_len ? "\n" : "", inst_len, inst);
- s->cur_prompt->instr_reqd = TRUE;
/*
* Get any prompt(s) from the packet.
echo, SSH_MAX_PASSWORD_LEN);
}
+ if (name_len) {
+ /* FIXME: better prefix to distinguish from
+ * local prompts? */
+ s->cur_prompt->name =
+ dupprintf("SSH server: %.*s", name_len, name);
+ s->cur_prompt->name_reqd = TRUE;
+ } else {
+ s->cur_prompt->name =
+ dupstr("SSH server authentication");
+ s->cur_prompt->name_reqd = FALSE;
+ }
+ /* We add a prefix to try to make it clear that a prompt
+ * has come from the server.
+ * FIXME: ugly to print "Using..." in prompt _every_
+ * time round. Can this be done more subtly? */
+ /* Special case: for reasons best known to themselves,
+ * some servers send k-i requests with no prompts and
+ * nothing to display. Keep quiet in this case. */
+ if (s->num_prompts || name_len || inst_len) {
+ s->cur_prompt->instruction =
+ dupprintf("Using keyboard-interactive authentication.%s%.*s",
+ inst_len ? "\n" : "", inst_len, inst);
+ s->cur_prompt->instr_reqd = TRUE;
+ } else {
+ s->cur_prompt->instr_reqd = FALSE;
+ }
+
/*
* Display any instructions, and get the user's
* response(s).
/*
* Potentially enable X11 forwarding.
*/
- if (ssh->mainchan && !ssh->ncmode && ssh->cfg.x11_forward) {
- char proto[20], data[64];
+ if (ssh->mainchan && !ssh->ncmode && ssh->cfg.x11_forward &&
+ (ssh->x11disp = x11_setup_display(ssh->cfg.x11_display,
+ ssh->cfg.x11_auth, &ssh->cfg))) {
logevent("Requesting X11 forwarding");
- ssh->x11auth = x11_invent_auth(proto, sizeof(proto),
- data, sizeof(data), ssh->cfg.x11_auth);
- x11_get_real_auth(ssh->x11auth, ssh->cfg.x11_display);
s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);
ssh2_pkt_adduint32(s->pktout, ssh->mainchan->remoteid);
ssh2_pkt_addstring(s->pktout, "x11-req");
ssh2_pkt_addbool(s->pktout, 1); /* want reply */
ssh2_pkt_addbool(s->pktout, 0); /* many connections */
- ssh2_pkt_addstring(s->pktout, proto);
+ ssh2_pkt_addstring(s->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,
* cookie into the log.
*/
dont_log_password(ssh, s->pktout, PKTLOG_BLANK);
- ssh2_pkt_addstring(s->pktout, data);
+ ssh2_pkt_addstring(s->pktout, ssh->x11disp->remoteauthdatastring);
end_log_omission(ssh, s->pktout);
- ssh2_pkt_adduint32(s->pktout, x11_get_screen_number(ssh->cfg.x11_display));
+ ssh2_pkt_adduint32(s->pktout, ssh->x11disp->screennum);
ssh2_pkt_send(ssh, s->pktout);
crWaitUntilV(pktin);
ssh->fallback_cmd = 0;
ssh->pkt_kctx = SSH2_PKTCTX_NOKEX;
ssh->pkt_actx = SSH2_PKTCTX_NOAUTH;
- ssh->x11auth = NULL;
+ ssh->x11disp = NULL;
ssh->v1_compressing = FALSE;
ssh->v2_outgoing_sequence = 0;
ssh->ssh1_rdpkt_crstate = 0;
ssh->rportfwds = NULL;
}
sfree(ssh->deferred_send_data);
- if (ssh->x11auth)
- x11_free_auth(ssh->x11auth);
+ if (ssh->x11disp)
+ x11_free_display(ssh->x11disp);
sfree(ssh->do_ssh_init_state);
sfree(ssh->do_ssh1_login_state);
sfree(ssh->do_ssh2_transport_state);