Ssh ssh; /* pointer back to main context */
unsigned remoteid, localid;
int type;
+ /* True if we opened this channel but server hasn't confirmed. */
+ int halfopen;
/*
* In SSH1, this value contains four bits:
*
s->vstring[s->vslen] = 0;
s->vstring[strcspn(s->vstring, "\015\012")] = '\0';/* remove EOL chars */
- {
- char *vlog;
- vlog = snewn(20 + s->vslen, char);
- sprintf(vlog, "Server version: %s", s->vstring);
- logevent(vlog);
- sfree(vlog);
- }
+ logeventf(ssh, "Server version: %s", s->vstring);
ssh_detect_bugs(ssh, s->vstring);
/*
msg = dupprintf("Failed to connect to %s: %s", addrbuf, error_msg);
logevent(msg);
+ sfree(msg);
}
static int ssh_closing(Plug plug, const char *error_msg, int error_code,
s->p = s->response + 5;
s->nkeys = GET_32BIT(s->p);
s->p += 4;
- {
- char buf[64];
- sprintf(buf, "Pageant has %d SSH1 keys", s->nkeys);
- logevent(buf);
- }
+ logeventf(ssh, "Pageant has %d SSH1 keys", s->nkeys);
for (s->keyi = 0; s->keyi < s->nkeys; s->keyi++) {
- {
- char buf[64];
- sprintf(buf, "Trying Pageant key #%d", s->keyi);
- logevent(buf);
- }
+ logeventf(ssh, "Trying Pageant key #%d", s->keyi);
if (s->publickey_blob &&
!memcmp(s->p, s->publickey_blob,
s->publickey_bloblen)) {
if (s->pwpkt_type == SSH1_CMSG_AUTH_RSA) {
char *comment = NULL;
int type;
- char msgbuf[256];
if (flags & FLAG_VERBOSE)
c_write_str(ssh, "Trying public key authentication.\r\n");
logeventf(ssh, "Trying public key \"%s\"",
filename_to_str(&ssh->cfg.keyfile));
type = key_type(&ssh->cfg.keyfile);
if (type != SSH_KEYTYPE_SSH1) {
- sprintf(msgbuf, "Key is of wrong type (%s)",
- key_type_to_str(type));
- logevent(msgbuf);
- c_write_str(ssh, msgbuf);
+ char *msg = dupprintf("Key is of wrong type (%s)",
+ key_type_to_str(type));
+ logevent(msg);
+ c_write_str(ssh, msg);
c_write_str(ssh, "\r\n");
+ sfree(msg);
s->tried_publickey = 1;
continue;
}
if (c && !c->closes) {
/*
- * If the channel's remoteid is -1, we have sent
+ * If halfopen is true, we have sent
* CHANNEL_OPEN for this channel, but it hasn't even been
* acknowledged by the server. So we must set a close flag
* on it now, and then when the server acks the channel
* open, we can close it then.
*/
- if (((int)c->remoteid) != -1) {
+ if (!c->halfopen) {
if (ssh->version == 1) {
send_packet(ssh, SSH1_MSG_CHANNEL_CLOSE, PKT_INT, c->remoteid,
PKT_END);
}
} else {
while (*portfwd_strptr) portfwd_strptr++;
+ host[0] = 0;
+ dports[0] = 0;
dport = dserv = -1;
portfwd_strptr++; /* eat the NUL and move to next one */
}
if (epf->saddr) {
ssh2_pkt_addstring(pktout, epf->saddr);
} else if (ssh->cfg.rport_acceptall) {
+ /* XXX: ssh->cfg.rport_acceptall may not represent
+ * what was used to open the original connection,
+ * since it's reconfigurable. */
ssh2_pkt_addstring(pktout, "0.0.0.0");
} else {
ssh2_pkt_addstring(pktout, "127.0.0.1");
if (epf->type == 'L') {
const char *err = pfd_addforward(epf->daddr, epf->dport,
epf->saddr, epf->sport,
- ssh, &ssh->cfg,
+ ssh, cfg,
&epf->local,
epf->addressfamily);
} else if (epf->type == 'D') {
const char *err = pfd_addforward(NULL, -1,
epf->saddr, epf->sport,
- ssh, &ssh->cfg,
+ ssh, cfg,
&epf->local,
epf->addressfamily);
ssh2_pkt_addbool(pktout, 1);/* want reply */
if (epf->saddr) {
ssh2_pkt_addstring(pktout, epf->saddr);
- } else if (ssh->cfg.rport_acceptall) {
+ } else if (cfg->rport_acceptall) {
ssh2_pkt_addstring(pktout, "0.0.0.0");
} else {
ssh2_pkt_addstring(pktout, "127.0.0.1");
logevent
("Opening X11 forward connection succeeded");
c->remoteid = remoteid;
+ c->halfopen = FALSE;
c->localid = alloc_channel_id(ssh);
c->closes = 0;
c->v.v1.throttling = 0;
c = snew(struct ssh_channel);
c->ssh = ssh;
c->remoteid = remoteid;
+ c->halfopen = FALSE;
c->localid = alloc_channel_id(ssh);
c->closes = 0;
c->v.v1.throttling = 0;
struct ssh_rportfwd pf, *pfp;
int remoteid;
int hostsize, port;
- char *host, buf[1024];
+ char *host;
const char *e;
c = snew(struct ssh_channel);
c->ssh = ssh;
pfp = find234(ssh->rportfwds, &pf, NULL);
if (pfp == NULL) {
- sprintf(buf, "Rejected remote port open request for %s:%d",
- pf.dhost, port);
- logevent(buf);
+ logeventf(ssh, "Rejected remote port open request for %s:%d",
+ pf.dhost, port);
send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE,
PKT_INT, remoteid, PKT_END);
} else {
- sprintf(buf, "Received remote port open request for %s:%d",
- pf.dhost, port);
- logevent(buf);
+ 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->cfg, pfp->pfrec->addressfamily);
if (e != NULL) {
- char buf[256];
- sprintf(buf, "Port open failed: %s", e);
- logevent(buf);
+ logeventf(ssh, "Port open failed: %s", e);
sfree(c);
send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE,
PKT_INT, remoteid, PKT_END);
} else {
c->remoteid = remoteid;
+ c->halfopen = FALSE;
c->localid = alloc_channel_id(ssh);
c->closes = 0;
c->v.v1.throttling = 0;
c = find234(ssh->channels, &remoteid, ssh_channelfind);
if (c && c->type == CHAN_SOCKDATA_DORMANT) {
c->remoteid = localid;
+ c->halfopen = FALSE;
c->type = CHAN_SOCKDATA;
c->v.v1.throttling = 0;
pfd_confirm(c->u.pfd.s);
unsigned i = ssh_pkt_getuint32(pktin);
struct ssh_channel *c;
c = find234(ssh->channels, &i, ssh_channelfind);
- if (c && ((int)c->remoteid) != -1) {
+ if (c && !c->halfopen) {
int closetype;
closetype =
(pktin->type == SSH1_MSG_CHANNEL_CLOSE ? 1 : 2);
static void ssh1_smsg_exit_status(Ssh ssh, struct Packet *pktin)
{
- char buf[100];
ssh->exitcode = ssh_pkt_getuint32(pktin);
- sprintf(buf, "Server sent command exit status %d",
- ssh->exitcode);
- logevent(buf);
+ logeventf(ssh, "Server sent command exit status %d", ssh->exitcode);
send_packet(ssh, SSH1_CMSG_EXIT_CONFIRMATION, PKT_END);
/*
* In case `helpful' firewalls or proxies tack
*/
static void ssh1_msg_debug(Ssh ssh, struct Packet *pktin)
{
- char *buf, *msg;
+ char *msg;
int msglen;
ssh_pkt_getstring(pktin, &msg, &msglen);
- buf = dupprintf("Remote debug message: %.*s", msglen, msg);
- logevent(buf);
- sfree(buf);
+ logeventf(ssh, "Remote debug message: %.*s", msglen, msg);
}
static void ssh1_msg_disconnect(Ssh ssh, struct Packet *pktin)
bombout(("Server sent disconnect message:\n\"%.*s\"", msglen, msg));
}
-void ssh_msg_ignore(Ssh ssh, struct Packet *pktin)
+static void ssh_msg_ignore(Ssh ssh, struct Packet *pktin)
{
/* Do nothing, because we're ignoring it! Duhh. */
}
}
/*
+ * Similar routine for checking whether we have the first string in a list.
+ */
+static int first_in_commasep_string(char *needle, char *haystack, int haylen)
+{
+ int needlen;
+ if (!needle || !haystack) /* protect against null pointers */
+ return 0;
+ needlen = strlen(needle);
+ /*
+ * Is it at the start of the string?
+ */
+ if (haylen >= needlen && /* haystack is long enough */
+ !memcmp(needle, haystack, needlen) && /* initial match */
+ (haylen == needlen || haystack[needlen] == ',')
+ /* either , or EOS follows */
+ )
+ return 1;
+ return 0;
+}
+
+
+/*
* SSH2 key creation method.
*/
static void ssh2_mkkey(Ssh ssh, Bignum K, unsigned char *H,
*/
{
char *str;
- int i, j, len;
+ int i, j, len, guessok;
if (pktin->type != SSH2_MSG_KEXINIT) {
bombout(("expected key exchange packet from server"));
str ? str : "(null)"));
crStop(0);
}
+ /*
+ * Note that the server's guess is considered wrong if it doesn't match
+ * the first algorithm in our list, even if it's still the algorithm
+ * we end up using.
+ */
+ guessok =
+ first_in_commasep_string(s->preferred_kex[0]->name, str, len);
ssh_pkt_getstring(pktin, &str, &len); /* host key algorithms */
for (i = 0; i < lenof(hostkey_algs); i++) {
if (in_commasep_string(hostkey_algs[i]->name, str, len)) {
break;
}
}
+ guessok = guessok &&
+ first_in_commasep_string(hostkey_algs[0]->name, str, len);
ssh_pkt_getstring(pktin, &str, &len); /* client->server cipher */
s->warn = 0;
for (i = 0; i < s->n_preferred_ciphers; i++) {
break;
}
}
+ ssh_pkt_getstring(pktin, &str, &len); /* client->server language */
+ ssh_pkt_getstring(pktin, &str, &len); /* server->client language */
+ if (ssh2_pkt_getbool(pktin) && !guessok) /* first_kex_packet_follows */
+ crWaitUntil(pktin); /* Ignore packet */
}
/*
/*
* Now generate and send e for Diffie-Hellman.
*/
+ set_busy_status(ssh->frontend, BUSY_CPU); /* this can take a while */
s->e = dh_create_e(ssh->kex_ctx, s->nbits * 2);
s->pktout = ssh2_pkt_init(s->kex_init_value);
ssh2_pkt_addmp(s->pktout, s->e);
ssh2_pkt_send_noqueue(ssh, s->pktout);
+ set_busy_status(ssh->frontend, BUSY_WAITING); /* wait for server */
crWaitUntil(pktin);
if (pktin->type != s->kex_reply_value) {
bombout(("expected key exchange reply packet from server"));
crStop(0);
}
+ set_busy_status(ssh->frontend, BUSY_CPU); /* cogitate */
ssh_pkt_getstring(pktin, &s->hostkeydata, &s->hostkeylen);
s->f = ssh2_pkt_getmp(pktin);
if (!s->f) {
s->K = dh_find_K(ssh->kex_ctx, s->f);
+ /* We assume everything from now on will be quick, and it might
+ * involve user interaction. */
+ set_busy_status(ssh->frontend, BUSY_NOT);
+
sha_string(&ssh->exhash, s->hostkeydata, s->hostkeylen);
if (ssh->kex == &ssh_diffiehellman_gex) {
sha_uint32(&ssh->exhash, s->pbits);
struct Packet *pktout;
c = find234(ssh->channels, &i, ssh_channelfind);
- if (!c || ((int)c->remoteid) == -1) {
+ if (!c || c->halfopen) {
bombout(("Received CHANNEL_CLOSE for %s channel %d\n",
c ? "half-open" : "nonexistent", i));
return;
if (c->type != CHAN_SOCKDATA_DORMANT)
return; /* dunno why they're confirming 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);
unsigned reason_code;
char *reason_string;
int reason_length;
- char *message;
struct ssh_channel *c;
c = find234(ssh->channels, &i, ssh_channelfind);
if (!c)
if (reason_code >= lenof(reasons))
reason_code = 0; /* ensure reasons[reason_code] in range */
ssh_pkt_getstring(pktin, &reason_string, &reason_length);
- message = dupprintf("Forwarded connection refused by"
- " server: %s [%.*s]", reasons[reason_code],
- reason_length, reason_string);
- logevent(message);
- sfree(message);
+ logeventf(ssh, "Forwarded connection refused by server: %s [%.*s]",
+ reasons[reason_code], reason_length, reason_string);
pfd_close(c->u.pfd.s);
}
c->remoteid = remid;
+ c->halfopen = FALSE;
if (error) {
pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN_FAILURE);
ssh2_pkt_adduint32(pktout, c->remoteid);
s->p = s->response + 5;
s->nkeys = GET_32BIT(s->p);
s->p += 4;
- {
- char buf[64];
- sprintf(buf, "Pageant has %d SSH2 keys", s->nkeys);
- logevent(buf);
- }
+ logeventf(ssh, "Pageant has %d SSH2 keys", s->nkeys);
for (s->keyi = 0; s->keyi < s->nkeys; s->keyi++) {
void *vret;
- {
- char buf[64];
- sprintf(buf, "Trying Pageant key #%d", s->keyi);
- logevent(buf);
- }
+ logeventf(ssh, "Trying Pageant key #%d", s->keyi);
s->pklen = GET_32BIT(s->p);
s->p += 4;
if (s->publickey_blob &&
} else if (s->method == AUTH_KEYBOARD_INTERACTIVE) {
if (s->curr_prompt == 0) {
s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_INFO_RESPONSE);
+ s->pktout->forcepad = 256;
ssh2_pkt_adduint32(s->pktout, s->num_prompts);
}
if (s->need_pw) { /* only add pw if we just got one! */
crStopV;
}
ssh->mainchan->remoteid = ssh_pkt_getuint32(pktin);
+ ssh->mainchan->halfopen = FALSE;
ssh->mainchan->type = CHAN_MAINSESSION;
ssh->mainchan->closes = 0;
ssh->mainchan->v.v2.remwindow = ssh_pkt_getuint32(pktin);
/*
* Handlers for SSH2 messages that might arrive at any moment.
*/
-void ssh2_msg_disconnect(Ssh ssh, struct Packet *pktin)
+static void ssh2_msg_disconnect(Ssh ssh, struct Packet *pktin)
{
/* log reason code in disconnect message */
char *buf, *msg;
sfree(buf);
}
-void ssh2_msg_debug(Ssh ssh, struct Packet *pktin)
+static void ssh2_msg_debug(Ssh ssh, struct Packet *pktin)
{
/* log the debug message */
- char *buf, *msg;
+ char *msg;
int msglen;
int always_display;
always_display = ssh2_pkt_getbool(pktin);
ssh_pkt_getstring(pktin, &msg, &msglen);
- buf = dupprintf("Remote debug message: %.*s", msglen, msg);
- logevent(buf);
- sfree(buf);
+ logeventf(ssh, "Remote debug message: %.*s", msglen, msg);
}
-void ssh2_msg_something_unimplemented(Ssh ssh, struct Packet *pktin)
+static void ssh2_msg_something_unimplemented(Ssh ssh, struct Packet *pktin)
{
struct Packet *pktout;
pktout = ssh2_pkt_init(SSH2_MSG_UNIMPLEMENTED);
c->ssh = ssh;
if (c) {
- c->remoteid = -1; /* to be set when open confirmed */
+ c->halfopen = TRUE;
c->localid = alloc_channel_id(ssh);
c->closes = 0;
c->type = CHAN_SOCKDATA_DORMANT;/* identify channel type */