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