1 /*        $NetBSD: termstat.c,v 1.14 2005/02/06 05:58:21 perry Exp $  */
2 
3 /*
4  * Copyright (c) 1989, 1993
5  *        The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)termstat.c  8.2 (Berkeley) 5/30/95";
36 #else
37 __RCSID("$NetBSD: termstat.c,v 1.14 2005/02/06 05:58:21 perry Exp $");
38 #endif
39 #endif /* not lint */
40 
41 #include "telnetd.h"
42 
43 #ifdef ENCRYPTION
44 #include <libtelnet/encrypt.h>
45 #endif
46 
47 /*
48  * local variables
49  */
50 int def_tspeed = -1, def_rspeed = -1;
51 int def_row = 0, def_col = 0;
52 #ifdef    LINEMODE
53 static int _terminit = 0;
54 #endif    /* LINEMODE */
55 
56 
57 #ifdef    LINEMODE
58 /*
59  * localstat
60  *
61  * This function handles all management of linemode.
62  *
63  * Linemode allows the client to do the local editing of data
64  * and send only complete lines to the server.  Linemode state is
65  * based on the state of the pty driver.  If the pty is set for
66  * external processing, then we can use linemode.  Further, if we
67  * can use real linemode, then we can look at the edit control bits
68  * in the pty to determine what editing the client should do.
69  *
70  * Linemode support uses the following state flags to keep track of
71  * current and desired linemode state.
72  *        alwayslinemode : true if -l was specified on the telnetd
73  *        command line.  It means to have linemode on as much as
74  *        possible.
75  *
76  *        lmodetype: signifies whether the client can
77  *        handle real linemode, or if use of kludgeomatic linemode
78  *        is preferred.  It will be set to one of the following:
79  *                  REAL_LINEMODE : use linemode option
80  *                  NO_KLUDGE : don't initiate kludge linemode.
81  *                  KLUDGE_LINEMODE : use kludge linemode
82  *                  NO_LINEMODE : client is ignorant of linemode
83  *
84  *        linemode, uselinemode : linemode is true if linemode
85  *        is currently on, uselinemode is the state that we wish
86  *        to be in.  If another function wishes to turn linemode
87  *        on or off, it sets or clears uselinemode.
88  *
89  *        editmode, useeditmode : like linemode/uselinemode, but
90  *        these contain the edit mode states (edit and trapsig).
91  *
92  * The state variables correspond to some of the state information
93  * in the pty.
94  *        linemode:
95  *                  In real linemode, this corresponds to whether the pty
96  *                  expects external processing of incoming data.
97  *                  In kludge linemode, this more closely corresponds to the
98  *                  whether normal processing is on or not.  (ICANON in
99  *                  system V, or COOKED mode in BSD.)
100  *                  If the -l option was specified (alwayslinemode), then
101  *                  an attempt is made to force external processing on at
102  *                  all times.
103  *
104  * The following heuristics are applied to determine linemode
105  * handling within the server.
106  *        1) Early on in starting up the server, an attempt is made
107  *           to negotiate the linemode option.  If this succeeds
108  *           then lmodetype is set to REAL_LINEMODE and all linemode
109  *           processing occurs in the context of the linemode option.
110  *        2) If the attempt to negotiate the linemode option failed,
111  *           and the "-k" (don't initiate kludge linemode) isn't set,
112  *           then we try to use kludge linemode.  We test for this
113  *           capability by sending "do Timing Mark".  If a positive
114  *           response comes back, then we assume that the client
115  *           understands kludge linemode (ech!) and the
116  *           lmodetype flag is set to KLUDGE_LINEMODE.
117  *        3) Otherwise, linemode is not supported at all and
118  *           lmodetype remains set to NO_LINEMODE (which happens
119  *           to be 0 for convenience).
120  *        4) At any time a command arrives that implies a higher
121  *           state of linemode support in the client, we move to that
122  *           linemode support.
123  *
124  * A short explanation of kludge linemode is in order here.
125  *        1) The heuristic to determine support for kludge linemode
126  *           is to send a do timing mark.  We assume that a client
127  *           that supports timing marks also supports kludge linemode.
128  *           A risky proposition at best.
129  *        2) Further negotiation of linemode is done by changing the
130  *           the server's state regarding SGA.  If server will SGA,
131  *           then linemode is off, if server won't SGA, then linemode
132  *           is on.
133  */
134 void
localstat(void)135 localstat(void)
136 {
137           int need_will_echo = 0;
138 
139 
140           /*
141            * Check for state of BINARY options.
142            */
143           if (tty_isbinaryin()) {
144                     if (his_want_state_is_wont(TELOPT_BINARY))
145                               send_do(TELOPT_BINARY, 1);
146           } else {
147                     if (his_want_state_is_will(TELOPT_BINARY))
148                               send_dont(TELOPT_BINARY, 1);
149           }
150 
151           if (tty_isbinaryout()) {
152                     if (my_want_state_is_wont(TELOPT_BINARY))
153                               send_will(TELOPT_BINARY, 1);
154           } else {
155                     if (my_want_state_is_will(TELOPT_BINARY))
156                               send_wont(TELOPT_BINARY, 1);
157           }
158 
159           /*
160            * Check for changes to flow control if client supports it.
161            */
162           flowstat();
163 
164           /*
165            * Check linemode on/off state
166            */
167           uselinemode = tty_linemode();
168 
169           /*
170            * If alwayslinemode is on, and pty is changing to turn it off, then
171            * force linemode back on.
172            */
173           if (alwayslinemode && linemode && !uselinemode) {
174                     uselinemode = 1;
175                     tty_setlinemode(uselinemode);
176           }
177 
178 #ifdef    ENCRYPTION
179           /*
180            * If the terminal is not echoing, but editing is enabled,
181            * something like password input is going to happen, so
182            * if we the other side is not currently sending encrypted
183            * data, ask the other side to start encrypting.
184            */
185           if (his_state_is_will(TELOPT_ENCRYPT)) {
186                     static int enc_passwd = 0;
187                     if (uselinemode && !tty_isecho() && tty_isediting()
188                         && (enc_passwd == 0) && !decrypt_input) {
189                               encrypt_send_request_start();
190                               enc_passwd = 1;
191                     } else if (enc_passwd) {
192                               encrypt_send_request_end();
193                               enc_passwd = 0;
194                     }
195           }
196 #endif    /* ENCRYPTION */
197 
198           /*
199            * Do echo mode handling as soon as we know what the
200            * linemode is going to be.
201            * If the pty has echo turned off, then tell the client that
202            * the server will echo.  If echo is on, then the server
203            * will echo if in character mode, but in linemode the
204            * client should do local echoing.  The state machine will
205            * not send anything if it is unnecessary, so don't worry
206            * about that here.
207            *
208            * If we need to send the WILL ECHO (because echo is off),
209            * then delay that until after we have changed the MODE.
210            * This way, when the user is turning off both editing
211            * and echo, the client will get editing turned off first.
212            * This keeps the client from going into encryption mode
213            * and then right back out if it is doing auto-encryption
214            * when passwords are being typed.
215            */
216           if (uselinemode) {
217                     if (tty_isecho())
218                               send_wont(TELOPT_ECHO, 1);
219                     else
220                               need_will_echo = 1;
221 #ifdef    KLUDGELINEMODE
222                     if (lmodetype == KLUDGE_OK)
223                               lmodetype = KLUDGE_LINEMODE;
224 #endif
225           }
226 
227           /*
228            * If linemode is being turned off, send appropriate
229            * command and then we're all done.
230            */
231            if (!uselinemode && linemode) {
232 # ifdef   KLUDGELINEMODE
233                     if (lmodetype == REAL_LINEMODE) {
234 # endif   /* KLUDGELINEMODE */
235                               send_dont(TELOPT_LINEMODE, 1);
236 # ifdef   KLUDGELINEMODE
237                     } else if (lmodetype == KLUDGE_LINEMODE)
238                               send_will(TELOPT_SGA, 1);
239 # endif   /* KLUDGELINEMODE */
240                     send_will(TELOPT_ECHO, 1);
241                     linemode = uselinemode;
242                     goto done;
243           }
244 
245 # ifdef   KLUDGELINEMODE
246           /*
247            * If using real linemode check edit modes for possible later use.
248            * If we are in kludge linemode, do the SGA negotiation.
249            */
250           if (lmodetype == REAL_LINEMODE) {
251 # endif   /* KLUDGELINEMODE */
252                     useeditmode = 0;
253                     if (tty_isediting())
254                               useeditmode |= MODE_EDIT;
255                     if (tty_istrapsig())
256                               useeditmode |= MODE_TRAPSIG;
257                     if (tty_issofttab())
258                               useeditmode |= MODE_SOFT_TAB;
259                     if (tty_islitecho())
260                               useeditmode |= MODE_LIT_ECHO;
261 # ifdef   KLUDGELINEMODE
262           } else if (lmodetype == KLUDGE_LINEMODE) {
263                     if (tty_isediting() && uselinemode)
264                               send_wont(TELOPT_SGA, 1);
265                     else
266                               send_will(TELOPT_SGA, 1);
267           }
268 # endif   /* KLUDGELINEMODE */
269 
270           /*
271            * Negotiate linemode on if pty state has changed to turn it on.
272            * Send appropriate command and send along edit mode, then all done.
273            */
274           if (uselinemode && !linemode) {
275 # ifdef   KLUDGELINEMODE
276                     if (lmodetype == KLUDGE_LINEMODE) {
277                               send_wont(TELOPT_SGA, 1);
278                     } else if (lmodetype == REAL_LINEMODE) {
279 # endif   /* KLUDGELINEMODE */
280                               send_do(TELOPT_LINEMODE, 1);
281                               /* send along edit modes */
282                               (void) output_data("%c%c%c%c%c%c%c", IAC, SB,
283                                         TELOPT_LINEMODE, LM_MODE, useeditmode,
284                                         IAC, SE);
285                               editmode = useeditmode;
286 # ifdef   KLUDGELINEMODE
287                     }
288 # endif   /* KLUDGELINEMODE */
289                     linemode = uselinemode;
290                     goto done;
291           }
292 
293 # ifdef   KLUDGELINEMODE
294           /*
295            * None of what follows is of any value if not using
296            * real linemode.
297            */
298           if (lmodetype < REAL_LINEMODE)
299                     goto done;
300 # endif   /* KLUDGELINEMODE */
301 
302           if (linemode && his_state_is_will(TELOPT_LINEMODE)) {
303                     /*
304                      * If edit mode changed, send edit mode.
305                      */
306                      if (useeditmode != editmode) {
307                               /*
308                                * Send along appropriate edit mode mask.
309                                */
310                               (void) output_data("%c%c%c%c%c%c%c", IAC, SB,
311                                         TELOPT_LINEMODE, LM_MODE, useeditmode,
312                                         IAC, SE);
313                               editmode = useeditmode;
314                     }
315 
316 
317                     /*
318                      * Check for changes to special characters in use.
319                      */
320                     start_slc(0);
321                     check_slc();
322                     (void) end_slc(0);
323           }
324 
325 done:
326           if (need_will_echo)
327                     send_will(TELOPT_ECHO, 1);
328           /*
329            * Some things should be deferred until after the pty state has
330            * been set by the local process.  Do those things that have been
331            * deferred now.  This only happens once.
332            */
333           if (_terminit == 0) {
334                     _terminit = 1;
335                     defer_terminit();
336           }
337 
338           netflush();
339           set_termbuf();
340           return;
341 
342 }  /* end of localstat */
343 #endif    /* LINEMODE */
344 
345 /*
346  * flowstat
347  *
348  * Check for changes to flow control
349  */
350 void
flowstat(void)351 flowstat(void)
352 {
353           if (his_state_is_will(TELOPT_LFLOW)) {
354                     if (tty_flowmode() != flowmode) {
355                               flowmode = tty_flowmode();
356                               (void) output_data("%c%c%c%c%c%c",
357                                                   IAC, SB, TELOPT_LFLOW,
358                                                   flowmode ? LFLOW_ON : LFLOW_OFF,
359                                                   IAC, SE);
360                     }
361                     if (tty_restartany() != restartany) {
362                               restartany = tty_restartany();
363                               (void) output_data("%c%c%c%c%c%c",
364                                                   IAC, SB, TELOPT_LFLOW,
365                                                   restartany ? LFLOW_RESTART_ANY
366                                                                : LFLOW_RESTART_XON,
367                                                   IAC, SE);
368                     }
369           }
370 }
371 
372 /*
373  * clientstat
374  *
375  * Process linemode related requests from the client.
376  * Client can request a change to only one of linemode, editmode or slc's
377  * at a time, and if using kludge linemode, then only linemode may be
378  * affected.
379  */
380 void
clientstat(int code,int parm1,int parm2)381 clientstat(int code, int parm1, int parm2)
382 {
383 
384           /*
385            * Get a copy of terminal characteristics.
386            */
387           init_termbuf();
388 
389           /*
390            * Process request from client. code tells what it is.
391            */
392           switch (code) {
393 #ifdef    LINEMODE
394           case TELOPT_LINEMODE:
395                     /*
396                      * Don't do anything unless client is asking us to change
397                      * modes.
398                      */
399                     uselinemode = (parm1 == WILL);
400                     if (uselinemode != linemode) {
401 # ifdef   KLUDGELINEMODE
402                               /*
403                                * If using kludge linemode, make sure that
404                                * we can do what the client asks.
405                                * We can not turn off linemode if alwayslinemode
406                                * and the ICANON bit is set.
407                                */
408                               if (lmodetype == KLUDGE_LINEMODE) {
409                                         if (alwayslinemode && tty_isediting()) {
410                                                   uselinemode = 1;
411                                         }
412                               }
413 
414                               /*
415                                * Quit now if we can't do it.
416                                */
417                               if (uselinemode == linemode)
418                                         return;
419 
420                               /*
421                                * If using real linemode and linemode is being
422                                * turned on, send along the edit mode mask.
423                                */
424                               if (lmodetype == REAL_LINEMODE && uselinemode)
425 # else    /* KLUDGELINEMODE */
426                               if (uselinemode)
427 # endif   /* KLUDGELINEMODE */
428                               {
429                                         useeditmode = 0;
430                                         if (tty_isediting())
431                                                   useeditmode |= MODE_EDIT;
432                                         if (tty_istrapsig())
433                                                   useeditmode |= MODE_TRAPSIG;
434                                         if (tty_issofttab())
435                                                   useeditmode |= MODE_SOFT_TAB;
436                                         if (tty_islitecho())
437                                                   useeditmode |= MODE_LIT_ECHO;
438                                         (void) output_data("%c%c%c%c%c%c%c", IAC,
439                                                   SB, TELOPT_LINEMODE, LM_MODE,
440                                                                       useeditmode, IAC, SE);
441                                         editmode = useeditmode;
442                               }
443 
444 
445                               tty_setlinemode(uselinemode);
446 
447                               linemode = uselinemode;
448 
449                               if (!linemode)
450                                         send_will(TELOPT_ECHO, 1);
451                     }
452                     break;
453 
454           case LM_MODE:
455               {
456                     int ack, changed;
457 
458                     /*
459                      * Client has sent along a mode mask.  If it agrees with
460                      * what we are currently doing, ignore it; if not, it could
461                      * be viewed as a request to change.  Note that the server
462                      * will change to the modes in an ack if it is different from
463                      * what we currently have, but we will not ack the ack.
464                      */
465                      useeditmode &= MODE_MASK;
466                      ack = (useeditmode & MODE_ACK);
467                      useeditmode &= ~MODE_ACK;
468 
469                      if ((changed = (useeditmode ^ editmode))) {
470                               /*
471                                * This check is for a timing problem.  If the
472                                * state of the tty has changed (due to the user
473                                * application) we need to process that info
474                                * before we write in the state contained in the
475                                * ack!!!  This gets out the new MODE request,
476                                * and when the ack to that command comes back
477                                * we'll set it and be in the right mode.
478                                */
479                               if (ack)
480                                         localstat();
481                               if (changed & MODE_EDIT)
482                                         tty_setedit(useeditmode & MODE_EDIT);
483 
484                               if (changed & MODE_TRAPSIG)
485                                         tty_setsig(useeditmode & MODE_TRAPSIG);
486 
487                               if (changed & MODE_SOFT_TAB)
488                                         tty_setsofttab(useeditmode & MODE_SOFT_TAB);
489 
490                               if (changed & MODE_LIT_ECHO)
491                                         tty_setlitecho(useeditmode & MODE_LIT_ECHO);
492 
493                               set_termbuf();
494 
495                               if (!ack) {
496                                         (void) output_data("%c%c%c%c%c%c%c", IAC,
497                                                   SB, TELOPT_LINEMODE, LM_MODE,
498                                                   useeditmode|MODE_ACK,
499                                                   IAC, SE);
500                               }
501 
502                               editmode = useeditmode;
503                     }
504 
505                     break;
506 
507               }  /* end of case LM_MODE */
508 #endif    /* LINEMODE */
509 
510           case TELOPT_NAWS:
511               {
512                     struct winsize ws;
513 
514                     def_col = parm1;
515                     def_row = parm2;
516 #ifdef    LINEMODE
517                     /*
518                      * Defer changing window size until after terminal is
519                      * initialized.
520                      */
521                     if (terminit() == 0)
522                               return;
523 #endif    /* LINEMODE */
524 
525                     /*
526                      * Change window size as requested by client.
527                      */
528 
529                     ws.ws_col = parm1;
530                     ws.ws_row = parm2;
531                     (void) ioctl(pty, TIOCSWINSZ, (char *)&ws);
532               }
533 
534                     break;
535 
536           case TELOPT_TSPEED:
537               {
538                     def_tspeed = parm1;
539                     def_rspeed = parm2;
540 #ifdef    LINEMODE
541                     /*
542                      * Defer changing the terminal speed.
543                      */
544                     if (terminit() == 0)
545                               return;
546 #endif    /* LINEMODE */
547                     /*
548                      * Change terminal speed as requested by client.
549                      * We set the receive speed first, so that if we can't
550                      * store separate receive and transmit speeds, the transmit
551                      * speed will take precedence.
552                      */
553                     tty_rspeed(parm2);
554                     tty_tspeed(parm1);
555                     set_termbuf();
556 
557                     break;
558 
559               }  /* end of case TELOPT_TSPEED */
560 
561           default:
562                     /* What? */
563                     break;
564           }  /* end of switch */
565 
566 
567           netflush();
568 
569 }  /* end of clientstat */
570 
571 
572 #ifdef    LINEMODE
573 /*
574  * defer_terminit
575  *
576  * Some things should not be done until after the login process has started
577  * and all the pty modes are set to what they are supposed to be.  This
578  * function is called when the pty state has been processed for the first time.
579  * It calls other functions that do things that were deferred in each module.
580  */
581 void
defer_terminit(void)582 defer_terminit(void)
583 {
584 
585           /*
586            * local stuff that got deferred.
587            */
588           if (def_tspeed != -1) {
589                     clientstat(TELOPT_TSPEED, def_tspeed, def_rspeed);
590                     def_tspeed = def_rspeed = 0;
591           }
592 
593           if (def_col || def_row) {
594                     struct winsize ws;
595 
596                     memset((char *)&ws, 0, sizeof(ws));
597                     ws.ws_col = def_col;
598                     ws.ws_row = def_row;
599                     (void) ioctl(pty, TIOCSWINSZ, (char *)&ws);
600           }
601 
602           /*
603            * The only other module that currently defers anything.
604            */
605           deferslc();
606 
607 }  /* end of defer_terminit */
608 
609 /*
610  * terminit
611  *
612  * Returns true if the pty state has been processed yet.
613  */
614 int
terminit(void)615 terminit(void)
616 {
617           return(_terminit);
618 
619 }  /* end of terminit */
620 #endif    /* LINEMODE */
621