} if (bufsize > SSH1_BUFFER_LIMIT) { c->v.v1.throttling = 1; ssh1_throttle(+1);
static void ssh1_protocol(unsigned char *in, int inlen, int ispkt){    crBegin;    random_init();    while (!do_ssh1_login(in, inlen, ispkt)) {	crReturnV;    }    if (ssh_state == SSH_STATE_CLOSED)	crReturnV;    if (cfg.agentfwd && agent_exists()) {	logevent("Requesting agent forwarding");	send_packet(SSH1_CMSG_AGENT_REQUEST_FORWARDING, PKT_END);	do {	    crReturnV;	} while (!ispkt);	if (pktin.type != SSH1_SMSG_SUCCESS	    && pktin.type != SSH1_SMSG_FAILURE) {	    bombout(("Protocol confusion"));	    crReturnV;	} else if (pktin.type == SSH1_SMSG_FAILURE) {	    logevent("Agent forwarding refused");	} else {	    logevent("Agent forwarding enabled");	    ssh_agentfwd_enabled = TRUE;	}    }    if (cfg.x11_forward) {	char proto[20], data[64];	logevent("Requesting X11 forwarding");	x11_invent_auth(proto, sizeof(proto), data, sizeof(data));	if (ssh1_local_protoflags & SSH1_PROTOFLAG_SCREEN_NUMBER) {	    send_packet(SSH1_CMSG_X11_REQUEST_FORWARDING,			PKT_STR, proto, PKT_STR, data,			PKT_INT, 0, PKT_END);	} else {	    send_packet(SSH1_CMSG_X11_REQUEST_FORWARDING,			PKT_STR, proto, PKT_STR, data, PKT_END);	}	do {	    crReturnV;	} while (!ispkt);	if (pktin.type != SSH1_SMSG_SUCCESS	    && pktin.type != SSH1_SMSG_FAILURE) {	    bombout(("Protocol confusion"));	    crReturnV;	} else if (pktin.type == SSH1_SMSG_FAILURE) {	    logevent("X11 forwarding refused");	} else {	    logevent("X11 forwarding enabled");	    ssh_X11_fwd_enabled = TRUE;	}    }    {	char type, *e;	int n;	int sport,dport;	char sports[256], dports[256], host[256];	char buf[1024];	ssh_rportfwds = newtree234(ssh_rportcmp_ssh1);        /* Add port forwardings. */	e = cfg.portfwd;	while (*e) {	    type = *e++;	    n = 0;	    while (*e && *e != '\t')		sports[n++] = *e++;	    sports[n] = 0;	    if (*e == '\t')		e++;	    n = 0;	    while (*e && *e != ':')		host[n++] = *e++;	    host[n] = 0;	    if (*e == ':')		e++;	    n = 0;	    while (*e)		dports[n++] = *e++;	    dports[n] = 0;	    e++;	    dport = atoi(dports);	    sport = atoi(sports);	    if (sport && dport) {		if (type == 'L') {		    pfd_addforward(host, dport, sport);		    sprintf(buf, "Local port %d forwarding to %s:%d",			    sport, host, dport);		    logevent(buf);		} else {		    struct ssh_rportfwd *pf;		    pf = smalloc(sizeof(*pf));		    strcpy(pf->dhost, host);		    pf->dport = dport;		    if (add234(ssh_rportfwds, pf) != pf) {			sprintf(buf, 				"Duplicate remote port forwarding to %s:%d",				host, dport);			logevent(buf);			sfree(pf);		    } else {			sprintf(buf, "Requesting remote port %d forward to %s:%d",				sport, host, dport);			logevent(buf);			send_packet(SSH1_CMSG_PORT_FORWARD_REQUEST,				    PKT_INT, sport,				    PKT_STR, host,				    PKT_INT, dport,				    PKT_END);		    }		}	    }	}    }    if (!cfg.nopty) {	send_packet(SSH1_CMSG_REQUEST_PTY,		    PKT_STR, cfg.termtype,		    PKT_INT, rows, PKT_INT, cols,		    PKT_INT, 0, PKT_INT, 0, PKT_CHAR, 0, PKT_END);	ssh_state = SSH_STATE_INTERMED;	do {	    crReturnV;	} while (!ispkt);	if (pktin.type != SSH1_SMSG_SUCCESS	    && pktin.type != SSH1_SMSG_FAILURE) {	    bombout(("Protocol confusion"));	    crReturnV;	} else if (pktin.type == SSH1_SMSG_FAILURE) {	    c_write_str("Server refused to allocate pty\r\n");	    ssh_editing = ssh_echoing = 1;	}	logevent("Allocated pty");    } else {	ssh_editing = ssh_echoing = 1;    }    if (cfg.compression) {	send_packet(SSH1_CMSG_REQUEST_COMPRESSION, PKT_INT, 6, PKT_END);	do {	    crReturnV;	} while (!ispkt);	if (pktin.type != SSH1_SMSG_SUCCESS	    && pktin.type != SSH1_SMSG_FAILURE) {	    bombout(("Protocol confusion"));	    crReturnV;	} else if (pktin.type == SSH1_SMSG_FAILURE) {	    c_write_str("Server refused to compress\r\n");	}	logevent("Started compression");	ssh1_compressing = TRUE;	zlib_compress_init();	zlib_decompress_init();    }    if (*cfg.remote_cmd_ptr)	send_packet(SSH1_CMSG_EXEC_CMD, PKT_STR, cfg.remote_cmd_ptr,		    PKT_END);    else	send_packet(SSH1_CMSG_EXEC_SHELL, PKT_END);    logevent("Started session");    ssh_state = SSH_STATE_SESSION;    if (size_needed)	ssh_size();    if (eof_needed)	ssh_special(TS_EOF);    ldisc_send(NULL, 0);	       /* cause ldisc to notice changes */    ssh_send_ok = 1;    ssh_channels = newtree234(ssh_channelcmp);    while (1) {	crReturnV;	if (ispkt) {	    if (pktin.type == SSH1_SMSG_STDOUT_DATA ||		pktin.type == SSH1_SMSG_STDERR_DATA) {		long len = GET_32BIT(pktin.body);		from_backend(pktin.type == SSH1_SMSG_STDERR_DATA,			     pktin.body + 4, len);	    } else if (pktin.type == SSH1_MSG_DISCONNECT) {		ssh_state = SSH_STATE_CLOSED;		logevent("Received disconnect request");		crReturnV;	    } else if (pktin.type == SSH1_SMSG_X11_OPEN) {		/* Remote side is trying to open a channel to talk to our		 * X-Server. Give them back a local channel number. */		struct ssh_channel *c;		logevent("Received X11 connect request");		/* Refuse if X11 forwarding is disabled. */		if (!ssh_X11_fwd_enabled) {		    send_packet(SSH1_MSG_CHANNEL_OPEN_FAILURE,				PKT_INT, GET_32BIT(pktin.body), PKT_END);		    logevent("Rejected X11 connect request");		} else {		    c = smalloc(sizeof(struct ssh_channel));		    if (x11_init(&c->u.x11.s, cfg.x11_display, c) != NULL) {			logevent("opening X11 forward connection failed");			sfree(c);			send_packet(SSH1_MSG_CHANNEL_OPEN_FAILURE,				    PKT_INT, GET_32BIT(pktin.body),				    PKT_END);		    } else {			logevent			    ("opening X11 forward connection succeeded");			c->remoteid = GET_32BIT(pktin.body);			c->localid = alloc_channel_id();			c->closes = 0;			c->type = CHAN_X11;	/* identify channel type */			add234(ssh_channels, c);			send_packet(SSH1_MSG_CHANNEL_OPEN_CONFIRMATION,				    PKT_INT, c->remoteid, PKT_INT,				    c->localid, PKT_END);			logevent("Opened X11 forward channel");		    }		}	    } else if (pktin.type == SSH1_SMSG_AGENT_OPEN) {		/* Remote side is trying to open a channel to talk to our		 * agent. Give them back a local channel number. */		struct ssh_channel *c;		/* Refuse if agent forwarding is disabled. */		if (!ssh_agentfwd_enabled) {		    send_packet(SSH1_MSG_CHANNEL_OPEN_FAILURE,				PKT_INT, GET_32BIT(pktin.body), PKT_END);		} else {		    c = smalloc(sizeof(struct ssh_channel));		    c->remoteid = GET_32BIT(pktin.body);		    c->localid = alloc_channel_id();		    c->closes = 0;		    c->type = CHAN_AGENT;	/* identify channel type */		    c->u.a.lensofar = 0;		    add234(ssh_channels, c);		    send_packet(SSH1_MSG_CHANNEL_OPEN_CONFIRMATION,				PKT_INT, c->remoteid, PKT_INT, c->localid,				PKT_END);		}	    } else if (pktin.type == SSH1_MSG_PORT_OPEN) {   		/* Remote side is trying to open a channel to talk to a		 * forwarded port. Give them back a local channel number. */		struct ssh_channel *c;		struct ssh_rportfwd pf;		int hostsize, port;		char host[256], buf[1024];		char *p, *h, *e;		c = smalloc(sizeof(struct ssh_channel));		hostsize = GET_32BIT(pktin.body+4);		for(h = host, p = pktin.body+8; hostsize != 0; hostsize--) {		    if (h+1 < host+sizeof(host))			*h++ = *p;		    p++;		}		*h = 0;		port = GET_32BIT(p);		strcpy(pf.dhost, host);		pf.dport = port;		if (find234(ssh_rportfwds, &pf, NULL) == NULL) {		    sprintf(buf, "Rejected remote port open request for %s:%d",			    host, port);		    logevent(buf);                    send_packet(SSH1_MSG_CHANNEL_OPEN_FAILURE,                                PKT_INT, GET_32BIT(pktin.body), PKT_END);		} else {		    sprintf(buf, "Received remote port open request for %s:%d",			    host, port);		    logevent(buf);		    e = pfd_newconnect(&c->u.pfd.s, host, port, c);		    if (e != NULL) {			char buf[256];			sprintf(buf, "Port open failed: %s", e);			logevent(buf);			sfree(c);			send_packet(SSH1_MSG_CHANNEL_OPEN_FAILURE,				    PKT_INT, GET_32BIT(pktin.body),				    PKT_END);		    } else {			c->remoteid = GET_32BIT(pktin.body);			c->localid = alloc_channel_id();			c->closes = 0;			c->type = CHAN_SOCKDATA;	/* identify channel type */			add234(ssh_channels, c);			send_packet(SSH1_MSG_CHANNEL_OPEN_CONFIRMATION,				    PKT_INT, c->remoteid, PKT_INT,				    c->localid, PKT_END);			logevent("Forwarded port opened successfully");		    }		}	    } else if (pktin.type == SSH1_MSG_CHANNEL_OPEN_CONFIRMATION) {		unsigned int remoteid = GET_32BIT(pktin.body);		unsigned int localid = GET_32BIT(pktin.body+4);		struct ssh_channel *c;		c = find234(ssh_channels, &remoteid, ssh_channelfind);		if (c && c->type == CHAN_SOCKDATA_DORMANT) {		    c->remoteid = localid;		    c->type = CHAN_SOCKDATA;		    pfd_confirm(c->u.pfd.s);		}	    } else if (pktin.type == SSH1_MSG_CHANNEL_CLOSE ||		       pktin.type == SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION) {		/* Remote side closes a channel. */		unsigned i = GET_32BIT(pktin.body);		struct ssh_channel *c;		c = find234(ssh_channels, &i, ssh_channelfind);		if (c) {		    int closetype;		    closetype =			(pktin.type == SSH1_MSG_CHANNEL_CLOSE ? 1 : 2);		    if (!(c->closes & closetype))			send_packet(pktin.type, PKT_INT, c->remoteid,				    PKT_END);		    if ((c->closes == 0) && (c->type == CHAN_X11)) {			logevent("Forwarded X11 connection terminated");			assert(c->u.x11.s != NULL);			x11_close(c->u.x11.s);			c->u.x11.s = NULL;		    }		    if ((c->closes == 0) && (c->type == CHAN_SOCKDATA)) {			logevent("Forwarded port closed");			assert(c->u.pfd.s != NULL);			pfd_close(c->u.pfd.s);			c->u.pfd.s = NULL;		    }		    c->closes |= closetype;		    if (c->closes == 3) {			del234(ssh_channels, c);			sfree(c);		    }		}	    } else if (pktin.type == SSH1_MSG_CHANNEL_DATA) {		/* Data sent down one of our channels. */		int i = GET_32BIT(pktin.body);		int len = GET_32BIT(pktin.body + 4);		unsigned char *p = pktin.body + 8;		struct ssh_channel *c;		c = find234(ssh_channels, &i, ssh_channelfind);		if (c) {		    switch (c->type) {		      case CHAN_X11:			x11_send(c->u.x11.s, p, len);			break;		      case CHAN_SOCKDATA:			pfd_send(c->u.pfd.s, p, len);			break;		      case CHAN_AGENT:			/* Data for an agent message. Buffer it. */			while (len > 0) {			    if (c->u.a.lensofar < 4) {				int l = min(4 - c->u.a.lensofar, len);				memcpy(c->u.a.msglen + c->u.a.lensofar, p,				       l);				p += l;				len -= 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 && len > 0) {				int l =				    min(c->u.a.totallen - c->u.a.lensofar,					len);				memcpy(c->u.a.message + c->u.a.lensofar, p,				       l);				p += l;				len -= 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;				}				send_packet(SSH1_MSG_CHANNEL_DATA,					    PKT_INT, c->remoteid,					    PKT_INT, replylen,					    PKT_DATA, sentreply, replylen,					    PKT_END);				if (reply)				    sfree(reply);				sfree(c->u.a.message);				c->u.a.lensofar = 0;			    }			}			break;		    }		}	    } else if (pktin.type == SSH1_SMSG_SUCCESS) {		/* may be from EXEC_SHELL on some servers */	    } else if (pktin.type == SSH1_SMSG_FAILURE) {		/* may be from EXEC_SHELL on some servers		 * if no pty is available or in other odd cases. Ignore */	    } else if (pktin.type == SSH1_SMSG_EXIT_STATUS) {		send_packet(SSH1_CMSG_EXIT_CONFIRMATION, PKT_END);	    } else {		bombout(("Strange packet received: type %d", pktin.type));		crReturnV;	    }	} else {	    while (inlen > 0) {		int len = min(inlen, 512);		send_packet(SSH1_CMSG_STDIN_DATA,			    PKT_INT, len, PKT_DATA, in, len, PKT_END);		in += len;		inlen -= len;	    }	}    }    crFinishV;}