]> git.saurik.com Git - apple/network_cmds.git/blobdiff - telnetd.tproj/telnetd.c
network_cmds-85.tar.gz
[apple/network_cmds.git] / telnetd.tproj / telnetd.c
index 01943a4cb566749440fccc5c28ff49ac39396f7c..6f7777f5a61c14baba267a3d18ecbde5f85f969c 100644 (file)
@@ -1,26 +1,3 @@
-/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * "Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
- * Reserved.  This file contains Original Code and/or Modifications of
- * Original Code as defined in and that are subject to the Apple Public
- * Source License Version 1.0 (the 'License').  You may not use this file
- * except in compliance with the License.  Please obtain a copy of the
- * License at http://www.apple.com/publicsource and read it before using
- * this file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
- * License for the specific language governing rights and limitations
- * under the License."
- * 
- * @APPLE_LICENSE_HEADER_END@
- */
 /*
  * Copyright (c) 1989, 1993
  *     The Regents of the University of California.  All rights reserved.
  */
 
 #ifndef lint
-static char copyright[] =
+static const char copyright[] =
 "@(#) Copyright (c) 1989, 1993\n\
        The Regents of the University of California.  All rights reserved.\n";
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)telnetd.c  8.4 (Berkeley) 5/30/95";
+#if 0
+static char sccsid[] = "@(#)telnetd.c  8.2 (Berkeley) 12/15/93";
+#endif
+static const char rcsid[] =
+  "$FreeBSD: src/libexec/telnetd/telnetd.c,v 1.28 2001/07/20 15:14:03 ru Exp $";
 #endif /* not lint */
 
 #include "telnetd.h"
@@ -76,6 +57,14 @@ static char sccsid[] = "@(#)telnetd.c        8.4 (Berkeley) 5/30/95";
 # undef _SC_CRAY_SECURE_SYS
 #endif
 
+#include <err.h>
+#include <arpa/inet.h>
+#include <util.h>
+#include <sys/mman.h>
+#include <paths.h>
+#include <utmp.h>
+#include <sys/types.h>
+
 #if    defined(_SC_CRAY_SECURE_SYS)
 #include <sys/sysv.h>
 #include <sys/secdev.h>
@@ -83,6 +72,12 @@ static char sccsid[] = "@(#)telnetd.c        8.4 (Berkeley) 5/30/95";
 #include <sys/secparm.h>
 #include <sys/usrv.h>
 # endif /* SO_SEC_MULTI */
+
+/* wrapper for KAME-special getnameinfo() */
+#ifndef NI_WITHSCOPEID
+#define        NI_WITHSCOPEID  0
+#endif
+
 int    secflag;
 char   tty_dev[16];
 struct secdev dv;
@@ -102,7 +97,8 @@ int  auth_level = 0;
 int    require_SecurID = 0;
 #endif
 
-extern int utmp_len;
+char   remote_hostname[MAXHOSTNAMELEN];
+int    utmp_len = sizeof(remote_hostname) - 1;
 int    registerd_host_only = 0;
 
 #ifdef STREAMSPTY
@@ -114,7 +110,7 @@ int registerd_host_only = 0;
 
 /*
  * Because of the way ptyibuf is used with streams messages, we need
- * ptyibuf+1 to be on a full-word boundary.  The following wierdness
+ * ptyibuf+1 to be on a full-word boundary.  The following weirdness
  * is simply to make that happen.
  */
 long   ptyibufbuf[BUFSIZ/sizeof(long)+1];
@@ -146,13 +142,12 @@ int       lowpty = 0, highpty;    /* low, high pty numbers */
 
 int debug = 0;
 int keepalive = 1;
-char *progname;
+char *altlogin;
 
+void doit __P((struct sockaddr *));
+int terminaltypeok __P((char *));
+void startslave __P((char *, int, char *));
 extern void usage P((void));
-void doit(struct sockaddr_in *);
-int terminaltypeok(char *);
-void startslave(char *, int, char *);
-
 
 /*
  * The string to pass to getopt().  We do it this way so
@@ -160,7 +155,8 @@ void startslave(char *, int, char *);
  * passed off to getopt().
  */
 char valid_opts[] = {
-       'd', ':', 'h', 'k', 'n', 'S', ':', 'u', ':', 'U',
+       'd', ':', 'h', 'k', 'n', 'p', ':', 'S', ':', 'u', ':', 'U',
+       '4', '6',
 #ifdef AUTHENTICATION
        'a', ':', 'X', ':',
 #endif
@@ -170,9 +166,6 @@ char valid_opts[] = {
 #ifdef DIAGNOSTICS
        'D', ':',
 #endif
-#ifdef ENCRYPTION
-       'e', ':',
-#endif
 #if    defined(CRAY) && defined(NEWINIT)
        'I', ':',
 #endif
@@ -188,15 +181,15 @@ char valid_opts[] = {
        '\0'
 };
 
+int family = AF_INET;
+
 int
 main(argc, argv)
        char *argv[];
 {
-       struct sockaddr_in from;
+       struct sockaddr_storage from;
        int on = 1, fromlen;
        register int ch;
-       extern char *optarg;
-       extern int optind;
 #if    defined(IPPROTO_IP) && defined(IP_TOS)
        int tos = -1;
 #endif
@@ -204,11 +197,22 @@ main(argc, argv)
        pfrontp = pbackp = ptyobuf;
        netip = netibuf;
        nfrontp = nbackp = netobuf;
-#ifdef ENCRYPTION
-       nclearto = 0;
-#endif /* ENCRYPTION */
 
-       progname = *argv;
+       /*
+        * This initialization causes linemode to default to a configuration
+        * that works on all telnet clients, including the FreeBSD client.
+        * This is not quite the same as the telnet client issuing a "mode
+        * character" command, but has most of the same benefits, and is
+        * preferable since some clients (like usofts) don't have the
+        * mode character command anyway and linemode breaks things.
+        * The most notable symptom of fix is that csh "set filec" operations
+        * like <ESC> (filename completion) and ^D (choices) keys now work
+        * in telnet sessions and can be used more than once on the same line.
+        * CR/LF handling is also corrected in some termio modes.  This 
+        * change resolves problem reports bin/771 and bin/1037.
+        */
+
+       linemode=1;     /*Default to mode that works on bulk of clients*/
 
 #ifdef CRAY
        /*
@@ -218,7 +222,7 @@ main(argc, argv)
        highpty = getnpty();
 #endif /* CRAY */
 
-       while ((ch = getopt(argc, argv, valid_opts)) != EOF) {
+       while ((ch = getopt(argc, argv, valid_opts)) != -1) {
                switch(ch) {
 
 #ifdef AUTHENTICATION
@@ -243,8 +247,7 @@ main(argc, argv)
                                 */
                                auth_level = -1;
                        } else {
-                               fprintf(stderr,
-                           "telnetd: unknown authorization level for -a\n");
+                               warnx("unknown authorization level for -a");
                        }
                        break;
 #endif /* AUTHENTICATION */
@@ -286,17 +289,6 @@ main(argc, argv)
                        break;
 #endif /* DIAGNOSTICS */
 
-#ifdef ENCRYPTION
-               case 'e':
-                       if (strcmp(optarg, "debug") == 0) {
-                               extern int encrypt_debug_mode;
-                               encrypt_debug_mode = 1;
-                               break;
-                       }
-                       usage();
-                       /* NOTREACHED */
-                       break;
-#endif /* ENCRYPTION */
 
                case 'h':
                        hostinfo = 0;
@@ -329,6 +321,10 @@ main(argc, argv)
                        keepalive = 0;
                        break;
 
+               case 'p':
+                       altlogin = optarg;
+                       break;
+
 #ifdef CRAY
                case 'r':
                    {
@@ -366,17 +362,20 @@ main(argc, argv)
                case 'S':
 #ifdef HAS_GETTOS
                        if ((tos = parsetos(optarg, "tcp")) < 0)
-                               fprintf(stderr, "%s%s%s\n",
-                                       "telnetd: Bad TOS argument '", optarg,
+                               warnx("%s%s%s",
+                                       "bad TOS argument '", optarg,
                                        "'; will try to use default TOS");
 #else
-                       fprintf(stderr, "%s%s\n", "TOS option unavailable; ",
-                                               "-S flag not supported\n");
+                       warnx("TOS option unavailable; -S flag not supported");
 #endif
                        break;
 
                case 'u':
                        utmp_len = atoi(optarg);
+                       if (utmp_len < 0)
+                               utmp_len = -utmp_len;
+                       if (utmp_len >= sizeof(remote_hostname))
+                               utmp_len = sizeof(remote_hostname) - 1;
                        break;
 
                case 'U':
@@ -392,8 +391,18 @@ main(argc, argv)
                        break;
 #endif /* AUTHENTICATION */
 
+               case '4':
+                       family = AF_INET;
+                       break;
+
+#ifdef INET6
+               case '6':
+                       family = AF_INET6;
+                       break;
+#endif
+
                default:
-                       fprintf(stderr, "telnetd: %c: unknown option\n", ch);
+                       warnx("%c: unknown option", ch);
                        /* FALLTHROUGH */
                case '?':
                        usage();
@@ -405,55 +414,43 @@ main(argc, argv)
        argv += optind;
 
        if (debug) {
-           int s, ns, foo;
-           struct servent *sp;
-           static struct sockaddr_in sin = { AF_INET };
+           int s, ns, foo, error;
+           char *service = "telnet";
+           struct addrinfo hints, *res;
 
            if (argc > 1) {
                usage();
                /* NOT REACHED */
-           } else if (argc == 1) {
-                   if (sp = getservbyname(*argv, "tcp")) {
-                       sin.sin_port = sp->s_port;
-                   } else {
-                       sin.sin_port = atoi(*argv);
-                       if ((int)sin.sin_port <= 0) {
-                           fprintf(stderr, "telnetd: %s: bad port #\n", *argv);
-                           usage();
-                           /* NOT REACHED */
-                       }
-                       sin.sin_port = htons((u_short)sin.sin_port);
-                  }
-           } else {
-               sp = getservbyname("telnet", "tcp");
-               if (sp == 0) {
-                   fprintf(stderr, "telnetd: tcp/telnet: unknown service\n");
-                   exit(1);
-               }
-               sin.sin_port = sp->s_port;
+           } else if (argc == 1)
+               service = *argv;
+
+           memset(&hints, 0, sizeof(hints));
+           hints.ai_flags = AI_PASSIVE;
+           hints.ai_family = family;
+           hints.ai_socktype = SOCK_STREAM;
+           hints.ai_protocol = 0;
+           error = getaddrinfo(NULL, service, &hints, &res);
+
+           if (error) {
+               errx(1, "tcp/%s: %s\n", service, gai_strerror(error));
+               if (error == EAI_SYSTEM)
+                   errx(1, "tcp/%s: %s\n", service, strerror(errno));
+               usage();
            }
 
-           s = socket(AF_INET, SOCK_STREAM, 0);
-           if (s < 0) {
-                   perror("telnetd: socket");;
-                   exit(1);
-           }
+           s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+           if (s < 0)
+                   err(1, "socket");
            (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
                                (char *)&on, sizeof(on));
-           if (bind(s, (struct sockaddr *)&sin, sizeof sin) < 0) {
-               perror("bind");
-               exit(1);
-           }
-           if (listen(s, 1) < 0) {
-               perror("listen");
-               exit(1);
-           }
-           foo = sizeof sin;
-           ns = accept(s, (struct sockaddr *)&sin, &foo);
-           if (ns < 0) {
-               perror("accept");
-               exit(1);
-           }
+           if (bind(s, res->ai_addr, res->ai_addrlen) < 0)
+               err(1, "bind");
+           if (listen(s, 1) < 0)
+               err(1, "listen");
+           foo = res->ai_addrlen;
+           ns = accept(s, res->ai_addr, &foo);
+           if (ns < 0)
+               err(1, "accept");
            (void) dup2(ns, 0);
            (void) close(ns);
            (void) close(s);
@@ -479,12 +476,10 @@ main(argc, argv)
                int szi = sizeof(int);
 #endif /* SO_SEC_MULTI */
 
-               memset((char *)&dv, 0, sizeof(dv));
+               bzero((char *)&dv, sizeof(dv));
 
-               if (getsysv(&sysv, sizeof(struct sysv)) != 0) {
-                       perror("getsysv");
-                       exit(1);
-               }
+               if (getsysv(&sysv, sizeof(struct sysv)) != 0)
+                       err(1, "getsysv");
 
                /*
                 *      Get socket security label and set device values
@@ -495,8 +490,7 @@ main(argc, argv)
                               (char *)&ss, &szss) < 0) ||
                    (getsockopt(0, SOL_SOCKET, SO_SEC_MULTI,
                                (char *)&sock_multi, &szi) < 0)) {
-                       perror("getsockopt");
-                       exit(1);
+                       err(1, "getsockopt");
                } else {
                        dv.dv_actlvl = ss.ss_actlabel.lt_level;
                        dv.dv_actcmp = ss.ss_actlabel.lt_compart;
@@ -526,8 +520,7 @@ main(argc, argv)
        openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
        fromlen = sizeof (from);
        if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
-               fprintf(stderr, "%s: ", progname);
-               perror("getpeername");
+               warn("getpeername");
                _exit(1);
        }
        if (keepalive &&
@@ -537,7 +530,7 @@ main(argc, argv)
        }
 
 #if    defined(IPPROTO_IP) && defined(IP_TOS)
-       {
+       if (from.ss_family == AF_INET) {
 # if   defined(HAS_GETTOS)
                struct tosent *tp;
                if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
@@ -553,15 +546,15 @@ main(argc, argv)
        }
 #endif /* defined(IPPROTO_IP) && defined(IP_TOS) */
        net = 0;
-       doit(&from);
+       doit((struct sockaddr *)&from);
        /* NOTREACHED */
-       exit(0);
+       return(0);
 }  /* end of main */
 
        void
 usage()
 {
-       fprintf(stderr, "Usage: telnetd");
+       fprintf(stderr, "usage: telnetd");
 #ifdef AUTHENTICATION
        fprintf(stderr, " [-a (debug|other|user|valid|off|none)]\n\t");
 #endif
@@ -634,18 +627,12 @@ getterminaltype(name)
     }
 #endif
 
-#ifdef ENCRYPTION
-    send_will(TELOPT_ENCRYPT, 1);
-#endif /* ENCRYPTION */
     send_do(TELOPT_TTYPE, 1);
     send_do(TELOPT_TSPEED, 1);
     send_do(TELOPT_XDISPLOC, 1);
     send_do(TELOPT_NEW_ENVIRON, 1);
     send_do(TELOPT_OLD_ENVIRON, 1);
     while (
-#ifdef ENCRYPTION
-          his_do_dont_is_changing(TELOPT_ENCRYPT) ||
-#endif /* ENCRYPTION */
           his_will_wont_is_changing(TELOPT_TTYPE) ||
           his_will_wont_is_changing(TELOPT_TSPEED) ||
           his_will_wont_is_changing(TELOPT_XDISPLOC) ||
@@ -653,53 +640,33 @@ getterminaltype(name)
           his_will_wont_is_changing(TELOPT_OLD_ENVIRON)) {
        ttloop();
     }
-#ifdef ENCRYPTION
-    /*
-     * Wait for the negotiation of what type of encryption we can
-     * send with.  If autoencrypt is not set, this will just return.
-     */
-    if (his_state_is_will(TELOPT_ENCRYPT)) {
-       encrypt_wait();
-    }
-#endif /* ENCRYPTION */
     if (his_state_is_will(TELOPT_TSPEED)) {
        static unsigned char sb[] =
                        { IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE };
 
-       memmove(nfrontp, sb, sizeof sb);
-       nfrontp += sizeof sb;
-       DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
+       output_datalen(sb, sizeof sb);
     }
     if (his_state_is_will(TELOPT_XDISPLOC)) {
        static unsigned char sb[] =
                        { IAC, SB, TELOPT_XDISPLOC, TELQUAL_SEND, IAC, SE };
 
-       memmove(nfrontp, sb, sizeof sb);
-       nfrontp += sizeof sb;
-       DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
+       output_datalen(sb, sizeof sb);
     }
     if (his_state_is_will(TELOPT_NEW_ENVIRON)) {
        static unsigned char sb[] =
                        { IAC, SB, TELOPT_NEW_ENVIRON, TELQUAL_SEND, IAC, SE };
 
-       memmove(nfrontp, sb, sizeof sb);
-       nfrontp += sizeof sb;
-       DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
+       output_datalen(sb, sizeof sb);
     }
     else if (his_state_is_will(TELOPT_OLD_ENVIRON)) {
        static unsigned char sb[] =
                        { IAC, SB, TELOPT_OLD_ENVIRON, TELQUAL_SEND, IAC, SE };
 
-       memmove(nfrontp, sb, sizeof sb);
-       nfrontp += sizeof sb;
-       DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
+       output_datalen(sb, sizeof sb);
     }
     if (his_state_is_will(TELOPT_TTYPE)) {
 
-       memmove(nfrontp, ttytype_sbbuf, sizeof ttytype_sbbuf);
-       nfrontp += sizeof ttytype_sbbuf;
-       DIAG(TD_OPTIONS, printsub('>', ttytype_sbbuf + 2,
-                                       sizeof ttytype_sbbuf - 2););
+       output_datalen(ttytype_sbbuf, sizeof ttytype_sbbuf);
     }
     if (his_state_is_will(TELOPT_TSPEED)) {
        while (sequenceIs(tspeedsubopt, baseline))
@@ -728,12 +695,14 @@ getterminaltype(name)
         * we have to just go with what we (might) have already gotten.
         */
        if (his_state_is_will(TELOPT_TTYPE) && !terminaltypeok(terminaltype)) {
-           (void) strncpy(first, terminaltype, sizeof(first));
+           (void) strncpy(first, terminaltype, sizeof(first)-1);
+           first[sizeof(first)-1] = '\0';
            for(;;) {
                /*
                 * Save the unknown name, and request the next name.
                 */
-               (void) strncpy(last, terminaltype, sizeof(last));
+               (void) strncpy(last, terminaltype, sizeof(last)-1);
+               last[sizeof(last)-1] = '\0';
                _gettermname();
                if (terminaltypeok(terminaltype))
                    break;
@@ -751,8 +720,10 @@ getterminaltype(name)
                     * the start of the list.
                     */
                     _gettermname();
-                   if (strncmp(first, terminaltype, sizeof(first)) != 0)
-                       (void) strncpy(terminaltype, first, sizeof(first));
+                   if (strncmp(first, terminaltype, sizeof(first)) != 0) {
+                       (void) strncpy(terminaltype, first, sizeof(terminaltype)-1);
+                       terminaltype[sizeof(terminaltype)-1] = '\0';
+                   }
                    break;
                }
            }
@@ -772,10 +743,7 @@ _gettermname()
     if (his_state_is_wont(TELOPT_TTYPE))
        return;
     settimer(baseline);
-    memmove(nfrontp, ttytype_sbbuf, sizeof ttytype_sbbuf);
-    nfrontp += sizeof ttytype_sbbuf;
-    DIAG(TD_OPTIONS, printsub('>', ttytype_sbbuf + 2,
-                                       sizeof ttytype_sbbuf - 2););
+    output_datalen(ttytype_sbbuf, sizeof ttytype_sbbuf);
     while (sequenceIs(ttypesubopt, baseline))
        ttloop();
 }
@@ -802,31 +770,27 @@ terminaltypeok(s)
 }
 
 #ifndef        MAXHOSTNAMELEN
-#define        MAXHOSTNAMELEN 64
+#define        MAXHOSTNAMELEN 256
 #endif /* MAXHOSTNAMELEN */
 
 char *hostname;
 char host_name[MAXHOSTNAMELEN];
-char remote_host_name[MAXHOSTNAMELEN];
 
-#ifndef        convex
-extern void telnet P((int, int));
-#else
 extern void telnet P((int, int, char *));
-#endif
 
+int level;
+char user_name[256];
 /*
  * Get a pty, scan input lines.
  */
-void
+       void
 doit(who)
-       struct sockaddr_in *who;
+       struct sockaddr *who;
 {
-       char *host = NULL, *inet_ntoa();
+       char *host = NULL;
+       int err;
        struct hostent *hp;
-       int level;
        int ptynum;
-       char user_name[256];
 
        /*
         * Find an available pty to use.
@@ -838,14 +802,12 @@ doit(who)
 #else
        for (;;) {
                char *lp;
-               extern char *line, *getpty();
 
                if ((lp = getpty()) == NULL)
                        fatal(net, "Out of ptys");
 
-               if ((pty = open(lp, O_RDWR)) >= 0) {
-                       strncpy(line,lp, sizeof(line)-1);
-                       line[sizeof(line)-1] = '\0';
+               if ((pty = open(lp, 2)) >= 0) {
+                       strlcpy(line,lp,sizeof(line));
                        line[5] = 't';
                        break;
                }
@@ -859,42 +821,43 @@ doit(who)
        if (secflag) {
                char slave_dev[16];
 
-               sprintf(tty_dev, "/dev/pty/%03d", ptynum);
+               sprintf(tty_dev, "%spty/%03d", _PATH_DEV, ptynum);
                if (setdevs(tty_dev, &dv) < 0)
                        fatal(net, "cannot set pty security");
-               sprintf(slave_dev, "/dev/ttyp%03d", ptynum);
+               sprintf(slave_dev, "%sp%03d", _PATH_TTY, ptynum);
                if (setdevs(slave_dev, &dv) < 0)
                        fatal(net, "cannot set tty security");
        }
 #endif /* _SC_CRAY_SECURE_SYS */
 
-       /* get name of connected client */
-       hp = gethostbyaddr((char *)&who->sin_addr, sizeof (struct in_addr),
-               who->sin_family);
-
-       if (hp == NULL && registerd_host_only) {
-               fatal(net, "Couldn't resolve your address into a host name.\r\n\
-        Please contact your net administrator");
-       } else if (hp &&
-           (strlen(hp->h_name) <= (unsigned int)((utmp_len < 0) ? -utmp_len
-                                                                : utmp_len))) {
-               host = hp->h_name;
-       } else {
-               host = inet_ntoa(who->sin_addr);
-       }
-       /*
-        * We must make a copy because Kerberos is probably going
-        * to also do a gethost* and overwrite the static data...
-        */
-       strncpy(remote_host_name, host, sizeof(remote_host_name)-1);
-       remote_host_name[sizeof(remote_host_name)-1] = 0;
-       host = remote_host_name;
-
-       (void) gethostname(host_name, sizeof (host_name));
+        /* get name of connected client */
+        hp = gethostbyaddr((char *)&((struct sockaddr_in *)who)->sin_addr, sizeof (struct in_addr),
+                ((struct sockaddr_in *)who)->sin_family);
+
+        if (hp == NULL && registerd_host_only) {
+                fatal(net, "Couldn't resolve your address into a host name.\r\n\
+         Please contact your net administrator");
+        } else if (hp &&
+            (strlen(hp->h_name) <= (unsigned int)((utmp_len < 0) ? -utmp_len
+                                                                 : utmp_len))) {
+                host = hp->h_name;
+        } else {
+                host = inet_ntoa(((struct sockaddr_in *)who)->sin_addr);
+        }
+        /*       
+         * We must make a copy because Kerberos is probably going
+         * to also do a gethost* and overwrite the static data...
+         */      
+        strncpy(remote_hostname, host, sizeof(remote_hostname)-1);
+        remote_hostname[sizeof(remote_hostname)-1] = 0;
+        host = remote_hostname;
+
+       (void) gethostname(host_name, sizeof(host_name) - 1);
+       host_name[sizeof(host_name) - 1] = '\0';
        hostname = host_name;
 
-#if    defined(AUTHENTICATION) || defined(ENCRYPTION)
-       auth_encrypt_init(hostname, host, "TELNETD", 1);
+#if    defined(AUTHENTICATION)
+       auth_encrypt_init(hostname, remote_hostname, "TELNETD", 1);
 #endif
 
        init_env();
@@ -905,12 +868,6 @@ doit(who)
        level = getterminaltype(user_name);
        setenv("TERM", terminaltype ? terminaltype : "network", 1);
 
-       /*
-        * Start up the login process on the slave side of the terminal
-        */
-#ifndef        convex
-       startslave(host, level, user_name);
-
 #if    defined(_SC_CRAY_SECURE_SYS)
        if (secflag) {
                if (setulvl(dv.dv_actlvl) < 0)
@@ -920,10 +877,8 @@ doit(who)
        }
 #endif /* _SC_CRAY_SECURE_SYS */
 
-       telnet(net, pty);  /* begin server processing */
-#else
-       telnet(net, pty, host);
-#endif
+       telnet(net, pty, remote_hostname);      /* begin server process */
+
        /*NOTREACHED*/
 }  /* end of doit */
 
@@ -947,15 +902,9 @@ Xterm_output(ibufp, obuf, icountp, ocount)
  * hand data to telnet receiver finite state machine.
  */
        void
-#ifndef        convex
-telnet(f, p)
-#else
 telnet(f, p, host)
-#endif
        int f, p;
-#ifdef convex
        char *host;
-#endif
 {
        int on = 1;
 #define        TABBUFSIZ       512
@@ -965,8 +914,12 @@ telnet(f, p, host)
        char *HE;
        char *HN;
        char *IM;
+       char *IF;
+       char *if_buf;
+       int if_fd;
+       struct stat statbuf;
+
        void netflush();
-       int nfd;
 
        /*
         * Initialize the slc mapping table.
@@ -1051,9 +1004,7 @@ telnet(f, p, host)
         * mode, which we do not want.
         */
        if (his_want_state_is_will(TELOPT_ECHO)) {
-               DIAG(TD_OPTIONS,
-                       {sprintf(nfrontp, "td: simulating recv\r\n");
-                        nfrontp += strlen(nfrontp);});
+               DIAG(TD_OPTIONS, output_data("td: simulating recv\r\n"));
                willoption(TELOPT_ECHO);
        }
 
@@ -1119,9 +1070,9 @@ telnet(f, p, host)
         * side.  Set up signal handler now.
         */
        if ((int)signal(SIGUSR1, termstat) < 0)
-               perror("signal");
+               warn("signal");
        else if (ioctl(p, TCSIGME, (char *)SIGUSR1) < 0)
-               perror("ioctl:TCSIGME");
+               warn("ioctl:TCSIGME");
        /*
         * Make processing loop check terminal characteristics early on.
         */
@@ -1164,10 +1115,11 @@ telnet(f, p, host)
                HE = Getstr("he", &cp);
                HN = Getstr("hn", &cp);
                IM = Getstr("im", &cp);
-               if (HN && *HN) {
-                       (void) strncpy(host_name, HN, sizeof(host_name)-1);
-                       hostname[sizeof(host_name)-1] = '\0';
-               }
+               IF = Getstr("if", &cp);
+               if (HN && *HN)
+                       (void) strlcpy(host_name, HN, sizeof(host_name));
+               if (IF && (if_fd = open(IF, O_RDONLY, 000)) != -1)
+                       IM = 0;
                if (IM == 0)
                        IM = "";
        } else {
@@ -1177,6 +1129,14 @@ telnet(f, p, host)
        edithost(HE, host_name);
        if (hostinfo && *IM)
                putf(IM, ptyibuf2);
+       else if (IF && if_fd != -1) {
+               fstat (if_fd, &statbuf);
+               if_buf = (char *) mmap (0, statbuf.st_size, PROT_READ, 
+                   0, if_fd, 0);
+               putf(if_buf, ptyibuf2);
+               munmap (if_buf, statbuf.st_size);
+               close (if_fd);
+       }
 
        if (pcc)
                (void) strncat(ptyibuf2, ptyip, pcc+1);
@@ -1190,15 +1150,15 @@ telnet(f, p, host)
        localstat();
 #endif /* LINEMODE */
 
-       DIAG(TD_REPORT,
-               {sprintf(nfrontp, "td: Entering processing loop\r\n");
-                nfrontp += strlen(nfrontp);});
+       DIAG(TD_REPORT, output_data("td: Entering processing loop\r\n"));
 
-#ifdef convex
-       startslave(host);
-#endif
+       /*
+        * Startup the login process on the slave side of the terminal
+        * now.  We delay this until here to insure option negotiation
+        * is complete.
+        */
+       startslave(host, level, user_name);
 
-       nfd = ((f > p) ? f : p) + 1;
        for (;;) {
                fd_set ibits, obits, xbits;
                register int c;
@@ -1230,7 +1190,7 @@ telnet(f, p, host)
                if (!SYNCHing) {
                        FD_SET(f, &xbits);
                }
-               if ((c = select(nfd, &ibits, &obits, &xbits,
+               if ((c = select(16, &ibits, &obits, &xbits,
                                                (struct timeval *)0)) < 1) {
                        if (c == -1) {
                                if (errno == EINTR) {
@@ -1318,8 +1278,7 @@ telnet(f, p, host)
                        netip = netibuf;
                    }
                    DIAG((TD_REPORT | TD_NETDATA),
-                           {sprintf(nfrontp, "td: netread %d chars\r\n", ncc);
-                            nfrontp += strlen(nfrontp);});
+                       output_data("td: netread %d chars\r\n", ncc));
                    DIAG(TD_NETDATA, printdata("nd", netip, ncc));
                }
 
@@ -1366,12 +1325,8 @@ telnet(f, p, host)
                                         * royally if we send them urgent
                                         * mode data.
                                         */
-                                       *nfrontp++ = IAC;
-                                       *nfrontp++ = DM;
+                                       output_data("%c%c", IAC, DM);
                                        neturg = nfrontp-1; /* off by one XXX */
-                                       DIAG(TD_OPTIONS,
-                                           printoption("td: send IAC", DM));
-
 #endif
                                }
                                if (his_state_is_will(TELOPT_LFLOW) &&
@@ -1381,16 +1336,11 @@ telnet(f, p, host)
                                            ptyibuf[0] & TIOCPKT_DOSTOP ? 1 : 0;
                                        if (newflow != flowmode) {
                                                flowmode = newflow;
-                                               (void) sprintf(nfrontp,
-                                                       "%c%c%c%c%c%c",
+                                               output_data("%c%c%c%c%c%c",
                                                        IAC, SB, TELOPT_LFLOW,
                                                        flowmode ? LFLOW_ON
                                                                 : LFLOW_OFF,
                                                        IAC, SE);
-                                               nfrontp += 6;
-                                               DIAG(TD_OPTIONS, printsub('>',
-                                                   (unsigned char *)nfrontp-4,
-                                                   4););
                                        }
                                }
                                pcc--;
@@ -1413,19 +1363,19 @@ telnet(f, p, host)
                                break;
                        c = *ptyip++ & 0377, pcc--;
                        if (c == IAC)
-                               *nfrontp++ = c;
+                               output_data("%c", c);
 #if    defined(CRAY2) && defined(UNICOS5)
                        else if (c == '\n' &&
                                     my_state_is_wont(TELOPT_BINARY) && newmap)
-                               *nfrontp++ = '\r';
+                               output_data("\r");
 #endif /* defined(CRAY2) && defined(UNICOS5) */
-                       *nfrontp++ = c;
+                       output_data("%c", c);
                        if ((c == '\r') && (my_state_is_wont(TELOPT_BINARY))) {
                                if (pcc > 0 && ((*ptyip & 0377) == '\n')) {
-                                       *nfrontp++ = *ptyip++ & 0377;
+                                       output_data("%c", *ptyip++ & 0377);
                                        pcc--;
                                } else
-                                       *nfrontp++ = '\0';
+                                       output_data("%c", '\0');
                        }
                }
 #if    defined(CRAY2) && defined(UNICOS5)
@@ -1556,14 +1506,6 @@ interrupt()
 {
        ptyflush();     /* half-hearted */
 
-#if defined(STREAMSPTY) && defined(TIOCSIGNAL)
-       /* Streams PTY style ioctl to post a signal */
-       {
-               int sig = SIGINT;
-               (void) ioctl(pty, TIOCSIGNAL, &sig);
-               (void) ioctl(pty, I_FLUSH, FLUSHR);
-       }
-#else
 #ifdef TCSIG
        (void) ioctl(pty, TCSIG, (char *)SIGINT);
 #else  /* TCSIG */
@@ -1571,7 +1513,6 @@ interrupt()
        *pfrontp++ = slctab[SLC_IP].sptr ?
                        (unsigned char)*slctab[SLC_IP].sptr : '\177';
 #endif /* TCSIG */
-#endif
 }
 
 /*
@@ -1619,8 +1560,7 @@ recv_ayt()
                return;
        }
 #endif
-       (void) strcpy(nfrontp, "\r\n[Yes]\r\n");
-       nfrontp += 9;
+       output_data("\r\n[Yes]\r\n");
 }
 
        void