char buf[1024];
static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt){    struct do_ssh2_authconn_state {	enum {	    AUTH_INVALID, AUTH_PUBLICKEY_AGENT, AUTH_PUBLICKEY_FILE,		AUTH_PASSWORD,		AUTH_KEYBOARD_INTERACTIVE	} method;	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;	int gotit, need_pw, can_pubkey, can_passwd, can_keyb_inter;	int tried_pubkey_config, tried_agent, tried_keyb_inter;	int kbd_inter_running;	int we_are_in;	int num_prompts, curr_prompt, echo;	char username[100];	int got_username;	char pwprompt[200];	char password[100];	void *publickey_blob;	int publickey_bloblen;	unsigned char request[5], *response, *p;	int responselen;	int keyi, nkeys;	int authed;	char *pkblob, *alg, *commentp;	int pklen, alglen, commentlen;	int siglen, retlen, len;	char *q, *agentreq, *ret;	int try_send;    };    crState(do_ssh2_authconn_state);    crBegin(ssh->do_ssh2_authconn_crstate);    /*     * Request userauth protocol, and await a response to it.     */    ssh2_pkt_init(ssh, SSH2_MSG_SERVICE_REQUEST);    ssh2_pkt_addstring(ssh, "ssh-userauth");    ssh2_pkt_send(ssh);    crWaitUntilV(ispkt);    if (ssh->pktin.type != SSH2_MSG_SERVICE_ACCEPT) {	bombout((ssh,"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 can be sent back to the     * beginning to try another username, if this is configured on.     * (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!     */    s->username[0] = '\0';    s->got_username = FALSE;    do {	/*	 * Get a username.	 */	if (s->got_username && !cfg.change_username) {	    /*	     * We got a username last time round this loop, and	     * with change_username turned off we don't try to get	     * it again.	     */	} else if ((flags & FLAG_INTERACTIVE) && !*cfg.username) {	    if (ssh_get_line && !ssh_getline_pw_only) {		if (!ssh_get_line("login as: ",				  s->username, sizeof(s->username), FALSE)) {		    /*		     * get_line failed to get a username.		     * Terminate.		     */		    logevent("No username provided. Abandoning session.");		    ssh->state = SSH_STATE_CLOSED;		    crReturnV;		}	    } else {		int ret;	       /* need not be saved across crReturn */		c_write_str(ssh, "login as: ");		ssh->send_ok = 1;		setup_userpass_input(ssh, s->username, sizeof(s->username), 1);		do {		    crWaitUntilV(!ispkt);		    ret = process_userpass_input(ssh, in, inlen);		} while (ret == 0);		if (ret < 0)		    cleanup_exit(0);		c_write_str(ssh, "\r\n");	    }	    s->username[strcspn(s->username, "\n\r")] = '\0';	} else {	    char stuff[200];	    strncpy(s->username, cfg.username, sizeof(s->username));	    s->username[sizeof(s->username)-1] = '\0';	    if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE)) {		sprintf(stuff, "Using username \"%s\".\r\n", s->username);		c_write_str(ssh, stuff);	    }	}	s->got_username = TRUE;	/*	 * 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.	 */	ssh->pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;	ssh2_pkt_init(ssh, SSH2_MSG_USERAUTH_REQUEST);	ssh2_pkt_addstring(ssh, s->username);	ssh2_pkt_addstring(ssh, "ssh-connection");/* service requested */	ssh2_pkt_addstring(ssh, "none");    /* method */	ssh2_pkt_send(ssh);	s->type = AUTH_TYPE_NONE;	s->gotit = FALSE;	s->we_are_in = FALSE;	s->tried_pubkey_config = FALSE;	s->tried_agent = FALSE;	s->tried_keyb_inter = FALSE;	s->kbd_inter_running = FALSE;	/* Load the pub half of cfg.keyfile so we notice if it's in Pageant */	if (*cfg.keyfile) {	    int keytype;	    logeventf(ssh->frontend,		      "Reading private key file \"%.150s\"", cfg.keyfile);	    keytype = key_type(cfg.keyfile);	    if (keytype == SSH_KEYTYPE_SSH2) {		s->publickey_blob =		    ssh2_userkey_loadpub(cfg.keyfile, NULL,					 &s->publickey_bloblen);	    } else {		char msgbuf[256];		logeventf(ssh->frontend,			  "Unable to use this key file (%s)",			  key_type_to_str(keytype));		sprintf(msgbuf, "Unable to use key file \"%.150s\" (%s)\r\n",			cfg.keyfile, key_type_to_str(keytype));		c_write_str(ssh, msgbuf);		s->publickey_blob = NULL;	    }	} else	    s->publickey_blob = NULL;	while (1) {	    /*	     * Wait for the result of the last authentication request.	     */	    if (!s->gotit)		crWaitUntilV(ispkt);	    while (ssh->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(ssh, &banner, &size);		    if (banner)			c_write_untrusted(ssh, banner, size);		}		crWaitUntilV(ispkt);	    }	    if (ssh->pktin.type == SSH2_MSG_USERAUTH_SUCCESS) {		logevent("Access granted");		s->we_are_in = TRUE;		break;	    }	    if (s->kbd_inter_running &&		ssh->pktin.type == SSH2_MSG_USERAUTH_INFO_REQUEST) {		/*		 * This is either a further set-of-prompts packet		 * in keyboard-interactive authentication, or it's		 * the same one and we came back here with `gotit'		 * set. In the former case, we must reset the		 * curr_prompt variable.		 */		if (!s->gotit)		    s->curr_prompt = 0;	    } else if (ssh->pktin.type != SSH2_MSG_USERAUTH_FAILURE) {		bombout((ssh,"Strange packet received during authentication: type %d",			 ssh->pktin.type));		crReturnV;	    }	    s->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 (ssh->pktin.type == SSH2_MSG_USERAUTH_FAILURE) {		char *methods;		int methlen;		ssh2_pkt_getstring(ssh, &methods, &methlen);		s->kbd_inter_running = FALSE;		if (!ssh2_pkt_getbool(ssh)) {		    /*		     * 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 (s->type == AUTH_TYPE_NONE) {			/* do nothing */		    } else if (s->type == AUTH_TYPE_PUBLICKEY_OFFER_LOUD ||			       s->type == AUTH_TYPE_PUBLICKEY_OFFER_QUIET) {			if (s->type == AUTH_TYPE_PUBLICKEY_OFFER_LOUD)			    c_write_str(ssh, "Server refused our key\r\n");			logevent("Server refused public key");		    } else if (s->type==AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET) {			/* server declined keyboard-interactive; ignore */		    } else {			c_write_str(ssh, "Access denied\r\n");			logevent("Access denied");			if (s->type == AUTH_TYPE_PASSWORD) {			    s->we_are_in = FALSE;			    break;			}		    }		} else {		    c_write_str(ssh, "Further authentication required\r\n");		    logevent("Further authentication required");		}		s->can_pubkey =		    in_commasep_string("publickey", methods, methlen);		s->can_passwd =		    in_commasep_string("password", methods, methlen);		s->can_keyb_inter = cfg.try_ki_auth &&		    in_commasep_string("keyboard-interactive", methods, methlen);	    }	    s->method = 0;	    ssh->pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;	    /*	     * Most password/passphrase prompts will be	     * non-echoing, so we set this to 0 by default.	     * Exception is that some keyboard-interactive prompts	     * can be echoing, in which case we'll set this to 1.	     */	    s->echo = 0;	    if (!s->method && s->can_pubkey &&		agent_exists() && !s->tried_agent) {		/*		 * Attempt public-key authentication using Pageant.		 */		void *r;		s->authed = FALSE;		ssh->pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;		ssh->pkt_ctx |= SSH2_PKTCTX_PUBLICKEY;		s->tried_agent = TRUE;		logevent("Pageant is running. Requesting keys.");		/* Request the keys held by the agent. */		PUT_32BIT(s->request, 1);		s->request[4] = SSH2_AGENTC_REQUEST_IDENTITIES;		agent_query(s->request, 5, &r, &s->responselen);		s->response = (unsigned char *) r;		if (s->response && s->responselen >= 5 &&		    s->response[4] == SSH2_AGENT_IDENTITIES_ANSWER) {		    s->p = s->response + 5;		    s->nkeys = GET_32BIT(s->p);		    s->p += 4;		    {			char buf[64];			sprintf(buf, "Pageant has %d SSH2 keys", s->nkeys);			logevent(buf);		    }		    for (s->keyi = 0; s->keyi < s->nkeys; s->keyi++) {			void *vret;			{			    char buf[64];			    sprintf(buf, "Trying Pageant key #%d", s->keyi);			    logevent(buf);			}			s->pklen = GET_32BIT(s->p);			s->p += 4;			if (s->publickey_blob &&			    s->pklen == s->publickey_bloblen &&			    !memcmp(s->p, s->publickey_blob,				    s->publickey_bloblen)) {			    logevent("This key matches configured key file");			    s->tried_pubkey_config = 1;			}			s->pkblob = s->p;			s->p += s->pklen;			s->alglen = GET_32BIT(s->pkblob);			s->alg = s->pkblob + 4;			s->commentlen = GET_32BIT(s->p);			s->p += 4;			s->commentp = s->p;			s->p += s->commentlen;			ssh2_pkt_init(ssh, SSH2_MSG_USERAUTH_REQUEST);			ssh2_pkt_addstring(ssh, s->username);			ssh2_pkt_addstring(ssh, "ssh-connection");	/* service requested */			ssh2_pkt_addstring(ssh, "publickey");	/* method */			ssh2_pkt_addbool(ssh, FALSE);	/* no signature included */			ssh2_pkt_addstring_start(ssh);			ssh2_pkt_addstring_data(ssh, s->alg, s->alglen);			ssh2_pkt_addstring_start(ssh);			ssh2_pkt_addstring_data(ssh, s->pkblob, s->pklen);			ssh2_pkt_send(ssh);			crWaitUntilV(ispkt);			if (ssh->pktin.type != SSH2_MSG_USERAUTH_PK_OK) {			    logevent("Key refused");			    continue;			}			if (flags & FLAG_VERBOSE) {			    c_write_str(ssh, "Authenticating with "					"public key \"");			    c_write(ssh, s->commentp, s->commentlen);			    c_write_str(ssh, "\" from agent\r\n");			}			/*			 * Server is willing to accept the key.			 * Construct a SIGN_REQUEST.			 */			ssh2_pkt_init(ssh, SSH2_MSG_USERAUTH_REQUEST);			ssh2_pkt_addstring(ssh, s->username);			ssh2_pkt_addstring(ssh, "ssh-connection");	/* service requested */			ssh2_pkt_addstring(ssh, "publickey");	/* method */			ssh2_pkt_addbool(ssh, TRUE);			ssh2_pkt_addstring_start(ssh);			ssh2_pkt_addstring_data(ssh, s->alg, s->alglen);			ssh2_pkt_addstring_start(ssh);			ssh2_pkt_addstring_data(ssh, s->pkblob, s->pklen);			s->siglen = ssh->pktout.length - 5 + 4 + 20;			s->len = 1;       /* message type */			s->len += 4 + s->pklen;	/* key blob */			s->len += 4 + s->siglen;	/* data to sign */			s->len += 4;      /* flags */			s->agentreq = smalloc(4 + s->len);			PUT_32BIT(s->agentreq, s->len);			s->q = s->agentreq + 4;			*s->q++ = SSH2_AGENTC_SIGN_REQUEST;			PUT_32BIT(s->q, s->pklen);			s->q += 4;			memcpy(s->q, s->pkblob, s->pklen);			s->q += s->pklen;			PUT_32BIT(s->q, s->siglen);			s->q += 4;			/* Now the data to be signed... */			PUT_32BIT(s->q, 20);			s->q += 4;			memcpy(s->q, ssh->v2_session_id, 20);			s->q += 20;			memcpy(s->q, ssh->pktout.data + 5,			       ssh->pktout.length - 5);			s->q += ssh->pktout.length - 5;			/* And finally the (zero) flags word. */			PUT_32BIT(s->q, 0);			agent_query(s->agentreq, s->len + 4, &vret, &s->retlen);			s->ret = vret;			sfree(s->agentreq);			if (s->ret) {			    if (s->ret[4] == SSH2_AGENT_SIGN_RESPONSE) {				logevent("Sending Pageant's response");				ssh2_add_sigblob(ssh, s->pkblob, s->pklen,						 s->ret + 9,						 GET_32BIT(s->ret + 5));				ssh2_pkt_send(ssh);				s->authed = TRUE;				break;			    } else {				logevent				    ("Pageant failed to answer challenge");				sfree(s->ret);			    }			}		    }		    if (s->authed)			continue;		}	    }	    if (!s->method && s->can_pubkey && s->publickey_blob		&& !s->tried_pubkey_config) {		unsigned char *pub_blob;		char *algorithm, *comment;		int pub_blob_len;		s->tried_pubkey_config = TRUE;		ssh->pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;		ssh->pkt_ctx |= SSH2_PKTCTX_PUBLICKEY;		/*		 * 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(ssh, SSH2_MSG_USERAUTH_REQUEST);		    ssh2_pkt_addstring(ssh, s->username);		    ssh2_pkt_addstring(ssh, "ssh-connection");	/* service requested */		    ssh2_pkt_addstring(ssh, "publickey");	/* method */		    ssh2_pkt_addbool(ssh, FALSE);	/* no signature included */		    ssh2_pkt_addstring(ssh, algorithm);		    ssh2_pkt_addstring_start(ssh);		    ssh2_pkt_addstring_data(ssh, pub_blob, pub_blob_len);		    ssh2_pkt_send(ssh);		    logevent("Offered public key");	/* FIXME */		    crWaitUntilV(ispkt);		    if (ssh->pktin.type != SSH2_MSG_USERAUTH_PK_OK) {			s->gotit = TRUE;			s->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(s->pwprompt,				"Passphrase for key \"%.100s\": ",				comment);			s->need_pw = TRUE;		    } else {			s->need_pw = FALSE;		    }		    c_write_str(ssh, "Authenticating with public key \"");		    c_write_str(ssh, comment);		    c_write_str(ssh, "\"\r\n");		    s->method = AUTH_PUBLICKEY_FILE;		}	    }	    if (!s->method && s->can_keyb_inter && !s->tried_keyb_inter) {		s->method = AUTH_KEYBOARD_INTERACTIVE;		s->type = AUTH_TYPE_KEYBOARD_INTERACTIVE;		s->tried_keyb_inter = TRUE;		ssh->pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;		ssh->pkt_ctx |= SSH2_PKTCTX_KBDINTER;		ssh2_pkt_init(ssh, SSH2_MSG_USERAUTH_REQUEST);		ssh2_pkt_addstring(ssh, s->username);		ssh2_pkt_addstring(ssh, "ssh-connection");	/* service requested */		ssh2_pkt_addstring(ssh, "keyboard-interactive");	/* method */		ssh2_pkt_addstring(ssh, ""); /* lang */		ssh2_pkt_addstring(ssh, "");		ssh2_pkt_send(ssh);		crWaitUntilV(ispkt);		if (ssh->pktin.type != SSH2_MSG_USERAUTH_INFO_REQUEST) {		    if (ssh->pktin.type == SSH2_MSG_USERAUTH_FAILURE)			s->gotit = TRUE;		    logevent("Keyboard-interactive authentication refused");		    s->type = AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET;		    continue;		}		s->kbd_inter_running = TRUE;		s->curr_prompt = 0;	    }	    if (s->kbd_inter_running) {		s->method = AUTH_KEYBOARD_INTERACTIVE;		s->type = AUTH_TYPE_KEYBOARD_INTERACTIVE;		s->tried_keyb_inter = TRUE;		ssh->pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;		ssh->pkt_ctx |= SSH2_PKTCTX_KBDINTER;		if (s->curr_prompt == 0) {		    /*		     * We've got a fresh USERAUTH_INFO_REQUEST.		     * Display header data, and start going through		     * the prompts.		     */		    char *name, *inst, *lang;		    int name_len, inst_len, lang_len;		    ssh2_pkt_getstring(ssh, &name, &name_len);		    ssh2_pkt_getstring(ssh, &inst, &inst_len);		    ssh2_pkt_getstring(ssh, &lang, &lang_len);		    if (name_len > 0) {			c_write_untrusted(ssh, name, name_len);			c_write_str(ssh, "\r\n");		    }		    if (inst_len > 0) {			c_write_untrusted(ssh, inst, inst_len);			c_write_str(ssh, "\r\n");		    }		    s->num_prompts = ssh2_pkt_getuint32(ssh);		}		/*		 * If there are prompts remaining in the packet,		 * display one and get a response.		 */		if (s->curr_prompt < s->num_prompts) {		    char *prompt;		    int prompt_len;		    ssh2_pkt_getstring(ssh, &prompt, &prompt_len);		    if (prompt_len > 0) {			strncpy(s->pwprompt, prompt, sizeof(s->pwprompt));			s->pwprompt[prompt_len < sizeof(s->pwprompt) ?				    prompt_len : sizeof(s->pwprompt)-1] = '\0';		    } else {			strcpy(s->pwprompt,			       "<server failed to send prompt>: ");		    }		    s->echo = ssh2_pkt_getbool(ssh);		    s->need_pw = TRUE;		} else		    s->need_pw = FALSE;	    }	    if (!s->method && s->can_passwd) {		s->method = AUTH_PASSWORD;		ssh->pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;		ssh->pkt_ctx |= SSH2_PKTCTX_PASSWORD;		sprintf(s->pwprompt, "%.90s@%.90s's password: ", s->username,			ssh->savedhost);		s->need_pw = TRUE;	    }	    if (s->need_pw) {		if (ssh_get_line) {		    if (!ssh_get_line(s->pwprompt, s->password,				      sizeof(s->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(ssh, SSH2_MSG_DISCONNECT);			ssh2_pkt_adduint32(ssh,SSH2_DISCONNECT_BY_APPLICATION);			ssh2_pkt_addstring(ssh, "No more passwords available"					   " to try");			ssh2_pkt_addstring(ssh, "en");	/* language tag */			ssh2_pkt_send(ssh);			logevent("Unable to authenticate");			connection_fatal(ssh->frontend,					 "Unable to authenticate");			ssh->state = SSH_STATE_CLOSED;			crReturnV;		    }		} else {		    int ret;	       /* need not be saved across crReturn */		    c_write_untrusted(ssh, s->pwprompt, strlen(s->pwprompt));		    ssh->send_ok = 1;		    setup_userpass_input(ssh, s->password,					 sizeof(s->password), s->echo);		    do {			crWaitUntilV(!ispkt);			ret = process_userpass_input(ssh, in, inlen);		    } while (ret == 0);		    if (ret < 0)			cleanup_exit(0);		    c_write_str(ssh, "\r\n");		}	    }	    if (s->method == AUTH_PUBLICKEY_FILE) {		/*		 * We have our passphrase. Now try the actual authentication.		 */		struct ssh2_userkey *key;		key = ssh2_load_userkey(cfg.keyfile, s->password);		if (key == SSH2_WRONG_PASSPHRASE || key == NULL) {		    if (key == SSH2_WRONG_PASSPHRASE) {			c_write_str(ssh, "Wrong passphrase\r\n");			s->tried_pubkey_config = FALSE;		    } else {			c_write_str(ssh, "Unable to load private key\r\n");			s->tried_pubkey_config = TRUE;		    }		    /* Send a spurious AUTH_NONE to return to the top. */		    ssh2_pkt_init(ssh, SSH2_MSG_USERAUTH_REQUEST);		    ssh2_pkt_addstring(ssh, s->username);		    ssh2_pkt_addstring(ssh, "ssh-connection");	/* service requested */		    ssh2_pkt_addstring(ssh, "none");	/* method */		    ssh2_pkt_send(ssh);		    s->type = AUTH_TYPE_NONE;		} else {		    unsigned char *pkblob, *sigblob, *sigdata;		    int pkblob_len, sigblob_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(ssh, SSH2_MSG_USERAUTH_REQUEST);		    ssh2_pkt_addstring(ssh, s->username);		    ssh2_pkt_addstring(ssh, "ssh-connection");	/* service requested */		    ssh2_pkt_addstring(ssh, "publickey");	/* method */		    ssh2_pkt_addbool(ssh, TRUE);		    ssh2_pkt_addstring(ssh, key->alg->name);		    pkblob = key->alg->public_blob(key->data, &pkblob_len);		    ssh2_pkt_addstring_start(ssh);		    ssh2_pkt_addstring_data(ssh, pkblob, pkblob_len);		    /*		     * The data to be signed is:		     *		     *   string  session-id		     *		     * followed by everything so far placed in the		     * outgoing packet.		     */		    sigdata_len = ssh->pktout.length - 5 + 4 + 20;		    sigdata = smalloc(sigdata_len);		    PUT_32BIT(sigdata, 20);		    memcpy(sigdata + 4, ssh->v2_session_id, 20);		    memcpy(sigdata + 24, ssh->pktout.data + 5,			   ssh->pktout.length - 5);		    sigblob = key->alg->sign(key->data, sigdata,					     sigdata_len, &sigblob_len);		    ssh2_add_sigblob(ssh, pkblob, pkblob_len,				     sigblob, sigblob_len);		    sfree(pkblob);		    sfree(sigblob);		    sfree(sigdata);		    ssh2_pkt_send(ssh);		    s->type = AUTH_TYPE_PUBLICKEY;		}	    } else if (s->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(ssh, SSH2_MSG_USERAUTH_REQUEST);		ssh2_pkt_addstring(ssh, s->username);		ssh2_pkt_addstring(ssh, "ssh-connection");	/* service requested */		ssh2_pkt_addstring(ssh, "password");		ssh2_pkt_addbool(ssh, FALSE);		ssh2_pkt_addstring(ssh, s->password);		ssh2_pkt_defer(ssh);		/*		 * 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 (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);		    }		    ssh2_pkt_init(ssh, SSH2_MSG_IGNORE);		    ssh2_pkt_addstring_start(ssh);		    for (i = 0; i < stringlen; i++) {			char c = (char) random_byte();			ssh2_pkt_addstring_data(ssh, &c, 1);		    }		    ssh2_pkt_defer(ssh);		}		ssh_pkt_defersend(ssh);		logevent("Sent password");		s->type = AUTH_TYPE_PASSWORD;	    } else if (s->method == AUTH_KEYBOARD_INTERACTIVE) {		if (s->curr_prompt == 0) {		    ssh2_pkt_init(ssh, SSH2_MSG_USERAUTH_INFO_RESPONSE);		    ssh2_pkt_adduint32(ssh, s->num_prompts);		}		if (s->need_pw) {      /* only add pw if we just got one! */		    ssh2_pkt_addstring(ssh, s->password);		    memset(s->password, 0, sizeof(s->password));		    s->curr_prompt++;		}		if (s->curr_prompt >= s->num_prompts) {		    ssh2_pkt_send(ssh);		} 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");		ssh2_pkt_init(ssh, SSH2_MSG_DISCONNECT);		ssh2_pkt_adduint32(ssh, SSH2_DISCONNECT_BY_APPLICATION);		ssh2_pkt_addstring(ssh, "No supported authentication"				   " methods available");		ssh2_pkt_addstring(ssh, "en");	/* language tag */		ssh2_pkt_send(ssh);		ssh->state = SSH_STATE_CLOSED;		crReturnV;	    }	}    } 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.     */    /*     * So now create a channel with a session in it.     */    ssh->channels = newtree234(ssh_channelcmp);    ssh->mainchan = smalloc(sizeof(struct ssh_channel));    ssh->mainchan->ssh = ssh;    ssh->mainchan->localid = alloc_channel_id(ssh);    ssh2_pkt_init(ssh, SSH2_MSG_CHANNEL_OPEN);    ssh2_pkt_addstring(ssh, "session");    ssh2_pkt_adduint32(ssh, ssh->mainchan->localid);    ssh->mainchan->v.v2.locwindow = OUR_V2_WINSIZE;    ssh2_pkt_adduint32(ssh, ssh->mainchan->v.v2.locwindow);/* our window size */    ssh2_pkt_adduint32(ssh, 0x4000UL);      /* our max pkt size */    ssh2_pkt_send(ssh);    crWaitUntilV(ispkt);    if (ssh->pktin.type != SSH2_MSG_CHANNEL_OPEN_CONFIRMATION) {	bombout((ssh,"Server refused to open a session"));	crReturnV;	/* FIXME: error data comes back in FAILURE packet */    }    if (ssh2_pkt_getuint32(ssh) != ssh->mainchan->localid) {	bombout((ssh,"Server's channel confirmation cited wrong channel"));	crReturnV;    }    ssh->mainchan->remoteid = ssh2_pkt_getuint32(ssh);    ssh->mainchan->type = CHAN_MAINSESSION;    ssh->mainchan->closes = 0;    ssh->mainchan->v.v2.remwindow = ssh2_pkt_getuint32(ssh);    ssh->mainchan->v.v2.remmaxpkt = ssh2_pkt_getuint32(ssh);    bufchain_init(&ssh->mainchan->v.v2.outbuffer);    add234(ssh->channels, ssh->mainchan);    logevent("Opened channel for session");    /*     * Potentially enable X11 forwarding.     */    if (cfg.x11_forward) {	char proto[20], data[64];	logevent("Requesting X11 forwarding");	ssh->x11auth = x11_invent_auth(proto, sizeof(proto),				       data, sizeof(data));	ssh2_pkt_init(ssh, SSH2_MSG_CHANNEL_REQUEST);	ssh2_pkt_adduint32(ssh, ssh->mainchan->remoteid);	ssh2_pkt_addstring(ssh, "x11-req");	ssh2_pkt_addbool(ssh, 1);	       /* want reply */	ssh2_pkt_addbool(ssh, 0);	       /* many connections */	ssh2_pkt_addstring(ssh, proto);	ssh2_pkt_addstring(ssh, data);	ssh2_pkt_adduint32(ssh, 0);	       /* screen number */	ssh2_pkt_send(ssh);	do {	    crWaitUntilV(ispkt);	    if (ssh->pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST) {		unsigned i = ssh2_pkt_getuint32(ssh);		struct ssh_channel *c;		c = find234(ssh->channels, &i, ssh_channelfind);		if (!c)		    continue;	       /* nonexistent channel */		c->v.v2.remwindow += ssh2_pkt_getuint32(ssh);	    }	} while (ssh->pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST);	if (ssh->pktin.type != SSH2_MSG_CHANNEL_SUCCESS) {	    if (ssh->pktin.type != SSH2_MSG_CHANNEL_FAILURE) {		bombout((ssh,"Unexpected response to X11 forwarding request:"			 " packet type %d", ssh->pktin.type));		crReturnV;	    }	    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], host[256];	char buf[1024];	ssh->rportfwds = newtree234(ssh_rportcmp_ssh2);        /* Add port forwardings. */	ssh->portfwd_strptr = cfg.portfwd;	while (*ssh->portfwd_strptr) {	    type = *ssh->portfwd_strptr++;	    n = 0;	    while (*ssh->portfwd_strptr && *ssh->portfwd_strptr != '\t')		sports[n++] = *ssh->portfwd_strptr++;	    sports[n] = 0;	    if (*ssh->portfwd_strptr == '\t')		ssh->portfwd_strptr++;	    n = 0;	    while (*ssh->portfwd_strptr && *ssh->portfwd_strptr != ':')		host[n++] = *ssh->portfwd_strptr++;	    host[n] = 0;	    if (*ssh->portfwd_strptr == ':')		ssh->portfwd_strptr++;	    n = 0;	    while (*ssh->portfwd_strptr)		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) {		    sprintf(buf,			    "Service lookup failed for destination port \"%s\"",			    dports);		    logevent(buf);		}	    }	    sport = atoi(sports);	    sserv = 0;	    if (sport == 0) {		sserv = 1;		sport = net_service_lookup(sports);		if (!sport) {		    sprintf(buf,			    "Service lookup failed for source port \"%s\"",			    sports);		    logevent(buf);		}	    }	    if (sport && dport) {		if (type == 'L') {		    pfd_addforward(host, dport, sport, ssh);		    sprintf(buf, "Local port %.*s%.*s%d%.*s forwarding to"			    " %s:%.*s%.*s%d%.*s",			    (int)(sserv ? strlen(sports) : 0), sports,			    sserv, "(", sport, sserv, ")",			    host,			    (int)(dserv ? strlen(dports) : 0), dports,			    dserv, "(", dport, dserv, ")");		    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 %.*s%.*s%d%.*s"				" forward to %s:%.*s%.*s%d%.*s",			    (int)(sserv ? strlen(sports) : 0), sports,			    sserv, "(", sport, sserv, ")",			    host,			    (int)(dserv ? strlen(dports) : 0), dports,			    dserv, "(", dport, dserv, ")");			logevent(buf);			ssh2_pkt_init(ssh, SSH2_MSG_GLOBAL_REQUEST);			ssh2_pkt_addstring(ssh, "tcpip-forward");			ssh2_pkt_addbool(ssh, 1);/* want reply */			if (cfg.rport_acceptall)			    ssh2_pkt_addstring(ssh, "0.0.0.0");			else			    ssh2_pkt_addstring(ssh, "127.0.0.1");			ssh2_pkt_adduint32(ssh, sport);			ssh2_pkt_send(ssh);			do {			    crWaitUntilV(ispkt);			    if (ssh->pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST) {				unsigned i = ssh2_pkt_getuint32(ssh);				struct ssh_channel *c;				c = find234(ssh->channels, &i, ssh_channelfind);				if (!c)				    continue;/* nonexistent channel */				c->v.v2.remwindow += ssh2_pkt_getuint32(ssh);			    }			} while (ssh->pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST);			if (ssh->pktin.type != SSH2_MSG_REQUEST_SUCCESS) {			    if (ssh->pktin.type != SSH2_MSG_REQUEST_FAILURE) {				bombout((ssh,"Unexpected response to port "					 "forwarding request: packet type %d",					 ssh->pktin.type));				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(ssh, SSH2_MSG_CHANNEL_REQUEST);	ssh2_pkt_adduint32(ssh, ssh->mainchan->remoteid);	ssh2_pkt_addstring(ssh, "auth-agent-req@openssh.com");	ssh2_pkt_addbool(ssh, 1);	       /* want reply */	ssh2_pkt_send(ssh);	do {	    crWaitUntilV(ispkt);	    if (ssh->pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST) {		unsigned i = ssh2_pkt_getuint32(ssh);		struct ssh_channel *c;		c = find234(ssh->channels, &i, ssh_channelfind);		if (!c)		    continue;	       /* nonexistent channel */		c->v.v2.remwindow += ssh2_pkt_getuint32(ssh);	    }	} while (ssh->pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST);	if (ssh->pktin.type != SSH2_MSG_CHANNEL_SUCCESS) {	    if (ssh->pktin.type != SSH2_MSG_CHANNEL_FAILURE) {		bombout((ssh,"Unexpected response to agent forwarding request:"			 " packet type %d", ssh->pktin.type));		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(ssh, SSH2_MSG_CHANNEL_REQUEST);	ssh2_pkt_adduint32(ssh, ssh->mainchan->remoteid);	/* recipient channel */	ssh2_pkt_addstring(ssh, "pty-req");	ssh2_pkt_addbool(ssh, 1);	       /* want reply */	ssh2_pkt_addstring(ssh, cfg.termtype);	ssh2_pkt_adduint32(ssh, ssh->term_width);	ssh2_pkt_adduint32(ssh, ssh->term_height);	ssh2_pkt_adduint32(ssh, 0);	       /* pixel width */	ssh2_pkt_adduint32(ssh, 0);	       /* pixel height */	ssh2_pkt_addstring_start(ssh);	ssh2_pkt_addstring_data(ssh, "\0", 1);	/* TTY_OP_END, no special options */	ssh2_pkt_send(ssh);	ssh->state = SSH_STATE_INTERMED;	do {	    crWaitUntilV(ispkt);	    if (ssh->pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST) {		unsigned i = ssh2_pkt_getuint32(ssh);		struct ssh_channel *c;		c = find234(ssh->channels, &i, ssh_channelfind);		if (!c)		    continue;	       /* nonexistent channel */		c->v.v2.remwindow += ssh2_pkt_getuint32(ssh);	    }	} while (ssh->pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST);	if (ssh->pktin.type != SSH2_MSG_CHANNEL_SUCCESS) {	    if (ssh->pktin.type != SSH2_MSG_CHANNEL_FAILURE) {		bombout((ssh,"Unexpected response to pty request:"			 " packet type %d", ssh->pktin.type));		crReturnV;	    }	    c_write_str(ssh, "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(ssh, SSH2_MSG_CHANNEL_REQUEST);	ssh2_pkt_adduint32(ssh, ssh->mainchan->remoteid);	/* recipient channel */	if (subsys) {	    ssh2_pkt_addstring(ssh, "subsystem");	    ssh2_pkt_addbool(ssh, 1);	       /* want reply */	    ssh2_pkt_addstring(ssh, cmd);	} else if (*cmd) {	    ssh2_pkt_addstring(ssh, "exec");	    ssh2_pkt_addbool(ssh, 1);	       /* want reply */	    ssh2_pkt_addstring(ssh, cmd);	} else {	    ssh2_pkt_addstring(ssh, "shell");	    ssh2_pkt_addbool(ssh, 1);	       /* want reply */	}	ssh2_pkt_send(ssh);	do {	    crWaitUntilV(ispkt);	    if (ssh->pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST) {		unsigned i = ssh2_pkt_getuint32(ssh);		struct ssh_channel *c;		c = find234(ssh->channels, &i, ssh_channelfind);		if (!c)		    continue;	       /* nonexistent channel */		c->v.v2.remwindow += ssh2_pkt_getuint32(ssh);	    }	} while (ssh->pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST);	if (ssh->pktin.type != SSH2_MSG_CHANNEL_SUCCESS) {	    if (ssh->pktin.type != SSH2_MSG_CHANNEL_FAILURE) {		bombout((ssh,"Unexpected response to shell/command request:"			 " packet type %d", ssh->pktin.type));		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((ssh,"Server refused to start a shell/command"));	    crReturnV;	} else {	    logevent("Started a shell/command");	}	break;    }    ssh->state = SSH_STATE_SESSION;    if (ssh->size_needed)	ssh_size(ssh, ssh->term_width, ssh->term_height);    if (ssh->eof_needed)	ssh_special(ssh, TS_EOF);    /*     * Transfer data!     */    if (ssh->ldisc)	ldisc_send(ssh->ldisc, NULL, 0, 0);/* cause ldisc to notice changes */    ssh->send_ok = 1;    while (1) {	crReturnV;	s->try_send = FALSE;	if (ispkt) {	    if (ssh->pktin.type == SSH2_MSG_CHANNEL_DATA ||		ssh->pktin.type == SSH2_MSG_CHANNEL_EXTENDED_DATA) {		char *data;		int length;		unsigned i = ssh2_pkt_getuint32(ssh);		struct ssh_channel *c;		c = find234(ssh->channels, &i, ssh_channelfind);		if (!c)		    continue;	       /* nonexistent channel */		if (ssh->pktin.type == SSH2_MSG_CHANNEL_EXTENDED_DATA &&		    ssh2_pkt_getuint32(ssh) != SSH2_EXTENDED_DATA_STDERR)		    continue;	       /* extended but not stderr */		ssh2_pkt_getstring(ssh, &data, &length);		if (data) {		    int bufsize;		    c->v.v2.locwindow -= length;		    switch (c->type) {		      case CHAN_MAINSESSION:			bufsize =			    from_backend(ssh->frontend, ssh->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);				s->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 (ssh->pktin.type == SSH2_MSG_CHANNEL_EOF) {		unsigned i = ssh2_pkt_getuint32(ssh);		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 (ssh->pktin.type == SSH2_MSG_CHANNEL_CLOSE) {		unsigned i = ssh2_pkt_getuint32(ssh);		struct ssh_channel *c;		c = find234(ssh->channels, &i, ssh_channelfind);		if (!c || ((int)c->remoteid) == -1) {		    bombout((ssh,"Received CHANNEL_CLOSE for %s channel %d\n",			     c ? "half-open" : "nonexistent", i));		}		/* Do pre-close processing on the channel. */		switch (c->type) {		  case CHAN_MAINSESSION:		    break;	       /* nothing to see here, move along */		  case CHAN_X11:		    if (c->u.x11.s != NULL)			x11_close(c->u.x11.s);		    sshfwd_close(c);		    break;		  case CHAN_AGENT:		    sshfwd_close(c);		    break;		  case CHAN_SOCKDATA:		    if (c->u.pfd.s != NULL)			pfd_close(c->u.pfd.s);		    sshfwd_close(c);		    break;		}		if (c->closes == 0) {		    ssh2_pkt_init(ssh, SSH2_MSG_CHANNEL_CLOSE);		    ssh2_pkt_adduint32(ssh, c->remoteid);		    ssh2_pkt_send(ssh);		}		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) {#if 0                    /*                     * We used to send SSH_MSG_DISCONNECT here,                     * because I'd believed that _every_ conforming                     * SSH2 connection had to end with a disconnect                     * being sent by at least one side; apparently                     * I was wrong and it's perfectly OK to                     * unceremoniously slam the connection shut                     * when you're done, and indeed OpenSSH feels                     * this is more polite than sending a                     * DISCONNECT. So now we don't.                     */		    logevent("All channels closed. Disconnecting");		    ssh2_pkt_init(ssh, SSH2_MSG_DISCONNECT);		    ssh2_pkt_adduint32(ssh, SSH2_DISCONNECT_BY_APPLICATION);		    ssh2_pkt_addstring(ssh, "All open channels closed");		    ssh2_pkt_addstring(ssh, "en");	/* language tag */		    ssh2_pkt_send(ssh);#endif		    ssh->state = SSH_STATE_CLOSED;		    crReturnV;		}		continue;	       /* remote sends close; ignore (FIXME) */	    } else if (ssh->pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST) {		unsigned i = ssh2_pkt_getuint32(ssh);		struct ssh_channel *c;		c = find234(ssh->channels, &i, ssh_channelfind);		if (!c)		    continue;	       /* nonexistent channel */		c->v.v2.remwindow += ssh2_pkt_getuint32(ssh);		s->try_send = TRUE;	    } else if (ssh->pktin.type == SSH2_MSG_CHANNEL_OPEN_CONFIRMATION) {		unsigned i = ssh2_pkt_getuint32(ssh);		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(ssh);		c->type = CHAN_SOCKDATA;		c->v.v2.remwindow = ssh2_pkt_getuint32(ssh);		c->v.v2.remmaxpkt = ssh2_pkt_getuint32(ssh);		if (c->u.pfd.s)		    pfd_confirm(c->u.pfd.s);		if (c->closes) {		    /*		     * We have a pending close on this channel,		     * which we decided on before the server acked		     * the channel open. So now we know the		     * remoteid, we can close it again.		     */		    ssh2_pkt_init(ssh, SSH2_MSG_CHANNEL_CLOSE);		    ssh2_pkt_adduint32(ssh, c->remoteid);		    ssh2_pkt_send(ssh);		}	    } else if (ssh->pktin.type == SSH2_MSG_CHANNEL_OPEN_FAILURE) {		unsigned i = ssh2_pkt_getuint32(ssh);		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 failing this */		logevent("Forwarded connection refused by server");		pfd_close(c->u.pfd.s);		del234(ssh->channels, c);		sfree(c);	    } else if (ssh->pktin.type == SSH2_MSG_CHANNEL_REQUEST) { 		unsigned localid;		char *type;		int typelen, want_reply;		struct ssh_channel *c;		localid = ssh2_pkt_getuint32(ssh);		ssh2_pkt_getstring(ssh, &type, &typelen);		want_reply = ssh2_pkt_getbool(ssh);		/*		 * First, check that the channel exists. Otherwise,		 * we can instantly disconnect with a rude message.		 */		c = find234(ssh->channels, &localid, ssh_channelfind);		if (!c) {		    char buf[80];		    sprintf(buf, "Received channel request for nonexistent"			    " channel %d", localid);		    logevent(buf);		    ssh2_pkt_init(ssh, SSH2_MSG_DISCONNECT);		    ssh2_pkt_adduint32(ssh, SSH2_DISCONNECT_BY_APPLICATION);		    ssh2_pkt_addstring(ssh, buf);		    ssh2_pkt_addstring(ssh, "en");	/* language tag */		    ssh2_pkt_send(ssh);		    connection_fatal("%s", buf);		    ssh->state = SSH_STATE_CLOSED;		    crReturnV;		}		/*		 * Having got the channel number, we now look at		 * the request type string to see if it's something		 * we recognise.		 */		if (typelen == 11 && !memcmp(type, "exit-status", 11) &&		    c == ssh->mainchan) {		    /* We recognise "exit-status" on the primary channel. */		    char buf[100];		    ssh->exitcode = ssh2_pkt_getuint32(ssh);		    sprintf(buf, "Server sent command exit status %d",			    ssh->exitcode);		    logevent(buf);		    if (want_reply) {			ssh2_pkt_init(ssh, SSH2_MSG_CHANNEL_SUCCESS);			ssh2_pkt_adduint32(ssh, c->remoteid);			ssh2_pkt_send(ssh);		    }		} else {		    /*		     * This is a channel request we don't know		     * about, so we now either ignore the request		     * or respond with CHANNEL_FAILURE, depending		     * on want_reply.		     */		    if (want_reply) {			ssh2_pkt_init(ssh, SSH2_MSG_CHANNEL_FAILURE);			ssh2_pkt_adduint32(ssh, c->remoteid);			ssh2_pkt_send(ssh);		    }		}	    } else if (ssh->pktin.type == SSH2_MSG_GLOBAL_REQUEST) {		char *type;		int typelen, want_reply;		ssh2_pkt_getstring(ssh, &type, &typelen);		want_reply = ssh2_pkt_getbool(ssh);                /*                 * We currently don't support any global requests                 * at all, so we either ignore the request or                 * respond with REQUEST_FAILURE, depending on                 * want_reply.                 */                if (want_reply) {                    ssh2_pkt_init(ssh, SSH2_MSG_REQUEST_FAILURE);                    ssh2_pkt_send(ssh);		}	    } else if (ssh->pktin.type == SSH2_MSG_CHANNEL_OPEN) {		char *type;		int typelen;		char *error = NULL;		struct ssh_channel *c;		unsigned remid, winsize, pktsize;		ssh2_pkt_getstring(ssh, &type, &typelen);		c = smalloc(sizeof(struct ssh_channel));		c->ssh = ssh;		remid = ssh2_pkt_getuint32(ssh);		winsize = ssh2_pkt_getuint32(ssh);		pktsize = ssh2_pkt_getuint32(ssh);		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,				      ssh->x11auth) != 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(ssh, &dummy, &dummylen);/* skip address */		    pf.sport = ssh2_pkt_getuint32(ssh);		    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(ssh, SSH2_MSG_CHANNEL_OPEN_FAILURE);		    ssh2_pkt_adduint32(ssh, c->remoteid);		    ssh2_pkt_adduint32(ssh, SSH2_OPEN_CONNECT_FAILED);		    ssh2_pkt_addstring(ssh, error);		    ssh2_pkt_addstring(ssh, "en");	/* language tag */		    ssh2_pkt_send(ssh);		    sfree(c);		} else {		    c->localid = alloc_channel_id(ssh);		    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(ssh, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);		    ssh2_pkt_adduint32(ssh, c->remoteid);		    ssh2_pkt_adduint32(ssh, c->localid);		    ssh2_pkt_adduint32(ssh, c->v.v2.locwindow);		    ssh2_pkt_adduint32(ssh, 0x4000UL);	/* our max pkt size */		    ssh2_pkt_send(ssh);		}	    } else {		bombout((ssh,"Strange packet received: type %d", ssh->pktin.type));		crReturnV;	    }	} else {	    /*	     * We have spare data. Add it to the channel buffer.	     */	    ssh2_add_channel_data(ssh->mainchan, 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++) {		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;}