netkit-telnet-0.17/ 40700 144 144 0 7141142031 13416 5ustar dhollandpeoplenetkit-telnet-0.17/.cvsignore100644 144 144 10 6775463650 15505 0ustar dhollandpeopleMCONFIG netkit-telnet-0.17/BUGS100644 144 144 1554 6346656225 14242 0ustar dhollandpeopletelnet: - will apparently sometimes assert in ungetch. I think I've fixed this, so if you still see it let me know. - hangs if you telnet to chargen port and push ^Z (due to bogus protocol negotiation attempts) - binary mode doesn't handle crlf right - should warn if the connection isn't encrypted telnetd: - hangs if you do the following: telnet log in cat >/dev/null type 256 'a's with no CRs *THIS IS A KERNEL BUG* Patch enclosed. - crashes in ncurses if the terminal type is undefined, with some versions of ncurses. - should allow passing random user envs as "TELNET_*" - should set REMOTEHOST to the remote hostname - passes login the -p flag instead of sending envs explicitly - should only use included logout() et al. if real ones aren't available in system libs. - addarg() in sys_term.c does some very questionable casts. netkit-telnet-0.17/ChangeLog100644 144 144 13071 7136463037 15341 0ustar dhollandpeople22-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 (herbert@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; assume it is. This means telnetd no longer links against termcap. 12-Dec-1999: Massive buffer cleanup in telnetd; minor cleanup to telnet. 5-Dec-1999: Remove some more bogus #ifdefs in telnet. 29-Oct-1999: Fix latent bug in the array classes used in telnet. 14-Sep-1999: Merge old fix to keep telnet from hanging up when under heavy load (Olaf Kirch, okir@caldera.de) 19-Aug-1999: Patches for compiling with gcc 2.95. (Jeremy Buhler, jbuhler@cs.washington.edu) 18-Aug-1999: netkit-telnet-0.14 released. 17-Aug-1999: telnetd patch from Chris Evans to reject termcap entries with '/' in them, as libtermcap will treat them as paths and open them as root, with various interesting consequences... Issue found by Tymm Twillman (tymm@coe.missouri.edu). 1-Aug-1999: Massive cleanup of telnetd. Changed telnetd to use openpty() from libutil, so we can let libc deal with changes in pty management. 1-Aug-1999: Did complete y2k and y2038 audit. 31-Jul-1999: Redid makefiles/config stuff for new confgen version. 15-Jul-1999: Set the process title (visible with ps) to show the remote host name. Also filter control characters from the remote host name, just in case. Set environment variable REMOTEHOST also. 16-Oct-1997: Added OPOST to the terminal stuff a la NCSA telnet fixup 23-Sep-1997: Assorted signed/unsigned character fixes and hacking in telnet. (Martin Mares, mj@mj.gts.cz) Fix various crashes in telnet arising from undefining environment variables. "telnet h" no longer prints a usage message. 12-Jun-1997: netkit-telnet-0.10 released. 08-Jun-1997: More adjustments for glibc. Include kernel patch to fix hang on long input; thanks to Bill Hawes (whawes@star.net). 19-May-1997: Fix some nonsense with ayt and signals, since glibc has SIGINFO. 13-May-1997: 8-bit fix to telnet. (Lukas Wunner, lukas@design.de) Set ut_type correctly in telnetd's logout. (Steve Coile, steve@patriot.net) 05-Apr-1997: Added configure script to generate MCONFIG. Better utmp handling in telnetd. 08-Mar-1997: Split from full NetKit package. Generated this change log from NetKit's. 29-Dec-1996 NetKit-0.09 released. Assorted alpha/glibc patches. (Erik Troan, ewt@redhat.com) Assorted bug fixes from Debian. (Peter Tobias, tobias@et-inf.fho-emden.de) Telnetd supports -L option for alternate login program. (Peter Tobias) Hardened programs against DNS h_length spoofing attacks. Use inet_aton() everywhere instead of inet_addr(). Fixed crash in telnet caused by ^C or ^Z or ^\ under certain circumstances. Rewrote telnet and telnetd man pages. 22-Aug-1996 NetKit-B-0.08 released. (almost) everything now compiles with lots of warnings turned on. Massive hacking on telnet. telnet honors the -E flag (was broken in .07, .07A) telnetd intercepts ENV environment variable. Merged libtelnet into telnet and telnetd dirs. telnetd now sets idle tty devices to root.root mode 600. 25-Jul-1996 NetKit-B-0.07A released. Fixed a bug in telnet where the escape character was being ignored. Fixed a bug in telnetd; now uses the correct names for the last ptys (that is, ptya0-ptyef, not ptyA0-ptyEf.) 23-Jul-1996 NetKit-B-0.07 released. Integrated a collection of patches that had been lurking on the net, including the 256-ptys support for telnetd and passive mode ftp. Major security fixes, including to fingerd, lpr, rlogin, rsh, talkd, and telnetd. Do *not* use the sliplogin from earlier versions of this package, either. Much of the code builds without libbsd.a or bsd includes. Massive code cleanup. Almost everything compiles clean with gcc -Wall now. rusers and rusersd do not; patches to rpcgen to fix this would be appreciated if anyone feels like it. Kerberos support has been removed. It didn't work anyway, and proper Kerberos tools come with Kerberos. New maintainer: David A. Holland, dholland@hcs.harvard.edu date not known NetKit-B-0.06 released. date not known NetKit-B-0.05 released. Fixed writing entries to /var/adm/wtmp by ftpd, rlogind and telnetd. (logwtmp.c) Florian This is only necessary for the GNU last, not for the one in util-linux... date not known NetKit-B-0.04 released. Did some nasty changes to telnet/extern.h. I should really take the current version from NetBSD again and make a clean port of it. (signals). date not known NetKit-B-0.03 released. telnetd: changed the default 'etc/issue.net' to not output the hostname and then the domainname (that should be the fqdn, but is wrong!) Changed also the man page issue.net.5 changed telnetd to get the fqdn and not only use what 'gethostname' returns telnetd: changed some code back to original form to properly enable binary mode negotiation (outgoing data wasn't binary) Please test this out: do "telnet some_other_not_linux_host" and then do "vi TEST_FILE" and test some strange characters >127 like ° or §. telnetd: added issue.net.5 to "make install" netkit-telnet-0.17/MCONFIG.in100644 144 144 455 7017077053 15140 0ustar dhollandpeople# Dirs INSTALLROOT BINDIR MANDIR SBINDIR # Modes BINMODE DAEMONMODE MANMODE # Compiling ALLWARNINGS CC CXX CFLAGS CXXFLAGS LDFLAGS LIBS # Features FN(snprintf) FN(logwtmp) LIBTERMCAP GLIBC BSDSIGNAL # We actually use openpty, but they come from the same place on all systems # I know. FN(forkpty) netkit-telnet-0.17/MRULES100644 144 144 176 6750752734 14471 0ustar dhollandpeople# Standard compilation rules (don't use make builtins) %.o: %.c $(CC) $(CFLAGS) $< -c %.o: %.cc $(CXX) $(CXXFLAGS) $< -c netkit-telnet-0.17/Makefile100644 144 144 1000 7075216762 15177 0ustar dhollandpeople# 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 # not yet: telnetlogin %.build: (cd $(patsubst %.build, %, $@) && $(MAKE)) %.install: (cd $(patsubst %.install, %, $@) && $(MAKE) install) %.clean: (cd $(patsubst %.clean, %, $@) && $(MAKE) clean) all: $(patsubst %, %.build, $(SUB)) install: $(patsubst %, %.install, $(SUB)) clean: $(patsubst %, %.clean, $(SUB)) distclean: clean rm -f MCONFIG netkit-telnet-0.17/README100644 144 144 11304 7141137777 14451 0ustar dhollandpeopleThis is netkit-telnet-0.17 for Linux. 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. 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 telnetd Daemon for telnet protocol Note: These programs do not provide encryption or strong authentication of network connections. As such, their use for remote logins is discouraged. The "ssh" protocol and package can be used instead. Requires: Working compiler, libc, and kernel, and a recent version of ncurses or libtermcap. Note that while telnet uses the C++ compiler, it neither requires nor uses libstdc++. 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. 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. 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. 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 defaults should be suitable for most Linux systems. Then run the configure script. Do "make" to compile. Then (as root) do "make install". 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 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.) 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 libc version installed in /lib and /usr/lib. If you have weird problems this is the most likely culprit. Also, before reporting a bug, be sure you're working with the latest version. If something doesn't compile for you, fix it and send diffs. If you can't, send the compiler's error output. If it compiles but doesn't work, send as complete a bug report as you can. Patches and fixes are welcome, as long as you describe adequately what they're supposed to fix. Please, one patch per distinct fix. Please do NOT send the whole archive back or reindent the source. 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. :-) Mail should be sent to: netbug@ftp.uk.linux.org 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. 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 23 July 2000 netkit-telnet-0.17/configure100755 144 144 32606 7140615675 15505 0ustar dhollandpeople#!/bin/sh # # This file was generated by confgen version 2. # Do not edit. # PREFIX='/usr' #EXECPREFIX='$PREFIX' INSTALLROOT='' BINMODE='755' #DAEMONMODE='$BINMODE' MANMODE='644' while [ x$1 != x ]; do case $1 in --help) cat < __conftest.c int main() { int class=0; return class; } EOF if [ x"$CC" = x ]; then echo -n 'Looking for a C compiler... ' for TRY in egcs gcc g++ CC c++ cc; do ( $TRY __conftest.c -o __conftest || exit 1; ./__conftest || exit 1; ) >/dev/null 2>&1 || continue; CC=$TRY break; done if [ x"$CC" = x ]; then echo 'failed.' echo 'Cannot find a C compiler. Run configure with --with-c-compiler.' rm -f __conftest* exit fi echo "$CC" else echo -n 'Checking if C compiler works... ' if ( $CC __conftest.c -o __conftest || exit 1 ./__conftest || exit 1 ) >/dev/null 2>&1; then echo 'yes' else echo 'no' echo 'Compiler '"$CC"' does not exist or cannot compile C; try another.' rm -f __conftest* exit fi fi echo -n "Checking if $CC accepts gcc warnings... " if ( $CC $WARNINGS __conftest.c -o __conftest || exit 1 ) >/dev/null 2>&1; then echo 'yes' CC_WARNINGS=1 else echo 'no' fi cat << EOF > __conftest.cc template class fnord { public: T x; fnord(T y) { x=y; }}; int main() { fnord a(0); return a.x; } EOF if [ x"$CXX" = x ]; then echo -n 'Looking for a C++ compiler... ' for TRY in egcs gcc g++ CC c++ cc; do ( $TRY __conftest.cc -o __conftest || exit 1; ./__conftest || exit 1; ) >/dev/null 2>&1 || continue; CXX=$TRY break; done if [ x"$CXX" = x ]; then echo 'failed.' echo 'Cannot find a C++ compiler. Run configure with --with-cpp-compiler.' rm -f __conftest* exit fi echo "$CXX" else echo -n 'Checking if C++ compiler works... ' if ( $CXX __conftest.cc -o __conftest || exit 1 ./__conftest || exit 1 ) >/dev/null 2>&1; then echo 'yes' else echo 'no' echo 'Compiler '"$CXX"' does not exist or cannot compile C++; try another.' rm -f __conftest* exit fi fi echo -n "Checking if $CXX accepts gcc warnings... " if ( $CXX $WARNINGS __conftest.cc -o __conftest || exit 1 ) >/dev/null 2>&1; then echo 'yes' CXX_WARNINGS=1 else echo 'no' fi 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 ) >/dev/null 2>&1; then echo 'yes' CFLAGS="$CFLAGS -g" else echo 'no' fi fi if [ x"$CC" != x"$CXX" ]; then if [ x$DEBUG = x ]; then 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... " if ( $CXX -O __conftest.cc -o __conftest ) >/dev/null 2>&1; then echo 'yes' CXXFLAGS="$CXXFLAGS -O" else echo 'no' fi fi else echo -n "Checking if $CXX accepts -g... " if ( $CXX -g __conftest.cc -o __conftest ) >/dev/null 2>&1; then echo 'yes' CXXFLAGS="$CXXFLAGS -g" else echo 'no' fi fi else CXXFLAGS="$CFLAGS" fi echo -n "Checking if $CXX accepts -fno-rtti... " if ( $CXX -fno-rtti __conftest.cc -o __conftest ) >/dev/null 2>&1; then echo 'yes' CXXFLAGS="$CXXFLAGS -fno-rtti" else echo 'no' fi echo -n "Checking if $CXX accepts -fno-exceptions... " if ( $CXX -fno-exceptions __conftest.cc -o __conftest ) >/dev/null 2>&1; then echo 'yes' CXXFLAGS="$CXXFLAGS -fno-exceptions" else echo 'no' fi LDFLAGS= LIBS= rm -f __conftest* ################################################## echo -n 'Checking for BSD signal semantics... ' cat <__conftest.cc #include #include int count=0; void handle(int foo) { count++; } int main() { int pid=getpid(); signal(SIGINT, handle); kill(pid,SIGINT); kill(pid,SIGINT); kill(pid,SIGINT); if (count!=3) return 1; return 0; } EOF if ( $CXX $CXXFLAGS __conftest.cc -o __conftest || exit 1 ./__conftest || exit 1 ) >/dev/null 2>&1; then echo 'yes' else if ( $CXX $CXXFLAGS -D__USE_BSD_SIGNAL __conftest.cc -o __conftest || exit 1 ./__conftest || exit 1 ) >/dev/null 2>&1; then echo '-D__USE_BSD_SIGNAL' CFLAGS="$CFLAGS -D__USE_BSD_SIGNAL" CXXFLAGS="$CXXFLAGS -D__USE_BSD_SIGNAL" else echo 'no' echo 'This package needs BSD signal semantics to run.' rm -f __conftest* exit fi fi rm -f __conftest* ################################################## echo -n 'Checking for ncurses... ' cat <__conftest.cc #include #include #ifndef KEY_DOWN syntax error. /* not ncurses */ #endif int main() { endwin(); return 0; } EOF if ( $CXX $CXXFLAGS __conftest.cc -lncurses -o __conftest || exit 1 ) >/dev/null 2>&1; then echo 'yes' NCURSES=1 else if ( $CXX $CXXFLAGS -I/usr/include/ncurses __conftest.cc -lncurses -o __conftest || exit 1 ) >/dev/null 2>&1; then echo '-I/usr/include/ncurses' CFLAGS="$CFLAGS -I/usr/include/ncurses" CXXFLAGS="$CXXFLAGS -I/usr/include/ncurses" NCURSES=1 else echo 'no' fi fi if [ x$NCURSES != x ]; then LIBTERMCAP=-lncurses else echo -n 'Checking for traditional termcap... ' cat <__conftest.cc #include #include int main() { tgetent(NULL, NULL); return 0; } EOF if ( $CXX $CXXFLAGS __conftest.cc -ltermcap -o __conftest || exit 1 ) >/dev/null 2>&1; then echo '-ltermcap' LIBTERMCAP=-ltermcap else echo 'not found' echo 'This package needs termcap to run.' rm -f __conftest* exit fi fi rm -f __conftest* ################################################## echo -n 'Checking for GNU libc... ' cat <__conftest.cc #include #if defined(__GLIBC__) && (__GLIBC__ >= 2) int tester; #endif int main() { tester=6; return 0; } EOF if ( $CXX $CXXFLAGS __conftest.cc -o __conftest || exit 1 ) >/dev/null 2>&1; then echo 'yes' USE_GLIBC=1 else echo 'no' fi rm -f __conftest* ################################################## echo -n 'Checking for forkpty... ' cat <__conftest.cc #include int main() { forkpty(0, 0, 0, 0); } EOF if ( $CXX $CXXFLAGS __conftest.cc -o __conftest || exit 1 ) >/dev/null 2>&1; then echo 'yes' else if ( $CXX $CXXFLAGS __conftest.cc -lutil -o __conftest || exit 1 ) >/dev/null 2>&1; then echo '-lutil' LIBS="$LIBS -lutil" else if ( $CXX $CXXFLAGS __conftest.cc -lbsd -o __conftest || exit 1 ) >/dev/null 2>&1; then echo '-lbsd' LIBBSD="-lbsd" else echo 'no' echo 'This package requires forkpty.' rm -f __conftest* exit fi fi fi rm -f __conftest* ################################################## echo -n 'Checking for logwtmp... ' cat <__conftest.cc #ifdef __cplusplus extern "C" #endif void logwtmp(const char *, const char *, const char *); int main() { logwtmp(0, 0, 0); } EOF if ( $CXX $CXXFLAGS __conftest.cc -o __conftest || exit 1 ) >/dev/null 2>&1; then echo 'yes' else if ( $CXX $CXXFLAGS __conftest.cc -lutil -o __conftest || exit 1 ) >/dev/null 2>&1; then echo '-lutil' LIBS="$LIBS -lutil" else if ( $CXX $CXXFLAGS __conftest.cc -lbsd -o __conftest || exit 1 ) >/dev/null 2>&1; then echo '-lbsd' LIBBSD="-lbsd" else echo 'no' echo 'This package requires logwtmp.' rm -f __conftest* exit fi fi fi rm -f __conftest* ################################################## echo -n 'Checking for snprintf declaration... ' cat <__conftest.cc #include int main() { void *x = (void *)snprintf; printf("%lx", (long)x); return 0; } EOF if ( $CXX $CXXFLAGS __conftest.cc -o __conftest || exit 1 ) >/dev/null 2>&1; then echo 'ok' else if ( $CXX $CXXFLAGS -D_GNU_SOURCE __conftest.cc -o __conftest || exit 1 ./__conftest || exit 1 ) >/dev/null 2>&1; then echo '-D_GNU_SOURCE' CFLAGS="$CFLAGS -D_GNU_SOURCE" CXXFLAGS="$CXXFLAGS -D_GNU_SOURCE" else echo 'manual' CFLAGS="$CFLAGS -DDECLARE_SNPRINTF" CXXFLAGS="$CXXFLAGS -DDECLARE_SNPRINTF" fi fi rm -f __conftest* echo -n 'Checking for snprintf implementation... ' cat <__conftest.cc #include #include #ifdef DECLARE_SNPRINTF #ifdef __cplusplus extern "C" #endif /*__cplusplus*/ int snprintf(char *, int, const char *, ...); #endif /*DECLARE_SNPRINTF*/ int main() { char buf[32]; snprintf(buf, 8, "%s", "1234567890"); if (strlen(buf)!=7) return 1; return 0; } EOF if ( $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 ./__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 ./__conftest || exit 1 ) >/dev/null 2>&1; then echo '-ldb' LIBS="$LIBS -ldb" else echo 'missing' echo 'This package requires snprintf.' rm -f __conftest* exit fi fi fi rm -f __conftest* ################################################## ## libbsd should go last in case it's broken if [ "x$LIBBSD" != x ]; then LIBS="$LIBS $LIBBSD" fi echo 'Generating MCONFIG...' ( echo -n '# Generated by configure (confgen version 2) on ' date echo '#' echo echo "BINDIR=$BINDIR" echo "SBINDIR=$SBINDIR" echo "MANDIR=$MANDIR" echo "BINMODE=$BINMODE" echo "DAEMONMODE=$DAEMONMODE" echo "MANMODE=$MANMODE" echo "PREFIX=$PREFIX" echo "EXECPREFIX=$EXECPREFIX" echo "INSTALLROOT=$INSTALLROOT" echo "CC=$CC" echo "CXX=$CXX" if [ x$CC_WARNINGS != x ]; then CFLAGS="$CFLAGS $WARNINGS" fi if [ x$CXX_WARNINGS != x ]; then CXXFLAGS="$CXXFLAGS $WARNINGS" fi echo "CFLAGS=$CFLAGS" | sed 's/= */=/' echo "CXXFLAGS=$CXXFLAGS" | sed 's/= */=/' echo "LDFLAGS=$LDFLAGS" | sed 's/= */=/' echo "LIBS=$LIBS" | sed 's/= */=/' echo "LIBTERMCAP=$LIBTERMCAP" echo "USE_GLIBC=$USE_GLIBC" ) > MCONFIG netkit-telnet-0.17/pty-hang.patch100644 144 144 7662 6350012452 16314 0ustar dhollandpeopleFrom whawes@star.net Sun May 25 11:17:36 1997 Received: from venus.star.net (root@venus.star.net [199.232.114.5]) by hcs.harvard.edu (8.8.5/8.8.3) with ESMTP id LAA15293 for ; Sun, 25 May 1997 11:17:35 -0400 (EDT) Received: from hawes (bos221p.star.net [199.232.112.221]) by venus.star.net (8.8.5/8.7.3) with ESMTP id LAA29775; Sun, 25 May 1997 11:17:08 -0400 Message-ID: <33885894.B2043F5E@star.net> Date: Sun, 25 May 1997 11:19:48 -0400 From: Bill Hawes X-Mailer: Mozilla 4.0b3 [en] (WinNT; I) MIME-Version: 1.0 To: David Holland , Alan Cox , Peter Tobias , "Theodore Ts'o" Subject: kernel patch to fix telnetd deadlock X-Priority: 3 (Normal) Content-Type: multipart/mixed; boundary="------------B47A35BD86775A5D9DA0F308" Status: RO This is a multi-part message in MIME format. --------------B47A35BD86775A5D9DA0F308 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Attached is a patch for drivers/char/n_tty.c that fixes the telnetd deadlock when more than 256 chars are typed without a newline. With this patch in place, the total of typed-ahead and entered commands is still limited to 256 chars, but telnetd comes back to life when the buffer is emptied. Here's what the problem was: telnetd does a select() on the master side of a pty to see when it's safe to write a character without blocking. The N_TTY line discipline select() calls the pty driver's chars_in_buffer() function to see how many characters are buffered. If there are more than 256, the caller has to wait. The pty driver.chars_in_buffer calls the other side's ldisc chars_in_buffer() function. Here's where the problem arises: the slave pty is in canonical mode, so that no characters can be read until a newline is entered. But the n_tty_chars_in_buffer was returning the full number of characters entered, even if no newline had been entered. Hence after 256 characters were typed, select() makes telnetd wait, and the newline can never arrive. The patch corrects n_tty_chars_in_buffer() by checking for canonical mode and returning 0 if no data is available to be read. I've tested this on 2.0.30, and it should apply to 2.1.40 as well. Please check it out and forward it as you see wish. I'm working on a patch for pty.c to allow a greater amount of type-ahead while still avoiding a deadlock. Regards, Bill Hawes --------------B47A35BD86775A5D9DA0F308 Content-Type: text/plain; charset=us-ascii; name="n_tty-chars-patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="n_tty-chars-patch" --- drivers/char/n_tty.c.old Mon Sep 2 08:18:26 1996 +++ drivers/char/n_tty.c Sun May 25 10:10:29 1997 @@ -86,10 +86,31 @@ /* * Return number of characters buffered to be delivered to user + * WSH 05/20/97: Added check for canonical mode + * In canonical mode, no characters are available to be read until + * the first newline has been entered. (Any characters in the buffer + * may yet be erased ...) + * + * This was causing a deadlock in telnetd: select() thought the buffer + * was already too full, so telnetd couldn't send a newline, but the + * slave PTY couldn't read anything because there was no newline. */ int n_tty_chars_in_buffer(struct tty_struct *tty) { - return tty->read_cnt; + /* Check first for canonical mode ... */ + if (tty->icanon) { + if (!tty->canon_data) return 0; + + /* Would prefer to just fall through and return the true + * count, but that could still cause deadlocks until some + * other routines are patched. For now, calculate the + * characters actually available for reading. + */ + return (tty->canon_head > tty->read_tail) ? + tty->canon_head - tty->read_tail : + tty->canon_head + (N_TTY_BUF_SIZE - tty->read_tail); + } + return tty->read_cnt; /* all characters available */ } /* --------------B47A35BD86775A5D9DA0F308-- netkit-telnet-0.17/version.h100644 144 144 147 7141140324 15350 0ustar dhollandpeople/* * String to embed in binaries to identify package */ char pkg[]="$NetKit: netkit-telnet-0.17 $"; netkit-telnet-0.17/telnet/ 40700 144 144 0 7141142030 14710 5ustar dhollandpeoplenetkit-telnet-0.17/telnet/.cvsignore100644 144 144 7 6756362776 16774 0ustar dhollandpeopletelnet netkit-telnet-0.17/telnet/Makefile100644 144 144 1175 6750752735 16513 0ustar dhollandpeopleall: telnet include ../MCONFIG include ../MRULES #CXXFLAGS:=$(patsubst -O2, -g, $(CXXFLAGS)) # -DAUTHENTICATE CXXFLAGS += -DUSE_TERMIO -DKLUDGELINEMODE 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 OBJS = $(patsubst %.cc, %.o, $(SRCS)) telnet: $(OBJS) $(CXX) $(LDFLAGS) $^ $(LIBS) -o $@ include depend.mk depend: $(CXX) $(CXXFLAGS) -MM $(SRCS) >depend.mk install: telnet install -s -m$(BINMODE) telnet $(INSTALLROOT)$(BINDIR) install -m$(MANMODE) telnet.1 $(INSTALLROOT)$(MANDIR)/man1 clean: rm -f *.o telnet netkit-telnet-0.17/telnet/README100644 144 144 2035 6204244241 15705 0ustar dhollandpeople Telnet has been massively hacked up for this release. It presently requires a C++ compiler (gcc 2.7.2 or higher recommended), but not libg++ or libstdc++. That is, unless you went to special effort to not install the C++ compiler when you installed gcc, you'll be fine. Large amounts of further hacking are expected. If you're interested in working on it, please contact me, as diffs are likely to become useless very quickly. Support for assorted old/broken systems has been dropped. Some such support may be reinstated in the future once the code has been cleaned up sufficiently. On the other hand, it may not. Known bugs/shortcomings at this point: - Under some circumstances it can theoretically encounter a buffer overflow condition and drop data on the floor. If anyone actually observes this ``in the wild'' I'd appreciate knowing the circumstances. I'm also not convinced the old behavior was any better. - Various of the debug/trace modes don't work. This probably doesn't matter to anyone not actually coding on it. netkit-telnet-0.17/telnet/README.old100644 144 144 47122 6172622742 16522 0ustar dhollandpeople This is a distribution of both client and server telnet. These programs have been compiled on: telnet telnetd BSD 4.3 Reno X X UNICOS 5.1 X X UNICOS 6.0 X X UNICOS 6.1 X X UNICOS 7.0 X X SunOs 3.5 X X (no linemode in server) SunOs 4.1 X X (no linemode in server) DYNIX V3.0.17.9 X X (no linemode in server) Ultrix 3.1 X X (no linemode in server) Ultrix 4.0 X X (no linemode in server) In addition, previous versions have been compiled on the following machines, but were not available for testing this version. telnet telnetd SunOs 4.0.3c X X (no linemode in server) BSD 4.3 X X (no linemode in server) DYNIX V3.0.12 X X (no linemode in server) Februrary 22, 1991: Features: This version of telnet/telnetd has support for both the AUTHENTICATION and ENCRYPTION options. The AUTHENTICATION option is fairly well defined, and an option number has been assigned to it. The ENCRYPTION option is still in a state of flux; an option number has NOT been assigned to it yet. The code is provided in this release for experimental and testing purposes. The telnet "send" command can now be used to send do/dont/will/wont commands, with any telnet option name. The rules for when do/dont/will/wont are sent are still followed, so just because the user requests that one of these be sent doesn't mean that it will be sent... The telnet "getstatus" command no longer requires that option printing be enabled to see the response to the "DO STATUS" command. A -n flag has been added to telnetd to disable keepalives. A new telnet command, "auth" has been added (if AUTHENTICATE is defined). It has four sub-commands, "status", "debug", "disable", "enable" and "help". A new telnet command, "encrypt" has been added (if ENCRYPT is defined). It has many sub-commands: "enable", "type", "start", "stop", "input", "-input", "output", "-output", "status", "auto", "verbose", "debug", and "help". An "rlogin" interface has been added. If the program is named "rlogin", or the "-r" flag is given, then an rlogin type of interface will be used. ~. Terminates the session ~ Suspend the session ~^] Escape to telnet command mode ~~ Pass through the ~. BUG: If you type the rlogin escape character in the middle of a line while in rlogin mode, you cannot erase it or any characters before it. Hopefully this can be fixed in a future release... General changes: A "libtelnet.a" has now been created. This libraray contains code that is common to both telnet and telnetd. This is also where library routines that are needed, but are not in the standard C library, are placed. The makefiles have been re-done. All of the site specific configuration information has now been put into a single "Config.generic" file, in the top level directory. Changing this one file will take care of all three subdirectories. Also, to add a new/local definition, a "Config.local" file may be created at the top level; if that file exists, the subdirectories will use that file instead of "Config.generic". Many 1-2 line functions in commands.c have been removed, and just inserted in-line, or replaced with a macro. Bug Fixes: The non-termio code in both telnet and telnetd was setting/clearing CTLECH in the sg_flags word. This was incorrect, and has been changed to set/clear the LCTLECH bit in the local mode word. The SRCRT #define has been removed. If IP_OPTIONS and IPPROTO_IP are defined on the system, then the source route code is automatically enabled. The NO_GETTYTAB #define has been removed; there is a compatability routine that can be built into libtelnet to achive the same results. The server, telnetd, has been switched to use getopt() for parsing the argument list. The code for getting the input/output speeds via cfgetispeed()/cfgetospeed() was still not quite right in telnet. Posix says if the ispeed is 0, then it is really equal to the ospeed. The suboption processing code in telnet now has explicit checks to make sure that we received the entire suboption (telnetd was already doing this). The telnet code for processing the terminal type could cause a core dump if an existing connection was closed, and a new connection opened without exiting telnet. Telnetd was doing a TCSADRAIN when setting the new terminal settings; This is not good, because it means that the tcsetattr() will hang waiting for output to drain, and telnetd is the only one that will drain the output... The fix is to use TCSANOW which does not wait. Telnetd was improperly setting/clearing the ISTRIP flag in the c_lflag field, it should be using the c_iflag field. When the child process of telnetd was opening the slave side of the pty, it was re-setting the EXTPROC bit too early, and some of the other initialization code was wiping it out. This would cause telnetd to go out of linemode and into single character mode. One instance of leaving linemode in telnetd forgot to send a WILL ECHO to the client, the net result would be that the user would see double character echo. If the MODE was being changed several times very quickly, telnetd could get out of sync with the state changes and the returning acks; and wind up being left in the wrong state. September 14, 1990: Switch the client to use getopt() for parsing the argument list. The 4.3Reno getopt.c is included for systems that don't have getopt(). Use the posix _POSIX_VDISABLE value for what value to use when disabling special characters. If this is undefined, it defaults to 0x3ff. For non-termio systems, TIOCSETP was being used to change the state of the terminal. This causes the input queue to be flushed, which we don't want. This is now changed to TIOCSETN. Take out the "#ifdef notdef" around the code in the server that generates a "sync" when the pty oputput is flushed. The potential problem is that some older telnet clients may go into an infinate loop when they receive a "sync", if so, the server can be compiled with "NO_URGENT" defined. Fix the client where it was setting/clearing the OPOST bit in the c_lflag field, not the c_oflag field. Fix the client where it was setting/clearing the ISTRIP bit in the c_lflag field, not the c_iflag field. (On 4.3Reno, this is the ECHOPRT bit in the c_lflag field.) The client also had its interpretation of WILL BINARY and DO BINARY reversed. Fix a bug in client that would cause a core dump when attempting to remove the last environment variable. In the client, there were a few places were switch() was being passed a character, and if it was a negative value, it could get sign extended, and not match the 8 bit case statements. The fix is to and the switch value with 0xff. Add a couple more printoption() calls in the client, I don't think there are any more places were a telnet command can be received and not printed out when "options" is on. A new flag has been added to the client, "-a". Currently, this just causes the USER name to be sent across, in the future this may be used to signify that automatic authentication is requested. The USER variable is now only sent by the client if the "-a" or "-l user" options are explicity used, or if the user explicitly asks for the "USER" environment variable to be exported. In the server, if it receives the "USER" environment variable, it won't print out the banner message, so that only "Password:" will be printed. This makes the symantics more like rlogin, and should be more familiar to the user. (People are not used to getting a banner message, and then getting just a "Password:" prompt.) Re-vamp the code for starting up the child login process. The code was getting ugly, and it was hard to tell what was really going on. What we do now is after the fork(), in the child: 1) make sure we have no controlling tty 2) open and initialize the tty 3) do a setsid()/setpgrp() 4) makes the tty our controlling tty. On some systems, #2 makes the tty our controlling tty, and #4 is a no-op. The parent process does a gets rid of any controlling tty after the child is fork()ed. Use the strdup() library routine in telnet, instead of the local savestr() routine. If you don't have strdup(), you need to define NO_STRDUP. Add support for ^T (SIGINFO/VSTATUS), found in the 4.3Reno distribution. This maps to the AYT character. You need a 4-line bugfix in the kernel to get this to work properly: > *** tty_pty.c.ORG Tue Sep 11 09:41:53 1990 > --- tty_pty.c Tue Sep 11 17:48:03 1990 > *************** > *** 609,613 **** > if ((tp->t_lflag&NOFLSH) == 0) > ttyflush(tp, FREAD|FWRITE); > ! pgsignal(tp->t_pgrp, *(unsigned int *)data); > return(0); > } > --- 609,616 ---- > if ((tp->t_lflag&NOFLSH) == 0) > ttyflush(tp, FREAD|FWRITE); > ! pgsignal(tp->t_pgrp, *(unsigned int *)data, 1); > ! if ((*(unsigned int *)data == SIGINFO) && > ! ((tp->t_lflag&NOKERNINFO) == 0)) > ! ttyinfo(tp); > return(0); > } The client is now smarter when setting the telnet escape character; it only sets it to one of VEOL and VEOL2 if one of them is undefined, and the other one is not already defined to the telnet escape character. Handle TERMIOS systems that have seperate input and output line speed settings imbedded in the flags. Many other minor bug fixes. June 20, 1990: Re-organize makefiles and source tree. The telnet/Source directory is now gone, and all the source that was in telnet/Source is now just in the telnet directory. Seperate makefile for each system are now gone. There are two makefiles, Makefile and Makefile.generic. The "Makefile" has the definitions for the various system, and "Makefile.generic" does all the work. There is a variable called "WHAT" that is used to specify what to make. For example, in the telnet directory, you might say: make 4.4bsd WHAT=clean to clean out the directory. Add support for the ENVIRON and XDISPLOC options. In order for the server to work, login has to have the "-p" option to preserve environment variables. Add the SOFT_TAB and LIT_ECHO modes in the LINEMODE support. Add the "-l user" option to command line and open command (This is passed through the ENVIRON option). Add the "-e" command line option, for setting the escape character. Add the "-D", diagnostic, option to the server. This allows the server to print out debug information, which is very useful when trying to debug a telnet that doesn't have any debugging ability. Turn off the literal next character when not in LINEMODE. Don't recognize ^Y locally, just pass it through. Make minor modifications for Sun4.0 and Sun4.1 Add support for both FORW1 and FORW2 characters. The telnet escpape character is set to whichever of the two is not being used. If both are in use, the escape character is not set, so when in linemode the user will have to follow the escape character with a or The following TELNET options are supported: LINEMODE: The LINEMODE option is supported as per RFC1116. The FORWARDMASK option is not currently supported. BINARY: The client has the ability to turn on/off the BINARY option in each direction. Turning on BINARY from server to client causes the LITOUT bit to get set in the terminal driver on both ends, turning on BINARY from the client to the server causes the PASS8 bit to get set in the terminal driver on both ends. TERMINAL-TYPE: This is supported as per RFC1091. On the server side, when a terminal type is received, termcap/terminfo is consulted to determine if it is a known terminal type. It keeps requesting terminal types until it gets one that it recongnizes, or hits the end of the list. The server side looks up the entry in the termcap/terminfo data base, and generates a list of names which it then passes one at a time to each request for a terminal type, duplicating the last entry in the list before cycling back to the beginning. NAWS: The Negotiate about Window Size, as per RFC 1073. TERMINAL-SPEED: Implemented as per RFC 1079 TOGGLE-FLOW-CONTROL: Implemented as per RFC 1080 TIMING-MARK: As per RFC 860 SGA: As per RFC 858 ECHO: As per RFC 857 STATUS: The server will send its current status upon request. It does not ask for the clients status. The client will request the servers current status from the "send getstatus" command. ENVIRON: This option is currently being defined by the IETF Telnet Working Group, and an RFC has not yet been issued, but should be in the near future... X-DISPLAY-LOCATION: This functionality can be done through the ENVIRON option, it is added here for completeness. AUTHENTICATION: This option is currently being defined by the IETF Telnet Working Group, and an RFC has not yet been issued. The basic framework is pretty much decided, but the definitions for the specific authentication schemes is still in a state of flux. ENCRYPT: This option is currently being defined by the IETF Telnet Working Group, and an RFC has not yet been issued. The draft RFC is still in a state of flux, so this code may change in the future. netkit-telnet-0.17/telnet/TODO100644 144 144 435 6204244246 15504 0ustar dhollandpeopleeliminate global variables clean up command processing fix "send" command clean up option processing add empty encrypt hooks (layer over ring buffers) flushout --> use nullsink fix ring buffer so it allocates more buf instead of overflowing put tracing back in authentication? netkit-telnet-0.17/telnet/array.h100644 144 144 5412 7006332222 16314 0ustar dhollandpeople// // File: array.h // Date: 16-Jul-95 // Description: array template // /* * Copyright (c) 1995 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. 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 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 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. */ #ifndef ARRAY_H #define ARRAY_H #ifndef assert #include #endif #ifndef NULL #define NULL 0 #endif inline void *operator new(size_t, void *v) { return v; } template class array { protected: T *v; int n, max; void reallocto(int newsize) { while (maxmax) reallocto(newsize); if (newsize>n) { // call default constructors for (int i=n; i=0 && ix #include #include #include #include "ring.h" #include "externs.h" #include "defines.h" #include "types.h" #include "proto.h" int net_write(str, len) unsigned char *str; int len; { if (NETROOM() > len) { netoring.supply_data(str, len); if (str[0] == IAC && str[1] == SE) printsub('>', &str[2], len-2); return(len); } return(0); } void net_encrypt() { #if defined(ENCRYPT) if (encrypt_output) ring_encrypt(&netoring, encrypt_output); else ring_clearto(&netoring); #endif } int telnet_spin() { return(-1); } char * telnet_getenv(val) 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 * telnet_gets(prompt, result, length, echo) char *prompt; char *result; int length; int echo; { extern char *getpass(); extern int globalmode; int om = globalmode; char *res; TerminalNewMode(-1); if (echo) { printf("%s", prompt); res = fgets(result, length, stdin); } else if ((res = getpass(prompt))!=NULL) { strncpy(result, res, length); res = result; } TerminalNewMode(om); return(res); } #endif netkit-telnet-0.17/telnet/commands.cc100644 144 144 155743 7136470630 17224 0ustar dhollandpeople/* * Copyright (c) 1988, 1990 Regents of the University of California. * 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 the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND 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 REGENTS OR 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. */ /* * From: @(#)commands.c 5.5 (Berkeley) 3/22/91 */ char cmd_rcsid[] = "$Id: commands.cc,v 1.34 2000/07/23 04:16:24 dholland Exp $"; #include #include #include #include #include #include #include #ifdef CRAY #include #endif /* CRAY */ #include #include #include #include #include #include #include #include #include #include #include #include "ring.h" #include "externs.h" #include "defines.h" #include "types.h" #include "genget.h" #include "environ.h" #include "proto.h" #include "ptrarray.h" #include "netlink.h" /* In Linux, this is an enum */ #if defined(__linux__) || defined(IPPROTO_IP) #define HAS_IPPROTO_IP #endif #ifndef CRAY #if (defined(vax) || defined(tahoe) || defined(hp300)) && !defined(ultrix) #include #endif /* vax */ #endif /* CRAY */ #define HELPINDENT ((int) sizeof ("connect")) #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 64 #endif MAXHOSTNAMELEN #if defined(HAS_IPPROTO_IP) && defined(IP_TOS) int tos = -1; #endif /* defined(HAS_IPPROTO_IP) && defined(IP_TOS) */ static unsigned long sourceroute(char *arg, char **cpp, int *lenp); char *hostname; static char _hostname[MAXHOSTNAMELEN]; //typedef int (*intrtn_t)(int argc, const char *argv[]); class command_entry; typedef ptrarray command_table; static int process_command(command_table *tab, int argc, const char **argv); class command_entry { protected: const char *name; /* command name */ const char *help; /* help string (NULL for no help) */ int nargs; union { /* routine which executes command */ command_table *subhandler; int (*handlern)(int, const char **); int (*handler0)(void); int (*handler1)(const char *); int (*handler2)(const char *, const char *); }; public: command_entry(const char *n, const char *e, int (*h)(int, const char **)) { name = n; help = e; nargs = -1; handlern = h; } command_entry(const char *n, const char *e, int (*h)(void)) { name = n; help = e; nargs = 0; handler0 = h; } command_entry(const char *n, const char *e, int (*h)(const char *)) { name = n; help = e; nargs = 1; handler1 = h; } command_entry(const char *n, const char *e, int (*h)(const char *, const char *)) { name = n; help = e; nargs = 2; handler2 = h; } command_entry(const char *n, const char *e, command_table *sub) { name = n; help = e; nargs = -2; subhandler = sub; } int call(int argc, const char *argv[]) { 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]); return 0; /* is this right? */ } if (nargs==-2) { if (argc<2) { fprintf(stderr, "`%s' requires a subcommand.\n", argv[0]); fprintf(stderr, "Try %s ? for help\n", argv[0]); return 0; /* is this right? */ } return process_command(subhandler, argc-1, argv+1); } else if (nargs==-1) return handlern(argc, argv); else if (nargs==0) return handler0(); else if (nargs==1) return handler1(argv[1]); else if (nargs==2) return handler2(argv[1], argv[2]); return 0; } void describe() { if (help) printf("%-*s\t%s\n", HELPINDENT, name, help); } void gethelp() { if (help) printf("%s\n", help); else printf("No help available\n"); } const char *getname() const { return name; } }; static char line[256]; static char saveline[256]; static int margc; static const char *margv[20]; static void makeargv(void) { register char *cp, *cp2, c; register const char **argp = margv; margc = 0; cp = line; if (*cp == '!') { /* Special case shell escape */ strcpy(saveline, line); /* save for shell command */ *argp++ = "!"; /* No room in string to get this */ margc++; cp++; } while ((c = *cp)!=0) { register int inquote = 0; while (isspace(c)) c = *++cp; if (c == '\0') break; *argp++ = cp; margc += 1; for (cp2 = cp; c != '\0'; c = *++cp) { if (inquote) { if (c == inquote) { inquote = 0; continue; } } else { if (c == '\\') { if ((c = *++cp) == '\0') break; } else if (c == '"') { inquote = '"'; continue; } else if (c == '\'') { inquote = '\''; continue; } else if (isspace(c)) break; } *cp2++ = c; } *cp2 = '\0'; if (c == '\0') break; cp++; } *argp++ = 0; } /* * Make a character string into a number. * * Todo: 1. Could take random integers (12, 0x12, 012, 0b1). */ static int special(const char *s) { char c; char b; switch (*s) { case '^': b = *++s; if (b == '?') { c = b | 0x40; /* DEL */ } else { c = b & 0x1f; } break; default: c = *s; break; } return c; } /* * Construct a control character sequence * for a special character. */ static const char *control(cc_t c) { static char buf[5]; /* * The only way I could get the Sun 3.5 compiler * to shut up about * if ((unsigned int)c >= 0x80) * was to assign "c" to an unsigned int variable... * Arggg.... */ register unsigned int uic = (unsigned int)c; if (uic == 0x7f) return ("^?"); if (c == (cc_t)_POSIX_VDISABLE) { return "off"; } if (uic >= 0x80) { buf[0] = '\\'; buf[1] = ((c>>6)&07) + '0'; buf[2] = ((c>>3)&07) + '0'; buf[3] = (c&07) + '0'; buf[4] = 0; } else if (uic >= 0x20) { buf[0] = c; buf[1] = 0; } else { buf[0] = '^'; buf[1] = '@'+c; buf[2] = 0; } return (buf); } /* * The following are data structures and routines for * the "send" command. * */ struct sendlist { const char *name; /* How user refers to it (case independent) */ const char *help; /* Help information (0 ==> no help) */ int needconnect; /* Need to be connected */ int narg; /* Number of arguments */ int (*handler)(const char *, const char *); /* Routine to perform (for special ops) */ int nbyte; /* Number of bytes to send this command */ int what; /* Character to be sent (<0 ==> special) */ }; static int send_esc(const char *, const char *); static int send_help(const char *, const char *); static int send_docmd(const char *, const char *); static int send_dontcmd(const char *, const char *); static int send_willcmd(const char *, const char *); static int send_wontcmd(const char *, const char *); extern int send_do(int, int); extern int send_dont(int, int); extern int send_will(int, int); extern int send_wont(int, int); static int dosynch1(const char *, const char *) { return dosynch(); } static struct sendlist Sendlist[] = { { "ao", "Send Telnet Abort output", 1, 0, 0, 2, AO }, { "ayt", "Send Telnet 'Are You There'", 1, 0, 0, 2, AYT }, { "brk", "Send Telnet Break", 1, 0, 0, 2, BREAK }, { "break", 0, 1, 0, 0, 2, BREAK }, { "ec", "Send Telnet Erase Character", 1, 0, 0, 2, EC }, { "el", "Send Telnet Erase Line", 1, 0, 0, 2, EL }, { "escape", "Send current escape character", 1, 0, send_esc, 1, 0 }, { "ga", "Send Telnet 'Go Ahead' sequence", 1, 0, 0, 2, GA }, { "ip", "Send Telnet Interrupt Process", 1, 0, 0, 2, IP }, { "intp", 0, 1, 0, 0, 2, IP }, { "interrupt", 0, 1, 0, 0, 2, IP }, { "intr", 0, 1, 0, 0, 2, IP }, { "nop", "Send Telnet 'No operation'", 1, 0, 0, 2, NOP }, { "eor", "Send Telnet 'End of Record'", 1, 0, 0, 2, EOR }, { "abort", "Send Telnet 'Abort Process'", 1, 0, 0, 2, ABORT }, { "susp", "Send Telnet 'Suspend Process'", 1, 0, 0, 2, SUSP }, { "eof", "Send Telnet End of File Character", 1, 0, 0, 2, xEOF }, { "synch", "Perform Telnet 'Synch operation'", 1, 0, dosynch1, 2, 0 }, { "getstatus", "Send request for STATUS", 1, 0, get_status, 6, 0 }, { "?", "Display send options", 0, 0, send_help, 0, 0 }, { "help", 0, 0, 0, send_help, 0, 0 }, { "do", 0, 0, 1, send_docmd, 3, 0 }, { "dont", 0, 0, 1, send_dontcmd, 3, 0 }, { "will", 0, 0, 1, send_willcmd, 3, 0 }, { "wont", 0, 0, 1, send_wontcmd, 3, 0 }, { 0, 0, 0, 0, 0, 0, 0 } }; #define GETSEND(name) ((struct sendlist *) genget(name, (char **) Sendlist, \ sizeof(struct sendlist))) static int sendcmd(int argc, const char *argv[]) { int count; /* how many bytes we are going to need to send */ int i; /* int question = 0;*/ /* was at least one argument a question */ struct sendlist *s; /* pointer to current command */ int success = 0; int needconnect = 0; if (argc < 2) { printf("need at least one argument for 'send' command\n"); printf("'send ?' for help\n"); return 0; } /* * First, validate all the send arguments. * In addition, we see how much space we are going to need, and * whether or not we will be doing a "SYNCH" operation (which * flushes the network queue). */ count = 0; for (i = 1; i < argc; i++) { s = GETSEND(argv[i]); if (s == 0) { printf("Unknown send argument '%s'\n'send ?' for help.\n", argv[i]); return 0; } else if (s == AMBIGUOUS) { printf("Ambiguous send argument '%s'\n'send ?' for help.\n", argv[i]); return 0; } if (i + s->narg >= argc) { fprintf(stderr, "Need %d argument%s to 'send %s' command. 'send %s ?' for help.\n", s->narg, s->narg == 1 ? "" : "s", s->name, s->name); return 0; } count += s->nbyte; if (s->handler == send_help) { send_help(NULL, NULL); return 0; } i += s->narg; needconnect += s->needconnect; } if (!connected && needconnect) { printf("?Need to be connected first.\n"); printf("'send ?' for help\n"); return 0; } /* Now, do we have enough room? */ if (netoring.empty_count() < count) { printf("There is not enough room in the buffer TO the network\n"); printf("to process your request. Nothing will be done.\n"); printf("('send synch' will throw away most data in the network\n"); printf("buffer, if this might help.)\n"); return 0; } /* OK, they are all OK, now go through again and actually send */ count = 0; for (i = 1; i < argc; i++) { if ((s = GETSEND(argv[i])) == 0) { fprintf(stderr, "Telnet 'send' error - argument disappeared!\n"); quit(); /*NOTREACHED*/ } if (s->handler) { count++; success += (*s->handler)((s->narg > 0) ? argv[i+1] : 0, (s->narg > 1) ? argv[i+2] : 0); i += s->narg; } else { NET2ADD(IAC, s->what); printoption("SENT", IAC, s->what); } } return (count == success); } static int send_esc(const char *, const char *) { NETADD(escapechar); return 1; } static int send_docmd(const char *name, const char *) { return send_tncmd(send_do, "do", name); } static int send_dontcmd(const char *name, const char *) { return(send_tncmd(send_dont, "dont", name)); } static int send_willcmd(const char *name, const char *) { return(send_tncmd(send_will, "will", name)); } static int send_wontcmd(const char *name, const char *) { return(send_tncmd(send_wont, "wont", name)); } int send_tncmd(int (*func)(int, int), const char *cmd, const char *name) { char **cpp; extern char *telopts[]; if (isprefix(name, "help") || isprefix(name, "?")) { register int col, len; printf("Usage: send %s