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