home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / inetutils-1.2-src.tgz / tar.out / fsf / inetutils / telnetd / telnetd.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  40KB  |  1,653 lines

  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.  
  34. #ifndef lint
  35. static char copyright[] =
  36. "@(#) Copyright (c) 1989, 1993\n\
  37.     The Regents of the University of California.  All rights reserved.\n";
  38. #endif /* not lint */
  39.  
  40. #ifndef lint
  41. static char sccsid[] = "@(#)telnetd.c    8.4 (Berkeley) 5/30/95";
  42. #endif /* not lint */
  43.  
  44. #ifdef HAVE_CONFIG_H
  45. #include <config.h>
  46. #endif
  47.  
  48. #include "telnetd.h"
  49.  
  50. #if    defined(_SC_CRAY_SECURE_SYS) && !defined(SCM_SECURITY)
  51. /*
  52.  * UNICOS 6.0/6.1 do not have SCM_SECURITY defined, so we can
  53.  * use it to tell us to turn off all the socket security code,
  54.  * since that is only used in UNICOS 7.0 and later.
  55.  */
  56. # undef _SC_CRAY_SECURE_SYS
  57. #endif
  58.  
  59. #if    defined(_SC_CRAY_SECURE_SYS)
  60. #include <sys/sysv.h>
  61. #include <sys/secdev.h>
  62. # ifdef SO_SEC_MULTI        /* 8.0 code */
  63. #include <sys/secparm.h>
  64. #include <sys/usrv.h>
  65. # endif /* SO_SEC_MULTI */
  66. int    secflag;
  67. char    tty_dev[16];
  68. struct    secdev dv;
  69. struct    sysv sysv;
  70. # ifdef SO_SEC_MULTI        /* 8.0 code */
  71. struct    socksec ss;
  72. # else /* SO_SEC_MULTI */    /* 7.0 code */
  73. struct    socket_security ss;
  74. # endif /* SO_SEC_MULTI */
  75. #endif    /* _SC_CRAY_SECURE_SYS */
  76.  
  77. #if    defined(AUTHENTICATION)
  78. #include <libtelnet/auth.h>
  79. int    auth_level = 0;
  80. #endif
  81. #if    defined(SecurID)
  82. int    require_SecurID = 0;
  83. #endif
  84.  
  85. #ifdef HAVE_SYS_UTSNAME_H
  86. #include <sys/utsname.h>
  87. #endif
  88.  
  89. extern    int utmp_len;
  90. int    registerd_host_only = 0;
  91.  
  92. #ifdef    STREAMSPTY
  93. # include <stropts.h>
  94. # include <termio.h>
  95. /* make sure we don't get the bsd version */
  96. # include "/usr/include/sys/tty.h"
  97. # include <sys/ptyvar.h>
  98.  
  99. /*
  100.  * Because of the way ptyibuf is used with streams messages, we need
  101.  * ptyibuf+1 to be on a full-word boundary.  The following wierdness
  102.  * is simply to make that happen.
  103.  */
  104. long    ptyibufbuf[BUFSIZ/sizeof(long)+1];
  105. char    *ptyibuf = ((char *)&ptyibufbuf[1])-1;
  106. char    *ptyip = ((char *)&ptyibufbuf[1])-1;
  107. char    ptyibuf2[BUFSIZ];
  108. unsigned char ctlbuf[BUFSIZ];
  109. struct    strbuf strbufc, strbufd;
  110.  
  111. int readstream();
  112.  
  113. #else    /* ! STREAMPTY */
  114.  
  115. /*
  116.  * I/O data buffers,
  117.  * pointers, and counters.
  118.  */
  119. char    ptyibuf[BUFSIZ], *ptyip = ptyibuf;
  120. char    ptyibuf2[BUFSIZ];
  121.  
  122. #endif /* ! STREAMPTY */
  123.  
  124. int    hostinfo = 1;            /* do we print login banner? */
  125.  
  126. #ifdef    CRAY
  127. extern int      newmap; /* nonzero if \n maps to ^M^J */
  128. int    lowpty = 0, highpty;    /* low, high pty numbers */
  129. #endif /* CRAY */
  130.  
  131. int debug = 0;
  132. int keepalive = 1;
  133. char *progname;
  134.  
  135. extern void usage P((void));
  136.  
  137. /*
  138.  * The string to pass to getopt().  We do it this way so
  139.  * that only the actual options that we support will be
  140.  * passed off to getopt().
  141.  */
  142. char valid_opts[] = {
  143.     'd', ':', 'h', 'k', 'n', 'S', ':', 'u', ':', 'U',
  144. #ifdef    AUTHENTICATION
  145.     'a', ':', 'X', ':',
  146. #endif
  147. #ifdef BFTPDAEMON
  148.     'B',
  149. #endif
  150. #ifdef DIAGNOSTICS
  151.     'D', ':',
  152. #endif
  153. #ifdef    ENCRYPTION
  154.     'e', ':',
  155. #endif
  156. #if    defined(CRAY) && defined(NEWINIT)
  157.     'I', ':',
  158. #endif
  159. #ifdef    LINEMODE
  160.     'l',
  161. #endif
  162. #ifdef CRAY
  163.     'r', ':',
  164. #endif
  165. #ifdef    SecurID
  166.     's',
  167. #endif
  168.     '\0'
  169. };
  170.  
  171. main(argc, argv)
  172.     char *argv[];
  173. {
  174.     struct sockaddr_in from;
  175.     int on = 1, fromlen;
  176.     register int ch;
  177.     extern char *optarg;
  178.     extern int optind;
  179. #if    defined(IPPROTO_IP) && defined(IP_TOS)
  180.     int tos = -1;
  181. #endif
  182.  
  183.     pfrontp = pbackp = ptyobuf;
  184.     netip = netibuf;
  185.     nfrontp = nbackp = netobuf;
  186. #ifdef    ENCRYPTION
  187.     nclearto = 0;
  188. #endif    /* ENCRYPTION */
  189.  
  190.     progname = *argv;
  191.  
  192. #ifdef CRAY
  193.     /*
  194.      * Get number of pty's before trying to process options,
  195.      * which may include changing pty range.
  196.      */
  197.     highpty = getnpty();
  198. #endif /* CRAY */
  199.  
  200.     while ((ch = getopt(argc, argv, valid_opts)) != EOF) {
  201.         switch(ch) {
  202.  
  203. #ifdef    AUTHENTICATION
  204.         case 'a':
  205.             /*
  206.              * Check for required authentication level
  207.              */
  208.             if (strcmp(optarg, "debug") == 0) {
  209.                 extern int auth_debug_mode;
  210.                 auth_debug_mode = 1;
  211.             } else if (strcasecmp(optarg, "none") == 0) {
  212.                 auth_level = 0;
  213.             } else if (strcasecmp(optarg, "other") == 0) {
  214.                 auth_level = AUTH_OTHER;
  215.             } else if (strcasecmp(optarg, "user") == 0) {
  216.                 auth_level = AUTH_USER;
  217.             } else if (strcasecmp(optarg, "valid") == 0) {
  218.                 auth_level = AUTH_VALID;
  219.             } else if (strcasecmp(optarg, "off") == 0) {
  220.                 /*
  221.                  * This hack turns off authentication
  222.                  */
  223.                 auth_level = -1;
  224.             } else {
  225.                 fprintf(stderr,
  226.                 "telnetd: unknown authorization level for -a\n");
  227.             }
  228.             break;
  229. #endif    /* AUTHENTICATION */
  230.  
  231. #ifdef BFTPDAEMON
  232.         case 'B':
  233.             bftpd++;
  234.             break;
  235. #endif /* BFTPDAEMON */
  236.  
  237.         case 'd':
  238.             if (strcmp(optarg, "ebug") == 0) {
  239.                 debug++;
  240.                 break;
  241.             }
  242.             usage();
  243.             /* NOTREACHED */
  244.             break;
  245.  
  246. #ifdef DIAGNOSTICS
  247.         case 'D':
  248.             /*
  249.              * Check for desired diagnostics capabilities.
  250.              */
  251.             if (!strcmp(optarg, "report")) {
  252.                 diagnostic |= TD_REPORT|TD_OPTIONS;
  253.             } else if (!strcmp(optarg, "exercise")) {
  254.                 diagnostic |= TD_EXERCISE;
  255.             } else if (!strcmp(optarg, "netdata")) {
  256.                 diagnostic |= TD_NETDATA;
  257.             } else if (!strcmp(optarg, "ptydata")) {
  258.                 diagnostic |= TD_PTYDATA;
  259.             } else if (!strcmp(optarg, "options")) {
  260.                 diagnostic |= TD_OPTIONS;
  261.             } else {
  262.                 usage();
  263.                 /* NOT REACHED */
  264.             }
  265.             break;
  266. #endif /* DIAGNOSTICS */
  267.  
  268. #ifdef    ENCRYPTION
  269.         case 'e':
  270.             if (strcmp(optarg, "debug") == 0) {
  271.                 extern int encrypt_debug_mode;
  272.                 encrypt_debug_mode = 1;
  273.                 break;
  274.             }
  275.             usage();
  276.             /* NOTREACHED */
  277.             break;
  278. #endif    /* ENCRYPTION */
  279.  
  280.         case 'h':
  281.             hostinfo = 0;
  282.             break;
  283.  
  284. #if    defined(CRAY) && defined(NEWINIT)
  285.         case 'I':
  286.             {
  287.             extern char *gen_id;
  288.             gen_id = optarg;
  289.             break;
  290.             }
  291. #endif    /* defined(CRAY) && defined(NEWINIT) */
  292.  
  293. #ifdef    LINEMODE
  294.         case 'l':
  295.             alwayslinemode = 1;
  296.             break;
  297. #endif    /* LINEMODE */
  298.  
  299.         case 'k':
  300. #if    defined(LINEMODE) && defined(KLUDGELINEMODE)
  301.             lmodetype = NO_AUTOKLUDGE;
  302. #else
  303.             /* ignore -k option if built without kludge linemode */
  304. #endif    /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
  305.             break;
  306.  
  307.         case 'n':
  308.             keepalive = 0;
  309.             break;
  310.  
  311. #ifdef CRAY
  312.         case 'r':
  313.             {
  314.             char *strchr();
  315.             char *c;
  316.  
  317.             /*
  318.              * Allow the specification of alterations
  319.              * to the pty search range.  It is legal to
  320.              * specify only one, and not change the
  321.              * other from its default.
  322.              */
  323.             c = strchr(optarg, '-');
  324.             if (c) {
  325.                 *c++ = '\0';
  326.                 highpty = atoi(c);
  327.             }
  328.             if (*optarg != '\0')
  329.                 lowpty = atoi(optarg);
  330.             if ((lowpty > highpty) || (lowpty < 0) ||
  331.                             (highpty > 32767)) {
  332.                 usage();
  333.                 /* NOT REACHED */
  334.             }
  335.             break;
  336.             }
  337. #endif    /* CRAY */
  338.  
  339. #ifdef    SecurID
  340.         case 's':
  341.             /* SecurID required */
  342.             require_SecurID = 1;
  343.             break;
  344. #endif    /* SecurID */
  345.         case 'S':
  346. #ifdef    HAS_GETTOS
  347.             if ((tos = parsetos(optarg, "tcp")) < 0)
  348.                 fprintf(stderr, "%s%s%s\n",
  349.                     "telnetd: Bad TOS argument '", optarg,
  350.                     "'; will try to use default TOS");
  351. #else
  352.             fprintf(stderr, "%s%s\n", "TOS option unavailable; ",
  353.                         "-S flag not supported\n");
  354. #endif
  355.             break;
  356.  
  357.         case 'u':
  358.             utmp_len = atoi(optarg);
  359.             break;
  360.  
  361.         case 'U':
  362.             registerd_host_only = 1;
  363.             break;
  364.  
  365. #ifdef    AUTHENTICATION
  366.         case 'X':
  367.             /*
  368.              * Check for invalid authentication types
  369.              */
  370.             auth_disable_name(optarg);
  371.             break;
  372. #endif    /* AUTHENTICATION */
  373.  
  374.         default:
  375.             fprintf(stderr, "telnetd: %c: unknown option\n", ch);
  376.             /* FALLTHROUGH */
  377.         case '?':
  378.             usage();
  379.             /* NOTREACHED */
  380.         }
  381.     }
  382.  
  383.     argc -= optind;
  384.     argv += optind;
  385.  
  386.     if (debug) {
  387.         int s, ns, foo;
  388.         struct servent *sp;
  389.         static struct sockaddr_in sin = { AF_INET };
  390.  
  391.         if (argc > 1) {
  392.         usage();
  393.         /* NOT REACHED */
  394.         } else if (argc == 1) {
  395.             if (sp = getservbyname(*argv, "tcp")) {
  396.             sin.sin_port = sp->s_port;
  397.             } else {
  398.             sin.sin_port = atoi(*argv);
  399.             if ((int)sin.sin_port <= 0) {
  400.                 fprintf(stderr, "telnetd: %s: bad port #\n", *argv);
  401.                 usage();
  402.                 /* NOT REACHED */
  403.             }
  404.             sin.sin_port = htons((u_short)sin.sin_port);
  405.            }
  406.         } else {
  407.         sp = getservbyname("telnet", "tcp");
  408.         if (sp == 0) {
  409.             fprintf(stderr, "telnetd: tcp/telnet: unknown service\n");
  410.             exit(1);
  411.         }
  412.         sin.sin_port = sp->s_port;
  413.         }
  414.  
  415.         s = socket(AF_INET, SOCK_STREAM, 0);
  416.         if (s < 0) {
  417.             perror("telnetd: socket");;
  418.             exit(1);
  419.         }
  420.         (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
  421.                 (char *)&on, sizeof(on));
  422.         if (bind(s, (struct sockaddr *)&sin, sizeof sin) < 0) {
  423.         perror("bind");
  424.         exit(1);
  425.         }
  426.         if (listen(s, 1) < 0) {
  427.         perror("listen");
  428.         exit(1);
  429.         }
  430.         foo = sizeof sin;
  431.         ns = accept(s, (struct sockaddr *)&sin, &foo);
  432.         if (ns < 0) {
  433.         perror("accept");
  434.         exit(1);
  435.         }
  436.         (void) dup2(ns, 0);
  437.         (void) close(ns);
  438.         (void) close(s);
  439. #ifdef convex
  440.     } else if (argc == 1) {
  441.         ; /* VOID*/        /* Just ignore the host/port name */
  442. #endif
  443.     } else if (argc > 0) {
  444.         usage();
  445.         /* NOT REACHED */
  446.     }
  447.  
  448. #if    defined(_SC_CRAY_SECURE_SYS)
  449.     secflag = sysconf(_SC_CRAY_SECURE_SYS);
  450.  
  451.     /*
  452.      *    Get socket's security label
  453.      */
  454.     if (secflag)  {
  455.         int szss = sizeof(ss);
  456. #ifdef SO_SEC_MULTI            /* 8.0 code */
  457.         int sock_multi;
  458.         int szi = sizeof(int);
  459. #endif /* SO_SEC_MULTI */
  460.  
  461.         memset((char *)&dv, 0, sizeof(dv));
  462.  
  463.         if (getsysv(&sysv, sizeof(struct sysv)) != 0) {
  464.             perror("getsysv");
  465.             exit(1);
  466.         }
  467.  
  468.         /*
  469.          *    Get socket security label and set device values
  470.          *       {security label to be set on ttyp device}
  471.          */
  472. #ifdef SO_SEC_MULTI            /* 8.0 code */
  473.         if ((getsockopt(0, SOL_SOCKET, SO_SECURITY,
  474.                    (char *)&ss, &szss) < 0) ||
  475.             (getsockopt(0, SOL_SOCKET, SO_SEC_MULTI,
  476.                 (char *)&sock_multi, &szi) < 0)) {
  477.             perror("getsockopt");
  478.             exit(1);
  479.         } else {
  480.             dv.dv_actlvl = ss.ss_actlabel.lt_level;
  481.             dv.dv_actcmp = ss.ss_actlabel.lt_compart;
  482.             if (!sock_multi) {
  483.                 dv.dv_minlvl = dv.dv_maxlvl = dv.dv_actlvl;
  484.                 dv.dv_valcmp = dv.dv_actcmp;
  485.             } else {
  486.                 dv.dv_minlvl = ss.ss_minlabel.lt_level;
  487.                 dv.dv_maxlvl = ss.ss_maxlabel.lt_level;
  488.                 dv.dv_valcmp = ss.ss_maxlabel.lt_compart;
  489.             }
  490.             dv.dv_devflg = 0;
  491.         }
  492. #else /* SO_SEC_MULTI */        /* 7.0 code */
  493.         if (getsockopt(0, SOL_SOCKET, SO_SECURITY,
  494.                 (char *)&ss, &szss) >= 0) {
  495.             dv.dv_actlvl = ss.ss_slevel;
  496.             dv.dv_actcmp = ss.ss_compart;
  497.             dv.dv_minlvl = ss.ss_minlvl;
  498.             dv.dv_maxlvl = ss.ss_maxlvl;
  499.             dv.dv_valcmp = ss.ss_maxcmp;
  500.         }
  501. #endif /* SO_SEC_MULTI */
  502.     }
  503. #endif    /* _SC_CRAY_SECURE_SYS */
  504.  
  505.     openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
  506.     fromlen = sizeof (from);
  507.     if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
  508.         fprintf(stderr, "%s: ", progname);
  509.         perror("getpeername");
  510.         _exit(1);
  511.     }
  512.     if (keepalive &&
  513.         setsockopt(0, SOL_SOCKET, SO_KEEPALIVE,
  514.             (char *)&on, sizeof (on)) < 0) {
  515.         syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
  516.     }
  517.  
  518. #if    defined(IPPROTO_IP) && defined(IP_TOS)
  519.     {
  520. # if    defined(HAS_GETTOS)
  521.         struct tosent *tp;
  522.         if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
  523.             tos = tp->t_tos;
  524. # endif
  525.         if (tos < 0)
  526.             tos = 020;    /* Low Delay bit */
  527.         if (tos
  528.            && (setsockopt(0, IPPROTO_IP, IP_TOS,
  529.                   (char *)&tos, sizeof(tos)) < 0)
  530.            && (errno != ENOPROTOOPT) )
  531.             syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
  532.     }
  533. #endif    /* defined(IPPROTO_IP) && defined(IP_TOS) */
  534.     net = 0;
  535.     doit(&from);
  536.     /* NOTREACHED */
  537. }  /* end of main */
  538.  
  539.     void
  540. usage()
  541. {
  542.     fprintf(stderr, "Usage: telnetd");
  543. #ifdef    AUTHENTICATION
  544.     fprintf(stderr, " [-a (debug|other|user|valid|off|none)]\n\t");
  545. #endif
  546. #ifdef BFTPDAEMON
  547.     fprintf(stderr, " [-B]");
  548. #endif
  549.     fprintf(stderr, " [-debug]");
  550. #ifdef DIAGNOSTICS
  551.     fprintf(stderr, " [-D (options|report|exercise|netdata|ptydata)]\n\t");
  552. #endif
  553. #ifdef    AUTHENTICATION
  554.     fprintf(stderr, " [-edebug]");
  555. #endif
  556.     fprintf(stderr, " [-h]");
  557. #if    defined(CRAY) && defined(NEWINIT)
  558.     fprintf(stderr, " [-Iinitid]");
  559. #endif
  560. #if    defined(LINEMODE) && defined(KLUDGELINEMODE)
  561.     fprintf(stderr, " [-k]");
  562. #endif
  563. #ifdef LINEMODE
  564.     fprintf(stderr, " [-l]");
  565. #endif
  566.     fprintf(stderr, " [-n]");
  567. #ifdef    CRAY
  568.     fprintf(stderr, " [-r[lowpty]-[highpty]]");
  569. #endif
  570.     fprintf(stderr, "\n\t");
  571. #ifdef    SecurID
  572.     fprintf(stderr, " [-s]");
  573. #endif
  574. #ifdef    HAS_GETTOS
  575.     fprintf(stderr, " [-S tos]");
  576. #endif
  577. #ifdef    AUTHENTICATION
  578.     fprintf(stderr, " [-X auth-type]");
  579. #endif
  580.     fprintf(stderr, " [-u utmp_hostname_length] [-U]");
  581.     fprintf(stderr, " [port]\n");
  582.     exit(1);
  583. }
  584.  
  585. /*
  586.  * getterminaltype
  587.  *
  588.  *    Ask the other end to send along its terminal type and speed.
  589.  * Output is the variable terminaltype filled in.
  590.  */
  591. static unsigned char ttytype_sbbuf[] = {
  592.     IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE
  593. };
  594.  
  595.     int
  596. getterminaltype(name)
  597.     char *name;
  598. {
  599.     int retval = -1;
  600.     void _gettermname();
  601.  
  602.     settimer(baseline);
  603. #if    defined(AUTHENTICATION)
  604.     /*
  605.      * Handle the Authentication option before we do anything else.
  606.      */
  607.     send_do(TELOPT_AUTHENTICATION, 1);
  608.     while (his_will_wont_is_changing(TELOPT_AUTHENTICATION))
  609.     ttloop();
  610.     if (his_state_is_will(TELOPT_AUTHENTICATION)) {
  611.     retval = auth_wait(name);
  612.     }
  613. #endif
  614.  
  615. #ifdef    ENCRYPTION
  616.     send_will(TELOPT_ENCRYPT, 1);
  617. #endif    /* ENCRYPTION */
  618.     send_do(TELOPT_TTYPE, 1);
  619.     send_do(TELOPT_TSPEED, 1);
  620.     send_do(TELOPT_XDISPLOC, 1);
  621.     send_do(TELOPT_NEW_ENVIRON, 1);
  622.     send_do(TELOPT_OLD_ENVIRON, 1);
  623.     while (
  624. #ifdef    ENCRYPTION
  625.        his_do_dont_is_changing(TELOPT_ENCRYPT) ||
  626. #endif    /* ENCRYPTION */
  627.        his_will_wont_is_changing(TELOPT_TTYPE) ||
  628.        his_will_wont_is_changing(TELOPT_TSPEED) ||
  629.        his_will_wont_is_changing(TELOPT_XDISPLOC) ||
  630.        his_will_wont_is_changing(TELOPT_NEW_ENVIRON) ||
  631.        his_will_wont_is_changing(TELOPT_OLD_ENVIRON)) {
  632.     ttloop();
  633.     }
  634. #ifdef    ENCRYPTION
  635.     /*
  636.      * Wait for the negotiation of what type of encryption we can
  637.      * send with.  If autoencrypt is not set, this will just return.
  638.      */
  639.     if (his_state_is_will(TELOPT_ENCRYPT)) {
  640.     encrypt_wait();
  641.     }
  642. #endif    /* ENCRYPTION */
  643.     if (his_state_is_will(TELOPT_TSPEED)) {
  644.     static unsigned char sb[] =
  645.             { IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE };
  646.  
  647.     memmove(nfrontp, sb, sizeof sb);
  648.     nfrontp += sizeof sb;
  649.     DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
  650.     }
  651.     if (his_state_is_will(TELOPT_XDISPLOC)) {
  652.     static unsigned char sb[] =
  653.             { IAC, SB, TELOPT_XDISPLOC, TELQUAL_SEND, IAC, SE };
  654.  
  655.     memmove(nfrontp, sb, sizeof sb);
  656.     nfrontp += sizeof sb;
  657.     DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
  658.     }
  659.     if (his_state_is_will(TELOPT_NEW_ENVIRON)) {
  660.     static unsigned char sb[] =
  661.             { IAC, SB, TELOPT_NEW_ENVIRON, TELQUAL_SEND, IAC, SE };
  662.  
  663.     memmove(nfrontp, sb, sizeof sb);
  664.     nfrontp += sizeof sb;
  665.     DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
  666.     }
  667.     else if (his_state_is_will(TELOPT_OLD_ENVIRON)) {
  668.     static unsigned char sb[] =
  669.             { IAC, SB, TELOPT_OLD_ENVIRON, TELQUAL_SEND, IAC, SE };
  670.  
  671.     memmove(nfrontp, sb, sizeof sb);
  672.     nfrontp += sizeof sb;
  673.     DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
  674.     }
  675.     if (his_state_is_will(TELOPT_TTYPE)) {
  676.  
  677.     memmove(nfrontp, ttytype_sbbuf, sizeof ttytype_sbbuf);
  678.     nfrontp += sizeof ttytype_sbbuf;
  679.     DIAG(TD_OPTIONS, printsub('>', ttytype_sbbuf + 2,
  680.                     sizeof ttytype_sbbuf - 2););
  681.     }
  682.     if (his_state_is_will(TELOPT_TSPEED)) {
  683.     while (sequenceIs(tspeedsubopt, baseline))
  684.         ttloop();
  685.     }
  686.     if (his_state_is_will(TELOPT_XDISPLOC)) {
  687.     while (sequenceIs(xdisplocsubopt, baseline))
  688.         ttloop();
  689.     }
  690.     if (his_state_is_will(TELOPT_NEW_ENVIRON)) {
  691.     while (sequenceIs(environsubopt, baseline))
  692.         ttloop();
  693.     }
  694.     if (his_state_is_will(TELOPT_OLD_ENVIRON)) {
  695.     while (sequenceIs(oenvironsubopt, baseline))
  696.         ttloop();
  697.     }
  698.     if (his_state_is_will(TELOPT_TTYPE)) {
  699.     char first[256], last[256];
  700.  
  701.     while (sequenceIs(ttypesubopt, baseline))
  702.         ttloop();
  703.  
  704.     /*
  705.      * If the other side has already disabled the option, then
  706.      * we have to just go with what we (might) have already gotten.
  707.      */
  708.     if (his_state_is_will(TELOPT_TTYPE) && !terminaltypeok(terminaltype)) {
  709.         (void) strncpy(first, terminaltype, sizeof(first));
  710.         for(;;) {
  711.         /*
  712.          * Save the unknown name, and request the next name.
  713.          */
  714.         (void) strncpy(last, terminaltype, sizeof(last));
  715.         _gettermname();
  716.         if (terminaltypeok(terminaltype))
  717.             break;
  718.         if ((strncmp(last, terminaltype, sizeof(last)) == 0) ||
  719.             his_state_is_wont(TELOPT_TTYPE)) {
  720.             /*
  721.              * We've hit the end.  If this is the same as
  722.              * the first name, just go with it.
  723.              */
  724.             if (strncmp(first, terminaltype, sizeof(first)) == 0)
  725.             break;
  726.             /*
  727.              * Get the terminal name one more time, so that
  728.              * RFC1091 compliant telnets will cycle back to
  729.              * the start of the list.
  730.              */
  731.              _gettermname();
  732.             if (strncmp(first, terminaltype, sizeof(first)) != 0)
  733.             (void) strncpy(terminaltype, first, sizeof(first));
  734.             break;
  735.         }
  736.         }
  737.     }
  738.     }
  739.     return(retval);
  740. }  /* end of getterminaltype */
  741.  
  742.     void
  743. _gettermname()
  744. {
  745.     /*
  746.      * If the client turned off the option,
  747.      * we can't send another request, so we
  748.      * just return.
  749.      */
  750.     if (his_state_is_wont(TELOPT_TTYPE))
  751.     return;
  752.     settimer(baseline);
  753.     memmove(nfrontp, ttytype_sbbuf, sizeof ttytype_sbbuf);
  754.     nfrontp += sizeof ttytype_sbbuf;
  755.     DIAG(TD_OPTIONS, printsub('>', ttytype_sbbuf + 2,
  756.                     sizeof ttytype_sbbuf - 2););
  757.     while (sequenceIs(ttypesubopt, baseline))
  758.     ttloop();
  759. }
  760.  
  761.     int
  762. terminaltypeok(s)
  763.     char *s;
  764. {
  765.     char buf[1024];
  766.  
  767.     if (terminaltype == NULL)
  768.     return(1);
  769.  
  770.     /*
  771.      * tgetent() will return 1 if the type is known, and
  772.      * 0 if it is not known.  If it returns -1, it couldn't
  773.      * open the database.  But if we can't open the database,
  774.      * it won't help to say we failed, because we won't be
  775.      * able to verify anything else.  So, we treat -1 like 1.
  776.      */
  777.     if (tgetent(buf, s) == 0)
  778.     return(0);
  779.     return(1);
  780. }
  781.  
  782. #ifndef    MAXHOSTNAMELEN
  783. #define    MAXHOSTNAMELEN 64
  784. #endif    /* MAXHOSTNAMELEN */
  785.  
  786. char *hostname;
  787. char host_name[MAXHOSTNAMELEN];
  788. char remote_host_name[MAXHOSTNAMELEN];
  789.  
  790. #ifndef    convex
  791. extern void telnet P((int, int));
  792. #else
  793. extern void telnet P((int, int, char *));
  794. #endif
  795.  
  796. /*
  797.  * Get a pty, scan input lines.
  798.  */
  799. doit(who)
  800.     struct sockaddr_in *who;
  801. {
  802.     char *host, *inet_ntoa();
  803.     int t;
  804.     struct hostent *hp;
  805.     int level;
  806.     int ptynum;
  807.     char user_name[256];
  808.  
  809.     /*
  810.      * Find an available pty to use.
  811.      */
  812. #ifndef    convex
  813.     pty = getpty(&ptynum);
  814.     if (pty < 0)
  815.         fatal(net, "All network ports in use");
  816. #else
  817.     for (;;) {
  818.         char *lp;
  819.         extern char *line, *getpty();
  820.  
  821.         if ((lp = getpty()) == NULL)
  822.             fatal(net, "Out of ptys");
  823.  
  824.         if ((pty = open(lp, 2)) >= 0) {
  825.             strcpy(line,lp);
  826.             line[5] = 't';
  827.             break;
  828.         }
  829.     }
  830. #endif
  831.  
  832. #if    defined(_SC_CRAY_SECURE_SYS)
  833.     /*
  834.      *    set ttyp line security label 
  835.      */
  836.     if (secflag) {
  837.         char slave_dev[16];
  838.  
  839.         sprintf(tty_dev, "/dev/pty/%03d", ptynum);
  840.         if (setdevs(tty_dev, &dv) < 0)
  841.              fatal(net, "cannot set pty security");
  842.         sprintf(slave_dev, "/dev/ttyp%03d", ptynum);
  843.         if (setdevs(slave_dev, &dv) < 0)
  844.              fatal(net, "cannot set tty security");
  845.     }
  846. #endif    /* _SC_CRAY_SECURE_SYS */
  847.  
  848.     /* get name of connected client */
  849.     hp = gethostbyaddr((char *)&who->sin_addr, sizeof (struct in_addr),
  850.         who->sin_family);
  851.  
  852.     if (hp == NULL && registerd_host_only) {
  853.         fatal(net, "Couldn't resolve your address into a host name.\r\n\
  854.          Please contact your net administrator");
  855.     } else if (hp &&
  856.         (strlen(hp->h_name) <= (unsigned int)((utmp_len < 0) ? -utmp_len
  857.                                  : utmp_len))) {
  858.         host = hp->h_name;
  859.     } else {
  860.         host = inet_ntoa(who->sin_addr);
  861.     }
  862.     /*
  863.      * We must make a copy because Kerberos is probably going
  864.      * to also do a gethost* and overwrite the static data...
  865.      */
  866.     strncpy(remote_host_name, host, sizeof(remote_host_name)-1);
  867.     remote_host_name[sizeof(remote_host_name)-1] = 0;
  868.     host = remote_host_name;
  869.  
  870.     (void) gethostname(host_name, sizeof (host_name));
  871.     hostname = host_name;
  872.  
  873. #if    defined(AUTHENTICATION) || defined(ENCRYPTION)
  874.     auth_encrypt_init(hostname, host, "TELNETD", 1);
  875. #endif
  876.  
  877.     init_env();
  878.     /*
  879.      * get terminal type.
  880.      */
  881.     *user_name = 0;
  882.     level = getterminaltype(user_name);
  883.     setenv("TERM", terminaltype ? terminaltype : "network", 1);
  884.  
  885.     /*
  886.      * Start up the login process on the slave side of the terminal
  887.      */
  888. #ifndef    convex
  889.     startslave(host, level, user_name);
  890.  
  891. #if    defined(_SC_CRAY_SECURE_SYS)
  892.     if (secflag) {
  893.         if (setulvl(dv.dv_actlvl) < 0)
  894.             fatal(net,"cannot setulvl()");
  895.         if (setucmp(dv.dv_actcmp) < 0)
  896.             fatal(net, "cannot setucmp()");
  897.     }
  898. #endif    /* _SC_CRAY_SECURE_SYS */
  899.  
  900.     telnet(net, pty);  /* begin server processing */
  901. #else
  902.     telnet(net, pty, host);
  903. #endif
  904.     /*NOTREACHED*/
  905. }  /* end of doit */
  906.  
  907. #if    defined(CRAY2) && defined(UNICOS5) && defined(UNICOS50)
  908.     int
  909. Xterm_output(ibufp, obuf, icountp, ocount)
  910.     char **ibufp, *obuf;
  911.     int *icountp, ocount;
  912. {
  913.     int ret;
  914.     ret = term_output(*ibufp, obuf, *icountp, ocount);
  915.     *ibufp += *icountp;
  916.     *icountp = 0;
  917.     return(ret);
  918. }
  919. #define    term_output    Xterm_output
  920. #endif    /* defined(CRAY2) && defined(UNICOS5) && defined(UNICOS50) */
  921.  
  922. static FILE *_console = 0;
  923. #define  cprintf(fmt, args...) \
  924.   { if (! _console) _console = fopen ("/dev/console", "w"); \
  925.     fprintf (_console, fmt , ##args); }
  926.  
  927. /*
  928.  * Main loop.  Select from pty and network, and
  929.  * hand data to telnet receiver finite state machine.
  930.  */
  931.     void
  932. #ifndef    convex
  933. telnet(f, p)
  934. #else
  935. telnet(f, p, host)
  936. #endif
  937.     int f, p;
  938. #ifdef convex
  939.     char *host;
  940. #endif
  941. {
  942.     int on = 1;
  943. #define    TABBUFSIZ    512
  944.     char    defent[TABBUFSIZ];
  945.     char    defstrs[TABBUFSIZ];
  946. #undef    TABBUFSIZ
  947.     char *HE;
  948.     char *HN;
  949.     char *IM;
  950.     void netflush();
  951.     int nfd;
  952.  
  953.     /*
  954.      * Initialize the slc mapping table.
  955.      */
  956.     get_slc_defaults();
  957.  
  958.     /*
  959.      * Do some tests where it is desireable to wait for a response.
  960.      * Rather than doing them slowly, one at a time, do them all
  961.      * at once.
  962.      */
  963.     if (my_state_is_wont(TELOPT_SGA))
  964.         send_will(TELOPT_SGA, 1);
  965.     /*
  966.      * Is the client side a 4.2 (NOT 4.3) system?  We need to know this
  967.      * because 4.2 clients are unable to deal with TCP urgent data.
  968.      *
  969.      * To find out, we send out a "DO ECHO".  If the remote system
  970.      * answers "WILL ECHO" it is probably a 4.2 client, and we note
  971.      * that fact ("WILL ECHO" ==> that the client will echo what
  972.      * WE, the server, sends it; it does NOT mean that the client will
  973.      * echo the terminal input).
  974.      */
  975.     send_do(TELOPT_ECHO, 1);
  976.  
  977. #ifdef    LINEMODE
  978.     if (his_state_is_wont(TELOPT_LINEMODE)) {
  979.         /* Query the peer for linemode support by trying to negotiate
  980.          * the linemode option.
  981.          */
  982.         linemode = 0;
  983.         editmode = 0;
  984.         send_do(TELOPT_LINEMODE, 1);  /* send do linemode */
  985.     }
  986. #endif    /* LINEMODE */
  987.  
  988.     /*
  989.      * Send along a couple of other options that we wish to negotiate.
  990.      */
  991.     send_do(TELOPT_NAWS, 1);
  992.     send_will(TELOPT_STATUS, 1);
  993.     flowmode = 1;        /* default flow control state */
  994.     restartany = -1;    /* uninitialized... */
  995.     send_do(TELOPT_LFLOW, 1);
  996.  
  997.     /*
  998.      * Spin, waiting for a response from the DO ECHO.  However,
  999.      * some REALLY DUMB telnets out there might not respond
  1000.      * to the DO ECHO.  So, we spin looking for NAWS, (most dumb
  1001.      * telnets so far seem to respond with WONT for a DO that
  1002.      * they don't understand...) because by the time we get the
  1003.      * response, it will already have processed the DO ECHO.
  1004.      * Kludge upon kludge.
  1005.      */
  1006.     while (his_will_wont_is_changing(TELOPT_NAWS))
  1007.         ttloop();
  1008.  
  1009.     /*
  1010.      * But...
  1011.      * The client might have sent a WILL NAWS as part of its
  1012.      * startup code; if so, we'll be here before we get the
  1013.      * response to the DO ECHO.  We'll make the assumption
  1014.      * that any implementation that understands about NAWS
  1015.      * is a modern enough implementation that it will respond
  1016.      * to our DO ECHO request; hence we'll do another spin
  1017.      * waiting for the ECHO option to settle down, which is
  1018.      * what we wanted to do in the first place...
  1019.      */
  1020.     if (his_want_state_is_will(TELOPT_ECHO) &&
  1021.         his_state_is_will(TELOPT_NAWS)) {
  1022.         while (his_will_wont_is_changing(TELOPT_ECHO))
  1023.             ttloop();
  1024.     }
  1025.     /*
  1026.      * On the off chance that the telnet client is broken and does not
  1027.      * respond to the DO ECHO we sent, (after all, we did send the
  1028.      * DO NAWS negotiation after the DO ECHO, and we won't get here
  1029.      * until a response to the DO NAWS comes back) simulate the
  1030.      * receipt of a will echo.  This will also send a WONT ECHO
  1031.      * to the client, since we assume that the client failed to
  1032.      * respond because it believes that it is already in DO ECHO
  1033.      * mode, which we do not want.
  1034.      */
  1035.     if (his_want_state_is_will(TELOPT_ECHO)) {
  1036.         DIAG(TD_OPTIONS,
  1037.             {sprintf(nfrontp, "td: simulating recv\r\n");
  1038.              nfrontp += strlen(nfrontp);});
  1039.         willoption(TELOPT_ECHO);
  1040.     }
  1041.  
  1042.     /*
  1043.      * Finally, to clean things up, we turn on our echo.  This
  1044.      * will break stupid 4.2 telnets out of local terminal echo.
  1045.      */
  1046.  
  1047.     if (my_state_is_wont(TELOPT_ECHO))
  1048.         send_will(TELOPT_ECHO, 1);
  1049.  
  1050. #ifndef    STREAMSPTY
  1051.     /*
  1052.      * Turn on packet mode
  1053.      */
  1054.     (void) ioctl(p, TIOCPKT, (char *)&on);
  1055. #endif
  1056.  
  1057. #if    defined(LINEMODE) && defined(KLUDGELINEMODE)
  1058.     /*
  1059.      * Continuing line mode support.  If client does not support
  1060.      * real linemode, attempt to negotiate kludge linemode by sending
  1061.      * the do timing mark sequence.
  1062.      */
  1063.     if (lmodetype < REAL_LINEMODE)
  1064.         send_do(TELOPT_TM, 1);
  1065. #endif    /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
  1066.  
  1067.     /*
  1068.      * Call telrcv() once to pick up anything received during
  1069.      * terminal type negotiation, 4.2/4.3 determination, and
  1070.      * linemode negotiation.
  1071.      */
  1072.     telrcv();
  1073.  
  1074.     (void) ioctl(f, FIONBIO, (char *)&on);
  1075.     (void) ioctl(p, FIONBIO, (char *)&on);
  1076. #if    defined(CRAY2) && defined(UNICOS5)
  1077.     init_termdriver(f, p, interrupt, sendbrk);
  1078. #endif
  1079.  
  1080. #if    defined(SO_OOBINLINE)
  1081.     (void) setsockopt(net, SOL_SOCKET, SO_OOBINLINE,
  1082.                 (char *)&on, sizeof on);
  1083. #endif    /* defined(SO_OOBINLINE) */
  1084.  
  1085. #ifdef    SIGTSTP
  1086.     (void) signal(SIGTSTP, SIG_IGN);
  1087. #endif
  1088. #ifdef    SIGTTOU
  1089.     /*
  1090.      * Ignoring SIGTTOU keeps the kernel from blocking us
  1091.      * in ttioct() in /sys/tty.c.
  1092.      */
  1093.     (void) signal(SIGTTOU, SIG_IGN);
  1094. #endif
  1095.  
  1096.     (void) signal(SIGCHLD, cleanup);
  1097.  
  1098. #if    defined(CRAY2) && defined(UNICOS5)
  1099.     /*
  1100.      * Cray-2 will send a signal when pty modes are changed by slave
  1101.      * side.  Set up signal handler now.
  1102.      */
  1103.     if ((int)signal(SIGUSR1, termstat) < 0)
  1104.         perror("signal");
  1105.     else if (ioctl(p, TCSIGME, (char *)SIGUSR1) < 0)
  1106.         perror("ioctl:TCSIGME");
  1107.     /*
  1108.      * Make processing loop check terminal characteristics early on.
  1109.      */
  1110.     termstat();
  1111. #endif
  1112.  
  1113. #ifdef  TIOCNOTTY
  1114.     {
  1115.         register int t;
  1116.         t = open(_PATH_TTY, O_RDWR);
  1117.         if (t >= 0) {
  1118.             (void) ioctl(t, TIOCNOTTY, (char *)0);
  1119.             (void) close(t);
  1120.         }
  1121.     }
  1122. #endif
  1123.  
  1124. #if    defined(CRAY) && defined(NEWINIT) && defined(TIOCSCTTY)
  1125.     (void) setsid();
  1126.     ioctl(p, TIOCSCTTY, 0);
  1127. #endif
  1128.  
  1129.     /*
  1130.      * Show banner that getty never gave.
  1131.      *
  1132.      * We put the banner in the pty input buffer.  This way, it
  1133.      * gets carriage return null processing, etc., just like all
  1134.      * other pty --> client data.
  1135.      */
  1136.  
  1137. #if    !defined(CRAY) || !defined(NEWINIT)
  1138.     if (getenv("USER"))
  1139.         hostinfo = 0;
  1140. #endif
  1141.  
  1142.     if (getent(defent, "default") == 1) {
  1143.         char *getstr();
  1144.         char *cp=defstrs;
  1145.  
  1146.         HE = getstr("he", &cp);
  1147.         HN = getstr("hn", &cp);
  1148.         IM = getstr("im", &cp);
  1149.         if (HN && *HN)
  1150.             (void) strcpy(host_name, HN);
  1151.         if (IM == 0)
  1152.             IM = "";
  1153.     } else {
  1154. #ifdef HAVE_UNAME
  1155.         struct utsname u;
  1156. #endif
  1157.  
  1158. #ifdef DEFAULT_IM
  1159.         IM = DEFAULT_IM;
  1160. #else
  1161.         IM = 0;
  1162. #ifdef HAVE_UNAME
  1163.         if (uname (&u) == 0) {
  1164.             IM = malloc (strlen (UNAME_IM_PREFIX)
  1165.                      + strlen (u.sysname)
  1166.                      + 1 + strlen (u.release)
  1167.                      + strlen (UNAME_IM_SUFFIX) + 1);
  1168.             if (IM)
  1169.                 sprintf (IM, "%s%s %s%s",
  1170.                      UNAME_IM_PREFIX,
  1171.                      u.sysname, u.release,
  1172.                      UNAME_IM_SUFFIX);
  1173.         }
  1174. #endif /* HAVE_UNAME */
  1175.         if (! IM)
  1176.             IM = "\r\n\nUNIX (%h) (%t)\r\n\n";
  1177. #endif /* DEFAULT_IM */
  1178.  
  1179.         HE = 0;
  1180.     }
  1181.  
  1182.     edithost(HE, host_name);
  1183.     if (hostinfo && *IM)
  1184.         putf(IM, ptyibuf2);
  1185.  
  1186.     if (pcc)
  1187.         (void) strncat(ptyibuf2, ptyip, pcc+1);
  1188.     ptyip = ptyibuf2;
  1189.     pcc = strlen(ptyip);
  1190. #ifdef    LINEMODE
  1191.     /*
  1192.      * Last check to make sure all our states are correct.
  1193.      */
  1194.     init_termbuf();
  1195.     localstat();
  1196. #endif    /* LINEMODE */
  1197.  
  1198.     DIAG(TD_REPORT,
  1199.         {sprintf(nfrontp, "td: Entering processing loop\r\n");
  1200.          nfrontp += strlen(nfrontp);});
  1201.  
  1202. #ifdef    convex
  1203.     startslave(host);
  1204. #endif
  1205.  
  1206.     nfd = ((f > p) ? f : p) + 1;
  1207.     for (;;) {
  1208.         fd_set ibits, obits, xbits;
  1209.         register int c;
  1210.  
  1211.         if (ncc < 0 && pcc < 0)
  1212.           { cprintf ("Breaking because NCC = %d, PCC = %d\n", ncc, pcc);
  1213.             break;
  1214.           }
  1215.  
  1216. #if    defined(CRAY2) && defined(UNICOS5)
  1217.         if (needtermstat)
  1218.             _termstat();
  1219. #endif    /* defined(CRAY2) && defined(UNICOS5) */
  1220.         FD_ZERO(&ibits);
  1221.         FD_ZERO(&obits);
  1222.         FD_ZERO(&xbits);
  1223.         /*
  1224.          * Never look for input if there's still
  1225.          * stuff in the corresponding output buffer
  1226.          */
  1227.         if (nfrontp - nbackp || pcc > 0) {
  1228.             FD_SET(f, &obits);
  1229.         } else {
  1230.             FD_SET(p, &ibits);
  1231.         }
  1232.         if (pfrontp - pbackp || ncc > 0) {
  1233.             FD_SET(p, &obits);
  1234.         } else {
  1235.             FD_SET(f, &ibits);
  1236.         }
  1237.         if (!SYNCHing) {
  1238.             FD_SET(f, &xbits);
  1239.         }
  1240.         if ((c = select(nfd, &ibits, &obits, &xbits,
  1241.                         (struct timeval *)0)) < 1) {
  1242.             if (c == -1) {
  1243.                 if (errno == EINTR) {
  1244.                     continue;
  1245.                 }
  1246.             }
  1247.             sleep(5);
  1248.             continue;
  1249.         }
  1250.  
  1251.         /*
  1252.          * Any urgent data?
  1253.          */
  1254.         if (FD_ISSET(net, &xbits)) {
  1255.             SYNCHing = 1;
  1256.         }
  1257.  
  1258.         /*
  1259.          * Something to read from the network...
  1260.          */
  1261.         if (FD_ISSET(net, &ibits)) {
  1262. #if    !defined(SO_OOBINLINE)
  1263.             /*
  1264.              * In 4.2 (and 4.3 beta) systems, the
  1265.              * OOB indication and data handling in the kernel
  1266.              * is such that if two separate TCP Urgent requests
  1267.              * come in, one byte of TCP data will be overlaid.
  1268.              * This is fatal for Telnet, but we try to live
  1269.              * with it.
  1270.              *
  1271.              * In addition, in 4.2 (and...), a special protocol
  1272.              * is needed to pick up the TCP Urgent data in
  1273.              * the correct sequence.
  1274.              *
  1275.              * What we do is:  if we think we are in urgent
  1276.              * mode, we look to see if we are "at the mark".
  1277.              * If we are, we do an OOB receive.  If we run
  1278.              * this twice, we will do the OOB receive twice,
  1279.              * but the second will fail, since the second
  1280.              * time we were "at the mark", but there wasn't
  1281.              * any data there (the kernel doesn't reset
  1282.              * "at the mark" until we do a normal read).
  1283.              * Once we've read the OOB data, we go ahead
  1284.              * and do normal reads.
  1285.              *
  1286.              * There is also another problem, which is that
  1287.              * since the OOB byte we read doesn't put us
  1288.              * out of OOB state, and since that byte is most
  1289.              * likely the TELNET DM (data mark), we would
  1290.              * stay in the TELNET SYNCH (SYNCHing) state.
  1291.              * So, clocks to the rescue.  If we've "just"
  1292.              * received a DM, then we test for the
  1293.              * presence of OOB data when the receive OOB
  1294.              * fails (and AFTER we did the normal mode read
  1295.              * to clear "at the mark").
  1296.              */
  1297.             if (SYNCHing) {
  1298.             int atmark;
  1299.  
  1300.             (void) ioctl(net, SIOCATMARK, (char *)&atmark);
  1301.             if (atmark) {
  1302.                 ncc = recv(net, netibuf, sizeof (netibuf), MSG_OOB);
  1303.                 if ((ncc == -1) && (errno == EINVAL)) {
  1304.                 ncc = read(net, netibuf, sizeof (netibuf));
  1305.                 if (sequenceIs(didnetreceive, gotDM)) {
  1306.                     SYNCHing = stilloob(net);
  1307.                 }
  1308.                 }
  1309.             } else {
  1310.                 ncc = read(net, netibuf, sizeof (netibuf));
  1311.             }
  1312.             } else {
  1313.             ncc = read(net, netibuf, sizeof (netibuf));
  1314.             }
  1315.             settimer(didnetreceive);
  1316. #else    /* !defined(SO_OOBINLINE)) */
  1317.             ncc = read(net, netibuf, sizeof (netibuf));
  1318. #endif    /* !defined(SO_OOBINLINE)) */
  1319.             if (ncc < 0 && errno == EWOULDBLOCK)
  1320.             ncc = 0;
  1321.             else {
  1322.             if (ncc <= 0) {
  1323.               cprintf ("Breaking because NCC = %d: %s\n", ncc,
  1324.                    strerror (errno));
  1325.                 break;
  1326.             }
  1327.             netip = netibuf;
  1328.             }
  1329.             DIAG((TD_REPORT | TD_NETDATA),
  1330.                 {sprintf(nfrontp, "td: netread %d chars\r\n", ncc);
  1331.                  nfrontp += strlen(nfrontp);});
  1332.             DIAG(TD_NETDATA, printdata("nd", netip, ncc));
  1333.         }
  1334.  
  1335.         /*
  1336.          * Something to read from the pty...
  1337.          */
  1338.         if (FD_ISSET(p, &ibits)) {
  1339. #ifndef    STREAMSPTY
  1340.             pcc = read(p, ptyibuf, BUFSIZ);
  1341. #else
  1342.             pcc = readstream(p, ptyibuf, BUFSIZ);
  1343. #endif
  1344.             /*
  1345.              * On some systems, if we try to read something
  1346.              * off the master side before the slave side is
  1347.              * opened, we get EIO.
  1348.              */
  1349.             if (pcc < 0 && (errno == EWOULDBLOCK ||
  1350. #ifdef    EAGAIN
  1351.                     errno == EAGAIN ||
  1352. #endif
  1353.                     errno == EIO)) {
  1354.                 pcc = 0;
  1355.             } else {
  1356.                 if (pcc <= 0)
  1357.                   { 
  1358.                     cprintf ("Breaking because PCC = %d\n", pcc);
  1359.                     break;
  1360.                   }
  1361. #if    !defined(CRAY2) || !defined(UNICOS5)
  1362. #if defined (LINEMODE) && defined (TIOCPKT_IOCTL)
  1363.                 /*
  1364.                  * If ioctl from pty, pass it through net
  1365.                  */
  1366.                 if (ptyibuf[0] & TIOCPKT_IOCTL) {
  1367.                     copy_termbuf(ptyibuf+1, pcc-1);
  1368.                     localstat();
  1369.                     pcc = 1;
  1370.                 }
  1371. #endif    /* LINEMODE && TIOCPKT_IOCTL */
  1372.                 if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) {
  1373.                     netclear();    /* clear buffer back */
  1374. #ifndef    NO_URGENT
  1375.                     /*
  1376.                      * There are client telnets on some
  1377.                      * operating systems get screwed up
  1378.                      * royally if we send them urgent
  1379.                      * mode data.
  1380.                      */
  1381.                     *nfrontp++ = IAC;
  1382.                     *nfrontp++ = DM;
  1383.                     neturg = nfrontp-1; /* off by one XXX */
  1384.                     DIAG(TD_OPTIONS,
  1385.                         printoption("td: send IAC", DM));
  1386.  
  1387. #endif
  1388.                 }
  1389.                 if (his_state_is_will(TELOPT_LFLOW) &&
  1390.                     (ptyibuf[0] &
  1391.                      (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))) {
  1392.                     int newflow =
  1393.                         ptyibuf[0] & TIOCPKT_DOSTOP ? 1 : 0;
  1394.                     if (newflow != flowmode) {
  1395.                         flowmode = newflow;
  1396.                         (void) sprintf(nfrontp,
  1397.                             "%c%c%c%c%c%c",
  1398.                             IAC, SB, TELOPT_LFLOW,
  1399.                             flowmode ? LFLOW_ON
  1400.                                  : LFLOW_OFF,
  1401.                             IAC, SE);
  1402.                         nfrontp += 6;
  1403.                         DIAG(TD_OPTIONS, printsub('>',
  1404.                             (unsigned char *)nfrontp-4,
  1405.                             4););
  1406.                     }
  1407.                 }
  1408.                 pcc--;
  1409.                 ptyip = ptyibuf+1;
  1410. #else    /* defined(CRAY2) && defined(UNICOS5) */
  1411.                 if (!uselinemode) {
  1412.                     unpcc = pcc;
  1413.                     unptyip = ptyibuf;
  1414.                     pcc = term_output(&unptyip, ptyibuf2,
  1415.                                 &unpcc, BUFSIZ);
  1416.                     ptyip = ptyibuf2;
  1417.                 } else
  1418.                     ptyip = ptyibuf;
  1419. #endif    /* defined(CRAY2) && defined(UNICOS5) */
  1420.             }
  1421.         }
  1422.  
  1423.         while (pcc > 0) {
  1424.             if ((&netobuf[BUFSIZ] - nfrontp) < 2)
  1425.                 break;
  1426.             c = *ptyip++ & 0377, pcc--;
  1427.             if (c == IAC)
  1428.                 *nfrontp++ = c;
  1429. #if    defined(CRAY2) && defined(UNICOS5)
  1430.             else if (c == '\n' &&
  1431.                      my_state_is_wont(TELOPT_BINARY) && newmap)
  1432.                 *nfrontp++ = '\r';
  1433. #endif    /* defined(CRAY2) && defined(UNICOS5) */
  1434.             *nfrontp++ = c;
  1435.             if ((c == '\r') && (my_state_is_wont(TELOPT_BINARY))) {
  1436.                 if (pcc > 0 && ((*ptyip & 0377) == '\n')) {
  1437.                     *nfrontp++ = *ptyip++ & 0377;
  1438.                     pcc--;
  1439.                 } else
  1440.                     *nfrontp++ = '\0';
  1441.             }
  1442.         }
  1443. #if    defined(CRAY2) && defined(UNICOS5)
  1444.         /*
  1445.          * If chars were left over from the terminal driver,
  1446.          * note their existence.
  1447.          */
  1448.         if (!uselinemode && unpcc) {
  1449.             pcc = unpcc;
  1450.             unpcc = 0;
  1451.             ptyip = unptyip;
  1452.         }
  1453. #endif    /* defined(CRAY2) && defined(UNICOS5) */
  1454.  
  1455.         if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0)
  1456.             netflush();
  1457.         if (ncc > 0)
  1458.             telrcv();
  1459.         if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0)
  1460.             ptyflush();
  1461.     }
  1462.     cleanup(0);
  1463. }  /* end of telnet */
  1464.     
  1465. #ifndef    TCSIG
  1466. # ifdef    TIOCSIG
  1467. #  define TCSIG TIOCSIG
  1468. # endif
  1469. #endif
  1470.  
  1471. #ifdef    STREAMSPTY
  1472.  
  1473. int flowison = -1;  /* current state of flow: -1 is unknown */
  1474.  
  1475. int readstream(p, ibuf, bufsize)
  1476.     int p;
  1477.     char *ibuf;
  1478.     int bufsize;
  1479. {
  1480.     int flags = 0;
  1481.     int ret = 0;
  1482.     struct termios *tsp;
  1483.     struct termio *tp;
  1484.     struct iocblk *ip;
  1485.     char vstop, vstart;
  1486.     int ixon;
  1487.     int newflow;
  1488.  
  1489.     strbufc.maxlen = BUFSIZ;
  1490.     strbufc.buf = (char *)ctlbuf;
  1491.     strbufd.maxlen = bufsize-1;
  1492.     strbufd.len = 0;
  1493.     strbufd.buf = ibuf+1;
  1494.     ibuf[0] = 0;
  1495.  
  1496.     ret = getmsg(p, &strbufc, &strbufd, &flags);
  1497.     if (ret < 0)  /* error of some sort -- probably EAGAIN */
  1498.         return(-1);
  1499.  
  1500.     if (strbufc.len <= 0 || ctlbuf[0] == M_DATA) {
  1501.         /* data message */
  1502.         if (strbufd.len > 0) {            /* real data */
  1503.             return(strbufd.len + 1);    /* count header char */
  1504.         } else {
  1505.             /* nothing there */
  1506.             errno = EAGAIN;
  1507.             return(-1);
  1508.         }
  1509.     }
  1510.  
  1511.     /*
  1512.      * It's a control message.  Return 1, to look at the flag we set
  1513.      */
  1514.  
  1515.     switch (ctlbuf[0]) {
  1516.     case M_FLUSH:
  1517.         if (ibuf[1] & FLUSHW)
  1518.             ibuf[0] = TIOCPKT_FLUSHWRITE;
  1519.         return(1);
  1520.  
  1521.     case M_IOCTL:
  1522.         ip = (struct iocblk *) (ibuf+1);
  1523.  
  1524.         switch (ip->ioc_cmd) {
  1525.         case TCSETS:
  1526.         case TCSETSW:
  1527.         case TCSETSF:
  1528.             tsp = (struct termios *)
  1529.                     (ibuf+1 + sizeof(struct iocblk));
  1530.             vstop = tsp->c_cc[VSTOP];
  1531.             vstart = tsp->c_cc[VSTART];
  1532.             ixon = tsp->c_iflag & IXON;
  1533.             break;
  1534.         case TCSETA:
  1535.         case TCSETAW:
  1536.         case TCSETAF:
  1537.             tp = (struct termio *) (ibuf+1 + sizeof(struct iocblk));
  1538.             vstop = tp->c_cc[VSTOP];
  1539.             vstart = tp->c_cc[VSTART];
  1540.             ixon = tp->c_iflag & IXON;      
  1541.             break;
  1542.         default:
  1543.             errno = EAGAIN;
  1544.             return(-1);
  1545.         }
  1546.  
  1547.         newflow =  (ixon && (vstart == 021) && (vstop == 023)) ? 1 : 0;
  1548.         if (newflow != flowison) {  /* it's a change */
  1549.             flowison = newflow;
  1550.             ibuf[0] = newflow ? TIOCPKT_DOSTOP : TIOCPKT_NOSTOP;
  1551.             return(1);
  1552.         }
  1553.     }
  1554.  
  1555.     /* nothing worth doing anything about */
  1556.     errno = EAGAIN;
  1557.     return(-1);
  1558. }
  1559. #endif /* STREAMSPTY */
  1560.  
  1561. /*
  1562.  * Send interrupt to process on other side of pty.
  1563.  * If it is in raw mode, just write NULL;
  1564.  * otherwise, write intr char.
  1565.  */
  1566.     void
  1567. interrupt()
  1568. {
  1569.     ptyflush();    /* half-hearted */
  1570.  
  1571. #if defined(STREAMSPTY) && defined(TIOCSIGNAL)
  1572.     /* Streams PTY style ioctl to post a signal */
  1573.     {
  1574.         int sig = SIGINT;
  1575.         (void) ioctl(pty, TIOCSIGNAL, &sig);
  1576.         (void) ioctl(pty, I_FLUSH, FLUSHR);
  1577.     }
  1578. #else
  1579. #ifdef    TCSIG
  1580.     (void) ioctl(pty, TCSIG, (char *)SIGINT);
  1581. #else    /* TCSIG */
  1582.     init_termbuf();
  1583.     *pfrontp++ = slctab[SLC_IP].sptr ?
  1584.             (unsigned char)*slctab[SLC_IP].sptr : '\177';
  1585. #endif    /* TCSIG */
  1586. #endif
  1587. }
  1588.  
  1589. /*
  1590.  * Send quit to process on other side of pty.
  1591.  * If it is in raw mode, just write NULL;
  1592.  * otherwise, write quit char.
  1593.  */
  1594.     void
  1595. sendbrk()
  1596. {
  1597.     ptyflush();    /* half-hearted */
  1598. #ifdef    TCSIG
  1599.     (void) ioctl(pty, TCSIG, (char *)SIGQUIT);
  1600. #else    /* TCSIG */
  1601.     init_termbuf();
  1602.     *pfrontp++ = slctab[SLC_ABORT].sptr ?
  1603.             (unsigned char)*slctab[SLC_ABORT].sptr : '\034';
  1604. #endif    /* TCSIG */
  1605. }
  1606.  
  1607.     void
  1608. sendsusp()
  1609. {
  1610. #ifdef    SIGTSTP
  1611.     ptyflush();    /* half-hearted */
  1612. # ifdef    TCSIG
  1613.     (void) ioctl(pty, TCSIG, (char *)SIGTSTP);
  1614. # else    /* TCSIG */
  1615.     *pfrontp++ = slctab[SLC_SUSP].sptr ?
  1616.             (unsigned char)*slctab[SLC_SUSP].sptr : '\032';
  1617. # endif    /* TCSIG */
  1618. #endif    /* SIGTSTP */
  1619. }
  1620.  
  1621. /*
  1622.  * When we get an AYT, if ^T is enabled, use that.  Otherwise,
  1623.  * just send back "[Yes]".
  1624.  */
  1625.     void
  1626. recv_ayt()
  1627. {
  1628. #if    defined(SIGINFO) && defined(TCSIG)
  1629.     if (slctab[SLC_AYT].sptr && *slctab[SLC_AYT].sptr != _POSIX_VDISABLE) {
  1630.         (void) ioctl(pty, TCSIG, (char *)SIGINFO);
  1631.         return;
  1632.     }
  1633. #endif
  1634.     (void) strcpy(nfrontp, "\r\n[Yes]\r\n");
  1635.     nfrontp += 9;
  1636. }
  1637.  
  1638.     void
  1639. doeof()
  1640. {
  1641.     init_termbuf();
  1642.  
  1643. #if    defined(LINEMODE) && defined(USE_TERMIO) && (VEOF == VMIN)
  1644.     if (!tty_isediting()) {
  1645.         extern char oldeofc;
  1646.         *pfrontp++ = oldeofc;
  1647.         return;
  1648.     }
  1649. #endif
  1650.     *pfrontp++ = slctab[SLC_EOF].sptr ?
  1651.             (unsigned char)*slctab[SLC_EOF].sptr : '\004';
  1652. }
  1653.