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