+
+ if (ssh_get_password) {
+ char prompt[200];
+ sprintf(prompt, "%.90s@%.90s's password: ", username, savedhost);
+ if (!ssh_get_password(prompt, password, sizeof(password))) {
+ /*
+ * get_password failed to get a password (for
+ * example because one was supplied on the command
+ * line which has already failed to work).
+ * Terminate.
+ */
+ logevent("No more passwords to try");
+ ssh_state = SSH_STATE_CLOSED;
+ crReturnV;
+ }
+ } else {
+ c_write("password: ", 10);
+ ssh_send_ok = 1;
+
+ pos = 0;
+ while (pos >= 0) {
+ crWaitUntilV(!ispkt);
+ while (inlen--) switch (c = *in++) {
+ case 10: case 13:
+ password[pos] = 0;
+ pos = -1;
+ break;
+ case 8: case 127:
+ if (pos > 0)
+ pos--;
+ break;
+ case 21: case 27:
+ pos = 0;
+ break;
+ case 3: case 4:
+ random_save_seed();
+ exit(0);
+ break;
+ default:
+ if (((c >= ' ' && c <= '~') ||
+ ((unsigned char)c >= 160)) && pos < 40)
+ password[pos++] = c;
+ break;
+ }
+ }
+ c_write("\r\n", 2);
+ }
+
+ ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);
+ ssh2_pkt_addstring(username);
+ ssh2_pkt_addstring("ssh-connection"); /* service requested */
+ ssh2_pkt_addstring("password");
+ ssh2_pkt_addbool(FALSE);
+ ssh2_pkt_addstring(password);
+ ssh2_pkt_send();
+
+ crWaitUntilV(ispkt);
+ if (pktin.type != SSH2_MSG_USERAUTH_SUCCESS) {
+ c_write("Access denied\r\n", 15);
+ logevent("Authentication refused");
+ } else
+ break;
+ }
+
+ /*
+ * Now we're authenticated for the connection protocol. The
+ * connection protocol will automatically have started at this
+ * point; there's no need to send SERVICE_REQUEST.
+ */
+
+ /*
+ * So now create a channel with a session in it.
+ */
+ mainchan = smalloc(sizeof(struct ssh_channel));
+ mainchan->localid = 100; /* as good as any */
+ ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN);
+ ssh2_pkt_addstring("session");
+ ssh2_pkt_adduint32(mainchan->localid);
+ ssh2_pkt_adduint32(0x8000UL); /* our window size */
+ ssh2_pkt_adduint32(0x4000UL); /* our max pkt size */
+ ssh2_pkt_send();
+ crWaitUntilV(ispkt);
+ if (pktin.type != SSH2_MSG_CHANNEL_OPEN_CONFIRMATION) {
+ bombout(("Server refused to open a session"));
+ crReturnV;
+ /* FIXME: error data comes back in FAILURE packet */
+ }
+ if (ssh2_pkt_getuint32() != mainchan->localid) {
+ bombout(("Server's channel confirmation cited wrong channel"));
+ crReturnV;
+ }
+ mainchan->remoteid = ssh2_pkt_getuint32();
+ mainchan->u.v2.remwindow = ssh2_pkt_getuint32();
+ mainchan->u.v2.remmaxpkt = ssh2_pkt_getuint32();
+ mainchan->u.v2.outbuffer = NULL;
+ mainchan->u.v2.outbuflen = mainchan->u.v2.outbufsize = 0;
+ logevent("Opened channel for session");
+
+ /*
+ * Now allocate a pty for the session.
+ */
+ if (!cfg.nopty) {
+ ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);
+ ssh2_pkt_adduint32(mainchan->remoteid); /* recipient channel */
+ ssh2_pkt_addstring("pty-req");
+ ssh2_pkt_addbool(1); /* want reply */
+ ssh2_pkt_addstring(cfg.termtype);
+ ssh2_pkt_adduint32(cols);
+ ssh2_pkt_adduint32(rows);
+ ssh2_pkt_adduint32(0); /* pixel width */
+ ssh2_pkt_adduint32(0); /* pixel height */
+ ssh2_pkt_addstring_start();
+ ssh2_pkt_addstring_data("\0", 1);/* TTY_OP_END, no special options */
+ ssh2_pkt_send();
+ ssh_state = SSH_STATE_INTERMED;
+
+ do {
+ crWaitUntilV(ispkt);
+ if (pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST) {
+ /* FIXME: be able to handle other channels here */
+ if (ssh2_pkt_getuint32() != mainchan->localid)
+ continue; /* wrong channel */
+ mainchan->u.v2.remwindow += ssh2_pkt_getuint32();
+ }
+ } while (pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST);
+
+ if (pktin.type != SSH2_MSG_CHANNEL_SUCCESS) {
+ if (pktin.type != SSH2_MSG_CHANNEL_FAILURE) {
+ bombout(("Server got confused by pty request"));
+ crReturnV;
+ }
+ c_write("Server refused to allocate pty\r\n", 32);
+ } else {
+ logevent("Allocated pty");
+ }
+ }
+
+ /*
+ * Start a shell or a remote command.
+ */
+ ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);
+ ssh2_pkt_adduint32(mainchan->remoteid); /* recipient channel */
+ if (*cfg.remote_cmd) {
+ ssh2_pkt_addstring("exec");
+ ssh2_pkt_addbool(1); /* want reply */
+ ssh2_pkt_addstring(cfg.remote_cmd);
+ } else {
+ ssh2_pkt_addstring("shell");
+ ssh2_pkt_addbool(1); /* want reply */
+ }
+ ssh2_pkt_send();
+ do {
+ crWaitUntilV(ispkt);
+ if (pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST) {
+ /* FIXME: be able to handle other channels here */
+ if (ssh2_pkt_getuint32() != mainchan->localid)
+ continue; /* wrong channel */
+ mainchan->u.v2.remwindow += ssh2_pkt_getuint32();
+ }
+ } while (pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST);
+ if (pktin.type != SSH2_MSG_CHANNEL_SUCCESS) {
+ if (pktin.type != SSH2_MSG_CHANNEL_FAILURE) {
+ bombout(("Server got confused by shell/command request"));
+ crReturnV;
+ }
+ bombout(("Server refused to start a shell/command"));
+ crReturnV;
+ } else {
+ logevent("Started a shell/command");
+ }
+
+ ssh_state = SSH_STATE_SESSION;
+ if (size_needed)
+ ssh_size();
+ if (eof_needed)
+ ssh_special(TS_EOF);
+
+ /*
+ * Transfer data!
+ */
+ ssh_send_ok = 1;
+ begin_session();
+ while (1) {
+ static int try_send;
+ crReturnV;
+ try_send = FALSE;
+ if (ispkt) {
+ if (pktin.type == SSH2_MSG_CHANNEL_DATA ||
+ pktin.type == SSH2_MSG_CHANNEL_EXTENDED_DATA) {
+ char *data;
+ int length;
+ /* FIXME: be able to handle other channels here */
+ if (ssh2_pkt_getuint32() != mainchan->localid)
+ continue; /* wrong channel */
+ if (pktin.type == SSH2_MSG_CHANNEL_EXTENDED_DATA &&
+ ssh2_pkt_getuint32() != SSH2_EXTENDED_DATA_STDERR)
+ continue; /* extended but not stderr */
+ ssh2_pkt_getstring(&data, &length);
+ if (data) {
+ from_backend(pktin.type == SSH2_MSG_CHANNEL_EXTENDED_DATA,
+ data, length);
+ /*
+ * Enlarge the window again at the remote side,
+ * just in case it ever runs down and they fail
+ * to send us any more data.
+ */
+ ssh2_pkt_init(SSH2_MSG_CHANNEL_WINDOW_ADJUST);
+ ssh2_pkt_adduint32(mainchan->remoteid);
+ ssh2_pkt_adduint32(length);
+ ssh2_pkt_send();
+ }
+ } else if (pktin.type == SSH2_MSG_DISCONNECT) {
+ ssh_state = SSH_STATE_CLOSED;
+ logevent("Received disconnect message");
+ crReturnV;
+ } else if (pktin.type == SSH2_MSG_CHANNEL_REQUEST) {
+ continue; /* exit status et al; ignore (FIXME?) */
+ } else if (pktin.type == SSH2_MSG_CHANNEL_EOF) {
+ continue; /* remote sends EOF; ignore */
+ } else if (pktin.type == SSH2_MSG_CHANNEL_CLOSE) {
+ /* FIXME: be able to handle other channels here */
+ if (ssh2_pkt_getuint32() != mainchan->localid)
+ continue; /* wrong channel */
+ ssh2_pkt_init(SSH2_MSG_CHANNEL_CLOSE);
+ ssh2_pkt_adduint32(mainchan->remoteid);
+ ssh2_pkt_send();
+ /* FIXME: mark the channel as closed */
+ if (1 /* FIXME: "all channels are closed" */) {
+ logevent("All channels closed. Disconnecting");
+ ssh2_pkt_init(SSH2_MSG_DISCONNECT);
+ ssh2_pkt_adduint32(SSH2_DISCONNECT_BY_APPLICATION);
+ ssh2_pkt_addstring("All open channels closed");
+ ssh2_pkt_addstring("en"); /* language tag */
+ ssh2_pkt_send();
+ ssh_state = SSH_STATE_CLOSED;
+ crReturnV;
+ }
+ continue; /* remote sends close; ignore (FIXME) */
+ } else if (pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST) {
+ /* FIXME: be able to handle other channels here */
+ if (ssh2_pkt_getuint32() != mainchan->localid)
+ continue; /* wrong channel */
+ mainchan->u.v2.remwindow += ssh2_pkt_getuint32();
+ try_send = TRUE;
+ } else {
+ bombout(("Strange packet received: type %d", pktin.type));
+ crReturnV;
+ }
+ } else {
+ /*
+ * We have spare data. Add it to the channel buffer.
+ */
+ if (mainchan->u.v2.outbufsize <
+ mainchan->u.v2.outbuflen + inlen) {
+ mainchan->u.v2.outbufsize =
+ mainchan->u.v2.outbuflen + inlen + 1024;
+ mainchan->u.v2.outbuffer = srealloc(mainchan->u.v2.outbuffer,
+ mainchan->u.v2.outbufsize);
+ }
+ memcpy(mainchan->u.v2.outbuffer + mainchan->u.v2.outbuflen,
+ in, inlen);
+ mainchan->u.v2.outbuflen += inlen;
+ try_send = TRUE;
+ }
+ if (try_send) {
+ /*
+ * Try to send data on the channel if we can. (FIXME:
+ * on _all_ channels.)
+ */
+ while (mainchan->u.v2.remwindow > 0 &&
+ mainchan->u.v2.outbuflen > 0) {
+ unsigned len = mainchan->u.v2.remwindow;
+ if (len > mainchan->u.v2.outbuflen)
+ len = mainchan->u.v2.outbuflen;
+ if (len > mainchan->u.v2.remmaxpkt)
+ len = mainchan->u.v2.remmaxpkt;
+ ssh2_pkt_init(SSH2_MSG_CHANNEL_DATA);
+ ssh2_pkt_adduint32(mainchan->remoteid);
+ ssh2_pkt_addstring_start();
+ ssh2_pkt_addstring_data(mainchan->u.v2.outbuffer, len);
+ ssh2_pkt_send();
+ mainchan->u.v2.outbuflen -= len;
+ memmove(mainchan->u.v2.outbuffer, mainchan->u.v2.outbuffer+len,
+ mainchan->u.v2.outbuflen);
+ mainchan->u.v2.remwindow -= len;
+ }
+ }