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