+ if (ssh->cscipher) {
+ int stringlen, i;
+
+ stringlen = (256 - ssh->deferred_len);
+ stringlen += ssh->cscipher->blksize - 1;
+ stringlen -= (stringlen % ssh->cscipher->blksize);
+ if (ssh->cscomp) {
+ /*
+ * Temporarily disable actual compression,
+ * so we can guarantee to get this string
+ * exactly the length we want it. The
+ * compression-disabling routine should
+ * return an integer indicating how many
+ * bytes we should adjust our string length
+ * by.
+ */
+ stringlen -=
+ ssh->cscomp->disable_compression(ssh->cs_comp_ctx);
+ }
+ s->pktout = ssh2_pkt_init(SSH2_MSG_IGNORE);
+ ssh2_pkt_addstring_start(s->pktout);
+ for (i = 0; i < stringlen; i++) {
+ char c = (char) random_byte();
+ ssh2_pkt_addstring_data(s->pktout, &c, 1);
+ }
+ ssh2_pkt_defer(ssh, s->pktout);
+ }
+ ssh_pkt_defersend(ssh);
+ logevent("Sent password");
+ s->type = AUTH_TYPE_PASSWORD;
+ } else if (s->method == AUTH_KEYBOARD_INTERACTIVE) {
+ if (s->curr_prompt == 0) {
+ s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_INFO_RESPONSE);
+ ssh2_pkt_adduint32(s->pktout, s->num_prompts);
+ }
+ if (s->need_pw) { /* only add pw if we just got one! */
+ dont_log_password(ssh, s->pktout, PKTLOG_BLANK);
+ ssh2_pkt_addstring(s->pktout, s->password);
+ memset(s->password, 0, sizeof(s->password));
+ end_log_omission(ssh, s->pktout);
+ s->curr_prompt++;
+ }
+ if (s->curr_prompt >= s->num_prompts) {
+ ssh2_pkt_send(ssh, s->pktout);
+ } else {
+ /*
+ * If there are prompts remaining, we set
+ * `gotit' so that we won't attempt to get
+ * another packet. Then we go back round the
+ * loop and will end up retrieving another
+ * prompt out of the existing packet. Funky or
+ * what?
+ */
+ s->gotit = TRUE;
+ }
+ s->type = AUTH_TYPE_KEYBOARD_INTERACTIVE;
+ } else {
+ c_write_str(ssh, "No supported authentication methods"
+ " left to try!\r\n");
+ logevent("No supported authentications offered."
+ " Disconnecting");
+ s->pktout = ssh2_pkt_init(SSH2_MSG_DISCONNECT);
+ ssh2_pkt_adduint32(s->pktout, SSH2_DISCONNECT_BY_APPLICATION);
+ ssh2_pkt_addstring(s->pktout, "No supported authentication"
+ " methods available");
+ ssh2_pkt_addstring(s->pktout, "en"); /* language tag */
+ ssh2_pkt_send_noqueue(ssh, s->pktout);
+ ssh_closing((Plug)ssh, NULL, 0, 0);
+ crStopV;
+ }
+ }
+ } while (!s->we_are_in);
+
+ /*
+ * 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.
+ */
+
+ ssh->channels = newtree234(ssh_channelcmp);
+
+ /*
+ * Set up handlers for some connection protocol messages, so we
+ * don't have to handle them repeatedly in this coroutine.
+ */
+ ssh->packet_dispatch[SSH2_MSG_CHANNEL_WINDOW_ADJUST] =
+ ssh2_msg_channel_window_adjust;
+ ssh->packet_dispatch[SSH2_MSG_GLOBAL_REQUEST] =
+ ssh2_msg_global_request;
+
+ /*
+ * Create the main session channel.
+ */
+ if (!ssh->cfg.ssh_no_shell) {
+ ssh->mainchan = snew(struct ssh_channel);
+ ssh->mainchan->ssh = ssh;
+ ssh->mainchan->localid = alloc_channel_id(ssh);
+ s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN);
+ ssh2_pkt_addstring(s->pktout, "session");
+ ssh2_pkt_adduint32(s->pktout, ssh->mainchan->localid);
+ ssh->mainchan->v.v2.locwindow = OUR_V2_WINSIZE;
+ ssh2_pkt_adduint32(s->pktout, ssh->mainchan->v.v2.locwindow);/* our window size */
+ ssh2_pkt_adduint32(s->pktout, 0x4000UL); /* our max pkt size */
+ ssh2_pkt_send(ssh, s->pktout);
+ crWaitUntilV(pktin);
+ if (pktin->type != SSH2_MSG_CHANNEL_OPEN_CONFIRMATION) {
+ bombout(("Server refused to open a session"));
+ crStopV;
+ /* FIXME: error data comes back in FAILURE packet */
+ }
+ if (ssh_pkt_getuint32(pktin) != ssh->mainchan->localid) {
+ bombout(("Server's channel confirmation cited wrong channel"));
+ crStopV;
+ }
+ ssh->mainchan->remoteid = ssh_pkt_getuint32(pktin);
+ ssh->mainchan->type = CHAN_MAINSESSION;
+ ssh->mainchan->closes = 0;
+ ssh->mainchan->v.v2.remwindow = ssh_pkt_getuint32(pktin);
+ ssh->mainchan->v.v2.remmaxpkt = ssh_pkt_getuint32(pktin);
+ bufchain_init(&ssh->mainchan->v.v2.outbuffer);
+ add234(ssh->channels, ssh->mainchan);
+ update_specials_menu(ssh->frontend);
+ logevent("Opened channel for session");
+ } else
+ ssh->mainchan = NULL;
+
+ /*
+ * Now we have a channel, make dispatch table entries for
+ * general channel-based messages.
+ */
+ ssh->packet_dispatch[SSH2_MSG_CHANNEL_DATA] =
+ ssh->packet_dispatch[SSH2_MSG_CHANNEL_EXTENDED_DATA] =
+ ssh2_msg_channel_data;
+ ssh->packet_dispatch[SSH2_MSG_CHANNEL_EOF] = ssh2_msg_channel_eof;
+ ssh->packet_dispatch[SSH2_MSG_CHANNEL_CLOSE] = ssh2_msg_channel_close;
+ ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_CONFIRMATION] =
+ ssh2_msg_channel_open_confirmation;
+ ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_FAILURE] =
+ ssh2_msg_channel_open_failure;
+ ssh->packet_dispatch[SSH2_MSG_CHANNEL_REQUEST] =
+ ssh2_msg_channel_request;
+ ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN] =
+ ssh2_msg_channel_open;
+
+ /*
+ * Potentially enable X11 forwarding.
+ */
+ if (ssh->mainchan && ssh->cfg.x11_forward) {
+ char proto[20], data[64];
+ 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, data);
+ ssh2_pkt_adduint32(s->pktout, x11_get_screen_number(ssh->cfg.x11_display));
+ ssh2_pkt_send(ssh, s->pktout);
+
+ crWaitUntilV(pktin);
+
+ if (pktin->type != SSH2_MSG_CHANNEL_SUCCESS) {
+ if (pktin->type != SSH2_MSG_CHANNEL_FAILURE) {
+ bombout(("Unexpected response to X11 forwarding request:"
+ " packet type %d", pktin->type));
+ crStopV;
+ }
+ logevent("X11 forwarding refused");
+ } else {
+ logevent("X11 forwarding enabled");
+ ssh->X11_fwd_enabled = TRUE;
+ }
+ }
+
+ /*
+ * Enable port forwardings.
+ */
+ {
+ char type;
+ int n;
+ int sport,dport,sserv,dserv;
+ char sports[256], dports[256], saddr[256], host[256];
+
+ ssh->rportfwds = newtree234(ssh_rportcmp_ssh2);
+ /* Add port forwardings. */
+ ssh->portfwd_strptr = ssh->cfg.portfwd;
+ while (*ssh->portfwd_strptr) {
+ type = *ssh->portfwd_strptr++;
+ saddr[0] = '\0';
+ n = 0;
+ while (*ssh->portfwd_strptr && *ssh->portfwd_strptr != '\t') {
+ if (*ssh->portfwd_strptr == ':') {
+ /*
+ * We've seen a colon in the middle of the
+ * source port number. This means that
+ * everything we've seen until now is the
+ * source _address_, so we'll move it into
+ * saddr and start sports from the beginning
+ * again.
+ */
+ ssh->portfwd_strptr++;
+ sports[n] = '\0';
+ strcpy(saddr, sports);
+ n = 0;
+ }
+ if (n < 255) sports[n++] = *ssh->portfwd_strptr++;
+ }
+ sports[n] = 0;
+ if (type != 'D') {
+ if (*ssh->portfwd_strptr == '\t')
+ ssh->portfwd_strptr++;
+ n = 0;
+ while (*ssh->portfwd_strptr && *ssh->portfwd_strptr != ':') {
+ if (n < 255) host[n++] = *ssh->portfwd_strptr++;
+ }
+ host[n] = 0;
+ if (*ssh->portfwd_strptr == ':')
+ ssh->portfwd_strptr++;
+ n = 0;
+ while (*ssh->portfwd_strptr) {
+ if (n < 255) dports[n++] = *ssh->portfwd_strptr++;
+ }
+ dports[n] = 0;
+ ssh->portfwd_strptr++;
+ dport = atoi(dports);
+ dserv = 0;
+ if (dport == 0) {
+ dserv = 1;
+ dport = net_service_lookup(dports);
+ if (!dport) {
+ logeventf(ssh, "Service lookup failed for destination"
+ " port \"%s\"", dports);
+ }
+ }
+ } else {
+ while (*ssh->portfwd_strptr) ssh->portfwd_strptr++;
+ dport = dserv = -1;
+ ssh->portfwd_strptr++; /* eat the NUL and move to next one */
+ }
+ sport = atoi(sports);
+ sserv = 0;
+ if (sport == 0) {
+ sserv = 1;
+ sport = net_service_lookup(sports);
+ if (!sport) {
+ logeventf(ssh, "Service lookup failed for source"
+ " port \"%s\"", sports);
+ }
+ }
+ if (sport && dport) {
+ /* Set up a description of the source port. */
+ static char *sportdesc;
+ sportdesc = dupprintf("%.*s%.*s%.*s%.*s%d%.*s",
+ (int)(*saddr?strlen(saddr):0), *saddr?saddr:NULL,
+ (int)(*saddr?1:0), ":",
+ (int)(sserv ? strlen(sports) : 0), sports,
+ sserv, "(", sport, sserv, ")");
+ if (type == 'L') {
+ /* Verbose description of the destination port */
+ char *dportdesc = dupprintf("%s:%.*s%.*s%d%.*s",
+ host,
+ (int)(dserv ? strlen(dports) : 0), dports,
+ dserv, "(", dport, dserv, ")");
+ const char *err = pfd_addforward(host, dport,
+ *saddr ? saddr : NULL,
+ sport, ssh, &ssh->cfg);
+ if (err) {
+ logeventf(ssh, "Local port %s forward to %s"
+ " failed: %s", sportdesc, dportdesc, err);
+ } else {
+ logeventf(ssh, "Local port %s forwarding to %s",
+ sportdesc, dportdesc);
+ }
+ sfree(dportdesc);
+ } else if (type == 'D') {
+ const char *err = pfd_addforward(NULL, -1,
+ *saddr ? saddr : NULL,
+ sport, ssh, &ssh->cfg);
+ if (err) {
+ logeventf(ssh, "Local port %s SOCKS dynamic forward"
+ " setup failed: %s", sportdesc, err);
+ } else {
+ logeventf(ssh, "Local port %s doing SOCKS"
+ " dynamic forwarding", sportdesc);
+ }
+ } else {
+ struct ssh_rportfwd *pf;
+ pf = snew(struct ssh_rportfwd);
+ strcpy(pf->dhost, host);
+ pf->dport = dport;
+ pf->sport = sport;
+ if (add234(ssh->rportfwds, pf) != pf) {
+ logeventf(ssh, "Duplicate remote port forwarding"
+ " to %s:%d", host, dport);
+ sfree(pf);
+ } else {
+ logeventf(ssh, "Requesting remote port %s"
+ " forward to %s:%.*s%.*s%d%.*s",
+ sportdesc,
+ host,
+ (int)(dserv ? strlen(dports) : 0), dports,
+ dserv, "(", dport, dserv, ")");
+ s->pktout = ssh2_pkt_init(SSH2_MSG_GLOBAL_REQUEST);
+ ssh2_pkt_addstring(s->pktout, "tcpip-forward");
+ ssh2_pkt_addbool(s->pktout, 1);/* want reply */
+ if (*saddr) {
+ ssh2_pkt_addstring(s->pktout, saddr);
+ } else if (ssh->cfg.rport_acceptall) {
+ ssh2_pkt_addstring(s->pktout, "0.0.0.0");
+ } else {
+ ssh2_pkt_addstring(s->pktout, "127.0.0.1");
+ }
+ ssh2_pkt_adduint32(s->pktout, sport);
+ ssh2_pkt_send(ssh, s->pktout);
+
+ crWaitUntilV(pktin);
+
+ if (pktin->type != SSH2_MSG_REQUEST_SUCCESS) {
+ if (pktin->type != SSH2_MSG_REQUEST_FAILURE) {
+ bombout(("Unexpected response to port "
+ "forwarding request: packet type %d",
+ pktin->type));
+ crStopV;
+ }
+ logevent("Server refused this port forwarding");
+ } else {
+ logevent("Remote port forwarding enabled");