Annotation of 43BSDReno/libexec/telnetd/telnetd.c, revision 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.