On Sun, Mar 29, 2020 at 04:50:07PM +0200, Salvatore Bonaccorso wrote:
> It might be possible that Debian is fixed for it since 0.17-18woody2
> (for src:netkit-telnet).

For reference the respective diff.

Salvatore
diff --git a/ChangeLog b/ChangeLog
index 01b552ed0824..7ef5e3e04927 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+22-Jul-2000:
+	Bug fixes for environment processing from Olaf Kirch. Also fixes
+	  privacy issue noticed by Steve Bellovin. Also fix a wrong 
+	  assert().
+
+21-May-2000:
+	Fix bug found by Herbert Xu (herb...@gondor.apana.org.au) - telnet
+	  was sending terminal type "(null)" as part of the terminal type
+	  list.
+
+12-Apr-2000:
+	IPPROTO_IP is not a macro in Linux, so don't check it with #ifdef.
+	Also, add initial experimental login wrapper, but don't make it 
+	  part of the default build.
+
+14-Dec-1999:
+	netkit-telnet-0.16 is released.
+
 13-Dec-1999:
 	Per recommendation of the linux-security-audit list, don't bother
 	  (in telnetd) to ask termcap/ncurses if a terminal type is good;
diff --git a/Makefile b/Makefile
index 1942aee33c5e..06c8e1e70f6a 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 # You can do "make SUB=blah" to make only a few, or edit here, or both
 # You can also run make directly in the subdirs you want.
 
-SUB =   telnet telnetd
+SUB =   telnet telnetd telnetlogin
 
 %.build:
 	(cd $(patsubst %.build, %, $@) && $(MAKE))
diff --git a/README b/README
index c9b4f49eb5ce..87f56d2e5419 100644
--- a/README
+++ b/README
@@ -1,9 +1,11 @@
-This is netkit-telnet-0.16.
+This is netkit-telnet-0.17 for Linux.
 
-This package updates netkit-telnet-0.14.
+This package updates netkit-telnet-0.16.
 
 If you're reading this off a CD, go right away and check the net
-archives for later versions and security fixes.
+archives for later versions and security fixes. As of this writing the
+home site for NetKit is
+	ftp://ftp.uk.linux.org/pub/linux/Networking/netkit
 
 Contents:
 	telnet		Client for telnet protocol
@@ -18,28 +20,33 @@ Requires:
 	Working compiler, libc, and kernel, and a recent version of
 	ncurses or libtermcap.
 
-Security:
-	This release probably does not contain new security fixes. On
-	the other hand, vast amounts of suspicious pointer manipulation
-	in telnetd were cleaned up, so it is quite likely that this
-	version is less dangerous than previous ones.
+	Note that while telnet uses the C++ compiler, it neither requires
+	nor uses libstdc++.
 
-	In any event, telnetd is evil legacy code and is not
-	trustworthy - do not run it unless you absolutely need it.
+Security:
+	This release contains no security fixes relative to 
+	netkit-telnet-0.16. However, versions prior to that should not be 
+	used.
 
+	Telnetd is evil legacy code and is not trustworthy - do not
+	run it unless you absolutely need it.
 
-	netkit-telnet-0.14 contained a fix for a set of remote (and
-	possibly serious) denial of service attacks possible against
-	older versions of the telnet daemon.
+	This release contains experimental login wrapper code to permit
+	running telnetd as a non-root user. This code is not built by 
+	default. Look in the "telnetlogin" directory and the telnetlogin 
+	man page contained therein for more information.
 
-	Do not under any circumstances use telnetd older than
-	NetKit-0.09!
+Old kernels:
+	If you have an old kernel, you may need to apply the enclosed
+	pty-hang patch to it. I don't unfortunately know at the moment 
+	which kernel versions need the patch, but current 2.0.x and
+	2.2.x should be ok without it.
 
-DEC Alpha:
-        The currently available Compaq C compiler does not provide
-	a C++ compiler, so it cannot compile telnet. Compiling
-	telnetd it may produce a few warnings, but they should be
-	harmless.
+	The following test will tell you if you need the patch: telnet
+	to localhost, do "cat >/dev/null", and type 256 characters
+	without any newlines. If you need the patch, telnetd will hang
+	completely at this point. If it refuses to accept more input,
+	but does not hang, you do not need the patch.
 
 Installation:
 	Do "./configure --help" and decide what options you want. The
@@ -52,16 +59,26 @@ Installation:
 	Save a backup copy of any mission-critical program in case the
 	new one doesn't work, and so forth. We warned you.
 
-  ***	If you have an old kernel, you may need to apply the enclosed
-	pty-hang patch to it. I don't unfortunately know at the moment 
-	which kernel versions need the patch, but current 2.0.x and
-	2.2.x should be ok without it.
+	If you get gcc warnings from files in /usr/include, they are
+	due to problems in your libc, not netkit. (You may only see
+	them when compiling netkit because netkit turns on a lot of
+	compiler warnings.)
 
-	The following test will tell you if you need the patch: telnet
-	to localhost, do "cat >/dev/null", and type 256 characters
-	without any newlines. If you need the patch, telnetd will hang
-	completely at this point. If it refuses to accept more input,
-	but does not hang, you do not need the patch.
+DEC CC:
+	The DEC compiler for the Alpha is now freely available. This
+	is a much better compiler with gcc, that is, it generates much
+	better code. If you have the DEC compiler, you can explicitly
+	use the DEC compiler instead of gcc by configuring like this:
+
+		./configure --with-c-compiler=ccc
+
+	It is known to generate spurious warnings on some files. Also,
+	some headers from some versions of glibc confuse it; that may
+	prevent	netkit from working. Other problems should be reported
+	as bugs.
+
+	Note that there is no corresponding C++ compiler, so telnet
+	will be compiled with g++ anyway.
 
 Bugs:
 	Please make sure the header files in /usr/include match the
@@ -80,8 +97,10 @@ Bugs:
 	distinct fix. Please do NOT send the whole archive back or
 	reindent the source.
 
-	Be sure to send all correspondence in e-mail. Postings to netnews 
-	will not be seen due to the enormous volume.
+	Be sure to send all correspondence in e-mail to the netkit address.
+	Postings to netnews or mailing lists will not be seen due to the 
+	enormous volume. Also, anything that doesn't get filed in the bug
+	database is quite likely to end up forgotten.
 
 	Please don't report known bugs (see the BUGS file(s)) unless you
 	are including fixes. :-)
@@ -89,14 +108,20 @@ Bugs:
 	Mail should be sent to: net...@ftp.uk.linux.org
 
 
-Note: please see http://www.hcs.harvard.edu/~dholland/computers/netkit.html
-if you are curious why it's been so long since the last NetKit release.
-(The short version is that I gave things to some other people, who let
-them kind of slide.)
+Early in April 2000, a hacker broke into the machine that was hosting
+the netkit bug database for me and trashed it. Unfortunately, it seems
+backups hadn't gotten done for a while, so three months of mail (since
+mid-January) was lost. So, if you sent something and didn't hear back,
+or you sent something, heard back, but the changes failed to appear in
+this release (unlikely but possible) - please resend.
+
+Please see http://www.hcs.harvard.edu/~dholland/computers/netkit.html
+if you are curious why it was so long between the 0.10 and 0.16 releases.
 
-I do not currently plan to continue maintaining NetKit; I am doing this
-release and perhaps one or two more, and then I intend to give the source
-tree to Red Hat or some similar organization for long-term maintenance.
+Future plans for netkit maintenance are still up in the air, but in the
+meantime new releases will still appear from time to time. I don't have
+a whole lot of cycles to spare to work on netkit, so things are likely
+to continue to be fairly slow.
 
 David A. Holland
-12 December 1999
+23 July 2000
diff --git a/configure b/configure
index a17f8f5dbe3d..eb0493385390 100755
--- a/configure
+++ b/configure
@@ -42,9 +42,6 @@ EOF
 	--manmode=*) MANMODE=`echo $1 | sed 's/^[^=]*=//'` ;;
 	--with-c-compiler=*) CC=`echo $1 | sed 's/^[^=]*=//'` ;;
 	--with-c++-compiler=*) CXX=`echo $1 | sed 's/^[^=]*=//'` ;;
-	--without-pam|--disable-pam) WITHOUT_PAM=1;;
-	--without-readline|--disable-readline) WITHOUT_READLINE=1;;
-	--without-shadow|--disable-shadow) WITHOUT_SHADOW=1;;
 	*) echo "Unrecognized option: $1"; exit 1;;
 esac 
 shift
@@ -120,7 +117,7 @@ fi
 
 cat << EOF > __conftest.cc
     template <class T> class fnord { public: T x; fnord(T y) { x=y; }};
-    int main() { fnord<int> a(0); return a.x; }
+    int main() { fnord<int> *a = new fnord<int>(0); return a->x; }
 EOF
 
 if [ x"$CXX" = x ]; then
@@ -165,7 +162,27 @@ else
      echo 'no'
 fi
 
-if [ x$DEBUG != x ]; then
+if [ x$DEBUG = x ]; then
+    echo -n "Checking if $CC accepts -O2... "
+    if (
+         $CC -O2 __conftest.c -o __conftest
+       ) >/dev/null 2>&1; then
+         echo 'yes'
+         CFLAGS="$CFLAGS -O2"
+    else
+         echo 'no'
+         echo -n "Checking if $CC accepts -O... "
+         if (
+              $CC -O __conftest.c -o __conftest
+            ) >/dev/null 2>&1; then
+              echo 'yes'
+              CFLAGS="$CFLAGS -O"
+         else
+              echo 'no'
+         fi
+    fi
+
+else
     echo -n "Checking if $CC accepts -g... "
     if (
          $CC -g __conftest.c -o __conftest
@@ -175,57 +192,41 @@ if [ x$DEBUG != x ]; then
     else
          echo 'no'
     fi
-fi
 
-echo -n "Checking if $CC accepts -O2... "
-if (
-     $CC -O2 __conftest.c -o __conftest
-   ) >/dev/null 2>&1; then
-     echo 'yes'
-     CFLAGS="$CFLAGS -O2"
-else
-     echo 'no'
-     echo -n "Checking if $CC accepts -O... "
-     if (
-          $CC -O __conftest.c -o __conftest
-        ) >/dev/null 2>&1; then
-          echo 'yes'
-          CFLAGS="$CFLAGS -O"
-     else
-          echo 'no'
-     fi
 fi
 
 if [ x"$CC" != x"$CXX" ]; then
-    if [ x$DEBUG != x ]; then
-        echo -n "Checking if $CXX accepts -g... "
+    if [ x$DEBUG = x ]; then
+        echo -n "Checking if $CXX accepts -O2... "
         if (
-             $CXX -g __conftest.cc -o __conftest
+             $CXX -O2 __conftest.cc -o __conftest
            ) >/dev/null 2>&1; then
              echo 'yes'
-             CXXFLAGS="$CXXFLAGS -g"
+             CXXFLAGS="$CXXFLAGS -O2"
         else
              echo 'no'
+             echo -n "Checking if $CXX accepts -O... "
+             if (
+                  $CXX -O __conftest.cc -o __conftest
+                ) >/dev/null 2>&1; then
+                  echo 'yes'
+                  CXXFLAGS="$CXXFLAGS -O"
+             else
+                  echo 'no'
+             fi
         fi
 
-    fi
-    echo -n "Checking if $CXX accepts -O2... "
-    if (
-         $CXX -O2 __conftest.cc -o __conftest
-       ) >/dev/null 2>&1; then
-        echo 'yes'
-        CXXFLAGS="$CXXFLAGS -O2"
     else
-        echo 'no'
-        echo -n "Checking if $CXX accepts -O... "
+        echo -n "Checking if $CXX accepts -g... "
         if (
-             $CXX -O __conftest.cc -o __conftest
+             $CXX -g __conftest.cc -o __conftest
            ) >/dev/null 2>&1; then
              echo 'yes'
-             CXXFLAGS="$CXXFLAGS -O"
+             CXXFLAGS="$CXXFLAGS -g"
         else
              echo 'no'
         fi
+
     fi
 else
     CXXFLAGS="$CFLAGS"
@@ -499,20 +500,20 @@ int main() {
 
 EOF
 if (
-      $CXX $CXXFLAGS  __conftest.cc $(LIBBSD) -o __conftest || exit 1
+      $CXX $CXXFLAGS  __conftest.cc $LIBBSD -o __conftest || exit 1
       ./__conftest || exit 1
    ) >/dev/null 2>&1; then
     echo 'ok'
 else
     if (
-          $CXX $CXXFLAGS  __conftest.cc -lsnprintf $(LIBBSD) -o __conftest || exit 1
+          $CXX $CXXFLAGS  __conftest.cc -lsnprintf $LIBBSD -o __conftest || exit 1
           ./__conftest || exit 1
        ) >/dev/null 2>&1; then
         echo '-lsnprintf'
         LIBS="$LIBS -lsnprintf"
     else
         if (
-              $CXX $CXXFLAGS  __conftest.cc -ldb $(LIBBSD) -o __conftest || exit 1
+              $CXX $CXXFLAGS  __conftest.cc -ldb $LIBBSD -o __conftest || exit 1
               ./__conftest || exit 1
            ) >/dev/null 2>&1; then
             echo '-ldb'
diff --git a/debian/changelog b/debian/changelog
index 48cda9d48240..5743eda31860 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,21 +1,161 @@
-netkit-telnet (0.16-4potato.3) stable; urgency=high
+netkit-telnet (0.17-18woody2) stable-security; urgency=high
 
-  * Fixed same overflow with minimal change.
+  * Non-maintainer upload by the Security Team
+  * Really applied the patch by Herbert Xu to fix DoS and possibly worse
+    [telnetd/utility.c, CAN-2004-0911]
 
- -- Herbert Xu <herb...@debian.org>  Sun, 12 Aug 2001 10:33:24 +1000
+ -- Martin Schulze <j...@infodrom.org>  Sat, 16 Oct 2004 10:40:32 +0200
 
-netkit-telnet (0.16-4potato.2) stable; urgency=low
+netkit-telnet (0.17-18woody1) stable-security; urgency=high
 
-  * Security release
-  * Fixes for AYT buffer overflows.
+  * Non-maintainer upload by the Security Team
+  * Apply patch from Herbert Xu to fix DoS, possibly worse (CAN-2004-0911)
 
- -- Robert van der Meulen <r...@debian.org>  Thu,  9 Aug 2001 20:05:38 +0200
+ -- Matt Zimmerman <m...@debian.org>  Mon, 27 Sep 2004 14:24:58 -0700
 
-netkit-telnet (0.16-4potato.1) stable; urgency=low
+netkit-telnet (0.17-18) unstable; urgency=low
+
+  * Added missing El's in telnetd(8).
+  * -S now accepts a number (closes: #136804).
+  * Show the machine we are connected instead of the first (closes: #137554).
+
+ -- Herbert Xu <herb...@debian.org>  Sun,  7 Apr 2002 09:41:12 +1000
+
+netkit-telnet (0.17-17) unstable; urgency=high
+
+  * Provide telnet-server (closes: #120180).
+  * Fixed IAC+SB crash (closes: #122313, #128988).
+
+ -- Herbert Xu <herb...@debian.org>  Fri, 18 Jan 2002 20:13:23 +1100
+
+netkit-telnet (0.17-16) unstable; urgency=low
+
+  * Set resolv_hostp outside the source routing ifdef in telnetd.
+  * Documented telnet options -4 and -6 (closes: #109636).
+
+ -- Herbert Xu <herb...@debian.org>  Sun, 16 Sep 2001 14:38:05 +1000
+
+netkit-telnet (0.17-15) unstable; urgency=low
+
+  * Don't ignore all EADDRINUSE errors in telnet.
+  * Don't clear the environment in telnetlogin (closes: #108872).
+
+ -- Herbert Xu <herb...@debian.org>  Thu, 16 Aug 2001 19:38:11 +1000
+
+netkit-telnet (0.17-14) unstable; urgency=high
+
+  * Fixed netobuf buffer overflows.
+
+ -- Herbert Xu <herb...@debian.org>  Sat, 11 Aug 2001 17:52:25 +1000
+
+netkit-telnet (0.17-13) unstable; urgency=medium
+
+  * Updated devpts check to include devfs as well.
+
+ -- Herbert Xu <herb...@debian.org>  Sat, 19 May 2001 15:33:41 +1000
+
+netkit-telnet (0.17-12) unstable; urgency=low
+
+  * Added include <sys/time.h> to telnetd/utility.c (closes: #96803).
+
+ -- Herbert Xu <herb...@debian.org>  Wed,  9 May 2001 21:17:12 +1000
+
+netkit-telnet (0.17-11) unstable; urgency=low
+
+  * Added exit 0 to telnetd.postrm (closes: #93934).
+  * Changed misleading help message (closes: #94231).
+
+ -- Herbert Xu <herb...@debian.org>  Sat, 21 Apr 2001 22:52:11 +1000
+
+netkit-telnet (0.17-10) unstable; urgency=low
+
+  * Renamed member printf to xprintf (closes: #91351).
+  * Use new in C++ compiler test (closes: #91353).
+
+ -- Herbert Xu <herb...@debian.org>  Fri, 13 Apr 2001 19:34:12 +1000
+
+netkit-telnet (0.17-9) unstable; urgency=low
+
+  * Fixed path to license file (Christoph Martin, closes: #86476).
+  * Added missing #DEBHELPER# tag to telnet.prerm (Hiroyuki YAMAMORI,
+    closes: #86894).
+  * Only call update-alternatives in prerm if removing or deconfiguring
+    (closes: #87330).
+
+ -- Herbert Xu <herb...@debian.org>  Sun, 25 Feb 2001 00:00:59 +1100
+
+netkit-telnet (0.17-8) unstable; urgency=low
+
+  * Removed remnant of suidregister from telnetd (closes: #85882).
+  * Fixed handling of sockaddr lengths (closes: #86177).
+  * Dynamically allocate editedhost (closes: #86080).
+
+ -- Herbert Xu <herb...@debian.org>  Sat, 17 Feb 2001 12:53:11 +1100
+
+netkit-telnet (0.17-7) unstable; urgency=low
+
+  * Added includes for gcc 2.97 (Randolph Chung, closes: #83337).
+  * Avoid DNS lookups if the address is numerical (closes: #83828).
+  * Added menu hint (closes: #80161).
+
+ -- Herbert Xu <herb...@debian.org>  Mon, 29 Jan 2001 21:10:59 +1100
+
+netkit-telnet (0.17-6) unstable; urgency=low
+
+  * Added menu entry for telnet (closes: #74845).
+
+ -- Herbert Xu <herb...@debian.org>  Sat, 21 Oct 2000 11:08:44 +1100
+
+netkit-telnet (0.17-5) unstable; urgency=low
 
   * Fixed a memory allocation bug.
 
- -- Herbert Xu <herb...@debian.org>  Fri, 22 Sep 2000 23:30:18 +1100
+ -- Herbert Xu <herb...@debian.org>  Fri, 22 Sep 2000 23:12:57 +1100
+
+netkit-telnet (0.17-4) unstable; urgency=low
+
+  * Relaxed telnetlogin a bit.
+  * Provide telnet-client (closes: #70549).
+
+ -- Herbert Xu <herb...@debian.org>  Sat,  9 Sep 2000 17:42:53 +1100
+
+netkit-telnet (0.17-3) unstable; urgency=low
+
+  * Check for EAFNOSUPPORT after calling socket(2) in telnet.
+  * Added IPv6 support for telnetd.
+
+ -- Herbert Xu <herb...@debian.org>  Sun, 27 Aug 2000 11:28:48 +1100
+
+netkit-telnet (0.17-2) unstable; urgency=low
+
+  * Install telnetlogin ourselves (closes: #69773).
+  * Fixed alternatives typo (closes: #69597).
+
+ -- Herbert Xu <herb...@debian.org>  Wed, 23 Aug 2000 20:01:38 +1000
+
+netkit-telnet (0.17-1) unstable; urgency=low
+
+  * New upstream release.
+  * Applied a modified version of Jason Gunthorpe's IPv6 patch for telnet
+    (closes: #68998).
+  * Read /etc/telnetrc before .telnetrc if it exists.  The idea was from
+    Robert Luberda.  Documented the special hostname DEFAULT (closes: #69113).
+  * Use alternatives for /usr/bin/telnet (closes: #56754).
+
+ -- Herbert Xu <herb...@debian.org>  Sat, 19 Aug 2000 14:06:48 +1000
+
+netkit-telnet (0.16-6) unstable; urgency=low
+
+  * Handle localchars correctly (closes: #66039).
+
+ -- Herbert Xu <herb...@debian.org>  Mon, 26 Jun 2000 15:01:42 +1000
+
+netkit-telnet (0.16-5) unstable; urgency=low
+
+  * Fixed a bug in responses to TTYPE queries where a (null) could be sent
+    instead of the correct terminal type (closes: #63155).
+
+ -- Herbert Xu <herb...@debian.org>  Sat,  6 May 2000 09:42:58 +1000
 
 netkit-telnet (0.16-4) frozen unstable; urgency=low
 
diff --git a/debian/control b/debian/control
index fe25130dee68..5545b94dc5f0 100644
--- a/debian/control
+++ b/debian/control
@@ -2,20 +2,26 @@ Source: netkit-telnet
 Section: net
 Priority: standard
 Maintainer: Herbert Xu <herb...@debian.org>
-Standards-Version: 3.0.1
+Standards-Version: 3.5.6
+Build-Depends: debhelper, libncurses-dev
 
 Package: telnet
 Architecture: any
 Depends: ${shlibs:Depends}
 Replaces: netstd
+Provides: telnet-client
 Description: The telnet client.
  The telnet command is used for interactive communication with another host
  using the TELNET protocol.
 
 Package: telnetd
 Architecture: any
-Depends: netbase, adduser, base-files (>= 2.1.8), ${shlibs:Depends}
+Priority: optional
+Depends: adduser, base-files (>= 2.1.8), dpkg (>= 1.7.0), netbase, passwd, ${shlibs:Depends}
 Replaces: netstd
+Provides: telnet-server
+Conflicts: suidmanager (<< 0.50)
 Description: The telnet server.
  The in.telnetd program is a server which supports the DARPA telnet interactive
  communication protocol.
+
diff --git a/debian/copyright b/debian/copyright
index 94881eb39be7..35d61af09d31 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -4,7 +4,7 @@ Mon, 28 Sep 1998 16:50:43 +1000.
 netstd was created by Peter Tobias tob...@et-inf.fho-emden.de on
 Wed, 20 Jul 1994 17:23:21 +0200.
 
-It was downloaded from ftp://ftp.uk.linux.org/pub/linux/Networking/telnet+ftp/.
+It was downloaded from ftp://ftp.uk.linux.org/pub/linux/Networking/netkit/.
 
 Copyright:
 
@@ -13,6 +13,6 @@ Copyright (c) 1995 David A. Holland
 Copyright (c) 1994 Peter Tobias (issue.net(5))
 Copyright (c) 1983, 1995 Eric P. Allman (setproctitle.[ch])
 
-The license can be found at /usr/doc/copyright/BSD.
+The license can be found at /usr/share/common-licenses/BSD.
 
-$Id: copyright,v 1.2 2000/03/08 01:14:59 herbert Exp $
+$Id: copyright,v 1.4 2001/02/18 20:28:33 herbert Exp $
diff --git a/debian/dirs b/debian/dirs
index 98d15831b4c5..b078dea0e753 100644
--- a/debian/dirs
+++ b/debian/dirs
@@ -1,2 +1,3 @@
 usr/bin
+usr/share/doc/telnet
 usr/share/man/man1
diff --git a/debian/login.c b/debian/login.c
deleted file mode 100644
index 653129eac8b2..000000000000
--- a/debian/login.c
+++ /dev/null
@@ -1,23 +0,0 @@
-#include <unistd.h>
-#include <paths.h>
-#include <syslog.h>
-
-#ifndef _PATH_LOGIN
-#define _PATH_LOGIN	"/bin/login"
-#endif
-
-int main(int argc, char **argv)
-{
-	while(argc--) {
-		if((argv[argc][0] == '-')
-		&& (argv[argc][1] == 'f')) {
-			openlog("login.telnetd", LOG_PID, LOG_AUTHPRIV);
-			syslog(LOG_CRIT, "login.telnetd tried to use \"-f\"");
-			closelog();
-			return 1;
-		}
-	}
-	setuid(geteuid());
-	argv[0] = _PATH_LOGIN;
-	return execv(argv[0], argv);
-}
diff --git a/debian/menu b/debian/menu
new file mode 100644
index 000000000000..f8d50c642e5f
--- /dev/null
+++ b/debian/menu
@@ -0,0 +1,3 @@
+?package(telnet): \
+	needs="text" section="Apps/Net" title="Telnet" command="telnet" \
+	hints="Terminal"
diff --git a/debian/postinst b/debian/postinst
new file mode 100644
index 000000000000..9e6119fbb4f4
--- /dev/null
+++ b/debian/postinst
@@ -0,0 +1,8 @@
+#!/bin/sh -e
+# $Id: postinst,v 1.4 2000/08/23 10:08:42 herbert Exp $
+
+update-alternatives --install /usr/bin/telnet telnet /usr/bin/telnet.netkit \
+		    100 --slave /usr/share/man/man1/telnet.1.gz telnet.1.gz \
+				/usr/share/man/man1/telnet.netkit.1.gz
+
+#DEBHELPER#
diff --git a/debian/prerm b/debian/prerm
new file mode 100644
index 000000000000..5d58010c5301
--- /dev/null
+++ b/debian/prerm
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+if [ "$1" = remove ] || [ "$1" = deconfigure ]; then
+	update-alternatives --remove telnet /usr/bin/telnet.netkit
+fi
+
+#DEBHELPER#
diff --git a/debian/rules b/debian/rules
index 16719e576954..ebbb79b656c5 100755
--- a/debian/rules
+++ b/debian/rules
@@ -1,23 +1,20 @@
 #!/usr/bin/make -f
-# $Id: rules,v 1.6.2.1 2001/08/12 00:34:01 herbert Exp $
+# $Id: rules,v 1.11 2001/01/28 11:03:24 herbert Exp $
 # Sample debian/rules that uses debhelper. GNU copyright 1997 by Joey Hess.
 
 # Uncomment this to turn on verbose mode.
 #export DH_VERBOSE=1
 
-CFLAGS=-g -O2 -Wall
-
 build: build-stamp
-build-stamp: debian/login
+build-stamp:
 	dh_testdir
 
 	if [ ! -f MCONFIG ]; then \
 		./configure; \
-		sed \
-			-e 's/^CFLAGS=.*/& -D_GNU_SOURCE -g/' \
-			-e 's/^CXXFLAGS=.*/& -D_GNU_SOURCE -g/' \
-			MCONFIG > MCONFIG.new; \
-                mv MCONFIG.new MCONFIG; \
+		sed -e 's/^CFLAGS=\(.*\)$$/CFLAGS= -Ddebian -D_GNU_SOURCE -g \1/' \
+		    -e 's/^CXXFLAGS=\(.*\)$$/CXXFLAGS= -Ddebian -D_GNU_SOURCE -g \1/' \
+		    MCONFIG > MCONFIG.new; \
+		mv MCONFIG.new MCONFIG; \
 	fi
 	$(MAKE)
 
@@ -29,7 +26,6 @@ clean:
 	rm -f build-stamp install-stamp
 
 	-$(MAKE) distclean
-	rm -f debian/login debian/login.o
 
 	dh_clean
 
@@ -42,9 +38,15 @@ install-stamp: build-stamp
 
 	$(MAKE) -C telnet INSTALLROOT=`pwd`/debian/tmp MANDIR=/usr/share/man \
 		install
+	mv debian/tmp/usr/bin/telnet debian/tmp/usr/bin/telnet.netkit
+	mv debian/tmp/usr/share/man/man1/telnet.1 \
+	   debian/tmp/usr/share/man/man1/telnet.netkit.1
+	cp telnet/README debian/tmp/usr/share/doc/telnet/README.telnet
+	cp telnet/README.old debian/tmp/usr/share/doc/telnet/README.telnet.old
 	$(MAKE) -C telnetd INSTALLROOT=`pwd`/debian/telnetd \
 		MANDIR=/usr/share/man install
-	cp debian/login debian/telnetd/usr/lib/telnetd
+	cp telnetlogin/telnetlogin.8 debian/telnetd/usr/share/man/man8
+	cp telnetlogin/telnetlogin debian/telnetd/usr/lib
 
 	touch install-stamp
 
@@ -69,7 +71,6 @@ binary-arch: build install
 	dh_strip
 	dh_compress
 	dh_fixperms
-	dh_suidregister
 	dh_installdeb
 	dh_shlibdeps
 	dh_gencontrol
diff --git a/debian/telnetd.dirs b/debian/telnetd.dirs
index 8759ade38d06..710b719aa7c3 100644
--- a/debian/telnetd.dirs
+++ b/debian/telnetd.dirs
@@ -1,4 +1,4 @@
-usr/lib/telnetd
+usr/lib
 usr/share/man/man5
 usr/share/man/man8
 usr/sbin
diff --git a/debian/telnetd.docs b/debian/telnetd.docs
new file mode 100644
index 000000000000..9632452575ab
--- /dev/null
+++ b/debian/telnetd.docs
@@ -0,0 +1,2 @@
+BUGS
+README 
diff --git a/debian/telnetd.postinst b/debian/telnetd.postinst
index 6ff8f5c96514..48c3981cecbb 100644
--- a/debian/telnetd.postinst
+++ b/debian/telnetd.postinst
@@ -1,26 +1,40 @@
 #!/bin/sh -e
-# $Id: telnetd.postinst,v 1.9 2000/03/08 01:13:20 herbert Exp $
+# $Id: telnetd.postinst,v 1.13 2001/05/19 05:34:26 herbert Exp $
+
+update_inetd_entry() {
+	if [ $2 ]; then
+		update-inetd --remove "$rootent"
+		update-inetd --group STANDARD --add "$telnetdent"
+	else
+		update-inetd --remove "$telnetdent"
+		update-inetd --group STANDARD --add "$rootent"
+	fi
+}
 
 if ! id -u telnetd >/dev/null 2>&1; then
 	if sg telnetd -c true 2>/dev/null; then
-		groupdel telnetd
+		adduser --quiet --system --ingroup telnetd \
+			--home /usr/lib/telnetd telnetd
+	else
+		adduser --quiet --system --group --home /usr/lib/telnetd \
+			telnetd
 	fi
 	adduser --quiet --system --group --home /usr/lib/telnetd telnetd
 fi
 adduser --quiet telnetd utmp
-if [ -e /etc/suid.conf -a -x /usr/sbin/suidregister ]; then
-	suidregister -s telnetd /usr/lib/telnetd/login root telnetd 4754
-else
-	chown root.telnetd /usr/lib/telnetd/login
-	chmod 4754 /usr/lib/telnetd/login
+
+if [ -z "$(dpkg-statoverride --list /usr/lib/telnetlogin)" ]; then
+	chown root.telnetd /usr/lib/telnetlogin
+	chmod 4754 /usr/lib/telnetlogin
 fi
 
-if grep -q "^devpts " /proc/mounts; then
-	REMOVE="telnet		stream	tcp	nowait	root	/usr/sbin/tcpd	/usr/sbin/in.telnetd"
-	ADD="telnet		stream	tcp	nowait	telnetd.telnetd	/usr/sbin/tcpd	/usr/sbin/in.telnetd"
+rootent="telnet		stream	tcp	nowait	root	/usr/sbin/tcpd	/usr/sbin/in.telnetd"
+telnetdent="telnet		stream	tcp	nowait	telnetd.telnetd	/usr/sbin/tcpd	/usr/sbin/in.telnetd"
+
+if egrep -q "^(devpts /dev/pts|devfs /dev) " /proc/mounts; then
+	devpts=yes
 else
-	REMOVE="telnet		stream	tcp	nowait	telnetd.telnetd	/usr/sbin/tcpd	/usr/sbin/in.telnetd"
-	ADD="telnet		stream	tcp	nowait	root	/usr/sbin/tcpd	/usr/sbin/in.telnetd"
+	devpts=
 fi
 
 case "$1" in
@@ -28,12 +42,10 @@ abort-upgrade | abort-deconfigure | abort-remove)
 	update-inetd --enable telnet
 	;;
 configure)
-	if [ -n "$2" ] && dpkg --compare-versions "$2" ge 0.14-1 &&
-	   ! grep -q "^$REMOVE" /etc/inetd.conf; then
-		update-inetd --enable telnet
+	if [ -z "$2" ] || dpkg --compare-versions "$2" lt 0.17-13; then
+		update_inetd_entry "$2" $devpts
 	else
-		update-inetd --remove "$REMOVE"
-		update-inetd --group STANDARD --add "$ADD"
+		update-inetd --enable telnet
 	fi
 	;;
 *)
diff --git a/debian/telnetd.postrm b/debian/telnetd.postrm
index cc0531c8ada2..2178a8c1aa2b 100644
--- a/debian/telnetd.postrm
+++ b/debian/telnetd.postrm
@@ -1,20 +1,14 @@
 #!/bin/sh -e
-# $Id: telnetd.postrm,v 1.6 1999/11/25 21:27:08 herbert Exp $
-
-if [ -e /etc/suid.conf -a -x /usr/sbin/suidunregister ]; then
-	suidunregister -s telnetd /usr/lib/telnetd/login
-fi
+# $Id: telnetd.postrm,v 1.9 2001/04/14 07:02:13 herbert Exp $
 
 case "$1" in
-abort-install | remove | abort-upgrade | upgrade | failed-upgrade | disappear)
+abort-install | abort-upgrade | upgrade | failed-upgrade)
+	;;
+remove | disappear)
+	id telnetd > /dev/null 2>&1 && userdel telnetd
+	sg telnetd -c true 2> /dev/null && groupdel telnetd
 	;;
 purge)
-	if id telnetd >/dev/null 2>&1; then
-		userdel telnetd
-	fi
-	if sg telnetd -c true 2>/dev/null; then
-		groupdel telnetd
-	fi
 	# If netbase is not installed, then we don't need to do the remove.
 	if command -v update-inetd >/dev/null 2>&1; then
 		update-inetd --remove "telnet	.*	/usr/sbin/in.telnetd"
@@ -27,3 +21,5 @@ purge)
 esac
 
 #DEBHELPER#
+
+exit 0
diff --git a/debian/telnetd.prerm b/debian/telnetd.prerm
index 47a26d26c12b..0d344ed651bb 100644
--- a/debian/telnetd.prerm
+++ b/debian/telnetd.prerm
@@ -1,9 +1,6 @@
 #!/bin/sh -e
-# $Id: telnetd.prerm,v 1.2 1999/08/27 10:45:45 herbert Exp $
+# $Id: telnetd.prerm,v 1.3 2001/03/15 20:38:36 herbert Exp $
 
-# If netbase is not installed, then we don't need to do the remove.
-if command -v update-inetd >/dev/null 2>&1; then
-        update-inetd --disable telnet
-fi
+update-inetd --disable telnet
 
 #DEBHELPER#
diff --git a/telnet/Makefile b/telnet/Makefile
index cef866f07dbf..70246feaabf3 100644
--- a/telnet/Makefile
+++ b/telnet/Makefile
@@ -7,7 +7,7 @@ include ../MRULES
 
 # -DAUTHENTICATE
 CXXFLAGS += -DUSE_TERMIO -DKLUDGELINEMODE
-LIBS += $(LIBTERMCAP)
+LIBS = $(LIBTERMCAP)
 
 SRCS = commands.cc main.cc network.cc ring.cc sys_bsd.cc telnet.cc \
 	terminal.cc tn3270.cc utilities.cc genget.cc environ.cc netlink.cc
diff --git a/telnet/NetKit-B-0.06-telnet.patch b/telnet/NetKit-B-0.06-telnet.patch
deleted file mode 100644
index 892423b6a956..000000000000
--- a/telnet/NetKit-B-0.06-telnet.patch
+++ /dev/null
@@ -1,27 +0,0 @@
-diff -ur NetKit-B-0.06.orig/telnet/defines.h NetKit-B-0.06/telnet/defines.h
---- NetKit-B-0.06.orig/telnet/defines.h	Fri Dec 17 07:18:16 1993
-+++ NetKit-B-0.06/telnet/defines.h	Mon Jun  5 15:34:51 1995
-@@ -34,6 +34,10 @@
-  *	$Id: NetKit-B-0.06-telnet.patch,v 1.1 1996/07/16 05:17:22 dholland Exp $
-  */
- 
-+#define ENV_VAR NEW_ENV_VAR
-+#define ENV_VALUE NEW_ENV_VALUE
-+#define TELOPT_ENVIRON TELOPT_NEW_ENVIRON
-+
- #define	settimer(x)	clocks.x = clocks.system++
- 
- #if	!defined(TN3270)
-diff -ur NetKit-B-0.06.orig/telnetd/defs.h NetKit-B-0.06/telnetd/defs.h
---- NetKit-B-0.06.orig/telnetd/defs.h	Mon May 23 09:11:57 1994
-+++ NetKit-B-0.06/telnetd/defs.h	Mon Jun  5 15:34:39 1995
-@@ -40,6 +40,9 @@
- #include <sys/types.h>
- #include <sys/param.h>
- 
-+#define ENV_VAR NEW_ENV_VAR
-+#define ENV_VALUE NEW_ENV_VALUE
-+#define TELOPT_ENVIRON TELOPT_NEW_ENVIRON
- 
- #ifndef	BSD
- # define	BSD 43
diff --git a/telnet/authenc.cc b/telnet/authenc.cc
index 5a12a11b3d11..8cc6e576339a 100644
--- a/telnet/authenc.cc
+++ b/telnet/authenc.cc
@@ -35,7 +35,7 @@
  * From: @(#)authenc.c	5.1 (Berkeley) 3/1/91
  */
 char au_rcsid[] = 
-  "$Id: authenc.cc,v 1.5 1996/08/02 01:06:31 dholland Exp $";
+  "$Id: authenc.cc,v 1.6 2000/07/23 03:24:53 dholland Exp $";
 
 #if	defined(ENCRYPT) || defined(AUTHENTICATE)
 #include <sys/types.h>
@@ -84,7 +84,9 @@ telnet_spin()
 telnet_getenv(val)
 	char *val;
 {
-	return((char *)env_getvalue((unsigned char *)val));
+	/* not sure about the export_only flag, but this code
+	 * isn't used anyway --okir */
+	return((char *)env_getvalue((unsigned char *)val, 1));
 }
 
 	char *
diff --git a/telnet/commands.cc b/telnet/commands.cc
index b3a2a3caa5f2..8ee32ccb705c 100644
--- a/telnet/commands.cc
+++ b/telnet/commands.cc
@@ -35,7 +35,7 @@
  * From: @(#)commands.c	5.5 (Berkeley) 3/22/91
  */
 char cmd_rcsid[] = 
-  "$Id: commands.cc,v 1.32 1999/09/28 16:29:24 dholland Exp $";
+  "$Id: commands.cc,v 1.34 2000/07/23 04:16:24 dholland Exp $";
 
 #include <string.h>
 
@@ -73,11 +73,8 @@ char cmd_rcsid[] =
 #include "ptrarray.h"
 #include "netlink.h"
 
-#ifdef __linux__
-#define HAS_IPPROTO_IP
-#endif
-
-#ifdef IPPROTO_IP
+/* In Linux, this is an enum */
+#if defined(__linux__) || defined(IPPROTO_IP)
 #define HAS_IPPROTO_IP
 #endif
 
@@ -160,7 +157,7 @@ class command_entry {
 	assert(argc>=1);
 	if (nargs>=0 && argc!=nargs+1) {
 	    fprintf(stderr, "Wrong number of arguments for command.\n");
-	    fprintf(stderr, "Try %s ? for help\n", argv[0]);
+	    fprintf(stderr, "Try ? %s for help\n", argv[0]);
 	    return 0;    /* is this right? */
 	}
 	if (nargs==-2) {
@@ -688,9 +685,9 @@ static struct togglelist Togglelist[] = {
       "print encryption debugging information" },
 #endif
 
-    { "skiprc", "don't read ~/.telnetrc file",
+    { "skiprc", "don't read the telnetrc files",
       NULL, &skiprc,
-      "read ~/.telnetrc file" },
+      "read the telnetrc files" },
     { "binary",
       "sending and receiving of binary data",
       togbinary, NULL,
@@ -1614,22 +1611,26 @@ void ayt_status(int) {
 #endif
 
 int tn(int argc, const char *argv[]) {
-    register struct hostent *host = 0;
     struct sockaddr_in sn;
-    struct servent *sp = 0;
     char *srp = NULL;
     int srlen;
-
+    int family = 0;
     const char *cmd, *volatile user = 0;
     const char *portp = NULL;
     char *hostp = NULL;
+    char *resolv_hostp;
+    struct addrinfo hints;
+    struct addrinfo *hostaddr = 0;
+    int res;
+    char name[NI_MAXHOST];
+    char service[NI_MAXSERV];
+    struct addrinfo *tmpaddr;
 
     /* clear the socket address prior to use */
     memset(&sn, 0, sizeof(sn));
 
     if (connected) {
 	printf("?Already connected to %s\n", hostname);
-	setuid(getuid());
 	return 0;
     }
     if (_hostname) {
@@ -1666,6 +1667,20 @@ int tn(int argc, const char *argv[]) {
 	    autologin = 1;
 	    continue;
 	}
+	if (strcmp(*argv, "-6") == 0) {
+	    --argc; ++argv;
+#ifdef AF_INET6
+	    family = AF_INET6;
+#else
+	    puts("IPv6 unsupported");
+#endif
+	    continue;
+	}
+	if (strcmp(*argv, "-4") == 0) {
+	    --argc; ++argv;
+	    family = AF_INET;
+	    continue;
+	}
 	if (hostp == 0) {
 	    /* this leaks memory - FIXME */
 	    hostp = strdup(*argv++);
@@ -1679,12 +1694,13 @@ int tn(int argc, const char *argv[]) {
 	}
     usage:
 	printf("usage: %s [-l user] [-a] host-name [port]\n", cmd);
-	setuid(getuid());
 	return 0;
     }
     if (hostp == 0)
 	goto usage;
 
+    resolv_hostp = hostp;
+
 #if defined(IP_OPTIONS) && defined(HAS_IPPROTO_IP)
     if (hostp[0] == '@' || hostp[0] == '!') {
 	if ((hostname = strrchr(hostp, ':')) == NULL)
@@ -1694,91 +1710,101 @@ int tn(int argc, const char *argv[]) {
 	int temp = sourceroute(hostp, &srp, &srlen);
 	if (temp == 0) {
 	    herror(srp);
-	    setuid(getuid());
 	    return 0;
 	} else if (temp == -1) {
 	    printf("Bad source route option: %s\n", hostp);
-	    setuid(getuid());
 	    return 0;
 	} else {
 	    sn.sin_addr.s_addr = temp;
 	    sn.sin_family = AF_INET;
+	    /*
+	     * For source route we just make sure to get the IP given
+	     * on the command line when looking up the port.
+	     */
+	    resolv_hostp = inet_ntoa(sn.sin_addr);
 	}
     } 
-    else {
-#endif
-	if (inet_aton(hostp, &sn.sin_addr)) {
-	    sn.sin_family = AF_INET;
-	    _hostname = new char[strlen(hostp) + 1];
-	    strcpy(_hostname, hostp);
-	    hostname = _hostname;
-	} 
-	else {
-	    host = gethostbyname(hostp);
-	    if (host) {
-		sn.sin_family = host->h_addrtype;
-		if (host->h_length > (int)sizeof(sn.sin_addr)) {
-		    host->h_length = sizeof(sn.sin_addr);
-		}
-#if	defined(h_addr)		/* In 4.3, this is a #define */
-		memcpy((caddr_t)&sn.sin_addr,
-				host->h_addr_list[0], host->h_length);
-#else	/* defined(h_addr) */
-		memcpy((caddr_t)&sn.sin_addr, host->h_addr, host->h_length);
-#endif	/* defined(h_addr) */
-		_hostname = new char [strlen(host->h_name) + 1];
-		strcpy(_hostname, host->h_name);
-		hostname = _hostname;
-	    } else {
-		herror(hostp);
-	        setuid(getuid());
-		return 0;
-	    }
-	}
-#if defined(IP_OPTIONS) && defined(HAS_IPPROTO_IP)
-    }
 #endif
+
+    /* User port or the default name of telnet. */
     if (portp) {
 	if (*portp == '-') {
 	    portp++;
 	    telnetport = 1;
 	} else
 	    telnetport = 0;
-	sn.sin_port = atoi(portp);
-	if (sn.sin_port == 0) {
-	    sp = getservbyname(portp, "tcp");
-	    if (sp)
-		sn.sin_port = sp->s_port;
-	    else {
-		printf("%s: bad port number\n", portp);
-	        setuid(getuid());
-		return 0;
-	    }
-	} 
-	else {
-	    sn.sin_port = htons(sn.sin_port);
-	}
-    } 
+    }
     else {
-	if (sp == 0) {
-	    sp = getservbyname("telnet", "tcp");
-	    if (sp == 0) {
-		fprintf(stderr, "telnet: tcp/telnet: unknown service\n");
-	        setuid(getuid());
-		return 0;
-	    }
-	    sn.sin_port = sp->s_port;
-	}
+	portp = "telnet";
 	telnetport = 1;
     }
-    printf("Trying %s...\n", inet_ntoa(sn.sin_addr));
+
+    /* We only understand SOCK_STREAM sockets. */
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_socktype = SOCK_STREAM;
+    hints.ai_flags = AI_NUMERICHOST;
+    hints.ai_family = family;
+        
+    /* Resolve both the host and service simultaneously. */
+    res = getaddrinfo(resolv_hostp, portp, &hints, &hostaddr);
+    if (res == EAI_NONAME) {
+	hints.ai_flags = AI_CANONNAME;
+	res = getaddrinfo(resolv_hostp, portp, &hints, &hostaddr);
+    } else if (hostaddr) {
+	hostaddr->ai_canonname = 0;
+    }
+    if (res || !hostaddr) {
+	fprintf(stderr, "telnet: could not resolve %s/%s: %s\n", resolv_hostp, portp, gai_strerror(res));
+	return 0;
+    }
+     
+    /* Try to connect to every listed round robin IP. */
+    tmpaddr = hostaddr;
+    errno = 0;
     do {
-	int x = nlink.connect(debug, host, &sn, srp, srlen, tos);
-	if (!x) return 0;
-	else if (x==1) continue;
+	int x;
+
+	if (!tmpaddr) {
+	    if (errno)
+		perror("telnet: Unable to connect to remote host");
+	    else
+		fputs("telnet: Unable to connect to remote host: "
+		      "Bad port number\n", stderr);
+err:
+	    freeaddrinfo(hostaddr);
+	    return 0;
+	}
+
+	if (tmpaddr->ai_family == AF_UNIX) {
+nextaddr:
+	    tmpaddr = tmpaddr->ai_next;
+	    continue;
+	}
+
+	getnameinfo(tmpaddr->ai_addr, tmpaddr->ai_addrlen,
+		    name, sizeof(name), service, sizeof(service),
+		    NI_NUMERICHOST | NI_NUMERICSERV);
+
+	printf("Trying %s...\n", name);
+	x = nlink.connect(debug, tmpaddr, srp, srlen, tos);
+	if (!x)
+	    goto err;
+	else if (x==1)
+	    goto nextaddr;
+
 	connected++;
     } while (connected == 0);
+    if (tmpaddr->ai_canonname == 0) {
+	hostname = new char[strlen(hostp)+1];
+	strcpy(hostname, hostp);
+    }
+    else {
+	hostname = new char[strlen(tmpaddr->ai_canonname)+1];
+	strcpy(hostname, tmpaddr->ai_canonname);
+    }
+
     cmdrc(hostp, hostname);
+    freeaddrinfo(hostaddr);
     if (autologin && user == NULL) {
 	struct passwd *pw;
 
@@ -2024,31 +2050,16 @@ static int help(command_table *tab, int argc, const char *argv[]) {
     return 0;
 }
 
-static char *rcname = 0;
-static char rcbuf[128];
-
-void cmdrc(const char *m1, const char *m2) {
+static void readrc(const char *m1, const char *m2, const char *rcname) {
     FILE *rcfile;
     int gotmachine = 0;
     int l1 = strlen(m1);
     int l2 = strlen(m2);
     char m1save[strlen(m1) + 1];
 
-    if (skiprc) return;
-
     strcpy(m1save, m1);
     m1 = m1save;
 
-    if (rcname == 0) {
-	rcname = getenv("HOME");
-	if (rcname)
-	    strcpy(rcbuf, rcname);
-	else
-	    rcbuf[0] = '\0';
-	strcat(rcbuf, "/.telnetrc");
-	rcname = rcbuf;
-    }
-
     rcfile = fopen(rcname, "r");
     if (!rcfile) return;
 
@@ -2084,6 +2095,25 @@ void cmdrc(const char *m1, const char *m2) {
     fclose(rcfile);
 }
 
+void cmdrc(const char *m1, const char *m2) {
+    static char *rcname = 0;
+    static char rcbuf[128];
+
+    if (skiprc) return;
+
+    readrc(m1, m2, "/etc/telnetrc");
+    if (rcname == 0) {
+	rcname = getenv("HOME");
+	if (rcname)
+	    strcpy(rcbuf, rcname);
+	else
+	    rcbuf[0] = '\0';
+	strcat(rcbuf, "/.telnetrc");
+	rcname = rcbuf;
+    }
+    readrc(m1, m2, rcname);
+}
+
 #if defined(IP_OPTIONS) && defined(HAS_IPPROTO_IP)
 
 /*
diff --git a/telnet/environ.cc b/telnet/environ.cc
index 3950f0471a8d..62d45feccf8d 100644
--- a/telnet/environ.cc
+++ b/telnet/environ.cc
@@ -193,8 +193,9 @@ const char *env_next(int *iter, int exported_only) {
     return NULL;
 }
 
-const char *env_getvalue(const char *var) {
+const char *env_getvalue(const char *var, int exported_only) {
     enviro *ep = env_find(var);
-    if (ep) return ep->getval();
+    if (ep && (!exported_only || ep->getexport()))
+    	return ep->getval();
     return NULL;
 }
diff --git a/telnet/environ.h b/telnet/environ.h
index bc45c088609b..81ad751426af 100644
--- a/telnet/environ.h
+++ b/telnet/environ.h
@@ -4,7 +4,7 @@ void env_export(const char *var);
 void env_unexport(const char *);
 void env_send(const char *);
 void env_list(void);
-const char *env_getvalue(const char *);
+const char *env_getvalue(const char *, int exported_only);
 
 void env_iterate(int *, int exported_only);
 const char *env_next(int *, int exported_only);
diff --git a/telnet/main.cc b/telnet/main.cc
index b67f2ce199c0..565e7055097b 100644
--- a/telnet/main.cc
+++ b/telnet/main.cc
@@ -45,7 +45,10 @@ char main_rcsid[] =
 
 #include <sys/types.h>
 #include <getopt.h>
+#include <stdlib.h>
 #include <string.h>
+#include <netdb.h>
+#include <errno.h>
 
 #include "ring.h"
 #include "externs.h"
@@ -80,12 +83,13 @@ tninit(void)
 void usage(void) {
     fprintf(stderr, "Usage: %s %s%s%s%s\n",
 	    prompt,
-	    " [-8] [-E] [-L] [-a] [-d] [-e char] [-l user] [-n tracefile]",
-	    "\n\t",
+	    "[-4] [-6] [-8] [-E] [-L] [-a] [-d] [-e char] [-l user]",
+	    "\n\t[-n tracefile]",
 #ifdef TN3270
+	    "\n\t"
 	    "[-noasynch] [-noasynctty] [-noasyncnet] [-r] [-t transcom]\n\t",
 #else
-	    "[-r] ",
+	    " [-r] ",
 #endif
 	    "[host-name [port]]"
 	);
@@ -103,6 +107,7 @@ main(int argc, char *argv[])
 	extern int optind;
 	int ch;
 	char *user;
+	int family;
 
 	tninit();		/* Clear out things */
 #if	defined(CRAY) && !defined(__STDC__)
@@ -117,12 +122,23 @@ main(int argc, char *argv[])
 		prompt = argv[0];
 
 	user = NULL;
+	family = 0;
 
 	rlogin = (strncmp(prompt, "rlog", 4) == 0) ? '~' : _POSIX_VDISABLE;
 	autologin = -1;
 
-	while ((ch = getopt(argc, argv, "8EKLS:X:ade:k:l:n:rt:x")) != EOF) {
+	while ((ch = getopt(argc, argv, "468EKLS:X:ade:k:l:n:rt:x")) != EOF) {
 		switch(ch) {
+		case '4':
+			family = AF_INET;
+			break;
+		case '6':
+#ifdef AF_INET6
+			family = AF_INET6;
+#else
+			fputs("IPv6 unsupported\n", stderr);
+#endif
+			break;
 		case '8':
 			eight = 3;	/* binary output and input */
 			break;
@@ -137,19 +153,22 @@ main(int argc, char *argv[])
 			break;
 		case 'S':
 		    {
-#ifdef	HAS_GETTOS
 			extern int tos;
+			int num;
 
-			if ((tos = parsetos(optarg, "tcp")) < 0)
+#ifdef	HAS_GETTOS
+			if ((num = parsetos(optarg, "tcp")) < 0) {
+#else
+			errno = 0;
+			num = strtol(optarg, 0, 0);
+			if (errno) {
+#endif
 				fprintf(stderr, "%s%s%s%s\n",
 					prompt, ": Bad TOS argument '",
 					optarg,
 					"; will try to use default TOS");
-#else
-			fprintf(stderr,
-			   "%s: Warning: -S ignored, no parsetos() support.\n",
-								prompt);
-#endif
+			} else
+				tos = num;
 		    }
 			break;
 		case 'X':
@@ -233,6 +252,9 @@ main(int argc, char *argv[])
 			*argp++ = "-l";
 			*argp++ = user;
 		}
+		if (family) {
+			*argp++ = family == AF_INET ? "-4" : "-6";
+		}
 		*argp++ = argv[0];		/* host */
 		if (argc > 1)
 			*argp++ = argv[1];	/* port */
diff --git a/telnet/netlink.cc b/telnet/netlink.cc
index c4189933ea0a..17d58808a354 100644
--- a/telnet/netlink.cc
+++ b/telnet/netlink.cc
@@ -12,16 +12,11 @@
 #include "proto.h"
 #include "ring.h"
 
-/* In linux, this is an enum */
-#ifdef __linux__
+/* In Linux, this is an enum */
+#if defined(__linux__) || defined(IPPROTO_IP)
 #define HAS_IPPROTO_IP
 #endif
 
-#ifdef IPPROTO_IP
-#define HAS_IPPROTO_IP
-#endif
-
-
 netlink nlink;
 
 class netchannel : public ringbuf::source {
@@ -86,21 +81,23 @@ void netlink::close(int doshutdown) {
     ::close(net);
 }
 
-int netlink::connect(int debug, struct hostent *host, 
-		     struct sockaddr_in *sn, 
+int netlink::connect(int debug, struct addrinfo *addr, 
 		     char *srcroute, int srlen, int tos) 
 {
     int on=1;
 
-    net = socket(AF_INET, SOCK_STREAM, 0);
-    setuid(getuid());
+    net = socket(addr->ai_family, SOCK_STREAM, 0);
     if (net < 0) {
+	if (errno == EAFNOSUPPORT)
+	    return 1;
 	perror("telnet: socket");
 	return 0;
     }
 
 #if defined(IP_OPTIONS) && defined(HAS_IPPROTO_IP)
     if (srcroute) {
+	if (addr->ai_family != AF_INET)
+	    fputs("Source route is only supported for IPv4\n", stderr);
 	if (setsockopt(net, IPPROTO_IP, IP_OPTIONS, srcroute, srlen) < 0)
 	    perror("setsockopt (IP_OPTIONS)");
     }
@@ -114,7 +111,7 @@ int netlink::connect(int debug, struct hostent *host,
 #endif
     if (tos < 0) tos = 020;	/* Low Delay bit */
     if (tos && (setsockopt(net, IPPROTO_IP, IP_TOS, &tos, sizeof(int)) < 0)
-	&& (errno != ENOPROTOOPT))
+	&& (errno != ENOPROTOOPT) && (errno != EOPNOTSUPP))
 	perror("telnet: setsockopt (IP_TOS) (ignored)");
 #endif	/* defined(IPPROTO_IP) && defined(IP_TOS) */
 
@@ -122,27 +119,8 @@ int netlink::connect(int debug, struct hostent *host,
 	perror("setsockopt (SO_DEBUG)");
     }
     
-    if (::connect(net, (struct sockaddr *)sn, sizeof(*sn)) < 0) {
-#if defined(h_addr)		/* In 4.3, this is a #define */
-	if (host && host->h_addr_list[1]) {
-	    int oerrno = errno;
-	    
-	    fprintf(stderr, "telnet: connect to address %s: ",
-		    inet_ntoa(sn->sin_addr));
-	    errno = oerrno;
-	    perror(NULL);
-	    host->h_addr_list++;
-	    if (host->h_length > (int)sizeof(sn->sin_addr)) {
-		host->h_length = sizeof(sn->sin_addr);
-	    }
-	    memcpy(&sn->sin_addr, host->h_addr_list[0], host->h_length);
-	    close(net);
-	    return 1;
-	}
-#endif	/* defined(h_addr) */
-
-	perror("telnet: Unable to connect to remote host");
-	return 0;
+    if (::connect(net, addr->ai_addr, addr->ai_addrlen) < 0) {
+	return 1;
     }
     return 2;
 }
diff --git a/telnet/netlink.h b/telnet/netlink.h
index 9852b3044428..095bac550855 100644
--- a/telnet/netlink.h
+++ b/telnet/netlink.h
@@ -6,8 +6,7 @@ class netlink {
     netlink();
     ~netlink();
 
-    int connect(int debug, struct hostent *host, 
-		struct sockaddr_in *sin, 
+    int connect(int debug, struct addrinfo *hostaddr, 
 		char *srcroute, int srlen,
 		int tos);
     void close(int doshutdown);
diff --git a/telnet/network.cc b/telnet/network.cc
index 6a2c3744f6dc..0dcf3e22a901 100644
--- a/telnet/network.cc
+++ b/telnet/network.cc
@@ -40,6 +40,7 @@ char net_rcsid[] =
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/time.h>
+#include <stdlib.h>
 #include <errno.h>
 #include <arpa/telnet.h>
 
diff --git a/telnet/ring.cc b/telnet/ring.cc
index fdff63e04b2a..772c6c57a4f7 100644
--- a/telnet/ring.cc
+++ b/telnet/ring.cc
@@ -35,7 +35,7 @@
  * From: @(#)ring.c	5.2 (Berkeley) 3/1/91
  */
 char ring_rcsid[] =
-  "$Id: ring.cc,v 1.22 1997/09/23 11:33:16 dholland Exp $";
+  "$Id: ring.cc,v 1.23 2000/07/23 03:25:09 dholland Exp $";
 
 /*
  * This defines a structure for a ring buffer. 
@@ -129,7 +129,11 @@ int ringbuf::flush() {
     busy=1;
 
     /* should always be true */
-    assert(((size+head-tail)%size)==count);
+    /* assert(((size+head-tail)%size)==count); */
+    /* Nope! The above fails if the buffer is full; then:
+     * head == tail (so LHS is 0), but count == size.
+     * The following formula should be better. --okir */
+    assert(((head - tail - count) % size) == 0);
 
     while (count > 0) {
 	int bot = tail;
@@ -161,7 +165,7 @@ int ringbuf::flush() {
 
 /////////////////////////////////////////////////// supply //////////////
 
-void ringbuf::printf(const char *format, ...) {
+void ringbuf::xprintf(const char *format, ...) {
     char xbuf[256];
     va_list ap;
     va_start(ap, format);
diff --git a/telnet/ring.h b/telnet/ring.h
index 15d3f3f637da..049377e51448 100644
--- a/telnet/ring.h
+++ b/telnet/ring.h
@@ -83,7 +83,7 @@ class ringbuf {
     // manual supply
     void putch(char c) { write(&c, 1); }
     void write(const char *buffer, int ct);
-    void printf(const char *format, ...);
+    void xprintf(const char *format, ...);
     int empty_count() { return size - count; }
 
     // automatic supply
diff --git a/telnet/sys_bsd.cc b/telnet/sys_bsd.cc
index 63f89e94e174..a8c9aab91281 100644
--- a/telnet/sys_bsd.cc
+++ b/telnet/sys_bsd.cc
@@ -194,14 +194,20 @@ static void deadpeer(int /*sig*/) {
     setcommandmode();
     siglongjmp(peerdied, -1);
 }
+#endif
 
 static void intr(int /*sig*/) {
     if (localchars) {
 	intp();
     }
     else {
+#if 0
         setcommandmode();
 	siglongjmp(toplevel, -1);
+#else
+	signal(SIGINT, SIG_DFL);
+	raise(SIGINT);
+#endif
     }
 }
 
@@ -215,8 +221,9 @@ static void intr2(int /*sig*/) {
 	    sendabort();
 	return;
     }
+    signal(SIGQUIT, SIG_DFL);
+    raise(SIGQUIT);
 }
-#endif
 
 #ifdef	SIGWINCH
 static void sendwin(int /*sig*/) {
@@ -238,9 +245,9 @@ void ayt(int sig) {
 #endif
 
 void sys_telnet_init(void) {
-#if 0
     signal(SIGINT, intr);
     signal(SIGQUIT, intr2);
+#if 0
     signal(SIGPIPE, deadpeer);
 #endif
 #ifdef	SIGWINCH
diff --git a/telnet/telnet.1 b/telnet/telnet.1
index 543d794eb02c..55d4bee96f9e 100644
--- a/telnet/telnet.1
+++ b/telnet/telnet.1
@@ -30,11 +30,11 @@
 .\" SUCH DAMAGE.
 .\"
 .\"	from: @(#)telnet.1	6.16 (Berkeley) 7/27/91
-.\"	$Id: telnet.1,v 1.10 1999/12/14 12:53:02 dholland Exp $
+.\"	$Id: telnet.1,v 1.15 2000/07/30 23:57:08 dholland Exp $
 .\"
 .Dd August 15, 1999
 .Dt TELNET 1
-.Os "Linux NetKit (0.16)"
+.Os "Linux NetKit (0.17)"
 .Sh NAME
 .Nm telnet
 .Nd user interface to the 
@@ -42,7 +42,7 @@
 protocol
 .Sh SYNOPSIS
 .Nm telnet
-.Op Fl 8ELadr
+.Op Fl 468ELadr
 .Op Fl S Ar tos
 .Op Fl e Ar escapechar
 .Op Fl l Ar user
@@ -68,6 +68,10 @@ command implicitly; see the description below.
 .Pp
 Options:
 .Bl -tag -width indent
+.It Fl 4
+Force IPv4 address resolution.
+.It Fl 6
+Force IPv6 address resolution.
 .It Fl 8
 Request 8-bit operation. This causes an attempt to negotiate the
 .Dv TELNET BINARY
@@ -474,17 +478,21 @@ protocol without making a mess. Protocol negotiation can be forced by
 placing a dash before the port number.
 .Pp
 After establishing a connection, any commands associated with the
-remote host in the user's
+remote host in
+.Pa /etc/telnetrc
+and the user's
 .Pa .telnetrc
-file are executed.
+file are executed, in that order.
 .Pp
-The format of the .telnetrc file is as follows: Lines beginning with a
+The format of the telnetrc files is as follows: Lines beginning with a
 #, and blank lines, are ignored.  The rest of the file should consist
 of hostnames and sequences of
 .Nm telnet
 commands to use with that host. Commands should be one per line,
 indented by whitespace; lines beginning without whitespace are
-interpreted as hostnames. Upon connecting to a particular host, the
+interpreted as hostnames.  Lines beginning with the special hostname
+.Ql DEFAULT
+will apply to all hosts.  Upon connecting to a particular host, the
 commands associated with that host are executed.
 .It Ic quit
 Close any open session and exit
@@ -1184,9 +1192,7 @@ escape sequences are preceded by a '*' to aid in locating them.
 When the skiprc toggle is
 .Dv TRUE ,
 .Tn telnet
-does not read the 
-.Pa \&.telnetrc
-file.  The initial value for this toggle is
+does not read the telnetrc files.  The initial value for this toggle is
 .Dv FALSE.
 .It Ic termdata
 Toggles the display of all terminal data (in hexadecimal format).
@@ -1239,7 +1245,9 @@ to the other side via the
 .Dv TELNET ENVIRON
 option.
 .Sh FILES
-.Bl -tag -width ~/.telnetrc -compact
+.Bl -tag -width /etc/telnetrc -compact
+.It Pa /etc/telnetrc
+global telnet startup values
 .It Pa ~/.telnetrc
 user customized telnet startup values
 .El
diff --git a/telnet/telnet.cc b/telnet/telnet.cc
index 7a682599e513..e5c613dd5da8 100644
--- a/telnet/telnet.cc
+++ b/telnet/telnet.cc
@@ -35,7 +35,7 @@
  * From: @(#)telnet.c	5.53 (Berkeley) 3/22/91
  */
 char telnet_rcsid[] = 
-"$Id: telnet.cc,v 1.34 1999/08/19 09:34:15 dholland Exp $";
+"$Id: telnet.cc,v 1.36 2000/07/23 03:24:53 dholland Exp $";
 
 #include <string.h>
 #include <sys/types.h>
@@ -456,7 +456,7 @@ static void dooption(int option) {
 	break;
 	
       case TELOPT_XDISPLOC:	/* X Display location */
-	if (env_getvalue("DISPLAY"))
+	if (env_getvalue("DISPLAY", 0))
 	  new_state_ok = 1;
 	break;
 	
@@ -600,7 +600,9 @@ static void mklist(char *buf, const char *name, stringarray &fill) {
    */
   
   fill.add(fill[fill.num()-1]);
-  fill.add(NULL);
+
+  /* dholland 21-May-2000 I think this is bogus */
+  /*fill.add(NULL);*/
 }
 
 char termbuf[2048];
@@ -636,7 +638,7 @@ static const char *gettermname(void) {
   
   if (resettermname) {
     resettermname = 0;
-    tname = env_getvalue("TERM");
+    tname = env_getvalue("TERM", 0);
     if (!tname || my_setupterm(tname, 1, &err)) {
       termbuf[0] = 0;
       tname = "UNKNOWN";
@@ -644,7 +646,7 @@ static const char *gettermname(void) {
     mklist(termbuf, tname, termtypes);
     next = 0;
   }
-  if (next==termtypes.num()) next = 0;
+  if (next==termtypes.num()-1) next = 0;
   return termtypes[next++];
 }
 /*
@@ -679,7 +681,7 @@ static void suboption(void) {
       }
 #endif /* TN3270 */
       name = gettermname();
-      netoring.printf("%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
+      netoring.xprintf("%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
 		      TELQUAL_IS, name, IAC, SE);
     }
     break;
@@ -691,7 +693,7 @@ static void suboption(void) {
     if (SB_GET() == TELQUAL_SEND) {
       long oospeed, iispeed;
       TerminalSpeeds(&iispeed, &oospeed);
-      netoring.printf("%c%c%c%c%ld,%ld%c%c", IAC, SB, TELOPT_TSPEED, 
+      netoring.xprintf("%c%c%c%c%ld,%ld%c%c", IAC, SB, TELOPT_TSPEED, 
 		      TELQUAL_IS, oospeed, iispeed, IAC, SE);
     }
     break;
@@ -769,7 +771,7 @@ static void suboption(void) {
     if (SB_EOF())
       return;
     if (SB_GET() == TELQUAL_SEND) {
-      const char *dp = env_getvalue("DISPLAY");
+      const char *dp = env_getvalue("DISPLAY", 0);
       if (dp == NULL) {
 	/*
 	 * Something happened, we no longer have a DISPLAY
@@ -778,7 +780,7 @@ static void suboption(void) {
 	send_wont(TELOPT_XDISPLOC, 1);
 	break;
       }
-      netoring.printf("%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC,
+      netoring.xprintf("%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC,
 		      TELQUAL_IS, dp, IAC, SE);
     }
     break;
@@ -796,7 +798,7 @@ void lm_will(unsigned char *cmd, int len) {
     return;
   }
   
-  netoring.printf("%c%c%c%c%c%c%c", IAC, SB, TELOPT_LINEMODE, 
+  netoring.xprintf("%c%c%c%c%c%c%c", IAC, SB, TELOPT_LINEMODE, 
 		  DONT, cmd[0], IAC, SE);
 }
 
@@ -813,7 +815,7 @@ void lm_do(unsigned char *cmd, int len) {
     /*@*/	printf("lm_do: no command!!!\n");	/* Should not happen... */
     return;
   }
-  netoring.printf("%c%c%c%c%c%c%c", IAC, SB, TELOPT_LINEMODE, 
+  netoring.xprintf("%c%c%c%c%c%c%c", IAC, SB, TELOPT_LINEMODE, 
 		  WONT, cmd[0], IAC, SE);
 }
 
@@ -836,7 +838,7 @@ void lm_mode(unsigned char *cmd, int len, int init) {
     k |= MODE_ACK;
   }
   
-  netoring.printf("%c%c%c%c%c%c%c", IAC, SB, TELOPT_LINEMODE, LM_MODE,
+  netoring.xprintf("%c%c%c%c%c%c%c", IAC, SB, TELOPT_LINEMODE, LM_MODE,
 		  k, IAC, SE);
   
   setconnmode(0);	/* set changed mode */
@@ -931,11 +933,11 @@ void slc_mode_import(int def) {
 
 void slc_import(int def) {
   if (def) {
-    netoring.printf("%c%c%c%c%c%c%c%c%c", IAC, SB, TELOPT_LINEMODE,
+    netoring.xprintf("%c%c%c%c%c%c%c%c%c", IAC, SB, TELOPT_LINEMODE,
 		    LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE);
   }
   else {
-    netoring.printf("%c%c%c%c%c%c%c%c%c", IAC, SB, TELOPT_LINEMODE,
+    netoring.xprintf("%c%c%c%c%c%c%c%c%c", IAC, SB, TELOPT_LINEMODE,
 		    LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE);
   }
 }
@@ -1184,7 +1186,7 @@ void env_opt_add(const char *ep) {
     for (ep = env_next(&i,1); ep; ep = env_next(&i,1)) env_opt_add(ep);
     return;
   }
-  vp = env_getvalue(ep);
+  vp = env_getvalue(ep, 1);
   tp = opt_replyp + (vp ? strlen(vp) * 2 : 0) + strlen(ep) * 2 + 6;
   if (tp > opt_replyend)
     {
@@ -1739,7 +1741,7 @@ void telnet(const char * /*user*/) {
     send_will(TELOPT_LINEMODE, 1);
     send_will(TELOPT_ENVIRON, 1);
     send_do(TELOPT_STATUS, 1);
-    if (env_getvalue("DISPLAY"))
+    if (env_getvalue("DISPLAY", 0))
       send_will(TELOPT_XDISPLOC, 1);
     if (eight)
       tel_enter_binary(eight);
diff --git a/telnet/terminal.cc b/telnet/terminal.cc
index 9eb47aec3b68..c1adf18b64ce 100644
--- a/telnet/terminal.cc
+++ b/telnet/terminal.cc
@@ -45,6 +45,8 @@ char terminal_rcsid[] =
 #include <signal.h>
 #include <errno.h>
 #include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
 
 #include "ring.h"
 #include "defines.h"
diff --git a/telnet/utilities.cc b/telnet/utilities.cc
index 0448f0a990c6..66839abd6534 100644
--- a/telnet/utilities.cc
+++ b/telnet/utilities.cc
@@ -47,6 +47,8 @@ char util_rcsid[] =
 #include <sys/socket.h>
 #include <unistd.h>
 #include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
 
 #include "ring.h"
 #include "defines.h"
diff --git a/telnetd/Makefile b/telnetd/Makefile
index 9b80e987adb3..8ebd78e1bde1 100644
--- a/telnetd/Makefile
+++ b/telnetd/Makefile
@@ -10,7 +10,7 @@ include ../MRULES
 
 CFLAGS += '-DISSUE_FILE="/etc/issue.net"' -DPARANOID_TTYS \
 	   -DNO_REVOKE -DKLUDGELINEMODE -DDIAGNOSTICS \
-	   -DLOGIN_WRAPPER=\"/usr/lib/telnetd/login\"
+	   -DLOGIN_WRAPPER=\"/usr/lib/telnetlogin\"
 # LIBS += $(LIBTERMCAP)
 
 OBJS = telnetd.o state.o termstat.o slc.o sys_term.o utility.o \
diff --git a/telnetd/authenc.c b/telnetd/authenc.c
index d11a7244d891..c01dfbc65330 100644
--- a/telnetd/authenc.c
+++ b/telnetd/authenc.c
@@ -42,18 +42,6 @@ net_write(str, len)
     return(0);
 }
 
-void
-net_encrypt()
-{
-#if	defined(ENCRYPT)
-    char *s = (nclearto > nbackp) ? nclearto : nbackp;
-    if (s < nfrontp && encrypt_output) {
-	(*encrypt_output)((unsigned char *)s, nfrontp - s);
-    }
-    nclearto = nfrontp;
-#endif
-}
-
 int
 telnet_spin()
 {
diff --git a/telnetd/defs.h b/telnetd/defs.h
index ea1997fdc0f1..397948c7548c 100644
--- a/telnetd/defs.h
+++ b/telnetd/defs.h
@@ -55,10 +55,11 @@
 #include <fcntl.h>
 #include <sys/file.h>
 #include <sys/stat.h>
-#include <sys/time.h>
+#include <time.h>
 #include <sys/ioctl.h>
 #include <netinet/in.h>
 #include <arpa/telnet.h>
+#include <sys/uio.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <signal.h>
diff --git a/telnetd/ext.h b/telnetd/ext.h
index b98d6ec01589..0929432b4fda 100644
--- a/telnetd/ext.h
+++ b/telnetd/ext.h
@@ -81,12 +81,11 @@ extern char *loginprg;
  */
 extern char ptyobuf[BUFSIZ+NETSLOP], *pfrontp, *pbackp;
 extern char netibuf[BUFSIZ], *netip;
-extern char netobuf[BUFSIZ+NETSLOP], *nfrontp, *nbackp;
-extern char *neturg;		/* one past last byte of urgent data */
 extern int pcc, ncc;
+extern FILE *netfile;
 
 /* printf into netobuf */
-void netoprintf(const char *fmt, ...) __attribute((format (printf, 1, 2))); 
+#define netoprintf(fmt, ...) fprintf(netfile, fmt, ## __VA_ARGS__)
 
 extern int pty, net;
 extern char *line;
@@ -96,7 +95,7 @@ void _termstat(void);
 void add_slc(int, int, int);
 void check_slc(void);
 void change_slc(int, int, int);
-void cleanup(int);
+void cleanup(int) __attribute__ ((noreturn));
 void clientstat(int, int, int);
 void copy_termbuf(char *, int);
 void deferslc(void);
@@ -106,8 +105,8 @@ void doeof(void);
 void dooption(int);
 void dontoption(int);
 void edithost(const char *, const char *);
-void fatal(int, const char *);
-void fatalperror(int, const char *);
+void fatal(int, const char *) __attribute__ ((noreturn));
+void fatalperror(int, const char *) __attribute__ ((noreturn));
 void get_slc_defaults(void);
 void init_env(void);
 void init_termbuf(void);
@@ -115,6 +114,8 @@ void interrupt(void);
 void localstat(void);
 void netclear(void);
 void netflush(void);
+size_t netbuflen(int);
+void sendurg(const char *, size_t);
 
 #ifdef DIAGNOSTICS
 void printoption(const char *, int);
@@ -182,10 +183,11 @@ void tty_setsofttab(int);
 void tty_tspeed(int);
 void willoption(int);
 void wontoption(int);
-void writenet(unsigned char *, int);
+#define writenet(b, l) fwrite(b, 1, l, netfile)
+void netopen(void);
 
 #if defined(ENCRYPT)
-extern void (*encrypt_output)(unsigned char *, int);
+extern void (*encrypt_output)(const unsigned char *, int);
 extern int (*decrypt_input)(int);
 extern char *nclearto;
 #endif
diff --git a/telnetd/global.c b/telnetd/global.c
index badd4d53000b..c8d1d2b7540a 100644
--- a/telnetd/global.c
+++ b/telnetd/global.c
@@ -87,11 +87,10 @@ char	ptyobuf[BUFSIZ+NETSLOP], *pfrontp, *pbackp;
 
 char	netibuf[BUFSIZ], *netip;
 
-char	netobuf[BUFSIZ+NETSLOP], *nfrontp, *nbackp;
-char	*neturg;		/* one past last bye of urgent data */
-
 int	pcc, ncc;
 
+FILE	*netfile;
+
 int	pty, net;
 int	SYNCHing;		/* we are in TELNET SYNCH mode */
 
diff --git a/telnetd/issue.net.5 b/telnetd/issue.net.5
index c3337ee6efad..ff5de097909e 100644
--- a/telnetd/issue.net.5
+++ b/telnetd/issue.net.5
@@ -6,7 +6,7 @@
 .\"
 .Dd May 22, 1994
 .Dt ISSUE.NET 5 
-.Os "Linux NetKit (0.16)"
+.Os "Linux NetKit (0.17)"
 .Sh NAME
 .Nm issue.net 
 .Nd identification file for telnet sessions
diff --git a/telnetd/login.3 b/telnetd/login.3
index f059f60a70db..5a8d20b3f067 100644
--- a/telnetd/login.3
+++ b/telnetd/login.3
@@ -35,7 +35,7 @@
 .\"
 .Dd December 14, 1995
 .Dt LOGIN 3
-.Os "Linux NetKit (0.16)"
+.Os "Linux NetKit (0.17)"
 .Sh NAME
 .Nm login ,
 .Nm logout ,
diff --git a/telnetd/setproctitle.3 b/telnetd/setproctitle.3
index 541fa507397a..9eb43e86ec8f 100644
--- a/telnetd/setproctitle.3
+++ b/telnetd/setproctitle.3
@@ -1,5 +1,5 @@
 .\"	OpenBSD: setproctitle.3,v 1.4 1996/10/08 01:20:08 michaels Exp 
-.\"     $Id: setproctitle.3,v 1.8 1999/12/14 12:53:06 dholland Exp $
+.\"     $Id: setproctitle.3,v 1.13 2000/07/30 23:57:09 dholland Exp $
 .\"
 .\" Copyright (c) 1994, 1995 Christopher G. Demetriou
 .\" All rights reserved.
@@ -32,7 +32,7 @@
 .\"
 .Dd April 13, 1994
 .Dt SETPROCTITLE 3
-.Os "Linux NetKit (0.16)"
+.Os "Linux NetKit (0.17)"
 .Sh NAME
 .Nm setproctitle
 .Nd set process title
diff --git a/telnetd/state.c b/telnetd/state.c
index b757411330ec..0054ce917600 100644
--- a/telnetd/state.c
+++ b/telnetd/state.c
@@ -179,6 +179,7 @@ void telrcv(void) {
 		   */
 	      case AO:
 		  {
+		      static const char msg[] = { IAC, DM };
 		      DIAG(TD_OPTIONS, printoption("td: recv IAC", c));
 		      ptyflush();	/* half-hearted */
 		      init_termbuf();
@@ -191,9 +192,7 @@ void telrcv(void) {
 		      }
 
 		      netclear();	/* clear buffer back */
-		      *nfrontp++ = (char)IAC;
-		      *nfrontp++ = (char)DM;
-		      neturg = nfrontp-1; /* off by one XXX */
+		      sendurg(msg, sizeof(msg));
 		      DIAG(TD_OPTIONS, printoption("td: send IAC", DM));
 		      break;
 		  }
diff --git a/telnetd/sys_term.c b/telnetd/sys_term.c
index 57db62428859..4ec45bb2c294 100644
--- a/telnetd/sys_term.c
+++ b/telnetd/sys_term.c
@@ -35,7 +35,7 @@
  * From: @(#)sys_term.c	5.16 (Berkeley) 3/22/91
  */
 char st_rcsid[] = 
-  "$Id: sys_term.c,v 1.16 1999/12/12 14:59:45 dholland Exp $";
+  "$Id: sys_term.c,v 1.17 1999/12/17 14:28:47 dholland Exp $";
 
 #include <utmp.h>
 
@@ -740,5 +740,5 @@ void cleanup(int sig) {
     chmod(line, 0666);
     chown(line, 0, 0);
     shutdown(net, 2);
-    exit(1);
+    exit(0);
 }
diff --git a/telnetd/telnetd.8 b/telnetd/telnetd.8
index 7353448e2941..d7a2ae7bd916 100644
--- a/telnetd/telnetd.8
+++ b/telnetd/telnetd.8
@@ -30,13 +30,13 @@
 .\" SUCH DAMAGE.
 .\"
 .\"	from: @(#)telnetd.8	6.8 (Berkeley) 4/20/91
-.\"	$Id: telnetd.8,v 1.13 1999/12/14 12:53:06 dholland Exp $
+.\"	$Id: telnetd.8,v 1.18 2000/07/30 23:57:10 dholland Exp $
 .\"
 .Dd December 29, 1996
-.Dt IN.TELNETD 8
-.Os "Linux NetKit (0.16)"
+.Dt TELNETD 8
+.Os "Linux NetKit (0.17)"
 .Sh NAME
-.Nm in.telnetd
+.Nm telnetd
 .Nd DARPA
 .Tn telnet
 protocol server
@@ -52,12 +52,12 @@ protocol server
 .Op Fl debug Ar port
 .Sh DESCRIPTION
 The
-.Nm in.telnetd
+.Nm telnetd
 program is a server which supports the 
 .Tn DARPA
 .Tn telnet
 interactive communication protocol.
-.Nm In.telnetd
+.Nm Telnetd
 is normally invoked by the internet server (see
 .Xr inetd 8 )
 for requests to connect to the
@@ -69,26 +69,26 @@ file (see
 The
 .Fl debug
 option may be used to start up 
-.Nm in.telnetd
+.Nm telnetd
 manually, instead of through
 .Xr inetd 8 .
 If started up this way, 
 .Ar port
 may be specified to run 
-.Nm in.telnetd
+.Nm telnetd
 on an alternate 
 .Tn TCP 
 port number.
 .Pp
 The 
-.Nm in.telnetd
+.Nm telnetd
 program accepts the following options:
 .Bl -tag -width "-a authmode"
 .It Fl a Ar authmode
 This option may be used for specifying what mode should
 be used for authentication.
 Note that this option is only useful if
-.Nm in.telnetd
+.Nm telnetd
 has been compiled with support for authentication, which is not
 available in the current version.  The following values of
 .Ar authmode 
@@ -125,10 +125,10 @@ program.
 .El
 .It Fl D Ar debugmode
 This option may be used for debugging purposes.  This allows
-.Nm in.telnetd
+.Nm telnetd
 to print out debugging information to the connection, allowing the
 user to see what
-.Nm in.telnetd
+.Nm telnetd
 is doing.  There are several possible values for
 .Ar debugmode:
 .Bl -tag -width exercise
@@ -143,7 +143,7 @@ information, plus some additional information about what processing is
 going on.
 .It Cm netdata
 Displays the data stream received by
-.Nm in.telnetd.
+.Nm telnetd.
 .It Cm ptydata
 Displays data written to the pty.
 .It Cm exercise
@@ -151,7 +151,7 @@ Has not been implemented yet.
 .El
 .It Fl edebug
 If
-.Nm in.telnetd
+.Nm telnetd
 has been compiled with support for encryption, then the
 .Fl edebug
 option may be used to enable encryption debugging code.
@@ -161,13 +161,13 @@ login has been completed.
 .It Fl L Ar loginprg
 This option may be used to specify a different login program.
 By default, 
-.Pa /usr/lib/telnetd/login
+.Pa /usr/sbin/telnetlogin
 is used.
 .It Fl n
 Disable
 .Dv TCP
 keep-alives.  Normally
-.Nm in.telnetd
+.Nm telnetd
 enables the
 .Tn TCP
 keep-alive mechanism to probe connections that
@@ -177,7 +177,7 @@ from machines that have crashed or can no longer
 be reached may be cleaned up.
 .It Fl s
 This option is only enabled if
-.Nm in.telnetd
+.Nm telnetd
 is compiled with support for
 .Tn SecurID
 cards.
@@ -199,24 +199,24 @@ connection to the value
 .Ar tos .
 .It Fl X Ar authtype
 This option is only valid if
-.Nm in.telnetd
+.Nm telnetd
 has been built with support for the authentication option.
 It disables the use of
 .Ar authtype
 authentication, and
 can be used to temporarily disable
 a specific authentication type without having to recompile
-.Nm in.telnetd .
+.Nm telnetd .
 .El
 .Pp
 If the file
 .Pa /etc/issue.net
 is present,
-.Nm in.telnetd
+.Nm telnetd
 will display its contents before the login prompt of a telnet session (see
 .Xr issue.net 5 ) .
 .Pp
-.Nm In.telnetd
+.Nm Telnetd
 operates by allocating a pseudo-terminal device (see
 .Xr pty 4 )
 for a client, then creating a login process which has
@@ -225,7 +225,7 @@ the slave side of the pseudo-terminal as
 .Dv stdout ,
 and
 .Dv stderr .
-.Nm In.telnetd
+.Nm Telnetd
 manipulates the master side of the pseudo-terminal,
 implementing the
 .Tn telnet
@@ -235,7 +235,7 @@ between the remote client and the login process.
 When a
 .Tn telnet
 session is started up, 
-.Nm in.telnetd
+.Nm telnetd
 sends
 .Tn telnet
 options to the client side indicating
@@ -267,7 +267,7 @@ to operate in \*(lqcooked\*(rq mode, and with
 enabled (see
 .Xr tty 4 ) .
 .Pp
-.Nm In.telnetd
+.Nm Telnetd
 has support for enabling locally the following
 .Tn telnet
 options:
@@ -284,13 +284,13 @@ current state of terminal echoing.
 When terminal echo is not desired, a
 .Dv WILL ECHO
 is sent to indicate that
-.Tn in.telnetd
+.Tn telnetd
 will take care of echoing any data that needs to be
 echoed to the terminal, and then nothing is echoed.
 When terminal echo is desired, a
 .Dv WONT ECHO
 is sent to indicate that
-.Tn in.telnetd
+.Tn telnetd
 will not be doing any terminal echoing, so the
 client should do any terminal echoing that is needed.
 .It "WILL BINARY"
@@ -322,20 +322,20 @@ is sent in response, and the
 session is shut down.
 .It "WILL ENCRYPT"
 Only sent if
-.Nm in.telnetd
+.Nm telnetd
 is compiled with support for data encryption, and
 indicates a willingness to decrypt
 the data stream.
 .El
 .Pp
-.Nm In.telnetd
+.Nm Telnetd
 has support for enabling remotely the following
 .Tn TELNET
 options:
 .Bl -tag -width "DO AUTHENTICATION"
 .It "DO BINARY"
 Sent to indicate that
-.Tn in.telnetd
+.Tn telnetd
 is willing to receive an 8 bit data stream.
 .It "DO LFLOW"
 Requests that the client handle flow control
@@ -377,12 +377,12 @@ Indicates a desire to be able to request environment
 variable information, as described in RFC 1408.
 .It "DO LINEMODE"
 Only sent if
-.Nm in.telnetd
+.Nm telnetd
 is compiled with support for linemode, and
 requests that the client do line by line processing.
 .It "DO TIMING-MARK"
 Only sent if
-.Nm in.telnetd
+.Nm telnetd
 is compiled with support for both linemode and
 kludge linemode, and the client responded with
 .Dv WONT LINEMODE.
@@ -395,17 +395,18 @@ Note that the
 option can be used to disable this.
 .It "DO AUTHENTICATION"
 Only sent if
-.Nm in.telnetd
+.Nm telnetd
 is compiled with support for authentication, and
 indicates a willingness to receive authentication
 information for automatic login.
 .It "DO ENCRYPT"
 Only sent if
-.Nm in.telnetd
+.Nm telnetd
 is compiled with support for data encryption, and
 indicates a willingness to decrypt
 the data stream.
 .Xr issue.net 5 ) .
+.El
 .Sh FILES
 .Pa /etc/services ,
 .Pa /etc/issue.net
@@ -458,6 +459,7 @@ Telnet Authentication: SPX
 Telnet Environment Option Interoperability Issues
 .It Cm RFC-1572
 Telnet Environment Option
+.El
 .Sh BUGS
 Some
 .Tn TELNET
@@ -465,7 +467,7 @@ commands are only partially implemented.
 .Pp
 Because of bugs in the original 4.2 BSD
 .Xr telnet 1 ,
-.Nm in.telnetd
+.Nm telnetd
 performs some dubious protocol exchanges to try to discover if the remote
 client is, in fact, a 4.2 BSD
 .Xr telnet 1 .
@@ -477,7 +479,7 @@ has no common interpretation except between similar operating systems
 The terminal type name received from the remote client is converted to
 lower case.
 .Pp
-.Nm In.telnetd
+.Nm Telnetd
 never sends
 .Tn TELNET
 .Dv IAC GA
diff --git a/telnetd/telnetd.c b/telnetd/telnetd.c
index ffa49e8d4d8a..7de8b982e301 100644
--- a/telnetd/telnetd.c
+++ b/telnetd/telnetd.c
@@ -39,16 +39,20 @@ char copyright[] =
  * From: @(#)telnetd.c	5.48 (Berkeley) 3/1/91
  */
 char telnetd_rcsid[] = 
-  "$Id: telnetd.c,v 1.23 1999/12/14 00:43:31 dholland Exp $";
+  "$Id: telnetd.c,v 1.24 2000/04/12 21:36:12 dholland Exp $";
 
 #include "../version.h"
 
+#include <sys/socket.h>
 #include <netdb.h>
 #include <termcap.h>
 #include <netinet/in.h>
 /* #include <netinet/ip.h> */ /* Don't think this is used at all here */
 #include <arpa/inet.h>
 #include <assert.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <unistd.h>
 #include "telnetd.h"
 #include "pathnames.h"
 #include "setproctitle.h"
@@ -63,7 +67,12 @@ int	auth_level = 0;
 int	require_SecurID = 0;
 #endif
 
-static void doit(struct sockaddr_in *who);
+/* In Linux, this is an enum */
+#if defined(__linux__) || defined(IPPROTO_IP)
+#define HAS_IPPROTO_IP
+#endif
+
+static void doit(struct sockaddr *who, socklen_t who_len);
 static int terminaltypeok(const char *s);
 
 /*
@@ -82,19 +91,119 @@ char *loginprg = LOGIN_WRAPPER;
 #else
 char *loginprg = _PATH_LOGIN;
 #endif
-char *progname;
 
 extern void usage(void);
 
+static void
+wait_for_connection(const char *service)
+{
+	struct addrinfo hints;
+	struct addrinfo *res, *addr;
+	struct pollfd *fds, *fdp;
+	int nfds;
+	int i;
+	int error;
+	int on = 1;
+
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_family = PF_UNSPEC;
+	hints.ai_flags = AI_PASSIVE;
+	hints.ai_socktype = SOCK_STREAM;
+	error = getaddrinfo(NULL, service, &hints, &res);
+	if (error) {
+		char *p;
+		error = asprintf(&p, "getaddrinfo: %s\n", gai_strerror(error));
+		fatal(2, error >= 0 ? p : "");
+	}
+
+	for (addr = res, nfds = 0; addr; addr = addr->ai_next, nfds++)
+		;
+	fds = malloc(sizeof(struct pollfd) * nfds);
+	for (addr = res, fdp = fds; addr; addr = addr->ai_next, fdp++) {
+		int s;
+
+		if (addr->ai_family == AF_LOCAL) {
+nextaddr:
+			fdp--;
+			nfds--;
+			continue;
+		}
+
+		s = socket(addr->ai_family, SOCK_STREAM, 0);
+		if (s < 0) {
+			if (errno == EAFNOSUPPORT || errno == EINVAL) {
+				goto nextaddr;
+			}
+			fatalperror(2, "socket");
+		}
+		if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) {
+			fatalperror(2, "setsockopt");
+		}
+		if (bind(s, addr->ai_addr, addr->ai_addrlen)) {
+#ifdef linux
+			if (fdp != fds && errno == EADDRINUSE) {
+				close(s);
+				goto nextaddr;
+			}
+#endif
+			fatalperror(2, "bind");
+		}
+		if (listen(s, 1)) {
+			fatalperror(2, "listen");
+		}
+		if (fcntl(s, F_SETFL, O_NONBLOCK)) {
+			fatalperror(2, "fcntl");
+		}
+
+		fdp->fd = s;
+		fdp->events = POLLIN;
+	}
+
+	freeaddrinfo(res);
+
+	while (1) {
+		if (poll(fds, nfds, -1) < 0) {
+			if (errno == EINTR) {
+				continue;
+			}
+			fatalperror(2, "poll");
+		}
+
+		for (i = 0, fdp = fds; i < nfds; i++, fdp++) {
+			int fd;
+
+			if (!(fdp->revents & POLLIN)) {
+				continue;
+			}
+
+			fd = accept(fdp->fd, 0, 0);
+			if (fd >= 0) {
+				dup2(fd, 0);
+				close(fd);
+				goto out;
+			}
+			if (errno != EAGAIN) {
+				fatalperror(2, "accept");
+			}
+		}
+	}
+
+out:
+	for (i = 0, fdp = fds; i < nfds; i++, fdp++) {
+		close(fdp->fd);
+	}
+	free(fds);
+}
+
 int
 main(int argc, char *argv[], char *env[])
 {
-	struct sockaddr_in from;
+	struct sockaddr_storage from;
 	int on = 1;
 	socklen_t fromlen;
 	register int ch;
 
-#if	defined(IPPROTO_IP) && defined(IP_TOS)
+#if	defined(HAS_IPPROTO_IP) && defined(IP_TOS)
 	int tos = -1;
 #endif
 
@@ -102,12 +211,6 @@ main(int argc, char *argv[], char *env[])
 
 	pfrontp = pbackp = ptyobuf;
 	netip = netibuf;
-	nfrontp = nbackp = netobuf;
-#if	defined(ENCRYPT)
-	nclearto = 0;
-#endif
-
-	progname = strdup(*argv);
 
 	while ((ch = getopt(argc, argv, "d:a:e:lhnr:I:D:B:sS:a:X:L:")) != EOF) {
 		switch(ch) {
@@ -248,81 +351,25 @@ main(int argc, char *argv[], char *env[])
 	argv += optind;
 
 	if (debug) {
-	    int s, ns;
-	    socklen_t foo;
-	    struct servent *sp;
-	    struct sockaddr_in sn;
-
-	    memset(&sn, 0, sizeof(sn));
-	    sn.sin_family = AF_INET;
-
-	    if (argc > 1) {
-		usage();
-		/* NOTREACHED */
-	    } else if (argc == 1) {
-		    if ((sp = getservbyname(*argv, "tcp"))!=NULL) {
-			sn.sin_port = sp->s_port;
-		    } 
-		    else {
-			int pt = atoi(*argv);
-			if (pt <= 0) {
-			    fprintf(stderr, "telnetd: %s: bad port number\n",
-				    *argv);
-			    usage();
-			    /* NOTREACHED */
-			}
-			sn.sin_port = htons(pt);
-		   }
-	    } else {
-		sp = getservbyname("telnet", "tcp");
-		if (sp == 0) {
-		    fprintf(stderr, "telnetd: tcp/telnet: unknown service\n");
-		    exit(1);
+		if (argc > 1) {
+			usage();
+			/* NOTREACHED */
 		}
-		sn.sin_port = sp->s_port;
-	    }
 
-	    s = socket(AF_INET, SOCK_STREAM, 0);
-	    if (s < 0) {
-		    perror("telnetd: socket");;
-		    exit(1);
-	    }
-	    (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
-	    if (bind(s, (struct sockaddr *)&sn, sizeof(sn)) < 0) {
-		perror("bind");
-		exit(1);
-	    }
-	    if (listen(s, 1) < 0) {
-		perror("listen");
-		exit(1);
-	    }
-	    foo = sizeof(sn);
-	    ns = accept(s, (struct sockaddr *)&sn, &foo);
-	    if (ns < 0) {
-		perror("accept");
-		exit(1);
-	    }
-	    (void) dup2(ns, 0);
-	    (void) close(ns);
-	    (void) close(s);
-	} else if (argc > 0) {
-		usage();
-		/* NOT REACHED */
+		wait_for_connection((argc == 1) ? *argv : "telnet");
 	}
 
 	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");
-		_exit(1);
+		fatalperror(2, "getpeername");
 	}
 	if (keepalive &&
 	    setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) {
 		syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
 	}
 
-#if	defined(IPPROTO_IP) && defined(IP_TOS)
+#if	defined(HAS_IPPROTO_IP) && defined(IP_TOS)
 	{
 # if	defined(HAS_GETTOS)
 		struct tosent *tp;
@@ -336,9 +383,10 @@ main(int argc, char *argv[], char *env[])
 		   && (errno != ENOPROTOOPT) )
 			syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
 	}
-#endif	/* defined(IPPROTO_IP) && defined(IP_TOS) */
+#endif	/* defined(HAS_IPPROTO_IP) && defined(IP_TOS) */
 	net = 0;
-	doit(&from);
+	netopen();
+	doit((struct sockaddr *)&from, fromlen);
 	/* NOTREACHED */
 	return 0;
 }  /* end of main */
@@ -607,12 +655,13 @@ extern void telnet(int, int);
  * Get a pty, scan input lines.
  */
 static void
-doit(struct sockaddr_in *who)
+doit(struct sockaddr *who, socklen_t who_len)
 {
 	const char *host;
-	struct hostent *hp;
 	int level;
 	char user_name[256];
+	int i;
+	struct addrinfo hints, *res;
 
 	/*
 	 * Find an available pty to use.
@@ -622,39 +671,29 @@ doit(struct sockaddr_in *who)
 		fatalperror(net, "getpty");
 
 	/* get name of connected client */
-	hp = gethostbyaddr((char *)&who->sin_addr, sizeof (struct in_addr),
-		who->sin_family);
-	if (hp)
-		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...
-	 */
-	{
-		int i;
-		strncpy(remote_host_name, host, sizeof(remote_host_name)-1);
-		remote_host_name[sizeof(remote_host_name)-1] = 0;
-
-		/* Disallow funnies. */
-		for (i=0; remote_host_name[i]; i++) {
-		    if (remote_host_name[i]<=32 || remote_host_name[i]>126) 
-			remote_host_name[i] = '?';
-		}
+	if (getnameinfo(who, who_len, remote_host_name,
+			sizeof(remote_host_name), 0, 0, 0)) {
+		syslog(LOG_ERR, "doit: getnameinfo: %m");
+		*remote_host_name = 0;
+        }
+
+	/* Disallow funnies. */
+	for (i=0; remote_host_name[i]; i++) {
+	    if (remote_host_name[i]<=32 || remote_host_name[i]>126) 
+		remote_host_name[i] = '?';
 	}
 	host = remote_host_name;
 
 	/* Get local host name */
-	{
-		struct hostent *h;
-		gethostname(host_name, sizeof(host_name));
-		h = gethostbyname(host_name);
-		if (h) {
-		    strncpy(host_name, h->h_name, sizeof(host_name));
-		    host_name[sizeof(host_name)-1] = 0;
-		}
+	gethostname(host_name, sizeof(host_name));
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_family = PF_UNSPEC;
+	hints.ai_flags = AI_CANONNAME;
+	if ((i = getaddrinfo(host_name, 0, &hints, &res)))
+		syslog(LOG_WARNING, "doit: getaddrinfo: %s", gai_strerror(i));
+	else {
+		strncpy(host_name, res->ai_canonname, sizeof(host_name)-1);
+		host_name[sizeof(host_name)-1] = 0;
 	}
 
 #if	defined(AUTHENTICATE) || defined(ENCRYPT)
@@ -891,7 +930,7 @@ void telnet(int f, int p)
 	 * Never look for input if there's still
 	 * stuff in the corresponding output buffer
 	 */
-	if (nfrontp - nbackp || pcc > 0) {
+	if (netbuflen(1) || pcc > 0) {
 	    FD_SET(f, &obits);
 	    if (f >= hifd) hifd = f+1;
 	} 
@@ -1032,6 +1071,7 @@ void telnet(int f, int p)
 		}
 #endif	/* LINEMODE */
 		if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) {
+		    static const char msg[] = { IAC, DM };
 		    netclear();	/* clear buffer back */
 #ifndef	NO_URGENT
 		    /*
@@ -1040,8 +1080,7 @@ void telnet(int f, int p)
 		     * royally if we send them urgent
 		     * mode data.
 		     */
-		    netoprintf("%c%c", IAC, DM);
-		    neturg = nfrontp-1; /* off by one XXX */
+		    sendurg(msg, sizeof(msg));
 #endif
 		}
 		if (his_state_is_will(TELOPT_LFLOW) &&
@@ -1057,23 +1096,21 @@ void telnet(int f, int p)
 	    }
 	}
 	
-	while (pcc > 0) {
-	    if ((&netobuf[BUFSIZ] - nfrontp) < 2)
-		break;
+	while (pcc > 0 && !netbuflen(0)) {
 	    c = *ptyip++ & 0377, pcc--;
 	    if (c == IAC)
-		*nfrontp++ = c;
-	    *nfrontp++ = c;
+		putc(c, netfile);
+	    putc(c, netfile);
 	    if ((c == '\r'  ) && (my_state_is_wont(TELOPT_BINARY))) {
 		if (pcc > 0 && ((*ptyip & 0377) == '\n')) {
-		    *nfrontp++ = *ptyip++ & 0377;
+		    putc(*ptyip++ & 0377, netfile);
 		    pcc--;
 		} 
-		else *nfrontp++ = '\0';
+		else putc('\0', netfile);
 	    }
 	}
 
-	if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0)
+	if (FD_ISSET(f, &obits))
 	    netflush();
 	if (ncc > 0)
 	    telrcv();
diff --git a/telnetd/utility.c b/telnetd/utility.c
index 02003817ca39..1f79e27b63d7 100644
--- a/telnetd/utility.c
+++ b/telnetd/utility.c
@@ -41,6 +41,7 @@ char util_rcsid[] =
 
 #include <stdarg.h>
 #include <sys/utsname.h>
+#include <sys/time.h>
 
 #ifdef AUTHENTICATE
 #include <libtelnet/auth.h>
@@ -48,30 +49,19 @@ char util_rcsid[] =
 
 #include "telnetd.h"
 
-/*
- * utility functions performing io related tasks
- */
-
-/*
- * This function appends data to nfrontp and advances nfrontp.
- * Returns the number of characters written altogether (the
- * buffer may have been flushed in the process).
- */
-
-void
-netoprintf(const char *fmt, ...)
-{
-	va_list args;
-	int len;
+struct buflist {
+	struct buflist *next;
 	char *buf;
+	size_t len;
+};
 
-	va_start(args, fmt);
-	if ((len = vasprintf(&buf, fmt, args)) == -1)
-		return;
-	writenet(buf, len);
-	va_end(args);
-	free(buf);
-}
+static struct buflist head = { next: &head, buf: 0, len: 0 };
+static struct buflist *tail = &head;
+static size_t skip;
+static int trailing;
+static size_t listlen;
+static int doclear;
+static struct buflist *urg;
 
 /*
  * ttloop
@@ -88,9 +78,7 @@ ttloop(void)
 
     DIAG(TD_REPORT, netoprintf("td: ttloop\r\n"););
 		     
-    if (nfrontp-nbackp) {
-	netflush();
-    }
+    netflush();
     ncc = read(net, netibuf, sizeof(netibuf));
     if (ncc < 0) {
 	syslog(LOG_INFO, "ttloop: read: %m\n");
@@ -164,33 +152,64 @@ void 	ptyflush(void)
  * character.
  */
 static
-char *
-nextitem(char *current)
-{
-    if ((*current&0xff) != IAC) {
-	return current+1;
-    }
-    switch (*(current+1)&0xff) {
-    case DO:
-    case DONT:
-    case WILL:
-    case WONT:
-	return current+3;
-    case SB:		/* loop forever looking for the SE */
-	{
-	    register char *look = current+2;
-
-	    for (;;) {
-		if ((*look++&0xff) == IAC) {
-		    if ((*look++&0xff) == SE) {
-			return look;
-		    }
+const char *
+nextitem(
+	const unsigned char *current, const unsigned char *end,
+	const unsigned char *next, const unsigned char *nextend
+) {
+	if (*current++ != IAC) {
+		while (current < end && *current++ != IAC)
+			;
+		goto out;
+	}
+
+	if (current >= end) {
+		current = next;
+		if (!current) {
+			return 0;
 		}
-	    }
+		end = nextend;
+		next = 0;
 	}
-    default:
-	return current+2;
-    }
+
+	switch (*current++) {
+	case DO:
+	case DONT:
+	case WILL:
+	case WONT:
+		current++;
+		break;
+	case SB:		/* loop forever looking for the SE */
+		for (;;) {
+			int iac;
+
+			while (iac = 0, current < end) {
+				if (*current++ == IAC) {
+					if (current >= end) {
+						iac = 1;
+						break;
+					}
+iac:
+					if (*current++ == SE) {
+						goto out;
+					}
+				}
+			}
+
+			current = next;
+			if (!current) {
+				return 0;
+			}
+			end = nextend;
+			next = 0;
+			if (iac) {
+				goto iac;
+			}
+		}
+	}
+
+out:
+	return next ? next + (current - end) : current;
 }  /* end of nextitem */
 
 
@@ -212,160 +231,103 @@ nextitem(char *current)
  */
 void netclear(void)
 {
-    register char *thisitem, *next;
-    char *good;
-#define	wewant(p)	((nfrontp > p) && ((*p&0xff) == IAC) && \
-				((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
+	doclear++;
+	netflush();
+	doclear--;
+}  /* end of netclear */
 
-#if	defined(ENCRYPT)
-    thisitem = nclearto > netobuf ? nclearto : netobuf;
-#else
-    thisitem = netobuf;
-#endif
+static void
+netwritebuf(void)
+{
+	struct iovec *vector;
+	struct iovec *v;
+	struct buflist *lp;
+	ssize_t n;
+	size_t len;
+	int ltrailing = trailing;
+
+	if (!listlen)
+		return;
 
-    while ((next = nextitem(thisitem)) <= nbackp) {
-	thisitem = next;
-    }
+	vector = malloc(listlen * sizeof(struct iovec));
+	if (!vector) {
+		return;
+	}
 
-    /* Now, thisitem is first before/at boundary. */
+	len = listlen - (doclear & ltrailing);
+	v = vector;
+	lp = head.next;
+	while (lp != &head) {
+		if (lp == urg) {
+			len = v - vector;
+			if (!len) {
+				n = send(net, lp->buf, 1, MSG_OOB);
+				if (n > 0) {
+					urg = 0;
+				}
+				goto epi;
+			}
+			break;
+		}
+		v->iov_base = lp->buf;
+		v->iov_len = lp->len;
+		v++;
+		lp = lp->next;
+	}
 
-#if	defined(ENCRYPT)
-    good = nclearto > netobuf ? nclearto : netobuf;
-#else
-    good = netobuf;	/* where the good bytes go */
-#endif
+	vector->iov_base = (char *)vector->iov_base + skip;
+	vector->iov_len -= skip;
 
-    while (nfrontp > thisitem) {
-	if (wewant(thisitem)) {
-	    int length;
-
-	    next = thisitem;
-	    do {
-		next = nextitem(next);
-	    } while (wewant(next) && (nfrontp > next));
-	    length = next-thisitem;
-	    bcopy(thisitem, good, length);
-	    good += length;
-	    thisitem = next;
-	} else {
-	    thisitem = nextitem(thisitem);
+	n = writev(net, vector, len);
+
+epi:
+	free(vector);
+
+	if (n < 0) {
+		if (errno != EWOULDBLOCK && errno != EINTR)
+			cleanup(0);
+		return;
 	}
-    }
 
-    nbackp = netobuf;
-    nfrontp = good;		/* next byte to be sent */
-    neturg = 0;
-}  /* end of netclear */
+	len = n + skip;
 
-/*
- *  netflush
- *		Send as much data as possible to the network,
- *	handling requests for urgent data.
- */
-extern int not42;
-void
-netflush(void)
-{
-    int n;
+	lp = head.next;
+	while (lp->len <= len) {
+		if (lp == tail && ltrailing) {
+			break;
+		}
 
-    if ((n = nfrontp - nbackp) > 0) {
+		len -= lp->len;
 
-#if 0
-	/* XXX This causes netoprintf() to recurse and die */
-	DIAG(TD_REPORT,
-	    { netoprintf("td: netflush %d chars\r\n", n);
-	      n = nfrontp - nbackp;  /* update count */
-	    });
-#endif
+		head.next = lp->next;
+		listlen--;
+		free(lp->buf);
+		free(lp);
 
-#if	defined(ENCRYPT)
-	if (encrypt_output) {
-		char *s = nclearto ? nclearto : nbackp;
-		if (nfrontp - s > 0) {
-			(*encrypt_output)((unsigned char *)s, nfrontp-s);
-			nclearto = nfrontp;
+		lp = head.next;
+		if (lp == &head) {
+			tail = &head;
+			break;
 		}
 	}
-#endif
-	/*
-	 * if no urgent data, or if the other side appears to be an
-	 * old 4.2 client (and thus unable to survive TCP urgent data),
-	 * write the entire buffer in non-OOB mode.
-	 */
-	if ((neturg == 0) || (not42 == 0)) {
-	    n = write(net, nbackp, n);	/* normal write */
-	} else {
-	    n = neturg - nbackp;
-	    /*
-	     * In 4.2 (and 4.3) systems, there is some question about
-	     * what byte in a sendOOB operation is the "OOB" data.
-	     * To make ourselves compatible, we only send ONE byte
-	     * out of band, the one WE THINK should be OOB (though
-	     * we really have more the TCP philosophy of urgent data
-	     * rather than the Unix philosophy of OOB data).
-	     */
-	    if (n > 1) {
-		n = send(net, nbackp, n-1, 0);	/* send URGENT all by itself */
-	    } else {
-		n = send(net, nbackp, n, MSG_OOB);	/* URGENT data */
-	    }
-	}
-    }
-    if (n < 0) {
-	if (errno == EWOULDBLOCK || errno == EINTR)
-		return;
-	cleanup(0);
-    }
-    nbackp += n;
-#if	defined(ENCRYPT)
-    if (nbackp > nclearto)
-	nclearto = 0;
-#endif
-    if (nbackp >= neturg) {
-	neturg = 0;
-    }
-    if (nbackp == nfrontp) {
-	nbackp = nfrontp = netobuf;
-#if	defined(ENCRYPT)
-	nclearto = 0;
-#endif
-    }
-    return;
-}  /* end of netflush */
 
+	skip = len;
+}
 
 /*
- * writenet
- *
- * Just a handy little function to write a bit of raw data to the net.
- * It will force a transmit of the buffer if necessary
- *
- * arguments
- *    ptr - A pointer to a character string to write
- *    len - How many bytes to write
+ *  netflush
+ *             Send as much data as possible to the network,
+ *     handling requests for urgent data.
  */
-void writenet(register unsigned char *ptr, register int len)
+void
+netflush(void)
 {
-	int remaining, copied;
-	
-	remaining = BUFSIZ - (nfrontp - netobuf);
-	while (len > 0) {
-		/* Free up enough space if the room is too low*/
-		if ((len > BUFSIZ ? BUFSIZ : len) > remaining) {
-			netflush();
-			remaining = BUFSIZ - (nfrontp - netobuf);
-		}
-
-		/* Copy out as much as will fit */
-		copied = remaining > len ? len : remaining;
-		memmove(nfrontp, ptr, copied);
-		nfrontp += copied;
-		len -= copied;
-		remaining -= copied;
-		ptr += copied;
+	if (fflush(netfile)) {
+		/* out of memory? */
+		cleanup(0);
 	}
-	return;
-}  /* end of writenet */
+	netwritebuf();
+}
 
 
 /*
@@ -402,18 +364,30 @@ fatalperror(int f, const char *msg)
 	fatal(f, buf);
 }
 
-char editedhost[32];
+char *editedhost;
 struct utsname kerninfo;
 
 void
 edithost(const char *pat, const char *host)
 {
-	char *res = editedhost;
+	char *res;
 
 	uname(&kerninfo);
 
 	if (!pat)
 		pat = "";
+
+	res = realloc(editedhost, strlen(pat) + strlen(host) + 1);
+	if (!res) {
+		if (editedhost) {
+			free(editedhost);
+			editedhost = 0;
+		}
+		fprintf(stderr, "edithost: Out of memory\n");
+		return;
+	}
+	editedhost = res;
+
 	while (*pat) {
 		switch (*pat) {
 
@@ -431,18 +405,12 @@ edithost(const char *pat, const char *host)
 			*res++ = *pat;
 			break;
 		}
-		if (res == &editedhost[sizeof editedhost - 1]) {
-			*res = '\0';
-			return;
-		}
 		pat++;
 	}
 	if (*host)
-		(void) strncpy(res, host,
-				sizeof editedhost - (res - editedhost) -1);
+		(void) strcpy(res, host);
 	else
 		*res = '\0';
-	editedhost[sizeof editedhost - 1] = '\0';
 }
 
 static char *putlocation;
@@ -486,7 +454,9 @@ void putf(const char *cp, char *where)
 			break;
 
 		case 'h':
-			putstr(editedhost);
+			if (editedhost) {
+				putstr(editedhost);
+			}
 			break;
 
 		case 'd':
@@ -1129,11 +1099,6 @@ printdata(const char *tag, const char *ptr, int cnt)
 	char xbuf[30];
 
 	while (cnt) {
-		/* flush net output buffer if no room for new data) */
-		if ((&netobuf[BUFSIZ] - nfrontp) < 80) {
-			netflush();
-		}
-
 		/* add a line of output */
 		netoprintf("%s: ", tag);
 		for (i = 0; i < 20 && cnt; i++) {
@@ -1154,3 +1119,154 @@ printdata(const char *tag, const char *ptr, int cnt)
 	} 
 }
 #endif /* DIAGNOSTICS */
+
+static struct buflist *
+addbuf(const char *buf, size_t len)
+{
+	struct buflist *bufl;
+
+	bufl = malloc(sizeof(struct buflist));
+	if (!bufl) {
+		return 0;
+	}
+	bufl->next = tail->next;
+	bufl->buf = malloc(len);
+	if (!bufl->buf) {
+		free(bufl);
+		return 0;
+	}
+	bufl->len = len;
+
+	tail = tail->next = bufl;
+	listlen++;
+
+	memcpy(bufl->buf, buf, len);
+	return bufl;
+}
+
+static ssize_t
+netwrite(void *cookie, const char *buf, size_t len)
+{
+	size_t ret;
+	const char *const end = buf + len;
+	int ltrailing = trailing;
+	int ldoclear = doclear;
+
+#define	wewant(p)	((*p&0xff) == IAC) && \
+				((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)
+
+	ret = 0;
+
+	if (ltrailing) {
+		const char *p;
+		size_t l;
+		size_t m = tail->len;
+
+		p = nextitem(tail->buf, tail->buf + tail->len, buf, end);
+		ltrailing = !p;
+		if (ltrailing) {
+			p = end;
+		}
+
+		l = p - buf;
+		tail->len += l;
+		tail->buf = realloc(tail->buf, tail->len);
+		if (!tail->buf) {
+			return -1;
+		}
+
+		memcpy(tail->buf + m, buf, l);
+		buf += l;
+		len -= l;
+		ret += l;
+		trailing = ltrailing;
+	}
+
+	if (ldoclear) {
+		struct buflist *lpprev;
+
+		skip = 0;
+		lpprev = &head;
+		for (;;) {
+			struct buflist *lp;
+
+			lp = lpprev->next;
+
+			if (lp == &head) {
+				tail = lpprev;
+				break;
+			}
+
+			if (lp == tail && ltrailing) {
+				break;
+			}
+
+			if (!wewant(lp->buf)) {
+				lpprev->next = lp->next;
+				listlen--;
+				free(lp->buf);
+				free(lp);
+			} else {
+				lpprev = lp;
+			}
+		}
+	}
+
+	while (len) {
+		const char *p;
+		size_t l;
+
+		p = nextitem(buf, end, 0, 0);
+		ltrailing = !p;
+		if (ltrailing) {
+			p = end;
+		} else if (ldoclear) {
+			if (!wewant(buf)) {
+				l = p - buf;
+				goto cont;
+			}
+		}
+
+		l = p - buf;
+		if (!addbuf(buf, l)) {
+			return ret ? ret : -1;
+		}
+		trailing = ltrailing;
+
+cont:
+		buf += l;
+		len -= l;
+		ret += l;
+	}
+
+	netwritebuf();
+	return ret;
+}
+
+void
+netopen() {
+	static const cookie_io_functions_t funcs = {
+		read: 0, write: netwrite, seek: 0, close: 0
+	};
+
+	netfile = fopencookie(0, "w", funcs);
+}
+
+extern int not42;
+void
+sendurg(const char *buf, size_t len) {
+	if (!not42) {
+		fwrite(buf, 1, len, netfile);
+		return;
+	}
+
+	urg = addbuf(buf, len);
+}
+
+size_t
+netbuflen(int flush) {
+	if (flush) {
+		netflush();
+	}
+	return listlen != 1 ? listlen : tail->len - skip;
+}
diff --git a/telnetlogin/.cvsignore b/telnetlogin/.cvsignore
new file mode 100644
index 000000000000..a677bff70ff1
--- /dev/null
+++ b/telnetlogin/.cvsignore
@@ -0,0 +1 @@
+telnetlogin
diff --git a/telnetlogin/Makefile b/telnetlogin/Makefile
new file mode 100644
index 000000000000..74d2680a4b08
--- /dev/null
+++ b/telnetlogin/Makefile
@@ -0,0 +1,18 @@
+all: telnetlogin
+
+include ../MCONFIG
+include ../MRULES
+
+OBJS = telnetlogin.o
+
+telnetlogin: $(OBJS)
+	$(CC) $(LDFLAGS) $^ $(LIBS) -o $@
+
+$(OBJS): ../version.h
+
+install: telnetlogin
+	install -s -m4750 -oroot -gtelnetd telnetlogin $(INSTALLROOT)$(SBINDIR)
+	install -m$(MANMODE) telnetlogin.8 $(INSTALLROOT)$(MANDIR)/man8
+
+clean:
+	rm -f *.o telnetlogin
diff --git a/telnetlogin/telnetlogin.8 b/telnetlogin/telnetlogin.8
new file mode 100644
index 000000000000..2433fd8efcf7
--- /dev/null
+++ b/telnetlogin/telnetlogin.8
@@ -0,0 +1,91 @@
+.\" Copyright (c) 2000 David A. Holland.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by David A. Holland.
+.\" 4. Neither the name of the Author nor the names of any contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND ANY CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR ANY CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"	$Id: telnetlogin.8,v 1.4 2000/07/30 23:57:10 dholland Exp $
+.\"
+.Dd April 12, 2000
+.Dt TELNETLOGIN 8
+.Os "Linux NetKit (0.17)"
+.Sh NAME
+.Nm telnetlogin
+.Nd login wrapper for telnetd
+.Sh SYNOPSIS
+.Nm telnetlogin
+.Op Fl h Ar host
+.Op Fl p
+.Op Ar username
+.Sh DESCRIPTION
+.Nm telnetlogin
+is a setuid wrapper that runs
+.Xr login 1 .
+It is meant to be invoked by
+.Xr telnetd 8 ;
+the idea is to remove the necessity of running telnetd as root.
+.Pp
+.Nm telnetlogin
+should be installed mode 4750, user root, group telnetd. Then,
+telnetd may be run from
+.Pa /etc/inetd.conf
+as user ``nobody'', group ``telnetd'', and with the option
+.Fl L Ar path-to-telnetlogin .
+.Pp
+.Nm telnetlogin
+accepts only the subset of options to
+.Xr login 1
+shown above, in the order listed. This is the order 
+.Nm telnetd 8
+normally provides them in.
+.Nm telnetlogin
+also does sanity checks on the environment variables
+.Ev TERM , 
+and
+.Ev REMOTEHOST .
+It also insists that the standard input, output, and error streams are
+open on a terminal, and that it is the process group leader of the
+foreground process of that terminal. After checking all of these
+conditions, checking the values of the above environment variables for
+reasonable values, resetting signal handlers, and so forth, it execs
+login.
+.Sh SEE ALSO
+.Xr login 1 ,
+.Xr inetd.conf 5 ,
+.Xr inetd 8 ,
+.Xr telnetd 8
+.Sh RESTRICTIONS
+.Nm telnetlogin
+does not permit the
+.Fl f
+option to login, so will not
+work with telnetds that perform authentication via Kerberos or SSL.
+.Pp
+THIS IS PRESENTLY EXPERIMENTAL CODE; USE WITH CAUTION.
+.Sh HISTORY
+.Nm telnetlogin
+was written during the development of NetKit 0.17.
diff --git a/telnetlogin/telnetlogin.c b/telnetlogin/telnetlogin.c
new file mode 100644
index 000000000000..e3c3fc6ef901
--- /dev/null
+++ b/telnetlogin/telnetlogin.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2000 David A. Holland.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by David A. Holland.
+ * 4. Neither the name of the Author nor the names of any contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND ANY CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR ANY CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+char copyright[] =
+ "@(#) Copyright (c) 2000 David A. Holland.\n"
+ "All rights reserved.\n";
+
+char rcsid[] =
+  "$Id: telnetlogin.c,v 1.1 2000/04/13 01:07:22 dholland Exp $";
+#include "../version.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <paths.h>
+#include <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <syslog.h>
+
+#ifndef _PATH_LOGIN
+#define _PATH_LOGIN "/bin/login"
+#endif
+
+extern char **environ;
+
+static const char *remhost = NULL;
+
+static void die(const char *, ...) __attribute__ ((noreturn));
+
+static void die(const char *fmt, ...) {
+   va_list ap;
+   openlog("telnetlogin", LOG_PID, LOG_AUTHPRIV);
+   va_start(ap, fmt);
+   vsyslog(LOG_CRIT, fmt, ap);
+   va_end(ap);
+   exit(1);
+}
+
+static int check_a_hostname(char *hname) {
+   int i=0;
+   /* should we check length? */
+   for (i=0; hname[i]; i++) {
+      if (hname[i]<=32 && hname[i]>126) return -1;
+   }
+   return 0;
+}
+
+static int check_term(char *termtype) {
+   int i;
+   if (strlen(termtype) > 32) return -1;
+   for (i=0; termtype[i]; i++) {
+      if (!isalnum(termtype[i]) && !strchr("+._-", termtype[i])) return -1;
+   }
+   return 0;
+}
+
+static int check_remotehost(char *val) {
+   if (check_a_hostname(val)) return -1;
+   if (remhost && strcmp(val, remhost)) return -1;
+   return 0;
+}
+
+struct {
+   const char *name;
+   int (*validator)(char *);
+} legal_envs[] = {
+   { "TERM", check_term },
+   { "REMOTEHOST", check_remotehost },
+   { NULL, NULL }
+};
+
+static void validate_tty(void) {
+   struct stat buf, buf2;
+   const char *tty;
+   pid_t pgrp;
+
+   tty = ttyname(0);
+   if (!tty) die("stdin not a tty");
+
+   if (fstat(0, &buf)) die("fstat stdin");
+   if (!S_ISCHR(buf.st_mode)) die("stdin not char device");
+
+   if (fstat(1, &buf2)) die("fstat stdout");
+   if (!S_ISCHR(buf2.st_mode)) die("stdout not char device");
+   if (buf.st_rdev!=buf2.st_rdev) die("stdout and stdin not same tty");
+
+   if (fstat(2, &buf2)) die("fstat stderr");
+   if (!S_ISCHR(buf2.st_mode)) die("stderr not char device");
+   if (buf.st_rdev!=buf2.st_rdev) die("stderr and stdin not same tty");
+   
+   if (ioctl(0, TIOCGPGRP, &pgrp)) die("cannot get tty process group");
+   if (pgrp != getpgrp()) die("not foreground pgrp of tty");
+   if (pgrp != getpid()) die("not process group leader");
+}
+
+int main(int argc, char *argv[]) {
+   static char argv0[] = "login";
+   int argn, i, j;
+   const char *rh = NULL;
+   char **envs = environ;
+
+   /* first, make sure our stdin/stdout/stderr are aimed somewhere */
+   i = open("/", O_RDONLY);
+   if (i<3) {
+      /* Oops. Can't even print an error message... */
+      exit(100);
+   }
+   close(i);
+
+   /* check args */
+   argn=1;
+   if (argc<1) {
+      die("Illegal args: argc < 1");
+   }
+   if (argn < argc && !strcmp(argv[argn], "-h")) {
+      argn++;
+      if (argn==argc) die("Illegal args: -h requires argument");
+      if (check_a_hostname(argv[argn])) die("Illegal remote host specified");
+      rh = argv[argn];
+      argn++;
+   }
+   if (argn < argc && !strcmp(argv[argn], "-p")) {
+      argn++;
+   }
+   if (argn < argc && argv[argn][0] != '-') {
+      argn++;
+   }
+   if (argn < argc) die("Illegal args: too many args");
+   argv[0] = argv0;
+
+   /* check environment */
+   if (envs) for (i=0; envs[i]; i++) {
+      char *testenv = envs[i];
+      size_t testlen = strlen(testenv);
+      for (j=0; legal_envs[j].name; j++) {
+	 const char *okenv = legal_envs[j].name;
+	 size_t oklen = strlen(okenv);
+	 int sign;
+
+	 if (testlen < oklen) continue;
+	 if (testenv[oklen]!='=') continue;
+	 if ((sign = memcmp(testenv, okenv, oklen)) < 0) {
+	    continue;
+	 } else if (sign > 0) {
+	    break;
+	 }
+	 if (legal_envs[j].validator(testenv+oklen+1)) {
+	    die("Invalid environment: bad value for %s", okenv);
+	 }
+	 break;
+      }
+   }
+
+   /* unignore all signals so they get cleared at exec time */
+   for (i=1; i<NSIG; i++) {
+      signal(i, SIG_DFL);
+   }
+
+   /* just in case */
+   if (chdir("/")) die("chdir to / failed");
+
+   /* 
+    * don't do anything with uids and gids, as login is normally meant
+    * to be able to take care of them.  
+    * 
+    * but, should we insist that ruid==nobody?
+    */
+
+#ifdef debian
+   /*
+    * Debian's /bin/login doesn't work properly unless we're really root.
+    */
+   setuid(0);
+#endif
+
+   /*
+    * don't do anything with limits, itimers, or process priority either
+    */
+
+   /*
+    * should we check to make sure stdin=stdout=stderr and they're a tty
+    * and it's our controlling tty [hard] and we're the leader of the 
+    * foreground process group?
+    *
+    * Yeah, we should.
+    */
+   validate_tty();
+
+   /*
+    * now exec login
+    * argv[0] was set up above.
+    */
+   execve(_PATH_LOGIN, argv, envs);
+   exit(255);
+}
diff --git a/version.h b/version.h
index 3cfe28f5d5f0..ad92951e3b97 100644
--- a/version.h
+++ b/version.h
@@ -2,4 +2,4 @@
  * String to embed in binaries to identify package
  */
 
-char pkg[]="$NetKit: netkit-telnet-0.16 $";
+char pkg[]="$NetKit: netkit-telnet-0.17 $";

Reply via email to