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 $";