* ensure that the server never has any need to throttle its end
* of the connection), so we set this high as well.
*
- * - OUR_V2_WINSIZE is the maximum window size we present on SSH-2
+ * - OUR_V2_WINSIZE is the default window size we present on SSH-2
* channels.
*
* - OUR_V2_BIGWIN is the window size we advertise for the only
/* Anything greater or equal to "1.99" means protocol 2 is supported. */
s->proto2 = ssh_versioncmp(s->version, "1.99") >= 0;
- if (conf_get_int(ssh->conf, CONF_sshprot) == 0 && !s->proto1) {
- bombout(("SSH protocol version 1 required by configuration but "
- "not provided by server"));
- crStop(0);
- }
- if (conf_get_int(ssh->conf, CONF_sshprot) == 3 && !s->proto2) {
- bombout(("SSH protocol version 2 required by configuration but "
- "not provided by server"));
- crStop(0);
+ if (conf_get_int(ssh->conf, CONF_sshprot) == 0) {
+ if (!s->proto1) {
+ bombout(("SSH protocol version 1 required by our configuration "
+ "but not provided by server"));
+ crStop(0);
+ }
+ } else if (conf_get_int(ssh->conf, CONF_sshprot) == 3) {
+ if (!s->proto2) {
+ bombout(("SSH protocol version 2 required by our configuration "
+ "but server only provides (old, insecure) SSH-1"));
+ crStop(0);
+ }
+ } else {
+ /* No longer support values 1 or 2 for CONF_sshprot */
+ assert(!"Unexpected value for CONF_sshprot");
}
if (s->proto2 && (conf_get_int(ssh->conf, CONF_sshprot) >= 2 || !s->proto1))
}
/*
- * If the SSH version number's fixed, set it now, and if it's SSH-2,
- * send the version string too.
+ * The SSH version number is always fixed (since we no longer support
+ * fallback between versions), so set it now, and if it's SSH-2,
+ * send the version string now too.
*/
sshprot = conf_get_int(ssh->conf, CONF_sshprot);
+ assert(sshprot == 0 || sshprot == 3);
if (sshprot == 0)
+ /* SSH-1 only */
ssh->version = 1;
if (sshprot == 3 && !ssh->bare_connection) {
+ /* SSH-2 only */
ssh->version = 2;
ssh_send_verstring(ssh, "SSH-", NULL);
}
}
}
+/*
+ * Handle incoming data on an SSH-1 or SSH-2 agent-forwarding channel.
+ */
+static int ssh_agent_channel_data(struct ssh_channel *c, char *data,
+ int length)
+{
+ while (length > 0) {
+ if (c->u.a.lensofar < 4) {
+ unsigned int l = min(4 - c->u.a.lensofar, (unsigned)length);
+ memcpy(c->u.a.msglen + c->u.a.lensofar, data, l);
+ data += l;
+ length -= l;
+ c->u.a.lensofar += l;
+ }
+ if (c->u.a.lensofar == 4) {
+ c->u.a.totallen = 4 + GET_32BIT(c->u.a.msglen);
+ c->u.a.message = snewn(c->u.a.totallen, unsigned char);
+ memcpy(c->u.a.message, c->u.a.msglen, 4);
+ }
+ if (c->u.a.lensofar >= 4 && length > 0) {
+ unsigned int l = min(c->u.a.totallen - c->u.a.lensofar,
+ (unsigned)length);
+ memcpy(c->u.a.message + c->u.a.lensofar, data, l);
+ data += l;
+ length -= l;
+ c->u.a.lensofar += l;
+ }
+ if (c->u.a.lensofar == c->u.a.totallen) {
+ void *reply;
+ int replylen;
+ c->u.a.outstanding_requests++;
+ if (agent_query(c->u.a.message, c->u.a.totallen, &reply, &replylen,
+ ssh_agentf_callback, c))
+ ssh_agentf_callback(c, reply, replylen);
+ sfree(c->u.a.message);
+ c->u.a.message = NULL;
+ c->u.a.lensofar = 0;
+ }
+ }
+ return 0; /* agent channels never back up */
+}
+
static void ssh1_msg_channel_data(Ssh ssh, struct Packet *pktin)
{
/* Data sent down one of our channels. */
bufsize = pfd_send(c->u.pfd.pf, p, len);
break;
case CHAN_AGENT:
- /* Data for an agent message. Buffer it. */
- while (len > 0) {
- if (c->u.a.lensofar < 4) {
- unsigned int l = min(4 - c->u.a.lensofar, (unsigned)len);
- memcpy(c->u.a.msglen + c->u.a.lensofar, p,
- l);
- p += l;
- len -= l;
- c->u.a.lensofar += l;
- }
- if (c->u.a.lensofar == 4) {
- c->u.a.totallen =
- 4 + GET_32BIT(c->u.a.msglen);
- c->u.a.message = snewn(c->u.a.totallen,
- unsigned char);
- memcpy(c->u.a.message, c->u.a.msglen, 4);
- }
- if (c->u.a.lensofar >= 4 && len > 0) {
- unsigned int l =
- min(c->u.a.totallen - c->u.a.lensofar,
- (unsigned)len);
- memcpy(c->u.a.message + c->u.a.lensofar, p,
- l);
- p += l;
- len -= l;
- c->u.a.lensofar += l;
- }
- if (c->u.a.lensofar == c->u.a.totallen) {
- void *reply;
- int replylen;
- c->u.a.outstanding_requests++;
- if (agent_query(c->u.a.message,
- c->u.a.totallen,
- &reply, &replylen,
- ssh_agentf_callback, c))
- ssh_agentf_callback(c, reply, replylen);
- sfree(c->u.a.message);
- c->u.a.lensofar = 0;
- }
- }
- bufsize = 0; /* agent channels never back up */
+ bufsize = ssh_agent_channel_data(c, p, len);
break;
}
if (!c->throttling_conn && bufsize > SSH1_BUFFER_LIMIT) {
}
if (s->warn_hk) {
+ int j, k;
+ char *betteralgs;
+
ssh_set_frozen(ssh, 1);
- s->dlgret = askalg(ssh->frontend, "host key type",
- ssh->hostkey->name,
- ssh_dialog_callback, ssh);
+
+ /*
+ * Change warning box wording depending on why we chose a
+ * warning-level host key algorithm. If it's because
+ * that's all we have *cached*, use the askhk mechanism,
+ * and list the host keys we could usefully cross-certify.
+ * Otherwise, use askalg for the standard wording.
+ */
+ betteralgs = NULL;
+ for (j = 0; j < ssh->n_uncert_hostkeys; j++) {
+ const struct ssh_signkey_with_user_pref_id *hktype =
+ &hostkey_algs[ssh->uncert_hostkeys[j]];
+ int better = FALSE;
+ for (k = 0; k < HK_MAX; k++) {
+ int id = conf_get_int_int(ssh->conf, CONF_ssh_hklist, k);
+ if (id == HK_WARN) {
+ break;
+ } else if (id == hktype->id) {
+ better = TRUE;
+ break;
+ }
+ }
+ if (better) {
+ if (betteralgs) {
+ char *old_ba = betteralgs;
+ betteralgs = dupcat(betteralgs, ",",
+ hktype->alg->name,
+ (const char *)NULL);
+ sfree(old_ba);
+ } else {
+ betteralgs = dupstr(hktype->alg->name);
+ }
+ }
+ }
+ if (betteralgs) {
+ s->dlgret = askhk(ssh->frontend, ssh->hostkey->name,
+ betteralgs, ssh_dialog_callback, ssh);
+ sfree(betteralgs);
+ } else {
+ s->dlgret = askalg(ssh->frontend, "host key type",
+ ssh->hostkey->name,
+ ssh_dialog_callback, ssh);
+ }
if (s->dlgret < 0) {
do {
crReturnV;
* Make a note of any other host key formats that are available.
*/
{
- int i, j;
+ int i, j, nkeys = 0;
char *list = NULL;
for (i = 0; i < lenof(hostkey_algs); i++) {
if (hostkey_algs[i].alg == ssh->hostkey)
newlist = dupprintf("%s", hostkey_algs[i].alg->name);
sfree(list);
list = newlist;
+ nkeys++;
}
}
if (list) {
logeventf(ssh,
"Server also has %s host key%s, but we "
"don't know %s", list,
- j > 1 ? "s" : "", j > 1 ? "any of them" : "it");
+ nkeys > 1 ? "s" : "",
+ nkeys > 1 ? "any of them" : "it");
sfree(list);
}
}
bufsize = pfd_send(c->u.pfd.pf, data, length);
break;
case CHAN_AGENT:
- while (length > 0) {
- if (c->u.a.lensofar < 4) {
- unsigned int l = min(4 - c->u.a.lensofar,
- (unsigned)length);
- memcpy(c->u.a.msglen + c->u.a.lensofar,
- data, l);
- data += l;
- length -= l;
- c->u.a.lensofar += l;
- }
- if (c->u.a.lensofar == 4) {
- c->u.a.totallen =
- 4 + GET_32BIT(c->u.a.msglen);
- c->u.a.message = snewn(c->u.a.totallen,
- unsigned char);
- memcpy(c->u.a.message, c->u.a.msglen, 4);
- }
- if (c->u.a.lensofar >= 4 && length > 0) {
- unsigned int l =
- min(c->u.a.totallen - c->u.a.lensofar,
- (unsigned)length);
- memcpy(c->u.a.message + c->u.a.lensofar,
- data, l);
- data += l;
- length -= l;
- c->u.a.lensofar += l;
- }
- if (c->u.a.lensofar == c->u.a.totallen) {
- void *reply;
- int replylen;
- c->u.a.outstanding_requests++;
- if (agent_query(c->u.a.message,
- c->u.a.totallen,
- &reply, &replylen,
- ssh_agentf_callback, c))
- ssh_agentf_callback(c, reply, replylen);
- sfree(c->u.a.message);
- c->u.a.message = NULL;
- c->u.a.lensofar = 0;
- }
- }
- bufsize = 0;
+ bufsize = ssh_agent_channel_data(c, data, length);
break;
}
/*
int pklen, alglen, commentlen;
int siglen, retlen, len;
char *q, *agentreq, *ret;
- int try_send;
struct Packet *pktout;
Filename *keyfile;
#ifndef NO_GSSAPI
ssh->send_ok = 1;
while (1) {
crReturnV;
- s->try_send = FALSE;
if (pktin) {
/*
* We have spare data. Add it to the channel buffer.
*/
ssh2_add_channel_data(ssh->mainchan, (char *)in, inlen);
- s->try_send = TRUE;
- }
- if (s->try_send) {
- int i;
- struct ssh_channel *c;
- /*
- * Try to send data on all channels if we can.
- */
- for (i = 0; NULL != (c = index234(ssh->channels, i)); i++)
- if (c->type != CHAN_SHARING)
- ssh2_try_send_and_unthrottle(ssh, c);
+ ssh2_try_send(ssh->mainchan);
}
}