if (s->kbd_inter_running && pktin->type == SSH2_MSG_USERAUTH_INFO_REQUEST) {  if (!s->gotit) s->curr_prompt = 0; } else if (pktin->type == SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ) {
if (pktin->type == SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ) {
static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,			     struct Packet *pktin){    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 done_service_req;	int gotit, need_pw, can_pubkey, can_passwd, can_keyb_inter;	int tried_pubkey_config, tried_agent;	int kbd_inter_running, kbd_inter_refused;	int we_are_in;	int num_prompts, curr_prompt, echo;	char username[100];	int got_username;	char pwprompt[512];	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;	int num_env, env_left, env_ok;	struct Packet *pktout;    };    crState(do_ssh2_authconn_state);    crBegin(ssh->do_ssh2_authconn_crstate);    s->done_service_req = FALSE;    s->we_are_in = FALSE;    if (!ssh->cfg.ssh_no_userauth) {	/*	 * Request userauth protocol, and await a response to it.	 */	s->pktout = ssh2_pkt_init(SSH2_MSG_SERVICE_REQUEST);	ssh2_pkt_addstring(s->pktout, "ssh-userauth");	ssh2_pkt_send(ssh, s->pktout);	crWaitUntilV(pktin);	if (pktin->type == SSH2_MSG_SERVICE_ACCEPT)	    s->done_service_req = TRUE;    }    if (!s->done_service_req) {	/*	 * Request connection protocol directly, without authentication.	 */	s->pktout = ssh2_pkt_init(SSH2_MSG_SERVICE_REQUEST);	ssh2_pkt_addstring(s->pktout, "ssh-connection");	ssh2_pkt_send(ssh, s->pktout);	crWaitUntilV(pktin);	if (pktin->type == SSH2_MSG_SERVICE_ACCEPT) {	    s->we_are_in = TRUE; /* no auth required */	} else {	    bombout(("Server refused service request"));	    crStopV;	}    }    /*     * 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;    bufchain_init(&ssh->banner);    ssh->packet_dispatch[SSH2_MSG_USERAUTH_BANNER] =	ssh2_msg_userauth_banner;    while (!s->we_are_in) {	/*	 * Get a username.	 */	if (s->got_username && !ssh->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 (!*ssh->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.		     */		    ssh_disconnect(ssh, "No username provided", NULL, 0, TRUE);		    crStopV;		}	    } 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(!pktin);		    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;	    strncpy(s->username, ssh->cfg.username, sizeof(s->username));	    s->username[sizeof(s->username)-1] = '\0';	    if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE)) {		stuff = dupprintf("Using username \"%s\".\r\n", s->username);		c_write_str(ssh, stuff);		sfree(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;	s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);	ssh2_pkt_addstring(s->pktout, s->username);	ssh2_pkt_addstring(s->pktout, "ssh-connection");/* service requested */	ssh2_pkt_addstring(s->pktout, "none");    /* method */	ssh2_pkt_send(ssh, s->pktout);	s->type = AUTH_TYPE_NONE;	s->gotit = FALSE;	s->we_are_in = FALSE;	s->tried_pubkey_config = FALSE;	s->tried_agent = FALSE;	s->kbd_inter_running = FALSE;	s->kbd_inter_refused = FALSE;	/* Load the pub half of ssh->cfg.keyfile so we notice if it's in Pageant */	if (!filename_is_null(ssh->cfg.keyfile)) {	    int keytype;	    logeventf(ssh, "Reading private key file \"%.150s\"",		      filename_to_str(&ssh->cfg.keyfile));	    keytype = key_type(&ssh->cfg.keyfile);	    if (keytype == SSH_KEYTYPE_SSH2) {		s->publickey_blob =		    ssh2_userkey_loadpub(&ssh->cfg.keyfile, NULL,					 &s->publickey_bloblen, NULL, NULL);	    } else {		char *msgbuf;		logeventf(ssh, "Unable to use this key file (%s)",			  key_type_to_str(keytype));		msgbuf = dupprintf("Unable to use key file \"%.150s\""				   " (%s)\r\n",				   filename_to_str(&ssh->cfg.keyfile),				   key_type_to_str(keytype));		c_write_str(ssh, msgbuf);		sfree(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(pktin);	    /*	     * Now is a convenient point to spew any banner material	     * that we've accumulated. (This should ensure that when	     * we exit the auth loop, we haven't any left to deal	     * with.)	     */	    {		int size = bufchain_size(&ssh->banner);		/*		 * 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 (size && (flags & (FLAG_VERBOSE | FLAG_INTERACTIVE))) {		    char *banner = snewn(size, char);		    bufchain_fetch(&ssh->banner, banner, size);		    c_write_untrusted(ssh, banner, size);		    sfree(banner);		}		bufchain_clear(&ssh->banner);	    }	    if (pktin->type == SSH2_MSG_USERAUTH_SUCCESS) {		logevent("Access granted");		s->we_are_in = TRUE;		break;	    }	    if (s->kbd_inter_running &&		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 (pktin->type == SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ) {		/* FIXME: perhaps we should support this? */		bombout(("PASSWD_CHANGEREQ not yet supported"));		crStopV;	    } else if (pktin->type != SSH2_MSG_USERAUTH_FAILURE) {		bombout(("Strange packet received during authentication: type %d",			 pktin->type));		crStopV;	    }	    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 (pktin->type == SSH2_MSG_USERAUTH_FAILURE) {		char *methods;		int methlen;		ssh_pkt_getstring(pktin, &methods, &methlen);		s->kbd_inter_running = FALSE;		if (!ssh2_pkt_getbool(pktin)) {		    /*		     * 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 (iff we're configured to allow		     * username change attempts).		     */		    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 &&			    ssh->cfg.change_username) {			    /* XXX perhaps we should allow			     * keyboard-interactive to do this too? */			    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 = ssh->cfg.try_ki_auth &&		    in_commasep_string("keyboard-interactive", methods, methlen);	    }	    s->method = 0;	    ssh->pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;	    s->need_pw = FALSE;	    /*	     * 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;		if (!agent_query(s->request, 5, &r, &s->responselen,				 ssh_agent_callback, ssh)) {		    do {			crReturnV;			if (pktin) {			    bombout(("Unexpected data from server while"				     " waiting for agent response"));			    crStopV;			}		    } while (pktin || inlen > 0);		    r = ssh->agent_response;		    s->responselen = ssh->agent_response_len;		}		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;		    logeventf(ssh, "Pageant has %d SSH-2 keys", s->nkeys);		    for (s->keyi = 0; s->keyi < s->nkeys; s->keyi++) {			void *vret;			logeventf(ssh, "Trying Pageant key #%d", s->keyi);			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 = (char *)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 = (char *)s->p;			s->p += s->commentlen;			s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);			ssh2_pkt_addstring(s->pktout, s->username);			ssh2_pkt_addstring(s->pktout, "ssh-connection");	/* service requested */			ssh2_pkt_addstring(s->pktout, "publickey");	/* method */			ssh2_pkt_addbool(s->pktout, FALSE);	/* no signature included */			ssh2_pkt_addstring_start(s->pktout);			ssh2_pkt_addstring_data(s->pktout, s->alg, s->alglen);			ssh2_pkt_addstring_start(s->pktout);			ssh2_pkt_addstring_data(s->pktout, s->pkblob, s->pklen);			ssh2_pkt_send(ssh, s->pktout);			crWaitUntilV(pktin);			if (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.			 */			s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);			ssh2_pkt_addstring(s->pktout, s->username);			ssh2_pkt_addstring(s->pktout, "ssh-connection");	/* service requested */			ssh2_pkt_addstring(s->pktout, "publickey");	/* method */			ssh2_pkt_addbool(s->pktout, TRUE);			ssh2_pkt_addstring_start(s->pktout);			ssh2_pkt_addstring_data(s->pktout, s->alg, s->alglen);			ssh2_pkt_addstring_start(s->pktout);			ssh2_pkt_addstring_data(s->pktout, s->pkblob, s->pklen);			s->siglen = s->pktout->length - 5 + 4 +			    ssh->v2_session_id_len;                        if (ssh->remote_bugs & BUG_SSH2_PK_SESSIONID)                            s->siglen -= 4;			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 = snewn(4 + s->len, char);			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... */                        if (!(ssh->remote_bugs & BUG_SSH2_PK_SESSIONID)) {                            PUT_32BIT(s->q, ssh->v2_session_id_len);                            s->q += 4;                        }			memcpy(s->q, ssh->v2_session_id,			       ssh->v2_session_id_len);			s->q += ssh->v2_session_id_len;			memcpy(s->q, s->pktout->data + 5,			       s->pktout->length - 5);			s->q += s->pktout->length - 5;			/* And finally the (zero) flags word. */			PUT_32BIT(s->q, 0);			if (!agent_query(s->agentreq, s->len + 4,					 &vret, &s->retlen,					 ssh_agent_callback, ssh)) {			    do {				crReturnV;				if (pktin) {				    bombout(("Unexpected data from server"					     " while waiting for agent"					     " response"));				    crStopV;				}			    } while (pktin || inlen > 0);			    vret = ssh->agent_response;			    s->retlen = ssh->agent_response_len;			}			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->pktout,						 s->pkblob, s->pklen,						 s->ret + 9,						 GET_32BIT(s->ret + 5));				ssh2_pkt_send(ssh, s->pktout);				s->authed = TRUE;				break;			    } else {				logevent				    ("Pageant failed to answer challenge");				sfree(s->ret);			    }			}		    }		    if (s->authed)			continue;		}		sfree(s->response);	    }	    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 =		    (unsigned char *)ssh2_userkey_loadpub(&ssh->cfg.keyfile,							  &algorithm,							  &pub_blob_len,							  NULL, NULL);		if (pub_blob) {		    s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);		    ssh2_pkt_addstring(s->pktout, s->username);		    ssh2_pkt_addstring(s->pktout, "ssh-connection");	/* service requested */		    ssh2_pkt_addstring(s->pktout, "publickey");	/* method */		    ssh2_pkt_addbool(s->pktout, FALSE);	/* no signature included */		    ssh2_pkt_addstring(s->pktout, algorithm);		    ssh2_pkt_addstring_start(s->pktout);		    ssh2_pkt_addstring_data(s->pktout, (char *)pub_blob,					    pub_blob_len);		    ssh2_pkt_send(ssh, s->pktout);		    logevent("Offered public key");		    crWaitUntilV(pktin);		    if (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(&ssh->cfg.keyfile, &comment)) {			sprintf(s->pwprompt,				"Passphrase for key \"%.100s\": ",				comment);			s->need_pw = TRUE;		    } else {			s->need_pw = FALSE;		    }		    if (flags & FLAG_VERBOSE) {			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->kbd_inter_refused &&		!s->kbd_inter_running) {		s->method = AUTH_KEYBOARD_INTERACTIVE;		s->type = AUTH_TYPE_KEYBOARD_INTERACTIVE;		ssh->pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;		ssh->pkt_ctx |= SSH2_PKTCTX_KBDINTER;		s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);		ssh2_pkt_addstring(s->pktout, s->username);		ssh2_pkt_addstring(s->pktout, "ssh-connection");	/* service requested */		ssh2_pkt_addstring(s->pktout, "keyboard-interactive");	/* method */		ssh2_pkt_addstring(s->pktout, ""); /* lang */		ssh2_pkt_addstring(s->pktout, "");		ssh2_pkt_send(ssh, s->pktout);		crWaitUntilV(pktin);		if (pktin->type != SSH2_MSG_USERAUTH_INFO_REQUEST) {		    if (pktin->type == SSH2_MSG_USERAUTH_FAILURE)			s->gotit = TRUE;		    logevent("Keyboard-interactive authentication refused");		    s->type = AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET;		    s->kbd_inter_refused = TRUE; /* don't try it again */		    continue;		}		c_write_str(ssh, "Using keyboard-interactive authentication.\r\n");		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;		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;		    ssh_pkt_getstring(pktin, &name, &name_len);		    ssh_pkt_getstring(pktin, &inst, &inst_len);		    ssh_pkt_getstring(pktin, &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 = ssh_pkt_getuint32(pktin);		}		/*		 * 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;		    ssh_pkt_getstring(pktin, &prompt, &prompt_len);		    if (prompt_len > 0) {			static const char trunc[] = "<prompt truncated>: ";			static const int prlen = sizeof(s->pwprompt) -						 lenof(trunc);			if (prompt_len > prlen) {			    memcpy(s->pwprompt, prompt, prlen);			    strcpy(s->pwprompt + prlen, trunc);			} else {			    memcpy(s->pwprompt, prompt, prompt_len);			    s->pwprompt[prompt_len] = '\0';			}		    } else {			strcpy(s->pwprompt,			       "<server failed to send prompt>: ");		    }		    s->echo = ssh2_pkt_getbool(pktin);		    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.			 */			ssh_disconnect(ssh, NULL, "Unable to authenticate",				       SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER,				       FALSE);			crStopV;		    }		} 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(!pktin);			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;		const char *error = NULL;		key = ssh2_load_userkey(&ssh->cfg.keyfile, s->password,					&error);		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 (");			c_write_str(ssh, error);			c_write_str(ssh, ")\r\n");			s->tried_pubkey_config = TRUE;		    }		    /* Send a spurious AUTH_NONE to return to the top. */		    s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);		    ssh2_pkt_addstring(s->pktout, s->username);		    ssh2_pkt_addstring(s->pktout, "ssh-connection");	/* service requested */		    ssh2_pkt_addstring(s->pktout, "none");	/* method */		    ssh2_pkt_send(ssh, s->pktout);		    s->type = AUTH_TYPE_NONE;		} else {		    unsigned char *pkblob, *sigblob, *sigdata;		    int pkblob_len, sigblob_len, sigdata_len;                    int p;		    /*		     * 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.		     */		    s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);		    ssh2_pkt_addstring(s->pktout, s->username);		    ssh2_pkt_addstring(s->pktout, "ssh-connection");	/* service requested */		    ssh2_pkt_addstring(s->pktout, "publickey");	/* method */		    ssh2_pkt_addbool(s->pktout, TRUE);		    ssh2_pkt_addstring(s->pktout, key->alg->name);		    pkblob = key->alg->public_blob(key->data, &pkblob_len);		    ssh2_pkt_addstring_start(s->pktout);		    ssh2_pkt_addstring_data(s->pktout, (char *)pkblob, pkblob_len);		    /*		     * The data to be signed is:		     *		     *   string  session-id		     *		     * followed by everything so far placed in the		     * outgoing packet.		     */		    sigdata_len = s->pktout->length - 5 + 4 +			ssh->v2_session_id_len;                    if (ssh->remote_bugs & BUG_SSH2_PK_SESSIONID)                        sigdata_len -= 4;		    sigdata = snewn(sigdata_len, unsigned char);                    p = 0;                    if (!(ssh->remote_bugs & BUG_SSH2_PK_SESSIONID)) {                        PUT_32BIT(sigdata+p, ssh->v2_session_id_len);                        p += 4;                    }		    memcpy(sigdata+p, ssh->v2_session_id,			   ssh->v2_session_id_len);		    p += ssh->v2_session_id_len;		    memcpy(sigdata+p, s->pktout->data + 5,			   s->pktout->length - 5);                    p += s->pktout->length - 5;                    assert(p == sigdata_len);		    sigblob = key->alg->sign(key->data, (char *)sigdata,					     sigdata_len, &sigblob_len);		    ssh2_add_sigblob(ssh, s->pktout, pkblob, pkblob_len,				     sigblob, sigblob_len);		    sfree(pkblob);		    sfree(sigblob);		    sfree(sigdata);		    ssh2_pkt_send(ssh, s->pktout);		    s->type = AUTH_TYPE_PUBLICKEY;		    key->alg->freekey(key->data);		}	    } else if (s->method == AUTH_PASSWORD) {		/*		 * We pad out the password packet to 256 bytes to make		 * it harder for an attacker to find the length of the		 * user's password.		 *		 * Anyone using a password longer than 256 bytes		 * probably doesn't have much to worry about from		 * people who find out how long their password is!		 */		s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);		s->pktout->forcepad = 256;		ssh2_pkt_addstring(s->pktout, s->username);		ssh2_pkt_addstring(s->pktout, "ssh-connection");	/* service requested */		ssh2_pkt_addstring(s->pktout, "password");		ssh2_pkt_addbool(s->pktout, FALSE);		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);		ssh2_pkt_send(ssh, s->pktout);		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);		    s->pktout->forcepad = 256;		    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 {		ssh_disconnect(ssh, NULL,			       "No supported authentication methods available",			       SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE,			       FALSE);		crStopV;	    }	}    }    ssh->packet_dispatch[SSH2_MSG_USERAUTH_BANNER] = NULL;    /*     * Now the connection protocol has started, one way or another.     */    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, OUR_V2_MAXPKT);    /* 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->halfopen = FALSE;	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);	/*	 * Note that while we blank the X authentication data here, we don't	 * take any special action to blank the start of an X11 channel,	 * so using MIT-MAGIC-COOKIE-1 and actually opening an X connection	 * without having session blanking enabled is likely to leak your	 * cookie into the log.	 */	dont_log_password(ssh, s->pktout, PKTLOG_BLANK);	ssh2_pkt_addstring(s->pktout, data);	end_log_omission(ssh, s->pktout);	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.     */    ssh_setup_portfwd(ssh, &ssh->cfg);    /*     * Potentially enable agent forwarding.     */    if (ssh->mainchan && ssh->cfg.agentfwd && agent_exists()) {	logevent("Requesting OpenSSH-style agent forwarding");	s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);	ssh2_pkt_adduint32(s->pktout, ssh->mainchan->remoteid);	ssh2_pkt_addstring(s->pktout, "auth-agent-req@openssh.com");	ssh2_pkt_addbool(s->pktout, 1);	       /* want reply */	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 agent forwarding request:"			 " packet type %d", pktin->type));		crStopV;	    }	    logevent("Agent forwarding refused");	} else {	    logevent("Agent forwarding enabled");	    ssh->agentfwd_enabled = TRUE;	}    }    /*     * Now allocate a pty for the session.     */    if (ssh->mainchan && !ssh->cfg.nopty) {	/* Unpick the terminal-speed string. */	/* XXX perhaps we should allow no speeds to be sent. */        ssh->ospeed = 38400; ssh->ispeed = 38400; /* last-resort defaults */	sscanf(ssh->cfg.termspeed, "%d,%d", &ssh->ospeed, &ssh->ispeed);	/* Build the pty request. */	s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);	ssh2_pkt_adduint32(s->pktout, ssh->mainchan->remoteid);	/* recipient channel */	ssh2_pkt_addstring(s->pktout, "pty-req");	ssh2_pkt_addbool(s->pktout, 1);	       /* want reply */	ssh2_pkt_addstring(s->pktout, ssh->cfg.termtype);	ssh2_pkt_adduint32(s->pktout, ssh->term_width);	ssh2_pkt_adduint32(s->pktout, ssh->term_height);	ssh2_pkt_adduint32(s->pktout, 0);	       /* pixel width */	ssh2_pkt_adduint32(s->pktout, 0);	       /* pixel height */	ssh2_pkt_addstring_start(s->pktout);	parse_ttymodes(ssh, ssh->cfg.ttymodes,		       ssh2_send_ttymode, (void *)s->pktout);	ssh2_pkt_addbyte(s->pktout, SSH2_TTY_OP_ISPEED);	ssh2_pkt_adduint32(s->pktout, ssh->ispeed);	ssh2_pkt_addbyte(s->pktout, SSH2_TTY_OP_OSPEED);	ssh2_pkt_adduint32(s->pktout, ssh->ospeed);	ssh2_pkt_addstring_data(s->pktout, "\0", 1); /* TTY_OP_END */	ssh2_pkt_send(ssh, s->pktout);	ssh->state = SSH_STATE_INTERMED;	crWaitUntilV(pktin);	if (pktin->type != SSH2_MSG_CHANNEL_SUCCESS) {	    if (pktin->type != SSH2_MSG_CHANNEL_FAILURE) {		bombout(("Unexpected response to pty request:"			 " packet type %d", pktin->type));		crStopV;	    }	    c_write_str(ssh, "Server refused to allocate pty\r\n");	    ssh->editing = ssh->echoing = 1;	} else {	    logeventf(ssh, "Allocated pty (ospeed %dbps, ispeed %dbps)",		      ssh->ospeed, ssh->ispeed);	}    } else {	ssh->editing = ssh->echoing = 1;    }    /*     * Send environment variables.     *      * Simplest thing here is to send all the requests at once, and     * then wait for a whole bunch of successes or failures.     */    if (ssh->mainchan && *ssh->cfg.environmt) {	char *e = ssh->cfg.environmt;	char *var, *varend, *val;	s->num_env = 0;	while (*e) {	    var = e;	    while (*e && *e != '\t') e++;	    varend = e;	    if (*e == '\t') e++;	    val = e;	    while (*e) e++;	    e++;	    s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);	    ssh2_pkt_adduint32(s->pktout, ssh->mainchan->remoteid);	    ssh2_pkt_addstring(s->pktout, "env");	    ssh2_pkt_addbool(s->pktout, 1);	       /* want reply */	    ssh2_pkt_addstring_start(s->pktout);	    ssh2_pkt_addstring_data(s->pktout, var, varend-var);	    ssh2_pkt_addstring(s->pktout, val);	    ssh2_pkt_send(ssh, s->pktout);	    s->num_env++;	}	logeventf(ssh, "Sent %d environment variables", s->num_env);	s->env_ok = 0;	s->env_left = s->num_env;	while (s->env_left > 0) {	    crWaitUntilV(pktin);	    if (pktin->type != SSH2_MSG_CHANNEL_SUCCESS) {		if (pktin->type != SSH2_MSG_CHANNEL_FAILURE) {		    bombout(("Unexpected response to environment request:"			     " packet type %d", pktin->type));		    crStopV;		}	    } else {		s->env_ok++;	    }	    s->env_left--;	}	if (s->env_ok == s->num_env) {	    logevent("All environment variables successfully set");	} else if (s->env_ok == 0) {	    logevent("All environment variables refused");	    c_write_str(ssh, "Server refused to set environment variables\r\n");	} else {	    logeventf(ssh, "%d environment variables refused",		      s->num_env - s->env_ok);	    c_write_str(ssh, "Server refused to set all environment variables\r\n");	}    }    /*     * 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.     */    if (ssh->mainchan) while (1) {	int subsys;	char *cmd;	if (ssh->fallback_cmd) {	    subsys = ssh->cfg.ssh_subsys2;	    cmd = ssh->cfg.remote_cmd_ptr2;	} else {	    subsys = ssh->cfg.ssh_subsys;	    cmd = ssh->cfg.remote_cmd_ptr;	    if (!cmd) cmd = ssh->cfg.remote_cmd;	}	s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);	ssh2_pkt_adduint32(s->pktout, ssh->mainchan->remoteid);	/* recipient channel */	if (subsys) {	    ssh2_pkt_addstring(s->pktout, "subsystem");	    ssh2_pkt_addbool(s->pktout, 1);	       /* want reply */	    ssh2_pkt_addstring(s->pktout, cmd);	} else if (*cmd) {	    ssh2_pkt_addstring(s->pktout, "exec");	    ssh2_pkt_addbool(s->pktout, 1);	       /* want reply */	    ssh2_pkt_addstring(s->pktout, cmd);	} else {	    ssh2_pkt_addstring(s->pktout, "shell");	    ssh2_pkt_addbool(s->pktout, 1);	       /* want reply */	}	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 shell/command request:"			 " packet type %d", pktin->type));		crStopV;	    }	    /*	     * 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 && ssh->cfg.remote_cmd_ptr2 != NULL) {		logevent("Primary command failed; attempting fallback");		ssh->fallback_cmd = TRUE;		continue;	    }	    bombout(("Server refused to start a shell/command"));	    crStopV;	} 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 */    if (ssh->mainchan)	ssh->send_ok = 1;    while (1) {	crReturnV;	s->try_send = FALSE;	if (pktin) {	    /*	     * _All_ the connection-layer packets we expect to	     * receive are now handled by the dispatch table.	     * Anything that reaches here must be bogus.	     */	    bombout(("Strange packet received: type %d", pktin->type));	    crStopV;	} else if (ssh->mainchan) {	    /*	     * We have spare data. Add it to the channel buffer.	     */	    ssh2_add_channel_data(ssh->mainchan, (char *)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++)		ssh2_try_send_and_unthrottle(c);	}    }    crFinishV;}