} else if (pktin.type == SSH2_MSG_CHANNEL_OPEN_FAILURE) { unsigned i = ssh2_pkt_getuint32(); struct ssh_channel *c; c = find234(ssh_channels, &i, ssh_channelfind); if (!c) continue;	        if (c->type != CHAN_SOCKDATA_DORMANT) continue;	         logevent("Forwarded connection refused by server");  pfd_close(c->u.pfd.s);  del234(ssh_channels, c); sfree(c);
static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt){    static enum {	AUTH_INVALID, AUTH_PUBLICKEY_AGENT, AUTH_PUBLICKEY_FILE,	AUTH_PASSWORD,        AUTH_KEYBOARD_INTERACTIVE    } method;    static enum {	AUTH_TYPE_NONE,	AUTH_TYPE_PUBLICKEY,	AUTH_TYPE_PUBLICKEY_OFFER_LOUD,	AUTH_TYPE_PUBLICKEY_OFFER_QUIET,	AUTH_TYPE_PASSWORD,	AUTH_TYPE_KEYBOARD_INTERACTIVE,	AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET    } type;    static int gotit, need_pw, can_pubkey, can_passwd, can_keyb_inter;    static int tried_pubkey_config, tried_agent, tried_keyb_inter;    static int kbd_inter_running;    static int we_are_in;    static int num_prompts, echo;    static char username[100];    static char pwprompt[200];    static char password[100];    crBegin;    /*     * Request userauth protocol, and await a response to it.     */    ssh2_pkt_init(SSH2_MSG_SERVICE_REQUEST);    ssh2_pkt_addstring("ssh-userauth");    ssh2_pkt_send();    crWaitUntilV(ispkt);    if (pktin.type != SSH2_MSG_SERVICE_ACCEPT) {	bombout(("Server refused user authentication protocol"));	crReturnV;    }    /*     * We repeat this whole loop, including the username prompt,     * until we manage a successful authentication. If the user     * types the wrong _password_, they are sent back to the     * beginning to try another username. (If they specify a     * username in the config, they are never asked, even if they     * do give a wrong password.)     *      * I think this best serves the needs of     *      *  - the people who have no configuration, no keys, and just     *    want to try repeated (username,password) pairs until they     *    type both correctly     *      *  - people who have keys and configuration but occasionally     *    need to fall back to passwords     *      *  - people with a key held in Pageant, who might not have     *    logged in to a particular machine before; so they want to     *    type a username, and then _either_ their key will be     *    accepted, _or_ they will type a password. If they mistype     *    the username they will want to be able to get back and     *    retype it!     */    do {	static int pos;	static char c;	/*	 * Get a username.	 */	pos = 0;	if ((flags & FLAG_INTERACTIVE) && !*cfg.username) {	    if (ssh_get_line) {		if (!ssh_get_line("login as: ",				  username, sizeof(username), FALSE)) {		    /*		     * get_line failed to get a username.		     * Terminate.		     */		    logevent("No username provided. Abandoning session.");		    ssh_state = SSH_STATE_CLOSED;		    crReturnV;		}	    } else {		c_write_str("login as: ");		ssh_send_ok = 1;		while (pos >= 0) {		    crWaitUntilV(!ispkt);		    while (inlen--)			switch (c = *in++) {			  case 10:			  case 13:			    username[pos] = 0;			    pos = -1;			    break;			  case 8:			  case 127:			    if (pos > 0) {				c_write_str("\b \b");				pos--;			    }			    break;			  case 21:			  case 27:			    while (pos > 0) {				c_write_str("\b \b");				pos--;			    }			    break;			  case 3:			  case 4:			    random_save_seed();			    exit(0);			    break;			  default:			    if (((c >= ' ' && c <= '~') ||				 ((unsigned char) c >= 160))				&& pos < sizeof(username)-1) {				username[pos++] = c;				c_write(&c, 1);			    }			    break;			}		}	    }	    c_write_str("\r\n");	    username[strcspn(username, "\n\r")] = '\0';	} else {	    char stuff[200];	    strncpy(username, cfg.username, 99);	    username[99] = '\0';	    if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE)) {		sprintf(stuff, "Using username \"%s\".\r\n", username);		c_write_str(stuff);	    }	}	/*	 * Send an authentication request using method "none": (a)	 * just in case it succeeds, and (b) so that we know what	 * authentication methods we can usefully try next.	 */	ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);	ssh2_pkt_addstring(username);	ssh2_pkt_addstring("ssh-connection");	/* service requested */	ssh2_pkt_addstring("none");    /* method */	ssh2_pkt_send();	type = AUTH_TYPE_NONE;	gotit = FALSE;	we_are_in = FALSE;	tried_pubkey_config = FALSE;	tried_agent = FALSE;	tried_keyb_inter = FALSE;	kbd_inter_running = FALSE;	while (1) {	    /*	     * Wait for the result of the last authentication request.	     */	    if (!gotit)		crWaitUntilV(ispkt);	    while (pktin.type == SSH2_MSG_USERAUTH_BANNER) {		char *banner;		int size;		/*		 * Don't show the banner if we're operating in		 * non-verbose non-interactive mode. (It's probably		 * a script, which means nobody will read the		 * banner _anyway_, and moreover the printing of		 * the banner will screw up processing on the		 * output of (say) plink.)		 */		if (flags & (FLAG_VERBOSE | FLAG_INTERACTIVE)) {		    ssh2_pkt_getstring(&banner, &size);		    if (banner)			c_write_untrusted(banner, size);		}		crWaitUntilV(ispkt);	    }	    if (pktin.type == SSH2_MSG_USERAUTH_SUCCESS) {		logevent("Access granted");		we_are_in = TRUE;		break;	    }	    if (kbd_inter_running &&		pktin.type == SSH2_MSG_USERAUTH_INFO_REQUEST) {		/*		 * This is a further prompt in keyboard-interactive		 * authentication. Do nothing.		 */	    } else if (pktin.type != SSH2_MSG_USERAUTH_FAILURE) {		bombout(("Strange packet received during authentication: type %d",			 pktin.type));		crReturnV;	    }	    gotit = FALSE;	    /*	     * OK, we're now sitting on a USERAUTH_FAILURE message, so	     * we can look at the string in it and know what we can	     * helpfully try next.	     */	    if (pktin.type == SSH2_MSG_USERAUTH_FAILURE) {		char *methods;		int methlen;		ssh2_pkt_getstring(&methods, &methlen);		kbd_inter_running = FALSE;		if (!ssh2_pkt_getbool()) {		    /*		     * We have received an unequivocal Access		     * Denied. This can translate to a variety of		     * messages:		     * 		     *  - if we'd just tried "none" authentication,		     *    it's not worth printing anything at all		     * 		     *  - if we'd just tried a public key _offer_,		     *    the message should be "Server refused our		     *    key" (or no message at all if the key		     *    came from Pageant)		     * 		     *  - if we'd just tried anything else, the		     *    message really should be "Access denied".		     * 		     * Additionally, if we'd just tried password		     * authentication, we should break out of this		     * whole loop so as to go back to the username		     * prompt.		     */		    if (type == AUTH_TYPE_NONE) {			/* do nothing */		    } else if (type == AUTH_TYPE_PUBLICKEY_OFFER_LOUD ||			       type == AUTH_TYPE_PUBLICKEY_OFFER_QUIET) {			if (type == AUTH_TYPE_PUBLICKEY_OFFER_LOUD)			    c_write_str("Server refused our key\r\n");			logevent("Server refused public key");		    } else if (type == AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET) {			/* server declined keyboard-interactive; ignore */		    } else {			c_write_str("Access denied\r\n");			logevent("Access denied");			if (type == AUTH_TYPE_PASSWORD) {			    we_are_in = FALSE;			    break;			}		    }		} else {		    c_write_str("Further authentication required\r\n");		    logevent("Further authentication required");		}		can_pubkey =		    in_commasep_string("publickey", methods, methlen);		can_passwd =		    in_commasep_string("password", methods, methlen);		can_passwd =		    in_commasep_string("password", methods, methlen);		can_keyb_inter = 		    in_commasep_string("keyboard-interactive", methods, methlen);	    }	    method = 0;	    if (!method && can_keyb_inter && !tried_keyb_inter) {		method = AUTH_KEYBOARD_INTERACTIVE;		type = AUTH_TYPE_KEYBOARD_INTERACTIVE;		tried_keyb_inter = TRUE;		ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);		ssh2_pkt_addstring(username);		ssh2_pkt_addstring("ssh-connection");	/* service requested */		ssh2_pkt_addstring("keyboard-interactive");	/* method */		ssh2_pkt_addstring(""); /* lang */		ssh2_pkt_addstring("");		ssh2_pkt_send();		crWaitUntilV(ispkt);		if (pktin.type != SSH2_MSG_USERAUTH_INFO_REQUEST) {		    if (pktin.type == SSH2_MSG_USERAUTH_FAILURE)			gotit = TRUE;		    logevent("Keyboard-interactive authentication refused");		    type = AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET;		    continue;		}		kbd_inter_running = TRUE;	    }	    if (kbd_inter_running) {		method = AUTH_KEYBOARD_INTERACTIVE;		type = AUTH_TYPE_KEYBOARD_INTERACTIVE;		tried_keyb_inter = TRUE;		/* We've got packet with that "interactive" info		   dump banners, and set its prompt as ours */		{		    char *name, *inst, *lang, *prompt;		    int name_len, inst_len, lang_len, prompt_len;		    ssh2_pkt_getstring(&name, &name_len);		    ssh2_pkt_getstring(&inst, &inst_len);		    ssh2_pkt_getstring(&lang, &lang_len);		    if (name_len > 0)			c_write_untrusted(name, name_len);		    if (inst_len > 0)			c_write_untrusted(inst, inst_len);		    num_prompts = ssh2_pkt_getuint32();		    ssh2_pkt_getstring(&prompt, &prompt_len);		    strncpy(pwprompt, prompt, sizeof(pwprompt));		    need_pw = TRUE;		    echo = ssh2_pkt_getbool();		}	    }	    if (!method && can_pubkey && agent_exists() && !tried_agent) {		/*		 * Attempt public-key authentication using Pageant.		 */		static unsigned char request[5], *response, *p;		static int responselen;		static int i, nkeys;		static int authed = FALSE;		void *r;		tried_agent = TRUE;		logevent("Pageant is running. Requesting keys.");		/* Request the keys held by the agent. */		PUT_32BIT(request, 1);		request[4] = SSH2_AGENTC_REQUEST_IDENTITIES;		agent_query(request, 5, &r, &responselen);		response = (unsigned char *) r;		if (response && responselen >= 5 &&		    response[4] == SSH2_AGENT_IDENTITIES_ANSWER) {		    p = response + 5;		    nkeys = GET_32BIT(p);		    p += 4;		    {			char buf[64];			sprintf(buf, "Pageant has %d SSH2 keys", nkeys);			logevent(buf);		    }		    for (i = 0; i < nkeys; i++) {			static char *pkblob, *alg, *commentp;			static int pklen, alglen, commentlen;			static int siglen, retlen, len;			static char *q, *agentreq, *ret;			void *vret;			{			    char buf[64];			    sprintf(buf, "Trying Pageant key #%d", i);			    logevent(buf);			}			pklen = GET_32BIT(p);			p += 4;			pkblob = p;			p += pklen;			alglen = GET_32BIT(pkblob);			alg = pkblob + 4;			commentlen = GET_32BIT(p);			p += 4;			commentp = p;			p += commentlen;			ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);			ssh2_pkt_addstring(username);			ssh2_pkt_addstring("ssh-connection");	/* service requested */			ssh2_pkt_addstring("publickey");	/* method */			ssh2_pkt_addbool(FALSE);	/* no signature included */			ssh2_pkt_addstring_start();			ssh2_pkt_addstring_data(alg, alglen);			ssh2_pkt_addstring_start();			ssh2_pkt_addstring_data(pkblob, pklen);			ssh2_pkt_send();			crWaitUntilV(ispkt);			if (pktin.type != SSH2_MSG_USERAUTH_PK_OK) {			    logevent("Key refused");			    continue;			}			if (flags & FLAG_VERBOSE) {			    c_write_str				("Authenticating with public key \"");			    c_write(commentp, commentlen);			    c_write_str("\" from agent\r\n");			}			/*			 * Server is willing to accept the key.			 * Construct a SIGN_REQUEST.			 */			ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);			ssh2_pkt_addstring(username);			ssh2_pkt_addstring("ssh-connection");	/* service requested */			ssh2_pkt_addstring("publickey");	/* method */			ssh2_pkt_addbool(TRUE);			ssh2_pkt_addstring_start();			ssh2_pkt_addstring_data(alg, alglen);			ssh2_pkt_addstring_start();			ssh2_pkt_addstring_data(pkblob, pklen);			siglen = pktout.length - 5 + 4 + 20;			len = 1;       /* message type */			len += 4 + pklen;	/* key blob */			len += 4 + siglen;	/* data to sign */			len += 4;      /* flags */			agentreq = smalloc(4 + len);			PUT_32BIT(agentreq, len);			q = agentreq + 4;			*q++ = SSH2_AGENTC_SIGN_REQUEST;			PUT_32BIT(q, pklen);			q += 4;			memcpy(q, pkblob, pklen);			q += pklen;			PUT_32BIT(q, siglen);			q += 4;			/* Now the data to be signed... */			PUT_32BIT(q, 20);			q += 4;			memcpy(q, ssh2_session_id, 20);			q += 20;			memcpy(q, pktout.data + 5, pktout.length - 5);			q += pktout.length - 5;			/* And finally the (zero) flags word. */			PUT_32BIT(q, 0);			agent_query(agentreq, len + 4, &vret, &retlen);			ret = vret;			sfree(agentreq);			if (ret) {			    if (ret[4] == SSH2_AGENT_SIGN_RESPONSE) {				logevent("Sending Pageant's response");				ssh2_pkt_addstring_start();				ssh2_pkt_addstring_data(ret + 9,							GET_32BIT(ret +								  5));				ssh2_pkt_send();				authed = TRUE;				break;			    } else {				logevent				    ("Pageant failed to answer challenge");				sfree(ret);			    }			}		    }		    if (authed)			continue;		}	    }	    if (!method && can_pubkey && *cfg.keyfile		&& !tried_pubkey_config) {		unsigned char *pub_blob;		char *algorithm, *comment;		int pub_blob_len;		tried_pubkey_config = TRUE;		/*		 * Try the public key supplied in the configuration.		 *		 * First, offer the public blob to see if the server is		 * willing to accept it.		 */		pub_blob = ssh2_userkey_loadpub(cfg.keyfile, &algorithm,						&pub_blob_len);		if (pub_blob) {		    ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);		    ssh2_pkt_addstring(username);		    ssh2_pkt_addstring("ssh-connection");	/* service requested */		    ssh2_pkt_addstring("publickey");	/* method */		    ssh2_pkt_addbool(FALSE);	/* no signature included */		    ssh2_pkt_addstring(algorithm);		    ssh2_pkt_addstring_start();		    ssh2_pkt_addstring_data(pub_blob, pub_blob_len);		    ssh2_pkt_send();		    logevent("Offered public key");	/* FIXME */		    crWaitUntilV(ispkt);		    if (pktin.type != SSH2_MSG_USERAUTH_PK_OK) {			gotit = TRUE;			type = AUTH_TYPE_PUBLICKEY_OFFER_LOUD;			continue;      /* key refused; give up on it */		    }		    logevent("Offer of public key accepted");		    /*		     * Actually attempt a serious authentication using		     * the key.		     */		    if (ssh2_userkey_encrypted(cfg.keyfile, &comment)) {			sprintf(pwprompt,				"Passphrase for key \"%.100s\": ",				comment);			need_pw = TRUE;		    } else {			need_pw = FALSE;		    }		    c_write_str("Authenticating with public key \"");		    c_write_str(comment);		    c_write_str("\"\r\n");		    method = AUTH_PUBLICKEY_FILE;		}	    }	    if (!method && can_passwd) {		method = AUTH_PASSWORD;		sprintf(pwprompt, "%.90s@%.90s's password: ", username,			savedhost);		need_pw = TRUE;	    }	    if (need_pw) {		if (ssh_get_line) {		    if (!ssh_get_line(pwprompt, password,				      sizeof(password), TRUE)) {			/*			 * get_line failed to get a password (for			 * example because one was supplied on the			 * command line which has already failed to			 * work). Terminate.			 */			ssh2_pkt_init(SSH2_MSG_DISCONNECT);			ssh2_pkt_adduint32(SSH2_DISCONNECT_BY_APPLICATION);			ssh2_pkt_addstring			    ("No more passwords available to try");			ssh2_pkt_addstring("en");	/* language tag */			ssh2_pkt_send();			connection_fatal("Unable to authenticate");			ssh_state = SSH_STATE_CLOSED;			crReturnV;		    }		} else {		    static int pos = 0;		    static char c;		    c_write_untrusted(pwprompt, strlen(pwprompt));		    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 (pos < sizeof(password)-1)				    password[pos++] = c;				break;			    }		    }		    c_write_str("\r\n");		}	    }	    if (method == AUTH_PUBLICKEY_FILE) {		/*		 * We have our passphrase. Now try the actual authentication.		 */		struct ssh2_userkey *key;		key = ssh2_load_userkey(cfg.keyfile, password);		if (key == SSH2_WRONG_PASSPHRASE || key == NULL) {		    if (key == SSH2_WRONG_PASSPHRASE) {			c_write_str("Wrong passphrase\r\n");			tried_pubkey_config = FALSE;		    } else {			c_write_str("Unable to load private key\r\n");			tried_pubkey_config = TRUE;		    }		    /* Send a spurious AUTH_NONE to return to the top. */		    ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);		    ssh2_pkt_addstring(username);		    ssh2_pkt_addstring("ssh-connection");	/* service requested */		    ssh2_pkt_addstring("none");	/* method */		    ssh2_pkt_send();		    type = AUTH_TYPE_NONE;		} else {		    unsigned char *blob, *sigdata;		    int blob_len, sigdata_len;		    /*		     * We have loaded the private key and the server		     * has announced that it's willing to accept it.		     * Hallelujah. Generate a signature and send it.		     */		    ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);		    ssh2_pkt_addstring(username);		    ssh2_pkt_addstring("ssh-connection");	/* service requested */		    ssh2_pkt_addstring("publickey");	/* method */		    ssh2_pkt_addbool(TRUE);		    ssh2_pkt_addstring(key->alg->name);		    blob = key->alg->public_blob(key->data, &blob_len);		    ssh2_pkt_addstring_start();		    ssh2_pkt_addstring_data(blob, blob_len);		    sfree(blob);		    /*		     * The data to be signed is:		     *		     *   string  session-id		     *		     * followed by everything so far placed in the		     * outgoing packet.		     */		    sigdata_len = pktout.length - 5 + 4 + 20;		    sigdata = smalloc(sigdata_len);		    PUT_32BIT(sigdata, 20);		    memcpy(sigdata + 4, ssh2_session_id, 20);		    memcpy(sigdata + 24, pktout.data + 5,			   pktout.length - 5);		    blob =			key->alg->sign(key->data, sigdata, sigdata_len,				       &blob_len);		    ssh2_pkt_addstring_start();		    ssh2_pkt_addstring_data(blob, blob_len);		    sfree(blob);		    sfree(sigdata);		    ssh2_pkt_send();		    type = AUTH_TYPE_PUBLICKEY;		}	    } else if (method == AUTH_PASSWORD) {		/*		 * We send the password packet lumped tightly together with		 * an SSH_MSG_IGNORE packet. The IGNORE packet contains a		 * string long enough to make the total length of the two		 * packets constant. This should ensure that a passive		 * listener doing traffic analyis can't work out the length		 * of the password.		 *		 * For this to work, we need an assumption about the		 * maximum length of the password packet. I think 256 is		 * pretty conservative. Anyone using a password longer than		 * that probably doesn't have much to worry about from		 * people who find out how long their password is!		 */		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_defer();		/*		 * We'll include a string that's an exact multiple of the		 * cipher block size. If the cipher is NULL for some		 * reason, we don't do this trick at all because we gain		 * nothing by it.		 */		if (cscipher) {		    int stringlen, i;		    stringlen = (256 - deferred_len);		    stringlen += cscipher->blksize - 1;		    stringlen -= (stringlen % cscipher->blksize);		    if (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 -= cscomp->disable_compression();		    }		    ssh2_pkt_init(SSH2_MSG_IGNORE);		    ssh2_pkt_addstring_start();		    for (i = 0; i < stringlen; i++) {			char c = (char) random_byte();			ssh2_pkt_addstring_data(&c, 1);		    }		    ssh2_pkt_defer();		}		ssh_pkt_defersend();		logevent("Sent password");		type = AUTH_TYPE_PASSWORD;	    } else if (method == AUTH_KEYBOARD_INTERACTIVE) {                ssh2_pkt_init(SSH2_MSG_USERAUTH_INFO_RESPONSE);                ssh2_pkt_adduint32(num_prompts);                ssh2_pkt_addstring(password);                memset(password, 0, sizeof(password));                ssh2_pkt_send();		type = AUTH_TYPE_KEYBOARD_INTERACTIVE;	    } else {		c_write_str		    ("No supported authentication methods left to try!\r\n");		logevent		    ("No supported authentications offered. Disconnecting");		ssh2_pkt_init(SSH2_MSG_DISCONNECT);		ssh2_pkt_adduint32(SSH2_DISCONNECT_BY_APPLICATION);		ssh2_pkt_addstring		    ("No supported authentication methods available");		ssh2_pkt_addstring("en");	/* language tag */		ssh2_pkt_send();		ssh_state = SSH_STATE_CLOSED;		crReturnV;	    }	}    } while (!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.     */    /*     * So now create a channel with a session in it.     */    ssh_channels = newtree234(ssh_channelcmp);    mainchan = smalloc(sizeof(struct ssh_channel));    mainchan->localid = alloc_channel_id();    ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN);    ssh2_pkt_addstring("session");    ssh2_pkt_adduint32(mainchan->localid);    mainchan->v.v2.locwindow = OUR_V2_WINSIZE;    ssh2_pkt_adduint32(mainchan->v.v2.locwindow);      /* 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->type = CHAN_MAINSESSION;    mainchan->closes = 0;    mainchan->v.v2.remwindow = ssh2_pkt_getuint32();    mainchan->v.v2.remmaxpkt = ssh2_pkt_getuint32();    bufchain_init(&mainchan->v.v2.outbuffer);    add234(ssh_channels, mainchan);    logevent("Opened channel for session");    /*     * Potentially enable X11 forwarding.     */    if (cfg.x11_forward) {	char proto[20], data[64];	logevent("Requesting X11 forwarding");	x11_invent_auth(proto, sizeof(proto), data, sizeof(data));	ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);	ssh2_pkt_adduint32(mainchan->remoteid);	ssh2_pkt_addstring("x11-req");	ssh2_pkt_addbool(1);	       /* want reply */	ssh2_pkt_addbool(0);	       /* many connections */	ssh2_pkt_addstring(proto);	ssh2_pkt_addstring(data);	ssh2_pkt_adduint32(0);	       /* screen number */	ssh2_pkt_send();	do {	    crWaitUntilV(ispkt);	    if (pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST) {		unsigned i = ssh2_pkt_getuint32();		struct ssh_channel *c;		c = find234(ssh_channels, &i, ssh_channelfind);		if (!c)		    continue;	       /* nonexistent channel */		c->v.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 X11 forwarding request"));		crReturnV;	    }	    logevent("X11 forwarding refused");	} else {	    logevent("X11 forwarding enabled");	    ssh_X11_fwd_enabled = TRUE;	}    }    /*     * Enable port forwardings.     */    {	static char *e;		       /* preserve across crReturn */	char type;	int n;	int sport,dport;	char sports[256], dports[256], host[256];	char buf[1024];	ssh_rportfwds = newtree234(ssh_rportcmp_ssh2);        /* Add port forwardings. */	e = cfg.portfwd;	while (*e) {	    type = *e++;	    n = 0;	    while (*e && *e != '\t')		sports[n++] = *e++;	    sports[n] = 0;	    if (*e == '\t')		e++;	    n = 0;	    while (*e && *e != ':')		host[n++] = *e++;	    host[n] = 0;	    if (*e == ':')		e++;	    n = 0;	    while (*e)		dports[n++] = *e++;	    dports[n] = 0;	    e++;	    dport = atoi(dports);	    sport = atoi(sports);	    if (sport && dport) {		if (type == 'L') {		    pfd_addforward(host, dport, sport);		    sprintf(buf, "Local port %d forwarding to %s:%d",			    sport, host, dport);		    logevent(buf);		} else {		    struct ssh_rportfwd *pf;		    pf = smalloc(sizeof(*pf));		    strcpy(pf->dhost, host);		    pf->dport = dport;		    pf->sport = sport;		    if (add234(ssh_rportfwds, pf) != pf) {			sprintf(buf, 				"Duplicate remote port forwarding to %s:%d",				host, dport);			logevent(buf);			sfree(pf);		    } else {			sprintf(buf, "Requesting remote port %d (forwarded to %s:%d)",				sport, host, dport);			logevent(buf);			ssh2_pkt_init(SSH2_MSG_GLOBAL_REQUEST);			ssh2_pkt_addstring("tcpip-forward");			ssh2_pkt_addbool(1);/* want reply */			ssh2_pkt_addstring("127.0.0.1");			ssh2_pkt_adduint32(sport);			ssh2_pkt_send();			do {			    crWaitUntilV(ispkt);			    if (pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST) {				unsigned i = ssh2_pkt_getuint32();				struct ssh_channel *c;				c = find234(ssh_channels, &i, ssh_channelfind);				if (!c)				    continue;/* nonexistent channel */				c->v.v2.remwindow += ssh2_pkt_getuint32();			    }			} while (pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST);			if (pktin.type != SSH2_MSG_REQUEST_SUCCESS) {			    if (pktin.type != SSH2_MSG_REQUEST_FAILURE) {				bombout(("Server got confused by port forwarding request"));				crReturnV;			    }			    logevent("Server refused this port forwarding");			} else {			    logevent("Remote port forwarding enabled");			}		    }		}	    }	}    }    /*     * Potentially enable agent forwarding.     */    if (cfg.agentfwd && agent_exists()) {	logevent("Requesting OpenSSH-style agent forwarding");	ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);	ssh2_pkt_adduint32(mainchan->remoteid);	ssh2_pkt_addstring("auth-agent-req@openssh.com");	ssh2_pkt_addbool(1);	       /* want reply */	ssh2_pkt_send();	do {	    crWaitUntilV(ispkt);	    if (pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST) {		unsigned i = ssh2_pkt_getuint32();		struct ssh_channel *c;		c = find234(ssh_channels, &i, ssh_channelfind);		if (!c)		    continue;	       /* nonexistent channel */		c->v.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 agent forwarding request"));		crReturnV;	    }	    logevent("Agent forwarding refused");	} else {	    logevent("Agent forwarding enabled");	    ssh_agentfwd_enabled = TRUE;	}    }    /*     * 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) {		unsigned i = ssh2_pkt_getuint32();		struct ssh_channel *c;		c = find234(ssh_channels, &i, ssh_channelfind);		if (!c)		    continue;	       /* nonexistent channel */		c->v.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_str("Server refused to allocate pty\r\n");	    ssh_editing = ssh_echoing = 1;	} else {	    logevent("Allocated pty");	}    } else {	ssh_editing = ssh_echoing = 1;    }    /*     * Start a shell or a remote command. We may have to attempt     * this twice if the config data has provided a second choice     * of command.     */    while (1) {	int subsys;	char *cmd;	if (ssh_fallback_cmd) {	    subsys = cfg.ssh_subsys2;	    cmd = cfg.remote_cmd_ptr2;	} else {	    subsys = cfg.ssh_subsys;	    cmd = cfg.remote_cmd_ptr;	}	ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);	ssh2_pkt_adduint32(mainchan->remoteid);	/* recipient channel */	if (subsys) {	    ssh2_pkt_addstring("subsystem");	    ssh2_pkt_addbool(1);	       /* want reply */	    ssh2_pkt_addstring(cmd);	} else if (*cmd) {	    ssh2_pkt_addstring("exec");	    ssh2_pkt_addbool(1);	       /* want reply */	    ssh2_pkt_addstring(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) {		unsigned i = ssh2_pkt_getuint32();		struct ssh_channel *c;		c = find234(ssh_channels, &i, ssh_channelfind);		if (!c)		    continue;	       /* nonexistent channel */		c->v.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;	    }	    /*	     * We failed to start the command. If this is the	     * fallback command, we really are finished; if it's	     * not, and if the fallback command exists, try falling	     * back to it before complaining.	     */	    if (!ssh_fallback_cmd && cfg.remote_cmd_ptr2 != NULL) {		logevent("Primary command failed; attempting fallback");		ssh_fallback_cmd = TRUE;		continue;	    }	    bombout(("Server refused to start a shell/command"));	    crReturnV;	} else {	    logevent("Started a shell/command");	}	break;    }    ssh_state = SSH_STATE_SESSION;    if (size_needed)	ssh_size();    if (eof_needed)	ssh_special(TS_EOF);    /*     * Transfer data!     */    ldisc_send(NULL, 0);	       /* cause ldisc to notice changes */    ssh_send_ok = 1;    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;		unsigned i = ssh2_pkt_getuint32();		struct ssh_channel *c;		c = find234(ssh_channels, &i, ssh_channelfind);		if (!c)		    continue;	       /* nonexistent 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) {		    int bufsize;		    c->v.v2.locwindow -= length;		    switch (c->type) {		      case CHAN_MAINSESSION:			bufsize =			    from_backend(pktin.type ==					 SSH2_MSG_CHANNEL_EXTENDED_DATA,					 data, length);			break;		      case CHAN_X11:			bufsize = x11_send(c->u.x11.s, data, length);			break;		      case CHAN_SOCKDATA:			bufsize = pfd_send(c->u.pfd.s, data, length);			break;		      case CHAN_AGENT:			while (length > 0) {			    if (c->u.a.lensofar < 4) {				int l = min(4 - c->u.a.lensofar, 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 = smalloc(c->u.a.totallen);				memcpy(c->u.a.message, c->u.a.msglen, 4);			    }			    if (c->u.a.lensofar >= 4 && length > 0) {				int l =				    min(c->u.a.totallen - c->u.a.lensofar,					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, *sentreply;				int replylen;				agent_query(c->u.a.message,					    c->u.a.totallen, &reply,					    &replylen);				if (reply)				    sentreply = reply;				else {				    /* Fake SSH_AGENT_FAILURE. */				    sentreply = "\0\0\0\1\5";				    replylen = 5;				}				ssh2_add_channel_data(c, sentreply,						      replylen);				try_send = TRUE;				if (reply)				    sfree(reply);				sfree(c->u.a.message);				c->u.a.lensofar = 0;			    }			}			bufsize = 0;			break;		    }		    /*		     * If we are not buffering too much data,		     * enlarge the window again at the remote side.		     */		    if (bufsize < OUR_V2_WINSIZE)			ssh2_set_window(c, OUR_V2_WINSIZE - bufsize);		}	    } 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) {		unsigned i = ssh2_pkt_getuint32();		struct ssh_channel *c;		c = find234(ssh_channels, &i, ssh_channelfind);		if (!c)		    continue;	       /* nonexistent channel */		if (c->type == CHAN_X11) {		    /*		     * Remote EOF on an X11 channel means we should		     * wrap up and close the channel ourselves.		     */		    x11_close(c->u.x11.s);		    sshfwd_close(c);		} else if (c->type == CHAN_AGENT) {		    sshfwd_close(c);		} else if (c->type == CHAN_SOCKDATA) {		    pfd_close(c->u.pfd.s);		    sshfwd_close(c);		}	    } else if (pktin.type == SSH2_MSG_CHANNEL_CLOSE) {		unsigned i = ssh2_pkt_getuint32();		struct ssh_channel *c;		c = find234(ssh_channels, &i, ssh_channelfind);		if (!c)		    continue;	       /* nonexistent channel */		if (c->closes == 0) {		    ssh2_pkt_init(SSH2_MSG_CHANNEL_CLOSE);		    ssh2_pkt_adduint32(c->remoteid);		    ssh2_pkt_send();		}		/* Do pre-close processing on the channel. */		switch (c->type) {		  case CHAN_MAINSESSION:		    break;	       /* nothing to see here, move along */		  case CHAN_X11:		    break;		  case CHAN_AGENT:		    break;		  case CHAN_SOCKDATA:		    break;		}		del234(ssh_channels, c);		bufchain_clear(&c->v.v2.outbuffer);		sfree(c);		/*		 * See if that was the last channel left open.		 */		if (count234(ssh_channels) == 0) {		    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) {		unsigned i = ssh2_pkt_getuint32();		struct ssh_channel *c;		c = find234(ssh_channels, &i, ssh_channelfind);		if (!c)		    continue;	       /* nonexistent channel */		c->v.v2.remwindow += ssh2_pkt_getuint32();		try_send = TRUE;	    } else if (pktin.type == SSH2_MSG_CHANNEL_OPEN_CONFIRMATION) {		unsigned i = ssh2_pkt_getuint32();		struct ssh_channel *c;		c = find234(ssh_channels, &i, ssh_channelfind);		if (!c)		    continue;	       /* nonexistent channel */		if (c->type != CHAN_SOCKDATA_DORMANT)		    continue;	       /* dunno why they're confirming this */		c->remoteid = ssh2_pkt_getuint32();		c->type = CHAN_SOCKDATA;		c->closes = 0;		c->v.v2.remwindow = ssh2_pkt_getuint32();		c->v.v2.remmaxpkt = ssh2_pkt_getuint32();		bufchain_init(&c->v.v2.outbuffer);		pfd_confirm(c->u.pfd.s);	    } else if (pktin.type == SSH2_MSG_CHANNEL_OPEN) {		char *type;		int typelen;		char *error = NULL;		struct ssh_channel *c;		unsigned remid, winsize, pktsize;		ssh2_pkt_getstring(&type, &typelen);		c = smalloc(sizeof(struct ssh_channel));		remid = ssh2_pkt_getuint32();		winsize = ssh2_pkt_getuint32();		pktsize = ssh2_pkt_getuint32();		if (typelen == 3 && !memcmp(type, "x11", 3)) {		    if (!ssh_X11_fwd_enabled)			error = "X11 forwarding is not enabled";		    else if (x11_init(&c->u.x11.s, cfg.x11_display, c) !=			     NULL) {			error = "Unable to open an X11 connection";		    } else {			c->type = CHAN_X11;		    }		} else if (typelen == 15 &&			   !memcmp(type, "forwarded-tcpip", 15)) {		    struct ssh_rportfwd pf, *realpf;		    char *dummy;		    int dummylen;		    ssh2_pkt_getstring(&dummy, &dummylen);/* skip address */		    pf.sport = ssh2_pkt_getuint32();		    realpf = find234(ssh_rportfwds, &pf, NULL);		    if (realpf == NULL) {			error = "Remote port is not recognised";		    } else {			char *e = pfd_newconnect(&c->u.pfd.s, realpf->dhost,						 realpf->dport, c);			char buf[1024];			sprintf(buf, "Received remote port open request for %s:%d",				realpf->dhost, realpf->dport);			logevent(buf);			if (e != NULL) {			    sprintf(buf, "Port open failed: %s", e);			    logevent(buf);			    error = "Port open failed";			} else {			    logevent("Forwarded port opened successfully");			    c->type = CHAN_SOCKDATA;			}		    }		} else if (typelen == 22 &&			   !memcmp(type, "auth-agent@openssh.com", 3)) {		    if (!ssh_agentfwd_enabled)			error = "Agent forwarding is not enabled";		    else {			c->type = CHAN_AGENT;	/* identify channel type */			c->u.a.lensofar = 0;		    }		} else {		    error = "Unsupported channel type requested";		}		c->remoteid = remid;		if (error) {		    ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN_FAILURE);		    ssh2_pkt_adduint32(c->remoteid);		    ssh2_pkt_adduint32(SSH2_OPEN_CONNECT_FAILED);		    ssh2_pkt_addstring(error);		    ssh2_pkt_addstring("en");	/* language tag */		    ssh2_pkt_send();		    sfree(c);		} else {		    c->localid = alloc_channel_id();		    c->closes = 0;		    c->v.v2.locwindow = OUR_V2_WINSIZE;		    c->v.v2.remwindow = winsize;		    c->v.v2.remmaxpkt = pktsize;		    bufchain_init(&c->v.v2.outbuffer);		    add234(ssh_channels, c);		    ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);		    ssh2_pkt_adduint32(c->remoteid);		    ssh2_pkt_adduint32(c->localid);		    ssh2_pkt_adduint32(c->v.v2.locwindow);		    ssh2_pkt_adduint32(0x4000UL);	/* our max pkt size */		    ssh2_pkt_send();		}	    } else {		bombout(("Strange packet received: type %d", pktin.type));		crReturnV;	    }	} else {	    /*	     * We have spare data. Add it to the channel buffer.	     */	    ssh2_add_channel_data(mainchan, in, inlen);	    try_send = TRUE;	}	if (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++) {		int bufsize = ssh2_try_send(c);		if (bufsize == 0) {		    switch (c->type) {		      case CHAN_MAINSESSION:			/* stdin need not receive an unthrottle			 * notification since it will be polled */			break;		      case CHAN_X11:			x11_unthrottle(c->u.x11.s);			break;		      case CHAN_AGENT:			/* agent sockets are request/response and need no			 * buffer management */			break;		      case CHAN_SOCKDATA:			pfd_unthrottle(c->u.pfd.s);			break;		    }		}	    }	}    }    crFinishV;}