Annotation of src/usr.bin/telnet/telnet.c, Revision 1.21
1.21 ! guenther 1: /* $OpenBSD: telnet.c,v 1.20 2009/04/28 06:46:03 chl Exp $ */
1.2 niklas 2: /* $NetBSD: telnet.c,v 1.7 1996/02/28 21:04:15 thorpej Exp $ */
3:
1.1 deraadt 4: /*
5: * Copyright (c) 1988, 1990, 1993
6: * The Regents of the University of California. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
1.16 millert 16: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 17: * may be used to endorse or promote products derived from this software
18: * without specific prior written permission.
19: *
20: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30: * SUCH DAMAGE.
31: */
32:
1.4 art 33: #include "telnet_locl.h"
1.9 millert 34: #include <curses.h>
35: #include <term.h>
1.1 deraadt 36:
1.4 art 37: #define strip(x) (eight ? (x) : ((x) & 0x7f))
1.1 deraadt 38:
39: static unsigned char subbuffer[SUBBUFSIZE],
40: *subpointer, *subend; /* buffer for sub-options */
41: #define SB_CLEAR() subpointer = subbuffer;
42: #define SB_TERM() { subend = subpointer; SB_CLEAR(); }
43: #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \
44: *subpointer++ = (c); \
45: }
46:
47: #define SB_GET() ((*subpointer++)&0xff)
48: #define SB_PEEK() ((*subpointer)&0xff)
49: #define SB_EOF() (subpointer >= subend)
50: #define SB_LEN() (subend - subpointer)
51:
52: char options[256]; /* The combined options */
53: char do_dont_resp[256];
54: char will_wont_resp[256];
55:
56: int
1.4 art 57: eight = 3,
58: binary = 0,
1.1 deraadt 59: autologin = 0, /* Autologin anyone? */
60: skiprc = 0,
61: connected,
62: showoptions,
63: ISend, /* trying to send network data in */
64: debug = 0,
65: crmod,
66: netdata, /* Print out network data flow */
67: crlf, /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
68: telnetport,
1.15 hin 69: wantencryption = 0,
1.1 deraadt 70: SYNCHing, /* we are in TELNET SYNCH mode */
71: flushout, /* flush output */
72: autoflush = 0, /* flush output when interrupting? */
73: autosynch, /* send interrupt characters with SYNCH? */
74: localflow, /* we handle flow control locally */
75: restartany, /* if flow control enabled, restart on any character */
76: localchars, /* we recognize interrupt/quit */
77: donelclchars, /* the user has set "localchars" */
78: donebinarytoggle, /* the user has put us in binary */
79: dontlecho, /* do we suppress local echoing right now? */
80: globalmode,
81: clienteof = 0;
82:
83: char *prompt = 0;
84:
1.15 hin 85: int scheduler_lockout_tty = 0;
86:
1.1 deraadt 87: cc_t escape;
88: cc_t rlogin;
89: #ifdef KLUDGELINEMODE
90: cc_t echoc;
91: #endif
92:
93: /*
94: * Telnet receiver states for fsm
95: */
96: #define TS_DATA 0
97: #define TS_IAC 1
98: #define TS_WILL 2
99: #define TS_WONT 3
100: #define TS_DO 4
101: #define TS_DONT 5
102: #define TS_CR 6
103: #define TS_SB 7 /* sub-option collection */
104: #define TS_SE 8 /* looking for sub-option end */
105:
106: static int telrcv_state;
107: # define telopt_environ TELOPT_NEW_ENVIRON
108:
109: jmp_buf toplevel = { 0 };
110: jmp_buf peerdied;
111:
112: int flushline;
113: int linemode;
114:
115: #ifdef KLUDGELINEMODE
116: int kludgelinemode = 1;
117: #endif
118:
119: /*
120: * The following are some clocks used to decide how to interpret
121: * the relationship between various variables.
122: */
123:
124: Clocks clocks;
125:
126:
127: /*
128: * Initialize telnet environment.
129: */
130:
131: void
132: init_telnet()
133: {
134: env_init();
135:
136: SB_CLEAR();
1.4 art 137: memset((char *)options, 0, sizeof options);
1.1 deraadt 138:
1.21 ! guenther 139: connected = ISend = localflow = donebinarytoggle = 0;
1.1 deraadt 140: restartany = -1;
141:
142: SYNCHing = 0;
143:
144: /* Don't change NetTrace */
145:
146: escape = CONTROL(']');
147: rlogin = _POSIX_VDISABLE;
148: #ifdef KLUDGELINEMODE
149: echoc = CONTROL('E');
150: #endif
151:
152: flushline = 1;
153: telrcv_state = TS_DATA;
154: }
155:
156:
157: /*
158: * These routines are in charge of sending option negotiations
159: * to the other side.
160: *
161: * The basic idea is that we send the negotiation if either side
162: * is in disagreement as to what the current state should be.
163: */
164:
165: void
166: send_do(c, init)
1.13 mpech 167: int c, init;
1.1 deraadt 168: {
169: if (init) {
170: if (((do_dont_resp[c] == 0) && my_state_is_do(c)) ||
171: my_want_state_is_do(c))
172: return;
173: set_my_want_state_do(c);
174: do_dont_resp[c]++;
175: }
176: NET2ADD(IAC, DO);
177: NETADD(c);
1.12 hin 178: printoption("SENT",DO, c);
1.1 deraadt 179: }
180:
181: void
182: send_dont(c, init)
1.13 mpech 183: int c, init;
1.1 deraadt 184: {
185: if (init) {
186: if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) ||
187: my_want_state_is_dont(c))
188: return;
189: set_my_want_state_dont(c);
190: do_dont_resp[c]++;
191: }
192: NET2ADD(IAC, DONT);
193: NETADD(c);
194: printoption("SENT", DONT, c);
195: }
196:
197: void
198: send_will(c, init)
1.13 mpech 199: int c, init;
1.1 deraadt 200: {
201: if (init) {
202: if (((will_wont_resp[c] == 0) && my_state_is_will(c)) ||
203: my_want_state_is_will(c))
204: return;
205: set_my_want_state_will(c);
206: will_wont_resp[c]++;
207: }
208: NET2ADD(IAC, WILL);
209: NETADD(c);
210: printoption("SENT", WILL, c);
211: }
212:
213: void
214: send_wont(c, init)
1.13 mpech 215: int c, init;
1.1 deraadt 216: {
217: if (init) {
218: if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) ||
219: my_want_state_is_wont(c))
220: return;
221: set_my_want_state_wont(c);
222: will_wont_resp[c]++;
223: }
224: NET2ADD(IAC, WONT);
225: NETADD(c);
226: printoption("SENT", WONT, c);
227: }
228:
229:
230: void
231: willoption(option)
232: int option;
233: {
234: int new_state_ok = 0;
235:
236: if (do_dont_resp[option]) {
237: --do_dont_resp[option];
238: if (do_dont_resp[option] && my_state_is_do(option))
239: --do_dont_resp[option];
240: }
241:
242: if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) {
243:
244: switch (option) {
245:
246: case TELOPT_ECHO:
247: case TELOPT_BINARY:
248: case TELOPT_SGA:
249: settimer(modenegotiated);
250: /* FALL THROUGH */
251: case TELOPT_STATUS:
252: new_state_ok = 1;
253: break;
254:
255: case TELOPT_TM:
256: if (flushout)
257: flushout = 0;
258: /*
259: * Special case for TM. If we get back a WILL,
260: * pretend we got back a WONT.
261: */
262: set_my_want_state_dont(option);
263: set_my_state_dont(option);
264: return; /* Never reply to TM will's/wont's */
265:
266: case TELOPT_LINEMODE:
267: default:
268: break;
269: }
270:
271: if (new_state_ok) {
272: set_my_want_state_do(option);
273: send_do(option, 0);
274: setconnmode(0); /* possibly set new tty mode */
275: } else {
276: do_dont_resp[option]++;
277: send_dont(option, 0);
278: }
279: }
280: set_my_state_do(option);
1.4 art 281:
1.1 deraadt 282: }
283:
284: void
285: wontoption(option)
286: int option;
287: {
288: if (do_dont_resp[option]) {
289: --do_dont_resp[option];
290: if (do_dont_resp[option] && my_state_is_dont(option))
291: --do_dont_resp[option];
292: }
293:
294: if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) {
295:
296: switch (option) {
297:
298: #ifdef KLUDGELINEMODE
299: case TELOPT_SGA:
300: if (!kludgelinemode)
301: break;
302: /* FALL THROUGH */
303: #endif
304: case TELOPT_ECHO:
305: settimer(modenegotiated);
306: break;
307:
308: case TELOPT_TM:
309: if (flushout)
310: flushout = 0;
311: set_my_want_state_dont(option);
312: set_my_state_dont(option);
313: return; /* Never reply to TM will's/wont's */
314:
315: default:
316: break;
317: }
318: set_my_want_state_dont(option);
319: if (my_state_is_do(option))
320: send_dont(option, 0);
321: setconnmode(0); /* Set new tty mode */
322: } else if (option == TELOPT_TM) {
323: /*
324: * Special case for TM.
325: */
326: if (flushout)
327: flushout = 0;
328: set_my_want_state_dont(option);
329: }
330: set_my_state_dont(option);
331: }
332:
333: static void
334: dooption(option)
335: int option;
336: {
337: int new_state_ok = 0;
338:
339: if (will_wont_resp[option]) {
340: --will_wont_resp[option];
341: if (will_wont_resp[option] && my_state_is_will(option))
342: --will_wont_resp[option];
343: }
344:
345: if (will_wont_resp[option] == 0) {
346: if (my_want_state_is_wont(option)) {
347:
348: switch (option) {
349:
350: case TELOPT_TM:
351: /*
352: * Special case for TM. We send a WILL, but pretend
353: * we sent WONT.
354: */
355: send_will(option, 0);
356: set_my_want_state_wont(TELOPT_TM);
357: set_my_state_wont(TELOPT_TM);
358: return;
359:
360: case TELOPT_BINARY: /* binary mode */
361: case TELOPT_NAWS: /* window size */
362: case TELOPT_TSPEED: /* terminal speed */
363: case TELOPT_LFLOW: /* local flow control */
364: case TELOPT_TTYPE: /* terminal type option */
365: case TELOPT_SGA: /* no big deal */
366: new_state_ok = 1;
367: break;
368:
369: case TELOPT_NEW_ENVIRON: /* New environment variable option */
370: new_state_ok = 1;
371: break;
372:
373: case TELOPT_XDISPLOC: /* X Display location */
1.19 otto 374: if (env_getvalue((unsigned char *)"DISPLAY", 0))
1.1 deraadt 375: new_state_ok = 1;
376: break;
377:
378: case TELOPT_LINEMODE:
379: #ifdef KLUDGELINEMODE
380: kludgelinemode = 0;
381: send_do(TELOPT_SGA, 1);
382: #endif
383: set_my_want_state_will(TELOPT_LINEMODE);
384: send_will(option, 0);
385: set_my_state_will(TELOPT_LINEMODE);
386: slc_init();
387: return;
388:
389: case TELOPT_ECHO: /* We're never going to echo... */
390: default:
391: break;
392: }
393:
394: if (new_state_ok) {
395: set_my_want_state_will(option);
396: send_will(option, 0);
397: setconnmode(0); /* Set new tty mode */
398: } else {
399: will_wont_resp[option]++;
400: send_wont(option, 0);
401: }
402: } else {
403: /*
404: * Handle options that need more things done after the
405: * other side has acknowledged the option.
406: */
407: switch (option) {
408: case TELOPT_LINEMODE:
409: #ifdef KLUDGELINEMODE
410: kludgelinemode = 0;
411: send_do(TELOPT_SGA, 1);
412: #endif
413: set_my_state_will(option);
414: slc_init();
415: send_do(TELOPT_SGA, 0);
416: return;
417: }
418: }
419: }
420: set_my_state_will(option);
421: }
422:
423: static void
424: dontoption(option)
425: int option;
426: {
427:
428: if (will_wont_resp[option]) {
429: --will_wont_resp[option];
430: if (will_wont_resp[option] && my_state_is_wont(option))
431: --will_wont_resp[option];
432: }
433:
434: if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) {
435: switch (option) {
436: case TELOPT_LINEMODE:
437: linemode = 0; /* put us back to the default state */
438: break;
439: }
440: /* we always accept a DONT */
441: set_my_want_state_wont(option);
442: if (my_state_is_will(option))
443: send_wont(option, 0);
444: setconnmode(0); /* Set new tty mode */
445: }
446: set_my_state_wont(option);
447: }
448:
449: /*
1.11 provos 450: * This routine will turn a pipe separated list of names in the buffer
1.9 millert 451: * into an array of pointers to NUL terminated names. We toss out any
452: * bad, duplicate, or verbose names (names with spaces).
1.1 deraadt 453: */
454:
1.14 millert 455: int is_unique(char *, char **, char **);
1.5 art 456:
1.1 deraadt 457: static char *name_unknown = "UNKNOWN";
458: static char *unknown[] = { 0, 0 };
459:
460: char **
461: mklist(buf, name)
462: char *buf, *name;
463: {
1.13 mpech 464: int n;
465: char c, *cp, **argvp, *cp2, **argv, **avt;
1.1 deraadt 466:
467: if (name) {
1.2 niklas 468: if ((int)strlen(name) > 40) {
1.1 deraadt 469: name = 0;
470: unknown[0] = name_unknown;
471: } else {
472: unknown[0] = name;
473: upcase(name);
474: }
475: } else
476: unknown[0] = name_unknown;
477: /*
478: * Count up the number of names.
479: */
1.9 millert 480: for (n = 1, cp = buf; *cp; cp++) {
1.1 deraadt 481: if (*cp == '|')
482: n++;
483: }
484: /*
485: * Allocate an array to put the name pointers into
486: */
487: argv = (char **)malloc((n+3)*sizeof(char *));
488: if (argv == 0)
489: return(unknown);
490:
491: /*
492: * Fill up the array of pointers to names.
493: */
494: *argv = 0;
495: argvp = argv+1;
496: n = 0;
497: for (cp = cp2 = buf; (c = *cp); cp++) {
498: if (c == '|' || c == ':') {
499: *cp++ = '\0';
500: /*
501: * Skip entries that have spaces or are over 40
502: * characters long. If this is our environment
503: * name, then put it up front. Otherwise, as
504: * long as this is not a duplicate name (case
505: * insensitive) add it to the list.
506: */
507: if (n || (cp - cp2 > 41))
508: ;
509: else if (name && (strncasecmp(name, cp2, cp-cp2) == 0))
510: *argv = cp2;
511: else if (is_unique(cp2, argv+1, argvp))
512: *argvp++ = cp2;
513: if (c == ':')
514: break;
515: /*
516: * Skip multiple delimiters. Reset cp2 to
517: * the beginning of the next name. Reset n,
518: * the flag for names with spaces.
519: */
520: while ((c = *cp) == '|')
521: cp++;
522: cp2 = cp;
523: n = 0;
524: }
525: /*
526: * Skip entries with spaces or non-ascii values.
527: * Convert lower case letters to upper case.
528: */
1.4 art 529: #define ISASCII(c) (!((c)&0x80))
530: if ((c == ' ') || !ISASCII(c))
1.1 deraadt 531: n = 1;
532: else if (islower(c))
533: *cp = toupper(c);
534: }
1.2 niklas 535:
1.1 deraadt 536: /*
537: * Check for an old V6 2 character name. If the second
538: * name points to the beginning of the buffer, and is
539: * only 2 characters long, move it to the end of the array.
540: */
541: if ((argv[1] == buf) && (strlen(argv[1]) == 2)) {
542: --argvp;
543: for (avt = &argv[1]; avt < argvp; avt++)
544: *avt = *(avt+1);
545: *argvp++ = buf;
546: }
547:
548: /*
549: * Duplicate last name, for TTYPE option, and null
550: * terminate the array. If we didn't find a match on
551: * our terminal name, put that name at the beginning.
552: */
553: cp = *(argvp-1);
554: *argvp++ = cp;
555: *argvp = 0;
556:
557: if (*argv == 0) {
558: if (name)
559: *argv = name;
560: else {
561: --argvp;
562: for (avt = argv; avt < argvp; avt++)
563: *avt = *(avt+1);
564: }
565: }
566: if (*argv)
567: return(argv);
568: else
569: return(unknown);
570: }
571:
572: int
573: is_unique(name, as, ae)
1.13 mpech 574: char *name, **as, **ae;
1.1 deraadt 575: {
1.13 mpech 576: char **ap;
577: int n;
1.1 deraadt 578:
579: n = strlen(name) + 1;
580: for (ap = as; ap < ae; ap++)
581: if (strncasecmp(*ap, name, n) == 0)
582: return(0);
583: return (1);
584: }
585:
586: int resettermname = 1;
587:
588: char *
589: gettermname()
590: {
591: char *tname;
592: static char **tnamep = 0;
593: static char **next;
1.10 millert 594: int errret;
1.1 deraadt 595:
596: if (resettermname) {
597: resettermname = 0;
598: if (tnamep && tnamep != unknown)
599: free(tnamep);
1.19 otto 600: if ((tname = (char *)env_getvalue((unsigned char *)"TERM", 0)) &&
1.10 millert 601: (setupterm(tname, 1, &errret) == OK)) {
1.9 millert 602: tnamep = mklist(ttytype, tname);
1.1 deraadt 603: } else {
1.2 niklas 604: if (tname && ((int)strlen(tname) <= 40)) {
1.1 deraadt 605: unknown[0] = tname;
606: upcase(tname);
607: } else
608: unknown[0] = name_unknown;
609: tnamep = unknown;
610: }
611: next = tnamep;
612: }
613: if (*next == 0)
614: next = tnamep;
615: return(*next++);
616: }
617: /*
618: * suboption()
619: *
620: * Look at the sub-option buffer, and try to be helpful to the other
621: * side.
622: *
623: * Currently we recognize:
624: *
625: * Terminal type, send request.
626: * Terminal speed (send request).
627: * Local flow control (is request).
628: * Linemode
629: */
630:
631: static void
632: suboption()
633: {
634: unsigned char subchar;
635:
636: printsub('<', subbuffer, SB_LEN()+2);
637: switch (subchar = SB_GET()) {
638: case TELOPT_TTYPE:
639: if (my_want_state_is_wont(TELOPT_TTYPE))
640: return;
641: if (SB_EOF() || SB_GET() != TELQUAL_SEND) {
642: return;
643: } else {
644: char *name;
645: unsigned char temp[50];
646: int len;
647:
648: name = gettermname();
649: len = strlen(name) + 4 + 2;
650: if (len < NETROOM()) {
1.4 art 651: snprintf((char *)temp, sizeof(temp),
652: "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
653: TELQUAL_IS, name, IAC, SE);
1.1 deraadt 654: ring_supply_data(&netoring, temp, len);
655: printsub('>', &temp[2], len-2);
656: } else {
657: ExitString("No room in buffer for terminal type.\n", 1);
658: /*NOTREACHED*/
659: }
660: }
661: break;
662: case TELOPT_TSPEED:
663: if (my_want_state_is_wont(TELOPT_TSPEED))
664: return;
665: if (SB_EOF())
666: return;
667: if (SB_GET() == TELQUAL_SEND) {
668: long ospeed, ispeed;
669: unsigned char temp[50];
670: int len;
671:
672: TerminalSpeeds(&ispeed, &ospeed);
673:
1.4 art 674: snprintf((char *)temp, sizeof(temp),
1.5 art 675: "%c%c%c%c%ld,%ld%c%c", IAC, SB, TELOPT_TSPEED,
1.4 art 676: TELQUAL_IS, ospeed, ispeed, IAC, SE);
1.1 deraadt 677: len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */
678:
679: if (len < NETROOM()) {
680: ring_supply_data(&netoring, temp, len);
681: printsub('>', temp+2, len - 2);
682: }
683: /*@*/ else printf("lm_will: not enough room in buffer\n");
684: }
685: break;
686: case TELOPT_LFLOW:
687: if (my_want_state_is_wont(TELOPT_LFLOW))
688: return;
689: if (SB_EOF())
690: return;
691: switch(SB_GET()) {
692: case LFLOW_RESTART_ANY:
693: restartany = 1;
694: break;
695: case LFLOW_RESTART_XON:
696: restartany = 0;
697: break;
698: case LFLOW_ON:
699: localflow = 1;
700: break;
701: case LFLOW_OFF:
702: localflow = 0;
703: break;
704: default:
705: return;
706: }
707: setcommandmode();
708: setconnmode(0);
709: break;
710:
711: case TELOPT_LINEMODE:
712: if (my_want_state_is_wont(TELOPT_LINEMODE))
713: return;
714: if (SB_EOF())
715: return;
716: switch (SB_GET()) {
717: case WILL:
718: lm_will(subpointer, SB_LEN());
719: break;
720: case WONT:
721: lm_wont(subpointer, SB_LEN());
722: break;
723: case DO:
724: lm_do(subpointer, SB_LEN());
725: break;
726: case DONT:
727: lm_dont(subpointer, SB_LEN());
728: break;
729: case LM_SLC:
730: slc(subpointer, SB_LEN());
731: break;
732: case LM_MODE:
733: lm_mode(subpointer, SB_LEN(), 0);
734: break;
735: default:
736: break;
737: }
738: break;
739:
740: case TELOPT_NEW_ENVIRON:
741: if (SB_EOF())
742: return;
743: switch(SB_PEEK()) {
744: case TELQUAL_IS:
745: case TELQUAL_INFO:
746: if (my_want_state_is_dont(subchar))
747: return;
748: break;
749: case TELQUAL_SEND:
750: if (my_want_state_is_wont(subchar)) {
751: return;
752: }
753: break;
754: default:
755: return;
756: }
757: env_opt(subpointer, SB_LEN());
758: break;
759:
760: case TELOPT_XDISPLOC:
761: if (my_want_state_is_wont(TELOPT_XDISPLOC))
762: return;
763: if (SB_EOF())
764: return;
765: if (SB_GET() == TELQUAL_SEND) {
766: unsigned char temp[50], *dp;
767: int len;
768:
1.19 otto 769: if ((dp = env_getvalue((unsigned char *)"DISPLAY", 0)) == NULL) {
1.1 deraadt 770: /*
771: * Something happened, we no longer have a DISPLAY
772: * variable. So, turn off the option.
773: */
774: send_wont(TELOPT_XDISPLOC, 1);
775: break;
776: }
1.4 art 777: snprintf((char *)temp, sizeof(temp),
778: "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC,
1.1 deraadt 779: TELQUAL_IS, dp, IAC, SE);
780: len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */
781:
782: if (len < NETROOM()) {
783: ring_supply_data(&netoring, temp, len);
784: printsub('>', temp+2, len - 2);
785: }
786: /*@*/ else printf("lm_will: not enough room in buffer\n");
787: }
788: break;
789:
790: default:
791: break;
792: }
793: }
794:
795: static unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE };
796:
797: void
798: lm_will(cmd, len)
799: unsigned char *cmd;
800: int len;
801: {
802: if (len < 1) {
803: /*@*/ printf("lm_will: no command!!!\n"); /* Should not happen... */
804: return;
805: }
806: switch(cmd[0]) {
807: case LM_FORWARDMASK: /* We shouldn't ever get this... */
808: default:
809: str_lm[3] = DONT;
810: str_lm[4] = cmd[0];
811: if (NETROOM() > sizeof(str_lm)) {
812: ring_supply_data(&netoring, str_lm, sizeof(str_lm));
813: printsub('>', &str_lm[2], sizeof(str_lm)-2);
814: }
815: /*@*/ else printf("lm_will: not enough room in buffer\n");
816: break;
817: }
818: }
819:
820: void
821: lm_wont(cmd, len)
822: unsigned char *cmd;
823: int len;
824: {
825: if (len < 1) {
826: /*@*/ printf("lm_wont: no command!!!\n"); /* Should not happen... */
827: return;
828: }
829: switch(cmd[0]) {
830: case LM_FORWARDMASK: /* We shouldn't ever get this... */
831: default:
832: /* We are always DONT, so don't respond */
833: return;
834: }
835: }
836:
837: void
838: lm_do(cmd, len)
839: unsigned char *cmd;
840: int len;
841: {
842: if (len < 1) {
843: /*@*/ printf("lm_do: no command!!!\n"); /* Should not happen... */
844: return;
845: }
846: switch(cmd[0]) {
847: case LM_FORWARDMASK:
848: default:
849: str_lm[3] = WONT;
850: str_lm[4] = cmd[0];
851: if (NETROOM() > sizeof(str_lm)) {
852: ring_supply_data(&netoring, str_lm, sizeof(str_lm));
853: printsub('>', &str_lm[2], sizeof(str_lm)-2);
854: }
855: /*@*/ else printf("lm_do: not enough room in buffer\n");
856: break;
857: }
858: }
859:
860: void
861: lm_dont(cmd, len)
862: unsigned char *cmd;
863: int len;
864: {
865: if (len < 1) {
866: /*@*/ printf("lm_dont: no command!!!\n"); /* Should not happen... */
867: return;
868: }
869: switch(cmd[0]) {
870: case LM_FORWARDMASK:
871: default:
872: /* we are always WONT, so don't respond */
873: break;
874: }
875: }
876:
877: static unsigned char str_lm_mode[] = {
878: IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE
879: };
880:
881: void
882: lm_mode(cmd, len, init)
883: unsigned char *cmd;
884: int len, init;
885: {
886: if (len != 1)
887: return;
888: if ((linemode&MODE_MASK&~MODE_ACK) == *cmd)
889: return;
890: if (*cmd&MODE_ACK)
891: return;
892: linemode = *cmd&(MODE_MASK&~MODE_ACK);
893: str_lm_mode[4] = linemode;
894: if (!init)
895: str_lm_mode[4] |= MODE_ACK;
896: if (NETROOM() > sizeof(str_lm_mode)) {
897: ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode));
898: printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2);
899: }
900: /*@*/ else printf("lm_mode: not enough room in buffer\n");
901: setconnmode(0); /* set changed mode */
902: }
903:
904:
905:
906: /*
907: * slc()
908: * Handle special character suboption of LINEMODE.
909: */
910:
911: struct spc {
912: cc_t val;
913: cc_t *valp;
914: char flags; /* Current flags & level */
915: char mylevel; /* Maximum level & flags */
916: } spc_data[NSLC+1];
917:
918: #define SLC_IMPORT 0
919: #define SLC_EXPORT 1
920: #define SLC_RVALUE 2
921: static int slc_mode = SLC_EXPORT;
922:
923: void
924: slc_init()
925: {
1.13 mpech 926: struct spc *spcp;
1.1 deraadt 927:
928: localchars = 1;
929: for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) {
930: spcp->val = 0;
931: spcp->valp = 0;
932: spcp->flags = spcp->mylevel = SLC_NOSUPPORT;
933: }
934:
935: #define initfunc(func, flags) { \
936: spcp = &spc_data[func]; \
1.4 art 937: if ((spcp->valp = tcval(func))) { \
1.1 deraadt 938: spcp->val = *spcp->valp; \
939: spcp->mylevel = SLC_VARIABLE|flags; \
940: } else { \
941: spcp->val = 0; \
942: spcp->mylevel = SLC_DEFAULT; \
943: } \
944: }
945:
946: initfunc(SLC_SYNCH, 0);
947: /* No BRK */
948: initfunc(SLC_AO, 0);
949: initfunc(SLC_AYT, 0);
950: /* No EOR */
951: initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT);
952: initfunc(SLC_EOF, 0);
953: initfunc(SLC_SUSP, SLC_FLUSHIN);
954: initfunc(SLC_EC, 0);
955: initfunc(SLC_EL, 0);
956: initfunc(SLC_EW, 0);
957: initfunc(SLC_RP, 0);
958: initfunc(SLC_LNEXT, 0);
959: initfunc(SLC_XON, 0);
960: initfunc(SLC_XOFF, 0);
961: initfunc(SLC_FORW1, 0);
962: initfunc(SLC_FORW2, 0);
963: /* No FORW2 */
964:
965: initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT);
966: #undef initfunc
967:
968: if (slc_mode == SLC_EXPORT)
969: slc_export();
970: else
971: slc_import(1);
972:
973: }
974:
975: void
976: slcstate()
977: {
978: printf("Special characters are %s values\n",
979: slc_mode == SLC_IMPORT ? "remote default" :
980: slc_mode == SLC_EXPORT ? "local" :
981: "remote");
982: }
983:
984: void
985: slc_mode_export()
986: {
987: slc_mode = SLC_EXPORT;
988: if (my_state_is_will(TELOPT_LINEMODE))
989: slc_export();
990: }
991:
992: void
993: slc_mode_import(def)
994: int def;
995: {
996: slc_mode = def ? SLC_IMPORT : SLC_RVALUE;
997: if (my_state_is_will(TELOPT_LINEMODE))
998: slc_import(def);
999: }
1000:
1001: unsigned char slc_import_val[] = {
1002: IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE
1003: };
1004: unsigned char slc_import_def[] = {
1005: IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE
1006: };
1007:
1008: void
1009: slc_import(def)
1010: int def;
1011: {
1012: if (NETROOM() > sizeof(slc_import_val)) {
1013: if (def) {
1014: ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def));
1015: printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2);
1016: } else {
1017: ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val));
1018: printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2);
1019: }
1020: }
1021: /*@*/ else printf("slc_import: not enough room\n");
1022: }
1023:
1024: void
1025: slc_export()
1026: {
1.13 mpech 1027: struct spc *spcp;
1.1 deraadt 1028:
1029: TerminalDefaultChars();
1030:
1031: slc_start_reply();
1032: for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1033: if (spcp->mylevel != SLC_NOSUPPORT) {
1034: if (spcp->val == (cc_t)(_POSIX_VDISABLE))
1035: spcp->flags = SLC_NOSUPPORT;
1036: else
1037: spcp->flags = spcp->mylevel;
1038: if (spcp->valp)
1039: spcp->val = *spcp->valp;
1040: slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
1041: }
1042: }
1043: slc_end_reply();
1044: (void)slc_update();
1045: setconnmode(1); /* Make sure the character values are set */
1046: }
1047:
1048: void
1049: slc(cp, len)
1.13 mpech 1050: unsigned char *cp;
1.1 deraadt 1051: int len;
1052: {
1.13 mpech 1053: struct spc *spcp;
1054: int func,level;
1.1 deraadt 1055:
1056: slc_start_reply();
1057:
1058: for (; len >= 3; len -=3, cp +=3) {
1059:
1060: func = cp[SLC_FUNC];
1061:
1062: if (func == 0) {
1063: /*
1064: * Client side: always ignore 0 function.
1065: */
1066: continue;
1067: }
1068: if (func > NSLC) {
1069: if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT)
1070: slc_add_reply(func, SLC_NOSUPPORT, 0);
1071: continue;
1072: }
1073:
1074: spcp = &spc_data[func];
1075:
1076: level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK);
1077:
1078: if ((cp[SLC_VALUE] == (unsigned char)spcp->val) &&
1079: ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) {
1080: continue;
1081: }
1082:
1083: if (level == (SLC_DEFAULT|SLC_ACK)) {
1084: /*
1085: * This is an error condition, the SLC_ACK
1086: * bit should never be set for the SLC_DEFAULT
1087: * level. Our best guess to recover is to
1088: * ignore the SLC_ACK bit.
1089: */
1090: cp[SLC_FLAGS] &= ~SLC_ACK;
1091: }
1092:
1093: if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) {
1094: spcp->val = (cc_t)cp[SLC_VALUE];
1095: spcp->flags = cp[SLC_FLAGS]; /* include SLC_ACK */
1096: continue;
1097: }
1098:
1099: level &= ~SLC_ACK;
1100:
1101: if (level <= (spcp->mylevel&SLC_LEVELBITS)) {
1102: spcp->flags = cp[SLC_FLAGS]|SLC_ACK;
1103: spcp->val = (cc_t)cp[SLC_VALUE];
1104: }
1105: if (level == SLC_DEFAULT) {
1106: if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT)
1107: spcp->flags = spcp->mylevel;
1108: else
1109: spcp->flags = SLC_NOSUPPORT;
1110: }
1111: slc_add_reply(func, spcp->flags, spcp->val);
1112: }
1113: slc_end_reply();
1114: if (slc_update())
1115: setconnmode(1); /* set the new character values */
1116: }
1117:
1118: void
1119: slc_check()
1120: {
1.13 mpech 1121: struct spc *spcp;
1.1 deraadt 1122:
1123: slc_start_reply();
1124: for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1125: if (spcp->valp && spcp->val != *spcp->valp) {
1126: spcp->val = *spcp->valp;
1127: if (spcp->val == (cc_t)(_POSIX_VDISABLE))
1128: spcp->flags = SLC_NOSUPPORT;
1129: else
1130: spcp->flags = spcp->mylevel;
1131: slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
1132: }
1133: }
1134: slc_end_reply();
1135: setconnmode(1);
1136: }
1137:
1138:
1.19 otto 1139: static unsigned char slc_reply[2 * SUBBUFSIZE];
1140: static unsigned char *slc_replyp;
1141:
1142: unsigned char
1143: slc_add(unsigned char ch)
1144: {
1145: if (slc_replyp == slc_reply + sizeof(slc_reply))
1146: return ch;
1147: return *slc_replyp++ = ch;
1148: }
1.1 deraadt 1149:
1150: void
1151: slc_start_reply()
1152: {
1153: slc_replyp = slc_reply;
1.19 otto 1154: slc_add(IAC);
1155: slc_add(SB);
1156: slc_add(TELOPT_LINEMODE);
1157: slc_add(LM_SLC);
1.1 deraadt 1158: }
1159:
1160: void
1161: slc_add_reply(func, flags, value)
1162: unsigned char func;
1163: unsigned char flags;
1164: cc_t value;
1165: {
1.19 otto 1166: if (slc_replyp + 6 >= slc_reply + sizeof(slc_reply)) {
1167: printf("slc_add_reply: not enough room\n");
1168: return;
1169: }
1170: if (slc_add(func) == IAC)
1171: slc_add(IAC);
1172: if (slc_add(flags) == IAC)
1173: slc_add(IAC);
1174: if (slc_add((unsigned char)value) == IAC)
1175: slc_add(IAC);
1.1 deraadt 1176: }
1177:
1178: void
1179: slc_end_reply()
1180: {
1.13 mpech 1181: int len;
1.1 deraadt 1182:
1.19 otto 1183: if (slc_replyp + 2 >= slc_reply + sizeof(slc_reply)) {
1184: printf("slc_end_reply: not enough room\n");
1185: return;
1186: }
1187:
1188: slc_add(IAC);
1189: slc_add(SE);
1.1 deraadt 1190: len = slc_replyp - slc_reply;
1191: if (len <= 6)
1192: return;
1193: if (NETROOM() > len) {
1194: ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply);
1195: printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2);
1196: }
1197: /*@*/else printf("slc_end_reply: not enough room\n");
1198: }
1199:
1200: int
1201: slc_update()
1202: {
1.13 mpech 1203: struct spc *spcp;
1.1 deraadt 1204: int need_update = 0;
1205:
1206: for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1207: if (!(spcp->flags&SLC_ACK))
1208: continue;
1209: spcp->flags &= ~SLC_ACK;
1210: if (spcp->valp && (*spcp->valp != spcp->val)) {
1211: *spcp->valp = spcp->val;
1212: need_update = 1;
1213: }
1214: }
1215: return(need_update);
1216: }
1217:
1218: void
1219: env_opt(buf, len)
1.13 mpech 1220: unsigned char *buf;
1221: int len;
1.1 deraadt 1222: {
1.13 mpech 1223: unsigned char *ep = 0, *epc = 0;
1224: int i;
1.1 deraadt 1225:
1226: switch(buf[0]&0xff) {
1227: case TELQUAL_SEND:
1228: env_opt_start();
1229: if (len == 1) {
1230: env_opt_add(NULL);
1231: } else for (i = 1; i < len; i++) {
1232: switch (buf[i]&0xff) {
1233: case NEW_ENV_VAR:
1234: case ENV_USERVAR:
1235: if (ep) {
1236: *epc = 0;
1237: env_opt_add(ep);
1238: }
1239: ep = epc = &buf[i+1];
1240: break;
1241: case ENV_ESC:
1242: i++;
1243: /*FALL THROUGH*/
1244: default:
1245: if (epc)
1246: *epc++ = buf[i];
1247: break;
1248: }
1249: }
1250: if (ep) {
1251: *epc = 0;
1252: env_opt_add(ep);
1253: }
1254: env_opt_end(1);
1255: break;
1256:
1257: case TELQUAL_IS:
1258: case TELQUAL_INFO:
1259: /* Ignore for now. We shouldn't get it anyway. */
1260: break;
1261:
1262: default:
1263: break;
1264: }
1265: }
1266:
1.19 otto 1267: #define OPT_REPLY_SIZE (2 * SUBBUFSIZE)
1268: static unsigned char *opt_reply;
1269: static unsigned char *opt_replyp;
1270: static unsigned char *opt_replyend;
1.1 deraadt 1271:
1272: void
1.19 otto 1273: opt_add(unsigned char ch)
1274: {
1275: if (opt_replyp == opt_replyend)
1276: return;
1277: *opt_replyp++ = ch;
1278: }
1279: void
1.1 deraadt 1280: env_opt_start()
1281: {
1.8 itojun 1282: unsigned char *p;
1283:
1.20 chl 1284: p = (unsigned char *)realloc(opt_reply, OPT_REPLY_SIZE);
1285: if (p == NULL)
1286: free(opt_reply);
1.8 itojun 1287: opt_reply = p;
1.1 deraadt 1288: if (opt_reply == NULL) {
1.20 chl 1289: /*@*/ printf("env_opt_start: realloc() failed!!!\n");
1.1 deraadt 1290: opt_reply = opt_replyp = opt_replyend = NULL;
1291: return;
1292: }
1293: opt_replyp = opt_reply;
1294: opt_replyend = opt_reply + OPT_REPLY_SIZE;
1.19 otto 1295: opt_add(IAC);
1296: opt_add(SB);
1297: opt_add(telopt_environ);
1298: opt_add(TELQUAL_IS);
1.1 deraadt 1299: }
1300:
1301: void
1302: env_opt_start_info()
1303: {
1304: env_opt_start();
1305: if (opt_replyp)
1306: opt_replyp[-1] = TELQUAL_INFO;
1307: }
1308:
1309: void
1310: env_opt_add(ep)
1.13 mpech 1311: unsigned char *ep;
1.1 deraadt 1312: {
1.13 mpech 1313: unsigned char *vp, c;
1.1 deraadt 1314:
1315: if (opt_reply == NULL) /*XXX*/
1316: return; /*XXX*/
1317:
1318: if (ep == NULL || *ep == '\0') {
1319: /* Send user defined variables first. */
1320: env_default(1, 0);
1.4 art 1321: while ((ep = env_default(0, 0)))
1.1 deraadt 1322: env_opt_add(ep);
1323:
1324: /* Now add the list of well know variables. */
1325: env_default(1, 1);
1.4 art 1326: while ((ep = env_default(0, 1)))
1.1 deraadt 1327: env_opt_add(ep);
1328: return;
1329: }
1.19 otto 1330: vp = env_getvalue(ep, 1);
1331: if (opt_replyp + 2 * (vp ? strlen((char *)vp) : 0) +
1332: 2 * strlen((char *)ep) + 6 > opt_replyend)
1.1 deraadt 1333: {
1.19 otto 1334: size_t len;
1.8 itojun 1335: unsigned char *p;
1.19 otto 1336:
1.1 deraadt 1337: len = opt_replyend - opt_reply;
1.19 otto 1338: len += OPT_REPLY_SIZE + 2 * strlen(ep);
1339: if (vp)
1340: len += 2 * strlen(vp);
1.8 itojun 1341: p = (unsigned char *)realloc(opt_reply, len);
1.19 otto 1342: if (p == NULL) {
1.8 itojun 1343: free(opt_reply);
1.1 deraadt 1344: /*@*/ printf("env_opt_add: realloc() failed!!!\n");
1345: opt_reply = opt_replyp = opt_replyend = NULL;
1346: return;
1347: }
1.19 otto 1348: opt_replyp = p + (opt_replyp - opt_reply);
1349: opt_replyend = p + len;
1350: opt_reply = p;
1.1 deraadt 1351: }
1.4 art 1352: if (opt_welldefined((char *)ep))
1.19 otto 1353: opt_add(NEW_ENV_VAR);
1.1 deraadt 1354: else
1.19 otto 1355: opt_add(ENV_USERVAR);
1356:
1.1 deraadt 1357: for (;;) {
1.4 art 1358: while ((c = *ep++)) {
1.1 deraadt 1359: switch(c&0xff) {
1360: case IAC:
1.19 otto 1361: opt_add(IAC);
1.1 deraadt 1362: break;
1363: case NEW_ENV_VAR:
1364: case NEW_ENV_VALUE:
1365: case ENV_ESC:
1366: case ENV_USERVAR:
1.19 otto 1367: opt_add(ENV_ESC);
1.1 deraadt 1368: break;
1369: }
1.19 otto 1370: opt_add(c);
1.1 deraadt 1371: }
1.4 art 1372: if ((ep = vp)) {
1.19 otto 1373: opt_add(NEW_ENV_VALUE);
1.1 deraadt 1374: vp = NULL;
1375: } else
1376: break;
1377: }
1378: }
1379:
1380: int
1381: opt_welldefined(ep)
1382: char *ep;
1383: {
1384: if ((strcmp(ep, "USER") == 0) ||
1385: (strcmp(ep, "DISPLAY") == 0) ||
1386: (strcmp(ep, "PRINTER") == 0) ||
1387: (strcmp(ep, "SYSTEMTYPE") == 0) ||
1388: (strcmp(ep, "JOB") == 0) ||
1389: (strcmp(ep, "ACCT") == 0))
1390: return(1);
1391: return(0);
1392: }
1393: void
1394: env_opt_end(emptyok)
1.13 mpech 1395: int emptyok;
1.1 deraadt 1396: {
1.13 mpech 1397: int len;
1.1 deraadt 1398:
1399: len = opt_replyp - opt_reply + 2;
1400: if (emptyok || len > 6) {
1.19 otto 1401: opt_add(IAC);
1402: opt_add(SE);
1.1 deraadt 1403: if (NETROOM() > len) {
1404: ring_supply_data(&netoring, opt_reply, len);
1405: printsub('>', &opt_reply[2], len - 2);
1406: }
1407: /*@*/ else printf("slc_end_reply: not enough room\n");
1408: }
1409: if (opt_reply) {
1410: free(opt_reply);
1411: opt_reply = opt_replyp = opt_replyend = NULL;
1412: }
1413: }
1414:
1415:
1416:
1417: int
1418: telrcv()
1419: {
1.13 mpech 1420: int c;
1421: int scc;
1422: unsigned char *sbp;
1.1 deraadt 1423: int count;
1424: int returnValue = 0;
1425:
1426: scc = 0;
1427: count = 0;
1428: while (TTYROOM() > 2) {
1429: if (scc == 0) {
1430: if (count) {
1431: ring_consumed(&netiring, count);
1432: returnValue = 1;
1433: count = 0;
1434: }
1435: sbp = netiring.consume;
1436: scc = ring_full_consecutive(&netiring);
1437: if (scc == 0) {
1438: /* No more data coming in */
1439: break;
1440: }
1441: }
1442:
1443: c = *sbp++ & 0xff, scc--; count++;
1444:
1445: switch (telrcv_state) {
1446:
1447: case TS_CR:
1448: telrcv_state = TS_DATA;
1449: if (c == '\0') {
1450: break; /* Ignore \0 after CR */
1451: }
1452: else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) {
1453: TTYADD(c);
1454: break;
1455: }
1456: /* Else, fall through */
1457:
1458: case TS_DATA:
1459: if (c == IAC) {
1460: telrcv_state = TS_IAC;
1461: break;
1462: }
1463: /*
1464: * The 'crmod' hack (see following) is needed
1.4 art 1465: * since we can't set CRMOD on output only.
1.1 deraadt 1466: * Machines like MULTICS like to send \r without
1467: * \n; since we must turn off CRMOD to get proper
1468: * input, the mapping is done here (sigh).
1469: */
1470: if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) {
1471: if (scc > 0) {
1472: c = *sbp&0xff;
1473: if (c == 0) {
1474: sbp++, scc--; count++;
1475: /* a "true" CR */
1476: TTYADD('\r');
1477: } else if (my_want_state_is_dont(TELOPT_ECHO) &&
1478: (c == '\n')) {
1479: sbp++, scc--; count++;
1480: TTYADD('\n');
1481: } else {
1482: TTYADD('\r');
1483: if (crmod) {
1484: TTYADD('\n');
1485: }
1486: }
1487: } else {
1488: telrcv_state = TS_CR;
1489: TTYADD('\r');
1490: if (crmod) {
1491: TTYADD('\n');
1492: }
1493: }
1494: } else {
1495: TTYADD(c);
1496: }
1497: continue;
1498:
1499: case TS_IAC:
1500: process_iac:
1501: switch (c) {
1.2 niklas 1502:
1.1 deraadt 1503: case WILL:
1504: telrcv_state = TS_WILL;
1505: continue;
1506:
1507: case WONT:
1508: telrcv_state = TS_WONT;
1509: continue;
1510:
1511: case DO:
1512: telrcv_state = TS_DO;
1513: continue;
1514:
1515: case DONT:
1516: telrcv_state = TS_DONT;
1517: continue;
1518:
1519: case DM:
1520: /*
1521: * We may have missed an urgent notification,
1522: * so make sure we flush whatever is in the
1523: * buffer currently.
1524: */
1525: printoption("RCVD", IAC, DM);
1526: SYNCHing = 1;
1527: (void) ttyflush(1);
1528: SYNCHing = stilloob();
1529: break;
1530:
1531: case SB:
1532: SB_CLEAR();
1533: telrcv_state = TS_SB;
1534: continue;
1535:
1536: case IAC:
1537: TTYADD(IAC);
1538: break;
1539:
1540: case NOP:
1541: case GA:
1542: default:
1543: printoption("RCVD", IAC, c);
1544: break;
1545: }
1546: telrcv_state = TS_DATA;
1547: continue;
1548:
1549: case TS_WILL:
1550: printoption("RCVD", WILL, c);
1551: willoption(c);
1552: telrcv_state = TS_DATA;
1553: continue;
1554:
1555: case TS_WONT:
1556: printoption("RCVD", WONT, c);
1557: wontoption(c);
1558: telrcv_state = TS_DATA;
1559: continue;
1560:
1561: case TS_DO:
1562: printoption("RCVD", DO, c);
1563: dooption(c);
1564: if (c == TELOPT_NAWS) {
1565: sendnaws();
1566: } else if (c == TELOPT_LFLOW) {
1567: localflow = 1;
1568: setcommandmode();
1569: setconnmode(0);
1570: }
1571: telrcv_state = TS_DATA;
1572: continue;
1573:
1574: case TS_DONT:
1575: printoption("RCVD", DONT, c);
1576: dontoption(c);
1577: flushline = 1;
1578: setconnmode(0); /* set new tty mode (maybe) */
1579: telrcv_state = TS_DATA;
1580: continue;
1581:
1582: case TS_SB:
1583: if (c == IAC) {
1584: telrcv_state = TS_SE;
1585: } else {
1586: SB_ACCUM(c);
1587: }
1588: continue;
1589:
1590: case TS_SE:
1591: if (c != SE) {
1592: if (c != IAC) {
1593: /*
1594: * This is an error. We only expect to get
1595: * "IAC IAC" or "IAC SE". Several things may
1.18 jmc 1596: * have happened. An IAC was not doubled, the
1.1 deraadt 1597: * IAC SE was left off, or another option got
1598: * inserted into the suboption are all possibilities.
1599: * If we assume that the IAC was not doubled,
1600: * and really the IAC SE was left off, we could
1601: * get into an infinate loop here. So, instead,
1602: * we terminate the suboption, and process the
1603: * partial suboption if we can.
1604: */
1605: SB_ACCUM(IAC);
1606: SB_ACCUM(c);
1607: subpointer -= 2;
1608: SB_TERM();
1609:
1610: printoption("In SUBOPTION processing, RCVD", IAC, c);
1611: suboption(); /* handle sub-option */
1612: telrcv_state = TS_IAC;
1613: goto process_iac;
1614: }
1615: SB_ACCUM(c);
1616: telrcv_state = TS_SB;
1617: } else {
1618: SB_ACCUM(IAC);
1619: SB_ACCUM(SE);
1620: subpointer -= 2;
1621: SB_TERM();
1622: suboption(); /* handle sub-option */
1623: telrcv_state = TS_DATA;
1624: }
1625: }
1626: }
1627: if (count)
1628: ring_consumed(&netiring, count);
1629: return returnValue||count;
1630: }
1631:
1632: static int bol = 1, local = 0;
1633:
1634: int
1635: rlogin_susp()
1636: {
1637: if (local) {
1638: local = 0;
1639: bol = 1;
1640: command(0, "z\n", 2);
1641: return(1);
1642: }
1643: return(0);
1644: }
1645:
1646: static int
1647: telsnd()
1648: {
1649: int tcc;
1650: int count;
1651: int returnValue = 0;
1652: unsigned char *tbp;
1653:
1654: tcc = 0;
1655: count = 0;
1656: while (NETROOM() > 2) {
1.13 mpech 1657: int sc;
1658: int c;
1.1 deraadt 1659:
1660: if (tcc == 0) {
1661: if (count) {
1662: ring_consumed(&ttyiring, count);
1663: returnValue = 1;
1664: count = 0;
1665: }
1666: tbp = ttyiring.consume;
1667: tcc = ring_full_consecutive(&ttyiring);
1668: if (tcc == 0) {
1669: break;
1670: }
1671: }
1672: c = *tbp++ & 0xff, sc = strip(c), tcc--; count++;
1673: if (rlogin != _POSIX_VDISABLE) {
1674: if (bol) {
1675: bol = 0;
1676: if (sc == rlogin) {
1677: local = 1;
1678: continue;
1679: }
1680: } else if (local) {
1681: local = 0;
1682: if (sc == '.' || c == termEofChar) {
1683: bol = 1;
1684: command(0, "close\n", 6);
1685: continue;
1686: }
1687: if (sc == termSuspChar) {
1688: bol = 1;
1689: command(0, "z\n", 2);
1690: continue;
1691: }
1692: if (sc == escape) {
1693: command(0, (char *)tbp, tcc);
1694: bol = 1;
1695: count += tcc;
1696: tcc = 0;
1697: flushline = 1;
1698: break;
1699: }
1700: if (sc != rlogin) {
1701: ++tcc;
1702: --tbp;
1703: --count;
1704: c = sc = rlogin;
1705: }
1706: }
1707: if ((sc == '\n') || (sc == '\r'))
1708: bol = 1;
1.7 aaron 1709: } else if (escape != _POSIX_VDISABLE && sc == escape) {
1.1 deraadt 1710: /*
1711: * Double escape is a pass through of a single escape character.
1712: */
1713: if (tcc && strip(*tbp) == escape) {
1714: tbp++;
1715: tcc--;
1716: count++;
1717: bol = 0;
1718: } else {
1719: command(0, (char *)tbp, tcc);
1720: bol = 1;
1721: count += tcc;
1722: tcc = 0;
1723: flushline = 1;
1724: break;
1725: }
1726: } else
1727: bol = 0;
1728: #ifdef KLUDGELINEMODE
1729: if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) {
1730: if (tcc > 0 && strip(*tbp) == echoc) {
1731: tcc--; tbp++; count++;
1732: } else {
1733: dontlecho = !dontlecho;
1734: settimer(echotoggle);
1735: setconnmode(0);
1736: flushline = 1;
1737: break;
1738: }
1739: }
1740: #endif
1.3 deraadt 1741: if (sc != _POSIX_VDISABLE && MODE_LOCAL_CHARS(globalmode)) {
1.1 deraadt 1742: if (TerminalSpecialChars(sc) == 0) {
1743: bol = 1;
1744: break;
1745: }
1746: }
1747: if (my_want_state_is_wont(TELOPT_BINARY)) {
1748: switch (c) {
1749: case '\n':
1750: /*
1751: * If we are in CRMOD mode (\r ==> \n)
1752: * on our local machine, then probably
1753: * a newline (unix) is CRLF (TELNET).
1754: */
1755: if (MODE_LOCAL_CHARS(globalmode)) {
1756: NETADD('\r');
1757: }
1758: NETADD('\n');
1759: bol = flushline = 1;
1760: break;
1761: case '\r':
1762: if (!crlf) {
1763: NET2ADD('\r', '\0');
1764: } else {
1765: NET2ADD('\r', '\n');
1766: }
1767: bol = flushline = 1;
1768: break;
1769: case IAC:
1770: NET2ADD(IAC, IAC);
1771: break;
1772: default:
1773: NETADD(c);
1774: break;
1775: }
1776: } else if (c == IAC) {
1777: NET2ADD(IAC, IAC);
1778: } else {
1779: NETADD(c);
1780: }
1781: }
1782: if (count)
1783: ring_consumed(&ttyiring, count);
1784: return returnValue||count; /* Non-zero if we did anything */
1785: }
1786:
1787: /*
1788: * Scheduler()
1789: *
1790: * Try to do something.
1791: *
1792: * If we do something useful, return 1; else return 0.
1793: *
1794: */
1795:
1796:
1797: int
1798: Scheduler(block)
1799: int block; /* should we block in the select ? */
1800: {
1801: /* One wants to be a bit careful about setting returnValue
1802: * to one, since a one implies we did some useful work,
1803: * and therefore probably won't be called to block next
1804: * time (TN3270 mode only).
1805: */
1806: int returnValue;
1807: int netin, netout, netex, ttyin, ttyout;
1808:
1809: /* Decide which rings should be processed */
1810:
1811: netout = ring_full_count(&netoring) &&
1812: (flushline ||
1813: (my_want_state_is_wont(TELOPT_LINEMODE)
1814: #ifdef KLUDGELINEMODE
1815: && (!kludgelinemode || my_want_state_is_do(TELOPT_SGA))
1816: #endif
1817: ) ||
1818: my_want_state_is_will(TELOPT_BINARY));
1819: ttyout = ring_full_count(&ttyoring);
1820:
1821: ttyin = ring_empty_count(&ttyiring) && (clienteof == 0);
1822:
1823: netin = !ISend && ring_empty_count(&netiring);
1824:
1825: netex = !SYNCHing;
1826:
1827: /* If we have seen a signal recently, reset things */
1.15 hin 1828:
1829: if (scheduler_lockout_tty) {
1830: ttyin = ttyout = 0;
1831: }
1832:
1.1 deraadt 1833: /* Call to system code to process rings */
1834:
1835: returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block);
1836:
1837: /* Now, look at the input rings, looking for work to do. */
1838:
1839: if (ring_full_count(&ttyiring)) {
1.21 ! guenther 1840: returnValue |= telsnd();
1.1 deraadt 1841: }
1842:
1843: if (ring_full_count(&netiring)) {
1844: returnValue |= telrcv();
1845: }
1846: return returnValue;
1847: }
1848:
1849: /*
1850: * Select from tty and network...
1851: */
1852: void
1853: telnet(user)
1854: char *user;
1855: {
1856: sys_telnet_init();
1857:
1858: if (telnetport) {
1859: send_do(TELOPT_SGA, 1);
1860: send_will(TELOPT_TTYPE, 1);
1861: send_will(TELOPT_NAWS, 1);
1862: send_will(TELOPT_TSPEED, 1);
1863: send_will(TELOPT_LFLOW, 1);
1864: send_will(TELOPT_LINEMODE, 1);
1865: send_will(TELOPT_NEW_ENVIRON, 1);
1866: send_do(TELOPT_STATUS, 1);
1.19 otto 1867: if (env_getvalue((unsigned char *)"DISPLAY", 0))
1.1 deraadt 1868: send_will(TELOPT_XDISPLOC, 1);
1.4 art 1869: if (binary)
1870: tel_enter_binary(binary);
1.1 deraadt 1871: }
1872:
1873: for (;;) {
1874: int schedValue;
1875:
1876: while ((schedValue = Scheduler(0)) != 0) {
1877: if (schedValue == -1) {
1878: setcommandmode();
1879: return;
1880: }
1881: }
1882:
1883: if (Scheduler(1) == -1) {
1884: setcommandmode();
1885: return;
1886: }
1887: }
1888: }
1889:
1890: #if 0 /* XXX - this not being in is a bug */
1891: /*
1892: * nextitem()
1893: *
1894: * Return the address of the next "item" in the TELNET data
1895: * stream. This will be the address of the next character if
1896: * the current address is a user data character, or it will
1897: * be the address of the character following the TELNET command
1898: * if the current address is a TELNET IAC ("I Am a Command")
1899: * character.
1900: */
1901:
1902: static char *
1903: nextitem(current)
1904: char *current;
1905: {
1906: if ((*current&0xff) != IAC) {
1907: return current+1;
1908: }
1909: switch (*(current+1)&0xff) {
1910: case DO:
1911: case DONT:
1912: case WILL:
1913: case WONT:
1914: return current+3;
1915: case SB: /* loop forever looking for the SE */
1916: {
1.13 mpech 1917: char *look = current+2;
1.1 deraadt 1918:
1919: for (;;) {
1920: if ((*look++&0xff) == IAC) {
1921: if ((*look++&0xff) == SE) {
1922: return look;
1923: }
1924: }
1925: }
1926: }
1927: default:
1928: return current+2;
1929: }
1930: }
1931: #endif /* 0 */
1932:
1933: /*
1934: * netclear()
1935: *
1936: * We are about to do a TELNET SYNCH operation. Clear
1937: * the path to the network.
1938: *
1939: * Things are a bit tricky since we may have sent the first
1940: * byte or so of a previous TELNET command into the network.
1941: * So, we have to scan the network buffer from the beginning
1942: * until we are up to where we want to be.
1943: *
1944: * A side effect of what we do, just to keep things
1945: * simple, is to clear the urgent data pointer. The principal
1946: * caller should be setting the urgent data pointer AFTER calling
1947: * us in any case.
1948: */
1949:
1950: static void
1951: netclear()
1952: {
1953: #if 0 /* XXX */
1.13 mpech 1954: char *thisitem, *next;
1.1 deraadt 1955: char *good;
1956: #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \
1957: ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
1958:
1959: thisitem = netobuf;
1960:
1961: while ((next = nextitem(thisitem)) <= netobuf.send) {
1962: thisitem = next;
1963: }
1964:
1965: /* Now, thisitem is first before/at boundary. */
1966:
1967: good = netobuf; /* where the good bytes go */
1968:
1969: while (netoring.add > thisitem) {
1970: if (wewant(thisitem)) {
1971: int length;
1972:
1973: next = thisitem;
1974: do {
1975: next = nextitem(next);
1976: } while (wewant(next) && (nfrontp > next));
1977: length = next-thisitem;
1.2 niklas 1978: memmove(good, thisitem, length);
1.1 deraadt 1979: good += length;
1980: thisitem = next;
1981: } else {
1982: thisitem = nextitem(thisitem);
1983: }
1984: }
1985:
1986: #endif /* 0 */
1987: }
1988:
1989: /*
1990: * These routines add various telnet commands to the data stream.
1991: */
1992:
1993: static void
1994: doflush()
1995: {
1996: NET2ADD(IAC, DO);
1997: NETADD(TELOPT_TM);
1998: flushline = 1;
1999: flushout = 1;
2000: (void) ttyflush(1); /* Flush/drop output */
2001: /* do printoption AFTER flush, otherwise the output gets tossed... */
2002: printoption("SENT", DO, TELOPT_TM);
2003: }
2004:
2005: void
2006: xmitAO()
2007: {
2008: NET2ADD(IAC, AO);
2009: printoption("SENT", IAC, AO);
2010: if (autoflush) {
2011: doflush();
2012: }
2013: }
2014:
2015:
2016: void
2017: xmitEL()
2018: {
2019: NET2ADD(IAC, EL);
2020: printoption("SENT", IAC, EL);
2021: }
2022:
2023: void
2024: xmitEC()
2025: {
2026: NET2ADD(IAC, EC);
2027: printoption("SENT", IAC, EC);
2028: }
2029:
2030:
2031: int
2032: dosynch()
2033: {
2034: netclear(); /* clear the path to the network */
2035: NETADD(IAC);
2036: setneturg();
2037: NETADD(DM);
2038: printoption("SENT", IAC, DM);
2039: return 1;
2040: }
2041:
2042: int want_status_response = 0;
2043:
2044: int
2045: get_status()
2046: {
2047: unsigned char tmp[16];
1.13 mpech 2048: unsigned char *cp;
1.1 deraadt 2049:
2050: if (my_want_state_is_dont(TELOPT_STATUS)) {
2051: printf("Remote side does not support STATUS option\n");
2052: return 0;
2053: }
2054: cp = tmp;
2055:
2056: *cp++ = IAC;
2057: *cp++ = SB;
2058: *cp++ = TELOPT_STATUS;
2059: *cp++ = TELQUAL_SEND;
2060: *cp++ = IAC;
2061: *cp++ = SE;
2062: if (NETROOM() >= cp - tmp) {
2063: ring_supply_data(&netoring, tmp, cp-tmp);
2064: printsub('>', tmp+2, cp - tmp - 2);
2065: }
2066: ++want_status_response;
2067: return 1;
2068: }
2069:
2070: void
2071: intp()
2072: {
2073: NET2ADD(IAC, IP);
2074: printoption("SENT", IAC, IP);
2075: flushline = 1;
2076: if (autoflush) {
2077: doflush();
2078: }
2079: if (autosynch) {
2080: dosynch();
2081: }
2082: }
2083:
2084: void
2085: sendbrk()
2086: {
2087: NET2ADD(IAC, BREAK);
2088: printoption("SENT", IAC, BREAK);
2089: flushline = 1;
2090: if (autoflush) {
2091: doflush();
2092: }
2093: if (autosynch) {
2094: dosynch();
2095: }
2096: }
2097:
2098: void
2099: sendabort()
2100: {
2101: NET2ADD(IAC, ABORT);
2102: printoption("SENT", IAC, ABORT);
2103: flushline = 1;
2104: if (autoflush) {
2105: doflush();
2106: }
2107: if (autosynch) {
2108: dosynch();
2109: }
2110: }
2111:
2112: void
2113: sendsusp()
2114: {
2115: NET2ADD(IAC, SUSP);
2116: printoption("SENT", IAC, SUSP);
2117: flushline = 1;
2118: if (autoflush) {
2119: doflush();
2120: }
2121: if (autosynch) {
2122: dosynch();
2123: }
2124: }
2125:
2126: void
2127: sendeof()
2128: {
2129: NET2ADD(IAC, xEOF);
2130: printoption("SENT", IAC, xEOF);
2131: }
2132:
2133: void
2134: sendayt()
2135: {
2136: NET2ADD(IAC, AYT);
2137: printoption("SENT", IAC, AYT);
2138: }
2139:
2140: /*
2141: * Send a window size update to the remote system.
2142: */
2143:
2144: void
2145: sendnaws()
2146: {
2147: long rows, cols;
2148: unsigned char tmp[16];
1.13 mpech 2149: unsigned char *cp;
1.1 deraadt 2150:
2151: if (my_state_is_wont(TELOPT_NAWS))
2152: return;
2153:
2154: #define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \
2155: if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; }
2156:
2157: if (TerminalWindowSize(&rows, &cols) == 0) { /* Failed */
2158: return;
2159: }
2160:
2161: cp = tmp;
2162:
2163: *cp++ = IAC;
2164: *cp++ = SB;
2165: *cp++ = TELOPT_NAWS;
2166: PUTSHORT(cp, cols);
2167: PUTSHORT(cp, rows);
2168: *cp++ = IAC;
2169: *cp++ = SE;
2170: if (NETROOM() >= cp - tmp) {
2171: ring_supply_data(&netoring, tmp, cp-tmp);
2172: printsub('>', tmp+2, cp - tmp - 2);
2173: }
2174: }
2175:
2176: void
2177: tel_enter_binary(rw)
2178: int rw;
2179: {
2180: if (rw&1)
2181: send_do(TELOPT_BINARY, 1);
2182: if (rw&2)
2183: send_will(TELOPT_BINARY, 1);
2184: }
2185:
2186: void
2187: tel_leave_binary(rw)
2188: int rw;
2189: {
2190: if (rw&1)
2191: send_dont(TELOPT_BINARY, 1);
2192: if (rw&2)
2193: send_wont(TELOPT_BINARY, 1);
2194: }