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 < 40) { username[pos++] = c; c_write(&c, 1); } break; } }
if (ssh_get_line) { if (!ssh_get_line("login as: ", username, sizeof(username), FALSE)) {  logevent("No username provided. Abandoning session."); ssh_state = SSH_STATE_CLOSED; crReturn(1); } } 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 < 40) { username[pos++] = c; c_write(&c, 1); } break; } } }
static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt){    static unsigned long remote_winsize;    static unsigned long remote_maxpkt;    static enum {	AUTH_INVALID, AUTH_PUBLICKEY_AGENT, AUTH_PUBLICKEY_FILE, AUTH_PASSWORD    } method;    static enum {        AUTH_TYPE_NONE,        AUTH_TYPE_PUBLICKEY,        AUTH_TYPE_PUBLICKEY_OFFER_LOUD,        AUTH_TYPE_PUBLICKEY_OFFER_QUIET,        AUTH_TYPE_PASSWORD    } type;    static int gotit, need_pw, can_pubkey, can_passwd;    static int tried_pubkey_config, tried_agent;    static int we_are_in;    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) {	    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 < 40) {			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;	while (1) {	    /*	     * Wait for the result of the last authentication request.	     */	    if (!gotit)		crWaitUntilV(ispkt);	    while (pktin.type == SSH2_MSG_USERAUTH_BANNER) {		/* FIXME: should support this */		crWaitUntilV(ispkt);	    }	    if (pktin.type == SSH2_MSG_USERAUTH_SUCCESS) {		logevent("Access granted");		we_are_in = TRUE;		break;	    }	    if (pktin.type != SSH2_MSG_USERAUTH_FAILURE) {		bombout(("Strange packet received during authentication: type %d",			 pktin.type));	    }	    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.	     */	    {		char *methods;		int methlen;		ssh2_pkt_getstring(&methods, &methlen);		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 {			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);	    }	    method = 0;	    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) {		    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;			{ 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;			}			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, &ret, &retlen);			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_password) {		    if (!ssh_get_password(pwprompt, password, sizeof(password))) {			/*			 * get_password failed to get a password (for			 * example because one was supplied on the command			 * line which has already failed to work).			 * Terminate.			 */			logevent("No more passwords to try");			ssh_state = SSH_STATE_CLOSED;			crReturnV;		    }		} else {		    static int pos = 0;		    static char c;		    c_write_str(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 (((c >= ' ' && c <= '~') ||				 ((unsigned char)c >= 160)) && pos < 40)				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 {		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.     */    mainchan = smalloc(sizeof(struct ssh_channel));    mainchan->localid = 100;           /* as good as any */    ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN);    ssh2_pkt_addstring("session");    ssh2_pkt_adduint32(mainchan->localid);    ssh2_pkt_adduint32(0x8000UL);  /* our window size */    ssh2_pkt_adduint32(0x4000UL);  /* our max pkt size */    ssh2_pkt_send();    crWaitUntilV(ispkt);    if (pktin.type != SSH2_MSG_CHANNEL_OPEN_CONFIRMATION) {        bombout(("Server refused to open a session"));        crReturnV;        /* FIXME: error data comes back in FAILURE packet */    }    if (ssh2_pkt_getuint32() != mainchan->localid) {        bombout(("Server's channel confirmation cited wrong channel"));        crReturnV;    }    mainchan->remoteid = ssh2_pkt_getuint32();    mainchan->type = CHAN_MAINSESSION;    mainchan->closes = 0;    mainchan->v2.remwindow = ssh2_pkt_getuint32();    mainchan->v2.remmaxpkt = ssh2_pkt_getuint32();    mainchan->v2.outbuffer = NULL;    mainchan->v2.outbuflen = mainchan->v2.outbufsize = 0;    ssh_channels = newtree234(ssh_channelcmp);    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->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;        }    }    /*     * Potentially enable agent forwarding.     */    if (cfg.agentfwd && agent_exists()) {        char proto[20], data[64];        logevent("Requesting OpenSSH-style agent 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("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->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->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.     */    ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);    ssh2_pkt_adduint32(mainchan->remoteid); /* recipient channel */    if (cfg.ssh_subsys) {        ssh2_pkt_addstring("subsystem");        ssh2_pkt_addbool(1);           /* want reply */        ssh2_pkt_addstring(cfg.remote_cmd);    } else if (*cfg.remote_cmd) {        ssh2_pkt_addstring("exec");        ssh2_pkt_addbool(1);           /* want reply */        ssh2_pkt_addstring(cfg.remote_cmd);    } else {        ssh2_pkt_addstring("shell");        ssh2_pkt_addbool(1);           /* want reply */    }    ssh2_pkt_send();    do {        crWaitUntilV(ispkt);        if (pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST) {            unsigned i = ssh2_pkt_getuint32();            struct ssh_channel *c;            c = find234(ssh_channels, &i, ssh_channelfind);            if (!c)                continue;              /* nonexistent channel */            c->v2.remwindow += ssh2_pkt_getuint32();        }    } while (pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST);    if (pktin.type != SSH2_MSG_CHANNEL_SUCCESS) {        if (pktin.type != SSH2_MSG_CHANNEL_FAILURE) {            bombout(("Server got confused by shell/command request"));            crReturnV;        }        bombout(("Server refused to start a shell/command"));        crReturnV;    } else {        logevent("Started a shell/command");    }    ssh_state = SSH_STATE_SESSION;    if (size_needed)	ssh_size();    if (eof_needed)        ssh_special(TS_EOF);    /*     * Transfer data!     */    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) {                    switch (c->type) {                      case CHAN_MAINSESSION:                        from_backend(pktin.type == SSH2_MSG_CHANNEL_EXTENDED_DATA,                                     data, length);                        break;                      case CHAN_X11:                        x11_send(c->u.x11.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;                            }                        }                        break;                    }                    /*                     * Enlarge the window again at the remote                     * side, just in case it ever runs down and                     * they fail to send us any more data.                     */                    ssh2_pkt_init(SSH2_MSG_CHANNEL_WINDOW_ADJUST);                    ssh2_pkt_adduint32(c->remoteid);                    ssh2_pkt_adduint32(length);                    ssh2_pkt_send();                }	    } else if (pktin.type == SSH2_MSG_DISCONNECT) {                ssh_state = SSH_STATE_CLOSED;		logevent("Received disconnect message");                crReturnV;	    } else if (pktin.type == SSH2_MSG_CHANNEL_REQUEST) {                continue;              /* exit status et al; ignore (FIXME?) */	    } else if (pktin.type == SSH2_MSG_CHANNEL_EOF) {                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 (pktin.type == SSH2_MSG_CHANNEL_CLOSE) {                unsigned i = ssh2_pkt_getuint32();                struct ssh_channel *c;                enum234 e;                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;                }                del234(ssh_channels, c);                sfree(c->v2.outbuffer);                sfree(c);                /*                 * See if that was the last channel left open.                 */                c = first234(ssh_channels, &e);                if (!c) {                    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 */                mainchan->v2.remwindow += ssh2_pkt_getuint32();                try_send = TRUE;	    } else if (pktin.type == SSH2_MSG_CHANNEL_OPEN) {                char *type;                int typelen;                char *error = NULL;                struct ssh_channel *c;                ssh2_pkt_getstring(&type, &typelen);                c = smalloc(sizeof(struct ssh_channel));                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 == 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 = ssh2_pkt_getuint32();                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 {                    struct ssh_channel *d;                    unsigned i;                    enum234 e;                    for (i=1, d = first234(ssh_channels, &e); d;                         d = next234(&e)) {			if (d->localid > i)                            break;     /* found a free number */			i = d->localid + 1;                    }                    c->localid = i;                    c->closes = 0;                    c->v2.remwindow = ssh2_pkt_getuint32();                    c->v2.remmaxpkt = ssh2_pkt_getuint32();                    c->v2.outbuffer = NULL;                    c->v2.outbuflen = c->v2.outbufsize = 0;                    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(0x8000UL);  /* our window size */                    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) {            enum234 e;            struct ssh_channel *c;            /*             * Try to send data on all channels if we can.             */            for (c = first234(ssh_channels, &e); c; c = next234(&e))                ssh2_try_send(c);        }    }    crFinishV;}