+ if (enable == ssh->throttled_all)
+ return;
+ ssh->throttled_all = enable;
+ ssh->overall_bufsize = bufsize;
+ if (!ssh->channels)
+ return;
+ for (i = 0; NULL != (c = index234(ssh->channels, i)); i++) {
+ switch (c->type) {
+ case CHAN_MAINSESSION:
+ /*
+ * This is treated separately, outside the switch.
+ */
+ break;
+ case CHAN_X11:
+ x11_override_throttle(c->u.x11.s, enable);
+ break;
+ case CHAN_AGENT:
+ /* Agent channels require no buffer management. */
+ break;
+ case CHAN_SOCKDATA:
+ pfd_override_throttle(c->u.pfd.s, enable);
+ break;
+ }
+ }
+}
+
+/*
+ * Username and password input, abstracted off into routines
+ * reusable in several places - even between SSH1 and SSH2.
+ */
+
+/* Set up a username or password input loop on a given buffer. */
+static void setup_userpass_input(Ssh ssh, char *buffer, int buflen, int echo)
+{
+ ssh->userpass_input_buffer = buffer;
+ ssh->userpass_input_buflen = buflen;
+ ssh->userpass_input_bufpos = 0;
+ ssh->userpass_input_echo = echo;
+}
+
+/*
+ * Process some terminal data in the course of username/password
+ * input. Returns >0 for success (line of input returned in
+ * buffer), <0 for failure (user hit ^C/^D, bomb out and exit), 0
+ * for inconclusive (keep waiting for more input please).
+ */
+static int process_userpass_input(Ssh ssh, unsigned char *in, int inlen)
+{
+ char c;
+
+ while (inlen--) {
+ switch (c = *in++) {
+ case 10:
+ case 13:
+ ssh->userpass_input_buffer[ssh->userpass_input_bufpos] = 0;
+ ssh->userpass_input_buffer[ssh->userpass_input_buflen-1] = 0;
+ return +1;
+ break;
+ case 8:
+ case 127:
+ if (ssh->userpass_input_bufpos > 0) {
+ if (ssh->userpass_input_echo)
+ c_write_str(ssh, "\b \b");
+ ssh->userpass_input_bufpos--;
+ }
+ break;
+ case 21:
+ case 27:
+ while (ssh->userpass_input_bufpos > 0) {
+ if (ssh->userpass_input_echo)
+ c_write_str(ssh, "\b \b");
+ ssh->userpass_input_bufpos--;
+ }
+ break;
+ case 3:
+ case 4:
+ return -1;
+ break;
+ default:
+ /*
+ * This simplistic check for printability is disabled
+ * when we're doing password input, because some people
+ * have control characters in their passwords.o
+ */
+ if ((!ssh->userpass_input_echo ||
+ (c >= ' ' && c <= '~') ||
+ ((unsigned char) c >= 160))
+ && ssh->userpass_input_bufpos < ssh->userpass_input_buflen-1) {
+ ssh->userpass_input_buffer[ssh->userpass_input_bufpos++] = c;
+ if (ssh->userpass_input_echo)
+ c_write(ssh, &c, 1);
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+static void ssh_agent_callback(void *sshv, void *reply, int replylen)
+{
+ Ssh ssh = (Ssh) sshv;
+
+ ssh->agent_response = reply;
+ ssh->agent_response_len = replylen;
+
+ if (ssh->version == 1)
+ do_ssh1_login(ssh, NULL, -1, 0);
+ else
+ do_ssh2_authconn(ssh, NULL, -1, 0);
+}
+
+static void ssh_agentf_callback(void *cv, void *reply, int replylen)
+{
+ struct ssh_channel *c = (struct ssh_channel *)cv;
+ Ssh ssh = c->ssh;
+ void *sentreply = reply;
+
+ if (!sentreply) {
+ /* Fake SSH_AGENT_FAILURE. */
+ sentreply = "\0\0\0\1\5";
+ replylen = 5;
+ }
+ if (ssh->version == 2) {
+ ssh2_add_channel_data(c, sentreply, replylen);
+ ssh2_try_send(c);
+ } else {
+ send_packet(ssh, SSH1_MSG_CHANNEL_DATA,
+ PKT_INT, c->remoteid,
+ PKT_INT, replylen,
+ PKT_DATA, sentreply, replylen,
+ PKT_END);
+ }
+ if (reply)
+ sfree(reply);
+}
+
+/*
+ * Handle the key exchange and user authentication phases.
+ */
+static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt)
+{
+ int i, j, ret;
+ unsigned char cookie[8], *ptr;
+ struct RSAKey servkey, hostkey;
+ struct MD5Context md5c;
+ struct do_ssh1_login_state {
+ int len;
+ unsigned char *rsabuf, *keystr1, *keystr2;
+ unsigned long supported_ciphers_mask, supported_auths_mask;
+ int tried_publickey, tried_agent;
+ int tis_auth_refused, ccard_auth_refused;
+ unsigned char session_id[16];
+ int cipher_type;
+ char username[100];
+ void *publickey_blob;
+ int publickey_bloblen;
+ char password[100];
+ char prompt[200];
+ int pos;
+ char c;
+ int pwpkt_type;
+ unsigned char request[5], *response, *p;
+ int responselen;
+ int keyi, nkeys;
+ int authed;
+ struct RSAKey key;
+ Bignum challenge;
+ char *commentp;
+ int commentlen;
+ };
+ crState(do_ssh1_login_state);
+
+ crBegin(ssh->do_ssh1_login_crstate);
+
+ if (!ispkt)
+ crWaitUntil(ispkt);
+
+ if (ssh->pktin.type != SSH1_SMSG_PUBLIC_KEY) {
+ bombout(("Public key packet not received"));
+ crStop(0);
+ }
+
+ logevent("Received public keys");
+
+ ptr = ssh_pkt_getdata(ssh, 8);
+ if (!ptr) {
+ bombout(("SSH1 public key packet stopped before random cookie"));
+ crStop(0);
+ }
+ memcpy(cookie, ptr, 8);
+
+ if (!ssh1_pkt_getrsakey(ssh, &servkey, &s->keystr1) ||
+ !ssh1_pkt_getrsakey(ssh, &hostkey, &s->keystr2)) {
+ bombout(("Failed to read SSH1 public keys from public key packet"));
+ crStop(0);
+ }
+
+ /*
+ * Log the host key fingerprint.