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