|
|
1.1 root 1: /*
2: * Copyright (c) 1989 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted provided
6: * that: (1) source distributions retain this entire copyright notice and
7: * comment, and (2) distributions including binaries display the following
8: * acknowledgement: ``This product includes software developed by the
9: * University of California, Berkeley and its contributors'' in the
10: * documentation or other materials provided with the distribution and in
11: * all advertising materials mentioning features or use of this software.
12: * Neither the name of the University nor the names of its contributors may
13: * be used to endorse or promote products derived from this software without
14: * specific prior written permission.
15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
16: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
17: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18: */
19:
20: #ifndef lint
21: static char sccsid[] = "@(#)state.c 5.7 (Berkeley) 6/28/90";
22: #endif /* not lint */
23:
24: #include "telnetd.h"
25:
26: char doopt[] = { IAC, DO, '%', 'c', 0 };
27: char dont[] = { IAC, DONT, '%', 'c', 0 };
28: char will[] = { IAC, WILL, '%', 'c', 0 };
29: char wont[] = { IAC, WONT, '%', 'c', 0 };
30: int not42 = 1;
31:
32: /*
33: * Buffer for sub-options, and macros
34: * for suboptions buffer manipulations
35: */
36: char subbuffer[100], *subpointer= subbuffer, *subend= subbuffer;
37:
38: #define SB_CLEAR() subpointer = subbuffer;
39: #define SB_TERM() { subend = subpointer; SB_CLEAR(); }
40: #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \
41: *subpointer++ = (c); \
42: }
43: #define SB_GET() ((*subpointer++)&0xff)
44: #define SB_EOF() (subpointer >= subend)
45: #define SB_LEN() (subend - subpointer)
46:
47:
48:
49: /*
50: * State for recv fsm
51: */
52: #define TS_DATA 0 /* base state */
53: #define TS_IAC 1 /* look for double IAC's */
54: #define TS_CR 2 /* CR-LF ->'s CR */
55: #define TS_SB 3 /* throw away begin's... */
56: #define TS_SE 4 /* ...end's (suboption negotiation) */
57: #define TS_WILL 5 /* will option negotiation */
58: #define TS_WONT 6 /* wont " */
59: #define TS_DO 7 /* do " */
60: #define TS_DONT 8 /* dont " */
61:
62: telrcv()
63: {
64: register int c;
65: static int state = TS_DATA;
66: #if defined(CRAY2) && defined(UNICOS5)
67: char *opfrontp = pfrontp;
68: #endif
69:
70: while (ncc > 0) {
71: if ((&ptyobuf[BUFSIZ] - pfrontp) < 2)
72: break;
73: c = *netip++ & 0377, ncc--;
74: switch (state) {
75:
76: case TS_CR:
77: state = TS_DATA;
78: /* Strip off \n or \0 after a \r */
79: if ((c == 0) || (c == '\n')) {
80: break;
81: }
82: /* FALL THROUGH */
83:
84: case TS_DATA:
85: if (c == IAC) {
86: state = TS_IAC;
87: break;
88: }
89: /*
90: * We now map \r\n ==> \r for pragmatic reasons.
91: * Many client implementations send \r\n when
92: * the user hits the CarriageReturn key.
93: *
94: * We USED to map \r\n ==> \n, since \r\n says
95: * that we want to be in column 1 of the next
96: * printable line, and \n is the standard
97: * unix way of saying that (\r is only good
98: * if CRMOD is set, which it normally is).
99: */
100: if ((c == '\r') && his_state_is_wont(TELOPT_BINARY)) {
101: /*
102: * If we are operating in linemode,
103: * convert to local end-of-line.
104: */
105: if ((linemode) && (ncc > 0)&&('\n' == *netip)) {
106: netip++; ncc--;
107: c = '\n';
108: } else {
109: state = TS_CR;
110: }
111: }
112: *pfrontp++ = c;
113: break;
114:
115: case TS_IAC:
116: gotiac: switch (c) {
117:
118: /*
119: * Send the process on the pty side an
120: * interrupt. Do this with a NULL or
121: * interrupt char; depending on the tty mode.
122: */
123: case IP:
124: #ifdef DIAGNOSTICS
125: if (diagnostic & TD_OPTIONS)
126: printoption("td: recv IAC", c);
127: #endif /* DIAGNOSTICS */
128: interrupt();
129: break;
130:
131: case BREAK:
132: #ifdef DIAGNOSTICS
133: if (diagnostic & TD_OPTIONS)
134: printoption("td: recv IAC", c);
135: #endif /* DIAGNOSTICS */
136: sendbrk();
137: break;
138:
139: /*
140: * Are You There?
141: */
142: case AYT:
143: #ifdef DIAGNOSTICS
144: if (diagnostic & TD_OPTIONS)
145: printoption("td: recv IAC", c);
146: #endif /* DIAGNOSTICS */
147: (void) strcpy(nfrontp, "\r\n[Yes]\r\n");
148: nfrontp += 9;
149: break;
150:
151: /*
152: * Abort Output
153: */
154: case AO:
155: {
156: #ifdef DIAGNOSTICS
157: if (diagnostic & TD_OPTIONS)
158: printoption("td: recv IAC", c);
159: #endif /* DIAGNOSTICS */
160: ptyflush(); /* half-hearted */
161: init_termbuf();
162:
163: if (slctab[SLC_AO].sptr &&
164: *slctab[SLC_AO].sptr != (cc_t)-1) {
165: *pfrontp++ =
166: (unsigned char)*slctab[SLC_AO].sptr;
167: }
168:
169: netclear(); /* clear buffer back */
170: *nfrontp++ = IAC;
171: *nfrontp++ = DM;
172: neturg = nfrontp-1; /* off by one XXX */
173: #ifdef DIAGNOSTICS
174: if (diagnostic & TD_OPTIONS)
175: printoption("td: send IAC", DM);
176: #endif /* DIAGNOSTICS */
177: break;
178: }
179:
180: /*
181: * Erase Character and
182: * Erase Line
183: */
184: case EC:
185: case EL:
186: {
187: cc_t ch;
188:
189: #ifdef DIAGNOSTICS
190: if (diagnostic & TD_OPTIONS)
191: printoption("td: recv IAC", c);
192: #endif /* DIAGNOSTICS */
193: ptyflush(); /* half-hearted */
194: init_termbuf();
195: if (c == EC)
196: ch = *slctab[SLC_EC].sptr;
197: else
198: ch = *slctab[SLC_EL].sptr;
199: if (ch != (cc_t)-1)
200: *pfrontp++ = (unsigned char)ch;
201: break;
202: }
203:
204: /*
205: * Check for urgent data...
206: */
207: case DM:
208: #ifdef DIAGNOSTICS
209: if (diagnostic & TD_OPTIONS)
210: printoption("td: recv IAC", c);
211: #endif /* DIAGNOSTICS */
212: SYNCHing = stilloob(net);
213: settimer(gotDM);
214: break;
215:
216:
217: /*
218: * Begin option subnegotiation...
219: */
220: case SB:
221: state = TS_SB;
222: SB_CLEAR();
223: continue;
224:
225: case WILL:
226: state = TS_WILL;
227: continue;
228:
229: case WONT:
230: state = TS_WONT;
231: continue;
232:
233: case DO:
234: state = TS_DO;
235: continue;
236:
237: case DONT:
238: state = TS_DONT;
239: continue;
240: case EOR:
241: if (his_state_is_will(TELOPT_EOR))
242: doeof();
243: break;
244:
245: /*
246: * Handle RFC 10xx Telnet linemode option additions
247: * to command stream (EOF, SUSP, ABORT).
248: */
249: case xEOF:
250: doeof();
251: break;
252:
253: case SUSP:
254: sendsusp();
255: break;
256:
257: case ABORT:
258: sendbrk();
259: break;
260:
261: case IAC:
262: *pfrontp++ = c;
263: break;
264: }
265: state = TS_DATA;
266: break;
267:
268: case TS_SB:
269: if (c == IAC) {
270: state = TS_SE;
271: } else {
272: SB_ACCUM(c);
273: }
274: break;
275:
276: case TS_SE:
277: if (c != SE) {
278: if (c != IAC) {
279: /*
280: * bad form of suboption negotiation.
281: * handle it in such a way as to avoid
282: * damage to local state. Parse
283: * suboption buffer found so far,
284: * then treat remaining stream as
285: * another command sequence.
286: */
287: #ifdef DIAGNOSTICS
288: SB_ACCUM(IAC);
289: SB_ACCUM(c);
290: subpointer -= 2;
291: #endif
292: SB_TERM();
293: suboption();
294: state = TS_IAC;
295: goto gotiac;
296: }
297: SB_ACCUM(c);
298: state = TS_SB;
299: } else {
300: #ifdef DIAGNOSTICS
301: SB_ACCUM(IAC);
302: SB_ACCUM(SE);
303: subpointer -= 2;
304: #endif
305: SB_TERM();
306: suboption(); /* handle sub-option */
307: state = TS_DATA;
308: }
309: break;
310:
311: case TS_WILL:
312: willoption(c);
313: state = TS_DATA;
314: continue;
315:
316: case TS_WONT:
317: wontoption(c);
318: state = TS_DATA;
319: continue;
320:
321: case TS_DO:
322: dooption(c);
323: state = TS_DATA;
324: continue;
325:
326: case TS_DONT:
327: dontoption(c);
328: state = TS_DATA;
329: continue;
330:
331: default:
332: syslog(LOG_ERR, "telnetd: panic state=%d\n", state);
333: printf("telnetd: panic state=%d\n", state);
334: exit(1);
335: }
336: }
337: #if defined(CRAY2) && defined(UNICOS5)
338: if (!linemode) {
339: char xptyobuf[BUFSIZ+NETSLOP];
340: char xbuf2[BUFSIZ];
341: register char *cp;
342: int n = pfrontp - opfrontp, oc;
343: bcopy(opfrontp, xptyobuf, n);
344: pfrontp = opfrontp;
345: pfrontp += term_input(xptyobuf, pfrontp, n, BUFSIZ+NETSLOP,
346: xbuf2, &oc, BUFSIZ);
347: for (cp = xbuf2; oc > 0; --oc)
348: if ((*nfrontp++ = *cp++) == IAC)
349: *nfrontp++ = IAC;
350: }
351: #endif /* defined(CRAY2) && defined(UNICOS5) */
352: } /* end of telrcv */
353:
354: /*
355: * The will/wont/do/dont state machines are based on Dave Borman's
356: * Telnet option processing state machine.
357: *
358: * These correspond to the following states:
359: * my_state = the last negotiated state
360: * want_state = what I want the state to go to
361: * want_resp = how many requests I have sent
362: * All state defaults are negative, and resp defaults to 0.
363: *
364: * When initiating a request to change state to new_state:
365: *
366: * if ((want_resp == 0 && new_state == my_state) || want_state == new_state) {
367: * do nothing;
368: * } else {
369: * want_state = new_state;
370: * send new_state;
371: * want_resp++;
372: * }
373: *
374: * When receiving new_state:
375: *
376: * if (want_resp) {
377: * want_resp--;
378: * if (want_resp && (new_state == my_state))
379: * want_resp--;
380: * }
381: * if ((want_resp == 0) && (new_state != want_state)) {
382: * if (ok_to_switch_to new_state)
383: * want_state = new_state;
384: * else
385: * want_resp++;
386: * send want_state;
387: * }
388: * my_state = new_state;
389: *
390: * Note that new_state is implied in these functions by the function itself.
391: * will and do imply positive new_state, wont and dont imply negative.
392: *
393: * Finally, there is one catch. If we send a negative response to a
394: * positive request, my_state will be the positive while want_state will
395: * remain negative. my_state will revert to negative when the negative
396: * acknowlegment arrives from the peer. Thus, my_state generally tells
397: * us not only the last negotiated state, but also tells us what the peer
398: * wants to be doing as well. It is important to understand this difference
399: * as we may wish to be processing data streams based on our desired state
400: * (want_state) or based on what the peer thinks the state is (my_state).
401: *
402: * This all works fine because if the peer sends a positive request, the data
403: * that we receive prior to negative acknowlegment will probably be affected
404: * by the positive state, and we can process it as such (if we can; if we
405: * can't then it really doesn't matter). If it is that important, then the
406: * peer probably should be buffering until this option state negotiation
407: * is complete.
408: *
409: */
410: send_do(option, init)
411: int option, init;
412: {
413: if (init) {
414: if ((do_dont_resp[option] == 0 && his_state_is_will(option)) ||
415: his_want_state_is_will(option))
416: return;
417: /*
418: * Special case for TELOPT_TM: We send a DO, but pretend
419: * that we sent a DONT, so that we can send more DOs if
420: * we want to.
421: */
422: if (option == TELOPT_TM)
423: set_his_want_state_wont(option);
424: else
425: set_his_want_state_will(option);
426: do_dont_resp[option]++;
427: }
428: (void) sprintf(nfrontp, doopt, option);
429: nfrontp += sizeof (dont) - 2;
430: #ifdef DIAGNOSTICS
431: /*
432: * Report sending option to other side.
433: */
434: if (diagnostic & TD_OPTIONS) {
435: printoption("td: send do", option);
436: }
437: #endif /* DIAGNOSTICS */
438: }
439:
440: willoption(option)
441: int option;
442: {
443: int changeok = 0;
444:
445: /*
446: * process input from peer.
447: */
448:
449: #ifdef DIAGNOSTICS
450: /*
451: * Report receiving option from other side.
452: */
453: if (diagnostic & TD_OPTIONS) {
454: printoption("td: recv will", option);
455: }
456: #endif /* DIAGNOSTICS */
457:
458: if (do_dont_resp[option]) {
459: do_dont_resp[option]--;
460: if (do_dont_resp[option] && his_state_is_will(option))
461: do_dont_resp[option]--;
462: }
463: if (do_dont_resp[option] == 0) {
464: if (his_want_state_is_wont(option)) {
465: switch (option) {
466:
467: case TELOPT_BINARY:
468: init_termbuf();
469: tty_binaryin(1);
470: set_termbuf();
471: changeok++;
472: break;
473:
474: case TELOPT_ECHO:
475: /*
476: * See comments below for more info.
477: */
478: not42 = 0; /* looks like a 4.2 system */
479: break;
480:
481: case TELOPT_TM:
482: #if defined(LINEMODE) && defined(KLUDGELINEMODE)
483: /*
484: * This telnetd implementation does not really
485: * support timing marks, it just uses them to
486: * support the kludge linemode stuff. If we
487: * receive a will or wont TM in response to our
488: * do TM request that may have been sent to
489: * determine kludge linemode support, process
490: * it, otherwise TM should get a negative
491: * response back.
492: */
493: /*
494: * Handle the linemode kludge stuff.
495: * If we are not currently supporting any
496: * linemode at all, then we assume that this
497: * is the client telling us to use kludge
498: * linemode in response to our query. Set the
499: * linemode type that is to be supported, note
500: * that the client wishes to use linemode, and
501: * eat the will TM as though it never arrived.
502: */
503: if (lmodetype < KLUDGE_LINEMODE) {
504: lmodetype = KLUDGE_LINEMODE;
505: clientstat(TELOPT_LINEMODE, WILL, 0);
506: send_wont(TELOPT_SGA, 1);
507: }
508: #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
509: /*
510: * We never respond to a WILL TM, and
511: * we leave the state WONT.
512: */
513: return;
514:
515: case TELOPT_LFLOW:
516: /*
517: * If we are going to support flow control
518: * option, then don't worry peer that we can't
519: * change the flow control characters.
520: */
521: slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS;
522: slctab[SLC_XON].defset.flag |= SLC_DEFAULT;
523: slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS;
524: slctab[SLC_XOFF].defset.flag |= SLC_DEFAULT;
525: case TELOPT_TTYPE:
526: case TELOPT_SGA:
527: case TELOPT_NAWS:
528: case TELOPT_TSPEED:
529: case TELOPT_XDISPLOC:
530: case TELOPT_ENVIRON:
531: changeok++;
532: break;
533:
534: #ifdef LINEMODE
535: case TELOPT_LINEMODE:
536: /*
537: * Local processing of 'will linemode' should
538: * occur after placing 'do linemode' in the data
539: * stream, because we may wish to send other
540: * linemode related messages. So, we duplicate
541: * the other three lines of code here, and then
542: * return.
543: */
544: set_his_want_state_will(option);
545: send_do(option, 0);
546: set_his_state_will(option);
547: # ifdef KLUDGELINEMODE
548: /*
549: * Note client's desire to use linemode.
550: */
551: lmodetype = REAL_LINEMODE;
552: # endif /* KLUDGELINEMODE */
553: clientstat(TELOPT_LINEMODE, WILL, 0);
554: return;
555: #endif /* LINEMODE */
556:
557: default:
558: break;
559: }
560: if (changeok) {
561: set_his_want_state_will(option);
562: send_do(option, 0);
563: } else {
564: do_dont_resp[option]++;
565: send_dont(option, 0);
566: }
567: } else {
568: /*
569: * Option processing that should happen when
570: * we receive conformation of a change in
571: * state that we had requested.
572: */
573: switch (option) {
574: case TELOPT_ECHO:
575: not42 = 0; /* looks like a 4.2 system */
576: /*
577: * Egads, he responded "WILL ECHO". Turn
578: * it off right now!
579: */
580: send_dont(option, 1);
581: /*
582: * "WILL ECHO". Kludge upon kludge!
583: * A 4.2 client is now echoing user input at
584: * the tty. This is probably undesireable and
585: * it should be stopped. The client will
586: * respond WONT TM to the DO TM that we send to
587: * check for kludge linemode. When the WONT TM
588: * arrives, linemode will be turned off and a
589: * change propogated to the pty. This change
590: * will cause us to process the new pty state
591: * in localstat(), which will notice that
592: * linemode is off and send a WILL ECHO
593: * so that we are properly in character mode and
594: * all is well.
595: */
596: break;
597: #ifdef LINEMODE
598: case TELOPT_LINEMODE:
599: # ifdef KLUDGELINEMODE
600: /*
601: * Note client's desire to use linemode.
602: */
603: lmodetype = REAL_LINEMODE;
604: # endif /* KLUDGELINEMODE */
605: clientstat(TELOPT_LINEMODE, WILL, 0);
606: #endif /* LINEMODE */
607: }
608: }
609: }
610: set_his_state_will(option);
611: } /* end of willoption */
612:
613: send_dont(option, init)
614: int option, init;
615: {
616: if (init) {
617: if ((do_dont_resp[option] == 0 && his_state_is_wont(option)) ||
618: his_want_state_is_wont(option))
619: return;
620: set_his_want_state_wont(option);
621: do_dont_resp[option]++;
622: }
623: (void) sprintf(nfrontp, dont, option);
624: nfrontp += sizeof (doopt) - 2;
625: #ifdef DIAGNOSTICS
626: /*
627: * Report sending option to other side.
628: */
629: if (diagnostic & TD_OPTIONS) {
630: printoption("td: send dont", option);
631: }
632: #endif /* DIAGNOSTICS */
633: }
634:
635: wontoption(option)
636: int option;
637: {
638: /*
639: * Process client input.
640: */
641:
642: #ifdef DIAGNOSTICS
643: /*
644: * Report receiving option from other side.
645: */
646: if (diagnostic & TD_OPTIONS) {
647: printoption("td: recv wont", option);
648: }
649: #endif /* DIAGNOSTICS */
650:
651: if (do_dont_resp[option]) {
652: do_dont_resp[option]--;
653: if (do_dont_resp[option] && his_state_is_wont(option))
654: do_dont_resp[option]--;
655: }
656: if (do_dont_resp[option] == 0) {
657: if (his_want_state_is_will(option)) {
658: /* it is always ok to change to negative state */
659: switch (option) {
660: case TELOPT_ECHO:
661: not42 = 1; /* doesn't seem to be a 4.2 system */
662: break;
663:
664: case TELOPT_BINARY:
665: init_termbuf();
666: tty_binaryin(0);
667: set_termbuf();
668: break;
669:
670: #ifdef LINEMODE
671: case TELOPT_LINEMODE:
672: # ifdef KLUDGELINEMODE
673: /*
674: * If real linemode is supported, then client is
675: * asking to turn linemode off.
676: */
677: if (lmodetype != REAL_LINEMODE)
678: break;
679: lmodetype = KLUDGE_LINEMODE;
680: # endif /* KLUDGELINEMODE */
681: clientstat(TELOPT_LINEMODE, WONT, 0);
682: break;
683: #endif LINEMODE
684:
685: case TELOPT_TM:
686: /*
687: * If we get a WONT TM, and had sent a DO TM,
688: * don't respond with a DONT TM, just leave it
689: * as is. Short circut the state machine to
690: * achive this.
691: */
692: set_his_want_state_wont(TELOPT_TM);
693: return;
694:
695: case TELOPT_LFLOW:
696: /*
697: * If we are not going to support flow control
698: * option, then let peer know that we can't
699: * change the flow control characters.
700: */
701: slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS;
702: slctab[SLC_XON].defset.flag |= SLC_CANTCHANGE;
703: slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS;
704: slctab[SLC_XOFF].defset.flag |= SLC_CANTCHANGE;
705: break;
706:
707: /*
708: * For options that we might spin waiting for
709: * sub-negotiation, if the client turns off the
710: * option rather than responding to the request,
711: * we have to treat it here as if we got a response
712: * to the sub-negotiation, (by updating the timers)
713: * so that we'll break out of the loop.
714: */
715: case TELOPT_TTYPE:
716: settimer(ttypesubopt);
717: break;
718:
719: case TELOPT_TSPEED:
720: settimer(tspeedsubopt);
721: break;
722:
723: case TELOPT_XDISPLOC:
724: settimer(xdisplocsubopt);
725: break;
726:
727: case TELOPT_ENVIRON:
728: settimer(environsubopt);
729: break;
730:
731: default:
732: break;
733: }
734: set_his_want_state_wont(option);
735: if (his_state_is_will(option))
736: send_dont(option, 0);
737: } else {
738: switch (option) {
739: case TELOPT_TM:
740: #if defined(LINEMODE) && defined(KLUDGELINEMODE)
741: if (lmodetype < REAL_LINEMODE) {
742: lmodetype = NO_LINEMODE;
743: clientstat(TELOPT_LINEMODE, WONT, 0);
744: send_will(TELOPT_SGA, 1);
745: /*@*/ send_will(TELOPT_ECHO, 1);
746: }
747: #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
748: default:
749: break;
750: }
751: }
752: }
753: set_his_state_wont(option);
754:
755: } /* end of wontoption */
756:
757: send_will(option, init)
758: int option, init;
759: {
760: if (init) {
761: if ((will_wont_resp[option] == 0 && my_state_is_will(option))||
762: my_want_state_is_will(option))
763: return;
764: set_my_want_state_will(option);
765: will_wont_resp[option]++;
766: }
767: (void) sprintf(nfrontp, will, option);
768: nfrontp += sizeof (doopt) - 2;
769: #ifdef DIAGNOSTICS
770: /*
771: * Report sending option to other side.
772: */
773: if (diagnostic & TD_OPTIONS) {
774: printoption("td: send will", option);
775: }
776: #endif /* DIAGNOSTICS */
777: }
778:
779: dooption(option)
780: int option;
781: {
782: int changeok = 0;
783:
784: /*
785: * Process client input.
786: */
787:
788: #ifdef DIAGNOSTICS
789: /*
790: * Report receiving option from other side.
791: */
792: if (diagnostic & TD_OPTIONS) {
793: printoption("td: recv do", option);
794: }
795: #endif /* DIAGNOSTICS */
796:
797: if (will_wont_resp[option]) {
798: will_wont_resp[option]--;
799: if (will_wont_resp[option] && my_state_is_will(option))
800: will_wont_resp[option]--;
801: }
802: if ((will_wont_resp[option] == 0) && (my_want_state_is_wont(option))) {
803: switch (option) {
804: case TELOPT_ECHO:
805: #ifdef LINEMODE
806: if (lmodetype == NO_LINEMODE) {
807: #endif
808: init_termbuf();
809: tty_setecho(1);
810: set_termbuf();
811: #ifdef LINEMODE
812: }
813: #endif
814: changeok++;
815: break;
816:
817: case TELOPT_BINARY:
818: init_termbuf();
819: tty_binaryout(1);
820: set_termbuf();
821: changeok++;
822: break;
823:
824: case TELOPT_SGA:
825: #if defined(LINEMODE) && defined(KLUDGELINEMODE)
826: /*
827: * If kludge linemode is in use, then we must
828: * process an incoming do SGA for linemode
829: * purposes.
830: */
831: if (lmodetype == KLUDGE_LINEMODE) {
832: /*
833: * Receipt of "do SGA" in kludge
834: * linemode is the peer asking us to
835: * turn off linemode. Make note of
836: * the request.
837: */
838: clientstat(TELOPT_LINEMODE, WONT, 0);
839: /*
840: * If linemode did not get turned off
841: * then don't tell peer that we did.
842: * Breaking here forces a wont SGA to
843: * be returned.
844: */
845: if (linemode)
846: break;
847: }
848: #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
849: changeok++;
850: break;
851:
852: case TELOPT_STATUS:
853: changeok++;
854: break;
855:
856: case TELOPT_TM:
857: /*
858: * Special case for TM. We send a WILL, but
859: * pretend we sent a WONT.
860: */
861: send_will(option, 0);
862: set_my_want_state_wont(option);
863: set_my_state_wont(option);
864: return;
865:
866: case TELOPT_LINEMODE:
867: case TELOPT_TTYPE:
868: case TELOPT_NAWS:
869: case TELOPT_TSPEED:
870: case TELOPT_LFLOW:
871: case TELOPT_XDISPLOC:
872: case TELOPT_ENVIRON:
873: default:
874: break;
875: }
876: if (changeok) {
877: set_my_want_state_will(option);
878: send_will(option, 0);
879: } else {
880: will_wont_resp[option]++;
881: send_wont(option, 0);
882: }
883: }
884: set_my_state_will(option);
885:
886: } /* end of dooption */
887:
888: send_wont(option, init)
889: int option, init;
890: {
891: if (init) {
892: if ((will_wont_resp[option] == 0 && my_state_is_wont(option)) ||
893: my_want_state_is_wont(option))
894: return;
895: set_my_want_state_wont(option);
896: will_wont_resp[option]++;
897: }
898: (void) sprintf(nfrontp, wont, option);
899: nfrontp += sizeof (wont) - 2;
900: #ifdef DIAGNOSTICS
901: /*
902: * Report sending option to other side.
903: */
904: if (diagnostic & TD_OPTIONS) {
905: printoption("td: send wont", option);
906: }
907: #endif /* DIAGNOSTICS */
908: }
909:
910: dontoption(option)
911: int option;
912: {
913: /*
914: * Process client input.
915: */
916: #ifdef DIAGNOSTICS
917: /*
918: * Report receiving option from other side.
919: */
920: if (diagnostic & TD_OPTIONS) {
921: printoption("td: recv dont", option);
922: }
923: #endif /* DIAGNOSTICS */
924:
925: if (will_wont_resp[option]) {
926: will_wont_resp[option]--;
927: if (will_wont_resp[option] && my_state_is_wont(option))
928: will_wont_resp[option]--;
929: }
930: if ((will_wont_resp[option] == 0) && (my_want_state_is_will(option))) {
931: switch (option) {
932: case TELOPT_BINARY:
933: init_termbuf();
934: tty_binaryout(0);
935: set_termbuf();
936: break;
937:
938: case TELOPT_ECHO: /* we should stop echoing */
939: #ifdef LINEMODE
940: if (lmodetype == NO_LINEMODE) {
941: #endif
942: init_termbuf();
943: tty_setecho(0);
944: set_termbuf();
945: #ifdef LINEMODE
946: }
947: #endif
948: break;
949:
950: case TELOPT_SGA:
951: #if defined(LINEMODE) && defined(KLUDGELINEMODE)
952: /*
953: * If kludge linemode is in use, then we
954: * must process an incoming do SGA for
955: * linemode purposes.
956: */
957: if (lmodetype == KLUDGE_LINEMODE) {
958: /*
959: * The client is asking us to turn
960: * linemode on.
961: */
962: clientstat(TELOPT_LINEMODE, WILL, 0);
963: /*
964: * If we did not turn line mode on,
965: * then what do we say? Will SGA?
966: * This violates design of telnet.
967: * Gross. Very Gross.
968: */
969: }
970: #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
971:
972: default:
973: break;
974: }
975:
976: set_my_want_state_wont(option);
977: if (my_state_is_will(option))
978: send_wont(option, 0);
979: }
980: set_my_state_wont(option);
981:
982: } /* end of dontoption */
983:
984: /*
985: * suboption()
986: *
987: * Look at the sub-option buffer, and try to be helpful to the other
988: * side.
989: *
990: * Currently we recognize:
991: *
992: * Terminal type is
993: * Linemode
994: * Window size
995: * Terminal speed
996: */
997: suboption()
998: {
999: register int subchar;
1000: extern void unsetenv();
1001:
1002: #ifdef DIAGNOSTICS
1003: /*
1004: * Report receiving option from other side.
1005: */
1006: if (diagnostic & TD_OPTIONS) {
1007: netflush(); /* get rid of anything waiting to go out */
1008: printsub("td: recv", subpointer, SB_LEN()+2);
1009: }
1010: #endif DIAGNOSTIC
1011: subchar = SB_GET();
1012: switch (subchar) {
1013: case TELOPT_TSPEED: {
1014: register int xspeed, rspeed;
1015:
1016: if (his_state_is_wont(TELOPT_TSPEED)) /* Ignore if option disabled */
1017: break;
1018:
1019: settimer(tspeedsubopt);
1020:
1021: if (SB_EOF() || SB_GET() != TELQUAL_IS)
1022: return;
1023:
1024: xspeed = atoi(subpointer);
1025:
1026: while (SB_GET() != ',' && !SB_EOF());
1027: if (SB_EOF())
1028: return;
1029:
1030: rspeed = atoi(subpointer);
1031: clientstat(TELOPT_TSPEED, xspeed, rspeed);
1032:
1033: break;
1034:
1035: } /* end of case TELOPT_TSPEED */
1036:
1037: case TELOPT_TTYPE: { /* Yaaaay! */
1038: static char terminalname[41];
1039:
1040: if (his_state_is_wont(TELOPT_TTYPE)) /* Ignore if option disabled */
1041: break;
1042: settimer(ttypesubopt);
1043:
1044: if (SB_GET() != TELQUAL_IS) {
1045: return; /* ??? XXX but, this is the most robust */
1046: }
1047:
1048: terminaltype = terminalname;
1049:
1050: while ((terminaltype < (terminalname + sizeof terminalname-1)) &&
1051: !SB_EOF()) {
1052: register int c;
1053:
1054: c = SB_GET();
1055: if (isupper(c)) {
1056: c = tolower(c);
1057: }
1058: *terminaltype++ = c; /* accumulate name */
1059: }
1060: *terminaltype = 0;
1061: terminaltype = terminalname;
1062: break;
1063: } /* end of case TELOPT_TTYPE */
1064:
1065: case TELOPT_NAWS: {
1066: register int xwinsize, ywinsize;
1067:
1068: if (his_state_is_wont(TELOPT_NAWS)) /* Ignore if option disabled */
1069: break;
1070:
1071: if (SB_EOF())
1072: return;
1073: xwinsize = SB_GET() << 8;
1074: if (SB_EOF())
1075: return;
1076: xwinsize |= SB_GET();
1077: if (SB_EOF())
1078: return;
1079: ywinsize = SB_GET() << 8;
1080: if (SB_EOF())
1081: return;
1082: ywinsize |= SB_GET();
1083: clientstat(TELOPT_NAWS, xwinsize, ywinsize);
1084:
1085: break;
1086:
1087: } /* end of case TELOPT_NAWS */
1088:
1089: #ifdef LINEMODE
1090: case TELOPT_LINEMODE: {
1091: register int request;
1092:
1093: if (his_state_is_wont(TELOPT_LINEMODE)) /* Ignore if option disabled */
1094: break;
1095: /*
1096: * Process linemode suboptions.
1097: */
1098: if (SB_EOF()) break; /* garbage was sent */
1099: request = SB_GET(); /* get will/wont */
1100: if (SB_EOF()) break; /* another garbage check */
1101:
1102: if (request == LM_SLC) { /* SLC is not preceeded by WILL or WONT */
1103: /*
1104: * Process suboption buffer of slc's
1105: */
1106: start_slc(1);
1107: do_opt_slc(subpointer, subend - subpointer);
1108: end_slc(0);
1109:
1110: } else if (request == LM_MODE) {
1111: useeditmode = SB_GET(); /* get mode flag */
1112: clientstat(LM_MODE, 0, 0);
1113: }
1114:
1115: switch (SB_GET()) { /* what suboption? */
1116: case LM_FORWARDMASK:
1117: /*
1118: * According to spec, only server can send request for
1119: * forwardmask, and client can only return a positive response.
1120: * So don't worry about it.
1121: */
1122:
1123: default:
1124: break;
1125: }
1126: break;
1127: } /* end of case TELOPT_LINEMODE */
1128: #endif
1129: case TELOPT_STATUS: {
1130: int mode;
1131:
1132: mode = SB_GET();
1133: switch (mode) {
1134: case TELQUAL_SEND:
1135: if (my_state_is_will(TELOPT_STATUS))
1136: send_status();
1137: break;
1138:
1139: case TELQUAL_IS:
1140: break;
1141:
1142: default:
1143: break;
1144: }
1145: break;
1146: } /* end of case TELOPT_STATUS */
1147:
1148: case TELOPT_XDISPLOC: {
1149: if (SB_EOF() || SB_GET() != TELQUAL_IS)
1150: return;
1151: settimer(xdisplocsubopt);
1152: subpointer[SB_LEN()] = '\0';
1153: setenv("DISPLAY", subpointer, 1);
1154: break;
1155: } /* end of case TELOPT_XDISPLOC */
1156:
1157: case TELOPT_ENVIRON: {
1158: register int c;
1159: register char *cp, *varp, *valp;
1160:
1161: if (SB_EOF())
1162: return;
1163: c = SB_GET();
1164: if (c == TELQUAL_IS)
1165: settimer(environsubopt);
1166: else if (c != TELQUAL_INFO)
1167: return;
1168:
1169: while (!SB_EOF() && SB_GET() != ENV_VAR)
1170: ;
1171:
1172: if (SB_EOF())
1173: return;
1174:
1175: cp = varp = subpointer;
1176: valp = 0;
1177:
1178: while (!SB_EOF()) {
1179: switch (c = SB_GET()) {
1180: case ENV_VALUE:
1181: *cp = '\0';
1182: cp = valp = subpointer;
1183: break;
1184:
1185: case ENV_VAR:
1186: *cp = '\0';
1187: if (valp)
1188: setenv(varp, valp, 1);
1189: else
1190: unsetenv(varp);
1191: cp = varp = subpointer;
1192: valp = 0;
1193: break;
1194:
1195: case ENV_ESC:
1196: if (SB_EOF())
1197: break;
1198: c = SB_GET();
1199: /* FALL THROUGH */
1200: default:
1201: *cp++ = c;
1202: break;
1203: }
1204: }
1205: *cp = '\0';
1206: if (valp)
1207: setenv(varp, valp, 1);
1208: else
1209: unsetenv(varp);
1210: break;
1211: } /* end of case TELOPT_ENVIRON */
1212:
1213: default:
1214: break;
1215: } /* end of switch */
1216:
1217: } /* end of suboption */
1218:
1219: #define ADD(c) *ncp++ = c;
1220: #define ADD_DATA(c) { *ncp++ = c; if (c == SE) *ncp++ = c; }
1221: send_status()
1222: {
1223: unsigned char statusbuf[256];
1224: register unsigned char *ncp;
1225: register unsigned char i;
1226:
1227: ncp = statusbuf;
1228:
1229: netflush(); /* get rid of anything waiting to go out */
1230:
1231: ADD(IAC);
1232: ADD(SB);
1233: ADD(TELOPT_STATUS);
1234: ADD(TELQUAL_IS);
1235:
1236: for (i = 0; i < NTELOPTS; i++) {
1237: if (my_state_is_will(i)) {
1238: ADD(WILL);
1239: ADD_DATA(i);
1240: if (i == IAC)
1241: ADD(IAC);
1242: }
1243: if (his_state_is_will(i)) {
1244: ADD(DO);
1245: ADD_DATA(i);
1246: if (i == IAC)
1247: ADD(IAC);
1248: }
1249: }
1250:
1251: #ifdef LINEMODE
1252: if (his_state_is_will(TELOPT_LINEMODE)) {
1253: unsigned char *cp, *cpe;
1254: int len;
1255:
1256: ADD(SB);
1257: ADD(TELOPT_LINEMODE);
1258: ADD(LM_MODE);
1259: ADD_DATA(editmode);
1260: if (editmode == IAC)
1261: ADD(IAC);
1262: ADD(SE);
1263:
1264: ADD(SB);
1265: ADD(TELOPT_LINEMODE);
1266: ADD(LM_SLC);
1267: start_slc(0);
1268: send_slc();
1269: len = end_slc(&cp);
1270: for (cpe = cp + len; cp < cpe; cp++)
1271: ADD_DATA(*cp);
1272: ADD(SE);
1273: }
1274: #endif /* LINEMODE */
1275:
1276: ADD(IAC);
1277: ADD(SE);
1278:
1279: writenet(statusbuf, ncp - statusbuf);
1280: netflush(); /* Send it on its way */
1281: #ifdef DIAGNOSTICS
1282: /*
1283: * Report sending status suboption.
1284: */
1285: if (diagnostic & TD_OPTIONS) {
1286: printsub("td: send", statusbuf, ncp - statusbuf);
1287: netflush(); /* Send it on its way */
1288: }
1289: #endif DIAGNOSTIC
1290: }
1291:
1292: #ifdef NO_SETENV
1293: #include "setenv.c"
1294: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.