{ static int pos = 0;
do { static int pos;
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 int gotit, need_pw, can_pubkey, can_passwd, tried_pubkey_config;    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;    }    /*     * Get a username.     */    {	static int pos = 0;	static char c;	if ((flags & FLAG_INTERACTIVE) && !*cfg.username) {	    c_write("login as: ", 10);	    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("\b \b", 3);			pos--;		    }		    break;		  case 21: case 27:		    while (pos > 0) {			c_write("\b \b", 3);			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("\r\n", 2);	    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(stuff, strlen(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();    logevent("Attempting null authentication");    gotit = 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");	    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()) {		/*		 * FIXME: these messages are often inappropriate.		 */		c_write("Access denied\r\n", 15);		logevent("Access denied");	    } else {		c_write("Authentication partially successful\r\n", 37);		logevent("Authentication partially successful");	    }	    can_pubkey = in_commasep_string("publickey", methods, methlen);	    can_passwd = in_commasep_string("password", methods, methlen);	}	method = 0;	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;		    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;		}		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(pwprompt, strlen(pwprompt));		ssh_send_ok = 1;		pos = 0;		while (pos >= 0) {		    crWaitUntilV(!ispkt);		    while (inlen--) switch (c = *in++) {		      case 10: case 13:			password[pos] = 0;			pos = -1;			break;		      case 8: case 127:			if (pos > 0)			    pos--;			break;		      case 21: case 27:			pos = 0;			break;		      case 3: case 4:			random_save_seed();			exit(0);			break;		      default:			if (((c >= ' ' && c <= '~') ||			     ((unsigned char)c >= 160)) && pos < 40)			    password[pos++] = c;			break;		    }		}		c_write("\r\n", 2);	    }	}	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) {		c_write("Wrong passphrase\r\n", 18);		tried_pubkey_config = FALSE;		/* 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();	    } else if (key == NULL) {		c_write("Unable to load private key\r\n",28);		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();	    } 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();	    }	} 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 i, j;		ssh2_pkt_init(SSH2_MSG_IGNORE);		ssh2_pkt_addstring_start();		for (i = deferred_len; i <= 256; i += cscipher->blksize) {		    for (j = 0; j < cscipher->blksize; j++) {			char c = (char)random_byte();			ssh2_pkt_addstring_data(&c, 1);		    }		}		ssh2_pkt_defer();	    }	    ssh2_pkt_defersend();	} else {	    c_write("No supported authentication methods left to try!\r\n", 50);	    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;	}    }    /*     * 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;        }    }    /*     * 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("Server refused to allocate pty\r\n", 32);            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;                    }                    /*                     * 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 (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;                }                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 {                    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;}