138905Sborman /* 238905Sborman * Copyright (c) 1989 Regents of the University of California. 338905Sborman * All rights reserved. 438905Sborman * 542673Sbostic * %sccs.include.redist.c% 638905Sborman */ 738905Sborman 838905Sborman #ifndef lint 9*47611Sdab static char sccsid[] = "@(#)state.c 5.10 (Berkeley) 03/22/91"; 1038905Sborman #endif /* not lint */ 1138905Sborman 1238905Sborman #include "telnetd.h" 1346809Sdab #if defined(AUTHENTICATE) 1446809Sdab #include <libtelnet/auth.h> 1546809Sdab #endif 1638905Sborman 1738905Sborman char doopt[] = { IAC, DO, '%', 'c', 0 }; 1838905Sborman char dont[] = { IAC, DONT, '%', 'c', 0 }; 1938905Sborman char will[] = { IAC, WILL, '%', 'c', 0 }; 2038905Sborman char wont[] = { IAC, WONT, '%', 'c', 0 }; 2138905Sborman int not42 = 1; 2238905Sborman 2338905Sborman /* 2438905Sborman * Buffer for sub-options, and macros 2538905Sborman * for suboptions buffer manipulations 2638905Sborman */ 2746809Sdab unsigned char subbuffer[512], *subpointer= subbuffer, *subend= subbuffer; 2838905Sborman 2938905Sborman #define SB_CLEAR() subpointer = subbuffer; 3038905Sborman #define SB_TERM() { subend = subpointer; SB_CLEAR(); } 3138905Sborman #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ 3238905Sborman *subpointer++ = (c); \ 3338905Sborman } 3438905Sborman #define SB_GET() ((*subpointer++)&0xff) 3538905Sborman #define SB_EOF() (subpointer >= subend) 3644364Sborman #define SB_LEN() (subend - subpointer) 3738905Sborman 3838905Sborman 3938905Sborman 4038905Sborman /* 4138905Sborman * State for recv fsm 4238905Sborman */ 4338905Sborman #define TS_DATA 0 /* base state */ 4438905Sborman #define TS_IAC 1 /* look for double IAC's */ 4538905Sborman #define TS_CR 2 /* CR-LF ->'s CR */ 4638905Sborman #define TS_SB 3 /* throw away begin's... */ 4738905Sborman #define TS_SE 4 /* ...end's (suboption negotiation) */ 4838905Sborman #define TS_WILL 5 /* will option negotiation */ 4938905Sborman #define TS_WONT 6 /* wont " */ 5038905Sborman #define TS_DO 7 /* do " */ 5138905Sborman #define TS_DONT 8 /* dont " */ 5238905Sborman 5346809Sdab void 5438905Sborman telrcv() 5538905Sborman { 5638905Sborman register int c; 5738905Sborman static int state = TS_DATA; 5840242Sborman #if defined(CRAY2) && defined(UNICOS5) 5938905Sborman char *opfrontp = pfrontp; 6038905Sborman #endif 6138905Sborman 6238905Sborman while (ncc > 0) { 6338905Sborman if ((&ptyobuf[BUFSIZ] - pfrontp) < 2) 6438905Sborman break; 6538905Sborman c = *netip++ & 0377, ncc--; 6646809Sdab #if defined(ENCRYPT) 6746809Sdab if (decrypt_input) 6846809Sdab c = (*decrypt_input)(c); 6946809Sdab #endif 7038905Sborman switch (state) { 7138905Sborman 7238905Sborman case TS_CR: 7338905Sborman state = TS_DATA; 7438905Sborman /* Strip off \n or \0 after a \r */ 7538905Sborman if ((c == 0) || (c == '\n')) { 7638905Sborman break; 7738905Sborman } 7838905Sborman /* FALL THROUGH */ 7938905Sborman 8038905Sborman case TS_DATA: 8138905Sborman if (c == IAC) { 8238905Sborman state = TS_IAC; 8338905Sborman break; 8438905Sborman } 8538905Sborman /* 8638905Sborman * We now map \r\n ==> \r for pragmatic reasons. 8738905Sborman * Many client implementations send \r\n when 8838905Sborman * the user hits the CarriageReturn key. 8938905Sborman * 9038905Sborman * We USED to map \r\n ==> \n, since \r\n says 9138905Sborman * that we want to be in column 1 of the next 9238905Sborman * printable line, and \n is the standard 9338905Sborman * unix way of saying that (\r is only good 9438905Sborman * if CRMOD is set, which it normally is). 9538905Sborman */ 9644364Sborman if ((c == '\r') && his_state_is_wont(TELOPT_BINARY)) { 9746809Sdab int nc = *netip; 9846809Sdab #if defined(ENCRYPT) 9946809Sdab if (decrypt_input) 10046809Sdab nc = (*decrypt_input)(nc & 0xff); 10146809Sdab #endif 10246809Sdab #ifdef LINEMODE 10338905Sborman /* 10438905Sborman * If we are operating in linemode, 10538905Sborman * convert to local end-of-line. 10638905Sborman */ 10746809Sdab if (linemode && (ncc > 0) && (('\n' == nc) || 10846809Sdab ((0 == nc) && tty_iscrnl())) ) { 10938905Sborman netip++; ncc--; 11038905Sborman c = '\n'; 11146809Sdab } else 11246809Sdab #endif 11346809Sdab { 11446809Sdab #if defined(ENCRYPT) 11546809Sdab if (decrypt_input) 11646809Sdab (void)(*decrypt_input)(-1); 11746809Sdab #endif 11838905Sborman state = TS_CR; 11938905Sborman } 12038905Sborman } 12138905Sborman *pfrontp++ = c; 12238905Sborman break; 12338905Sborman 12438905Sborman case TS_IAC: 12538905Sborman gotiac: switch (c) { 12638905Sborman 12738905Sborman /* 12838905Sborman * Send the process on the pty side an 12938905Sborman * interrupt. Do this with a NULL or 13038905Sborman * interrupt char; depending on the tty mode. 13138905Sborman */ 13238905Sborman case IP: 13346809Sdab DIAG(TD_OPTIONS, 13446809Sdab printoption("td: recv IAC", c)); 13538905Sborman interrupt(); 13638905Sborman break; 13738905Sborman 13838905Sborman case BREAK: 13946809Sdab DIAG(TD_OPTIONS, 14046809Sdab printoption("td: recv IAC", c)); 14138905Sborman sendbrk(); 14238905Sborman break; 14338905Sborman 14438905Sborman /* 14538905Sborman * Are You There? 14638905Sborman */ 14738905Sborman case AYT: 14846809Sdab DIAG(TD_OPTIONS, 14946809Sdab printoption("td: recv IAC", c)); 15045234Sborman recv_ayt(); 15138905Sborman break; 15238905Sborman 15338905Sborman /* 15438905Sborman * Abort Output 15538905Sborman */ 15638905Sborman case AO: 15738905Sborman { 15846809Sdab DIAG(TD_OPTIONS, 15946809Sdab printoption("td: recv IAC", c)); 16038905Sborman ptyflush(); /* half-hearted */ 16138905Sborman init_termbuf(); 16238905Sborman 16338905Sborman if (slctab[SLC_AO].sptr && 16445234Sborman *slctab[SLC_AO].sptr != (cc_t)(_POSIX_VDISABLE)) { 16540242Sborman *pfrontp++ = 16640242Sborman (unsigned char)*slctab[SLC_AO].sptr; 16738905Sborman } 16838905Sborman 16938905Sborman netclear(); /* clear buffer back */ 17038905Sborman *nfrontp++ = IAC; 17138905Sborman *nfrontp++ = DM; 17238905Sborman neturg = nfrontp-1; /* off by one XXX */ 17346809Sdab DIAG(TD_OPTIONS, 17446809Sdab printoption("td: send IAC", DM)); 17538905Sborman break; 17638905Sborman } 17738905Sborman 17838905Sborman /* 17938905Sborman * Erase Character and 18038905Sborman * Erase Line 18138905Sborman */ 18238905Sborman case EC: 18338905Sborman case EL: 18438905Sborman { 18540242Sborman cc_t ch; 18638905Sborman 18746809Sdab DIAG(TD_OPTIONS, 18846809Sdab printoption("td: recv IAC", c)); 18938905Sborman ptyflush(); /* half-hearted */ 19038905Sborman init_termbuf(); 19144364Sborman if (c == EC) 19244364Sborman ch = *slctab[SLC_EC].sptr; 19344364Sborman else 19444364Sborman ch = *slctab[SLC_EL].sptr; 19545234Sborman if (ch != (cc_t)(_POSIX_VDISABLE)) 19640242Sborman *pfrontp++ = (unsigned char)ch; 19738905Sborman break; 19838905Sborman } 19938905Sborman 20038905Sborman /* 20138905Sborman * Check for urgent data... 20238905Sborman */ 20338905Sborman case DM: 20446809Sdab DIAG(TD_OPTIONS, 20546809Sdab printoption("td: recv IAC", c)); 20638905Sborman SYNCHing = stilloob(net); 20738905Sborman settimer(gotDM); 20838905Sborman break; 20938905Sborman 21038905Sborman 21138905Sborman /* 21238905Sborman * Begin option subnegotiation... 21338905Sborman */ 21438905Sborman case SB: 21538905Sborman state = TS_SB; 21638905Sborman SB_CLEAR(); 21738905Sborman continue; 21838905Sborman 21938905Sborman case WILL: 22038905Sborman state = TS_WILL; 22138905Sborman continue; 22238905Sborman 22338905Sborman case WONT: 22438905Sborman state = TS_WONT; 22538905Sborman continue; 22638905Sborman 22738905Sborman case DO: 22838905Sborman state = TS_DO; 22938905Sborman continue; 23038905Sborman 23138905Sborman case DONT: 23238905Sborman state = TS_DONT; 23338905Sborman continue; 23438905Sborman case EOR: 23544364Sborman if (his_state_is_will(TELOPT_EOR)) 23638905Sborman doeof(); 23738905Sborman break; 23838905Sborman 23938905Sborman /* 24038905Sborman * Handle RFC 10xx Telnet linemode option additions 24138905Sborman * to command stream (EOF, SUSP, ABORT). 24238905Sborman */ 24338905Sborman case xEOF: 24438905Sborman doeof(); 24538905Sborman break; 24638905Sborman 24738905Sborman case SUSP: 24838905Sborman sendsusp(); 24938905Sborman break; 25038905Sborman 25138905Sborman case ABORT: 25238905Sborman sendbrk(); 25338905Sborman break; 25438905Sborman 25538905Sborman case IAC: 25638905Sborman *pfrontp++ = c; 25738905Sborman break; 25838905Sborman } 25938905Sborman state = TS_DATA; 26038905Sborman break; 26138905Sborman 26238905Sborman case TS_SB: 26338905Sborman if (c == IAC) { 26438905Sborman state = TS_SE; 26538905Sborman } else { 26638905Sborman SB_ACCUM(c); 26738905Sborman } 26838905Sborman break; 26938905Sborman 27038905Sborman case TS_SE: 27138905Sborman if (c != SE) { 27238905Sborman if (c != IAC) { 27338905Sborman /* 27438905Sborman * bad form of suboption negotiation. 27538905Sborman * handle it in such a way as to avoid 27638905Sborman * damage to local state. Parse 27738905Sborman * suboption buffer found so far, 27838905Sborman * then treat remaining stream as 27938905Sborman * another command sequence. 28038905Sborman */ 28146809Sdab 28246809Sdab /* for DIAGNOSTICS */ 28344364Sborman SB_ACCUM(IAC); 28444364Sborman SB_ACCUM(c); 28544364Sborman subpointer -= 2; 28646809Sdab 28738905Sborman SB_TERM(); 28838905Sborman suboption(); 28938905Sborman state = TS_IAC; 29038905Sborman goto gotiac; 29138905Sborman } 29238905Sborman SB_ACCUM(c); 29338905Sborman state = TS_SB; 29438905Sborman } else { 29546809Sdab /* for DIAGNOSTICS */ 29644364Sborman SB_ACCUM(IAC); 29744364Sborman SB_ACCUM(SE); 29844364Sborman subpointer -= 2; 29946809Sdab 30038905Sborman SB_TERM(); 30138905Sborman suboption(); /* handle sub-option */ 30238905Sborman state = TS_DATA; 30338905Sborman } 30438905Sborman break; 30538905Sborman 30638905Sborman case TS_WILL: 30739503Sborman willoption(c); 30838905Sborman state = TS_DATA; 30938905Sborman continue; 31038905Sborman 31138905Sborman case TS_WONT: 31239503Sborman wontoption(c); 31338905Sborman state = TS_DATA; 31438905Sborman continue; 31538905Sborman 31638905Sborman case TS_DO: 31739503Sborman dooption(c); 31838905Sborman state = TS_DATA; 31938905Sborman continue; 32038905Sborman 32138905Sborman case TS_DONT: 32239503Sborman dontoption(c); 32338905Sborman state = TS_DATA; 32438905Sborman continue; 32538905Sborman 32638905Sborman default: 32738905Sborman syslog(LOG_ERR, "telnetd: panic state=%d\n", state); 32838905Sborman printf("telnetd: panic state=%d\n", state); 32938905Sborman exit(1); 33038905Sborman } 33138905Sborman } 33240242Sborman #if defined(CRAY2) && defined(UNICOS5) 33338905Sborman if (!linemode) { 33438905Sborman char xptyobuf[BUFSIZ+NETSLOP]; 33538905Sborman char xbuf2[BUFSIZ]; 33638905Sborman register char *cp; 33738905Sborman int n = pfrontp - opfrontp, oc; 33838905Sborman bcopy(opfrontp, xptyobuf, n); 33938905Sborman pfrontp = opfrontp; 34038905Sborman pfrontp += term_input(xptyobuf, pfrontp, n, BUFSIZ+NETSLOP, 34138905Sborman xbuf2, &oc, BUFSIZ); 34238905Sborman for (cp = xbuf2; oc > 0; --oc) 34338905Sborman if ((*nfrontp++ = *cp++) == IAC) 34438905Sborman *nfrontp++ = IAC; 34538905Sborman } 34640242Sborman #endif /* defined(CRAY2) && defined(UNICOS5) */ 34738905Sborman } /* end of telrcv */ 34838905Sborman 34938905Sborman /* 35038905Sborman * The will/wont/do/dont state machines are based on Dave Borman's 35144364Sborman * Telnet option processing state machine. 35238905Sborman * 35338905Sborman * These correspond to the following states: 35438905Sborman * my_state = the last negotiated state 35538905Sborman * want_state = what I want the state to go to 35638905Sborman * want_resp = how many requests I have sent 35738905Sborman * All state defaults are negative, and resp defaults to 0. 35838905Sborman * 35938905Sborman * When initiating a request to change state to new_state: 36038905Sborman * 36138905Sborman * if ((want_resp == 0 && new_state == my_state) || want_state == new_state) { 36238905Sborman * do nothing; 36338905Sborman * } else { 36438905Sborman * want_state = new_state; 36538905Sborman * send new_state; 36638905Sborman * want_resp++; 36738905Sborman * } 36838905Sborman * 36938905Sborman * When receiving new_state: 37038905Sborman * 37138905Sborman * if (want_resp) { 37238905Sborman * want_resp--; 37338905Sborman * if (want_resp && (new_state == my_state)) 37438905Sborman * want_resp--; 37538905Sborman * } 37638905Sborman * if ((want_resp == 0) && (new_state != want_state)) { 37738905Sborman * if (ok_to_switch_to new_state) 37838905Sborman * want_state = new_state; 37938905Sborman * else 38038905Sborman * want_resp++; 38138905Sborman * send want_state; 38238905Sborman * } 38338905Sborman * my_state = new_state; 38438905Sborman * 38538905Sborman * Note that new_state is implied in these functions by the function itself. 38638905Sborman * will and do imply positive new_state, wont and dont imply negative. 38738905Sborman * 38838905Sborman * Finally, there is one catch. If we send a negative response to a 38938905Sborman * positive request, my_state will be the positive while want_state will 39038905Sborman * remain negative. my_state will revert to negative when the negative 39138905Sborman * acknowlegment arrives from the peer. Thus, my_state generally tells 39238905Sborman * us not only the last negotiated state, but also tells us what the peer 39338905Sborman * wants to be doing as well. It is important to understand this difference 39438905Sborman * as we may wish to be processing data streams based on our desired state 39538905Sborman * (want_state) or based on what the peer thinks the state is (my_state). 39638905Sborman * 39738905Sborman * This all works fine because if the peer sends a positive request, the data 39838905Sborman * that we receive prior to negative acknowlegment will probably be affected 39938905Sborman * by the positive state, and we can process it as such (if we can; if we 40038905Sborman * can't then it really doesn't matter). If it is that important, then the 40138905Sborman * peer probably should be buffering until this option state negotiation 40238905Sborman * is complete. 40338905Sborman * 40438905Sborman */ 40546809Sdab void 40639503Sborman send_do(option, init) 40739503Sborman int option, init; 40838905Sborman { 40939503Sborman if (init) { 41044364Sborman if ((do_dont_resp[option] == 0 && his_state_is_will(option)) || 41144364Sborman his_want_state_is_will(option)) 41239503Sborman return; 41339531Sborman /* 41439531Sborman * Special case for TELOPT_TM: We send a DO, but pretend 41539531Sborman * that we sent a DONT, so that we can send more DOs if 41639531Sborman * we want to. 41739531Sborman */ 41839531Sborman if (option == TELOPT_TM) 41944364Sborman set_his_want_state_wont(option); 42039531Sborman else 42144364Sborman set_his_want_state_will(option); 42239503Sborman do_dont_resp[option]++; 42339503Sborman } 42439503Sborman (void) sprintf(nfrontp, doopt, option); 42539503Sborman nfrontp += sizeof (dont) - 2; 42646809Sdab 42746809Sdab DIAG(TD_OPTIONS, printoption("td: send do", option)); 42839503Sborman } 42939503Sborman 43046809Sdab #ifdef AUTHENTICATE 43146809Sdab extern void auth_request(); 43246809Sdab #endif 43346809Sdab #ifdef LINEMODE 43446809Sdab extern void doclientstat(); 43546809Sdab #endif 43646809Sdab #ifdef ENCRYPT 43746809Sdab extern void encrypt_send_support(); 43846809Sdab #endif 43946809Sdab 44046809Sdab void 44139503Sborman willoption(option) 44239503Sborman int option; 44339503Sborman { 44438905Sborman int changeok = 0; 44546809Sdab void (*func)() = 0; 44638905Sborman 44739503Sborman /* 44839503Sborman * process input from peer. 44939503Sborman */ 45039503Sborman 45146809Sdab DIAG(TD_OPTIONS, printoption("td: recv will", option)); 45244364Sborman 45339503Sborman if (do_dont_resp[option]) { 45439503Sborman do_dont_resp[option]--; 45544364Sborman if (do_dont_resp[option] && his_state_is_will(option)) 45639503Sborman do_dont_resp[option]--; 45739503Sborman } 45839531Sborman if (do_dont_resp[option] == 0) { 45944364Sborman if (his_want_state_is_wont(option)) { 46038905Sborman switch (option) { 46138905Sborman 46238905Sborman case TELOPT_BINARY: 46338905Sborman init_termbuf(); 46438905Sborman tty_binaryin(1); 46538905Sborman set_termbuf(); 46638905Sborman changeok++; 46738905Sborman break; 46838905Sborman 46938905Sborman case TELOPT_ECHO: 47038905Sborman /* 47144364Sborman * See comments below for more info. 47238905Sborman */ 47344364Sborman not42 = 0; /* looks like a 4.2 system */ 47438905Sborman break; 47538905Sborman 47638905Sborman case TELOPT_TM: 47738905Sborman #if defined(LINEMODE) && defined(KLUDGELINEMODE) 47838905Sborman /* 47939503Sborman * This telnetd implementation does not really 48039503Sborman * support timing marks, it just uses them to 48139503Sborman * support the kludge linemode stuff. If we 48239503Sborman * receive a will or wont TM in response to our 48339503Sborman * do TM request that may have been sent to 48439503Sborman * determine kludge linemode support, process 48539503Sborman * it, otherwise TM should get a negative 48639503Sborman * response back. 48738905Sborman */ 48838905Sborman /* 48938905Sborman * Handle the linemode kludge stuff. 49038905Sborman * If we are not currently supporting any 49138905Sborman * linemode at all, then we assume that this 49238905Sborman * is the client telling us to use kludge 49338905Sborman * linemode in response to our query. Set the 49438905Sborman * linemode type that is to be supported, note 49538905Sborman * that the client wishes to use linemode, and 49638905Sborman * eat the will TM as though it never arrived. 49738905Sborman */ 49838905Sborman if (lmodetype < KLUDGE_LINEMODE) { 49938905Sborman lmodetype = KLUDGE_LINEMODE; 50038905Sborman clientstat(TELOPT_LINEMODE, WILL, 0); 50139503Sborman send_wont(TELOPT_SGA, 1); 50238905Sborman } 50338905Sborman #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ 50438905Sborman /* 50539531Sborman * We never respond to a WILL TM, and 50644364Sborman * we leave the state WONT. 50738905Sborman */ 50838905Sborman return; 50938905Sborman 51038905Sborman case TELOPT_LFLOW: 51138905Sborman /* 51239503Sborman * If we are going to support flow control 51339503Sborman * option, then don't worry peer that we can't 51439503Sborman * change the flow control characters. 51538905Sborman */ 51638905Sborman slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS; 51738905Sborman slctab[SLC_XON].defset.flag |= SLC_DEFAULT; 51838905Sborman slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS; 51938905Sborman slctab[SLC_XOFF].defset.flag |= SLC_DEFAULT; 52038905Sborman case TELOPT_TTYPE: 52138905Sborman case TELOPT_SGA: 52238905Sborman case TELOPT_NAWS: 52338905Sborman case TELOPT_TSPEED: 52444364Sborman case TELOPT_XDISPLOC: 52544364Sborman case TELOPT_ENVIRON: 52639531Sborman changeok++; 52739531Sborman break; 52839531Sborman 52938905Sborman #ifdef LINEMODE 53038905Sborman case TELOPT_LINEMODE: 53139531Sborman # ifdef KLUDGELINEMODE 53239531Sborman /* 53339531Sborman * Note client's desire to use linemode. 53439531Sborman */ 53539531Sborman lmodetype = REAL_LINEMODE; 53639531Sborman # endif /* KLUDGELINEMODE */ 53746809Sdab func = doclientstat; 53846809Sdab changeok++; 53946809Sdab break; 54039531Sborman #endif /* LINEMODE */ 54138905Sborman 54246809Sdab #ifdef AUTHENTICATE 54346809Sdab case TELOPT_AUTHENTICATION: 54446809Sdab func = auth_request; 54546809Sdab changeok++; 54646809Sdab break; 54746809Sdab #endif 54846809Sdab 54946809Sdab #ifdef ENCRYPT 55046809Sdab case TELOPT_ENCRYPT: 55146809Sdab func = encrypt_send_support; 55246809Sdab changeok++; 55346809Sdab break; 55446809Sdab #endif 55546809Sdab 55638905Sborman default: 55738905Sborman break; 55838905Sborman } 55939503Sborman if (changeok) { 56044364Sborman set_his_want_state_will(option); 56139503Sborman send_do(option, 0); 56239503Sborman } else { 56339503Sborman do_dont_resp[option]++; 56439503Sborman send_dont(option, 0); 56538905Sborman } 56644364Sborman } else { 56744364Sborman /* 56844364Sborman * Option processing that should happen when 56944364Sborman * we receive conformation of a change in 57044364Sborman * state that we had requested. 57144364Sborman */ 57244364Sborman switch (option) { 57344364Sborman case TELOPT_ECHO: 57444364Sborman not42 = 0; /* looks like a 4.2 system */ 57544364Sborman /* 57644364Sborman * Egads, he responded "WILL ECHO". Turn 57744364Sborman * it off right now! 57844364Sborman */ 57944364Sborman send_dont(option, 1); 58044364Sborman /* 58144364Sborman * "WILL ECHO". Kludge upon kludge! 58244364Sborman * A 4.2 client is now echoing user input at 58344364Sborman * the tty. This is probably undesireable and 58444364Sborman * it should be stopped. The client will 58544364Sborman * respond WONT TM to the DO TM that we send to 58644364Sborman * check for kludge linemode. When the WONT TM 58744364Sborman * arrives, linemode will be turned off and a 58844364Sborman * change propogated to the pty. This change 58944364Sborman * will cause us to process the new pty state 59044364Sborman * in localstat(), which will notice that 59144364Sborman * linemode is off and send a WILL ECHO 59244364Sborman * so that we are properly in character mode and 59344364Sborman * all is well. 59444364Sborman */ 59544364Sborman break; 59644364Sborman #ifdef LINEMODE 59744364Sborman case TELOPT_LINEMODE: 59844364Sborman # ifdef KLUDGELINEMODE 59944364Sborman /* 60044364Sborman * Note client's desire to use linemode. 60144364Sborman */ 60244364Sborman lmodetype = REAL_LINEMODE; 60344364Sborman # endif /* KLUDGELINEMODE */ 60446809Sdab func = doclientstat; 60546809Sdab break; 60644364Sborman #endif /* LINEMODE */ 60746809Sdab 60846809Sdab #ifdef AUTHENTICATE 60946809Sdab case TELOPT_AUTHENTICATION: 61046809Sdab func = auth_request; 61146809Sdab break; 61246809Sdab #endif 61346809Sdab 61446809Sdab #ifdef ENCRYPT 61546809Sdab case TELOPT_ENCRYPT: 61646809Sdab func = encrypt_send_support; 61746809Sdab break; 61846809Sdab #endif 61944364Sborman } 62039531Sborman } 62138905Sborman } 62244364Sborman set_his_state_will(option); 62346809Sdab if (func) 62446809Sdab (*func)(); 62538905Sborman } /* end of willoption */ 62638905Sborman 62746809Sdab void 62839503Sborman send_dont(option, init) 62939503Sborman int option, init; 63038905Sborman { 63139503Sborman if (init) { 63244364Sborman if ((do_dont_resp[option] == 0 && his_state_is_wont(option)) || 63344364Sborman his_want_state_is_wont(option)) 63439503Sborman return; 63544364Sborman set_his_want_state_wont(option); 63639503Sborman do_dont_resp[option]++; 63739503Sborman } 63839503Sborman (void) sprintf(nfrontp, dont, option); 63939503Sborman nfrontp += sizeof (doopt) - 2; 64046809Sdab 64146809Sdab DIAG(TD_OPTIONS, printoption("td: send dont", option)); 64239503Sborman } 64339503Sborman 64446809Sdab void 64539503Sborman wontoption(option) 64639503Sborman int option; 64739503Sborman { 64838905Sborman /* 64938905Sborman * Process client input. 65038905Sborman */ 65139503Sborman 65246809Sdab DIAG(TD_OPTIONS, printoption("td: recv wont", option)); 65344364Sborman 65439503Sborman if (do_dont_resp[option]) { 65539503Sborman do_dont_resp[option]--; 65644364Sborman if (do_dont_resp[option] && his_state_is_wont(option)) 65739503Sborman do_dont_resp[option]--; 65839503Sborman } 65939531Sborman if (do_dont_resp[option] == 0) { 66044364Sborman if (his_want_state_is_will(option)) { 66139503Sborman /* it is always ok to change to negative state */ 66238905Sborman switch (option) { 66338905Sborman case TELOPT_ECHO: 66439503Sborman not42 = 1; /* doesn't seem to be a 4.2 system */ 66538905Sborman break; 66638905Sborman 66738905Sborman case TELOPT_BINARY: 66838905Sborman init_termbuf(); 66938905Sborman tty_binaryin(0); 67038905Sborman set_termbuf(); 67138905Sborman break; 67238905Sborman 67338905Sborman #ifdef LINEMODE 67438905Sborman case TELOPT_LINEMODE: 67538905Sborman # ifdef KLUDGELINEMODE 67638905Sborman /* 67738905Sborman * If real linemode is supported, then client is 67838905Sborman * asking to turn linemode off. 67938905Sborman */ 68044364Sborman if (lmodetype != REAL_LINEMODE) 68144364Sborman break; 68244364Sborman lmodetype = KLUDGE_LINEMODE; 68338905Sborman # endif /* KLUDGELINEMODE */ 68444364Sborman clientstat(TELOPT_LINEMODE, WONT, 0); 68538905Sborman break; 68646809Sdab #endif /* LINEMODE */ 68738905Sborman 68838905Sborman case TELOPT_TM: 68938905Sborman /* 69039503Sborman * If we get a WONT TM, and had sent a DO TM, 69139503Sborman * don't respond with a DONT TM, just leave it 69239503Sborman * as is. Short circut the state machine to 69339531Sborman * achive this. 69438905Sborman */ 69544364Sborman set_his_want_state_wont(TELOPT_TM); 69638905Sborman return; 69738905Sborman 69838905Sborman case TELOPT_LFLOW: 69938905Sborman /* 70039503Sborman * If we are not going to support flow control 70139503Sborman * option, then let peer know that we can't 70239503Sborman * change the flow control characters. 70338905Sborman */ 70438905Sborman slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS; 70538905Sborman slctab[SLC_XON].defset.flag |= SLC_CANTCHANGE; 70638905Sborman slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS; 70738905Sborman slctab[SLC_XOFF].defset.flag |= SLC_CANTCHANGE; 70838905Sborman break; 70938905Sborman 71046809Sdab #if defined(AUTHENTICATE) 71146809Sdab case TELOPT_AUTHENTICATION: 71246809Sdab auth_finished(0, AUTH_REJECT); 71346809Sdab break; 71446809Sdab #endif 71546809Sdab 71644364Sborman /* 71744364Sborman * For options that we might spin waiting for 71844364Sborman * sub-negotiation, if the client turns off the 71944364Sborman * option rather than responding to the request, 72044364Sborman * we have to treat it here as if we got a response 72144364Sborman * to the sub-negotiation, (by updating the timers) 72244364Sborman * so that we'll break out of the loop. 72344364Sborman */ 72444364Sborman case TELOPT_TTYPE: 72544364Sborman settimer(ttypesubopt); 72644364Sborman break; 72744364Sborman 72844364Sborman case TELOPT_TSPEED: 72944364Sborman settimer(tspeedsubopt); 73044364Sborman break; 73144364Sborman 73244364Sborman case TELOPT_XDISPLOC: 73344364Sborman settimer(xdisplocsubopt); 73444364Sborman break; 73544364Sborman 73644364Sborman case TELOPT_ENVIRON: 73744364Sborman settimer(environsubopt); 73844364Sborman break; 73944364Sborman 74038905Sborman default: 74138905Sborman break; 74238905Sborman } 74344364Sborman set_his_want_state_wont(option); 74444364Sborman if (his_state_is_will(option)) 74544364Sborman send_dont(option, 0); 74639531Sborman } else { 74739531Sborman switch (option) { 74839531Sborman case TELOPT_TM: 74939531Sborman #if defined(LINEMODE) && defined(KLUDGELINEMODE) 75039531Sborman if (lmodetype < REAL_LINEMODE) { 75139531Sborman lmodetype = NO_LINEMODE; 75239531Sborman clientstat(TELOPT_LINEMODE, WONT, 0); 75339531Sborman send_will(TELOPT_SGA, 1); 75445234Sborman send_will(TELOPT_ECHO, 1); 75539531Sborman } 75639531Sborman #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ 75746809Sdab break; 75846809Sdab 75946809Sdab #if defined(AUTHENTICATE) 76046809Sdab case TELOPT_AUTHENTICATION: 76146809Sdab auth_finished(0, AUTH_REJECT); 76246809Sdab break; 76346809Sdab #endif 76439531Sborman default: 76539531Sborman break; 76639531Sborman } 76739531Sborman } 76838905Sborman } 76944364Sborman set_his_state_wont(option); 77038905Sborman 77139503Sborman } /* end of wontoption */ 77238905Sborman 77346809Sdab void 77439503Sborman send_will(option, init) 77539503Sborman int option, init; 77639503Sborman { 77739503Sborman if (init) { 77844364Sborman if ((will_wont_resp[option] == 0 && my_state_is_will(option))|| 77944364Sborman my_want_state_is_will(option)) 78039503Sborman return; 78144364Sborman set_my_want_state_will(option); 78239503Sborman will_wont_resp[option]++; 78338905Sborman } 78439503Sborman (void) sprintf(nfrontp, will, option); 78539503Sborman nfrontp += sizeof (doopt) - 2; 78646809Sdab 78746809Sdab DIAG(TD_OPTIONS, printoption("td: send will", option)); 78839503Sborman } 78938905Sborman 79045234Sborman #if !defined(LINEMODE) || !defined(KLUDGELINEMODE) 79145234Sborman /* 79245234Sborman * When we get a DONT SGA, we will try once to turn it 79345234Sborman * back on. If the other side responds DONT SGA, we 79445234Sborman * leave it at that. This is so that when we talk to 79545234Sborman * clients that understand KLUDGELINEMODE but not LINEMODE, 79645234Sborman * we'll keep them in char-at-a-time mode. 79745234Sborman */ 79845234Sborman int turn_on_sga = 0; 79945234Sborman #endif 80045234Sborman 80146809Sdab void 80239503Sborman dooption(option) 80339503Sborman int option; 80438905Sborman { 80538905Sborman int changeok = 0; 80638905Sborman 80738905Sborman /* 80838905Sborman * Process client input. 80938905Sborman */ 81039503Sborman 81146809Sdab DIAG(TD_OPTIONS, printoption("td: recv do", option)); 81244364Sborman 81339503Sborman if (will_wont_resp[option]) { 81439503Sborman will_wont_resp[option]--; 81544364Sborman if (will_wont_resp[option] && my_state_is_will(option)) 81639503Sborman will_wont_resp[option]--; 81739503Sborman } 81844364Sborman if ((will_wont_resp[option] == 0) && (my_want_state_is_wont(option))) { 81938905Sborman switch (option) { 82038905Sborman case TELOPT_ECHO: 82138905Sborman #ifdef LINEMODE 82245234Sborman # ifdef KLUDGELINEMODE 82345234Sborman if (lmodetype == NO_LINEMODE) 82445234Sborman # else 82545234Sborman if (his_state_is_wont(TELOPT_LINEMODE)) 82645234Sborman # endif 82738905Sborman #endif 82845234Sborman { 82938905Sborman init_termbuf(); 83038905Sborman tty_setecho(1); 83138905Sborman set_termbuf(); 83238905Sborman } 83338905Sborman changeok++; 83438905Sborman break; 83538905Sborman 83638905Sborman case TELOPT_BINARY: 83738905Sborman init_termbuf(); 83838905Sborman tty_binaryout(1); 83938905Sborman set_termbuf(); 84038905Sborman changeok++; 84138905Sborman break; 84238905Sborman 84338905Sborman case TELOPT_SGA: 84438905Sborman #if defined(LINEMODE) && defined(KLUDGELINEMODE) 84538905Sborman /* 84639503Sborman * If kludge linemode is in use, then we must 84739503Sborman * process an incoming do SGA for linemode 84839503Sborman * purposes. 84938905Sborman */ 85038905Sborman if (lmodetype == KLUDGE_LINEMODE) { 85138905Sborman /* 85239503Sborman * Receipt of "do SGA" in kludge 85339503Sborman * linemode is the peer asking us to 85439503Sborman * turn off linemode. Make note of 85539503Sborman * the request. 85638905Sborman */ 85738905Sborman clientstat(TELOPT_LINEMODE, WONT, 0); 85838905Sborman /* 85939503Sborman * If linemode did not get turned off 86039503Sborman * then don't tell peer that we did. 86139503Sborman * Breaking here forces a wont SGA to 86239503Sborman * be returned. 86338905Sborman */ 86438905Sborman if (linemode) 86538905Sborman break; 86638905Sborman } 86745234Sborman #else 86845234Sborman turn_on_sga = 0; 86938905Sborman #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ 87038905Sborman changeok++; 87138905Sborman break; 87238905Sborman 87338905Sborman case TELOPT_STATUS: 87438905Sborman changeok++; 87538905Sborman break; 87638905Sborman 87738905Sborman case TELOPT_TM: 87839503Sborman /* 87939503Sborman * Special case for TM. We send a WILL, but 88039503Sborman * pretend we sent a WONT. 88139503Sborman */ 88239503Sborman send_will(option, 0); 88344364Sborman set_my_want_state_wont(option); 88444364Sborman set_my_state_wont(option); 88539503Sborman return; 88639503Sborman 88746809Sdab case TELOPT_LOGOUT: 88846809Sdab /* 88946809Sdab * When we get a LOGOUT option, respond 89046809Sdab * with a WILL LOGOUT, make sure that 89146809Sdab * it gets written out to the network, 89246809Sdab * and then just go away... 89346809Sdab */ 89446809Sdab set_my_want_state_will(TELOPT_LOGOUT); 89546809Sdab send_will(TELOPT_LOGOUT, 0); 89646809Sdab set_my_state_will(TELOPT_LOGOUT); 89746809Sdab (void)netflush(); 89846809Sdab cleanup(0); 89946809Sdab /* NOT REACHED */ 90046809Sdab break; 90146809Sdab 90246809Sdab #if defined(ENCRYPT) 90346809Sdab case TELOPT_ENCRYPT: 90446809Sdab changeok++; 90546809Sdab break; 90646809Sdab #endif 90738905Sborman case TELOPT_LINEMODE: 90838905Sborman case TELOPT_TTYPE: 90938905Sborman case TELOPT_NAWS: 91038905Sborman case TELOPT_TSPEED: 91138905Sborman case TELOPT_LFLOW: 91244364Sborman case TELOPT_XDISPLOC: 91344364Sborman case TELOPT_ENVIRON: 91438905Sborman default: 91538905Sborman break; 91638905Sborman } 91739503Sborman if (changeok) { 91844364Sborman set_my_want_state_will(option); 91939503Sborman send_will(option, 0); 92039503Sborman } else { 92139503Sborman will_wont_resp[option]++; 92239503Sborman send_wont(option, 0); 92338905Sborman } 92438905Sborman } 92544364Sborman set_my_state_will(option); 92638905Sborman 92738905Sborman } /* end of dooption */ 92838905Sborman 92946809Sdab void 93039503Sborman send_wont(option, init) 93139503Sborman int option, init; 93239503Sborman { 93339503Sborman if (init) { 93444364Sborman if ((will_wont_resp[option] == 0 && my_state_is_wont(option)) || 93544364Sborman my_want_state_is_wont(option)) 93639503Sborman return; 93744364Sborman set_my_want_state_wont(option); 93839503Sborman will_wont_resp[option]++; 93939503Sborman } 94039503Sborman (void) sprintf(nfrontp, wont, option); 94139503Sborman nfrontp += sizeof (wont) - 2; 94246809Sdab 94346809Sdab DIAG(TD_OPTIONS, printoption("td: send wont", option)); 94439503Sborman } 94538905Sborman 94646809Sdab void 94739503Sborman dontoption(option) 94839503Sborman int option; 94938905Sborman { 95038905Sborman /* 95138905Sborman * Process client input. 95238905Sborman */ 95340242Sborman 95446809Sdab 95546809Sdab DIAG(TD_OPTIONS, printoption("td: recv dont", option)); 95646809Sdab 95739503Sborman if (will_wont_resp[option]) { 95839503Sborman will_wont_resp[option]--; 95944364Sborman if (will_wont_resp[option] && my_state_is_wont(option)) 96039503Sborman will_wont_resp[option]--; 96139503Sborman } 96244364Sborman if ((will_wont_resp[option] == 0) && (my_want_state_is_will(option))) { 96338905Sborman switch (option) { 96438905Sborman case TELOPT_BINARY: 96538905Sborman init_termbuf(); 96638905Sborman tty_binaryout(0); 96738905Sborman set_termbuf(); 96838905Sborman break; 96938905Sborman 97039503Sborman case TELOPT_ECHO: /* we should stop echoing */ 97138905Sborman #ifdef LINEMODE 97245234Sborman # ifdef KLUDGELINEMODE 97345234Sborman if (lmodetype == NO_LINEMODE) 97445234Sborman # else 97545234Sborman if (his_state_is_wont(TELOPT_LINEMODE)) 97645234Sborman # endif 97738905Sborman #endif 97845234Sborman { 97938905Sborman init_termbuf(); 98038905Sborman tty_setecho(0); 98138905Sborman set_termbuf(); 98238905Sborman } 98338905Sborman break; 98438905Sborman 98538905Sborman case TELOPT_SGA: 98638905Sborman #if defined(LINEMODE) && defined(KLUDGELINEMODE) 98738905Sborman /* 98839503Sborman * If kludge linemode is in use, then we 98939503Sborman * must process an incoming do SGA for 99039503Sborman * linemode purposes. 99138905Sborman */ 99238905Sborman if (lmodetype == KLUDGE_LINEMODE) { 99338905Sborman /* 99439503Sborman * The client is asking us to turn 99539503Sborman * linemode on. 99638905Sborman */ 99738905Sborman clientstat(TELOPT_LINEMODE, WILL, 0); 99838905Sborman /* 99939503Sborman * If we did not turn line mode on, 100039503Sborman * then what do we say? Will SGA? 100139503Sborman * This violates design of telnet. 100239503Sborman * Gross. Very Gross. 100338905Sborman */ 100438905Sborman } 100545234Sborman break; 100645234Sborman #else 100745234Sborman set_my_want_state_wont(option); 100845234Sborman if (my_state_is_will(option)) 100945234Sborman send_wont(option, 0); 101045234Sborman set_my_state_wont(option); 101145234Sborman if (turn_on_sga ^= 1) 101245234Sborman send_will(option); 101345234Sborman return; 101438905Sborman #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ 101538905Sborman 101638905Sborman default: 101738905Sborman break; 101838905Sborman } 101938905Sborman 102044364Sborman set_my_want_state_wont(option); 102144364Sborman if (my_state_is_will(option)) 102244364Sborman send_wont(option, 0); 102338905Sborman } 102444364Sborman set_my_state_wont(option); 102538905Sborman 102638905Sborman } /* end of dontoption */ 102738905Sborman 102838905Sborman /* 102938905Sborman * suboption() 103038905Sborman * 103138905Sborman * Look at the sub-option buffer, and try to be helpful to the other 103238905Sborman * side. 103338905Sborman * 103438905Sborman * Currently we recognize: 103538905Sborman * 103638905Sborman * Terminal type is 103738905Sborman * Linemode 103838905Sborman * Window size 103938905Sborman * Terminal speed 104038905Sborman */ 104146809Sdab void 104238905Sborman suboption() 104338905Sborman { 104438905Sborman register int subchar; 104538905Sborman 104646809Sdab DIAG(TD_OPTIONS, {netflush(); printsub('<', subpointer, SB_LEN()+2);}); 104746809Sdab 104838905Sborman subchar = SB_GET(); 104938905Sborman switch (subchar) { 105038905Sborman case TELOPT_TSPEED: { 105138905Sborman register int xspeed, rspeed; 105238905Sborman 105344364Sborman if (his_state_is_wont(TELOPT_TSPEED)) /* Ignore if option disabled */ 105438905Sborman break; 105538905Sborman 105638905Sborman settimer(tspeedsubopt); 105738905Sborman 105838905Sborman if (SB_EOF() || SB_GET() != TELQUAL_IS) 105938905Sborman return; 106038905Sborman 106146809Sdab xspeed = atoi((char *)subpointer); 106238905Sborman 106338905Sborman while (SB_GET() != ',' && !SB_EOF()); 106438905Sborman if (SB_EOF()) 106538905Sborman return; 106638905Sborman 106746809Sdab rspeed = atoi((char *)subpointer); 106838905Sborman clientstat(TELOPT_TSPEED, xspeed, rspeed); 106938905Sborman 107038905Sborman break; 107138905Sborman 107238905Sborman } /* end of case TELOPT_TSPEED */ 107338905Sborman 107438905Sborman case TELOPT_TTYPE: { /* Yaaaay! */ 107544364Sborman static char terminalname[41]; 107638905Sborman 107744364Sborman if (his_state_is_wont(TELOPT_TTYPE)) /* Ignore if option disabled */ 107838905Sborman break; 107938905Sborman settimer(ttypesubopt); 108038905Sborman 108146809Sdab if (SB_EOF() || SB_GET() != TELQUAL_IS) { 108238905Sborman return; /* ??? XXX but, this is the most robust */ 108338905Sborman } 108438905Sborman 108544364Sborman terminaltype = terminalname; 108638905Sborman 108738905Sborman while ((terminaltype < (terminalname + sizeof terminalname-1)) && 108838905Sborman !SB_EOF()) { 108938905Sborman register int c; 109038905Sborman 109138905Sborman c = SB_GET(); 109238905Sborman if (isupper(c)) { 109338905Sborman c = tolower(c); 109438905Sborman } 109538905Sborman *terminaltype++ = c; /* accumulate name */ 109638905Sborman } 109738905Sborman *terminaltype = 0; 109838905Sborman terminaltype = terminalname; 109938905Sborman break; 110038905Sborman } /* end of case TELOPT_TTYPE */ 110138905Sborman 110238905Sborman case TELOPT_NAWS: { 110338905Sborman register int xwinsize, ywinsize; 110438905Sborman 110544364Sborman if (his_state_is_wont(TELOPT_NAWS)) /* Ignore if option disabled */ 110638905Sborman break; 110738905Sborman 110838905Sborman if (SB_EOF()) 110938905Sborman return; 111038905Sborman xwinsize = SB_GET() << 8; 111138905Sborman if (SB_EOF()) 111238905Sborman return; 111338905Sborman xwinsize |= SB_GET(); 111438905Sborman if (SB_EOF()) 111538905Sborman return; 111638905Sborman ywinsize = SB_GET() << 8; 111738905Sborman if (SB_EOF()) 111838905Sborman return; 111938905Sborman ywinsize |= SB_GET(); 112038905Sborman clientstat(TELOPT_NAWS, xwinsize, ywinsize); 112138905Sborman 112238905Sborman break; 112338905Sborman 112438905Sborman } /* end of case TELOPT_NAWS */ 112538905Sborman 112638905Sborman #ifdef LINEMODE 112738905Sborman case TELOPT_LINEMODE: { 112838905Sborman register int request; 112938905Sborman 113044364Sborman if (his_state_is_wont(TELOPT_LINEMODE)) /* Ignore if option disabled */ 113138905Sborman break; 113238905Sborman /* 113338905Sborman * Process linemode suboptions. 113438905Sborman */ 113546809Sdab if (SB_EOF()) 113646809Sdab break; /* garbage was sent */ 113746809Sdab request = SB_GET(); /* get will/wont */ 113838905Sborman 113946809Sdab if (SB_EOF()) 114046809Sdab break; /* another garbage check */ 114146809Sdab 114238905Sborman if (request == LM_SLC) { /* SLC is not preceeded by WILL or WONT */ 114338905Sborman /* 114438905Sborman * Process suboption buffer of slc's 114538905Sborman */ 114638905Sborman start_slc(1); 114738905Sborman do_opt_slc(subpointer, subend - subpointer); 114846809Sdab (void) end_slc(0); 114946809Sdab break; 115038905Sborman } else if (request == LM_MODE) { 115146809Sdab if (SB_EOF()) 115246809Sdab return; 115338905Sborman useeditmode = SB_GET(); /* get mode flag */ 115438905Sborman clientstat(LM_MODE, 0, 0); 115546809Sdab break; 115638905Sborman } 115738905Sborman 115846809Sdab if (SB_EOF()) 115946809Sdab break; 116038905Sborman switch (SB_GET()) { /* what suboption? */ 116138905Sborman case LM_FORWARDMASK: 116238905Sborman /* 116338905Sborman * According to spec, only server can send request for 116438905Sborman * forwardmask, and client can only return a positive response. 116538905Sborman * So don't worry about it. 116638905Sborman */ 116738905Sborman 116838905Sborman default: 116938905Sborman break; 117038905Sborman } 117140242Sborman break; 117238905Sborman } /* end of case TELOPT_LINEMODE */ 117338905Sborman #endif 117438905Sborman case TELOPT_STATUS: { 117538905Sborman int mode; 117638905Sborman 117746809Sdab if (SB_EOF()) 117846809Sdab break; 117938905Sborman mode = SB_GET(); 118038905Sborman switch (mode) { 118138905Sborman case TELQUAL_SEND: 118244364Sborman if (my_state_is_will(TELOPT_STATUS)) 118338905Sborman send_status(); 118438905Sborman break; 118538905Sborman 118638905Sborman case TELQUAL_IS: 118738905Sborman break; 118838905Sborman 118938905Sborman default: 119038905Sborman break; 119138905Sborman } 119240242Sborman break; 119340242Sborman } /* end of case TELOPT_STATUS */ 119438905Sborman 119544364Sborman case TELOPT_XDISPLOC: { 119644364Sborman if (SB_EOF() || SB_GET() != TELQUAL_IS) 119744364Sborman return; 119844364Sborman settimer(xdisplocsubopt); 119944364Sborman subpointer[SB_LEN()] = '\0'; 120046809Sdab (void)setenv("DISPLAY", (char *)subpointer, 1); 120144364Sborman break; 120244364Sborman } /* end of case TELOPT_XDISPLOC */ 120344364Sborman 120444364Sborman case TELOPT_ENVIRON: { 120544364Sborman register int c; 120644364Sborman register char *cp, *varp, *valp; 120744364Sborman 120844364Sborman if (SB_EOF()) 120944364Sborman return; 121044364Sborman c = SB_GET(); 121144364Sborman if (c == TELQUAL_IS) 121244364Sborman settimer(environsubopt); 121344364Sborman else if (c != TELQUAL_INFO) 121444364Sborman return; 121544364Sborman 121644364Sborman while (!SB_EOF() && SB_GET() != ENV_VAR) 121744364Sborman ; 121844364Sborman 121944364Sborman if (SB_EOF()) 122044364Sborman return; 122144364Sborman 122246809Sdab cp = varp = (char *)subpointer; 122344364Sborman valp = 0; 122444364Sborman 122544364Sborman while (!SB_EOF()) { 122644364Sborman switch (c = SB_GET()) { 122744364Sborman case ENV_VALUE: 122844364Sborman *cp = '\0'; 122946809Sdab cp = valp = (char *)subpointer; 123044364Sborman break; 123144364Sborman 123244364Sborman case ENV_VAR: 123344364Sborman *cp = '\0'; 123444364Sborman if (valp) 123546809Sdab (void)setenv(varp, valp, 1); 123644364Sborman else 123744364Sborman unsetenv(varp); 123846809Sdab cp = varp = (char *)subpointer; 123944364Sborman valp = 0; 124044364Sborman break; 124144364Sborman 124244364Sborman case ENV_ESC: 124344364Sborman if (SB_EOF()) 124444364Sborman break; 124544364Sborman c = SB_GET(); 124644364Sborman /* FALL THROUGH */ 124744364Sborman default: 124844364Sborman *cp++ = c; 124944364Sborman break; 125044364Sborman } 125144364Sborman } 125244364Sborman *cp = '\0'; 125344364Sborman if (valp) 125446809Sdab (void)setenv(varp, valp, 1); 125544364Sborman else 125644364Sborman unsetenv(varp); 125744364Sborman break; 125844364Sborman } /* end of case TELOPT_ENVIRON */ 125946809Sdab #if defined(AUTHENTICATE) 126046809Sdab case TELOPT_AUTHENTICATION: 126146809Sdab if (SB_EOF()) 126246809Sdab break; 126346809Sdab switch(SB_GET()) { 126446809Sdab case TELQUAL_SEND: 126546809Sdab case TELQUAL_REPLY: 126646809Sdab /* 126746809Sdab * These are sent by us and cannot be sent by 126846809Sdab * the client. 126946809Sdab */ 127046809Sdab break; 127146809Sdab case TELQUAL_IS: 127246809Sdab auth_is(subpointer, SB_LEN()); 127346809Sdab break; 1274*47611Sdab case TELQUAL_NAME: 1275*47611Sdab auth_name(subpointer, SB_LEN()); 1276*47611Sdab break; 127746809Sdab } 127846809Sdab break; 127946809Sdab #endif 128046809Sdab #if defined(ENCRYPT) 128146809Sdab case TELOPT_ENCRYPT: 128246809Sdab if (SB_EOF()) 128346809Sdab break; 128446809Sdab switch(SB_GET()) { 128546809Sdab case ENCRYPT_SUPPORT: 128646809Sdab encrypt_support(subpointer, SB_LEN()); 128746809Sdab break; 128846809Sdab case ENCRYPT_IS: 128946809Sdab encrypt_is(subpointer, SB_LEN()); 129046809Sdab break; 129146809Sdab case ENCRYPT_REPLY: 129246809Sdab encrypt_reply(subpointer, SB_LEN()); 129346809Sdab break; 129446809Sdab case ENCRYPT_START: 1295*47611Sdab encrypt_start(subpointer, SB_LEN()); 129646809Sdab break; 129746809Sdab case ENCRYPT_END: 129846809Sdab encrypt_end(); 129946809Sdab break; 130046809Sdab case ENCRYPT_REQSTART: 1301*47611Sdab encrypt_request_start(subpointer, SB_LEN()); 130246809Sdab break; 130346809Sdab case ENCRYPT_REQEND: 130446809Sdab /* 130546809Sdab * We can always send an REQEND so that we cannot 130646809Sdab * get stuck encrypting. We should only get this 130746809Sdab * if we have been able to get in the correct mode 130846809Sdab * anyhow. 130946809Sdab */ 131046809Sdab encrypt_request_end(); 131146809Sdab break; 1312*47611Sdab case ENCRYPT_ENC_KEYID: 1313*47611Sdab encrypt_enc_keyid(subpointer, SB_LEN()); 1314*47611Sdab break; 1315*47611Sdab case ENCRYPT_DEC_KEYID: 1316*47611Sdab encrypt_dec_keyid(subpointer, SB_LEN()); 1317*47611Sdab break; 131846809Sdab default: 131946809Sdab break; 132046809Sdab } 132146809Sdab break; 132246809Sdab #endif 132344364Sborman 132438905Sborman default: 132538905Sborman break; 132638905Sborman } /* end of switch */ 132738905Sborman 132838905Sborman } /* end of suboption */ 132938905Sborman 133046809Sdab void 133146809Sdab doclientstat() 133246809Sdab { 133346809Sdab clientstat(TELOPT_LINEMODE, WILL, 0); 133446809Sdab } 133546809Sdab 133638905Sborman #define ADD(c) *ncp++ = c; 133738905Sborman #define ADD_DATA(c) { *ncp++ = c; if (c == SE) *ncp++ = c; } 133846809Sdab void 133938905Sborman send_status() 134038905Sborman { 134144364Sborman unsigned char statusbuf[256]; 134244364Sborman register unsigned char *ncp; 134344364Sborman register unsigned char i; 134438905Sborman 134538905Sborman ncp = statusbuf; 134638905Sborman 134738905Sborman netflush(); /* get rid of anything waiting to go out */ 134838905Sborman 134938905Sborman ADD(IAC); 135038905Sborman ADD(SB); 135138905Sborman ADD(TELOPT_STATUS); 135238905Sborman ADD(TELQUAL_IS); 135338905Sborman 135446809Sdab /* 135546809Sdab * We check the want_state rather than the current state, 135646809Sdab * because if we received a DO/WILL for an option that we 135746809Sdab * don't support, and the other side didn't send a DONT/WONT 135846809Sdab * in response to our WONT/DONT, then the "state" will be 135946809Sdab * WILL/DO, and the "want_state" will be WONT/DONT. We 136046809Sdab * need to go by the latter. 136146809Sdab */ 136238905Sborman for (i = 0; i < NTELOPTS; i++) { 136346809Sdab if (my_want_state_is_will(i)) { 136438905Sborman ADD(WILL); 136538905Sborman ADD_DATA(i); 136638905Sborman if (i == IAC) 136738905Sborman ADD(IAC); 136838905Sborman } 136946809Sdab if (his_want_state_is_will(i)) { 137038905Sborman ADD(DO); 137138905Sborman ADD_DATA(i); 137238905Sborman if (i == IAC) 137338905Sborman ADD(IAC); 137438905Sborman } 137538905Sborman } 137638905Sborman 137746809Sdab if (his_want_state_is_will(TELOPT_LFLOW)) { 137846809Sdab ADD(SB); 137946809Sdab ADD(TELOPT_LFLOW); 138046809Sdab ADD(flowmode); 138146809Sdab ADD(SE); 138246809Sdab } 138346809Sdab 138438905Sborman #ifdef LINEMODE 138546809Sdab if (his_want_state_is_will(TELOPT_LINEMODE)) { 138644364Sborman unsigned char *cp, *cpe; 138738905Sborman int len; 138838905Sborman 138938905Sborman ADD(SB); 139038905Sborman ADD(TELOPT_LINEMODE); 139138905Sborman ADD(LM_MODE); 139238905Sborman ADD_DATA(editmode); 139338905Sborman if (editmode == IAC) 139438905Sborman ADD(IAC); 139538905Sborman ADD(SE); 139638905Sborman 139738905Sborman ADD(SB); 139838905Sborman ADD(TELOPT_LINEMODE); 139938905Sborman ADD(LM_SLC); 140038905Sborman start_slc(0); 140138905Sborman send_slc(); 140238905Sborman len = end_slc(&cp); 140338905Sborman for (cpe = cp + len; cp < cpe; cp++) 140438905Sborman ADD_DATA(*cp); 140538905Sborman ADD(SE); 140638905Sborman } 140738905Sborman #endif /* LINEMODE */ 140838905Sborman 140938905Sborman ADD(IAC); 141038905Sborman ADD(SE); 141138905Sborman 141238905Sborman writenet(statusbuf, ncp - statusbuf); 141338905Sborman netflush(); /* Send it on its way */ 141446809Sdab 141546809Sdab DIAG(TD_OPTIONS, 141646809Sdab {printsub('>', statusbuf, ncp - statusbuf); netflush();}); 141738905Sborman } 1418