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