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