Annotation of src/usr.bin/telnet/telnet.c, Revision 1.26
1.26 ! guenther 1: /* $OpenBSD: telnet.c,v 1.25 2014/07/20 08:56:47 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.23 guenther 34:
1.24 guenther 35: #include <arpa/telnet.h>
1.23 guenther 36: #include <ctype.h>
1.9 millert 37: #include <curses.h>
1.24 guenther 38: #include <stdlib.h>
39: #include <string.h>
1.9 millert 40: #include <term.h>
1.1 deraadt 41:
1.4 art 42: #define strip(x) (eight ? (x) : ((x) & 0x7f))
1.1 deraadt 43:
44: static unsigned char subbuffer[SUBBUFSIZE],
45: *subpointer, *subend; /* buffer for sub-options */
46: #define SB_CLEAR() subpointer = subbuffer;
47: #define SB_TERM() { subend = subpointer; SB_CLEAR(); }
48: #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \
49: *subpointer++ = (c); \
50: }
51:
52: #define SB_GET() ((*subpointer++)&0xff)
53: #define SB_PEEK() ((*subpointer)&0xff)
54: #define SB_EOF() (subpointer >= subend)
55: #define SB_LEN() (subend - subpointer)
56:
57: char options[256]; /* The combined options */
58: char do_dont_resp[256];
59: char will_wont_resp[256];
60:
61: int
1.4 art 62: eight = 3,
63: binary = 0,
1.1 deraadt 64: autologin = 0, /* Autologin anyone? */
65: skiprc = 0,
66: connected,
67: showoptions,
68: ISend, /* trying to send network data in */
69: debug = 0,
70: crmod,
71: netdata, /* Print out network data flow */
72: crlf, /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
73: telnetport,
74: SYNCHing, /* we are in TELNET SYNCH mode */
75: flushout, /* flush output */
76: autoflush = 0, /* flush output when interrupting? */
77: autosynch, /* send interrupt characters with SYNCH? */
78: localflow, /* we handle flow control locally */
79: restartany, /* if flow control enabled, restart on any character */
80: localchars, /* we recognize interrupt/quit */
81: donelclchars, /* the user has set "localchars" */
82: donebinarytoggle, /* the user has put us in binary */
83: dontlecho, /* do we suppress local echoing right now? */
84: globalmode,
85: clienteof = 0;
86:
87: char *prompt = 0;
88:
1.15 hin 89: int scheduler_lockout_tty = 0;
90:
1.1 deraadt 91: cc_t escape;
92: cc_t rlogin;
93: #ifdef KLUDGELINEMODE
94: cc_t echoc;
95: #endif
96:
97: /*
98: * Telnet receiver states for fsm
99: */
100: #define TS_DATA 0
101: #define TS_IAC 1
102: #define TS_WILL 2
103: #define TS_WONT 3
104: #define TS_DO 4
105: #define TS_DONT 5
106: #define TS_CR 6
107: #define TS_SB 7 /* sub-option collection */
108: #define TS_SE 8 /* looking for sub-option end */
109:
110: static int telrcv_state;
111: # define telopt_environ TELOPT_NEW_ENVIRON
112:
113: jmp_buf toplevel = { 0 };
114: jmp_buf peerdied;
115:
116: int flushline;
117: int linemode;
118:
119: #ifdef KLUDGELINEMODE
120: int kludgelinemode = 1;
121: #endif
122:
123: /*
124: * The following are some clocks used to decide how to interpret
125: * the relationship between various variables.
126: */
127:
128: Clocks clocks;
129:
130:
131: /*
132: * Initialize telnet environment.
133: */
134:
135: void
136: init_telnet()
137: {
138: env_init();
139:
140: SB_CLEAR();
1.4 art 141: memset((char *)options, 0, sizeof options);
1.1 deraadt 142:
1.21 guenther 143: connected = ISend = localflow = donebinarytoggle = 0;
1.1 deraadt 144: restartany = -1;
145:
146: SYNCHing = 0;
147:
148: escape = CONTROL(']');
149: rlogin = _POSIX_VDISABLE;
150: #ifdef KLUDGELINEMODE
151: echoc = CONTROL('E');
152: #endif
153:
154: flushline = 1;
155: telrcv_state = TS_DATA;
156: }
157:
158:
159: /*
160: * These routines are in charge of sending option negotiations
161: * to the other side.
162: *
163: * The basic idea is that we send the negotiation if either side
164: * is in disagreement as to what the current state should be.
165: */
166:
167: void
168: send_do(c, init)
1.13 mpech 169: int c, init;
1.1 deraadt 170: {
171: if (init) {
172: if (((do_dont_resp[c] == 0) && my_state_is_do(c)) ||
173: my_want_state_is_do(c))
174: return;
175: set_my_want_state_do(c);
176: do_dont_resp[c]++;
177: }
178: NET2ADD(IAC, DO);
179: NETADD(c);
1.12 hin 180: printoption("SENT",DO, c);
1.1 deraadt 181: }
182:
183: void
184: send_dont(c, init)
1.13 mpech 185: int c, init;
1.1 deraadt 186: {
187: if (init) {
188: if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) ||
189: my_want_state_is_dont(c))
190: return;
191: set_my_want_state_dont(c);
192: do_dont_resp[c]++;
193: }
194: NET2ADD(IAC, DONT);
195: NETADD(c);
196: printoption("SENT", DONT, c);
197: }
198:
199: void
200: send_will(c, init)
1.13 mpech 201: int c, init;
1.1 deraadt 202: {
203: if (init) {
204: if (((will_wont_resp[c] == 0) && my_state_is_will(c)) ||
205: my_want_state_is_will(c))
206: return;
207: set_my_want_state_will(c);
208: will_wont_resp[c]++;
209: }
210: NET2ADD(IAC, WILL);
211: NETADD(c);
212: printoption("SENT", WILL, c);
213: }
214:
215: void
216: send_wont(c, init)
1.13 mpech 217: int c, init;
1.1 deraadt 218: {
219: if (init) {
220: if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) ||
221: my_want_state_is_wont(c))
222: return;
223: set_my_want_state_wont(c);
224: will_wont_resp[c]++;
225: }
226: NET2ADD(IAC, WONT);
227: NETADD(c);
228: printoption("SENT", WONT, c);
229: }
230:
231:
232: void
233: willoption(option)
234: int option;
235: {
236: int new_state_ok = 0;
237:
238: if (do_dont_resp[option]) {
239: --do_dont_resp[option];
240: if (do_dont_resp[option] && my_state_is_do(option))
241: --do_dont_resp[option];
242: }
243:
244: if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) {
245:
246: switch (option) {
247:
248: case TELOPT_ECHO:
249: case TELOPT_BINARY:
250: case TELOPT_SGA:
251: settimer(modenegotiated);
252: /* FALL THROUGH */
253: case TELOPT_STATUS:
254: new_state_ok = 1;
255: break;
256:
257: case TELOPT_TM:
258: if (flushout)
259: flushout = 0;
260: /*
261: * Special case for TM. If we get back a WILL,
262: * pretend we got back a WONT.
263: */
264: set_my_want_state_dont(option);
265: set_my_state_dont(option);
266: return; /* Never reply to TM will's/wont's */
267:
268: case TELOPT_LINEMODE:
269: default:
270: break;
271: }
272:
273: if (new_state_ok) {
274: set_my_want_state_do(option);
275: send_do(option, 0);
276: setconnmode(0); /* possibly set new tty mode */
277: } else {
278: do_dont_resp[option]++;
279: send_dont(option, 0);
280: }
281: }
282: set_my_state_do(option);
1.4 art 283:
1.1 deraadt 284: }
285:
286: void
287: wontoption(option)
288: int option;
289: {
290: if (do_dont_resp[option]) {
291: --do_dont_resp[option];
292: if (do_dont_resp[option] && my_state_is_dont(option))
293: --do_dont_resp[option];
294: }
295:
296: if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) {
297:
298: switch (option) {
299:
300: #ifdef KLUDGELINEMODE
301: case TELOPT_SGA:
302: if (!kludgelinemode)
303: break;
304: /* FALL THROUGH */
305: #endif
306: case TELOPT_ECHO:
307: settimer(modenegotiated);
308: break;
309:
310: case TELOPT_TM:
311: if (flushout)
312: flushout = 0;
313: set_my_want_state_dont(option);
314: set_my_state_dont(option);
315: return; /* Never reply to TM will's/wont's */
316:
317: default:
318: break;
319: }
320: set_my_want_state_dont(option);
321: if (my_state_is_do(option))
322: send_dont(option, 0);
323: setconnmode(0); /* Set new tty mode */
324: } else if (option == TELOPT_TM) {
325: /*
326: * Special case for TM.
327: */
328: if (flushout)
329: flushout = 0;
330: set_my_want_state_dont(option);
331: }
332: set_my_state_dont(option);
333: }
334:
335: static void
336: dooption(option)
337: int option;
338: {
339: int new_state_ok = 0;
340:
341: if (will_wont_resp[option]) {
342: --will_wont_resp[option];
343: if (will_wont_resp[option] && my_state_is_will(option))
344: --will_wont_resp[option];
345: }
346:
347: if (will_wont_resp[option] == 0) {
348: if (my_want_state_is_wont(option)) {
349:
350: switch (option) {
351:
352: case TELOPT_TM:
353: /*
354: * Special case for TM. We send a WILL, but pretend
355: * we sent WONT.
356: */
357: send_will(option, 0);
358: set_my_want_state_wont(TELOPT_TM);
359: set_my_state_wont(TELOPT_TM);
360: return;
361:
362: case TELOPT_BINARY: /* binary mode */
363: case TELOPT_NAWS: /* window size */
364: case TELOPT_TSPEED: /* terminal speed */
365: case TELOPT_LFLOW: /* local flow control */
366: case TELOPT_TTYPE: /* terminal type option */
367: case TELOPT_SGA: /* no big deal */
368: new_state_ok = 1;
369: break;
370:
371: case TELOPT_NEW_ENVIRON: /* New environment variable option */
372: new_state_ok = 1;
373: break;
374:
375: case TELOPT_XDISPLOC: /* X Display location */
1.19 otto 376: if (env_getvalue((unsigned char *)"DISPLAY", 0))
1.1 deraadt 377: new_state_ok = 1;
378: break;
379:
380: case TELOPT_LINEMODE:
381: #ifdef KLUDGELINEMODE
382: kludgelinemode = 0;
383: send_do(TELOPT_SGA, 1);
384: #endif
385: set_my_want_state_will(TELOPT_LINEMODE);
386: send_will(option, 0);
387: set_my_state_will(TELOPT_LINEMODE);
388: slc_init();
389: return;
390:
391: case TELOPT_ECHO: /* We're never going to echo... */
392: default:
393: break;
394: }
395:
396: if (new_state_ok) {
397: set_my_want_state_will(option);
398: send_will(option, 0);
399: setconnmode(0); /* Set new tty mode */
400: } else {
401: will_wont_resp[option]++;
402: send_wont(option, 0);
403: }
404: } else {
405: /*
406: * Handle options that need more things done after the
407: * other side has acknowledged the option.
408: */
409: switch (option) {
410: case TELOPT_LINEMODE:
411: #ifdef KLUDGELINEMODE
412: kludgelinemode = 0;
413: send_do(TELOPT_SGA, 1);
414: #endif
415: set_my_state_will(option);
416: slc_init();
417: send_do(TELOPT_SGA, 0);
418: return;
419: }
420: }
421: }
422: set_my_state_will(option);
423: }
424:
425: static void
426: dontoption(option)
427: int option;
428: {
429:
430: if (will_wont_resp[option]) {
431: --will_wont_resp[option];
432: if (will_wont_resp[option] && my_state_is_wont(option))
433: --will_wont_resp[option];
434: }
435:
436: if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) {
437: switch (option) {
438: case TELOPT_LINEMODE:
439: linemode = 0; /* put us back to the default state */
440: break;
441: }
442: /* we always accept a DONT */
443: set_my_want_state_wont(option);
444: if (my_state_is_will(option))
445: send_wont(option, 0);
446: setconnmode(0); /* Set new tty mode */
447: }
448: set_my_state_wont(option);
449: }
450:
451: /*
1.11 provos 452: * This routine will turn a pipe separated list of names in the buffer
1.9 millert 453: * into an array of pointers to NUL terminated names. We toss out any
454: * bad, duplicate, or verbose names (names with spaces).
1.1 deraadt 455: */
456:
1.14 millert 457: int is_unique(char *, char **, char **);
1.5 art 458:
1.1 deraadt 459: static char *name_unknown = "UNKNOWN";
460: static char *unknown[] = { 0, 0 };
461:
462: char **
463: mklist(buf, name)
464: char *buf, *name;
465: {
1.13 mpech 466: int n;
467: char c, *cp, **argvp, *cp2, **argv, **avt;
1.1 deraadt 468:
469: if (name) {
1.2 niklas 470: if ((int)strlen(name) > 40) {
1.1 deraadt 471: name = 0;
472: unknown[0] = name_unknown;
473: } else {
474: unknown[0] = name;
475: upcase(name);
476: }
477: } else
478: unknown[0] = name_unknown;
479: /*
480: * Count up the number of names.
481: */
1.9 millert 482: for (n = 1, cp = buf; *cp; cp++) {
1.1 deraadt 483: if (*cp == '|')
484: n++;
485: }
486: /*
487: * Allocate an array to put the name pointers into
488: */
489: argv = (char **)malloc((n+3)*sizeof(char *));
490: if (argv == 0)
491: return(unknown);
492:
493: /*
494: * Fill up the array of pointers to names.
495: */
496: *argv = 0;
497: argvp = argv+1;
498: n = 0;
499: for (cp = cp2 = buf; (c = *cp); cp++) {
500: if (c == '|' || c == ':') {
501: *cp++ = '\0';
502: /*
503: * Skip entries that have spaces or are over 40
504: * characters long. If this is our environment
505: * name, then put it up front. Otherwise, as
506: * long as this is not a duplicate name (case
507: * insensitive) add it to the list.
508: */
509: if (n || (cp - cp2 > 41))
510: ;
511: else if (name && (strncasecmp(name, cp2, cp-cp2) == 0))
512: *argv = cp2;
513: else if (is_unique(cp2, argv+1, argvp))
514: *argvp++ = cp2;
515: if (c == ':')
516: break;
517: /*
518: * Skip multiple delimiters. Reset cp2 to
519: * the beginning of the next name. Reset n,
520: * the flag for names with spaces.
521: */
522: while ((c = *cp) == '|')
523: cp++;
524: cp2 = cp;
525: n = 0;
526: }
527: /*
528: * Skip entries with spaces or non-ascii values.
529: * Convert lower case letters to upper case.
530: */
1.4 art 531: #define ISASCII(c) (!((c)&0x80))
532: if ((c == ' ') || !ISASCII(c))
1.1 deraadt 533: n = 1;
1.23 guenther 534: else
535: *cp = toupper((unsigned char)c);
1.1 deraadt 536: }
1.2 niklas 537:
1.1 deraadt 538: /*
539: * Check for an old V6 2 character name. If the second
540: * name points to the beginning of the buffer, and is
541: * only 2 characters long, move it to the end of the array.
542: */
543: if ((argv[1] == buf) && (strlen(argv[1]) == 2)) {
544: --argvp;
545: for (avt = &argv[1]; avt < argvp; avt++)
546: *avt = *(avt+1);
547: *argvp++ = buf;
548: }
549:
550: /*
551: * Duplicate last name, for TTYPE option, and null
552: * terminate the array. If we didn't find a match on
553: * our terminal name, put that name at the beginning.
554: */
555: cp = *(argvp-1);
556: *argvp++ = cp;
557: *argvp = 0;
558:
559: if (*argv == 0) {
560: if (name)
561: *argv = name;
562: else {
563: --argvp;
564: for (avt = argv; avt < argvp; avt++)
565: *avt = *(avt+1);
566: }
567: }
568: if (*argv)
569: return(argv);
570: else
571: return(unknown);
572: }
573:
574: int
575: is_unique(name, as, ae)
1.13 mpech 576: char *name, **as, **ae;
1.1 deraadt 577: {
1.13 mpech 578: char **ap;
579: int n;
1.1 deraadt 580:
581: n = strlen(name) + 1;
582: for (ap = as; ap < ae; ap++)
583: if (strncasecmp(*ap, name, n) == 0)
584: return(0);
585: return (1);
586: }
587:
588: int resettermname = 1;
589:
590: char *
591: gettermname()
592: {
593: char *tname;
594: static char **tnamep = 0;
595: static char **next;
1.10 millert 596: int errret;
1.1 deraadt 597:
598: if (resettermname) {
599: resettermname = 0;
600: if (tnamep && tnamep != unknown)
601: free(tnamep);
1.19 otto 602: if ((tname = (char *)env_getvalue((unsigned char *)"TERM", 0)) &&
1.10 millert 603: (setupterm(tname, 1, &errret) == OK)) {
1.9 millert 604: tnamep = mklist(ttytype, tname);
1.1 deraadt 605: } else {
1.2 niklas 606: if (tname && ((int)strlen(tname) <= 40)) {
1.1 deraadt 607: unknown[0] = tname;
608: upcase(tname);
609: } else
610: unknown[0] = name_unknown;
611: tnamep = unknown;
612: }
613: next = tnamep;
614: }
615: if (*next == 0)
616: next = tnamep;
617: return(*next++);
618: }
619: /*
620: * suboption()
621: *
622: * Look at the sub-option buffer, and try to be helpful to the other
623: * side.
624: *
625: * Currently we recognize:
626: *
627: * Terminal type, send request.
628: * Terminal speed (send request).
629: * Local flow control (is request).
630: * Linemode
631: */
632:
633: static void
634: suboption()
635: {
636: unsigned char subchar;
637:
638: printsub('<', subbuffer, SB_LEN()+2);
639: switch (subchar = SB_GET()) {
640: case TELOPT_TTYPE:
641: if (my_want_state_is_wont(TELOPT_TTYPE))
642: return;
643: if (SB_EOF() || SB_GET() != TELQUAL_SEND) {
644: return;
645: } else {
646: char *name;
647: unsigned char temp[50];
648: int len;
649:
650: name = gettermname();
651: len = strlen(name) + 4 + 2;
652: if (len < NETROOM()) {
1.4 art 653: snprintf((char *)temp, sizeof(temp),
654: "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
655: TELQUAL_IS, name, IAC, SE);
1.1 deraadt 656: ring_supply_data(&netoring, temp, len);
657: printsub('>', &temp[2], len-2);
1.26 ! guenther 658: } else
1.1 deraadt 659: ExitString("No room in buffer for terminal type.\n", 1);
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
1.25 guenther 985: slc_mode_export(int unused)
1.1 deraadt 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: }