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