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