Annotation of src/usr.bin/telnet/telnet.c, Revision 1.5
1.5 ! art 1: /* $OpenBSD: telnet.c,v 1.4 1998/03/12 04:57:43 art Exp $ */
1.2 niklas 2: /* $NetBSD: telnet.c,v 1.7 1996/02/28 21:04:15 thorpej Exp $ */
3:
1.1 deraadt 4: /*
5: * Copyright (c) 1988, 1990, 1993
6: * The Regents of the University of California. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
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:
1.4 art 37: #include "telnet_locl.h"
1.5 ! art 38: #include <term.h>
1.1 deraadt 39:
1.4 art 40: #define strip(x) (eight ? (x) : ((x) & 0x7f))
1.1 deraadt 41:
42: static unsigned char subbuffer[SUBBUFSIZE],
43: *subpointer, *subend; /* buffer for sub-options */
44: #define SB_CLEAR() subpointer = subbuffer;
45: #define SB_TERM() { subend = subpointer; SB_CLEAR(); }
46: #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \
47: *subpointer++ = (c); \
48: }
49:
50: #define SB_GET() ((*subpointer++)&0xff)
51: #define SB_PEEK() ((*subpointer)&0xff)
52: #define SB_EOF() (subpointer >= subend)
53: #define SB_LEN() (subend - subpointer)
54:
55: char options[256]; /* The combined options */
56: char do_dont_resp[256];
57: char will_wont_resp[256];
58:
59: int
1.4 art 60: eight = 3,
61: binary = 0,
1.1 deraadt 62: autologin = 0, /* Autologin anyone? */
63: skiprc = 0,
64: connected,
65: showoptions,
66: In3270, /* Are we in 3270 mode? */
67: ISend, /* trying to send network data in */
68: debug = 0,
69: crmod,
70: netdata, /* Print out network data flow */
71: crlf, /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
72: #if defined(TN3270)
73: noasynchtty = 0,/* User specified "-noasynch" on command line */
74: noasynchnet = 0,/* User specified "-noasynch" on command line */
75: askedSGA = 0, /* We have talked about suppress go ahead */
76: #endif /* defined(TN3270) */
77: telnetport,
78: SYNCHing, /* we are in TELNET SYNCH mode */
79: flushout, /* flush output */
80: autoflush = 0, /* flush output when interrupting? */
81: autosynch, /* send interrupt characters with SYNCH? */
82: localflow, /* we handle flow control locally */
83: restartany, /* if flow control enabled, restart on any character */
84: localchars, /* we recognize interrupt/quit */
85: donelclchars, /* the user has set "localchars" */
86: donebinarytoggle, /* the user has put us in binary */
87: dontlecho, /* do we suppress local echoing right now? */
88: globalmode,
89: clienteof = 0;
90:
91: char *prompt = 0;
92:
93: cc_t escape;
94: cc_t rlogin;
95: #ifdef KLUDGELINEMODE
96: cc_t echoc;
97: #endif
98:
99: /*
100: * Telnet receiver states for fsm
101: */
102: #define TS_DATA 0
103: #define TS_IAC 1
104: #define TS_WILL 2
105: #define TS_WONT 3
106: #define TS_DO 4
107: #define TS_DONT 5
108: #define TS_CR 6
109: #define TS_SB 7 /* sub-option collection */
110: #define TS_SE 8 /* looking for sub-option end */
111:
112: static int telrcv_state;
113: #ifdef OLD_ENVIRON
114: unsigned char telopt_environ = TELOPT_NEW_ENVIRON;
115: #else
116: # define telopt_environ TELOPT_NEW_ENVIRON
117: #endif
118:
119: jmp_buf toplevel = { 0 };
120: jmp_buf peerdied;
121:
122: int flushline;
123: int linemode;
124:
125: #ifdef KLUDGELINEMODE
126: int kludgelinemode = 1;
127: #endif
128:
129: /*
130: * The following are some clocks used to decide how to interpret
131: * the relationship between various variables.
132: */
133:
134: Clocks clocks;
135:
136:
137: /*
138: * Initialize telnet environment.
139: */
140:
141: void
142: init_telnet()
143: {
144: env_init();
145:
146: SB_CLEAR();
1.4 art 147: memset((char *)options, 0, sizeof options);
1.1 deraadt 148:
149: connected = In3270 = ISend = localflow = donebinarytoggle = 0;
1.4 art 150: #if defined(AUTHENTICATION) || defined(ENCRYPTION)
1.1 deraadt 151: auth_encrypt_connect(connected);
1.4 art 152: #endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */
1.1 deraadt 153: restartany = -1;
154:
155: SYNCHing = 0;
156:
157: /* Don't change NetTrace */
158:
159: escape = CONTROL(']');
160: rlogin = _POSIX_VDISABLE;
161: #ifdef KLUDGELINEMODE
162: echoc = CONTROL('E');
163: #endif
164:
165: flushline = 1;
166: telrcv_state = TS_DATA;
167: }
168:
169:
170: /*
171: * These routines are in charge of sending option negotiations
172: * to the other side.
173: *
174: * The basic idea is that we send the negotiation if either side
175: * is in disagreement as to what the current state should be.
176: */
177:
178: void
179: send_do(c, init)
180: register int c, init;
181: {
182: if (init) {
183: if (((do_dont_resp[c] == 0) && my_state_is_do(c)) ||
184: my_want_state_is_do(c))
185: return;
186: set_my_want_state_do(c);
187: do_dont_resp[c]++;
188: }
189: NET2ADD(IAC, DO);
190: NETADD(c);
191: printoption("SENT", DO, c);
192: }
193:
194: void
195: send_dont(c, init)
196: register int c, init;
197: {
198: if (init) {
199: if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) ||
200: my_want_state_is_dont(c))
201: return;
202: set_my_want_state_dont(c);
203: do_dont_resp[c]++;
204: }
205: NET2ADD(IAC, DONT);
206: NETADD(c);
207: printoption("SENT", DONT, c);
208: }
209:
210: void
211: send_will(c, init)
212: register int c, init;
213: {
214: if (init) {
215: if (((will_wont_resp[c] == 0) && my_state_is_will(c)) ||
216: my_want_state_is_will(c))
217: return;
218: set_my_want_state_will(c);
219: will_wont_resp[c]++;
220: }
221: NET2ADD(IAC, WILL);
222: NETADD(c);
223: printoption("SENT", WILL, c);
224: }
225:
226: void
227: send_wont(c, init)
228: register int c, init;
229: {
230: if (init) {
231: if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) ||
232: my_want_state_is_wont(c))
233: return;
234: set_my_want_state_wont(c);
235: will_wont_resp[c]++;
236: }
237: NET2ADD(IAC, WONT);
238: NETADD(c);
239: printoption("SENT", WONT, c);
240: }
241:
242:
243: void
244: willoption(option)
245: int option;
246: {
247: int new_state_ok = 0;
248:
249: if (do_dont_resp[option]) {
250: --do_dont_resp[option];
251: if (do_dont_resp[option] && my_state_is_do(option))
252: --do_dont_resp[option];
253: }
254:
255: if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) {
256:
257: switch (option) {
258:
259: case TELOPT_ECHO:
260: # if defined(TN3270)
261: /*
262: * The following is a pain in the rear-end.
263: * Various IBM servers (some versions of Wiscnet,
264: * possibly Fibronics/Spartacus, and who knows who
265: * else) will NOT allow us to send "DO SGA" too early
266: * in the setup proceedings. On the other hand,
267: * 4.2 servers (telnetd) won't set SGA correctly.
268: * So, we are stuck. Empirically (but, based on
269: * a VERY small sample), the IBM servers don't send
270: * out anything about ECHO, so we postpone our sending
271: * "DO SGA" until we see "WILL ECHO" (which 4.2 servers
272: * DO send).
273: */
274: {
275: if (askedSGA == 0) {
276: askedSGA = 1;
277: if (my_want_state_is_dont(TELOPT_SGA))
278: send_do(TELOPT_SGA, 1);
279: }
280: }
281: /* Fall through */
282: case TELOPT_EOR:
283: #endif /* defined(TN3270) */
284: case TELOPT_BINARY:
285: case TELOPT_SGA:
286: settimer(modenegotiated);
287: /* FALL THROUGH */
288: case TELOPT_STATUS:
289: #if defined(AUTHENTICATION)
290: case TELOPT_AUTHENTICATION:
291: #endif
1.4 art 292: #if defined(ENCRYPTION)
293: case TELOPT_ENCRYPT:
294: #endif
1.1 deraadt 295: new_state_ok = 1;
296: break;
297:
298: case TELOPT_TM:
299: if (flushout)
300: flushout = 0;
301: /*
302: * Special case for TM. If we get back a WILL,
303: * pretend we got back a WONT.
304: */
305: set_my_want_state_dont(option);
306: set_my_state_dont(option);
307: return; /* Never reply to TM will's/wont's */
308:
309: case TELOPT_LINEMODE:
310: default:
311: break;
312: }
313:
314: if (new_state_ok) {
315: set_my_want_state_do(option);
316: send_do(option, 0);
317: setconnmode(0); /* possibly set new tty mode */
318: } else {
319: do_dont_resp[option]++;
320: send_dont(option, 0);
321: }
322: }
323: set_my_state_do(option);
1.4 art 324: #if defined(ENCRYPTION)
325: if (option == TELOPT_ENCRYPT)
326: encrypt_send_support();
327: #endif
328:
1.1 deraadt 329: }
330:
331: void
332: wontoption(option)
333: int option;
334: {
335: if (do_dont_resp[option]) {
336: --do_dont_resp[option];
337: if (do_dont_resp[option] && my_state_is_dont(option))
338: --do_dont_resp[option];
339: }
340:
341: if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) {
342:
343: switch (option) {
344:
345: #ifdef KLUDGELINEMODE
346: case TELOPT_SGA:
347: if (!kludgelinemode)
348: break;
349: /* FALL THROUGH */
350: #endif
351: case TELOPT_ECHO:
352: settimer(modenegotiated);
353: break;
354:
355: case TELOPT_TM:
356: if (flushout)
357: flushout = 0;
358: set_my_want_state_dont(option);
359: set_my_state_dont(option);
360: return; /* Never reply to TM will's/wont's */
361:
1.4 art 362: #ifdef ENCRYPTION
363: case TELOPT_ENCRYPT:
364: encrypt_not();
365: break;
366: #endif
1.1 deraadt 367: default:
368: break;
369: }
370: set_my_want_state_dont(option);
371: if (my_state_is_do(option))
372: send_dont(option, 0);
373: setconnmode(0); /* Set new tty mode */
374: } else if (option == TELOPT_TM) {
375: /*
376: * Special case for TM.
377: */
378: if (flushout)
379: flushout = 0;
380: set_my_want_state_dont(option);
381: }
382: set_my_state_dont(option);
383: }
384:
385: static void
386: dooption(option)
387: int option;
388: {
389: int new_state_ok = 0;
390:
391: if (will_wont_resp[option]) {
392: --will_wont_resp[option];
393: if (will_wont_resp[option] && my_state_is_will(option))
394: --will_wont_resp[option];
395: }
396:
397: if (will_wont_resp[option] == 0) {
398: if (my_want_state_is_wont(option)) {
399:
400: switch (option) {
401:
402: case TELOPT_TM:
403: /*
404: * Special case for TM. We send a WILL, but pretend
405: * we sent WONT.
406: */
407: send_will(option, 0);
408: set_my_want_state_wont(TELOPT_TM);
409: set_my_state_wont(TELOPT_TM);
410: return;
411:
412: # if defined(TN3270)
413: case TELOPT_EOR: /* end of record */
414: # endif /* defined(TN3270) */
415: case TELOPT_BINARY: /* binary mode */
416: case TELOPT_NAWS: /* window size */
417: case TELOPT_TSPEED: /* terminal speed */
418: case TELOPT_LFLOW: /* local flow control */
419: case TELOPT_TTYPE: /* terminal type option */
420: case TELOPT_SGA: /* no big deal */
1.4 art 421: #if defined(ENCRYPTION)
422: case TELOPT_ENCRYPT: /* encryption variable option */
423: #endif
1.1 deraadt 424: new_state_ok = 1;
425: break;
426:
427: case TELOPT_NEW_ENVIRON: /* New environment variable option */
428: #ifdef OLD_ENVIRON
429: if (my_state_is_will(TELOPT_OLD_ENVIRON))
430: send_wont(TELOPT_OLD_ENVIRON, 1); /* turn off the old */
431: goto env_common;
432: case TELOPT_OLD_ENVIRON: /* Old environment variable option */
433: if (my_state_is_will(TELOPT_NEW_ENVIRON))
434: break; /* Don't enable if new one is in use! */
435: env_common:
436: telopt_environ = option;
437: #endif
438: new_state_ok = 1;
439: break;
440:
441: #if defined(AUTHENTICATION)
442: case TELOPT_AUTHENTICATION:
443: if (autologin)
444: new_state_ok = 1;
445: break;
446: #endif
447:
448: case TELOPT_XDISPLOC: /* X Display location */
449: if (env_getvalue((unsigned char *)"DISPLAY"))
450: new_state_ok = 1;
451: break;
452:
453: case TELOPT_LINEMODE:
454: #ifdef KLUDGELINEMODE
455: kludgelinemode = 0;
456: send_do(TELOPT_SGA, 1);
457: #endif
458: set_my_want_state_will(TELOPT_LINEMODE);
459: send_will(option, 0);
460: set_my_state_will(TELOPT_LINEMODE);
461: slc_init();
462: return;
463:
464: case TELOPT_ECHO: /* We're never going to echo... */
465: default:
466: break;
467: }
468:
469: if (new_state_ok) {
470: set_my_want_state_will(option);
471: send_will(option, 0);
472: setconnmode(0); /* Set new tty mode */
473: } else {
474: will_wont_resp[option]++;
475: send_wont(option, 0);
476: }
477: } else {
478: /*
479: * Handle options that need more things done after the
480: * other side has acknowledged the option.
481: */
482: switch (option) {
483: case TELOPT_LINEMODE:
484: #ifdef KLUDGELINEMODE
485: kludgelinemode = 0;
486: send_do(TELOPT_SGA, 1);
487: #endif
488: set_my_state_will(option);
489: slc_init();
490: send_do(TELOPT_SGA, 0);
491: return;
492: }
493: }
494: }
495: set_my_state_will(option);
496: }
497:
498: static void
499: dontoption(option)
500: int option;
501: {
502:
503: if (will_wont_resp[option]) {
504: --will_wont_resp[option];
505: if (will_wont_resp[option] && my_state_is_wont(option))
506: --will_wont_resp[option];
507: }
508:
509: if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) {
510: switch (option) {
511: case TELOPT_LINEMODE:
512: linemode = 0; /* put us back to the default state */
513: break;
514: #ifdef OLD_ENVIRON
515: case TELOPT_NEW_ENVIRON:
516: /*
517: * The new environ option wasn't recognized, try
518: * the old one.
519: */
520: send_will(TELOPT_OLD_ENVIRON, 1);
521: telopt_environ = TELOPT_OLD_ENVIRON;
522: break;
523: #endif
524: }
525: /* we always accept a DONT */
526: set_my_want_state_wont(option);
527: if (my_state_is_will(option))
528: send_wont(option, 0);
529: setconnmode(0); /* Set new tty mode */
530: }
531: set_my_state_wont(option);
532: }
533:
534: /*
535: * Given a buffer returned by tgetent(), this routine will turn
536: * the pipe seperated list of names in the buffer into an array
537: * of pointers to null terminated names. We toss out any bad,
538: * duplicate, or verbose names (names with spaces).
539: */
540:
1.5 ! art 541: int is_unique P((char *, char **, char **));
! 542:
1.1 deraadt 543: static char *name_unknown = "UNKNOWN";
544: static char *unknown[] = { 0, 0 };
545:
546: char **
547: mklist(buf, name)
548: char *buf, *name;
549: {
550: register int n;
551: register char c, *cp, **argvp, *cp2, **argv, **avt;
552:
553: if (name) {
1.2 niklas 554: if ((int)strlen(name) > 40) {
1.1 deraadt 555: name = 0;
556: unknown[0] = name_unknown;
557: } else {
558: unknown[0] = name;
559: upcase(name);
560: }
561: } else
562: unknown[0] = name_unknown;
563: /*
564: * Count up the number of names.
565: */
566: for (n = 1, cp = buf; *cp && *cp != ':'; cp++) {
567: if (*cp == '|')
568: n++;
569: }
570: /*
571: * Allocate an array to put the name pointers into
572: */
573: argv = (char **)malloc((n+3)*sizeof(char *));
574: if (argv == 0)
575: return(unknown);
576:
577: /*
578: * Fill up the array of pointers to names.
579: */
580: *argv = 0;
581: argvp = argv+1;
582: n = 0;
583: for (cp = cp2 = buf; (c = *cp); cp++) {
584: if (c == '|' || c == ':') {
585: *cp++ = '\0';
586: /*
587: * Skip entries that have spaces or are over 40
588: * characters long. If this is our environment
589: * name, then put it up front. Otherwise, as
590: * long as this is not a duplicate name (case
591: * insensitive) add it to the list.
592: */
593: if (n || (cp - cp2 > 41))
594: ;
595: else if (name && (strncasecmp(name, cp2, cp-cp2) == 0))
596: *argv = cp2;
597: else if (is_unique(cp2, argv+1, argvp))
598: *argvp++ = cp2;
599: if (c == ':')
600: break;
601: /*
602: * Skip multiple delimiters. Reset cp2 to
603: * the beginning of the next name. Reset n,
604: * the flag for names with spaces.
605: */
606: while ((c = *cp) == '|')
607: cp++;
608: cp2 = cp;
609: n = 0;
610: }
611: /*
612: * Skip entries with spaces or non-ascii values.
613: * Convert lower case letters to upper case.
614: */
1.4 art 615: #define ISASCII(c) (!((c)&0x80))
616: if ((c == ' ') || !ISASCII(c))
1.1 deraadt 617: n = 1;
618: else if (islower(c))
619: *cp = toupper(c);
620: }
1.2 niklas 621:
1.1 deraadt 622: /*
623: * Check for an old V6 2 character name. If the second
624: * name points to the beginning of the buffer, and is
625: * only 2 characters long, move it to the end of the array.
626: */
627: if ((argv[1] == buf) && (strlen(argv[1]) == 2)) {
628: --argvp;
629: for (avt = &argv[1]; avt < argvp; avt++)
630: *avt = *(avt+1);
631: *argvp++ = buf;
632: }
633:
634: /*
635: * Duplicate last name, for TTYPE option, and null
636: * terminate the array. If we didn't find a match on
637: * our terminal name, put that name at the beginning.
638: */
639: cp = *(argvp-1);
640: *argvp++ = cp;
641: *argvp = 0;
642:
643: if (*argv == 0) {
644: if (name)
645: *argv = name;
646: else {
647: --argvp;
648: for (avt = argv; avt < argvp; avt++)
649: *avt = *(avt+1);
650: }
651: }
652: if (*argv)
653: return(argv);
654: else
655: return(unknown);
656: }
657:
658: int
659: is_unique(name, as, ae)
660: register char *name, **as, **ae;
661: {
662: register char **ap;
663: register int n;
664:
665: n = strlen(name) + 1;
666: for (ap = as; ap < ae; ap++)
667: if (strncasecmp(*ap, name, n) == 0)
668: return(0);
669: return (1);
670: }
671:
1.4 art 672: static char termbuf[1024];
1.1 deraadt 673:
674: /*ARGSUSED*/
675: int
1.4 art 676: telnet_setupterm(tname, fd, errp)
1.1 deraadt 677: char *tname;
678: int fd, *errp;
679: {
680: if (tgetent(termbuf, tname) == 1) {
681: termbuf[1023] = '\0';
682: if (errp)
683: *errp = 1;
684: return(0);
685: }
686: if (errp)
687: *errp = 0;
688: return(-1);
689: }
690:
691: int resettermname = 1;
692:
693: char *
694: gettermname()
695: {
696: char *tname;
697: static char **tnamep = 0;
698: static char **next;
699: int err;
700:
701: if (resettermname) {
702: resettermname = 0;
703: if (tnamep && tnamep != unknown)
704: free(tnamep);
705: if ((tname = (char *)env_getvalue((unsigned char *)"TERM")) &&
1.4 art 706: (telnet_setupterm(tname, 1, &err) == 0)) {
1.1 deraadt 707: tnamep = mklist(termbuf, tname);
708: } else {
1.2 niklas 709: if (tname && ((int)strlen(tname) <= 40)) {
1.1 deraadt 710: unknown[0] = tname;
711: upcase(tname);
712: } else
713: unknown[0] = name_unknown;
714: tnamep = unknown;
715: }
716: next = tnamep;
717: }
718: if (*next == 0)
719: next = tnamep;
720: return(*next++);
721: }
722: /*
723: * suboption()
724: *
725: * Look at the sub-option buffer, and try to be helpful to the other
726: * side.
727: *
728: * Currently we recognize:
729: *
730: * Terminal type, send request.
731: * Terminal speed (send request).
732: * Local flow control (is request).
733: * Linemode
734: */
735:
736: static void
737: suboption()
738: {
739: unsigned char subchar;
740:
741: printsub('<', subbuffer, SB_LEN()+2);
742: switch (subchar = SB_GET()) {
743: case TELOPT_TTYPE:
744: if (my_want_state_is_wont(TELOPT_TTYPE))
745: return;
746: if (SB_EOF() || SB_GET() != TELQUAL_SEND) {
747: return;
748: } else {
749: char *name;
750: unsigned char temp[50];
751: int len;
752:
753: #if defined(TN3270)
754: if (tn3270_ttype()) {
755: return;
756: }
757: #endif /* defined(TN3270) */
758: name = gettermname();
759: len = strlen(name) + 4 + 2;
760: if (len < NETROOM()) {
1.4 art 761: snprintf((char *)temp, sizeof(temp),
762: "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
763: TELQUAL_IS, name, IAC, SE);
1.1 deraadt 764: ring_supply_data(&netoring, temp, len);
765: printsub('>', &temp[2], len-2);
766: } else {
767: ExitString("No room in buffer for terminal type.\n", 1);
768: /*NOTREACHED*/
769: }
770: }
771: break;
772: case TELOPT_TSPEED:
773: if (my_want_state_is_wont(TELOPT_TSPEED))
774: return;
775: if (SB_EOF())
776: return;
777: if (SB_GET() == TELQUAL_SEND) {
778: long ospeed, ispeed;
779: unsigned char temp[50];
780: int len;
781:
782: TerminalSpeeds(&ispeed, &ospeed);
783:
1.4 art 784: snprintf((char *)temp, sizeof(temp),
1.5 ! art 785: "%c%c%c%c%ld,%ld%c%c", IAC, SB, TELOPT_TSPEED,
1.4 art 786: TELQUAL_IS, ospeed, ispeed, IAC, SE);
1.1 deraadt 787: len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */
788:
789: if (len < NETROOM()) {
790: ring_supply_data(&netoring, temp, len);
791: printsub('>', temp+2, len - 2);
792: }
793: /*@*/ else printf("lm_will: not enough room in buffer\n");
794: }
795: break;
796: case TELOPT_LFLOW:
797: if (my_want_state_is_wont(TELOPT_LFLOW))
798: return;
799: if (SB_EOF())
800: return;
801: switch(SB_GET()) {
802: case LFLOW_RESTART_ANY:
803: restartany = 1;
804: break;
805: case LFLOW_RESTART_XON:
806: restartany = 0;
807: break;
808: case LFLOW_ON:
809: localflow = 1;
810: break;
811: case LFLOW_OFF:
812: localflow = 0;
813: break;
814: default:
815: return;
816: }
817: setcommandmode();
818: setconnmode(0);
819: break;
820:
821: case TELOPT_LINEMODE:
822: if (my_want_state_is_wont(TELOPT_LINEMODE))
823: return;
824: if (SB_EOF())
825: return;
826: switch (SB_GET()) {
827: case WILL:
828: lm_will(subpointer, SB_LEN());
829: break;
830: case WONT:
831: lm_wont(subpointer, SB_LEN());
832: break;
833: case DO:
834: lm_do(subpointer, SB_LEN());
835: break;
836: case DONT:
837: lm_dont(subpointer, SB_LEN());
838: break;
839: case LM_SLC:
840: slc(subpointer, SB_LEN());
841: break;
842: case LM_MODE:
843: lm_mode(subpointer, SB_LEN(), 0);
844: break;
845: default:
846: break;
847: }
848: break;
849:
850: #ifdef OLD_ENVIRON
851: case TELOPT_OLD_ENVIRON:
852: #endif
853: case TELOPT_NEW_ENVIRON:
854: if (SB_EOF())
855: return;
856: switch(SB_PEEK()) {
857: case TELQUAL_IS:
858: case TELQUAL_INFO:
859: if (my_want_state_is_dont(subchar))
860: return;
861: break;
862: case TELQUAL_SEND:
863: if (my_want_state_is_wont(subchar)) {
864: return;
865: }
866: break;
867: default:
868: return;
869: }
870: env_opt(subpointer, SB_LEN());
871: break;
872:
873: case TELOPT_XDISPLOC:
874: if (my_want_state_is_wont(TELOPT_XDISPLOC))
875: return;
876: if (SB_EOF())
877: return;
878: if (SB_GET() == TELQUAL_SEND) {
879: unsigned char temp[50], *dp;
880: int len;
881:
882: if ((dp = env_getvalue((unsigned char *)"DISPLAY")) == NULL) {
883: /*
884: * Something happened, we no longer have a DISPLAY
885: * variable. So, turn off the option.
886: */
887: send_wont(TELOPT_XDISPLOC, 1);
888: break;
889: }
1.4 art 890: snprintf((char *)temp, sizeof(temp),
891: "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC,
1.1 deraadt 892: TELQUAL_IS, dp, IAC, SE);
893: len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */
894:
895: if (len < NETROOM()) {
896: ring_supply_data(&netoring, temp, len);
897: printsub('>', temp+2, len - 2);
898: }
899: /*@*/ else printf("lm_will: not enough room in buffer\n");
900: }
901: break;
902:
903: #if defined(AUTHENTICATION)
904: case TELOPT_AUTHENTICATION: {
905: if (!autologin)
906: break;
907: if (SB_EOF())
908: return;
909: switch(SB_GET()) {
910: case TELQUAL_IS:
911: if (my_want_state_is_dont(TELOPT_AUTHENTICATION))
912: return;
913: auth_is(subpointer, SB_LEN());
914: break;
915: case TELQUAL_SEND:
916: if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
917: return;
918: auth_send(subpointer, SB_LEN());
919: break;
920: case TELQUAL_REPLY:
921: if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
922: return;
923: auth_reply(subpointer, SB_LEN());
924: break;
925: case TELQUAL_NAME:
926: if (my_want_state_is_dont(TELOPT_AUTHENTICATION))
927: return;
928: auth_name(subpointer, SB_LEN());
929: break;
930: }
931: }
932: break;
933: #endif
1.4 art 934: #if defined(ENCRYPTION)
935: case TELOPT_ENCRYPT:
936: if (SB_EOF())
937: return;
938: switch(SB_GET()) {
939: case ENCRYPT_START:
940: if (my_want_state_is_dont(TELOPT_ENCRYPT))
941: return;
942: encrypt_start(subpointer, SB_LEN());
943: break;
944: case ENCRYPT_END:
945: if (my_want_state_is_dont(TELOPT_ENCRYPT))
946: return;
947: encrypt_end();
948: break;
949: case ENCRYPT_SUPPORT:
950: if (my_want_state_is_wont(TELOPT_ENCRYPT))
951: return;
952: encrypt_support(subpointer, SB_LEN());
953: break;
954: case ENCRYPT_REQSTART:
955: if (my_want_state_is_wont(TELOPT_ENCRYPT))
956: return;
957: encrypt_request_start(subpointer, SB_LEN());
958: break;
959: case ENCRYPT_REQEND:
960: if (my_want_state_is_wont(TELOPT_ENCRYPT))
961: return;
962: /*
963: * We can always send an REQEND so that we cannot
964: * get stuck encrypting. We should only get this
965: * if we have been able to get in the correct mode
966: * anyhow.
967: */
968: encrypt_request_end();
969: break;
970: case ENCRYPT_IS:
971: if (my_want_state_is_dont(TELOPT_ENCRYPT))
972: return;
973: encrypt_is(subpointer, SB_LEN());
974: break;
975: case ENCRYPT_REPLY:
976: if (my_want_state_is_wont(TELOPT_ENCRYPT))
977: return;
978: encrypt_reply(subpointer, SB_LEN());
979: break;
980: case ENCRYPT_ENC_KEYID:
981: if (my_want_state_is_dont(TELOPT_ENCRYPT))
982: return;
983: encrypt_enc_keyid(subpointer, SB_LEN());
984: break;
985: case ENCRYPT_DEC_KEYID:
986: if (my_want_state_is_wont(TELOPT_ENCRYPT))
987: return;
988: encrypt_dec_keyid(subpointer, SB_LEN());
989: break;
990: default:
991: break;
992: }
993: break;
994: #endif
1.1 deraadt 995: default:
996: break;
997: }
998: }
999:
1000: static unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE };
1001:
1002: void
1003: lm_will(cmd, len)
1004: unsigned char *cmd;
1005: int len;
1006: {
1007: if (len < 1) {
1008: /*@*/ printf("lm_will: no command!!!\n"); /* Should not happen... */
1009: return;
1010: }
1011: switch(cmd[0]) {
1012: case LM_FORWARDMASK: /* We shouldn't ever get this... */
1013: default:
1014: str_lm[3] = DONT;
1015: str_lm[4] = cmd[0];
1016: if (NETROOM() > sizeof(str_lm)) {
1017: ring_supply_data(&netoring, str_lm, sizeof(str_lm));
1018: printsub('>', &str_lm[2], sizeof(str_lm)-2);
1019: }
1020: /*@*/ else printf("lm_will: not enough room in buffer\n");
1021: break;
1022: }
1023: }
1024:
1025: void
1026: lm_wont(cmd, len)
1027: unsigned char *cmd;
1028: int len;
1029: {
1030: if (len < 1) {
1031: /*@*/ printf("lm_wont: no command!!!\n"); /* Should not happen... */
1032: return;
1033: }
1034: switch(cmd[0]) {
1035: case LM_FORWARDMASK: /* We shouldn't ever get this... */
1036: default:
1037: /* We are always DONT, so don't respond */
1038: return;
1039: }
1040: }
1041:
1042: void
1043: lm_do(cmd, len)
1044: unsigned char *cmd;
1045: int len;
1046: {
1047: if (len < 1) {
1048: /*@*/ printf("lm_do: no command!!!\n"); /* Should not happen... */
1049: return;
1050: }
1051: switch(cmd[0]) {
1052: case LM_FORWARDMASK:
1053: default:
1054: str_lm[3] = WONT;
1055: str_lm[4] = cmd[0];
1056: if (NETROOM() > sizeof(str_lm)) {
1057: ring_supply_data(&netoring, str_lm, sizeof(str_lm));
1058: printsub('>', &str_lm[2], sizeof(str_lm)-2);
1059: }
1060: /*@*/ else printf("lm_do: not enough room in buffer\n");
1061: break;
1062: }
1063: }
1064:
1065: void
1066: lm_dont(cmd, len)
1067: unsigned char *cmd;
1068: int len;
1069: {
1070: if (len < 1) {
1071: /*@*/ printf("lm_dont: no command!!!\n"); /* Should not happen... */
1072: return;
1073: }
1074: switch(cmd[0]) {
1075: case LM_FORWARDMASK:
1076: default:
1077: /* we are always WONT, so don't respond */
1078: break;
1079: }
1080: }
1081:
1082: static unsigned char str_lm_mode[] = {
1083: IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE
1084: };
1085:
1086: void
1087: lm_mode(cmd, len, init)
1088: unsigned char *cmd;
1089: int len, init;
1090: {
1091: if (len != 1)
1092: return;
1093: if ((linemode&MODE_MASK&~MODE_ACK) == *cmd)
1094: return;
1095: if (*cmd&MODE_ACK)
1096: return;
1097: linemode = *cmd&(MODE_MASK&~MODE_ACK);
1098: str_lm_mode[4] = linemode;
1099: if (!init)
1100: str_lm_mode[4] |= MODE_ACK;
1101: if (NETROOM() > sizeof(str_lm_mode)) {
1102: ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode));
1103: printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2);
1104: }
1105: /*@*/ else printf("lm_mode: not enough room in buffer\n");
1106: setconnmode(0); /* set changed mode */
1107: }
1108:
1109:
1110:
1111: /*
1112: * slc()
1113: * Handle special character suboption of LINEMODE.
1114: */
1115:
1116: struct spc {
1117: cc_t val;
1118: cc_t *valp;
1119: char flags; /* Current flags & level */
1120: char mylevel; /* Maximum level & flags */
1121: } spc_data[NSLC+1];
1122:
1123: #define SLC_IMPORT 0
1124: #define SLC_EXPORT 1
1125: #define SLC_RVALUE 2
1126: static int slc_mode = SLC_EXPORT;
1127:
1128: void
1129: slc_init()
1130: {
1131: register struct spc *spcp;
1132:
1133: localchars = 1;
1134: for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) {
1135: spcp->val = 0;
1136: spcp->valp = 0;
1137: spcp->flags = spcp->mylevel = SLC_NOSUPPORT;
1138: }
1139:
1140: #define initfunc(func, flags) { \
1141: spcp = &spc_data[func]; \
1.4 art 1142: if ((spcp->valp = tcval(func))) { \
1.1 deraadt 1143: spcp->val = *spcp->valp; \
1144: spcp->mylevel = SLC_VARIABLE|flags; \
1145: } else { \
1146: spcp->val = 0; \
1147: spcp->mylevel = SLC_DEFAULT; \
1148: } \
1149: }
1150:
1151: initfunc(SLC_SYNCH, 0);
1152: /* No BRK */
1153: initfunc(SLC_AO, 0);
1154: initfunc(SLC_AYT, 0);
1155: /* No EOR */
1156: initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT);
1157: initfunc(SLC_EOF, 0);
1158: #ifndef SYSV_TERMIO
1159: initfunc(SLC_SUSP, SLC_FLUSHIN);
1160: #endif
1161: initfunc(SLC_EC, 0);
1162: initfunc(SLC_EL, 0);
1163: #ifndef SYSV_TERMIO
1164: initfunc(SLC_EW, 0);
1165: initfunc(SLC_RP, 0);
1166: initfunc(SLC_LNEXT, 0);
1167: #endif
1168: initfunc(SLC_XON, 0);
1169: initfunc(SLC_XOFF, 0);
1170: #ifdef SYSV_TERMIO
1171: spc_data[SLC_XON].mylevel = SLC_CANTCHANGE;
1172: spc_data[SLC_XOFF].mylevel = SLC_CANTCHANGE;
1173: #endif
1174: initfunc(SLC_FORW1, 0);
1175: #ifdef USE_TERMIO
1176: initfunc(SLC_FORW2, 0);
1177: /* No FORW2 */
1178: #endif
1179:
1180: initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT);
1181: #undef initfunc
1182:
1183: if (slc_mode == SLC_EXPORT)
1184: slc_export();
1185: else
1186: slc_import(1);
1187:
1188: }
1189:
1190: void
1191: slcstate()
1192: {
1193: printf("Special characters are %s values\n",
1194: slc_mode == SLC_IMPORT ? "remote default" :
1195: slc_mode == SLC_EXPORT ? "local" :
1196: "remote");
1197: }
1198:
1199: void
1200: slc_mode_export()
1201: {
1202: slc_mode = SLC_EXPORT;
1203: if (my_state_is_will(TELOPT_LINEMODE))
1204: slc_export();
1205: }
1206:
1207: void
1208: slc_mode_import(def)
1209: int def;
1210: {
1211: slc_mode = def ? SLC_IMPORT : SLC_RVALUE;
1212: if (my_state_is_will(TELOPT_LINEMODE))
1213: slc_import(def);
1214: }
1215:
1216: unsigned char slc_import_val[] = {
1217: IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE
1218: };
1219: unsigned char slc_import_def[] = {
1220: IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE
1221: };
1222:
1223: void
1224: slc_import(def)
1225: int def;
1226: {
1227: if (NETROOM() > sizeof(slc_import_val)) {
1228: if (def) {
1229: ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def));
1230: printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2);
1231: } else {
1232: ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val));
1233: printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2);
1234: }
1235: }
1236: /*@*/ else printf("slc_import: not enough room\n");
1237: }
1238:
1239: void
1240: slc_export()
1241: {
1242: register struct spc *spcp;
1243:
1244: TerminalDefaultChars();
1245:
1246: slc_start_reply();
1247: for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1248: if (spcp->mylevel != SLC_NOSUPPORT) {
1249: if (spcp->val == (cc_t)(_POSIX_VDISABLE))
1250: spcp->flags = SLC_NOSUPPORT;
1251: else
1252: spcp->flags = spcp->mylevel;
1253: if (spcp->valp)
1254: spcp->val = *spcp->valp;
1255: slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
1256: }
1257: }
1258: slc_end_reply();
1259: (void)slc_update();
1260: setconnmode(1); /* Make sure the character values are set */
1261: }
1262:
1263: void
1264: slc(cp, len)
1265: register unsigned char *cp;
1266: int len;
1267: {
1268: register struct spc *spcp;
1269: register int func,level;
1270:
1271: slc_start_reply();
1272:
1273: for (; len >= 3; len -=3, cp +=3) {
1274:
1275: func = cp[SLC_FUNC];
1276:
1277: if (func == 0) {
1278: /*
1279: * Client side: always ignore 0 function.
1280: */
1281: continue;
1282: }
1283: if (func > NSLC) {
1284: if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT)
1285: slc_add_reply(func, SLC_NOSUPPORT, 0);
1286: continue;
1287: }
1288:
1289: spcp = &spc_data[func];
1290:
1291: level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK);
1292:
1293: if ((cp[SLC_VALUE] == (unsigned char)spcp->val) &&
1294: ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) {
1295: continue;
1296: }
1297:
1298: if (level == (SLC_DEFAULT|SLC_ACK)) {
1299: /*
1300: * This is an error condition, the SLC_ACK
1301: * bit should never be set for the SLC_DEFAULT
1302: * level. Our best guess to recover is to
1303: * ignore the SLC_ACK bit.
1304: */
1305: cp[SLC_FLAGS] &= ~SLC_ACK;
1306: }
1307:
1308: if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) {
1309: spcp->val = (cc_t)cp[SLC_VALUE];
1310: spcp->flags = cp[SLC_FLAGS]; /* include SLC_ACK */
1311: continue;
1312: }
1313:
1314: level &= ~SLC_ACK;
1315:
1316: if (level <= (spcp->mylevel&SLC_LEVELBITS)) {
1317: spcp->flags = cp[SLC_FLAGS]|SLC_ACK;
1318: spcp->val = (cc_t)cp[SLC_VALUE];
1319: }
1320: if (level == SLC_DEFAULT) {
1321: if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT)
1322: spcp->flags = spcp->mylevel;
1323: else
1324: spcp->flags = SLC_NOSUPPORT;
1325: }
1326: slc_add_reply(func, spcp->flags, spcp->val);
1327: }
1328: slc_end_reply();
1329: if (slc_update())
1330: setconnmode(1); /* set the new character values */
1331: }
1332:
1333: void
1334: slc_check()
1335: {
1336: register struct spc *spcp;
1337:
1338: slc_start_reply();
1339: for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1340: if (spcp->valp && spcp->val != *spcp->valp) {
1341: spcp->val = *spcp->valp;
1342: if (spcp->val == (cc_t)(_POSIX_VDISABLE))
1343: spcp->flags = SLC_NOSUPPORT;
1344: else
1345: spcp->flags = spcp->mylevel;
1346: slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
1347: }
1348: }
1349: slc_end_reply();
1350: setconnmode(1);
1351: }
1352:
1353:
1354: unsigned char slc_reply[128];
1355: unsigned char *slc_replyp;
1356:
1357: void
1358: slc_start_reply()
1359: {
1360: slc_replyp = slc_reply;
1361: *slc_replyp++ = IAC;
1362: *slc_replyp++ = SB;
1363: *slc_replyp++ = TELOPT_LINEMODE;
1364: *slc_replyp++ = LM_SLC;
1365: }
1366:
1367: void
1368: slc_add_reply(func, flags, value)
1369: unsigned char func;
1370: unsigned char flags;
1371: cc_t value;
1372: {
1373: if ((*slc_replyp++ = func) == IAC)
1374: *slc_replyp++ = IAC;
1375: if ((*slc_replyp++ = flags) == IAC)
1376: *slc_replyp++ = IAC;
1377: if ((*slc_replyp++ = (unsigned char)value) == IAC)
1378: *slc_replyp++ = IAC;
1379: }
1380:
1381: void
1382: slc_end_reply()
1383: {
1384: register int len;
1385:
1386: *slc_replyp++ = IAC;
1387: *slc_replyp++ = SE;
1388: len = slc_replyp - slc_reply;
1389: if (len <= 6)
1390: return;
1391: if (NETROOM() > len) {
1392: ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply);
1393: printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2);
1394: }
1395: /*@*/else printf("slc_end_reply: not enough room\n");
1396: }
1397:
1398: int
1399: slc_update()
1400: {
1401: register struct spc *spcp;
1402: int need_update = 0;
1403:
1404: for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1405: if (!(spcp->flags&SLC_ACK))
1406: continue;
1407: spcp->flags &= ~SLC_ACK;
1408: if (spcp->valp && (*spcp->valp != spcp->val)) {
1409: *spcp->valp = spcp->val;
1410: need_update = 1;
1411: }
1412: }
1413: return(need_update);
1414: }
1415:
1416: #ifdef OLD_ENVIRON
1417: # ifdef ENV_HACK
1418: /*
1419: * Earlier version of telnet/telnetd from the BSD code had
1420: * the definitions of VALUE and VAR reversed. To ensure
1421: * maximum interoperability, we assume that the server is
1422: * an older BSD server, until proven otherwise. The newer
1423: * BSD servers should be able to handle either definition,
1424: * so it is better to use the wrong values if we don't
1425: * know what type of server it is.
1426: */
1427: int env_auto = 1;
1428: int old_env_var = OLD_ENV_VAR;
1429: int old_env_value = OLD_ENV_VALUE;
1430: # else
1431: # define old_env_var OLD_ENV_VAR
1432: # define old_env_value OLD_ENV_VALUE
1433: # endif
1434: #endif
1435:
1436: void
1437: env_opt(buf, len)
1438: register unsigned char *buf;
1439: register int len;
1440: {
1441: register unsigned char *ep = 0, *epc = 0;
1442: register int i;
1443:
1444: switch(buf[0]&0xff) {
1445: case TELQUAL_SEND:
1446: env_opt_start();
1447: if (len == 1) {
1448: env_opt_add(NULL);
1449: } else for (i = 1; i < len; i++) {
1450: switch (buf[i]&0xff) {
1451: #ifdef OLD_ENVIRON
1452: case OLD_ENV_VAR:
1453: # ifdef ENV_HACK
1454: if (telopt_environ == TELOPT_OLD_ENVIRON
1455: && env_auto) {
1456: /* Server has the same definitions */
1457: old_env_var = OLD_ENV_VAR;
1458: old_env_value = OLD_ENV_VALUE;
1459: }
1460: /* FALL THROUGH */
1461: # endif
1462: case OLD_ENV_VALUE:
1463: /*
1464: * Although OLD_ENV_VALUE is not legal, we will
1465: * still recognize it, just in case it is an
1466: * old server that has VAR & VALUE mixed up...
1467: */
1468: /* FALL THROUGH */
1469: #else
1470: case NEW_ENV_VAR:
1471: #endif
1472: case ENV_USERVAR:
1473: if (ep) {
1474: *epc = 0;
1475: env_opt_add(ep);
1476: }
1477: ep = epc = &buf[i+1];
1478: break;
1479: case ENV_ESC:
1480: i++;
1481: /*FALL THROUGH*/
1482: default:
1483: if (epc)
1484: *epc++ = buf[i];
1485: break;
1486: }
1487: }
1488: if (ep) {
1489: *epc = 0;
1490: env_opt_add(ep);
1491: }
1492: env_opt_end(1);
1493: break;
1494:
1495: case TELQUAL_IS:
1496: case TELQUAL_INFO:
1497: /* Ignore for now. We shouldn't get it anyway. */
1498: break;
1499:
1500: default:
1501: break;
1502: }
1503: }
1504:
1505: #define OPT_REPLY_SIZE 256
1506: unsigned char *opt_reply;
1507: unsigned char *opt_replyp;
1508: unsigned char *opt_replyend;
1509:
1510: void
1511: env_opt_start()
1512: {
1513: if (opt_reply)
1514: opt_reply = (unsigned char *)realloc(opt_reply, OPT_REPLY_SIZE);
1515: else
1516: opt_reply = (unsigned char *)malloc(OPT_REPLY_SIZE);
1517: if (opt_reply == NULL) {
1518: /*@*/ printf("env_opt_start: malloc()/realloc() failed!!!\n");
1519: opt_reply = opt_replyp = opt_replyend = NULL;
1520: return;
1521: }
1522: opt_replyp = opt_reply;
1523: opt_replyend = opt_reply + OPT_REPLY_SIZE;
1524: *opt_replyp++ = IAC;
1525: *opt_replyp++ = SB;
1526: *opt_replyp++ = telopt_environ;
1527: *opt_replyp++ = TELQUAL_IS;
1528: }
1529:
1530: void
1531: env_opt_start_info()
1532: {
1533: env_opt_start();
1534: if (opt_replyp)
1535: opt_replyp[-1] = TELQUAL_INFO;
1536: }
1537:
1538: void
1539: env_opt_add(ep)
1540: register unsigned char *ep;
1541: {
1542: register unsigned char *vp, c;
1543:
1544: if (opt_reply == NULL) /*XXX*/
1545: return; /*XXX*/
1546:
1547: if (ep == NULL || *ep == '\0') {
1548: /* Send user defined variables first. */
1549: env_default(1, 0);
1.4 art 1550: while ((ep = env_default(0, 0)))
1.1 deraadt 1551: env_opt_add(ep);
1552:
1553: /* Now add the list of well know variables. */
1554: env_default(1, 1);
1.4 art 1555: while ((ep = env_default(0, 1)))
1.1 deraadt 1556: env_opt_add(ep);
1557: return;
1558: }
1559: vp = env_getvalue(ep);
1560: if (opt_replyp + (vp ? strlen((char *)vp) : 0) +
1561: strlen((char *)ep) + 6 > opt_replyend)
1562: {
1563: register int len;
1564: opt_replyend += OPT_REPLY_SIZE;
1565: len = opt_replyend - opt_reply;
1566: opt_reply = (unsigned char *)realloc(opt_reply, len);
1567: if (opt_reply == NULL) {
1568: /*@*/ printf("env_opt_add: realloc() failed!!!\n");
1569: opt_reply = opt_replyp = opt_replyend = NULL;
1570: return;
1571: }
1572: opt_replyp = opt_reply + len - (opt_replyend - opt_replyp);
1573: opt_replyend = opt_reply + len;
1574: }
1.4 art 1575: if (opt_welldefined((char *)ep))
1.1 deraadt 1576: #ifdef OLD_ENVIRON
1577: if (telopt_environ == TELOPT_OLD_ENVIRON)
1578: *opt_replyp++ = old_env_var;
1579: else
1580: #endif
1581: *opt_replyp++ = NEW_ENV_VAR;
1582: else
1583: *opt_replyp++ = ENV_USERVAR;
1584: for (;;) {
1.4 art 1585: while ((c = *ep++)) {
1.1 deraadt 1586: switch(c&0xff) {
1587: case IAC:
1588: *opt_replyp++ = IAC;
1589: break;
1590: case NEW_ENV_VAR:
1591: case NEW_ENV_VALUE:
1592: case ENV_ESC:
1593: case ENV_USERVAR:
1594: *opt_replyp++ = ENV_ESC;
1595: break;
1596: }
1597: *opt_replyp++ = c;
1598: }
1.4 art 1599: if ((ep = vp)) {
1.1 deraadt 1600: #ifdef OLD_ENVIRON
1601: if (telopt_environ == TELOPT_OLD_ENVIRON)
1602: *opt_replyp++ = old_env_value;
1603: else
1604: #endif
1605: *opt_replyp++ = NEW_ENV_VALUE;
1606: vp = NULL;
1607: } else
1608: break;
1609: }
1610: }
1611:
1612: int
1613: opt_welldefined(ep)
1614: char *ep;
1615: {
1616: if ((strcmp(ep, "USER") == 0) ||
1617: (strcmp(ep, "DISPLAY") == 0) ||
1618: (strcmp(ep, "PRINTER") == 0) ||
1619: (strcmp(ep, "SYSTEMTYPE") == 0) ||
1620: (strcmp(ep, "JOB") == 0) ||
1621: (strcmp(ep, "ACCT") == 0))
1622: return(1);
1623: return(0);
1624: }
1625: void
1626: env_opt_end(emptyok)
1627: register int emptyok;
1628: {
1629: register int len;
1630:
1631: len = opt_replyp - opt_reply + 2;
1632: if (emptyok || len > 6) {
1633: *opt_replyp++ = IAC;
1634: *opt_replyp++ = SE;
1635: if (NETROOM() > len) {
1636: ring_supply_data(&netoring, opt_reply, len);
1637: printsub('>', &opt_reply[2], len - 2);
1638: }
1639: /*@*/ else printf("slc_end_reply: not enough room\n");
1640: }
1641: if (opt_reply) {
1642: free(opt_reply);
1643: opt_reply = opt_replyp = opt_replyend = NULL;
1644: }
1645: }
1646:
1647:
1648:
1649: int
1650: telrcv()
1651: {
1652: register int c;
1653: register int scc;
1654: register unsigned char *sbp;
1655: int count;
1656: int returnValue = 0;
1657:
1658: scc = 0;
1659: count = 0;
1660: while (TTYROOM() > 2) {
1661: if (scc == 0) {
1662: if (count) {
1663: ring_consumed(&netiring, count);
1664: returnValue = 1;
1665: count = 0;
1666: }
1667: sbp = netiring.consume;
1668: scc = ring_full_consecutive(&netiring);
1669: if (scc == 0) {
1670: /* No more data coming in */
1671: break;
1672: }
1673: }
1674:
1675: c = *sbp++ & 0xff, scc--; count++;
1.4 art 1676: #if defined(ENCRYPTION)
1677: if (decrypt_input)
1678: c = (*decrypt_input)(c);
1679: #endif
1.1 deraadt 1680:
1681: switch (telrcv_state) {
1682:
1683: case TS_CR:
1684: telrcv_state = TS_DATA;
1685: if (c == '\0') {
1686: break; /* Ignore \0 after CR */
1687: }
1688: else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) {
1689: TTYADD(c);
1690: break;
1691: }
1692: /* Else, fall through */
1693:
1694: case TS_DATA:
1695: if (c == IAC) {
1696: telrcv_state = TS_IAC;
1697: break;
1698: }
1699: # if defined(TN3270)
1700: if (In3270) {
1701: *Ifrontp++ = c;
1702: while (scc > 0) {
1703: c = *sbp++ & 0377, scc--; count++;
1704: if (c == IAC) {
1705: telrcv_state = TS_IAC;
1706: break;
1707: }
1708: *Ifrontp++ = c;
1709: }
1710: } else
1711: # endif /* defined(TN3270) */
1712: /*
1713: * The 'crmod' hack (see following) is needed
1.4 art 1714: * since we can't set CRMOD on output only.
1.1 deraadt 1715: * Machines like MULTICS like to send \r without
1716: * \n; since we must turn off CRMOD to get proper
1717: * input, the mapping is done here (sigh).
1718: */
1719: if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) {
1720: if (scc > 0) {
1721: c = *sbp&0xff;
1.4 art 1722: #if defined(ENCRYPTION)
1723: if (decrypt_input)
1724: c = (*decrypt_input)(c);
1725: #endif
1.1 deraadt 1726: if (c == 0) {
1727: sbp++, scc--; count++;
1728: /* a "true" CR */
1729: TTYADD('\r');
1730: } else if (my_want_state_is_dont(TELOPT_ECHO) &&
1731: (c == '\n')) {
1732: sbp++, scc--; count++;
1733: TTYADD('\n');
1734: } else {
1.4 art 1735: #if defined(ENCRYPTION)
1736: if (decrypt_input)
1737: (*decrypt_input)(-1);
1738: #endif
1.1 deraadt 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
1.3 deraadt 2028: if (sc != _POSIX_VDISABLE && MODE_LOCAL_CHARS(globalmode)) {
1.1 deraadt 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.4 art 2174: #if defined(AUTHENTICATION) || defined(ENCRYPTION)
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: }
1.4 art 2185: #endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */
1.1 deraadt 2186: # if !defined(TN3270)
2187: if (telnetport) {
2188: #if defined(AUTHENTICATION)
2189: if (autologin)
2190: send_will(TELOPT_AUTHENTICATION, 1);
2191: #endif
1.4 art 2192: #if defined(ENCRYPTION)
2193: send_do(TELOPT_ENCRYPT, 1);
2194: send_will(TELOPT_ENCRYPT, 1);
2195: #endif
1.1 deraadt 2196: send_do(TELOPT_SGA, 1);
2197: send_will(TELOPT_TTYPE, 1);
2198: send_will(TELOPT_NAWS, 1);
2199: send_will(TELOPT_TSPEED, 1);
2200: send_will(TELOPT_LFLOW, 1);
2201: send_will(TELOPT_LINEMODE, 1);
2202: send_will(TELOPT_NEW_ENVIRON, 1);
2203: send_do(TELOPT_STATUS, 1);
2204: if (env_getvalue((unsigned char *)"DISPLAY"))
2205: send_will(TELOPT_XDISPLOC, 1);
1.4 art 2206: if (binary)
2207: tel_enter_binary(binary);
1.1 deraadt 2208: }
2209: # endif /* !defined(TN3270) */
2210:
2211: # if !defined(TN3270)
2212: for (;;) {
2213: int schedValue;
2214:
2215: while ((schedValue = Scheduler(0)) != 0) {
2216: if (schedValue == -1) {
2217: setcommandmode();
2218: return;
2219: }
2220: }
2221:
2222: if (Scheduler(1) == -1) {
2223: setcommandmode();
2224: return;
2225: }
2226: }
2227: # else /* !defined(TN3270) */
2228: for (;;) {
2229: int schedValue;
2230:
2231: while (!In3270 && !shell_active) {
2232: if (Scheduler(1) == -1) {
2233: setcommandmode();
2234: return;
2235: }
2236: }
2237:
2238: while ((schedValue = Scheduler(0)) != 0) {
2239: if (schedValue == -1) {
2240: setcommandmode();
2241: return;
2242: }
2243: }
2244: /* If there is data waiting to go out to terminal, don't
2245: * schedule any more data for the terminal.
2246: */
2247: if (ring_full_count(&ttyoring)) {
2248: schedValue = 1;
2249: } else {
2250: if (shell_active) {
2251: if (shell_continue() == 0) {
2252: ConnectScreen();
2253: }
2254: } else if (In3270) {
2255: schedValue = DoTerminalOutput();
2256: }
2257: }
2258: if (schedValue && (shell_active == 0)) {
2259: if (Scheduler(1) == -1) {
2260: setcommandmode();
2261: return;
2262: }
2263: }
2264: }
2265: # endif /* !defined(TN3270) */
2266: }
2267:
2268: #if 0 /* XXX - this not being in is a bug */
2269: /*
2270: * nextitem()
2271: *
2272: * Return the address of the next "item" in the TELNET data
2273: * stream. This will be the address of the next character if
2274: * the current address is a user data character, or it will
2275: * be the address of the character following the TELNET command
2276: * if the current address is a TELNET IAC ("I Am a Command")
2277: * character.
2278: */
2279:
2280: static char *
2281: nextitem(current)
2282: char *current;
2283: {
2284: if ((*current&0xff) != IAC) {
2285: return current+1;
2286: }
2287: switch (*(current+1)&0xff) {
2288: case DO:
2289: case DONT:
2290: case WILL:
2291: case WONT:
2292: return current+3;
2293: case SB: /* loop forever looking for the SE */
2294: {
2295: register char *look = current+2;
2296:
2297: for (;;) {
2298: if ((*look++&0xff) == IAC) {
2299: if ((*look++&0xff) == SE) {
2300: return look;
2301: }
2302: }
2303: }
2304: }
2305: default:
2306: return current+2;
2307: }
2308: }
2309: #endif /* 0 */
2310:
2311: /*
2312: * netclear()
2313: *
2314: * We are about to do a TELNET SYNCH operation. Clear
2315: * the path to the network.
2316: *
2317: * Things are a bit tricky since we may have sent the first
2318: * byte or so of a previous TELNET command into the network.
2319: * So, we have to scan the network buffer from the beginning
2320: * until we are up to where we want to be.
2321: *
2322: * A side effect of what we do, just to keep things
2323: * simple, is to clear the urgent data pointer. The principal
2324: * caller should be setting the urgent data pointer AFTER calling
2325: * us in any case.
2326: */
2327:
2328: static void
2329: netclear()
2330: {
2331: #if 0 /* XXX */
2332: register char *thisitem, *next;
2333: char *good;
2334: #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \
2335: ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
2336:
2337: thisitem = netobuf;
2338:
2339: while ((next = nextitem(thisitem)) <= netobuf.send) {
2340: thisitem = next;
2341: }
2342:
2343: /* Now, thisitem is first before/at boundary. */
2344:
2345: good = netobuf; /* where the good bytes go */
2346:
2347: while (netoring.add > thisitem) {
2348: if (wewant(thisitem)) {
2349: int length;
2350:
2351: next = thisitem;
2352: do {
2353: next = nextitem(next);
2354: } while (wewant(next) && (nfrontp > next));
2355: length = next-thisitem;
1.2 niklas 2356: memmove(good, thisitem, length);
1.1 deraadt 2357: good += length;
2358: thisitem = next;
2359: } else {
2360: thisitem = nextitem(thisitem);
2361: }
2362: }
2363:
2364: #endif /* 0 */
2365: }
2366:
2367: /*
2368: * These routines add various telnet commands to the data stream.
2369: */
2370:
2371: static void
2372: doflush()
2373: {
2374: NET2ADD(IAC, DO);
2375: NETADD(TELOPT_TM);
2376: flushline = 1;
2377: flushout = 1;
2378: (void) ttyflush(1); /* Flush/drop output */
2379: /* do printoption AFTER flush, otherwise the output gets tossed... */
2380: printoption("SENT", DO, TELOPT_TM);
2381: }
2382:
2383: void
2384: xmitAO()
2385: {
2386: NET2ADD(IAC, AO);
2387: printoption("SENT", IAC, AO);
2388: if (autoflush) {
2389: doflush();
2390: }
2391: }
2392:
2393:
2394: void
2395: xmitEL()
2396: {
2397: NET2ADD(IAC, EL);
2398: printoption("SENT", IAC, EL);
2399: }
2400:
2401: void
2402: xmitEC()
2403: {
2404: NET2ADD(IAC, EC);
2405: printoption("SENT", IAC, EC);
2406: }
2407:
2408:
2409: int
2410: dosynch()
2411: {
2412: netclear(); /* clear the path to the network */
2413: NETADD(IAC);
2414: setneturg();
2415: NETADD(DM);
2416: printoption("SENT", IAC, DM);
2417: return 1;
2418: }
2419:
2420: int want_status_response = 0;
2421:
2422: int
2423: get_status()
2424: {
2425: unsigned char tmp[16];
2426: register unsigned char *cp;
2427:
2428: if (my_want_state_is_dont(TELOPT_STATUS)) {
2429: printf("Remote side does not support STATUS option\n");
2430: return 0;
2431: }
2432: cp = tmp;
2433:
2434: *cp++ = IAC;
2435: *cp++ = SB;
2436: *cp++ = TELOPT_STATUS;
2437: *cp++ = TELQUAL_SEND;
2438: *cp++ = IAC;
2439: *cp++ = SE;
2440: if (NETROOM() >= cp - tmp) {
2441: ring_supply_data(&netoring, tmp, cp-tmp);
2442: printsub('>', tmp+2, cp - tmp - 2);
2443: }
2444: ++want_status_response;
2445: return 1;
2446: }
2447:
2448: void
2449: intp()
2450: {
2451: NET2ADD(IAC, IP);
2452: printoption("SENT", IAC, IP);
2453: flushline = 1;
2454: if (autoflush) {
2455: doflush();
2456: }
2457: if (autosynch) {
2458: dosynch();
2459: }
2460: }
2461:
2462: void
2463: sendbrk()
2464: {
2465: NET2ADD(IAC, BREAK);
2466: printoption("SENT", IAC, BREAK);
2467: flushline = 1;
2468: if (autoflush) {
2469: doflush();
2470: }
2471: if (autosynch) {
2472: dosynch();
2473: }
2474: }
2475:
2476: void
2477: sendabort()
2478: {
2479: NET2ADD(IAC, ABORT);
2480: printoption("SENT", IAC, ABORT);
2481: flushline = 1;
2482: if (autoflush) {
2483: doflush();
2484: }
2485: if (autosynch) {
2486: dosynch();
2487: }
2488: }
2489:
2490: void
2491: sendsusp()
2492: {
2493: NET2ADD(IAC, SUSP);
2494: printoption("SENT", IAC, SUSP);
2495: flushline = 1;
2496: if (autoflush) {
2497: doflush();
2498: }
2499: if (autosynch) {
2500: dosynch();
2501: }
2502: }
2503:
2504: void
2505: sendeof()
2506: {
2507: NET2ADD(IAC, xEOF);
2508: printoption("SENT", IAC, xEOF);
2509: }
2510:
2511: void
2512: sendayt()
2513: {
2514: NET2ADD(IAC, AYT);
2515: printoption("SENT", IAC, AYT);
2516: }
2517:
2518: /*
2519: * Send a window size update to the remote system.
2520: */
2521:
2522: void
2523: sendnaws()
2524: {
2525: long rows, cols;
2526: unsigned char tmp[16];
2527: register unsigned char *cp;
2528:
2529: if (my_state_is_wont(TELOPT_NAWS))
2530: return;
2531:
2532: #define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \
2533: if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; }
2534:
2535: if (TerminalWindowSize(&rows, &cols) == 0) { /* Failed */
2536: return;
2537: }
2538:
2539: cp = tmp;
2540:
2541: *cp++ = IAC;
2542: *cp++ = SB;
2543: *cp++ = TELOPT_NAWS;
2544: PUTSHORT(cp, cols);
2545: PUTSHORT(cp, rows);
2546: *cp++ = IAC;
2547: *cp++ = SE;
2548: if (NETROOM() >= cp - tmp) {
2549: ring_supply_data(&netoring, tmp, cp-tmp);
2550: printsub('>', tmp+2, cp - tmp - 2);
2551: }
2552: }
2553:
2554: void
2555: tel_enter_binary(rw)
2556: int rw;
2557: {
2558: if (rw&1)
2559: send_do(TELOPT_BINARY, 1);
2560: if (rw&2)
2561: send_will(TELOPT_BINARY, 1);
2562: }
2563:
2564: void
2565: tel_leave_binary(rw)
2566: int rw;
2567: {
2568: if (rw&1)
2569: send_dont(TELOPT_BINARY, 1);
2570: if (rw&2)
2571: send_wont(TELOPT_BINARY, 1);
2572: }