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