Upgrade libressl. 1/2
[dragonfly.git] / libexec / telnetd / state.c
1 /*
2  * Copyright (c) 1989, 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. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * @(#)state.c  8.5 (Berkeley) 5/30/95
30  * $FreeBSD: src/crypto/telnet/telnetd/state.c,v 1.4.2.3 2002/04/13 10:59:08 markm Exp $
31  */
32
33 #include <stdarg.h>
34 #include "telnetd.h"
35 #ifdef  AUTHENTICATION
36 #include <libtelnet/auth.h>
37 #endif
38 #ifdef  ENCRYPTION
39 #include <libtelnet/encrypt.h>
40 #endif
41
42 static int envvarok(char *);
43
44 unsigned char   doopt[] = { IAC, DO, '%', 'c', 0 };
45 unsigned char   dont[] = { IAC, DONT, '%', 'c', 0 };
46 unsigned char   will[] = { IAC, WILL, '%', 'c', 0 };
47 unsigned char   wont[] = { IAC, WONT, '%', 'c', 0 };
48 int     not42 = 1;
49 char    *terminaltype;
50
51 /*
52  * Buffer for sub-options, and macros
53  * for suboptions buffer manipulations
54  */
55 unsigned char subbuffer[512], *subpointer= subbuffer, *subend= subbuffer;
56
57 #define SB_CLEAR()      subpointer = subbuffer
58 #define SB_TERM()       { subend = subpointer; SB_CLEAR(); }
59 #define SB_ACCUM(c)     if (subpointer < (subbuffer+sizeof subbuffer)) { \
60                                 *subpointer++ = (c); \
61                         }
62 #define SB_GET()        ((*subpointer++)&0xff)
63 #define SB_EOF()        (subpointer >= subend)
64 #define SB_LEN()        (subend - subpointer)
65
66 #ifdef  ENV_HACK
67 unsigned char *subsave;
68 #define SB_SAVE()       subsave = subpointer;
69 #define SB_RESTORE()    subpointer = subsave;
70 #endif
71
72
73 /*
74  * State for recv fsm
75  */
76 #define TS_DATA         0       /* base state */
77 #define TS_IAC          1       /* look for double IAC's */
78 #define TS_CR           2       /* CR-LF ->'s CR */
79 #define TS_SB           3       /* throw away begin's... */
80 #define TS_SE           4       /* ...end's (suboption negotiation) */
81 #define TS_WILL         5       /* will option negotiation */
82 #define TS_WONT         6       /* wont " */
83 #define TS_DO           7       /* do " */
84 #define TS_DONT         8       /* dont " */
85
86 static void doclientstat(void);
87
88 void
89 telrcv(void)
90 {
91         int c;
92         static int state = TS_DATA;
93
94         while (ncc > 0) {
95                 if ((&ptyobuf[BUFSIZ] - pfrontp) < 2)
96                         break;
97                 c = *netip++ & 0377, ncc--;
98 #ifdef  ENCRYPTION
99                 if (decrypt_input)
100                         c = (*decrypt_input)(c);
101 #endif  /* ENCRYPTION */
102                 switch (state) {
103
104                 case TS_CR:
105                         state = TS_DATA;
106                         /* Strip off \n or \0 after a \r */
107                         if ((c == 0) || (c == '\n')) {
108                                 break;
109                         }
110                         /* FALL THROUGH */
111
112                 case TS_DATA:
113                         if (c == IAC) {
114                                 state = TS_IAC;
115                                 break;
116                         }
117                         /*
118                          * We now map \r\n ==> \r for pragmatic reasons.
119                          * Many client implementations send \r\n when
120                          * the user hits the CarriageReturn key.
121                          *
122                          * We USED to map \r\n ==> \n, since \r\n says
123                          * that we want to be in column 1 of the next
124                          * printable line, and \n is the standard
125                          * unix way of saying that (\r is only good
126                          * if CRMOD is set, which it normally is).
127                          */
128                         if ((c == '\r') && his_state_is_wont(TELOPT_BINARY)) {
129                                 int nc = *netip;
130 #ifdef  ENCRYPTION
131                                 if (decrypt_input)
132                                         nc = (*decrypt_input)(nc & 0xff);
133 #endif  /* ENCRYPTION */
134 #ifdef  LINEMODE
135                                 /*
136                                  * If we are operating in linemode,
137                                  * convert to local end-of-line.
138                                  */
139                                 if (linemode && (ncc > 0) && (('\n' == nc) ||
140                                          ((0 == nc) && tty_iscrnl())) ) {
141                                         netip++; ncc--;
142                                         c = '\n';
143                                 } else
144 #endif
145                                 {
146 #ifdef  ENCRYPTION
147                                         if (decrypt_input)
148                                                 (void)(*decrypt_input)(-1);
149 #endif  /* ENCRYPTION */
150                                         state = TS_CR;
151                                 }
152                         }
153                         *pfrontp++ = c;
154                         break;
155
156                 case TS_IAC:
157 gotiac:                 switch (c) {
158
159                         /*
160                          * Send the process on the pty side an
161                          * interrupt.  Do this with a NULL or
162                          * interrupt char; depending on the tty mode.
163                          */
164                         case IP:
165                                 DIAG(TD_OPTIONS,
166                                         printoption("td: recv IAC", c));
167                                 interrupt();
168                                 break;
169
170                         case BREAK:
171                                 DIAG(TD_OPTIONS,
172                                         printoption("td: recv IAC", c));
173                                 sendbrk();
174                                 break;
175
176                         /*
177                          * Are You There?
178                          */
179                         case AYT:
180                                 DIAG(TD_OPTIONS,
181                                         printoption("td: recv IAC", c));
182                                 recv_ayt();
183                                 break;
184
185                         /*
186                          * Abort Output
187                          */
188                         case AO:
189                             {
190                                 DIAG(TD_OPTIONS,
191                                         printoption("td: recv IAC", c));
192                                 ptyflush();     /* half-hearted */
193                                 init_termbuf();
194
195                                 if (slctab[SLC_AO].sptr &&
196                                     *slctab[SLC_AO].sptr != (cc_t)(_POSIX_VDISABLE)) {
197                                     *pfrontp++ =
198                                         (unsigned char)*slctab[SLC_AO].sptr;
199                                 }
200
201                                 netclear();     /* clear buffer back */
202                                 output_data("%c%c", IAC, DM);
203                                 neturg = nfrontp-1; /* off by one XXX */
204                                 DIAG(TD_OPTIONS,
205                                         printoption("td: send IAC", DM));
206                                 break;
207                             }
208
209                         /*
210                          * Erase Character and
211                          * Erase Line
212                          */
213                         case EC:
214                         case EL:
215                             {
216                                 cc_t ch;
217
218                                 DIAG(TD_OPTIONS,
219                                         printoption("td: recv IAC", c));
220                                 ptyflush();     /* half-hearted */
221                                 init_termbuf();
222                                 if (c == EC)
223                                         ch = *slctab[SLC_EC].sptr;
224                                 else
225                                         ch = *slctab[SLC_EL].sptr;
226                                 if (ch != (cc_t)(_POSIX_VDISABLE))
227                                         *pfrontp++ = (unsigned char)ch;
228                                 break;
229                             }
230
231                         /*
232                          * Check for urgent data...
233                          */
234                         case DM:
235                                 DIAG(TD_OPTIONS,
236                                         printoption("td: recv IAC", c));
237                                 SYNCHing = stilloob(net);
238                                 settimer(gotDM);
239                                 break;
240
241
242                         /*
243                          * Begin option subnegotiation...
244                          */
245                         case SB:
246                                 state = TS_SB;
247                                 SB_CLEAR();
248                                 continue;
249
250                         case WILL:
251                                 state = TS_WILL;
252                                 continue;
253
254                         case WONT:
255                                 state = TS_WONT;
256                                 continue;
257
258                         case DO:
259                                 state = TS_DO;
260                                 continue;
261
262                         case DONT:
263                                 state = TS_DONT;
264                                 continue;
265                         case EOR:
266                                 if (his_state_is_will(TELOPT_EOR))
267                                         doeof();
268                                 break;
269
270                         /*
271                          * Handle RFC 10xx Telnet linemode option additions
272                          * to command stream (EOF, SUSP, ABORT).
273                          */
274                         case xEOF:
275                                 doeof();
276                                 break;
277
278                         case SUSP:
279                                 sendsusp();
280                                 break;
281
282                         case ABORT:
283                                 sendbrk();
284                                 break;
285
286                         case IAC:
287                                 *pfrontp++ = c;
288                                 break;
289                         }
290                         state = TS_DATA;
291                         break;
292
293                 case TS_SB:
294                         if (c == IAC) {
295                                 state = TS_SE;
296                         } else {
297                                 SB_ACCUM(c);
298                         }
299                         break;
300
301                 case TS_SE:
302                         if (c != SE) {
303                                 if (c != IAC) {
304                                         /*
305                                          * bad form of suboption negotiation.
306                                          * handle it in such a way as to avoid
307                                          * damage to local state.  Parse
308                                          * suboption buffer found so far,
309                                          * then treat remaining stream as
310                                          * another command sequence.
311                                          */
312
313                                         /* for DIAGNOSTICS */
314                                         SB_ACCUM(IAC);
315                                         SB_ACCUM(c);
316                                         subpointer -= 2;
317
318                                         SB_TERM();
319                                         suboption();
320                                         state = TS_IAC;
321                                         goto gotiac;
322                                 }
323                                 SB_ACCUM(c);
324                                 state = TS_SB;
325                         } else {
326                                 /* for DIAGNOSTICS */
327                                 SB_ACCUM(IAC);
328                                 SB_ACCUM(SE);
329                                 subpointer -= 2;
330
331                                 SB_TERM();
332                                 suboption();    /* handle sub-option */
333                                 state = TS_DATA;
334                         }
335                         break;
336
337                 case TS_WILL:
338                         willoption(c);
339                         state = TS_DATA;
340                         continue;
341
342                 case TS_WONT:
343                         wontoption(c);
344                         state = TS_DATA;
345                         continue;
346
347                 case TS_DO:
348                         dooption(c);
349                         state = TS_DATA;
350                         continue;
351
352                 case TS_DONT:
353                         dontoption(c);
354                         state = TS_DATA;
355                         continue;
356
357                 default:
358                         syslog(LOG_ERR, "panic state=%d", state);
359                         printf("telnetd: panic state=%d\n", state);
360                         exit(1);
361                 }
362         }
363 }  /* end of telrcv */
364
365 /*
366  * The will/wont/do/dont state machines are based on Dave Borman's
367  * Telnet option processing state machine.
368  *
369  * These correspond to the following states:
370  *      my_state = the last negotiated state
371  *      want_state = what I want the state to go to
372  *      want_resp = how many requests I have sent
373  * All state defaults are negative, and resp defaults to 0.
374  *
375  * When initiating a request to change state to new_state:
376  *
377  * if ((want_resp == 0 && new_state == my_state) || want_state == new_state) {
378  *      do nothing;
379  * } else {
380  *      want_state = new_state;
381  *      send new_state;
382  *      want_resp++;
383  * }
384  *
385  * When receiving new_state:
386  *
387  * if (want_resp) {
388  *      want_resp--;
389  *      if (want_resp && (new_state == my_state))
390  *              want_resp--;
391  * }
392  * if ((want_resp == 0) && (new_state != want_state)) {
393  *      if (ok_to_switch_to new_state)
394  *              want_state = new_state;
395  *      else
396  *              want_resp++;
397  *      send want_state;
398  * }
399  * my_state = new_state;
400  *
401  * Note that new_state is implied in these functions by the function itself.
402  * will and do imply positive new_state, wont and dont imply negative.
403  *
404  * Finally, there is one catch.  If we send a negative response to a
405  * positive request, my_state will be the positive while want_state will
406  * remain negative.  my_state will revert to negative when the negative
407  * acknowlegment arrives from the peer.  Thus, my_state generally tells
408  * us not only the last negotiated state, but also tells us what the peer
409  * wants to be doing as well.  It is important to understand this difference
410  * as we may wish to be processing data streams based on our desired state
411  * (want_state) or based on what the peer thinks the state is (my_state).
412  *
413  * This all works fine because if the peer sends a positive request, the data
414  * that we receive prior to negative acknowlegment will probably be affected
415  * by the positive state, and we can process it as such (if we can; if we
416  * can't then it really doesn't matter).  If it is that important, then the
417  * peer probably should be buffering until this option state negotiation
418  * is complete.
419  *
420  */
421 void
422 send_do(int option, int init)
423 {
424         if (init) {
425                 if ((do_dont_resp[option] == 0 && his_state_is_will(option)) ||
426                     his_want_state_is_will(option))
427                         return;
428                 /*
429                  * Special case for TELOPT_TM:  We send a DO, but pretend
430                  * that we sent a DONT, so that we can send more DOs if
431                  * we want to.
432                  */
433                 if (option == TELOPT_TM)
434                         set_his_want_state_wont(option);
435                 else
436                         set_his_want_state_will(option);
437                 do_dont_resp[option]++;
438         }
439         output_data((const char *)doopt, option);
440
441         DIAG(TD_OPTIONS, printoption("td: send do", option));
442 }
443
444 void
445 willoption(int option)
446 {
447         int changeok = 0;
448         void (*func)(void) = NULL;
449
450         /*
451          * process input from peer.
452          */
453
454         DIAG(TD_OPTIONS, printoption("td: recv will", option));
455
456         if (do_dont_resp[option]) {
457                 do_dont_resp[option]--;
458                 if (do_dont_resp[option] && his_state_is_will(option))
459                         do_dont_resp[option]--;
460         }
461         if (do_dont_resp[option] == 0) {
462             if (his_want_state_is_wont(option)) {
463                 switch (option) {
464
465                 case TELOPT_BINARY:
466                         init_termbuf();
467                         tty_binaryin(1);
468                         set_termbuf();
469                         changeok++;
470                         break;
471
472                 case TELOPT_ECHO:
473                         /*
474                          * See comments below for more info.
475                          */
476                         not42 = 0;      /* looks like a 4.2 system */
477                         break;
478
479                 case TELOPT_TM:
480 #if     defined(LINEMODE) && defined(KLUDGELINEMODE)
481                         /*
482                          * This telnetd implementation does not really
483                          * support timing marks, it just uses them to
484                          * support the kludge linemode stuff.  If we
485                          * receive a will or wont TM in response to our
486                          * do TM request that may have been sent to
487                          * determine kludge linemode support, process
488                          * it, otherwise TM should get a negative
489                          * response back.
490                          */
491                         /*
492                          * Handle the linemode kludge stuff.
493                          * If we are not currently supporting any
494                          * linemode at all, then we assume that this
495                          * is the client telling us to use kludge
496                          * linemode in response to our query.  Set the
497                          * linemode type that is to be supported, note
498                          * that the client wishes to use linemode, and
499                          * eat the will TM as though it never arrived.
500                          */
501                         if (lmodetype < KLUDGE_LINEMODE) {
502                                 lmodetype = KLUDGE_LINEMODE;
503                                 clientstat(TELOPT_LINEMODE, WILL, 0);
504                                 send_wont(TELOPT_SGA, 1);
505                         } else if (lmodetype == NO_AUTOKLUDGE) {
506                                 lmodetype = KLUDGE_OK;
507                         }
508 #endif  /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
509                         /*
510                          * We never respond to a WILL TM, and
511                          * we leave the state WONT.
512                          */
513                         return;
514
515                 case TELOPT_LFLOW:
516                         /*
517                          * If we are going to support flow control
518                          * option, then don't worry peer that we can't
519                          * change the flow control characters.
520                          */
521                         slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS;
522                         slctab[SLC_XON].defset.flag |= SLC_DEFAULT;
523                         slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS;
524                         slctab[SLC_XOFF].defset.flag |= SLC_DEFAULT;
525                         /* FALLTHROUGH */
526                 case TELOPT_TTYPE:
527                 case TELOPT_SGA:
528                 case TELOPT_NAWS:
529                 case TELOPT_TSPEED:
530                 case TELOPT_XDISPLOC:
531                 case TELOPT_NEW_ENVIRON:
532                 case TELOPT_OLD_ENVIRON:
533                         changeok++;
534                         break;
535
536 #ifdef  LINEMODE
537                 case TELOPT_LINEMODE:
538 # ifdef KLUDGELINEMODE
539                         /*
540                          * Note client's desire to use linemode.
541                          */
542                         lmodetype = REAL_LINEMODE;
543 # endif /* KLUDGELINEMODE */
544                         func = doclientstat;
545                         changeok++;
546                         break;
547 #endif  /* LINEMODE */
548
549 #ifdef  AUTHENTICATION
550                 case TELOPT_AUTHENTICATION:
551                         func = auth_request;
552                         changeok++;
553                         break;
554 #endif
555
556 #ifdef  ENCRYPTION
557                 case TELOPT_ENCRYPT:
558                         func = encrypt_send_support;
559                         changeok++;
560                         break;
561 #endif  /* ENCRYPTION */
562
563                 default:
564                         break;
565                 }
566                 if (changeok) {
567                         set_his_want_state_will(option);
568                         send_do(option, 0);
569                 } else {
570                         do_dont_resp[option]++;
571                         send_dont(option, 0);
572                 }
573             } else {
574                 /*
575                  * Option processing that should happen when
576                  * we receive conformation of a change in
577                  * state that we had requested.
578                  */
579                 switch (option) {
580                 case TELOPT_ECHO:
581                         not42 = 0;      /* looks like a 4.2 system */
582                         /*
583                          * Egads, he responded "WILL ECHO".  Turn
584                          * it off right now!
585                          */
586                         send_dont(option, 1);
587                         /*
588                          * "WILL ECHO".  Kludge upon kludge!
589                          * A 4.2 client is now echoing user input at
590                          * the tty.  This is probably undesireable and
591                          * it should be stopped.  The client will
592                          * respond WONT TM to the DO TM that we send to
593                          * check for kludge linemode.  When the WONT TM
594                          * arrives, linemode will be turned off and a
595                          * change propogated to the pty.  This change
596                          * will cause us to process the new pty state
597                          * in localstat(), which will notice that
598                          * linemode is off and send a WILL ECHO
599                          * so that we are properly in character mode and
600                          * all is well.
601                          */
602                         break;
603 #ifdef  LINEMODE
604                 case TELOPT_LINEMODE:
605 # ifdef KLUDGELINEMODE
606                         /*
607                          * Note client's desire to use linemode.
608                          */
609                         lmodetype = REAL_LINEMODE;
610 # endif /* KLUDGELINEMODE */
611                         func = doclientstat;
612                         break;
613 #endif  /* LINEMODE */
614
615 #ifdef  AUTHENTICATION
616                 case TELOPT_AUTHENTICATION:
617                         func = auth_request;
618                         break;
619 #endif
620
621 #ifdef  ENCRYPTION
622                 case TELOPT_ENCRYPT:
623                         func = encrypt_send_support;
624                         break;
625 #endif  /* ENCRYPTION */
626                 case TELOPT_LFLOW:
627                         func = flowstat;
628                         break;
629                 }
630             }
631         }
632         set_his_state_will(option);
633         if (func)
634                 (*func)();
635 }  /* end of willoption */
636
637 void
638 send_dont(int option, int init)
639 {
640         if (init) {
641                 if ((do_dont_resp[option] == 0 && his_state_is_wont(option)) ||
642                     his_want_state_is_wont(option))
643                         return;
644                 set_his_want_state_wont(option);
645                 do_dont_resp[option]++;
646         }
647         output_data((const char *)dont, option);
648
649         DIAG(TD_OPTIONS, printoption("td: send dont", option));
650 }
651
652 void
653 wontoption(int option)
654 {
655         /*
656          * Process client input.
657          */
658
659         DIAG(TD_OPTIONS, printoption("td: recv wont", option));
660
661         if (do_dont_resp[option]) {
662                 do_dont_resp[option]--;
663                 if (do_dont_resp[option] && his_state_is_wont(option))
664                         do_dont_resp[option]--;
665         }
666         if (do_dont_resp[option] == 0) {
667             if (his_want_state_is_will(option)) {
668                 /* it is always ok to change to negative state */
669                 switch (option) {
670                 case TELOPT_ECHO:
671                         not42 = 1; /* doesn't seem to be a 4.2 system */
672                         break;
673
674                 case TELOPT_BINARY:
675                         init_termbuf();
676                         tty_binaryin(0);
677                         set_termbuf();
678                         break;
679
680 #ifdef  LINEMODE
681                 case TELOPT_LINEMODE:
682 # ifdef KLUDGELINEMODE
683                         /*
684                          * If real linemode is supported, then client is
685                          * asking to turn linemode off.
686                          */
687                         if (lmodetype != REAL_LINEMODE)
688                                 break;
689                         lmodetype = KLUDGE_LINEMODE;
690 # endif /* KLUDGELINEMODE */
691                         clientstat(TELOPT_LINEMODE, WONT, 0);
692                         break;
693 #endif  /* LINEMODE */
694
695                 case TELOPT_TM:
696                         /*
697                          * If we get a WONT TM, and had sent a DO TM,
698                          * don't respond with a DONT TM, just leave it
699                          * as is.  Short circut the state machine to
700                          * achive this.
701                          */
702                         set_his_want_state_wont(TELOPT_TM);
703                         return;
704
705                 case TELOPT_LFLOW:
706                         /*
707                          * If we are not going to support flow control
708                          * option, then let peer know that we can't
709                          * change the flow control characters.
710                          */
711                         slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS;
712                         slctab[SLC_XON].defset.flag |= SLC_CANTCHANGE;
713                         slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS;
714                         slctab[SLC_XOFF].defset.flag |= SLC_CANTCHANGE;
715                         break;
716
717 #ifdef  AUTHENTICATION
718                 case TELOPT_AUTHENTICATION:
719                         auth_finished(0, AUTH_REJECT);
720                         break;
721 #endif
722
723                 /*
724                  * For options that we might spin waiting for
725                  * sub-negotiation, if the client turns off the
726                  * option rather than responding to the request,
727                  * we have to treat it here as if we got a response
728                  * to the sub-negotiation, (by updating the timers)
729                  * so that we'll break out of the loop.
730                  */
731                 case TELOPT_TTYPE:
732                         settimer(ttypesubopt);
733                         break;
734
735                 case TELOPT_TSPEED:
736                         settimer(tspeedsubopt);
737                         break;
738
739                 case TELOPT_XDISPLOC:
740                         settimer(xdisplocsubopt);
741                         break;
742
743                 case TELOPT_OLD_ENVIRON:
744                         settimer(oenvironsubopt);
745                         break;
746
747                 case TELOPT_NEW_ENVIRON:
748                         settimer(environsubopt);
749                         break;
750
751                 default:
752                         break;
753                 }
754                 set_his_want_state_wont(option);
755                 if (his_state_is_will(option))
756                         send_dont(option, 0);
757             } else {
758                 switch (option) {
759                 case TELOPT_TM:
760 #if     defined(LINEMODE) && defined(KLUDGELINEMODE)
761                         if (lmodetype < NO_AUTOKLUDGE) {
762                                 lmodetype = NO_LINEMODE;
763                                 clientstat(TELOPT_LINEMODE, WONT, 0);
764                                 send_will(TELOPT_SGA, 1);
765                                 send_will(TELOPT_ECHO, 1);
766                         }
767 #endif  /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
768                         break;
769
770 #ifdef AUTHENTICATION
771                 case TELOPT_AUTHENTICATION:
772                         auth_finished(0, AUTH_REJECT);
773                         break;
774 #endif
775                 default:
776                         break;
777                 }
778             }
779         }
780         set_his_state_wont(option);
781
782 }  /* end of wontoption */
783
784 void
785 send_will(int option, int init)
786 {
787         if (init) {
788                 if ((will_wont_resp[option] == 0 && my_state_is_will(option))||
789                     my_want_state_is_will(option))
790                         return;
791                 set_my_want_state_will(option);
792                 will_wont_resp[option]++;
793         }
794         output_data((const char *)will, option);
795
796         DIAG(TD_OPTIONS, printoption("td: send will", option));
797 }
798
799 #if     !defined(LINEMODE) || !defined(KLUDGELINEMODE)
800 /*
801  * When we get a DONT SGA, we will try once to turn it
802  * back on.  If the other side responds DONT SGA, we
803  * leave it at that.  This is so that when we talk to
804  * clients that understand KLUDGELINEMODE but not LINEMODE,
805  * we'll keep them in char-at-a-time mode.
806  */
807 int turn_on_sga = 0;
808 #endif
809
810 void
811 dooption(int option)
812 {
813         int changeok = 0;
814
815         /*
816          * Process client input.
817          */
818
819         DIAG(TD_OPTIONS, printoption("td: recv do", option));
820
821         if (will_wont_resp[option]) {
822                 will_wont_resp[option]--;
823                 if (will_wont_resp[option] && my_state_is_will(option))
824                         will_wont_resp[option]--;
825         }
826         if ((will_wont_resp[option] == 0) && (my_want_state_is_wont(option))) {
827                 switch (option) {
828                 case TELOPT_ECHO:
829 #ifdef  LINEMODE
830 # ifdef KLUDGELINEMODE
831                         if (lmodetype == NO_LINEMODE)
832 # else
833                         if (his_state_is_wont(TELOPT_LINEMODE))
834 # endif
835 #endif
836                         {
837                                 init_termbuf();
838                                 tty_setecho(1);
839                                 set_termbuf();
840                         }
841                         changeok++;
842                         break;
843
844                 case TELOPT_BINARY:
845                         init_termbuf();
846                         tty_binaryout(1);
847                         set_termbuf();
848                         changeok++;
849                         break;
850
851                 case TELOPT_SGA:
852 #if     defined(LINEMODE) && defined(KLUDGELINEMODE)
853                         /*
854                          * If kludge linemode is in use, then we must
855                          * process an incoming do SGA for linemode
856                          * purposes.
857                          */
858                         if (lmodetype == KLUDGE_LINEMODE) {
859                                 /*
860                                  * Receipt of "do SGA" in kludge
861                                  * linemode is the peer asking us to
862                                  * turn off linemode.  Make note of
863                                  * the request.
864                                  */
865                                 clientstat(TELOPT_LINEMODE, WONT, 0);
866                                 /*
867                                  * If linemode did not get turned off
868                                  * then don't tell peer that we did.
869                                  * Breaking here forces a wont SGA to
870                                  * be returned.
871                                  */
872                                 if (linemode)
873                                         break;
874                         }
875 #else
876                         turn_on_sga = 0;
877 #endif  /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
878                         changeok++;
879                         break;
880
881                 case TELOPT_STATUS:
882                         changeok++;
883                         break;
884
885                 case TELOPT_TM:
886                         /*
887                          * Special case for TM.  We send a WILL, but
888                          * pretend we sent a WONT.
889                          */
890                         send_will(option, 0);
891                         set_my_want_state_wont(option);
892                         set_my_state_wont(option);
893                         return;
894
895                 case TELOPT_LOGOUT:
896                         /*
897                          * When we get a LOGOUT option, respond
898                          * with a WILL LOGOUT, make sure that
899                          * it gets written out to the network,
900                          * and then just go away...
901                          */
902                         set_my_want_state_will(TELOPT_LOGOUT);
903                         send_will(TELOPT_LOGOUT, 0);
904                         set_my_state_will(TELOPT_LOGOUT);
905                         (void)netflush();
906                         cleanup(0);
907                         /* NOT REACHED */
908                         break;
909
910 #ifdef  ENCRYPTION
911                 case TELOPT_ENCRYPT:
912                         changeok++;
913                         break;
914 #endif  /* ENCRYPTION */
915                 case TELOPT_LINEMODE:
916                 case TELOPT_TTYPE:
917                 case TELOPT_NAWS:
918                 case TELOPT_TSPEED:
919                 case TELOPT_LFLOW:
920                 case TELOPT_XDISPLOC:
921 #ifdef  TELOPT_ENVIRON
922                 case TELOPT_NEW_ENVIRON:
923 #endif
924                 case TELOPT_OLD_ENVIRON:
925                 default:
926                         break;
927                 }
928                 if (changeok) {
929                         set_my_want_state_will(option);
930                         send_will(option, 0);
931                 } else {
932                         will_wont_resp[option]++;
933                         send_wont(option, 0);
934                 }
935         }
936         set_my_state_will(option);
937
938 }  /* end of dooption */
939
940 void
941 send_wont(int option, int init)
942 {
943         if (init) {
944                 if ((will_wont_resp[option] == 0 && my_state_is_wont(option)) ||
945                     my_want_state_is_wont(option))
946                         return;
947                 set_my_want_state_wont(option);
948                 will_wont_resp[option]++;
949         }
950         output_data((const char *)wont, option);
951
952         DIAG(TD_OPTIONS, printoption("td: send wont", option));
953 }
954
955 void
956 dontoption(int option)
957 {
958         /*
959          * Process client input.
960          */
961
962
963         DIAG(TD_OPTIONS, printoption("td: recv dont", option));
964
965         if (will_wont_resp[option]) {
966                 will_wont_resp[option]--;
967                 if (will_wont_resp[option] && my_state_is_wont(option))
968                         will_wont_resp[option]--;
969         }
970         if ((will_wont_resp[option] == 0) && (my_want_state_is_will(option))) {
971                 switch (option) {
972                 case TELOPT_BINARY:
973                         init_termbuf();
974                         tty_binaryout(0);
975                         set_termbuf();
976                         break;
977
978                 case TELOPT_ECHO:       /* we should stop echoing */
979 #ifdef  LINEMODE
980 # ifdef KLUDGELINEMODE
981                         if ((lmodetype != REAL_LINEMODE) &&
982                             (lmodetype != KLUDGE_LINEMODE))
983 # else
984                         if (his_state_is_wont(TELOPT_LINEMODE))
985 # endif
986 #endif
987                         {
988                                 init_termbuf();
989                                 tty_setecho(0);
990                                 set_termbuf();
991                         }
992                         break;
993
994                 case TELOPT_SGA:
995 #if     defined(LINEMODE) && defined(KLUDGELINEMODE)
996                         /*
997                          * If kludge linemode is in use, then we
998                          * must process an incoming do SGA for
999                          * linemode purposes.
1000                          */
1001                         if ((lmodetype == KLUDGE_LINEMODE) ||
1002                             (lmodetype == KLUDGE_OK)) {
1003                                 /*
1004                                  * The client is asking us to turn
1005                                  * linemode on.
1006                                  */
1007                                 lmodetype = KLUDGE_LINEMODE;
1008                                 clientstat(TELOPT_LINEMODE, WILL, 0);
1009                                 /*
1010                                  * If we did not turn line mode on,
1011                                  * then what do we say?  Will SGA?
1012                                  * This violates design of telnet.
1013                                  * Gross.  Very Gross.
1014                                  */
1015                         }
1016                         break;
1017 #else
1018                         set_my_want_state_wont(option);
1019                         if (my_state_is_will(option))
1020                                 send_wont(option, 0);
1021                         set_my_state_wont(option);
1022                         if (turn_on_sga ^= 1)
1023                                 send_will(option, 1);
1024                         return;
1025 #endif  /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
1026
1027                 default:
1028                         break;
1029                 }
1030
1031                 set_my_want_state_wont(option);
1032                 if (my_state_is_will(option))
1033                         send_wont(option, 0);
1034         }
1035         set_my_state_wont(option);
1036
1037 }  /* end of dontoption */
1038
1039 #ifdef  ENV_HACK
1040 int env_ovar = -1;
1041 int env_ovalue = -1;
1042 #else   /* ENV_HACK */
1043 # define env_ovar OLD_ENV_VAR
1044 # define env_ovalue OLD_ENV_VALUE
1045 #endif  /* ENV_HACK */
1046
1047 /* envvarok(char*) */
1048 /* check that variable is safe to pass to login or shell */
1049 static int
1050 envvarok(char *varp)
1051 {
1052
1053         if (strcmp(varp, "TERMCAP") &&  /* to prevent a security hole */
1054             strcmp(varp, "TERMINFO") && /* with tgetent */
1055             strcmp(varp, "TERMPATH") &&
1056             strcmp(varp, "HOME") &&     /* to prevent the tegetent bug  */
1057             strncmp(varp, "LD_", strlen("LD_")) &&      /* most systems */
1058             strncmp(varp, "_RLD_", strlen("_RLD_")) &&  /* IRIX */
1059             strcmp(varp, "LIBPATH") &&                  /* AIX */
1060             strcmp(varp, "ENV") &&
1061             strcmp(varp, "BASH_ENV") &&
1062             strcmp(varp, "IFS") &&
1063             strncmp(varp, "KRB5", strlen("KRB5")) &&    /* Krb5 */
1064             /*
1065              * The above case is a catch-all for now.  Here are some of
1066              * the specific ones we must avoid passing, at least until
1067              * we can prove it can be done safely.  Keep this list
1068              * around un case someone wants to remove the catch-all.
1069              */
1070             strcmp(varp, "KRB5_CONFIG") &&              /* Krb5 */
1071             strcmp(varp, "KRB5CCNAME") &&               /* Krb5 */
1072             strcmp(varp, "KRB5_KTNAME") &&              /* Krb5 */
1073             strcmp(varp, "KRBTKFILE") &&                /* Krb4 */
1074             strcmp(varp, "KRB_CONF") &&                 /* CNS 4 */
1075             strcmp(varp, "KRB_REALMS") &&               /* CNS 4 */
1076             strcmp(varp, "RESOLV_HOST_CONF"))           /* Linux */
1077                 return (1);
1078         else {
1079                 syslog(LOG_INFO, "Rejected the attempt to modify the "
1080                     "environment variable \"%s\"", varp);
1081                 return (0);
1082         }
1083 }
1084
1085 /*
1086  * suboption()
1087  *
1088  *      Look at the sub-option buffer, and try to be helpful to the other
1089  * side.
1090  *
1091  *      Currently we recognize:
1092  *
1093  *      Terminal type is
1094  *      Linemode
1095  *      Window size
1096  *      Terminal speed
1097  */
1098 void
1099 suboption(void)
1100 {
1101     int subchar;
1102
1103     DIAG(TD_OPTIONS, {netflush(); printsub('<', subpointer, SB_LEN()+2);});
1104
1105     subchar = SB_GET();
1106     switch (subchar) {
1107     case TELOPT_TSPEED: {
1108         int xspeed, rspeed;
1109
1110         if (his_state_is_wont(TELOPT_TSPEED))   /* Ignore if option disabled */
1111                 break;
1112
1113         settimer(tspeedsubopt);
1114
1115         if (SB_EOF() || SB_GET() != TELQUAL_IS)
1116                 return;
1117
1118         xspeed = atoi((char *)subpointer);
1119
1120         while (SB_GET() != ',' && !SB_EOF());
1121         if (SB_EOF())
1122                 return;
1123
1124         rspeed = atoi((char *)subpointer);
1125         clientstat(TELOPT_TSPEED, xspeed, rspeed);
1126
1127         break;
1128
1129     }  /* end of case TELOPT_TSPEED */
1130
1131     case TELOPT_TTYPE: {                /* Yaaaay! */
1132         static char terminalname[TERMINAL_TYPE_SIZE];
1133
1134         if (his_state_is_wont(TELOPT_TTYPE))    /* Ignore if option disabled */
1135                 break;
1136         settimer(ttypesubopt);
1137
1138         if (SB_EOF() || SB_GET() != TELQUAL_IS) {
1139             return;             /* ??? XXX but, this is the most robust */
1140         }
1141
1142         terminaltype = terminalname;
1143
1144         while ((terminaltype < (terminalname + sizeof terminalname-1)) &&
1145                                                                     !SB_EOF()) {
1146             int c;
1147
1148             c = SB_GET();
1149             if (isupper(c)) {
1150                 c = tolower(c);
1151             }
1152             *terminaltype++ = c;    /* accumulate name */
1153         }
1154         *terminaltype = 0;
1155         terminaltype = terminalname;
1156         break;
1157     }  /* end of case TELOPT_TTYPE */
1158
1159     case TELOPT_NAWS: {
1160         int xwinsize, ywinsize;
1161
1162         if (his_state_is_wont(TELOPT_NAWS))     /* Ignore if option disabled */
1163                 break;
1164
1165         if (SB_EOF())
1166                 return;
1167         xwinsize = SB_GET() << 8;
1168         if (SB_EOF())
1169                 return;
1170         xwinsize |= SB_GET();
1171         if (SB_EOF())
1172                 return;
1173         ywinsize = SB_GET() << 8;
1174         if (SB_EOF())
1175                 return;
1176         ywinsize |= SB_GET();
1177         clientstat(TELOPT_NAWS, xwinsize, ywinsize);
1178
1179         break;
1180
1181     }  /* end of case TELOPT_NAWS */
1182
1183 #ifdef  LINEMODE
1184     case TELOPT_LINEMODE: {
1185         int request;
1186
1187         if (his_state_is_wont(TELOPT_LINEMODE)) /* Ignore if option disabled */
1188                 break;
1189         /*
1190          * Process linemode suboptions.
1191          */
1192         if (SB_EOF())
1193             break;              /* garbage was sent */
1194         request = SB_GET();     /* get will/wont */
1195
1196         if (SB_EOF())
1197             break;              /* another garbage check */
1198
1199         if (request == LM_SLC) {  /* SLC is not preceeded by WILL or WONT */
1200                 /*
1201                  * Process suboption buffer of slc's
1202                  */
1203                 start_slc(1);
1204                 do_opt_slc(subpointer, subend - subpointer);
1205                 (void) end_slc(0);
1206                 break;
1207         } else if (request == LM_MODE) {
1208                 if (SB_EOF())
1209                     return;
1210                 useeditmode = SB_GET();  /* get mode flag */
1211                 clientstat(LM_MODE, 0, 0);
1212                 break;
1213         }
1214
1215         if (SB_EOF())
1216             break;
1217         switch (SB_GET()) {  /* what suboption? */
1218         case LM_FORWARDMASK:
1219                 /*
1220                  * According to spec, only server can send request for
1221                  * forwardmask, and client can only return a positive response.
1222                  * So don't worry about it.
1223                  */
1224
1225         default:
1226                 break;
1227         }
1228         break;
1229     }  /* end of case TELOPT_LINEMODE */
1230 #endif
1231     case TELOPT_STATUS: {
1232         int mode;
1233
1234         if (SB_EOF())
1235             break;
1236         mode = SB_GET();
1237         switch (mode) {
1238         case TELQUAL_SEND:
1239             if (my_state_is_will(TELOPT_STATUS))
1240                 send_status();
1241             break;
1242
1243         case TELQUAL_IS:
1244             break;
1245
1246         default:
1247             break;
1248         }
1249         break;
1250     }  /* end of case TELOPT_STATUS */
1251
1252     case TELOPT_XDISPLOC: {
1253         if (SB_EOF() || SB_GET() != TELQUAL_IS)
1254                 return;
1255         settimer(xdisplocsubopt);
1256         subpointer[SB_LEN()] = '\0';
1257         if (setenv("DISPLAY", (char *)subpointer, 1) == -1)
1258                 syslog(LOG_ERR, "setenv: cannot set DISPLAY=%s: %m", (char *)subpointer);
1259         break;
1260     }  /* end of case TELOPT_XDISPLOC */
1261
1262 #ifdef  TELOPT_NEW_ENVIRON
1263     case TELOPT_NEW_ENVIRON:
1264 #endif
1265     case TELOPT_OLD_ENVIRON: {
1266         int c;
1267         char *cp, *varp, *valp;
1268
1269         if (SB_EOF())
1270                 return;
1271         c = SB_GET();
1272         if (c == TELQUAL_IS) {
1273                 if (subchar == TELOPT_OLD_ENVIRON)
1274                         settimer(oenvironsubopt);
1275                 else
1276                         settimer(environsubopt);
1277         } else if (c != TELQUAL_INFO) {
1278                 return;
1279         }
1280
1281 #ifdef  TELOPT_NEW_ENVIRON
1282         if (subchar == TELOPT_NEW_ENVIRON) {
1283             while (!SB_EOF()) {
1284                 c = SB_GET();
1285                 if ((c == NEW_ENV_VAR) || (c == ENV_USERVAR))
1286                         break;
1287             }
1288         } else
1289 #endif
1290         {
1291 #ifdef  ENV_HACK
1292             /*
1293              * We only want to do this if we haven't already decided
1294              * whether or not the other side has its VALUE and VAR
1295              * reversed.
1296              */
1297             if (env_ovar < 0) {
1298                 int last = -1;          /* invalid value */
1299                 int empty = 0;
1300                 int got_var = 0, got_value = 0, got_uservar = 0;
1301
1302                 /*
1303                  * The other side might have its VALUE and VAR values
1304                  * reversed.  To be interoperable, we need to determine
1305                  * which way it is.  If the first recognized character
1306                  * is a VAR or VALUE, then that will tell us what
1307                  * type of client it is.  If the fist recognized
1308                  * character is a USERVAR, then we continue scanning
1309                  * the suboption looking for two consecutive
1310                  * VAR or VALUE fields.  We should not get two
1311                  * consecutive VALUE fields, so finding two
1312                  * consecutive VALUE or VAR fields will tell us
1313                  * what the client is.
1314                  */
1315                 SB_SAVE();
1316                 while (!SB_EOF()) {
1317                         c = SB_GET();
1318                         switch(c) {
1319                         case OLD_ENV_VAR:
1320                                 if (last < 0 || last == OLD_ENV_VAR
1321                                     || (empty && (last == OLD_ENV_VALUE)))
1322                                         goto env_ovar_ok;
1323                                 got_var++;
1324                                 last = OLD_ENV_VAR;
1325                                 break;
1326                         case OLD_ENV_VALUE:
1327                                 if (last < 0 || last == OLD_ENV_VALUE
1328                                     || (empty && (last == OLD_ENV_VAR)))
1329                                         goto env_ovar_wrong;
1330                                 got_value++;
1331                                 last = OLD_ENV_VALUE;
1332                                 break;
1333                         case ENV_USERVAR:
1334                                 /* count strings of USERVAR as one */
1335                                 if (last != ENV_USERVAR)
1336                                         got_uservar++;
1337                                 if (empty) {
1338                                         if (last == OLD_ENV_VALUE)
1339                                                 goto env_ovar_ok;
1340                                         if (last == OLD_ENV_VAR)
1341                                                 goto env_ovar_wrong;
1342                                 }
1343                                 last = ENV_USERVAR;
1344                                 break;
1345                         case ENV_ESC:
1346                                 if (!SB_EOF())
1347                                         c = SB_GET();
1348                                 /* FALL THROUGH */
1349                         default:
1350                                 empty = 0;
1351                                 continue;
1352                         }
1353                         empty = 1;
1354                 }
1355                 if (empty) {
1356                         if (last == OLD_ENV_VALUE)
1357                                 goto env_ovar_ok;
1358                         if (last == OLD_ENV_VAR)
1359                                 goto env_ovar_wrong;
1360                 }
1361                 /*
1362                  * Ok, the first thing was a USERVAR, and there
1363                  * are not two consecutive VAR or VALUE commands,
1364                  * and none of the VAR or VALUE commands are empty.
1365                  * If the client has sent us a well-formed option,
1366                  * then the number of VALUEs received should always
1367                  * be less than or equal to the number of VARs and
1368                  * USERVARs received.
1369                  *
1370                  * If we got exactly as many VALUEs as VARs and
1371                  * USERVARs, the client has the same definitions.
1372                  *
1373                  * If we got exactly as many VARs as VALUEs and
1374                  * USERVARS, the client has reversed definitions.
1375                  */
1376                 if (got_uservar + got_var == got_value) {
1377             env_ovar_ok:
1378                         env_ovar = OLD_ENV_VAR;
1379                         env_ovalue = OLD_ENV_VALUE;
1380                 } else if (got_uservar + got_value == got_var) {
1381             env_ovar_wrong:
1382                         env_ovar = OLD_ENV_VALUE;
1383                         env_ovalue = OLD_ENV_VAR;
1384                         DIAG(TD_OPTIONS,
1385                             output_data("ENVIRON VALUE and VAR are reversed!\r\n"));
1386
1387                 }
1388             }
1389             SB_RESTORE();
1390 #endif
1391
1392             while (!SB_EOF()) {
1393                 c = SB_GET();
1394                 if ((c == env_ovar) || (c == ENV_USERVAR))
1395                         break;
1396             }
1397         }
1398
1399         if (SB_EOF())
1400                 return;
1401
1402         cp = varp = (char *)subpointer;
1403         valp = NULL;
1404
1405         while (!SB_EOF()) {
1406                 c = SB_GET();
1407                 if (subchar == TELOPT_OLD_ENVIRON) {
1408                         if (c == env_ovar)
1409                                 c = NEW_ENV_VAR;
1410                         else if (c == env_ovalue)
1411                                 c = NEW_ENV_VALUE;
1412                 }
1413                 switch (c) {
1414
1415                 case NEW_ENV_VALUE:
1416                         *cp = '\0';
1417                         cp = valp = (char *)subpointer;
1418                         break;
1419
1420                 case NEW_ENV_VAR:
1421                 case ENV_USERVAR:
1422                         *cp = '\0';
1423                         if (envvarok(varp)) {
1424                                 if (valp) {
1425                                         if (setenv(varp, valp, 1) == -1)
1426                                                 syslog(LOG_ERR, "setenv: cannot set %s=%s: %m", varp, valp);
1427                                 }
1428                                 else
1429                                         unsetenv(varp);
1430                         }
1431                         cp = varp = (char *)subpointer;
1432                         valp = NULL;
1433                         break;
1434
1435                 case ENV_ESC:
1436                         if (SB_EOF())
1437                                 break;
1438                         c = SB_GET();
1439                         /* FALL THROUGH */
1440                 default:
1441                         *cp++ = c;
1442                         break;
1443                 }
1444         }
1445         *cp = '\0';
1446         if (envvarok(varp)) {
1447                 if (valp) {
1448                         if (setenv(varp, valp, 1) == -1)
1449                                 syslog(LOG_ERR, "setenv: cannot set %s=%s: %m", varp, valp);
1450                 }
1451                 else
1452                         unsetenv(varp);
1453         }
1454         break;
1455     }  /* end of case TELOPT_NEW_ENVIRON */
1456 #ifdef  AUTHENTICATION
1457     case TELOPT_AUTHENTICATION:
1458         if (SB_EOF())
1459                 break;
1460         switch(SB_GET()) {
1461         case TELQUAL_SEND:
1462         case TELQUAL_REPLY:
1463                 /*
1464                  * These are sent by us and cannot be sent by
1465                  * the client.
1466                  */
1467                 break;
1468         case TELQUAL_IS:
1469                 auth_is(subpointer, SB_LEN());
1470                 break;
1471         case TELQUAL_NAME:
1472                 auth_name(subpointer, SB_LEN());
1473                 break;
1474         }
1475         break;
1476 #endif
1477 #ifdef  ENCRYPTION
1478     case TELOPT_ENCRYPT:
1479         if (SB_EOF())
1480                 break;
1481         switch(SB_GET()) {
1482         case ENCRYPT_SUPPORT:
1483                 encrypt_support(subpointer, SB_LEN());
1484                 break;
1485         case ENCRYPT_IS:
1486                 encrypt_is(subpointer, SB_LEN());
1487                 break;
1488         case ENCRYPT_REPLY:
1489                 encrypt_reply(subpointer, SB_LEN());
1490                 break;
1491         case ENCRYPT_START:
1492                 encrypt_start(subpointer, SB_LEN());
1493                 break;
1494         case ENCRYPT_END:
1495                 encrypt_end();
1496                 break;
1497         case ENCRYPT_REQSTART:
1498                 encrypt_request_start(subpointer, SB_LEN());
1499                 break;
1500         case ENCRYPT_REQEND:
1501                 /*
1502                  * We can always send an REQEND so that we cannot
1503                  * get stuck encrypting.  We should only get this
1504                  * if we have been able to get in the correct mode
1505                  * anyhow.
1506                  */
1507                 encrypt_request_end();
1508                 break;
1509         case ENCRYPT_ENC_KEYID:
1510                 encrypt_enc_keyid(subpointer, SB_LEN());
1511                 break;
1512         case ENCRYPT_DEC_KEYID:
1513                 encrypt_dec_keyid(subpointer, SB_LEN());
1514                 break;
1515         default:
1516                 break;
1517         }
1518         break;
1519 #endif  /* ENCRYPTION */
1520
1521     default:
1522         break;
1523     }  /* end of switch */
1524
1525 }  /* end of suboption */
1526
1527 static void
1528 doclientstat(void)
1529 {
1530         clientstat(TELOPT_LINEMODE, WILL, 0);
1531 }
1532
1533 #define ADD(c)   *ncp++ = c
1534 #define ADD_DATA(c) { *ncp++ = c; if (c == SE || c == IAC) *ncp++ = c; }
1535 void
1536 send_status(void)
1537 {
1538         unsigned char statusbuf[256];
1539         unsigned char *ncp;
1540         unsigned char i;
1541
1542         ncp = statusbuf;
1543
1544         netflush();     /* get rid of anything waiting to go out */
1545
1546         ADD(IAC);
1547         ADD(SB);
1548         ADD(TELOPT_STATUS);
1549         ADD(TELQUAL_IS);
1550
1551         /*
1552          * We check the want_state rather than the current state,
1553          * because if we received a DO/WILL for an option that we
1554          * don't support, and the other side didn't send a DONT/WONT
1555          * in response to our WONT/DONT, then the "state" will be
1556          * WILL/DO, and the "want_state" will be WONT/DONT.  We
1557          * need to go by the latter.
1558          */
1559         for (i = 0; i < (unsigned char)NTELOPTS; i++) {
1560                 if (my_want_state_is_will(i)) {
1561                         ADD(WILL);
1562                         ADD_DATA(i);
1563                         if (i == IAC)
1564                                 ADD(IAC);
1565                 }
1566                 if (his_want_state_is_will(i)) {
1567                         ADD(DO);
1568                         ADD_DATA(i);
1569                         if (i == IAC)
1570                                 ADD(IAC);
1571                 }
1572         }
1573
1574         if (his_want_state_is_will(TELOPT_LFLOW)) {
1575                 ADD(SB);
1576                 ADD(TELOPT_LFLOW);
1577                 if (flowmode) {
1578                         ADD(LFLOW_ON);
1579                 } else {
1580                         ADD(LFLOW_OFF);
1581                 }
1582                 ADD(SE);
1583
1584                 if (restartany >= 0) {
1585                         ADD(SB);
1586                         ADD(TELOPT_LFLOW);
1587                         if (restartany) {
1588                                 ADD(LFLOW_RESTART_ANY);
1589                         } else {
1590                                 ADD(LFLOW_RESTART_XON);
1591                         }
1592                         ADD(SE);
1593                 }
1594         }
1595
1596 #ifdef  LINEMODE
1597         if (his_want_state_is_will(TELOPT_LINEMODE)) {
1598                 unsigned char *cp, *cpe;
1599                 int len;
1600
1601                 ADD(SB);
1602                 ADD(TELOPT_LINEMODE);
1603                 ADD(LM_MODE);
1604                 ADD_DATA(editmode);
1605                 ADD(SE);
1606
1607                 ADD(SB);
1608                 ADD(TELOPT_LINEMODE);
1609                 ADD(LM_SLC);
1610                 start_slc(0);
1611                 send_slc();
1612                 len = end_slc(&cp);
1613                 for (cpe = cp + len; cp < cpe; cp++)
1614                         ADD_DATA(*cp);
1615                 ADD(SE);
1616         }
1617 #endif  /* LINEMODE */
1618
1619         ADD(IAC);
1620         ADD(SE);
1621
1622         output_datalen(statusbuf, ncp - statusbuf);
1623         netflush();     /* Send it on its way */
1624
1625         DIAG(TD_OPTIONS,
1626                 {printsub('>', statusbuf, ncp - statusbuf); netflush();});
1627 }
1628
1629 /*
1630  * This function appends data to nfrontp and advances nfrontp.
1631  * Returns the number of characters written altogether (the
1632  * buffer may have been flushed in the process).
1633  */
1634
1635 int
1636 output_data(const char *format, ...)
1637 {
1638         va_list args;
1639         int len;
1640         char *buf;
1641
1642         va_start(args, format);
1643         if ((len = vasprintf(&buf, format, args)) == -1) {
1644                 va_end(args);
1645                 return -1;
1646         }
1647         output_datalen(buf, len);
1648         va_end(args);
1649         free(buf);
1650         return (len);
1651 }
1652
1653 void
1654 output_datalen(const char *buf, int len)
1655 {
1656         int remaining, copied;
1657         
1658         remaining = BUFSIZ - (nfrontp - netobuf);
1659         while (len > 0) {
1660                 /* Free up enough space if the room is too low*/
1661                 if ((len > BUFSIZ ? BUFSIZ : len) > remaining) {
1662                         netflush();
1663                         remaining = BUFSIZ - (nfrontp - netobuf);
1664                 }
1665
1666                 /* Copy out as much as will fit */
1667                 copied = remaining > len ? len : remaining;
1668                 memmove(nfrontp, buf, copied);
1669                 nfrontp += copied;
1670                 len -= copied;
1671                 remaining -= copied;
1672                 buf += copied;
1673         }
1674         return;
1675 }