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