示例#1
0
int sub_check(struct session *sp,char c)
{
    if(his_state_is_wont(sp,c))
    {
        sp->sub_state=SSEND;
    }
    return 1;
}
示例#2
0
void send_dont(int option, int init) {
    if (init) {
        if ((do_dont_resp[option] == 0 && his_state_is_wont(option)) ||
                his_want_state_is_wont(option))
            return;
        set_his_want_state_wont(option);
        do_dont_resp[option]++;
    }
    netoprintf((char *) dont, option);

    DIAG(TD_OPTIONS, printoption("td: send dont", option));
}
示例#3
0
static void
_gettermname(void)
{
    /*
     * If the client turned off the option,
     * we can't send another request, so we
     * just return.
     */
    if (his_state_is_wont(TELOPT_TTYPE))
	return;
    settimer(baseline);
    netoprintf("%c%c%c%c%c%c", IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE);
    while (sequenceIs(ttypesubopt, baseline))
	ttloop();
}
示例#4
0
static
void
_gettermname(void)
{
    /*
     * If the client turned off the option,
     * we can't send another request, so we
     * just return.
     */
    if (his_state_is_wont(TELOPT_TTYPE))
	return;
    settimer(baseline);
    bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf);
    nfrontp += sizeof ttytype_sbbuf;
    while (sequenceIs(ttypesubopt, baseline))
	ttloop();
}
示例#5
0
static
int
getterminaltype(char *name)
{
    int retval = -1;
    (void)name;

    settimer(baseline);
#if defined(AUTHENTICATE)
    /*
     * Handle the Authentication option before we do anything else.
     */
    send_do(TELOPT_AUTHENTICATION, 1);
    while (his_will_wont_is_changing(TELOPT_AUTHENTICATION))
	ttloop();
    if (his_state_is_will(TELOPT_AUTHENTICATION)) {
	retval = auth_wait(name);
    }
#endif

#if	defined(ENCRYPT)
    send_will(TELOPT_ENCRYPT, 1);
#endif
    send_do(TELOPT_TTYPE, 1);
    send_do(TELOPT_TSPEED, 1);
    send_do(TELOPT_XDISPLOC, 1);
    send_do(TELOPT_ENVIRON, 1);
    while (
#if	defined(ENCRYPT)
	   his_do_dont_is_changing(TELOPT_ENCRYPT) ||
#endif
	   his_will_wont_is_changing(TELOPT_TTYPE) ||
	   his_will_wont_is_changing(TELOPT_TSPEED) ||
	   his_will_wont_is_changing(TELOPT_XDISPLOC) ||
	   his_will_wont_is_changing(TELOPT_ENVIRON)) {
	ttloop();
    }
#if	defined(ENCRYPT)
    /*
     * Wait for the negotiation of what type of encryption we can
     * send with.  If autoencrypt is not set, this will just return.
     */
    if (his_state_is_will(TELOPT_ENCRYPT)) {
	encrypt_wait();
    }
#endif
    if (his_state_is_will(TELOPT_TSPEED)) {
	static char sbbuf[] = { IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE };

	bcopy(sbbuf, nfrontp, sizeof sbbuf);
	nfrontp += sizeof sbbuf;
    }
    if (his_state_is_will(TELOPT_XDISPLOC)) {
	static char sbbuf[] = { IAC, SB, TELOPT_XDISPLOC, TELQUAL_SEND, IAC, SE };

	bcopy(sbbuf, nfrontp, sizeof sbbuf);
	nfrontp += sizeof sbbuf;
    }
    if (his_state_is_will(TELOPT_ENVIRON)) {
	static char sbbuf[] = { IAC, SB, TELOPT_ENVIRON, TELQUAL_SEND, IAC, SE };

	bcopy(sbbuf, nfrontp, sizeof sbbuf);
	nfrontp += sizeof sbbuf;
    }
    if (his_state_is_will(TELOPT_TTYPE)) {

	bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf);
	nfrontp += sizeof ttytype_sbbuf;
    }
    if (his_state_is_will(TELOPT_TSPEED)) {
	while (sequenceIs(tspeedsubopt, baseline))
	    ttloop();
    }
    if (his_state_is_will(TELOPT_XDISPLOC)) {
	while (sequenceIs(xdisplocsubopt, baseline))
	    ttloop();
    }
    if (his_state_is_will(TELOPT_ENVIRON)) {
	while (sequenceIs(environsubopt, baseline))
	    ttloop();
    }
    if (his_state_is_will(TELOPT_TTYPE)) {
	char first[256], last[256];

	while (sequenceIs(ttypesubopt, baseline))
	    ttloop();

	/*
	 * If the other side has already disabled the option, then
	 * we have to just go with what we (might) have already gotten.
	 */
	if (his_state_is_will(TELOPT_TTYPE) && !terminaltypeok(terminaltype)) {
	    (void) strncpy(first, terminaltype, sizeof(first));
	    for(;;) {
		/*
		 * Save the unknown name, and request the next name.
		 */
		(void) strncpy(last, terminaltype, sizeof(last));
		_gettermname();
		if (terminaltypeok(terminaltype))
		    break;
		if ((strncmp(last, terminaltype, sizeof(last)) == 0) ||
		    his_state_is_wont(TELOPT_TTYPE)) {
		    /*
		     * We've hit the end.  If this is the same as
		     * the first name, just go with it.
		     */
		    if (strncmp(first, terminaltype, sizeof(first)) == 0)
			break;
		    /*
		     * Get the terminal name one more time, so that
		     * RFC1091 compliant telnets will cycle back to
		     * the start of the list.
		     */
		     _gettermname();
		    if (strncmp(first, terminaltype, sizeof(first)) != 0)
			(void) strncpy(terminaltype, first, sizeof(first));
		    break;
		}
	    }
	}
    }
    return(retval);
}  /* end of getterminaltype */
示例#6
0
文件: state.c 项目: MarginC/kame
void
telrcv()
{
    register int c;
    static int state = TS_DATA;
#if	defined(CRAY2) && defined(UNICOS5)
    char *opfrontp = pfrontp;
#endif

    while (ncc > 0) {
        if ((&ptyobuf[BUFSIZ] - pfrontp) < 2)
            break;
        c = *netip++ & 0377, ncc--;
        switch (state) {

        case TS_CR:
            state = TS_DATA;
            /* Strip off \n or \0 after a \r */
            if ((c == 0) || (c == '\n')) {
                break;
            }
        /* FALL THROUGH */

        case TS_DATA:
            if (c == IAC) {
                state = TS_IAC;
                break;
            }
            /*
             * We now map \r\n ==> \r for pragmatic reasons.
             * Many client implementations send \r\n when
             * the user hits the CarriageReturn key.
             *
             * We USED to map \r\n ==> \n, since \r\n says
             * that we want to be in column 1 of the next
             * printable line, and \n is the standard
             * unix way of saying that (\r is only good
             * if CRMOD is set, which it normally is).
             */
            if ((c == '\r') && his_state_is_wont(TELOPT_BINARY)) {
                int nc = *netip;
#ifdef	LINEMODE
                /*
                 * If we are operating in linemode,
                 * convert to local end-of-line.
                 */
                if (linemode && (ncc > 0) && (('\n' == nc) ||
                                              ((0 == nc) && tty_iscrnl())) ) {
                    netip++;
                    ncc--;
                    c = '\n';
                } else
#endif
                {
                    state = TS_CR;
                }
            }
            *pfrontp++ = c;
            break;

        case TS_IAC:
gotiac:
            switch (c) {

            /*
             * Send the process on the pty side an
             * interrupt.  Do this with a NULL or
             * interrupt char; depending on the tty mode.
             */
            case IP:
                DIAG(TD_OPTIONS,
                     printoption("td: recv IAC", c));
                interrupt();
                break;

            case BREAK:
                DIAG(TD_OPTIONS,
                     printoption("td: recv IAC", c));
                sendbrk();
                break;

            /*
             * Are You There?
             */
            case AYT:
                DIAG(TD_OPTIONS,
                     printoption("td: recv IAC", c));
                recv_ayt();
                break;

            /*
             * Abort Output
             */
            case AO:
            {
                DIAG(TD_OPTIONS,
                     printoption("td: recv IAC", c));
                ptyflush();	/* half-hearted */
                init_termbuf();

                if (slctab[SLC_AO].sptr &&
                        *slctab[SLC_AO].sptr != (cc_t)(_POSIX_VDISABLE)) {
                    *pfrontp++ =
                        (unsigned char)*slctab[SLC_AO].sptr;
                }

                netclear();	/* clear buffer back */
                *nfrontp++ = IAC;
                *nfrontp++ = DM;
                neturg = nfrontp-1; /* off by one XXX */
                DIAG(TD_OPTIONS,
                     printoption("td: send IAC", DM));
                break;
            }

            /*
             * Erase Character and
             * Erase Line
             */
            case EC:
            case EL:
            {
                cc_t ch;

                DIAG(TD_OPTIONS,
                     printoption("td: recv IAC", c));
                ptyflush();	/* half-hearted */
                init_termbuf();
                if (c == EC)
                    ch = *slctab[SLC_EC].sptr;
                else
                    ch = *slctab[SLC_EL].sptr;
                if (ch != (cc_t)(_POSIX_VDISABLE))
                    *pfrontp++ = (unsigned char)ch;
                break;
            }

            /*
             * Check for urgent data...
             */
            case DM:
                DIAG(TD_OPTIONS,
                     printoption("td: recv IAC", c));
                SYNCHing = stilloob(net);
                settimer(gotDM);
                break;


            /*
             * Begin option subnegotiation...
             */
            case SB:
                state = TS_SB;
                SB_CLEAR();
                continue;

            case WILL:
                state = TS_WILL;
                continue;

            case WONT:
                state = TS_WONT;
                continue;

            case DO:
                state = TS_DO;
                continue;

            case DONT:
                state = TS_DONT;
                continue;
            case EOR:
                if (his_state_is_will(TELOPT_EOR))
                    doeof();
                break;

            /*
             * Handle RFC 10xx Telnet linemode option additions
             * to command stream (EOF, SUSP, ABORT).
             */
            case xEOF:
                doeof();
                break;

            case SUSP:
                sendsusp();
                break;

            case ABORT:
                sendbrk();
                break;

            case IAC:
                *pfrontp++ = c;
                break;
            }
            state = TS_DATA;
            break;

        case TS_SB:
            if (c == IAC) {
                state = TS_SE;
            } else {
                SB_ACCUM(c);
            }
            break;

        case TS_SE:
            if (c != SE) {
                if (c != IAC) {
                    /*
                     * bad form of suboption negotiation.
                     * handle it in such a way as to avoid
                     * damage to local state.  Parse
                     * suboption buffer found so far,
                     * then treat remaining stream as
                     * another command sequence.
                     */

                    /* for DIAGNOSTICS */
                    SB_ACCUM(IAC);
                    SB_ACCUM(c);
                    subpointer -= 2;

                    SB_TERM();
                    suboption();
                    state = TS_IAC;
                    goto gotiac;
                }
                SB_ACCUM(c);
                state = TS_SB;
            } else {
                /* for DIAGNOSTICS */
                SB_ACCUM(IAC);
                SB_ACCUM(SE);
                subpointer -= 2;

                SB_TERM();
                suboption();	/* handle sub-option */
                state = TS_DATA;
            }
            break;

        case TS_WILL:
            willoption(c);
            state = TS_DATA;
            continue;

        case TS_WONT:
            wontoption(c);
            state = TS_DATA;
            continue;

        case TS_DO:
            dooption(c);
            state = TS_DATA;
            continue;

        case TS_DONT:
            dontoption(c);
            state = TS_DATA;
            continue;

        default:
            syslog(LOG_ERR, "telnetd: panic state=%d\n", state);
            printf("telnetd: panic state=%d\n", state);
            exit(1);
        }
    }
#if	defined(CRAY2) && defined(UNICOS5)
    if (!linemode) {
        char	xptyobuf[BUFSIZ+NETSLOP];
        char	xbuf2[BUFSIZ];
        register char *cp;
        int n = pfrontp - opfrontp, oc;
        memmove(xptyobuf, opfrontp, n);
        pfrontp = opfrontp;
        pfrontp += term_input(xptyobuf, pfrontp, n, BUFSIZ+NETSLOP,
                              xbuf2, &oc, BUFSIZ);
        for (cp = xbuf2; oc > 0; --oc)
            if ((*nfrontp++ = *cp++) == IAC)
                *nfrontp++ = IAC;
    }
#endif	/* defined(CRAY2) && defined(UNICOS5) */
}  /* end of telrcv */
示例#7
0
void dontoption(int option) {
    /*
     * Process client input.
     */
    DIAG(TD_OPTIONS, printoption("td: recv dont", option));

    if (will_wont_resp[option]) {
        will_wont_resp[option]--;
        if (will_wont_resp[option] && my_state_is_wont(option))
            will_wont_resp[option]--;
    }
    if ((will_wont_resp[option] == 0) && (my_want_state_is_will(option))) {
        switch (option) {
        case TELOPT_BINARY:
            init_termbuf();
            tty_binaryout(0);
            set_termbuf();
            break;

        case TELOPT_ECHO:	/* we should stop echoing */
#ifdef	LINEMODE
#ifdef	KLUDGELINEMODE
            if (lmodetype == NO_LINEMODE)
#else
            if (his_state_is_wont(TELOPT_LINEMODE))
#endif
#endif
            {
                init_termbuf();
                tty_setecho(0);
                set_termbuf();
            }
            break;

        case TELOPT_SGA:
#if defined(LINEMODE) && defined(KLUDGELINEMODE)
            /*
             * If kludge linemode is in use, then we
             * must process an incoming do SGA for
             * linemode purposes.
             */
            if (lmodetype == KLUDGE_LINEMODE) {
                /*
                 * The client is asking us to turn
                 * linemode on.
                 */
                clientstat(TELOPT_LINEMODE, WILL, 0);
                /*
                 * If we did not turn line mode on,
                 * then what do we say?  Will SGA?
                 * This violates design of telnet.
                 * Gross.  Very Gross.
                 */
            }
            break;
#else
            set_my_want_state_wont(option);
            if (my_state_is_will(option))
                send_wont(option, 0);
            set_my_state_wont(option);
            if (turn_on_sga ^= 1) send_will(option,1);
            return;
#endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */

        default:
            break;
        }

        set_my_want_state_wont(option);
        if (my_state_is_will(option))
            send_wont(option, 0);
    }
    set_my_state_wont(option);
}
示例#8
0
void dooption(int option) {
    int changeok = 0;

    /*
     * Process client input.
     */

    DIAG(TD_OPTIONS, printoption("td: recv do", option));

    if (will_wont_resp[option]) {
        will_wont_resp[option]--;
        if (will_wont_resp[option] && my_state_is_will(option))
            will_wont_resp[option]--;
    }
    if ((will_wont_resp[option] == 0) && (my_want_state_is_wont(option))) {
        switch (option) {
        case TELOPT_ECHO:
#ifdef	LINEMODE
#ifdef	KLUDGELINEMODE
            if (lmodetype == NO_LINEMODE)
#else
            if (his_state_is_wont(TELOPT_LINEMODE))
#endif
#endif
            {
                init_termbuf();
                tty_setecho(1);
                set_termbuf();
            }
            changeok++;
            break;

        case TELOPT_BINARY:
            init_termbuf();
            tty_binaryout(1);
            set_termbuf();
            changeok++;
            break;

        case TELOPT_SGA:
#if defined(LINEMODE) && defined(KLUDGELINEMODE)
            /*
             * If kludge linemode is in use, then we must
             * process an incoming do SGA for linemode
             * purposes.
             */
            if (lmodetype == KLUDGE_LINEMODE) {
                /*
                 * Receipt of "do SGA" in kludge
                 * linemode is the peer asking us to
                 * turn off linemode.  Make note of
                 * the request.
                 */
                clientstat(TELOPT_LINEMODE, WONT, 0);
                /*
                 * If linemode did not get turned off
                 * then don't tell peer that we did.
                 * Breaking here forces a wont SGA to
                 * be returned.
                 */
                if (linemode)  break;
            }
#else
            turn_on_sga = 0;
#endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */
            changeok++;
            break;

        case TELOPT_STATUS:
            changeok++;
            break;

        case TELOPT_TM:
            /*
             * Special case for TM.  We send a WILL, but
             * pretend we sent a WONT.
             */
            send_will(option, 0);
            set_my_want_state_wont(option);
            set_my_state_wont(option);
            return;

        case TELOPT_LOGOUT:
            /*
             * When we get a LOGOUT option, respond
             * with a WILL LOGOUT, make sure that
             * it gets written out to the network,
             * and then just go away...
             */
            set_my_want_state_will(TELOPT_LOGOUT);
            send_will(TELOPT_LOGOUT, 0);
            set_my_state_will(TELOPT_LOGOUT);
            (void)netflush();
            cleanup(0);
            /* NOT REACHED */
            break;

#if defined(ENCRYPT)
        case TELOPT_ENCRYPT:
            changeok++;
            break;
#endif
        case TELOPT_LINEMODE:
        case TELOPT_TTYPE:
        case TELOPT_NAWS:
        case TELOPT_TSPEED:
        case TELOPT_LFLOW:
        case TELOPT_XDISPLOC:
        case TELOPT_ENVIRON:
        default:
            break;
        }
        if (changeok) {
            set_my_want_state_will(option);
            send_will(option, 0);
        }
        else {
            will_wont_resp[option]++;
            send_wont(option, 0);
        }
    }
    set_my_state_will(option);
}
示例#9
0
void wontoption(int option) {
    /*
     * Process client input.
     */

    DIAG(TD_OPTIONS, printoption("td: recv wont", option));

    if (do_dont_resp[option]) {
        do_dont_resp[option]--;
        if (do_dont_resp[option] && his_state_is_wont(option))
            do_dont_resp[option]--;
    }
    if (do_dont_resp[option] == 0) {
        if (his_want_state_is_will(option)) {
            /* it is always ok to change to negative state */
            switch (option) {
            case TELOPT_ECHO:
                not42 = 1; /* doesn't seem to be a 4.2 system */
                break;

            case TELOPT_BINARY:
                init_termbuf();
                tty_binaryin(0);
                set_termbuf();
                break;

#ifdef LINEMODE
            case TELOPT_LINEMODE:
#ifdef KLUDGELINEMODE
                /*
                 * If real linemode is supported, then client is
                 * asking to turn linemode off.
                 */
                if (lmodetype != REAL_LINEMODE)
                    break;
                lmodetype = KLUDGE_LINEMODE;
# endif	/* KLUDGELINEMODE */
                clientstat(TELOPT_LINEMODE, WONT, 0);
                break;
#endif	/* LINEMODE */

            case TELOPT_TM:
                /*
                 * If we get a WONT TM, and had sent a DO TM,
                 * don't respond with a DONT TM, just leave it
                 * as is.  Short circut the state machine to
                 * achive this.
                 */
                set_his_want_state_wont(TELOPT_TM);
                return;

            case TELOPT_LFLOW:
                /*
                 * If we are not going to support flow control
                 * option, then let peer know that we can't
                 * change the flow control characters.
                 */
                slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS;
                slctab[SLC_XON].defset.flag |= SLC_CANTCHANGE;
                slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS;
                slctab[SLC_XOFF].defset.flag |= SLC_CANTCHANGE;
                break;

#if defined(AUTHENTICATE)
            case TELOPT_AUTHENTICATION:
                auth_finished(0, AUTH_REJECT);
                break;
#endif

            /*
             * For options that we might spin waiting for
             * sub-negotiation, if the client turns off the
             * option rather than responding to the request,
             * we have to treat it here as if we got a response
             * to the sub-negotiation, (by updating the timers)
             * so that we'll break out of the loop.
             */
            case TELOPT_TTYPE:
                settimer(ttypesubopt);
                break;

            case TELOPT_TSPEED:
                settimer(tspeedsubopt);
                break;

            case TELOPT_XDISPLOC:
                settimer(xdisplocsubopt);
                break;

            case TELOPT_ENVIRON:
                settimer(environsubopt);
                break;

            default:
                break;
            }
            set_his_want_state_wont(option);
            if (his_state_is_will(option)) send_dont(option, 0);
        }
        else {
            switch (option) {
            case TELOPT_TM:
#if defined(LINEMODE) && defined(KLUDGELINEMODE)
                if (lmodetype < REAL_LINEMODE) {
                    lmodetype = NO_LINEMODE;
                    clientstat(TELOPT_LINEMODE, WONT, 0);
                    send_will(TELOPT_SGA, 1);
                    send_will(TELOPT_ECHO, 1);
                }
#endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */
                break;

#if	defined(AUTHENTICATE)
            case TELOPT_AUTHENTICATION:
                auth_finished(0, AUTH_REJECT);
                break;
#endif
            default:
                break;
            }
        }
    }
}  /* end of wontoption */
示例#10
0
/*
 * Main loop.  Select from pty and network, and
 * hand data to telnet receiver finite state machine.
 */
void telnet(int f, int p)
{
    int on = 1;
    char *HE;
    const char *IM;

    /*
     * Initialize the slc mapping table.
     */
    get_slc_defaults();

    /*
     * Do some tests where it is desireable to wait for a response.
     * Rather than doing them slowly, one at a time, do them all
     * at once.
     */
    if (my_state_is_wont(TELOPT_SGA))
	send_will(TELOPT_SGA, 1);
    /*
     * Is the client side a 4.2 (NOT 4.3) system?  We need to know this
     * because 4.2 clients are unable to deal with TCP urgent data.
     *
     * To find out, we send out a "DO ECHO".  If the remote system
     * answers "WILL ECHO" it is probably a 4.2 client, and we note
     * that fact ("WILL ECHO" ==> that the client will echo what
     * WE, the server, sends it; it does NOT mean that the client will
     * echo the terminal input).
     */
    send_do(TELOPT_ECHO, 1);
    
#ifdef	LINEMODE
    if (his_state_is_wont(TELOPT_LINEMODE)) {
	/*
	 * Query the peer for linemode support by trying to negotiate
	 * the linemode option.
	 */
	linemode = 0;
	editmode = 0;
	send_do(TELOPT_LINEMODE, 1);  /* send do linemode */
    }
#endif	/* LINEMODE */

    /*
     * Send along a couple of other options that we wish to negotiate.
     */
    send_do(TELOPT_NAWS, 1);
    send_will(TELOPT_STATUS, 1);
    flowmode = 1;  /* default flow control state */
    send_do(TELOPT_LFLOW, 1);
    
    /*
     * Spin, waiting for a response from the DO ECHO.  However,
     * some REALLY DUMB telnets out there might not respond
     * to the DO ECHO.  So, we spin looking for NAWS, (most dumb
     * telnets so far seem to respond with WONT for a DO that
     * they don't understand...) because by the time we get the
     * response, it will already have processed the DO ECHO.
     * Kludge upon kludge.
     */
    while (his_will_wont_is_changing(TELOPT_NAWS)) {
	ttloop();
    }
    
    /*
     * But...
     * The client might have sent a WILL NAWS as part of its
     * startup code; if so, we'll be here before we get the
     * response to the DO ECHO.  We'll make the assumption
     * that any implementation that understands about NAWS
     * is a modern enough implementation that it will respond
     * to our DO ECHO request; hence we'll do another spin
     * waiting for the ECHO option to settle down, which is
     * what we wanted to do in the first place...
     */
    if (his_want_state_is_will(TELOPT_ECHO) &&
	his_state_is_will(TELOPT_NAWS)) {
	while (his_will_wont_is_changing(TELOPT_ECHO))
	    ttloop();
    }
    /*
     * On the off chance that the telnet client is broken and does not
     * respond to the DO ECHO we sent, (after all, we did send the
     * DO NAWS negotiation after the DO ECHO, and we won't get here
     * until a response to the DO NAWS comes back) simulate the
     * receipt of a will echo.  This will also send a WONT ECHO
     * to the client, since we assume that the client failed to
     * respond because it believes that it is already in DO ECHO
     * mode, which we do not want.
     */
    if (his_want_state_is_will(TELOPT_ECHO)) {
	DIAG(TD_OPTIONS, netoprintf("td: simulating recv\r\n"););
	willoption(TELOPT_ECHO);
    }
示例#11
0
static
int
getterminaltype(char *name)
{
    int retval = -1;
    (void)name;

    settimer(baseline);
#if defined(AUTHENTICATE)
    /*
     * Handle the Authentication option before we do anything else.
     */
    send_do(TELOPT_AUTHENTICATION, 1);
    while (his_will_wont_is_changing(TELOPT_AUTHENTICATION))
	ttloop();
    if (his_state_is_will(TELOPT_AUTHENTICATION)) {
	retval = auth_wait(name);
    }
#endif

#if	defined(ENCRYPT)
    send_will(TELOPT_ENCRYPT, 1);
#endif
    send_do(TELOPT_TTYPE, 1);
    send_do(TELOPT_TSPEED, 1);
    send_do(TELOPT_XDISPLOC, 1);
    send_do(TELOPT_ENVIRON, 1);
    while (
#if	defined(ENCRYPT)
	   his_do_dont_is_changing(TELOPT_ENCRYPT) ||
#endif
	   his_will_wont_is_changing(TELOPT_TTYPE) ||
	   his_will_wont_is_changing(TELOPT_TSPEED) ||
	   his_will_wont_is_changing(TELOPT_XDISPLOC) ||
	   his_will_wont_is_changing(TELOPT_ENVIRON)) {
	ttloop();
    }
#if	defined(ENCRYPT)
    /*
     * Wait for the negotiation of what type of encryption we can
     * send with.  If autoencrypt is not set, this will just return.
     */
    if (his_state_is_will(TELOPT_ENCRYPT)) {
	encrypt_wait();
    }
#endif
    if (his_state_is_will(TELOPT_TSPEED)) {
	netoprintf("%c%c%c%c%c%c", 
		   IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE);
    }
    if (his_state_is_will(TELOPT_XDISPLOC)) {
	netoprintf("%c%c%c%c%c%c", 
		   IAC, SB, TELOPT_XDISPLOC, TELQUAL_SEND, IAC, SE);
    }
    if (his_state_is_will(TELOPT_ENVIRON)) {
	netoprintf("%c%c%c%c%c%c", 
		   IAC, SB, TELOPT_ENVIRON, TELQUAL_SEND, IAC, SE);
    }
    if (his_state_is_will(TELOPT_TTYPE)) {
       netoprintf("%c%c%c%c%c%c", 
		  IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE);
    }
    if (his_state_is_will(TELOPT_TSPEED)) {
	while (sequenceIs(tspeedsubopt, baseline))
	    ttloop();
    }
    if (his_state_is_will(TELOPT_XDISPLOC)) {
	while (sequenceIs(xdisplocsubopt, baseline))
	    ttloop();
    }
    if (his_state_is_will(TELOPT_ENVIRON)) {
	while (sequenceIs(environsubopt, baseline))
	    ttloop();
    }
    if (his_state_is_will(TELOPT_TTYPE)) {
	char first[256], last[256];

	while (sequenceIs(ttypesubopt, baseline))
	    ttloop();

	/*
	 * If the other side has already disabled the option, then
	 * we have to just go with what we (might) have already gotten.
	 */
	if (his_state_is_will(TELOPT_TTYPE) && !terminaltypeok(terminaltype)) {
	    /*
	     * Due to state.c, terminaltype points to a static char[41].
	     * Therefore, this assert cannot fail, and therefore, strings
	     * arising from "terminaltype" can be safely strcpy'd into
	     * first[] or last[].
	     */
	    assert(strlen(terminaltype) < sizeof(first));

	    strcpy(first, terminaltype);

	    for(;;) {
		/*
		 * Save the unknown name, and request the next name.
		 */
		strcpy(last, terminaltype);

		_gettermname();
		assert(strlen(terminaltype) < sizeof(first));

		if (terminaltypeok(terminaltype))
		    break;

		if (!strcmp(last, terminaltype) ||
		    his_state_is_wont(TELOPT_TTYPE)) {
		    /*
		     * We've hit the end.  If this is the same as
		     * the first name, just go with it.
		     */
		    if (!strcmp(first, terminaltype))
			break;
		    /*
		     * Get the terminal name one more time, so that
		     * RFC1091 compliant telnets will cycle back to
		     * the start of the list.
		     */
		     _gettermname();
		    assert(strlen(terminaltype) < sizeof(first));

		    if (strcmp(first, terminaltype)) {
			/*
			 * first[] came from terminaltype, so it must fit
			 * back in.
			 */
			strcpy(terminaltype, first);
		    }
		    break;
		}
	    }
	}
    }
    return(retval);
}  /* end of getterminaltype */