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