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