home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / libexec / telnetd / termstat.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-20  |  16.5 KB  |  632 lines

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