Annotation of 43BSDReno/libexec/telnetd/telnetd.c, revision 1.1.1.1

1.1       root        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 are permitted provided
                      6:  * that: (1) source distributions retain this entire copyright notice and
                      7:  * comment, and (2) distributions including binaries display the following
                      8:  * acknowledgement:  ``This product includes software developed by the
                      9:  * University of California, Berkeley and its contributors'' in the
                     10:  * documentation or other materials provided with the distribution and in
                     11:  * all advertising materials mentioning features or use of this software.
                     12:  * Neither the name of the University nor the names of its contributors may
                     13:  * be used to endorse or promote products derived from this software without
                     14:  * specific prior written permission.
                     15:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
                     16:  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
                     17:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
                     18:  */
                     19: 
                     20: #ifndef lint
                     21: char copyright[] =
                     22: "@(#) Copyright (c) 1989 Regents of the University of California.\n\
                     23:  All rights reserved.\n";
                     24: #endif /* not lint */
                     25: 
                     26: #ifndef lint
                     27: static char sccsid[] = "@(#)telnetd.c  5.46 (Berkeley) 6/28/90";
                     28: #endif /* not lint */
                     29: 
                     30: #include "telnetd.h"
                     31: 
                     32: /*
                     33:  * I/O data buffers,
                     34:  * pointers, and counters.
                     35:  */
                     36: char   ptyibuf[BUFSIZ], *ptyip = ptyibuf;
                     37: char   ptyibuf2[BUFSIZ];
                     38: 
                     39: #ifdef CRAY
                     40: int    hostinfo = 1;                   /* do we print login banner? */
                     41: #endif
                     42: 
                     43: #ifdef CRAY
                     44: extern int      newmap; /* nonzero if \n maps to ^M^J */
                     45: int    lowpty = 0, highpty;    /* low, high pty numbers */
                     46: #endif /* CRAY */
                     47: 
                     48: int debug = 0;
                     49: char *progname;
                     50: 
                     51: #if    defined(NEED_GETTOS)
                     52: struct tosent {
                     53:        char    *t_name;        /* name */
                     54:        char    **t_aliases;    /* alias list */
                     55:        char    *t_proto;       /* protocol */
                     56:        int     t_tos;          /* Type Of Service bits */
                     57: };
                     58: 
                     59: struct tosent *
                     60: gettosbyname(name, proto)
                     61: char *name, *proto;
                     62: {
                     63:        static struct tosent te;
                     64:        static char *aliasp = 0;
                     65: 
                     66:        te.t_name = name;
                     67:        te.t_aliases = &aliasp;
                     68:        te.t_proto = proto;
                     69:        te.t_tos = 020; /* Low Delay bit */
                     70:        return(&te);
                     71: }
                     72: #endif
                     73: 
                     74: main(argc, argv)
                     75:        char *argv[];
                     76: {
                     77:        struct sockaddr_in from;
                     78:        int on = 1, fromlen;
                     79: #if    defined(HAS_IP_TOS) || defined(NEED_GETTOS)
                     80:        struct tosent *tp;
                     81: #endif /* defined(HAS_IP_TOS) || defined(NEED_GETTOS) */
                     82: 
                     83:        pfrontp = pbackp = ptyobuf;
                     84:        netip = netibuf;
                     85:        nfrontp = nbackp = netobuf;
                     86: 
                     87:        progname = *argv;
                     88: 
                     89: #ifdef CRAY
                     90:        /*
                     91:         * Get number of pty's before trying to process options,
                     92:         * which may include changing pty range.
                     93:         */
                     94:        highpty = getnpty();
                     95: #endif /* CRAY */
                     96: 
                     97: top:
                     98:        argc--, argv++;
                     99: 
                    100:        if (argc > 0 && strcmp(*argv, "-debug") == 0) {
                    101:                debug++;
                    102:                goto top;
                    103:        }
                    104: 
                    105: #ifdef LINEMODE
                    106:        if (argc > 0 && !strcmp(*argv, "-l")) {
                    107:                alwayslinemode = 1;
                    108:                goto top;
                    109:        }
                    110: #endif /* LINEMODE */
                    111: 
                    112: #ifdef CRAY
                    113:        if (argc > 0 && !strcmp(*argv, "-h")) {
                    114:                hostinfo = 0;
                    115:                goto top;
                    116:        }
                    117: 
                    118:        if (argc > 0 && !strncmp(*argv, "-r", 2)) {
                    119:                char *strchr();
                    120:                char *c;
                    121: 
                    122:                /*
                    123:                 * Allow the specification of alterations to the pty search
                    124:                 * range.  It is legal to specify only one, and not change the
                    125:                 * other from its default.
                    126:                 */
                    127:                *argv += 2;
                    128:                if (**argv == '\0' && argc)
                    129:                        argv++, argc--;
                    130:                c = strchr(*argv, '-');
                    131:                if (c) {
                    132:                        *c++ = '\0';
                    133:                        highpty = atoi(c);
                    134:                }
                    135:                if (**argv != '\0')
                    136:                        lowpty = atoi(*argv);
                    137:                if ((lowpty > highpty) || (lowpty < 0) || (highpty > 32767)) {
                    138:                        usage();
                    139:                        /* NOT REACHED */
                    140:                }
                    141:                goto top;
                    142:        }
                    143: # ifdef        NEWINIT
                    144:        if (argc > 0 && !strncmp(*argv, "-I", 2)) {
                    145:                extern char *gen_id;
                    146: 
                    147:                *argv += 2;
                    148:                if (**argv == '\0') {
                    149:                        if (argc < 2) {
                    150:                                usage();
                    151:                                /* NOT REACHED */
                    152:                        }
                    153:                        argv++, argc--;
                    154:                        if (**argv == '\0') {
                    155:                                usage();
                    156:                                /* NOT REACHED */
                    157:                        }
                    158:                }
                    159:                gen_id = *argv;
                    160:                goto top;
                    161:        }
                    162: # endif        /* NEWINIT */
                    163: #endif /* CRAY */
                    164: 
                    165: #ifdef DIAGNOSTICS
                    166:        /*
                    167:         * Check for desired diagnostics capabilities.
                    168:         */
                    169:        if (argc > 0 && !strncmp(*argv, "-D", 2)) {
                    170:                *argv += 2;
                    171:                if (**argv == '\0') {
                    172:                        if (argc < 2) {
                    173:                                usage();
                    174:                                /* NOT REACHED */
                    175:                        }
                    176:                        argv++, argc--;
                    177:                        if (**argv == '\0') {
                    178:                                usage();
                    179:                                /* NOT REACHED */
                    180:                        }
                    181:                }
                    182:                if (!strcmp(*argv, "report")) {
                    183:                        diagnostic |= TD_REPORT|TD_OPTIONS;
                    184:                } else if (!strcmp(*argv, "exercise")) {
                    185:                        diagnostic |= TD_EXERCISE;
                    186:                } else if (!strcmp(*argv, "netdata")) {
                    187:                        diagnostic |= TD_NETDATA;
                    188:                } else if (!strcmp(*argv, "ptydata")) {
                    189:                        diagnostic |= TD_PTYDATA;
                    190:                } else if (!strcmp(*argv, "options")) {
                    191:                        diagnostic |= TD_OPTIONS;
                    192:                } else {
                    193:                        usage();
                    194:                        /* NOT REACHED */
                    195:                }
                    196:                goto top;
                    197:        }
                    198: #endif /* DIAGNOSTICS */
                    199: 
                    200: #ifdef BFTPDAEMON
                    201:        /*
                    202:         * Check for bftp daemon
                    203:         */
                    204:        if (argc > 0 && !strncmp(*argv, "-B", 2)) {
                    205:                bftpd++;
                    206:                goto top;
                    207:        }
                    208: #endif /* BFTPDAEMON */
                    209: 
                    210:        if (argc > 0 && **argv == '-') {
                    211:                fprintf(stderr, "telnetd: %s: unknown option\n", *argv+1);
                    212:                usage();
                    213:                /* NOT REACHED */
                    214:        }
                    215: 
                    216:        if (debug) {
                    217:            int s, ns, foo;
                    218:            struct servent *sp;
                    219:            static struct sockaddr_in sin = { AF_INET };
                    220: 
                    221:            if (argc > 1) {
                    222:                usage();
                    223:                /* NOT REACHED */
                    224:            } else if (argc == 1) {
                    225:                    if (sp = getservbyname(*argv, "tcp")) {
                    226:                        sin.sin_port = sp->s_port;
                    227:                    } else {
                    228:                        sin.sin_port = atoi(*argv);
                    229:                        if ((int)sin.sin_port <= 0) {
                    230:                            fprintf(stderr, "telnetd: %s: bad port #\n", *argv);
                    231:                            usage();
                    232:                            /* NOT REACHED */
                    233:                        }
                    234:                        sin.sin_port = htons((u_short)sin.sin_port);
                    235:                   }
                    236:            } else {
                    237:                sp = getservbyname("telnet", "tcp");
                    238:                if (sp == 0) {
                    239:                    fprintf(stderr, "telnetd: tcp/telnet: unknown service\n");
                    240:                    exit(1);
                    241:                }
                    242:                sin.sin_port = sp->s_port;
                    243:            }
                    244: 
                    245:            s = socket(AF_INET, SOCK_STREAM, 0);
                    246:            if (s < 0) {
                    247:                    perror("telnetd: socket");;
                    248:                    exit(1);
                    249:            }
                    250:            (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
                    251:            if (bind(s, (struct sockaddr *)&sin, sizeof sin) < 0) {
                    252:                perror("bind");
                    253:                exit(1);
                    254:            }
                    255:            if (listen(s, 1) < 0) {
                    256:                perror("listen");
                    257:                exit(1);
                    258:            }
                    259:            foo = sizeof sin;
                    260:            ns = accept(s, (struct sockaddr *)&sin, &foo);
                    261:            if (ns < 0) {
                    262:                perror("accept");
                    263:                exit(1);
                    264:            }
                    265:            (void) dup2(ns, 0);
                    266:            (void) close(ns);
                    267:            (void) close(s);
                    268:        } else if (argc > 0) {
                    269:                usage();
                    270:                /* NOT REACHED */
                    271:        }
                    272: 
                    273:        openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
                    274:        fromlen = sizeof (from);
                    275:        if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
                    276:                fprintf(stderr, "%s: ", progname);
                    277:                perror("getpeername");
                    278:                _exit(1);
                    279:        }
                    280:        if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) {
                    281:                syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
                    282:        }
                    283: 
                    284: #if    defined(HAS_IP_TOS) || defined(NEED_GETTOS)
                    285:        if ((tp = gettosbyname("telnet", "tcp")) &&
                    286:            (setsockopt(0, IPPROTO_IP, IP_TOS, &tp->t_tos, sizeof(int)) < 0))
                    287:                syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
                    288: #endif /* defined(HAS_IP_TOS) || defined(NEED_GETTOS) */
                    289:        net = 0;
                    290:        doit(&from);
                    291:        /* NOTREACHED */
                    292: }  /* end of main */
                    293: 
                    294: usage()
                    295: {
                    296:        fprintf(stderr, "Usage: telnetd [-debug] [-h]");
                    297: #ifdef NEWINIT
                    298:        fprintf(stderr, " [-Iinitid]");
                    299: #endif /* NEWINIT */
                    300: #ifdef DIAGNOSTICS
                    301:        fprintf(stderr, " [-D (options|report|exercise|netdata|ptydata)]");
                    302: #endif /* DIAGNOSTICS */
                    303: #ifdef LINEMODE
                    304:        fprintf(stderr, " [-l]");
                    305: #endif
                    306: #ifdef CRAY
                    307:        fprintf(stderr, " [-r[lowpty]-[highpty]]");
                    308: #endif
                    309: #ifdef BFTPDAEMON
                    310:        fprintf(stderr, " [-B]");
                    311: #endif /* BFTPDAEMON */
                    312:        fprintf(stderr, " [port]\n");
                    313:        exit(1);
                    314: }
                    315: 
                    316: void   cleanup();
                    317: 
                    318: /*
                    319:  * getterminaltype
                    320:  *
                    321:  *     Ask the other end to send along its terminal type and speed.
                    322:  * Output is the variable terminaltype filled in.
                    323:  */
                    324: static char ttytype_sbbuf[] = { IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE };
                    325: void
                    326: getterminaltype()
                    327: {
                    328:     void ttloop();
                    329: 
                    330:     settimer(baseline);
                    331:     send_do(TELOPT_TTYPE, 1);
                    332:     send_do(TELOPT_TSPEED, 1);
                    333:     send_do(TELOPT_XDISPLOC, 1);
                    334:     send_do(TELOPT_ENVIRON, 1);
                    335:     while (his_will_wont_is_changing(TELOPT_TTYPE) ||
                    336:           his_will_wont_is_changing(TELOPT_TSPEED) ||
                    337:           his_will_wont_is_changing(TELOPT_XDISPLOC) ||
                    338:           his_will_wont_is_changing(TELOPT_ENVIRON)) {
                    339:        ttloop();
                    340:     }
                    341:     if (his_state_is_will(TELOPT_TSPEED)) {
                    342:        static char sbbuf[] = { IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE };
                    343: 
                    344:        bcopy(sbbuf, nfrontp, sizeof sbbuf);
                    345:        nfrontp += sizeof sbbuf;
                    346:     }
                    347:     if (his_state_is_will(TELOPT_XDISPLOC)) {
                    348:        static char sbbuf[] = { IAC, SB, TELOPT_XDISPLOC, TELQUAL_SEND, IAC, SE };
                    349: 
                    350:        bcopy(sbbuf, nfrontp, sizeof sbbuf);
                    351:        nfrontp += sizeof sbbuf;
                    352:     }
                    353:     if (his_state_is_will(TELOPT_ENVIRON)) {
                    354:        static char sbbuf[] = { IAC, SB, TELOPT_ENVIRON, TELQUAL_SEND, IAC, SE };
                    355: 
                    356:        bcopy(sbbuf, nfrontp, sizeof sbbuf);
                    357:        nfrontp += sizeof sbbuf;
                    358:     }
                    359:     if (his_state_is_will(TELOPT_TTYPE)) {
                    360: 
                    361:        bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf);
                    362:        nfrontp += sizeof ttytype_sbbuf;
                    363:     }
                    364:     if (his_state_is_will(TELOPT_TSPEED)) {
                    365:        while (sequenceIs(tspeedsubopt, baseline))
                    366:            ttloop();
                    367:     }
                    368:     if (his_state_is_will(TELOPT_XDISPLOC)) {
                    369:        while (sequenceIs(xdisplocsubopt, baseline))
                    370:            ttloop();
                    371:     }
                    372:     if (his_state_is_will(TELOPT_ENVIRON)) {
                    373:        while (sequenceIs(environsubopt, baseline))
                    374:            ttloop();
                    375:     }
                    376:     if (his_state_is_will(TELOPT_TTYPE)) {
                    377:        char first[256], last[256];
                    378: 
                    379:        while (sequenceIs(ttypesubopt, baseline))
                    380:            ttloop();
                    381: 
                    382:        /*
                    383:         * If the other side has already disabled the option, then
                    384:         * we have to just go with what we (might) have already gotten.
                    385:         */
                    386:        if (his_state_is_will(TELOPT_TTYPE) && !terminaltypeok(terminaltype)) {
                    387:            (void) strncpy(first, terminaltype, sizeof(first));
                    388:            for(;;) {
                    389:                /*
                    390:                 * Save the unknown name, and request the next name.
                    391:                 */
                    392:                (void) strncpy(last, terminaltype, sizeof(last));
                    393:                _gettermname();
                    394:                if (terminaltypeok(terminaltype))
                    395:                    break;
                    396:                if ((strncmp(last, terminaltype, sizeof(last)) == 0) ||
                    397:                    his_state_is_wont(TELOPT_TTYPE)) {
                    398:                    /*
                    399:                     * We've hit the end.  If this is the same as
                    400:                     * the first name, just go with it.
                    401:                     */
                    402:                    if (strncmp(first, terminaltype, sizeof(first) == 0))
                    403:                        break;
                    404:                    /*
                    405:                     * Get the terminal name one more time, so that
                    406:                     * RFC1091 compliant telnets will cycle back to
                    407:                     * the start of the list.
                    408:                     */
                    409:                     _gettermname();
                    410:                    if (strncmp(first, terminaltype, sizeof(first) != 0))
                    411:                        (void) strncpy(terminaltype, first, sizeof(first));
                    412:                    break;
                    413:                }
                    414:            }
                    415:        }
                    416:     }
                    417: }  /* end of getterminaltype */
                    418: 
                    419: _gettermname()
                    420: {
                    421:     /*
                    422:      * If the client turned off the option,
                    423:      * we can't send another request, so we
                    424:      * just return.
                    425:      */
                    426:     if (his_state_is_wont(TELOPT_TTYPE))
                    427:        return;
                    428:     settimer(baseline);
                    429:     bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf);
                    430:     nfrontp += sizeof ttytype_sbbuf;
                    431:     while (sequenceIs(ttypesubopt, baseline))
                    432:        ttloop();
                    433: }
                    434: 
                    435: terminaltypeok(s)
                    436: char *s;
                    437: {
                    438:     char buf[1024];
                    439: 
                    440:     if (terminaltype == NULL)
                    441:        return(1);
                    442: 
                    443:     /*
                    444:      * tgetent() will return 1 if the type is known, and
                    445:      * 0 if it is not known.  If it returns -1, it couldn't
                    446:      * open the database.  But if we can't open the database,
                    447:      * it won't help to say we failed, because we won't be
                    448:      * able to verify anything else.  So, we treat -1 like 1.
                    449:      */
                    450:     if (tgetent(buf, s) == 0)
                    451:        return(0);
                    452:     return(1);
                    453: }
                    454: 
                    455: /*
                    456:  * Get a pty, scan input lines.
                    457:  */
                    458: doit(who)
                    459:        struct sockaddr_in *who;
                    460: {
                    461:        char *host, *inet_ntoa();
                    462:        int t;
                    463:        struct hostent *hp;
                    464: #if BSD > 43
                    465:        extern char *line;
                    466: 
                    467:        if (openpty(&pty, &t, line, NULL, NULL) == -1)
                    468:                fatal(net, "All network ports in use");
                    469:        init_termbuf();
                    470: #else
                    471:        
                    472:        /*
                    473:         * Find an available pty to use.
                    474:         */
                    475:        pty = getpty();
                    476:        if (pty < 0)
                    477:                fatal(net, "All network ports in use");
                    478: 
                    479:        t = getptyslave();
                    480: #endif
                    481: 
                    482:        /* get name of connected client */
                    483:        hp = gethostbyaddr((char *)&who->sin_addr, sizeof (struct in_addr),
                    484:                who->sin_family);
                    485:        if (hp)
                    486:                host = hp->h_name;
                    487:        else
                    488:                host = inet_ntoa(who->sin_addr);
                    489: 
                    490:        init_env();
                    491:        /*
                    492:         * get terminal type.
                    493:         */
                    494:        getterminaltype();
                    495:        setenv("TERM", terminaltype ? terminaltype : "network", 1);
                    496: 
                    497:        /*
                    498:         * Start up the login process on the slave side of the terminal
                    499:         */
                    500:        startslave(t, host);
                    501: 
                    502:        telnet(net, pty);  /* begin server processing */
                    503:        /*NOTREACHED*/
                    504: }  /* end of doit */
                    505: 
                    506: #ifndef        MAXHOSTNAMELEN
                    507: #define        MAXHOSTNAMELEN 64
                    508: #endif MAXHOSTNAMELEN
                    509: /*
                    510:  * Main loop.  Select from pty and network, and
                    511:  * hand data to telnet receiver finite state machine.
                    512:  */
                    513: telnet(f, p)
                    514: int f, p;
                    515: {
                    516:        int on = 1;
                    517:        char hostname[MAXHOSTNAMELEN];
                    518: #if    defined(CRAY2) && defined(UNICOS5)
                    519:        int termstat();
                    520:        int interrupt(), sendbrk();
                    521: #endif
                    522: #define        TABBUFSIZ       512
                    523:        char    defent[TABBUFSIZ];
                    524:        char    defstrs[TABBUFSIZ];
                    525: #undef TABBUFSIZ
                    526:        char *HE;
                    527:        char *HN;
                    528:        char *IM;
                    529:        void netflush();
                    530:        
                    531:        /*
                    532:         * Initialize the slc mapping table.
                    533:         */
                    534:        get_slc_defaults();
                    535: 
                    536:        /*
                    537:         * Do some tests where it is desireable to wait for a response.
                    538:         * Rather than doing them slowly, one at a time, do them all
                    539:         * at once.
                    540:         */
                    541:        if (my_state_is_wont(TELOPT_SGA))
                    542:                send_will(TELOPT_SGA, 1);
                    543:        /*
                    544:         * Is the client side a 4.2 (NOT 4.3) system?  We need to know this
                    545:         * because 4.2 clients are unable to deal with TCP urgent data.
                    546:         *
                    547:         * To find out, we send out a "DO ECHO".  If the remote system
                    548:         * answers "WILL ECHO" it is probably a 4.2 client, and we note
                    549:         * that fact ("WILL ECHO" ==> that the client will echo what
                    550:         * WE, the server, sends it; it does NOT mean that the client will
                    551:         * echo the terminal input).
                    552:         */
                    553:        send_do(TELOPT_ECHO, 1);
                    554: 
                    555: #ifdef LINEMODE
                    556:        if (his_state_is_wont(TELOPT_LINEMODE)) {
                    557:                /* Query the peer for linemode support by trying to negotiate
                    558:                 * the linemode option.
                    559:                 */
                    560:                linemode = 0;
                    561:                editmode = 0;
                    562:                send_do(TELOPT_LINEMODE, 1);  /* send do linemode */
                    563:        }
                    564: #endif /* LINEMODE */
                    565: 
                    566:        /*
                    567:         * Send along a couple of other options that we wish to negotiate.
                    568:         */
                    569:        send_do(TELOPT_NAWS, 1);
                    570:        send_will(TELOPT_STATUS, 1);
                    571:        flowmode = 1;  /* default flow control state */
                    572:        send_do(TELOPT_LFLOW, 1);
                    573: 
                    574:        /*
                    575:         * Spin, waiting for a response from the DO ECHO.  However,
                    576:         * some REALLY DUMB telnets out there might not respond
                    577:         * to the DO ECHO.  So, we spin looking for NAWS, (most dumb
                    578:         * telnets so far seem to respond with WONT for a DO that
                    579:         * they don't understand...) because by the time we get the
                    580:         * response, it will already have processed the DO ECHO.
                    581:         * Kludge upon kludge.
                    582:         */
                    583:        while (his_will_wont_is_changing(TELOPT_NAWS))
                    584:                ttloop();
                    585: 
                    586:        /*
                    587:         * But...
                    588:         * The client might have sent a WILL NAWS as part of its
                    589:         * startup code; if so, we'll be here before we get the
                    590:         * response to the DO ECHO.  We'll make the assumption
                    591:         * that any implementation that understands about NAWS
                    592:         * is a modern enough implementation that it will respond
                    593:         * to our DO ECHO request; hence we'll do another spin
                    594:         * waiting for the ECHO option to settle down, which is
                    595:         * what we wanted to do in the first place...
                    596:         */
                    597:        if (his_want_state_is_will(TELOPT_ECHO) &&
                    598:            his_state_is_will(TELOPT_NAWS)) {
                    599:                while (his_will_wont_is_changing(TELOPT_ECHO))
                    600:                        ttloop();
                    601:        }
                    602:        /*
                    603:         * On the off chance that the telnet client is broken and does not
                    604:         * respond to the DO ECHO we sent, (after all, we did send the
                    605:         * DO NAWS negotiation after the DO ECHO, and we won't get here
                    606:         * until a response to the DO NAWS comes back) simulate the
                    607:         * receipt of a will echo.  This will also send a WONT ECHO
                    608:         * to the client, since we assume that the client failed to
                    609:         * respond because it believes that it is already in DO ECHO
                    610:         * mode, which we do not want.
                    611:         */
                    612:        if (his_want_state_is_will(TELOPT_ECHO)) {
                    613: #ifdef DIAGNOSTICS
                    614:                if (diagnostic & TD_OPTIONS) {
                    615:                        sprintf(nfrontp, "td: simulating recv\r\n");
                    616:                        nfrontp += strlen(nfrontp);
                    617:                }
                    618: #endif /* DIAGNOSTICS */
                    619:                willoption(TELOPT_ECHO);
                    620:        }
                    621: 
                    622:        /*
                    623:         * Finally, to clean things up, we turn on our echo.  This
                    624:         * will break stupid 4.2 telnets out of local terminal echo.
                    625:         */
                    626: 
                    627:        if (my_state_is_wont(TELOPT_ECHO))
                    628:                send_will(TELOPT_ECHO, 1);
                    629: 
                    630:        /*
                    631:         * Turn on packet mode, and default to line at at time mode.
                    632:         */
                    633:        (void) ioctl(p, TIOCPKT, (char *)&on);
                    634: #ifdef LINEMODE
                    635:        tty_setlinemode(1);
                    636: 
                    637: # ifdef        KLUDGELINEMODE
                    638:        /*
                    639:         * Continuing line mode support.  If client does not support
                    640:         * real linemode, attempt to negotiate kludge linemode by sending
                    641:         * the do timing mark sequence.
                    642:         */
                    643:        if (lmodetype < REAL_LINEMODE)
                    644:                send_do(TELOPT_TM, 1);
                    645: # endif        /* KLUDGELINEMODE */
                    646: #endif /* LINEMODE */
                    647: 
                    648:        /*
                    649:         * Call telrcv() once to pick up anything received during
                    650:         * terminal type negotiation, 4.2/4.3 determination, and
                    651:         * linemode negotiation.
                    652:         */
                    653:        telrcv();
                    654: 
                    655:        (void) ioctl(f, FIONBIO, (char *)&on);
                    656:        (void) ioctl(p, FIONBIO, (char *)&on);
                    657: #if    defined(CRAY2) && defined(UNICOS5)
                    658:        init_termdriver(f, p, interrupt, sendbrk);
                    659: #endif
                    660: 
                    661: #if    defined(SO_OOBINLINE)
                    662:        (void) setsockopt(net, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
                    663: #endif /* defined(SO_OOBINLINE) */
                    664: 
                    665: #ifdef SIGTSTP
                    666:        (void) signal(SIGTSTP, SIG_IGN);
                    667: #endif
                    668: #ifdef SIGTTOU
                    669:        /*
                    670:         * Ignoring SIGTTOU keeps the kernel from blocking us
                    671:         * in ttioct() in /sys/tty.c.
                    672:         */
                    673:        (void) signal(SIGTTOU, SIG_IGN);
                    674: #endif
                    675: 
                    676:        (void) signal(SIGCHLD, cleanup);
                    677: 
                    678: #if    defined(CRAY2) && defined(UNICOS5)
                    679:        /*
                    680:         * Cray-2 will send a signal when pty modes are changed by slave
                    681:         * side.  Set up signal handler now.
                    682:         */
                    683:        if ((int)signal(SIGUSR1, termstat) < 0)
                    684:                perror("signal");
                    685:        else if (ioctl(p, TCSIGME, (char *)SIGUSR1) < 0)
                    686:                perror("ioctl:TCSIGME");
                    687:        /*
                    688:         * Make processing loop check terminal characteristics early on.
                    689:         */
                    690:        termstat();
                    691: #endif
                    692: 
                    693: #ifdef NO_SETSID
                    694:        (void) setpgrp(0, 0);
                    695: #else
                    696:        (void) setsid();
                    697: #endif
                    698: #if    defined(TIOCSCTTY) && defined(CRAY)
                    699:        ioctl(p, TIOCSCTTY, 0);
                    700: #endif
                    701: 
                    702:        /*
                    703:         * Show banner that getty never gave.
                    704:         *
                    705:         * We put the banner in the pty input buffer.  This way, it
                    706:         * gets carriage return null processing, etc., just like all
                    707:         * other pty --> client data.
                    708:         */
                    709: 
                    710:        (void) gethostname(hostname, sizeof (hostname));
                    711: 
                    712:        if (getent(defent, "default") == 1) {
                    713:                char *getstr();
                    714:                char *cp=defstrs;
                    715: 
                    716:                HE = getstr("he", &cp);
                    717:                HN = getstr("hn", &cp);
                    718:                IM = getstr("im", &cp);
                    719:                if (HN && *HN)
                    720:                        (void) strcpy(hostname, HN);
                    721:                if (IM == 0)
                    722:                        IM = "";
                    723:        } else {
                    724: #ifdef CRAY
                    725:                if (hostinfo == 0)
                    726:                        IM = 0;
                    727:                else
                    728: #endif
                    729:                        IM = DEFAULT_IM;
                    730:                HE = 0;
                    731:        }
                    732:        edithost(HE, hostname);
                    733:        if (IM && *IM)
                    734:                putf(IM, ptyibuf2);
                    735: 
                    736:        if (pcc)
                    737:                (void) strncat(ptyibuf2, ptyip, pcc+1);
                    738:        ptyip = ptyibuf2;
                    739:        pcc = strlen(ptyip);
                    740: #ifdef LINEMODE
                    741:        /*
                    742:         * Last check to make sure all our states are correct.
                    743:         */
                    744:        init_termbuf();
                    745:        localstat();
                    746: #endif /* LINEMODE */
                    747: 
                    748: #ifdef DIAGNOSTICS
                    749:        if (diagnostic & TD_REPORT) {
                    750:                sprintf(nfrontp, "td: Entering processing loop\r\n");
                    751:                nfrontp += strlen(nfrontp);
                    752:        }
                    753: #endif /* DIAGNOSTICS */
                    754: 
                    755:        for (;;) {
                    756:                fd_set ibits, obits, xbits;
                    757:                register int c;
                    758: 
                    759:                if (ncc < 0 && pcc < 0)
                    760:                        break;
                    761: 
                    762: #if    defined(CRAY2) && defined(UNICOS5)
                    763:                if (needtermstat)
                    764:                        _termstat();
                    765: #endif /* defined(CRAY2) && defined(UNICOS5) */
                    766:                FD_ZERO(&ibits);
                    767:                FD_ZERO(&obits);
                    768:                FD_ZERO(&xbits);
                    769:                /*
                    770:                 * Never look for input if there's still
                    771:                 * stuff in the corresponding output buffer
                    772:                 */
                    773:                if (nfrontp - nbackp || pcc > 0) {
                    774:                        FD_SET(f, &obits);
                    775:                } else {
                    776:                        FD_SET(p, &ibits);
                    777:                }
                    778:                if (pfrontp - pbackp || ncc > 0) {
                    779:                        FD_SET(p, &obits);
                    780:                } else {
                    781:                        FD_SET(f, &ibits);
                    782:                }
                    783:                if (!SYNCHing) {
                    784:                        FD_SET(f, &xbits);
                    785:                }
                    786:                if ((c = select(16, &ibits, &obits, &xbits,
                    787:                                                (struct timeval *)0)) < 1) {
                    788:                        if (c == -1) {
                    789:                                if (errno == EINTR) {
                    790:                                        continue;
                    791:                                }
                    792:                        }
                    793:                        sleep(5);
                    794:                        continue;
                    795:                }
                    796: 
                    797:                /*
                    798:                 * Any urgent data?
                    799:                 */
                    800:                if (FD_ISSET(net, &xbits)) {
                    801:                    SYNCHing = 1;
                    802:                }
                    803: 
                    804:                /*
                    805:                 * Something to read from the network...
                    806:                 */
                    807:                if (FD_ISSET(net, &ibits)) {
                    808: #if    !defined(SO_OOBINLINE)
                    809:                        /*
                    810:                         * In 4.2 (and 4.3 beta) systems, the
                    811:                         * OOB indication and data handling in the kernel
                    812:                         * is such that if two separate TCP Urgent requests
                    813:                         * come in, one byte of TCP data will be overlaid.
                    814:                         * This is fatal for Telnet, but we try to live
                    815:                         * with it.
                    816:                         *
                    817:                         * In addition, in 4.2 (and...), a special protocol
                    818:                         * is needed to pick up the TCP Urgent data in
                    819:                         * the correct sequence.
                    820:                         *
                    821:                         * What we do is:  if we think we are in urgent
                    822:                         * mode, we look to see if we are "at the mark".
                    823:                         * If we are, we do an OOB receive.  If we run
                    824:                         * this twice, we will do the OOB receive twice,
                    825:                         * but the second will fail, since the second
                    826:                         * time we were "at the mark", but there wasn't
                    827:                         * any data there (the kernel doesn't reset
                    828:                         * "at the mark" until we do a normal read).
                    829:                         * Once we've read the OOB data, we go ahead
                    830:                         * and do normal reads.
                    831:                         *
                    832:                         * There is also another problem, which is that
                    833:                         * since the OOB byte we read doesn't put us
                    834:                         * out of OOB state, and since that byte is most
                    835:                         * likely the TELNET DM (data mark), we would
                    836:                         * stay in the TELNET SYNCH (SYNCHing) state.
                    837:                         * So, clocks to the rescue.  If we've "just"
                    838:                         * received a DM, then we test for the
                    839:                         * presence of OOB data when the receive OOB
                    840:                         * fails (and AFTER we did the normal mode read
                    841:                         * to clear "at the mark").
                    842:                         */
                    843:                    if (SYNCHing) {
                    844:                        int atmark;
                    845: 
                    846:                        (void) ioctl(net, SIOCATMARK, (char *)&atmark);
                    847:                        if (atmark) {
                    848:                            ncc = recv(net, netibuf, sizeof (netibuf), MSG_OOB);
                    849:                            if ((ncc == -1) && (errno == EINVAL)) {
                    850:                                ncc = read(net, netibuf, sizeof (netibuf));
                    851:                                if (sequenceIs(didnetreceive, gotDM)) {
                    852:                                    SYNCHing = stilloob(net);
                    853:                                }
                    854:                            }
                    855:                        } else {
                    856:                            ncc = read(net, netibuf, sizeof (netibuf));
                    857:                        }
                    858:                    } else {
                    859:                        ncc = read(net, netibuf, sizeof (netibuf));
                    860:                    }
                    861:                    settimer(didnetreceive);
                    862: #else  /* !defined(SO_OOBINLINE)) */
                    863:                    ncc = read(net, netibuf, sizeof (netibuf));
                    864: #endif /* !defined(SO_OOBINLINE)) */
                    865:                    if (ncc < 0 && errno == EWOULDBLOCK)
                    866:                        ncc = 0;
                    867:                    else {
                    868:                        if (ncc <= 0) {
                    869:                            break;
                    870:                        }
                    871:                        netip = netibuf;
                    872:                    }
                    873: #ifdef DIAGNOSTICS
                    874:                    if (diagnostic & (TD_REPORT | TD_NETDATA)) {
                    875:                            sprintf(nfrontp, "td: netread %d chars\r\n", ncc);
                    876:                            nfrontp += strlen(nfrontp);
                    877:                    }
                    878:                    if (diagnostic & TD_NETDATA) {
                    879:                            printdata("nd", netip, ncc);
                    880:                    }
                    881: #endif /* DIAGNOSTICS */
                    882:                }
                    883: 
                    884:                /*
                    885:                 * Something to read from the pty...
                    886:                 */
                    887:                if (FD_ISSET(p, &ibits)) {
                    888:                        pcc = read(p, ptyibuf, BUFSIZ);
                    889:                        if (pcc < 0 && errno == EWOULDBLOCK)
                    890:                                pcc = 0;
                    891:                        else {
                    892:                                if (pcc <= 0)
                    893:                                        break;
                    894: #if    !defined(CRAY2) || !defined(UNICOS5)
                    895: #ifdef LINEMODE
                    896:                                /*
                    897:                                 * If ioctl from pty, pass it through net
                    898:                                 */
                    899:                                if (ptyibuf[0] & TIOCPKT_IOCTL) {
                    900:                                        copy_termbuf(ptyibuf+1, pcc-1);
                    901:                                        localstat();
                    902:                                        pcc = 1;
                    903:                                }
                    904: #endif LINEMODE
                    905:                                if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) {
                    906:                                        netclear();     /* clear buffer back */
                    907: #ifdef notdef
                    908:                                        /*
                    909:                                         * We really should have this in, but
                    910:                                         * there are client telnets on some
                    911:                                         * operating systems get screwed up
                    912:                                         * royally if we send them urgent
                    913:                                         * mode data.  So, for now, we'll not
                    914:                                         * do this...
                    915:                                         */
                    916:                                        *nfrontp++ = IAC;
                    917:                                        *nfrontp++ = DM;
                    918:                                        neturg = nfrontp-1; /* off by one XXX */
                    919: #endif
                    920:                                }
                    921:                                if (his_state_is_will(TELOPT_LFLOW) &&
                    922:                                    (ptyibuf[0] &
                    923:                                     (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))) {
                    924:                                        (void) sprintf(nfrontp, "%c%c%c%c%c%c",
                    925:                                            IAC, SB, TELOPT_LFLOW,
                    926:                                            ptyibuf[0] & TIOCPKT_DOSTOP ? 1 : 0,
                    927:                                            IAC, SE);
                    928:                                        nfrontp += 6;
                    929:                                }
                    930:                                pcc--;
                    931:                                ptyip = ptyibuf+1;
                    932: #else  /* defined(CRAY2) && defined(UNICOS5) */
                    933:                                if (!uselinemode) {
                    934:                                        unpcc = pcc;
                    935:                                        unptyip = ptyibuf;
                    936:                                        pcc = term_output(&unptyip, ptyibuf2,
                    937:                                                                &unpcc, BUFSIZ);
                    938:                                        ptyip = ptyibuf2;
                    939:                                } else
                    940:                                        ptyip = ptyibuf;
                    941: #endif /* defined(CRAY2) && defined(UNICOS5) */
                    942:                        }
                    943:                }
                    944: 
                    945:                while (pcc > 0) {
                    946:                        if ((&netobuf[BUFSIZ] - nfrontp) < 2)
                    947:                                break;
                    948:                        c = *ptyip++ & 0377, pcc--;
                    949:                        if (c == IAC)
                    950:                                *nfrontp++ = c;
                    951: #if    defined(CRAY2) && defined(UNICOS5)
                    952:                        else if (c == '\n' &&
                    953:                                     my_state_is_wont(TELOPT_BINARY) && newmap)
                    954:                                *nfrontp++ = '\r';
                    955: #endif /* defined(CRAY2) && defined(UNICOS5) */
                    956:                        *nfrontp++ = c;
                    957:                        if ((c == '\r') && (my_state_is_wont(TELOPT_BINARY))) {
                    958:                                if (pcc > 0 && ((*ptyip & 0377) == '\n')) {
                    959:                                        *nfrontp++ = *ptyip++ & 0377;
                    960:                                        pcc--;
                    961:                                } else
                    962:                                        *nfrontp++ = '\0';
                    963:                        }
                    964:                }
                    965: #if    defined(CRAY2) && defined(UNICOS5)
                    966:                /*
                    967:                 * If chars were left over from the terminal driver,
                    968:                 * note their existence.
                    969:                 */
                    970:                 if (!uselinemode && unpcc) {
                    971:                        pcc = unpcc;
                    972:                        unpcc = 0;
                    973:                        ptyip = unptyip;
                    974:                }
                    975: #endif /* defined(CRAY2) && defined(UNICOS5) */
                    976: 
                    977:                if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0)
                    978:                        netflush();
                    979:                if (ncc > 0)
                    980:                        telrcv();
                    981:                if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0)
                    982:                        ptyflush();
                    983:        }
                    984:        cleanup();
                    985: }  /* end of telnet */
                    986:        
                    987: #ifndef        TCSIG
                    988: # ifdef        TIOCSIG
                    989: #  define TCSIG TIOCSIG
                    990: # endif
                    991: #endif
                    992: 
                    993: /*
                    994:  * Send interrupt to process on other side of pty.
                    995:  * If it is in raw mode, just write NULL;
                    996:  * otherwise, write intr char.
                    997:  */
                    998: interrupt()
                    999: {
                   1000:        ptyflush();     /* half-hearted */
                   1001: 
                   1002: #ifdef TCSIG
                   1003:        (void) ioctl(pty, TCSIG, (char *)SIGINT);
                   1004: #else  /* TCSIG */
                   1005:        init_termbuf();
                   1006:        *pfrontp++ = slctab[SLC_IP].sptr ?
                   1007:                        (unsigned char)*slctab[SLC_IP].sptr : '\177';
                   1008: #endif /* TCSIG */
                   1009: }
                   1010: 
                   1011: /*
                   1012:  * Send quit to process on other side of pty.
                   1013:  * If it is in raw mode, just write NULL;
                   1014:  * otherwise, write quit char.
                   1015:  */
                   1016: sendbrk()
                   1017: {
                   1018:        ptyflush();     /* half-hearted */
                   1019: #ifdef TCSIG
                   1020:        (void) ioctl(pty, TCSIG, (char *)SIGQUIT);
                   1021: #else  /* TCSIG */
                   1022:        init_termbuf();
                   1023:        *pfrontp++ = slctab[SLC_ABORT].sptr ?
                   1024:                        (unsigned char)*slctab[SLC_ABORT].sptr : '\034';
                   1025: #endif /* TCSIG */
                   1026: }
                   1027: 
                   1028: sendsusp()
                   1029: {
                   1030: #ifdef SIGTSTP
                   1031:        ptyflush();     /* half-hearted */
                   1032: # ifdef        TCSIG
                   1033:        (void) ioctl(pty, TCSIG, (char *)SIGTSTP);
                   1034: # else /* TCSIG */
                   1035:        *pfrontp++ = slctab[SLC_SUSP].sptr ?
                   1036:                        (unsigned char)*slctab[SLC_SUSP].sptr : '\032';
                   1037: # endif        /* TCSIG */
                   1038: #endif /* SIGTSTP */
                   1039: }
                   1040: 
                   1041: doeof()
                   1042: {
                   1043: #if    defined(USE_TERMIO) && defined(SYSV_TERMIO)
                   1044:        extern char oldeofc;
                   1045: #endif
                   1046:        init_termbuf();
                   1047: 
                   1048: #if    defined(USE_TERMIO) && defined(SYSV_TERMIO)
                   1049:        if (!tty_isediting()) {
                   1050:                *pfrontp++ = oldeofc;
                   1051:                return;
                   1052:        }
                   1053: #endif
                   1054:        *pfrontp++ = slctab[SLC_EOF].sptr ?
                   1055:                        (unsigned char)*slctab[SLC_EOF].sptr : '\004';
                   1056: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.