Import NetBSD telnet(1)

Change-Id: Ib58b43cc9baabe183a59410212827f65ec117277
This commit is contained in:
David van Moolenbroek
2017-02-15 17:41:07 +00:00
parent 72e899eafc
commit 7348b5c52b
44 changed files with 17305 additions and 3 deletions

View File

@@ -26,7 +26,7 @@ SUBDIR= asa \
\
sdiff sed seq shar shlock \
shuffle sort split stat su \
tail tee tic time touch \
tail tee telnet tic time touch \
tput \
tr true tsort tty ul uname unexpand unifdef \
uniq units unvis unzip users \

89
usr.bin/telnet/Makefile Normal file
View File

@@ -0,0 +1,89 @@
# $NetBSD: Makefile,v 1.50 2012/08/10 12:10:27 joerg Exp $
#
# Copyright (c) 1990 The 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: @(#)Makefile 8.1 (Berkeley) 6/6/93
#
WARNS?= 4 # XXX -Wshadow etc. fix asap
CWARNFLAGS.clang+= -Wno-tautological-compare -Wno-format-security
.include <bsd.own.mk>
USE_FORT?= yes # network client
PROG= telnet
CPPFLAGS+=-DKLUDGELINEMODE -DUSE_TERMIO -DENV_HACK
CPPFLAGS+=-I${.CURDIR}
LDADD+= -lterminfo ${LIBTELNETDIR}/libtelnet.a
DPADD+= ${LIBTERMINFO} ${LIBTELNETDIR}/libtelnet.a
SRCS= authenc.c commands.c main.c network.c ring.c sys_bsd.c telnet.c \
terminal.c tn3270.c utilities.c
CPPFLAGS+=-I${NETBSDSRCDIR}/lib
.if !defined(__MINIX)
CPPFLAGS+=-DIPSEC
LDADD+= -lipsec
DPADD+= ${LIBIPSEC}
.endif # !defined(__MINIX)
.if (${USE_INET6} != "no")
CPPFLAGS+=-DINET6
.endif
LIBTELNETDIR!= cd ${.CURDIR}/../../lib/libtelnet; ${PRINTOBJDIR}
.if (${USE_KERBEROS} != "no")
CPPFLAGS+=-DKRB5 -DFORWARD
LDADD+= -lkrb5 -lasn1 -lcom_err -lroken
DPADD+= ${LIBKRB5} ${LIBASN1} ${LIBCOM_ERR} ${LIBROKEN}
.endif
.if (${MKCRYPTO} != "no")
CPPFLAGS+=-DAUTHENTICATION -DENCRYPTION
LDADD+= -ldes -lcrypto -lcrypt
DPADD+= ${LIBDES} ${LIBCRYPTO} ${LIBCRYPT}
.endif
.if (${USE_PAM} != "no")
LDADD+= -lpam ${PAM_STATIC_LDADD}
DPADD+= ${LIBPAM} ${PAM_STATIC_DPADD}
.endif
.for f in commands telnet terminal utilities
COPTS.${f}.c+= -Wno-pointer-sign
.endfor
.include <bsd.prog.mk>

763
usr.bin/telnet/README Normal file
View File

@@ -0,0 +1,763 @@
This is a distribution of both client and server telnet. These programs
have been compiled on:
telnet telnetd
4.4 BSD-Lite x x
4.3 BSD Reno X X
UNICOS 9.1 X X
UNICOS 9.0 X X
UNICOS 8.0 X X
BSDI 2.0 X X
Solaris 2.4 x x (no linemode in server)
SunOs 4.1.4 X X (no linemode in server)
Ultrix 4.3 X X (no linemode in server)
Ultrix 4.1 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
Next1.0 X X
UNICOS 8.3 X X
UNICOS 7.C X X
UNICOS 7.0 X X
SunOs 4.0.3c X X (no linemode in server)
4.3 BSD X X (no linemode in server)
DYNIX V3.0.12 X X (no linemode in server)
Ultrix 3.1 X X (no linemode in server)
Ultrix 4.0 X X (no linemode in server)
SunOs 3.5 X X (no linemode in server)
SunOs 4.1.3 X X (no linemode in server)
Solaris 2.2 x x (no linemode in server)
Solaris 2.3 x x (no linemode in server)
BSDI 1.0 X X
BSDI 1.1 X X
DYNIX V3.0.17.9 X X (no linemode in server)
HP-UX 8.0 x x (no linemode in server)
This code should work, but there are no guarantees.
Oct 23, 1995
This is a bugfix release.
The change in the previous release from using makeutx() to
pututxline() caused problems on SunOS/Solaris. It has been
changed back to using makeutx(). Symptoms include users
getting error messages when logging in about not being able
to open the tty.
Using memmove() instead of memcpy() caused problems under
SunOS 4.x, since it doesn't have memmove(). Config.generic
has been modified to include mem.o for SunOS 4.x.
Some new code was added to telnetd to do some environment
variable cleanup before execing login. Thanks to Sam Hartman
at MIT for pointing this out.
A couple of other minor bugfixes.
May 30, 1995
This release represents what is on the 4.4BSD-Lite2 release, which
should be the final BSD release. I will continue to support of
telnet, The code (without encryption) is available via anonymous ftp
from ftp.cray.com, in src/telnet/telnet.YY.MM.DD.NE.tar.Z, where
YY.MM.DD is replaced with the year, month and day of the release.
If you can't find it at one of these places, at some point in the
near future information about the latest releases should be available
from ftp.borman.com.
In addition, the version with the encryption code is available via
ftp from net-dist.mit.edu, in the directory /pub/telnet. There
is a README file there that gives further information on how
to get the distribution.
Questions, comments, bug reports and bug fixes can be sent to
one of these addresses:
dab@borman.com
dab@cray.com
dab@bsdi.com
This release is mainly bug fixes and code cleanup.
Replace all calls to bcopy()/bzero() with calls to
memmove()/memset() and all calls to index()/rindex()
with calls to strchr()/strrchr().
Add some missing diagnostics for option tracing
to telnetd.
Add support for BSDI 2.0 and Solaris 2.4.
Add support for UNICOS 8.0
Get rid of expanded tabs and trailing white spaces.
From Paul Vixie:
Fix for telnet going into an endless spin
when the session dies abnormally.
From Jef Poskanzer:
Changes to allow telnet to compile
under SunOS 3.5.
From Philip Guenther:
makeutx() doesn't expand utmpx,
use pututxline() instead.
From Chris Torek:
Add a sleep(1) before execing login
to avoid race condition that can eat
up the login prompt.
Use terminal speed directly if it is
not an encoded value.
From Steve Parker:
Fix to realloc() call. Fix for execing
login on solaris with no user name.
January 19, 1994
This is a list of some of the changes since the last tar release
of telnet/telnetd. There are probably other changes that aren't
listed here, but this should hit a lot of the main ones.
General:
Changed #define for AUTHENTICATE to AUTHENTICATION
Changed #define for ENCRYPT to ENCRYPTION
Changed #define for DES_ENCRYPT to DES_ENCRYPTION
Added support for SPX authentication: -DSPX
Added support for Kerberos Version 5 authentication: -DKRB5
Added support for ANSI C function prototypes
Added support for the NEW-ENVIRON option (RFC-1572)
including support for USERVAR.
Made support for the old Environment Option (RFC-1408)
conditional on -DOLD_ENVIRON
Added #define ENV_HACK - support for RFC 1571
The encryption code is removed from the public distributions.
Domestic 4.4 BSD distributions contain the encryption code.
ENV_HACK: Code to deal with systems that only implement
the old ENVIRON option, and have reversed definitions
of ENV_VAR and ENV_VAL. Also fixes ENV processing in
client to handle things besides just the default set...
NO_BSD_SETJMP: UNICOS configuration for
UNICOS 6.1/6.0/5.1/5.0 systems.
STREAMSPTY: Use /dev/ptmx to get a clean pty. This
is for SVr4 derivatives (Like Solaris)
UTMPX: For systems that have /etc/utmpx. This is for
SVr4 derivatives (Like Solaris)
Definitions for BSDI 1.0
Definitions for 4.3 Reno and 4.4 BSD.
Definitions for UNICOS 8.0 and UNICOS 7.C
Definitions for Solaris 2.0
Definitions for HP-UX 8.0
Latest Copyright notices from Berkeley.
FLOW-CONTROL: support for RFC-XXXx
Client Specific:
Fix the "send" command to not send garbage...
Fix status message for "skiprc"
Make sure to send NAWS after telnet has been suspended
or an external command has been run, if the window size
has changed.
sysV88 support.
Server Specific:
Support flowcontrol option in non-linemode servers.
-k Server supports Kludge Linemode, but will default to
either single character mode or real Linemode support.
The user will have to explicitly ask to switch into
kludge linemode. ("stty extproc", or escape back to
to telnet and say "mode line".)
-u Specify the length of the hostname field in the utmp
file. Hostname longer than this length will be put
into the utmp file in dotted decimal notation, rather
than putting in a truncated hostname.
-U Registered hosts only. If a reverse hostname lookup
fails, the connection will be refused.
-f/-F
Allows forwarding of credentials for KRB5.
February 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 been assigned to, but it is still
subject to change. 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", "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", and "help".
The LOGOUT option is now supported by both telnet
and telnetd, a new command, "logout", was added
to support this.
Several new toggle options were added:
"autoencrypt", "autodecrypt", "autologin", "authdebug",
"encdebug", "skiprc", "verbose_encrypt"
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
~<susp> 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 library
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 compatibility routine that can be built into
libtelnet to achieve 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 output
is flushed. The potential problem is that some older
telnet clients may go into an infinite 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 explicitly 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 semantics 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 separate input and output
line speed settings embedded 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.
Separate 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 escape 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 <CR> or <EOF)
to get it passed through.
Commands can now be put in single and double quotes, and
a backslash is now an escape character. This is needed
for allowing arbitrary strings to be assigned to environment
variables.
Switch telnetd to use macros like telnet for keeping
track of the state of all the options.
Fix telnetd's processing of options so that we always do
the right processing of the LINEMODE option, regardless
of who initiates the request to turn it on. Also, make
sure that if the other side went "WILL ECHO" in response
to our "DO ECHO", that we send a "DONT ECHO" to get the
option turned back off!
Fix the TERMIOS setting of the terminal speed to handle both
BSD's separate fields, and the SYSV method of CBAUD bits.
Change how we deal with the other side refusing to enable
an option. The sequence used to be: send DO option; receive
WONT option; send DONT option. Now, the sequence is: send
DO option; receive WONT option. Both should be valid
according to the spec, but there has been at least one
client implementation of telnet identified that can get
really confused by this. (The exact sequence, from a trace
on the server side, is (numbers are number of responses that
we expect to get after that line...):
send WILL ECHO 1 (initial request)
send WONT ECHO 2 (server is changing state)
recv DO ECHO 1 (first reply, ok. expect DONT ECHO next)
send WILL ECHO 2 (server changes state again)
recv DONT ECHO 1 (second reply, ok. expect DO ECHO next)
recv DONT ECHO 0 (third reply, wrong answer. got DONT!!!)
*** send WONT ECHO (send WONT to acknowledge the DONT)
send WILL ECHO 1 (ask again to enable option)
recv DO ECHO 0
recv DONT ECHO 0
send WONT ECHO 1
recv DONT ECHO 0
recv DO ECHO 1
send WILL ECHO 0
(and the last 5 lines loop forever)
The line with the "***" is last of the WILL/DONT/WONT sequence.
The change to the server to not generate that makes this same
example become:
send will ECHO 1
send wont ECHO 2
recv do ECHO 1
send will ECHO 2
recv dont ECHO 1
recv dont ECHO 0
recv do ECHO 1
send will ECHO 0
There is other option negotiation going on, and not sending
the third part changes some of the timings, but this specific
example no longer gets stuck in a loop. The "telnet.state"
file has been modified to reflect this change to the algorithm.
A bunch of miscellaneous bug fixes and changes to make
lint happier.
This version of telnet also has some KERBEROS stuff in
it. This has not been tested, it uses an un-authorized
telnet option number, and uses an out-of-date version
of the (still being defined) AUTHENTICATION option.
There is no support for this code, do not enable it.
March 1, 1990:
CHANGES/BUGFIXES SINCE LAST RELEASE:
Some support for IP TOS has been added. Requires that the
kernel support the IP_TOS socket option (currently this
is only in UNICOS 6.0).
Both telnet and telnetd now use the cc_t typedef. typedefs are
included for systems that don't have it (in termios.h).
SLC_SUSP was not supported properly before. It is now.
IAC EOF was not translated properly in telnetd for SYSV_TERMIO
when not in linemode. It now saves a copy of the VEOF character,
so that when ICANON is turned off and we can't trust it anymore
(because it is now the VMIN character) we use the saved value.
There were two missing "break" commands in the linemode
processing code in telnetd.
Telnetd wasn't setting the kernel window size information
properly. It was using the rows for both rows and columns...
Questions/comments go to
David Borman
Cray Research, Inc.
655F Lone Oak Drive
Eagan, MN 55123
dab@cray.com.
README: You are reading it.
Config.generic:
This file contains all the OS specific definitions. It
has pre-definitions for many common system types, and is
in standard makefile format. See the comments at the top
of the file for more information.
Config.local:
This is not part of the distribution, but if this file exists,
it is used instead of "Config.generic". This allows site
specific configuration without having to modify the distributed
"Config.generic" file.
kern.diff:
This file contains the diffs for the changes needed for the
kernel to support LINEMODE is the server. These changes are
for a 4.3BSD system. You may need to make some changes for
your particular system.
There is a new bit in the terminal state word, TS_EXTPROC.
When this bit is set, several aspects of the terminal driver
are disabled. Input line editing, character echo, and
mapping of signals are all disabled. This allows the telnetd
to turn of these functions when in linemode, but still keep
track of what state the user wants the terminal to be in.
New ioctl()s:
TIOCEXT Turn on/off the TS_EXTPROC bit
TIOCGSTATE Get t_state of tty to look at TS_EXTPROC bit
TIOCSIG Generate a signal to processes in the
current process group of the pty.
There is a new mode for packet driver, the TIOCPKT_IOCTL bit.
When packet mode is turned on in the pty, and the TS_EXTPROC
bit is set, then whenever the state of the pty is changed, the
next read on the master side of the pty will have the TIOCPKT_IOCTL
bit set, and the data will contain the following:
struct xx {
struct sgttyb a;
struct tchars b;
struct ltchars c;
int t_state;
int t_flags;
}
This allows the process on the server side of the pty to know
when the state of the terminal has changed, and what the new
state is.
However, if you define USE_TERMIO or SYSV_TERMIO, the code will
expect that the structure returned in the TIOCPKT_IOCTL is
the termio/termios structure.
stty.diff:
This file contains the changes needed for the stty(1) program
to report on the current status of the TS_EXTPROC bit. It also
allows the user to turn on/off the TS_EXTPROC bit. This is useful
because it allows the user to say "stty -extproc", and the
LINEMODE option will be automatically disabled, and saying "stty
extproc" will re-enable the LINEMODE option.
telnet.state:
Both the client and server have code in them to deal
with option negotiation loops. The algorithm that is
used is described in this file.
telnet:
This directory contains the client code. No kernel changes are
needed to use this code.
telnetd:
This directory contains the server code. If LINEMODE or KLUDGELINEMODE
are defined, then the kernel modifications listed above are needed.
libtelnet:
This directory contains code that is common to both the client
and the server.
arpa:
This directory has a new <arpa/telnet.h>
libtelnet/Makefile.4.4:
telnet/Makefile.4.4:
telnetd/Makefile.4.4:
These are the makefiles that can be used on a 4.3Reno
system when this software is installed in /usr/src/lib/libtelnet,
/usr/src/libexec/telnetd, and /usr/src/usr.bin/telnet.
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 recognizes, 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
LOGOUT: As per RFC 727
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.
ENCRYPTION:
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.

107
usr.bin/telnet/authenc.c Normal file
View File

@@ -0,0 +1,107 @@
/* $NetBSD: authenc.c,v 1.13 2012/01/09 16:08:55 christos Exp $ */
/*-
* Copyright (c) 1991, 1993
* The 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. 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.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)authenc.c 8.1 (Berkeley) 6/6/93";
#else
__RCSID("$NetBSD: authenc.c,v 1.13 2012/01/09 16:08:55 christos Exp $");
#endif
#endif /* not lint */
#if defined(AUTHENTICATION) || defined(ENCRYPTION)
#include <unistd.h>
#include <sys/types.h>
#include <arpa/telnet.h>
#include <libtelnet/encrypt.h>
#include <libtelnet/misc.h>
#include "general.h"
#include "ring.h"
#include "externs.h"
#include "defines.h"
#include "types.h"
int
telnet_net_write(unsigned char *str, int len)
{
if (NETROOM() > len) {
ring_supply_data(&netoring, str, len);
if (str[0] == IAC && str[1] == SE)
printsub('>', &str[2], len-2);
return(len);
}
return(0);
}
void
net_encrypt(void)
{
#ifdef ENCRYPTION
if (encrypt_output)
ring_encrypt(&netoring, encrypt_output);
else
ring_clearto(&netoring);
#endif /* ENCRYPTION */
}
int
telnet_spin(void)
{
return(-1);
}
char *
telnet_getenv(char *val)
{
return((char *)env_getvalue((unsigned char *)val));
}
char *
telnet_gets(char *prmpt, char *result, int length, int echo)
{
extern int globalmode;
int om = globalmode;
char *res;
TerminalNewMode(-1);
if (echo) {
printf("%s", prmpt);
res = fgets(result, length, stdin);
} else if ((res = getpass(prmpt)) != NULL) {
strlcpy(result, res, length);
res = result;
}
TerminalNewMode(om);
return(res);
}
#endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */

2907
usr.bin/telnet/commands.c Normal file

File diff suppressed because it is too large Load Diff

59
usr.bin/telnet/defines.h Normal file
View File

@@ -0,0 +1,59 @@
/* $NetBSD: defines.h,v 1.8 2003/08/07 11:16:09 agc Exp $ */
/*
* Copyright (c) 1988, 1993
* The 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. 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: @(#)defines.h 8.1 (Berkeley) 6/6/93
*/
#define settimer(x) clocks.x = clocks.system++
#ifndef TN3270
#define SetIn3270()
#endif /* !defined(TN3270) */
#define NETADD(c) { *netoring.supply = (c); ring_supplied(&netoring, 1); }
#define NET2ADD(c1,c2) { NETADD((c1)); NETADD((c2)); }
#define NETBYTES() (ring_full_count(&netoring))
#define NETROOM() (ring_empty_count(&netoring))
#define TTYADD(c) if (!(SYNCHing||flushout)) { \
*ttyoring.supply = c; \
ring_supplied(&ttyoring, 1); \
}
#define TTYBYTES() (ring_full_count(&ttyoring))
#define TTYROOM() (ring_empty_count(&ttyoring))
/* Various modes */
#define MODE_LOCAL_CHARS(m) ((m)&(MODE_EDIT|MODE_TRAPSIG))
#define MODE_LOCAL_ECHO(m) ((m)&MODE_ECHO)
#define MODE_COMMAND_LINE(m) ((m)==-1)
#define CONTROL(x) ((x)&0x1f) /* CTRL(x) is not portable */

413
usr.bin/telnet/externs.h Normal file
View File

@@ -0,0 +1,413 @@
/* $NetBSD: externs.h,v 1.37 2012/01/10 23:39:11 joerg Exp $ */
/*
* Copyright (c) 1988, 1990, 1993
* The 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. 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: @(#)externs.h 8.3 (Berkeley) 5/30/95
*/
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <sys/termios.h>
#include <string.h>
#if defined(IPSEC)
#include <netipsec/ipsec.h>
#if defined(IPSEC_POLICY_IPSEC)
extern char *ipsec_policy_in;
extern char *ipsec_policy_out;
#endif
#endif
#ifndef _POSIX_VDISABLE
# ifdef sun
# include <sys/param.h> /* pick up VDISABLE definition, mayby */
# endif
# ifdef VDISABLE
# define _POSIX_VDISABLE VDISABLE
# else
# define _POSIX_VDISABLE ((cc_t)'\377')
# endif
#endif
#define SUBBUFSIZE 256
#include <sys/cdefs.h>
extern int
autologin, /* Autologin enabled */
skiprc, /* Don't process the ~/.telnetrc file */
eight, /* use eight bit mode (binary in and/or out */
family, /* address family of peer */
flushout, /* flush output */
connected, /* Are we connected to the other side? */
globalmode, /* Mode tty should be in */
In3270, /* Are we in 3270 mode? */
telnetport, /* Are we connected to the telnet port? */
localflow, /* Flow control handled locally */
restartany, /* If flow control, restart output on any character */
localchars, /* we recognize interrupt/quit */
donelclchars, /* the user has set "localchars" */
showoptions,
net, /* Network file descriptor */
tin, /* Terminal input file descriptor */
tout, /* Terminal output file descriptor */
crlf, /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
autoflush, /* flush output when interrupting? */
autosynch, /* send interrupt characters with SYNCH? */
SYNCHing, /* Is the stream in telnet SYNCH mode? */
donebinarytoggle, /* the user has put us in binary */
dontlecho, /* do we suppress local echoing right now? */
crmod,
netdata, /* Print out network data flow */
prettydump, /* Print "netdata" output in user readable format */
#ifdef TN3270
cursesdata, /* Print out curses data flow */
apitrace, /* Trace API transactions */
#endif /* defined(TN3270) */
termdata, /* Print out terminal data flow */
telnet_debug, /* Debug level */
doaddrlookup, /* do a reverse address lookup? */
clienteof; /* Client received EOF */
extern cc_t escape; /* Escape to command mode */
extern cc_t rlogin; /* Rlogin mode escape character */
#ifdef KLUDGELINEMODE
extern cc_t echoc; /* Toggle local echoing */
#endif
extern char
*prompt; /* Prompt for command. */
extern char
doopt[],
dont[],
will[],
wont[],
options[], /* All the little options */
*hostname; /* Who are we connected to? */
#ifdef ENCRYPTION
extern void (*encrypt_output)(unsigned char *, int);
extern int (*decrypt_input)(int);
#endif /* ENCRYPTION */
/*
* We keep track of each side of the option negotiation.
*/
#define MY_STATE_WILL 0x01
#define MY_WANT_STATE_WILL 0x02
#define MY_STATE_DO 0x04
#define MY_WANT_STATE_DO 0x08
/*
* Macros to check the current state of things
*/
#define my_state_is_do(opt) (options[opt]&MY_STATE_DO)
#define my_state_is_will(opt) (options[opt]&MY_STATE_WILL)
#define my_want_state_is_do(opt) (options[opt]&MY_WANT_STATE_DO)
#define my_want_state_is_will(opt) (options[opt]&MY_WANT_STATE_WILL)
#define my_state_is_dont(opt) (!my_state_is_do(opt))
#define my_state_is_wont(opt) (!my_state_is_will(opt))
#define my_want_state_is_dont(opt) (!my_want_state_is_do(opt))
#define my_want_state_is_wont(opt) (!my_want_state_is_will(opt))
#define set_my_state_do(opt) {options[opt] |= MY_STATE_DO;}
#define set_my_state_will(opt) {options[opt] |= MY_STATE_WILL;}
#define set_my_want_state_do(opt) {options[opt] |= MY_WANT_STATE_DO;}
#define set_my_want_state_will(opt) {options[opt] |= MY_WANT_STATE_WILL;}
#define set_my_state_dont(opt) {options[opt] &= ~MY_STATE_DO;}
#define set_my_state_wont(opt) {options[opt] &= ~MY_STATE_WILL;}
#define set_my_want_state_dont(opt) {options[opt] &= ~MY_WANT_STATE_DO;}
#define set_my_want_state_wont(opt) {options[opt] &= ~MY_WANT_STATE_WILL;}
/*
* Make everything symmetrical
*/
#define HIS_STATE_WILL MY_STATE_DO
#define HIS_WANT_STATE_WILL MY_WANT_STATE_DO
#define HIS_STATE_DO MY_STATE_WILL
#define HIS_WANT_STATE_DO MY_WANT_STATE_WILL
#define his_state_is_do my_state_is_will
#define his_state_is_will my_state_is_do
#define his_want_state_is_do my_want_state_is_will
#define his_want_state_is_will my_want_state_is_do
#define his_state_is_dont my_state_is_wont
#define his_state_is_wont my_state_is_dont
#define his_want_state_is_dont my_want_state_is_wont
#define his_want_state_is_wont my_want_state_is_dont
#define set_his_state_do set_my_state_will
#define set_his_state_will set_my_state_do
#define set_his_want_state_do set_my_want_state_will
#define set_his_want_state_will set_my_want_state_do
#define set_his_state_dont set_my_state_wont
#define set_his_state_wont set_my_state_dont
#define set_his_want_state_dont set_my_want_state_wont
#define set_his_want_state_wont set_my_want_state_dont
extern FILE
*NetTrace; /* Where debugging output goes */
extern char
NetTraceFile[]; /* Name of file where debugging output goes */
extern jmp_buf
toplevel; /* For error conditions. */
/* authenc.c */
int telnet_net_write(unsigned char *, int);
void net_encrypt(void);
int telnet_spin(void);
char *telnet_getenv(char *);
char *telnet_gets(char *, char *, int, int);
/* commands.c */
int send_tncmd(void (*)(int, int), const char *, char *);
void _setlist_init(void);
void set_escape_char(char *);
int set_mode(int);
int clear_mode(int);
int modehelp(int);
int suspend(int, char *[]);
int shell(int, char *[]);
int quit(int, char *[]);
int logout(int, char *[]);
int env_cmd(int, char *[]);
struct env_lst *env_find(const unsigned char *);
void env_init(void);
struct env_lst *env_define(const unsigned char *, unsigned char *);
struct env_lst *env_undefine(const unsigned char *, unsigned char *);
struct env_lst *env_export(const unsigned char *, unsigned char *);
struct env_lst *env_unexport(const unsigned char *, unsigned char *);
struct env_lst *env_send(const unsigned char *, unsigned char *);
struct env_lst *env_list(const unsigned char *, unsigned char *);
unsigned char *env_default(int, int );
unsigned char *env_getvalue(const unsigned char *);
void env_varval(const unsigned char *);
int auth_cmd(int, char *[]);
int ayt_status(void);
int encrypt_cmd(int, char *[]);
int tn(int, char *[]);
void command(int, const char *, int);
void cmdrc(const char *, const char *);
struct addrinfo;
int sourceroute(struct addrinfo *, char *, char **, int *, int*);
/* main.c */
void tninit(void);
void usage(void) __dead;
/* network.c */
void init_network(void);
int stilloob(void);
void setneturg(void);
int netflush(void);
/* sys_bsd.c */
void init_sys(void);
int TerminalWrite(char *, int);
int TerminalRead(unsigned char *, int);
int TerminalAutoFlush(void);
int TerminalSpecialChars(int);
void TerminalFlushOutput(void);
void TerminalSaveState(void);
cc_t *tcval(int);
void TerminalDefaultChars(void);
void TerminalRestoreState(void);
void TerminalNewMode(int);
void TerminalSpeeds(long *, long *);
int TerminalWindowSize(long *, long *);
int NetClose(int);
void NetNonblockingIO(int, int);
void NetSigIO(int, int);
void NetSetPgrp(int);
void sys_telnet_init(void);
int process_rings(int , int , int , int , int , int);
/* telnet.c */
void init_telnet(void);
void send_do(int, int );
void send_dont(int, int );
void send_will(int, int );
void send_wont(int, int );
void willoption(int);
void wontoption(int);
char **mklist(char *, char *);
int is_unique(char *, char **, char **);
int setup_term(char *, int, int *);
char *gettermname(void);
void lm_will(unsigned char *, int);
void lm_wont(unsigned char *, int);
void lm_do(unsigned char *, int);
void lm_dont(unsigned char *, int);
void lm_mode(unsigned char *, int, int );
void slc_init(void);
void slcstate(void);
void slc_mode_export(int);
void slc_mode_import(int);
void slc_import(int);
void slc_export(void);
void slc(unsigned char *, int);
void slc_check(void);
void slc_start_reply(void);
void slc_add_reply(unsigned int, unsigned int, cc_t);
void slc_end_reply(void);
int slc_update(void);
void env_opt(unsigned char *, int);
void env_opt_start(void);
void env_opt_start_info(void);
void env_opt_add(unsigned char *);
int opt_welldefined(const char *);
void env_opt_end(int);
int telrcv(void);
int rlogin_susp(void);
int Scheduler(int);
void telnet(const char *);
void xmitAO(void);
void xmitEL(void);
void xmitEC(void);
int dosynch(char *);
int get_status(char *);
void intp(void);
void sendbrk(void);
void sendabort(void);
void sendsusp(void);
void sendeof(void);
void sendayt(void);
void sendnaws(void);
void tel_enter_binary(int);
void tel_leave_binary(int);
/* terminal.c */
void init_terminal(void);
int ttyflush(int);
int getconnmode(void);
void setconnmode(int);
void setcommandmode(void);
/* utilities.c */
void upcase(char *);
int SetSockOpt(int, int, int, int);
void SetNetTrace(char *);
void Dump(int, unsigned char *, int);
void printoption(const char *, int, int );
void optionstatus(void);
void printsub(int, unsigned char *, int);
void EmptyTerminal(void);
void SetForExit(void);
void Exit(int) __attribute__((__noreturn__));
void ExitString(const char *, int) __attribute__((__noreturn__));
extern struct termios new_tc;
# define termEofChar new_tc.c_cc[VEOF]
# define termEraseChar new_tc.c_cc[VERASE]
# define termIntChar new_tc.c_cc[VINTR]
# define termKillChar new_tc.c_cc[VKILL]
# define termQuitChar new_tc.c_cc[VQUIT]
# define termSuspChar new_tc.c_cc[VSUSP]
# define termFlushChar new_tc.c_cc[VDISCARD]
# define termWerasChar new_tc.c_cc[VWERASE]
# define termRprntChar new_tc.c_cc[VREPRINT]
# define termLiteralNextChar new_tc.c_cc[VLNEXT]
# define termStartChar new_tc.c_cc[VSTART]
# define termStopChar new_tc.c_cc[VSTOP]
# define termForw1Char new_tc.c_cc[VEOL]
# define termForw2Char new_tc.c_cc[VEOL]
# define termAytChar new_tc.c_cc[VSTATUS]
# define termEofCharp &termEofChar
# define termEraseCharp &termEraseChar
# define termIntCharp &termIntChar
# define termKillCharp &termKillChar
# define termQuitCharp &termQuitChar
# define termSuspCharp &termSuspChar
# define termFlushCharp &termFlushChar
# define termWerasCharp &termWerasChar
# define termRprntCharp &termRprntChar
# define termLiteralNextCharp &termLiteralNextChar
# define termStartCharp &termStartChar
# define termStopCharp &termStopChar
# define termForw1Charp &termForw1Char
# define termForw2Charp &termForw2Char
# define termAytCharp &termAytChar
/* Tn3270 section */
#if defined(TN3270)
extern int
HaveInput, /* Whether an asynchronous I/O indication came in */
noasynchtty, /* Don't do signals on I/O (SIGURG, SIGIO) */
noasynchnet, /* Don't do signals on I/O (SIGURG, SIGIO) */
sigiocount, /* Count of SIGIO receptions */
shell_active; /* Subshell is active */
extern char
*Ibackp, /* Oldest byte of 3270 data */
Ibuf[], /* 3270 buffer */
*Ifrontp, /* Where next 3270 byte goes */
tline[200],
*transcom; /* Transparent command */
/* tn3270.c */
void init_3270(void);
int DataToNetwork(char *, int, int);
void inputAvailable(int);
void outputPurge(void);
int DataToTerminal(char *, int);
int Push3270(void);
void Finish3270(void);
void StringToTerminal(char *);
int _putchar(int);
void SetIn3270(void);
int tn3270_ttype(void);
int settranscom(int, char *[]);
int shell_continue(void);
int DataFromTerminal(char *, int);
int DataFromNetwork(char *, int, int);
void ConnectScreen(void);
int DoTerminalOutput(void);
#endif /* defined(TN3270) */

43
usr.bin/telnet/general.h Normal file
View File

@@ -0,0 +1,43 @@
/* $NetBSD: general.h,v 1.6 2003/08/07 11:16:09 agc Exp $ */
/*
* Copyright (c) 1988, 1993
* The 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. 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: @(#)general.h 8.1 (Berkeley) 6/6/93
*/
/*
* Some general definitions.
*/
#define numberof(x) (sizeof x/sizeof x[0])
#define highestof(x) (numberof(x)-1)
#define ClearElement(x) memset((char *)&x, 0, sizeof x)
#define ClearArray(x) memset((char *)x, 0, sizeof x)

361
usr.bin/telnet/main.c Normal file
View File

@@ -0,0 +1,361 @@
/* $NetBSD: main.c,v 1.29 2012/03/20 20:34:59 matt Exp $ */
/*
* Copyright (c) 1988, 1990, 1993
* The 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. 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.
*/
#include <sys/cdefs.h>
#ifndef lint
__COPYRIGHT("@(#) Copyright (c) 1988, 1990, 1993\
The Regents of the University of California. All rights reserved.");
#endif /* not lint */
#ifndef lint
#if 0
static char sccsid[] = "@(#)main.c 8.3 (Berkeley) 5/30/95";
#else
__RCSID("$NetBSD: main.c,v 1.29 2012/03/20 20:34:59 matt Exp $");
#endif
#endif /* not lint */
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include "ring.h"
#include "externs.h"
#include "defines.h"
#ifdef AUTHENTICATION
#include <libtelnet/auth.h>
#endif
#ifdef ENCRYPTION
#include <libtelnet/encrypt.h>
#endif
/* These values need to be the same as defined in libtelnet/kerberos5.c */
/* Either define them in both places, or put in some common header file. */
#define OPTS_FORWARD_CREDS 0x00000002
#define OPTS_FORWARDABLE_CREDS 0x00000001
#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
char *ipsec_policy_in = NULL;
char *ipsec_policy_out = NULL;
#endif
int family = AF_UNSPEC;
int main(int, char *[]);
/*
* Initialize variables.
*/
void
tninit(void)
{
init_terminal();
init_network();
init_telnet();
init_sys();
#ifdef TN3270
init_3270();
#endif
}
void
usage(void)
{
fprintf(stderr, "usage: %s %s%s%s%s\n",
prompt,
#ifdef AUTHENTICATION
"[-4] [-6] [-8] [-E] [-K] [-L] [-N] [-S tos] [-X atype] [-a] [-c]",
"\n\t[-d] [-e char] [-k realm] [-l user] [-f/-F] [-n tracefile] ",
#else
"[-4] [-6] [-8] [-E] [-L] [-N] [-S tos] [-a] [-c] [-d] [-e char]",
"\n\t[-l user] [-n tracefile] ",
#endif
#ifdef TN3270
# ifdef AUTHENTICATION
"[-noasynch] [-noasynctty]\n\t[-noasyncnet] [-r] [-t transcom] ",
# else
"[-noasynch] [-noasynctty] [-noasyncnet] [-r]\n\t[-t transcom]",
# endif
#else
"[-r] ",
#endif
#ifdef ENCRYPTION
"[-x] "
#endif
#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
"\n\t[-P policy] [host-name [port]]"
#else
"\n\t[host-name [port]]"
#endif
);
exit(1);
}
/*
* main. Parse arguments, invoke the protocol or command parser.
*/
int
main(int argc, char *argv[])
{
extern char *optarg;
extern int optind;
int ch;
char *user;
#ifdef FORWARD
extern int forward_flags;
#endif /* FORWARD */
tninit(); /* Clear out things */
TerminalSaveState();
if ((prompt = strrchr(argv[0], '/')) != NULL)
++prompt;
else
prompt = argv[0];
user = NULL;
rlogin = (strncmp(prompt, "rlog", 4) == 0) ? '~' : _POSIX_VDISABLE;
autologin = -1;
#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
#define IPSECOPT "P:"
#else
#define IPSECOPT
#endif
while ((ch = getopt(argc, argv, "468EKLNS:X:acde:fFk:l:n:rt:x"
IPSECOPT)) != -1) {
#undef IPSECOPT
switch(ch) {
case '4':
family = AF_INET;
break;
case '6':
family = AF_INET6;
break;
case '8':
eight = 3; /* binary output and input */
break;
case 'E':
rlogin = escape = _POSIX_VDISABLE;
break;
case 'K':
#ifdef AUTHENTICATION
autologin = 0;
#endif
break;
case 'L':
eight |= 2; /* binary output only */
break;
case 'N':
doaddrlookup = 0;
break;
case 'S':
{
fprintf(stderr,
"%s: Warning: -S ignored, no parsetos() support.\n",
prompt);
}
break;
case 'X':
#ifdef AUTHENTICATION
auth_disable_name(optarg);
#endif
break;
case 'a':
autologin = 1;
break;
case 'c':
skiprc = 1;
break;
case 'd':
telnet_debug = 1;
break;
case 'e':
set_escape_char(optarg);
break;
case 'f':
#if defined(AUTHENTICATION) && defined(KRB5) && defined(FORWARD)
if (forward_flags & OPTS_FORWARD_CREDS) {
fprintf(stderr,
"%s: Only one of -f and -F allowed.\n",
prompt);
usage();
}
forward_flags |= OPTS_FORWARD_CREDS;
#else
fprintf(stderr,
"%s: Warning: -f ignored, no Kerberos V5 support.\n",
prompt);
#endif
break;
case 'F':
#if defined(AUTHENTICATION) && defined(KRB5) && defined(FORWARD)
if (forward_flags & OPTS_FORWARD_CREDS) {
fprintf(stderr,
"%s: Only one of -f and -F allowed.\n",
prompt);
usage();
}
forward_flags |= OPTS_FORWARD_CREDS;
forward_flags |= OPTS_FORWARDABLE_CREDS;
#else
fprintf(stderr,
"%s: Warning: -F ignored, no Kerberos V5 support.\n",
prompt);
#endif
break;
case 'k':
fprintf(stderr,
"%s: Warning: -k ignored, no Kerberos V4 support.\n",
prompt);
break;
case 'l':
if(autologin == 0) {
autologin = -1;
}
user = optarg;
break;
case 'n':
#ifdef TN3270
/* distinguish between "-n oasynch" and "-noasynch" */
if (argv[optind - 1][0] == '-' && argv[optind - 1][1]
== 'n' && argv[optind - 1][2] == 'o') {
if (!strcmp(optarg, "oasynch")) {
noasynchtty = 1;
noasynchnet = 1;
} else if (!strcmp(optarg, "oasynchtty"))
noasynchtty = 1;
else if (!strcmp(optarg, "oasynchnet"))
noasynchnet = 1;
} else
#endif /* defined(TN3270) */
SetNetTrace(optarg);
break;
case 'r':
rlogin = '~';
break;
case 't':
#ifdef TN3270
(void)strlcpy(tline, optarg, sizeof(tline));
transcom = tline;
#else
fprintf(stderr,
"%s: Warning: -t ignored, no TN3270 support.\n",
prompt);
#endif
break;
case 'x':
#ifdef ENCRYPTION
encrypt_auto(1);
decrypt_auto(1);
#else /* ENCRYPTION */
fprintf(stderr,
"%s: Warning: -x ignored, no ENCRYPT support.\n",
prompt);
#endif /* ENCRYPTION */
break;
#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
case 'P':
if (!strncmp("in", optarg, 2))
ipsec_policy_in = strdup(optarg);
else if (!strncmp("out", optarg, 3))
ipsec_policy_out = strdup(optarg);
else
usage();
break;
#endif
case '?':
default:
usage();
/* NOTREACHED */
}
}
if (autologin == -1) { /* esc@magic.fi; force */
#if defined(AUTHENTICATION)
autologin = 1;
#endif
#if defined(ENCRYPTION)
encrypt_auto(1);
decrypt_auto(1);
#endif
}
if (autologin == -1)
autologin = (rlogin == _POSIX_VDISABLE) ? 0 : 1;
argc -= optind;
argv += optind;
if (argc) {
static char ml[] = "-l";
char *args[7];
char ** volatile argp; /* avoid longjmp clobbering */
argp = args;
if (argc > 2)
usage();
*argp++ = prompt;
if (user) {
*argp++ = ml;
*argp++ = user;
}
*argp++ = argv[0]; /* host */
if (argc > 1)
*argp++ = argv[1]; /* port */
*argp = 0;
if (setjmp(toplevel) != 0)
Exit(0);
if (tn(argp - args, args) == 1)
return (0);
else
return (1);
}
(void)setjmp(toplevel);
for (;;) {
#ifdef TN3270
if (shell_active)
shell_continue();
else
#endif
command(1, 0, 0);
}
}

179
usr.bin/telnet/network.c Normal file
View File

@@ -0,0 +1,179 @@
/* $NetBSD: network.c,v 1.17 2004/03/20 23:26:05 heas Exp $ */
/*
* Copyright (c) 1988, 1993
* The 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. 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.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)network.c 8.2 (Berkeley) 12/15/93";
#else
__RCSID("$NetBSD: network.c,v 1.17 2004/03/20 23:26:05 heas Exp $");
#endif
#endif /* not lint */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <errno.h>
#include <unistd.h>
#include <poll.h>
#include <arpa/telnet.h>
#include "ring.h"
#include "defines.h"
#include "externs.h"
Ring netoring, netiring;
unsigned char netobuf[2*BUFSIZ], netibuf[BUFSIZ];
/*
* Initialize internal network data structures.
*/
void
init_network(void)
{
if (ring_init(&netoring, netobuf, sizeof netobuf) != 1) {
exit(1);
}
if (ring_init(&netiring, netibuf, sizeof netibuf) != 1) {
exit(1);
}
NetTrace = stdout;
}
/*
* Check to see if any out-of-band data exists on a socket (for
* Telnet "synch" processing).
*/
int
stilloob(void)
{
struct pollfd set[1];
int value;
set[0].fd = net;
set[0].events = POLLPRI;
do {
value = poll(set, 1, 0);
} while ((value == -1) && (errno == EINTR));
if (value < 0) {
perror("poll");
(void) quit(0, NULL);
/* NOTREACHED */
}
if (set[0].revents & POLLPRI) {
return 1;
} else {
return 0;
}
}
/*
* setneturg()
*
* Sets "neturg" to the current location.
*/
void
setneturg(void)
{
ring_mark(&netoring);
}
/*
* netflush
* Send as much data as possible to the network,
* handling requests for urgent data.
*
* The return value indicates whether we did any
* useful work.
*/
int
netflush(void)
{
int n, n1;
#ifdef ENCRYPTION
if (encrypt_output)
ring_encrypt(&netoring, encrypt_output);
#endif /* ENCRYPTION */
if ((n1 = n = ring_full_consecutive(&netoring)) > 0) {
if (!ring_at_mark(&netoring)) {
n = send(net, (char *)netoring.consume, n, 0); /* normal write */
} else {
/*
* 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).
*/
n = send(net, (char *)netoring.consume, 1, MSG_OOB);/* URGENT data */
}
}
if (n < 0) {
if (errno != ENOBUFS && errno != EWOULDBLOCK) {
setcommandmode();
perror(hostname);
(void)NetClose(net);
ring_clear_mark(&netoring);
ExitString("Connection closed by foreign host.\n", 1);
/*NOTREACHED*/
}
n = 0;
}
if (netdata && n) {
Dump('>', netoring.consume, n);
}
if (n) {
ring_consumed(&netoring, n);
/*
* If we sent all, and more to send, then recurse to pick
* up the other half.
*/
if ((n1 == n) && ring_full_consecutive(&netoring)) {
(void) netflush();
}
return 1;
} else {
return 0;
}
}

339
usr.bin/telnet/ring.c Normal file
View File

@@ -0,0 +1,339 @@
/* $NetBSD: ring.c,v 1.13 2003/08/07 11:16:10 agc Exp $ */
/*
* Copyright (c) 1988, 1993
* The 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. 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.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)ring.c 8.2 (Berkeley) 5/30/95";
#else
__RCSID("$NetBSD: ring.c,v 1.13 2003/08/07 11:16:10 agc Exp $");
#endif
#endif /* not lint */
/*
* This defines a structure for a ring buffer.
*
* The circular buffer has two parts:
*(((
* full: [consume, supply)
* empty: [supply, consume)
*]]]
*
*/
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include "ring.h"
#include "general.h"
/* Internal macros */
#if !defined(MIN)
#define MIN(a,b) (((a)<(b))? (a):(b))
#endif /* !defined(MIN) */
#define ring_subtract(d,a,b) (((a)-(b) >= 0)? \
(a)-(b): (((a)-(b))+(d)->size))
#define ring_increment(d,a,c) (((a)+(c) < (d)->top)? \
(a)+(c) : (((a)+(c))-(d)->size))
#define ring_decrement(d,a,c) (((a)-(c) >= (d)->bottom)? \
(a)-(c) : (((a)-(c))-(d)->size))
/*
* The following is a clock, used to determine full, empty, etc.
*
* There is some trickiness here. Since the ring buffers are initialized
* to ZERO on allocation, we need to make sure, when interpreting the
* clock, that when the times are EQUAL, then the buffer is FULL.
*/
static u_long ring_clock = 0;
#define ring_empty(d) (((d)->consume == (d)->supply) && \
((d)->consumetime >= (d)->supplytime))
#define ring_full(d) (((d)->supply == (d)->consume) && \
((d)->supplytime > (d)->consumetime))
/* Buffer state transition routines */
int
ring_init(Ring *ring, unsigned char *buffer, int count)
{
memset((char *)ring, 0, sizeof *ring);
ring->size = count;
ring->supply = ring->consume = ring->bottom = buffer;
ring->top = ring->bottom+ring->size;
#ifdef ENCRYPTION
ring->clearto = 0;
#endif /* ENCRYPTION */
return 1;
}
/* Mark routines */
/*
* Mark the most recently supplied byte.
*/
void
ring_mark(Ring *ring)
{
ring->mark = ring_decrement(ring, ring->supply, 1);
}
/*
* Is the ring pointing to the mark?
*/
int
ring_at_mark(Ring *ring)
{
if (ring->mark == ring->consume) {
return 1;
} else {
return 0;
}
}
/*
* Clear any mark set on the ring.
*/
void
ring_clear_mark(Ring *ring)
{
ring->mark = 0;
}
/*
* Add characters from current segment to ring buffer.
*/
void
ring_supplied(Ring *ring, int count)
{
ring->supply = ring_increment(ring, ring->supply, count);
ring->supplytime = ++ring_clock;
}
/*
* We have just consumed "c" bytes.
*/
void
ring_consumed(Ring *ring, int count)
{
if (count == 0) /* don't update anything */
return;
if (ring->mark &&
(ring_subtract(ring, ring->mark, ring->consume) < count)) {
ring->mark = 0;
}
#ifdef ENCRYPTION
if (ring->consume < ring->clearto &&
ring->clearto <= ring->consume + count)
ring->clearto = 0;
else if (ring->consume + count > ring->top &&
ring->bottom <= ring->clearto &&
ring->bottom + ((ring->consume + count) - ring->top))
ring->clearto = 0;
#endif /* ENCRYPTION */
ring->consume = ring_increment(ring, ring->consume, count);
ring->consumetime = ++ring_clock;
/*
* Try to encourage "ring_empty_consecutive()" to be large.
*/
if (ring_empty(ring)) {
ring->consume = ring->supply = ring->bottom;
}
}
/* Buffer state query routines */
/* Number of bytes that may be supplied */
int
ring_empty_count(Ring *ring)
{
if (ring_empty(ring)) { /* if empty */
return ring->size;
} else {
return ring_subtract(ring, ring->consume, ring->supply);
}
}
/* number of CONSECUTIVE bytes that may be supplied */
int
ring_empty_consecutive(Ring *ring)
{
if ((ring->consume < ring->supply) || ring_empty(ring)) {
/*
* if consume is "below" supply, or empty, then
* return distance to the top
*/
return ring_subtract(ring, ring->top, ring->supply);
} else {
/*
* else, return what we may.
*/
return ring_subtract(ring, ring->consume, ring->supply);
}
}
/* Return the number of bytes that are available for consuming
* (but don't give more than enough to get to cross over set mark)
*/
int
ring_full_count(Ring *ring)
{
if ((ring->mark == 0) || (ring->mark == ring->consume)) {
if (ring_full(ring)) {
return ring->size; /* nothing consumed, but full */
} else {
return ring_subtract(ring, ring->supply, ring->consume);
}
} else {
return ring_subtract(ring, ring->mark, ring->consume);
}
}
/*
* Return the number of CONSECUTIVE bytes available for consuming.
* However, don't return more than enough to cross over set mark.
*/
int
ring_full_consecutive(Ring *ring)
{
if ((ring->mark == 0) || (ring->mark == ring->consume)) {
if ((ring->supply < ring->consume) || ring_full(ring)) {
return ring_subtract(ring, ring->top, ring->consume);
} else {
return ring_subtract(ring, ring->supply, ring->consume);
}
} else {
if (ring->mark < ring->consume) {
return ring_subtract(ring, ring->top, ring->consume);
} else { /* Else, distance to mark */
return ring_subtract(ring, ring->mark, ring->consume);
}
}
}
/*
* Move data into the "supply" portion of of the ring buffer.
*/
void
ring_supply_data(Ring *ring, unsigned char *buffer, int count)
{
int i;
while (count) {
i = MIN(count, ring_empty_consecutive(ring));
memmove(ring->supply, buffer, i);
ring_supplied(ring, i);
count -= i;
buffer += i;
}
}
#ifdef notdef
/*
* Move data from the "consume" portion of the ring buffer
*/
void
ring_consume_data(Ring *ring, unsigned char *buffer, int count)
{
int i;
while (count) {
i = MIN(count, ring_full_consecutive(ring));
memmove(buffer, ring->consume, i);
ring_consumed(ring, i);
count -= i;
buffer += i;
}
}
#endif
#ifdef ENCRYPTION
void
ring_encrypt(Ring *ring, void (*encryptor)(unsigned char *, int))
{
unsigned char *s, *c;
if (ring_empty(ring) || ring->clearto == ring->supply)
return;
if (!(c = ring->clearto))
c = ring->consume;
s = ring->supply;
if (s <= c) {
(*encryptor)(c, ring->top - c);
(*encryptor)(ring->bottom, s - ring->bottom);
} else
(*encryptor)(c, s - c);
ring->clearto = ring->supply;
}
void
ring_clearto(Ring *ring)
{
if (!ring_empty(ring))
ring->clearto = ring->supply;
else
ring->clearto = 0;
}
#endif /* ENCRYPTION */

104
usr.bin/telnet/ring.h Normal file
View File

@@ -0,0 +1,104 @@
/* $NetBSD: ring.h,v 1.10 2003/08/07 11:16:10 agc Exp $ */
/*
* Copyright (c) 1988, 1993
* The 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. 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: @(#)ring.h 8.1 (Berkeley) 6/6/93
*/
#include <sys/cdefs.h>
/*
* This defines a structure for a ring buffer.
*
* The circular buffer has two parts:
*(((
* full: [consume, supply)
* empty: [supply, consume)
*]]]
*
*/
typedef struct {
unsigned char *consume, /* where data comes out of */
*supply, /* where data comes in to */
*bottom, /* lowest address in buffer */
*top, /* highest address+1 in buffer */
*mark; /* marker (user defined) */
#ifdef ENCRYPTION
unsigned char *clearto; /* Data to this point is clear text */
unsigned char *encryyptedto; /* Data is encrypted to here */
#endif /* ENCRYPTION */
int size; /* size in bytes of buffer */
u_long consumetime, /* help us keep straight full, empty, etc. */
supplytime;
} Ring;
/* Ring buffer structures which are shared */
extern Ring
netoring,
netiring,
ttyoring,
ttyiring;
/* Here are some functions and macros to deal with the ring buffer */
/* Initialization routine */
extern int
ring_init(Ring *ring, unsigned char *buffer, int count);
/* Data movement routines */
extern void
ring_supply_data(Ring *ring, unsigned char *buffer, int count);
#ifdef notdef
extern void
ring_consume_data(Ring *ring, unsigned char *buffer, int count);
#endif
/* Buffer state transition routines */
extern void
ring_supplied(Ring *ring, int count),
ring_consumed(Ring *ring, int count);
/* Buffer state query routines */
extern int
ring_empty_count(Ring *ring),
ring_empty_consecutive(Ring *ring),
ring_full_count(Ring *ring),
ring_full_consecutive(Ring *ring),
ring_at_mark(Ring *ring);
#ifdef ENCRYPTION
extern void
ring_encrypt(Ring *ring, void (*func)(unsigned char *, int)),
ring_clearto(Ring *ring);
#endif /* ENCRYPTION */
extern void
ring_clear_mark(Ring *ring),
ring_mark(Ring *ring);

739
usr.bin/telnet/sys_bsd.c Normal file
View File

@@ -0,0 +1,739 @@
/* $NetBSD: sys_bsd.c,v 1.33 2012/01/09 16:08:55 christos Exp $ */
/*
* Copyright (c) 1988, 1990, 1993
* The 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. 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.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
from: static char sccsid[] = "@(#)sys_bsd.c 8.4 (Berkeley) 5/30/95";
#else
__RCSID("$NetBSD: sys_bsd.c,v 1.33 2012/01/09 16:08:55 christos Exp $");
#endif
#endif /* not lint */
/*
* The following routines try to encapsulate what is system dependent
* (at least between 4.x and dos) which is used in telnet.c.
*/
#include <fcntl.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <poll.h>
#include <arpa/telnet.h>
#include "ring.h"
#include "defines.h"
#include "externs.h"
#include "types.h"
#define SIG_FUNC_RET void
SIG_FUNC_RET susp(int);
SIG_FUNC_RET ayt(int);
SIG_FUNC_RET intr(int);
SIG_FUNC_RET intr2(int);
SIG_FUNC_RET sendwin(int);
int
tout, /* Output file descriptor */
tin, /* Input file descriptor */
net;
struct termios old_tc = { .c_iflag = 0 };
extern struct termios new_tc;
# ifndef TCSANOW
# ifdef TCSETS
# define TCSANOW TCSETS
# define TCSADRAIN TCSETSW
# define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
# else
# ifdef TCSETA
# define TCSANOW TCSETA
# define TCSADRAIN TCSETAW
# define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
# else
# define TCSANOW TIOCSETA
# define TCSADRAIN TIOCSETAW
# define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
# endif
# endif
# define tcsetattr(f, a, t) ioctl(f, a, (char *)t)
# define cfgetospeed(ptr) ((ptr)->c_cflag&CBAUD)
# ifdef CIBAUD
# define cfgetispeed(ptr) (((ptr)->c_cflag&CIBAUD) >> IBSHIFT)
# else
# define cfgetispeed(ptr) cfgetospeed(ptr)
# endif
# endif /* TCSANOW */
void
init_sys(void)
{
tout = fileno(stdout);
tin = fileno(stdin);
errno = 0;
}
int
TerminalWrite(char *buf, int n)
{
return write(tout, buf, n);
}
int
TerminalRead(unsigned char *buf, int n)
{
return read(tin, buf, n);
}
/*
*
*/
int
TerminalAutoFlush(void)
{
return 1;
}
#ifdef KLUDGELINEMODE
extern int kludgelinemode;
#endif
/*
* TerminalSpecialChars()
*
* Look at an input character to see if it is a special character
* and decide what to do.
*
* Output:
*
* 0 Don't add this character.
* 1 Do add this character
*/
int
TerminalSpecialChars(int c)
{
if (c == termIntChar) {
intp();
return 0;
} else if (c == termQuitChar) {
#ifdef KLUDGELINEMODE
if (kludgelinemode)
sendbrk();
else
#endif
sendabort();
return 0;
} else if (c == termEofChar) {
if (my_want_state_is_will(TELOPT_LINEMODE)) {
sendeof();
return 0;
}
return 1;
} else if (c == termSuspChar) {
sendsusp();
return(0);
} else if (c == termFlushChar) {
xmitAO(); /* Transmit Abort Output */
return 0;
} else if (!MODE_LOCAL_CHARS(globalmode)) {
if (c == termKillChar) {
xmitEL();
return 0;
} else if (c == termEraseChar) {
xmitEC(); /* Transmit Erase Character */
return 0;
}
}
return 1;
}
/*
* Flush output to the terminal
*/
void
TerminalFlushOutput(void)
{
int com = 0;
(void) ioctl(fileno(stdout), TIOCFLUSH, &com);
}
void
TerminalSaveState(void)
{
tcgetattr(0, &old_tc);
new_tc = old_tc;
}
cc_t *
tcval(int func)
{
switch(func) {
case SLC_IP: return(&termIntChar);
case SLC_ABORT: return(&termQuitChar);
case SLC_EOF: return(&termEofChar);
case SLC_EC: return(&termEraseChar);
case SLC_EL: return(&termKillChar);
case SLC_XON: return(&termStartChar);
case SLC_XOFF: return(&termStopChar);
case SLC_FORW1: return(&termForw1Char);
case SLC_FORW2: return(&termForw2Char);
case SLC_AO: return(&termFlushChar);
case SLC_SUSP: return(&termSuspChar);
case SLC_EW: return(&termWerasChar);
case SLC_RP: return(&termRprntChar);
case SLC_LNEXT: return(&termLiteralNextChar);
case SLC_AYT: return(&termAytChar);
case SLC_SYNCH:
case SLC_BRK:
case SLC_EOR:
default:
return((cc_t *)0);
}
}
void
TerminalDefaultChars(void)
{
memmove(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc));
}
#ifdef notdef
void
TerminalRestoreState(void)
{
}
#endif
/*
* TerminalNewMode - set up terminal to a specific mode.
* MODE_ECHO: do local terminal echo
* MODE_FLOW: do local flow control
* MODE_TRAPSIG: do local mapping to TELNET IAC sequences
* MODE_EDIT: do local line editing
*
* Command mode:
* MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG
* local echo
* local editing
* local xon/xoff
* local signal mapping
*
* Linemode:
* local/no editing
* Both Linemode and Single Character mode:
* local/remote echo
* local/no xon/xoff
* local/no signal mapping
*/
void
TerminalNewMode(int f)
{
static int prevmode = 0;
struct termios tmp_tc;
int onoff;
int old;
cc_t esc;
globalmode = f&~MODE_FORCE;
if (prevmode == f)
return;
/*
* Write any outstanding data before switching modes
* ttyflush() returns 0 only when there is no more data
* left to write out, it returns -1 if it couldn't do
* anything at all, otherwise it returns 1 + the number
* of characters left to write.
#ifndef USE_TERMIO
* We would really like to ask the kernel to wait for the output
* to drain, like we can do with the TCSADRAIN, but we don't have
* that option. The only ioctl that waits for the output to
* drain, TIOCSETP, also flushes the input queue, which is NOT
* what we want (TIOCSETP is like TCSADFLUSH).
#endif
*/
old = ttyflush(SYNCHing|flushout);
if (old < 0 || old > 1) {
tcgetattr(tin, &tmp_tc);
do {
/*
* Wait for data to drain, then flush again.
*/
tcsetattr(tin, TCSADRAIN, &tmp_tc);
old = ttyflush(SYNCHing|flushout);
} while (old < 0 || old > 1);
}
old = prevmode;
prevmode = f&~MODE_FORCE;
tmp_tc = new_tc;
if (f&MODE_ECHO) {
tmp_tc.c_lflag |= ECHO;
tmp_tc.c_oflag |= ONLCR;
if (crlf)
tmp_tc.c_iflag |= ICRNL;
} else {
tmp_tc.c_lflag &= ~ECHO;
tmp_tc.c_oflag &= ~ONLCR;
# ifdef notdef
if (crlf)
tmp_tc.c_iflag &= ~ICRNL;
# endif
}
if ((f&MODE_FLOW) == 0) {
tmp_tc.c_iflag &= ~(IXOFF|IXON); /* Leave the IXANY bit alone */
} else {
if (restartany < 0) {
tmp_tc.c_iflag |= IXOFF|IXON; /* Leave the IXANY bit alone */
} else if (restartany > 0) {
tmp_tc.c_iflag |= IXOFF|IXON|IXANY;
} else {
tmp_tc.c_iflag |= IXOFF|IXON;
tmp_tc.c_iflag &= ~IXANY;
}
}
if ((f&MODE_TRAPSIG) == 0) {
tmp_tc.c_lflag &= ~ISIG;
localchars = 0;
} else {
tmp_tc.c_lflag |= ISIG;
localchars = 1;
}
if (f&MODE_EDIT) {
tmp_tc.c_lflag |= ICANON;
} else {
tmp_tc.c_lflag &= ~ICANON;
tmp_tc.c_iflag &= ~ICRNL;
tmp_tc.c_cc[VMIN] = 1;
tmp_tc.c_cc[VTIME] = 0;
}
if ((f&(MODE_EDIT|MODE_TRAPSIG)) == 0) {
tmp_tc.c_lflag &= ~IEXTEN;
}
if (f&MODE_SOFT_TAB) {
# ifdef OXTABS
tmp_tc.c_oflag |= OXTABS;
# endif
# ifdef TABDLY
tmp_tc.c_oflag &= ~TABDLY;
tmp_tc.c_oflag |= TAB3;
# endif
} else {
# ifdef OXTABS
tmp_tc.c_oflag &= ~OXTABS;
# endif
# ifdef TABDLY
tmp_tc.c_oflag &= ~TABDLY;
# endif
}
if (f&MODE_LIT_ECHO) {
# ifdef ECHOCTL
tmp_tc.c_lflag &= ~ECHOCTL;
# endif
} else {
# ifdef ECHOCTL
tmp_tc.c_lflag |= ECHOCTL;
# endif
}
if (f == -1) {
onoff = 0;
} else {
if (f & MODE_INBIN)
tmp_tc.c_iflag &= ~ISTRIP;
else
tmp_tc.c_iflag |= ISTRIP;
if (f & MODE_OUTBIN) {
tmp_tc.c_cflag &= ~(CSIZE|PARENB);
tmp_tc.c_cflag |= CS8;
tmp_tc.c_oflag &= ~OPOST;
} else {
tmp_tc.c_cflag &= ~(CSIZE|PARENB);
tmp_tc.c_cflag |= old_tc.c_cflag & (CSIZE|PARENB);
tmp_tc.c_oflag |= OPOST;
}
onoff = 1;
}
if (f != -1) {
(void) signal(SIGTSTP, susp);
(void) signal(SIGINFO, ayt);
#if defined(USE_TERMIO) && defined(NOKERNINFO)
tmp_tc.c_lflag |= NOKERNINFO;
#endif
/*
* We don't want to process ^Y here. It's just another
* character that we'll pass on to the back end. It has
* to process it because it will be processed when the
* user attempts to read it, not when we send it.
*/
# ifdef VDSUSP
tmp_tc.c_cc[VDSUSP] = (cc_t)(_POSIX_VDISABLE);
# endif
/*
* If the VEOL character is already set, then use VEOL2,
* otherwise use VEOL.
*/
esc = (rlogin != _POSIX_VDISABLE) ? rlogin : escape;
if ((tmp_tc.c_cc[VEOL] != esc)
# ifdef VEOL2
&& (tmp_tc.c_cc[VEOL2] != esc)
# endif
) {
if (tmp_tc.c_cc[VEOL] == (cc_t)(_POSIX_VDISABLE))
tmp_tc.c_cc[VEOL] = esc;
# ifdef VEOL2
else if (tmp_tc.c_cc[VEOL2] == (cc_t)(_POSIX_VDISABLE))
tmp_tc.c_cc[VEOL2] = esc;
# endif
}
} else {
(void) signal(SIGINFO, (void (*)(int)) ayt_status);
(void) signal(SIGTSTP, SIG_DFL);
(void) sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
tmp_tc = old_tc;
}
if (tcsetattr(tin, TCSADRAIN, &tmp_tc) < 0)
tcsetattr(tin, TCSANOW, &tmp_tc);
ioctl(tin, FIONBIO, (char *)&onoff);
ioctl(tout, FIONBIO, (char *)&onoff);
#if defined(TN3270)
if (noasynchtty == 0) {
ioctl(tin, FIOASYNC, (char *)&onoff);
}
#endif /* defined(TN3270) */
}
void
TerminalSpeeds(long *ispeed, long *ospeed)
{
long in, out;
out = cfgetospeed(&old_tc);
in = cfgetispeed(&old_tc);
if (in == 0)
in = out;
*ispeed = in;
*ospeed = out;
}
int
TerminalWindowSize(long *rows, long *cols)
{
struct winsize ws;
if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) >= 0) {
*rows = ws.ws_row;
*cols = ws.ws_col;
return 1;
}
return 0;
}
int
NetClose(int fd)
{
return close(fd);
}
void
NetNonblockingIO(int fd, int onoff)
{
ioctl(fd, FIONBIO, (char *)&onoff);
}
#ifdef TN3270
void
NetSigIO(int fd, int onoff)
{
ioctl(fd, FIOASYNC, (char *)&onoff); /* hear about input */
}
void
NetSetPgrp(int fd)
{
int myPid;
myPid = getpid();
fcntl(fd, F_SETOWN, myPid);
}
#endif /*defined(TN3270)*/
/*
* Various signal handling routines.
*/
/* ARGSUSED */
SIG_FUNC_RET
intr(int sig)
{
if (localchars) {
intp();
return;
}
setcommandmode();
longjmp(toplevel, -1);
}
/* ARGSUSED */
SIG_FUNC_RET
intr2(int sig)
{
if (localchars) {
#ifdef KLUDGELINEMODE
if (kludgelinemode)
sendbrk();
else
#endif
sendabort();
return;
}
}
/* ARGSUSED */
SIG_FUNC_RET
susp(int sig)
{
if ((rlogin != _POSIX_VDISABLE) && rlogin_susp())
return;
if (localchars)
sendsusp();
}
/* ARGSUSED */
SIG_FUNC_RET
sendwin(int sig)
{
if (connected) {
sendnaws();
}
}
/* ARGSUSED */
SIG_FUNC_RET
ayt(int sig)
{
if (connected)
sendayt();
else
ayt_status();
}
void
sys_telnet_init(void)
{
(void) signal(SIGINT, intr);
(void) signal(SIGQUIT, intr2);
(void) signal(SIGPIPE, SIG_IGN);
(void) signal(SIGWINCH, sendwin);
(void) signal(SIGTSTP, susp);
(void) signal(SIGINFO, ayt);
setconnmode(0);
NetNonblockingIO(net, 1);
#ifdef TN3270
if (noasynchnet == 0) { /* DBX can't handle! */
NetSigIO(net, 1);
NetSetPgrp(net);
}
#endif /* defined(TN3270) */
if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) {
perror("SetSockOpt");
}
}
/*
* Process rings -
*
* This routine tries to fill up/empty our various rings.
*
* The parameter specifies whether this is a poll operation,
* or a block-until-something-happens operation.
*
* The return value is 1 if something happened, 0 if not, < 0 if an
* error occurred.
*/
int
process_rings(int netin, int netout, int netex, int ttyin, int ttyout,
int dopoll) /* If 0, then block until something to do */
{
struct pollfd set[3];
int c;
/* One wants to be a bit careful about setting returnValue
* to one, since a one implies we did some useful work,
* and therefore probably won't be called to block next
* time (TN3270 mode only).
*/
int returnValue = 0;
set[0].fd = net;
set[0].events = (netout ? POLLOUT : 0) | (netin ? POLLIN : 0) |
(netex ? POLLPRI : 0);
set[1].fd = tout;
set[1].events = ttyout ? POLLOUT : 0;
set[2].fd = tin;
set[2].events = ttyin ? POLLIN : 0;
if ((c = poll(set, 3, dopoll ? 0 : INFTIM)) < 0) {
if (c == -1) {
/*
* we can get EINTR if we are in line mode,
* and the user does an escape (TSTP), or
* some other signal generator.
*/
if (errno == EINTR) {
return 0;
}
#ifdef TN3270
/*
* we can get EBADF if we were in transparent
* mode, and the transcom process died.
*/
if (errno == EBADF)
return 0;
#endif /* defined(TN3270) */
/* I don't like this, does it ever happen? */
printf("sleep(5) from telnet, after poll\r\n");
sleep(5);
}
return 0;
}
/*
* Any urgent data?
*/
if (set[0].revents & POLLPRI) {
SYNCHing = 1;
(void) ttyflush(1); /* flush already enqueued data */
}
/*
* Something to read from the network...
*/
if (set[0].revents & POLLIN) {
int canread;
canread = ring_empty_consecutive(&netiring);
c = recv(net, (char *)netiring.supply, canread, 0);
if (c < 0 && errno == EWOULDBLOCK) {
c = 0;
} else if (c <= 0) {
return -1;
}
if (netdata) {
Dump('<', netiring.supply, c);
}
if (c)
ring_supplied(&netiring, c);
returnValue = 1;
}
/*
* Something to read from the tty...
*/
if (set[2].revents & POLLIN) {
c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring));
if (c < 0 && errno == EIO)
c = 0;
if (c < 0 && errno == EWOULDBLOCK) {
c = 0;
} else {
if (c < 0) {
return -1;
}
if (c == 0) {
/* must be an EOF... */
if (MODE_LOCAL_CHARS(globalmode) && isatty(tin)) {
*ttyiring.supply = termEofChar;
c = 1;
} else {
clienteof = 1;
shutdown(net, 1);
return 0;
}
}
if (termdata) {
Dump('<', ttyiring.supply, c);
}
ring_supplied(&ttyiring, c);
}
returnValue = 1; /* did something useful */
}
if (set[0].revents & POLLOUT) {
returnValue |= netflush();
}
if (set[1].revents & (POLLHUP|POLLNVAL))
return(-1);
if (set[1].revents & POLLOUT) {
returnValue |= (ttyflush(SYNCHing|flushout) > 0);
}
return returnValue;
}

1414
usr.bin/telnet/telnet.1 Normal file

File diff suppressed because it is too large Load Diff

2648
usr.bin/telnet/telnet.c Normal file

File diff suppressed because it is too large Load Diff

220
usr.bin/telnet/terminal.c Normal file
View File

@@ -0,0 +1,220 @@
/* $NetBSD: terminal.c,v 1.15 2005/02/19 23:28:41 christos Exp $ */
/*
* Copyright (c) 1988, 1990, 1993
* The 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. 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.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)terminal.c 8.2 (Berkeley) 2/16/95";
#else
__RCSID("$NetBSD: terminal.c,v 1.15 2005/02/19 23:28:41 christos Exp $");
#endif
#endif /* not lint */
#include <arpa/telnet.h>
#include <sys/types.h>
#include "ring.h"
#include "externs.h"
#include "types.h"
#ifdef ENCRYPTION
#include <libtelnet/encrypt.h>
#endif
Ring ttyoring, ttyiring;
unsigned char ttyobuf[2*BUFSIZ], ttyibuf[BUFSIZ];
char line[] = { '\0' };
int termdata; /* Debugging flag */
/*
* initialize the terminal data structures.
*/
void
init_terminal(void)
{
if (ring_init(&ttyoring, ttyobuf, sizeof ttyobuf) != 1) {
exit(1);
}
if (ring_init(&ttyiring, ttyibuf, sizeof ttyibuf) != 1) {
exit(1);
}
autoflush = TerminalAutoFlush();
}
/*
* Send as much data as possible to the terminal, else exits if
* it encounters a permanent failure when writing to the tty.
*
* Return value:
* -1: No useful work done, data waiting to go out.
* 0: No data was waiting, so nothing was done.
* 1: All waiting data was written out.
* n: All data - n was written out.
*/
int
ttyflush(int drop)
{
int n, n0, n1;
n0 = ring_full_count(&ttyoring);
if ((n1 = n = ring_full_consecutive(&ttyoring)) > 0) {
if (drop) {
TerminalFlushOutput();
/* we leave 'n' alone! */
} else {
n = TerminalWrite(ttyoring.consume, n);
}
}
if (n > 0) {
if (termdata && n) {
Dump('>', ttyoring.consume, n);
}
/*
* If we wrote everything, and the full count is
* larger than what we wrote, then write the
* rest of the buffer.
*/
if (n1 == n && n0 > n) {
n1 = n0 - n;
if (!drop)
n1 = TerminalWrite(ttyoring.bottom, n1);
if (n1 > 0)
n += n1;
}
ring_consumed(&ttyoring, n);
}
if (n < 0) {
if (errno == EAGAIN || errno == EINTR) {
return -1;
} else {
ring_consumed(&ttyoring, ring_full_count(&ttyoring));
setconnmode(0);
setcommandmode();
NetClose(net);
fprintf(stderr, "Connection closed by foreign host.\n");
exit(1);
}
}
if (n == n0) {
if (n0)
return -1;
return 0;
}
return n0 - n + 1;
}
/*
* These routines decides on what the mode should be (based on the values
* of various global variables).
*/
int
getconnmode(void)
{
extern int linemode;
int mode = 0;
#ifdef KLUDGELINEMODE
extern int kludgelinemode;
#endif
if (In3270)
return(MODE_FLOW);
if (my_want_state_is_dont(TELOPT_ECHO))
mode |= MODE_ECHO;
if (localflow)
mode |= MODE_FLOW;
if (my_want_state_is_will(TELOPT_BINARY))
mode |= MODE_INBIN;
if (his_want_state_is_will(TELOPT_BINARY))
mode |= MODE_OUTBIN;
#ifdef KLUDGELINEMODE
if (kludgelinemode) {
if (my_want_state_is_dont(TELOPT_SGA)) {
mode |= (MODE_TRAPSIG|MODE_EDIT);
if (dontlecho && (clocks.echotoggle > clocks.modenegotiated)) {
mode &= ~MODE_ECHO;
}
}
return(mode);
}
#endif
if (my_want_state_is_will(TELOPT_LINEMODE))
mode |= linemode;
return(mode);
}
void
setconnmode(int force)
{
#ifdef ENCRYPTION
static int enc_passwd = 0;
#endif
int newmode;
newmode = getconnmode()|(force?MODE_FORCE:0);
TerminalNewMode(newmode);
#ifdef ENCRYPTION
if ((newmode & (MODE_ECHO|MODE_EDIT)) == MODE_EDIT) {
if (my_want_state_is_will(TELOPT_ENCRYPT)
&& (enc_passwd == 0) && !encrypt_output) {
encrypt_request_start(0, 0);
enc_passwd = 1;
}
} else {
if (enc_passwd) {
encrypt_request_end();
enc_passwd = 0;
}
}
#endif /* ENCRYPTION */
}
void
setcommandmode(void)
{
TerminalNewMode(-1);
}

394
usr.bin/telnet/tn3270.c Normal file
View File

@@ -0,0 +1,394 @@
/* $NetBSD: tn3270.c,v 1.22 2006/10/07 17:27:57 elad Exp $ */
/*
* Copyright (c) 1988, 1993
* The 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. 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.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)tn3270.c 8.2 (Berkeley) 5/30/95";
#else
__RCSID("$NetBSD: tn3270.c,v 1.22 2006/10/07 17:27:57 elad Exp $");
#endif
#endif /* not lint */
#include <sys/types.h>
#include <sys/time.h>
#include <arpa/telnet.h>
#include <unistd.h>
#include <poll.h>
#include "general.h"
#include "defines.h"
#include "ring.h"
#include "externs.h"
#ifdef TN3270
#include "../ctlr/screen.h"
#include "../ctlr/declare.h"
#include "../ascii/state.h"
#include "../general/globals.h"
#include "../sys_curses/telextrn.h"
int
HaveInput, /* There is input available to scan */
cursesdata, /* Do we dump curses data? */
sigiocount; /* Number of times we got a SIGIO */
char tline[200];
char *transcom = 0; /* transparent mode command (default: none) */
char Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp;
static char sb_terminal[] = { IAC, SB,
TELOPT_TTYPE, TELQUAL_IS,
'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2',
IAC, SE };
#define SBTERMMODEL 13
static int
Sent3270TerminalType; /* Have we said we are a 3270? */
#endif /* defined(TN3270) */
#ifdef TN3270
void
init_3270(void)
{
HaveInput = 0;
sigiocount = 0;
Sent3270TerminalType = 0;
Ifrontp = Ibackp = Ibuf;
init_ctlr(); /* Initialize some things */
init_keyboard();
init_screen();
init_system();
}
#endif /* defined(TN3270) */
#ifdef TN3270
/*
* DataToNetwork - queue up some data to go to network. If "done" is set,
* then when last byte is queued, we add on an IAC EOR sequence (so,
* don't call us with "done" until you want that done...)
*
* We actually do send all the data to the network buffer, since our
* only client needs for us to do that.
*/
int
DataToNetwork(char *buffer, /* where the data is */
int count, /* how much to send */
int done) /* is this the last of a logical block */
{
int loop, c;
int origCount;
origCount = count;
while (count) {
/* If not enough room for EORs, IACs, etc., wait */
if (NETROOM() < 6) {
struct pollfd set[1];
set[0].fd = net;
set[0].events = POLLOUT;
netflush();
while (NETROOM() < 6) {
(void) poll(set, 1, INFTIM);
netflush();
}
}
c = ring_empty_count(&netoring);
if (c > count) {
c = count;
}
loop = c;
while (loop) {
if (((unsigned char)*buffer) == IAC) {
break;
}
buffer++;
loop--;
}
if ((c = c-loop)) {
ring_supply_data(&netoring, buffer-c, c);
count -= c;
}
if (loop) {
NET2ADD(IAC, IAC);
count--;
buffer++;
}
}
if (done) {
NET2ADD(IAC, EOR);
netflush(); /* try to move along as quickly as ... */
}
return(origCount - count);
}
void
inputAvailable(int signo)
{
HaveInput = 1;
sigiocount++;
}
void
outputPurge(void)
{
(void) ttyflush(1);
}
/*
* The following routines are places where the various tn3270
* routines make calls into telnet.c.
*/
/*
* DataToTerminal - queue up some data to go to terminal.
*
* Note: there are people who call us and depend on our processing
* *all* the data at one time (thus the poll).
*/
int
DataToTerminal(
char *buffer, /* where the data is */
int count) /* how much to send */
{
int c;
int origCount;
origCount = count;
while (count) {
if (TTYROOM() == 0) {
struct pollfd set[1];
set[0].fd = tout;
set[0].events = POLLOUT;
(void) ttyflush(0);
while (TTYROOM() == 0) {
(void) poll(set, 1, INFTIM);
(void) ttyflush(0);
}
}
c = TTYROOM();
if (c > count) {
c = count;
}
ring_supply_data(&ttyoring, buffer, c);
count -= c;
buffer += c;
}
return(origCount);
}
/*
* Push3270 - Try to send data along the 3270 output (to screen) direction.
*/
int
Push3270(void)
{
int save = ring_full_count(&netiring);
if (save) {
if (Ifrontp+save > Ibuf+sizeof Ibuf) {
if (Ibackp != Ibuf) {
memmove(Ibuf, Ibackp, Ifrontp-Ibackp);
Ifrontp -= (Ibackp-Ibuf);
Ibackp = Ibuf;
}
}
if (Ifrontp+save < Ibuf+sizeof Ibuf) {
(void)telrcv();
}
}
return save != ring_full_count(&netiring);
}
/*
* Finish3270 - get the last dregs of 3270 data out to the terminal
* before quitting.
*/
void
Finish3270(void)
{
while (Push3270() || !DoTerminalOutput()) {
HaveInput = 0;
;
}
}
/* StringToTerminal - output a null terminated string to the terminal */
void
StringToTerminal(char *s)
{
int count;
count = strlen(s);
if (count) {
(void) DataToTerminal(s, count); /* we know it always goes... */
}
}
/* _putchar - output a single character to the terminal. This name is so that
* curses(3x) can call us to send out data.
*/
int
_putchar(int cc)
{
char c = (char)cc;
if (cursesdata) {
Dump('>', &c, 1);
}
if (!TTYROOM()) {
(void) DataToTerminal(&c, 1);
} else {
TTYADD(c);
}
return (0);
}
void
SetIn3270(void)
{
if (Sent3270TerminalType && my_want_state_is_will(TELOPT_BINARY)
&& my_want_state_is_do(TELOPT_BINARY) && !donebinarytoggle) {
if (!In3270) {
In3270 = 1;
Init3270(); /* Initialize 3270 functions */
/* initialize terminal key mapping */
InitTerminal(); /* Start terminal going */
setconnmode(0);
}
} else {
if (In3270) {
StopScreen(1);
In3270 = 0;
Stop3270(); /* Tell 3270 we aren't here anymore */
setconnmode(0);
}
}
}
/*
* tn3270_ttype()
*
* Send a response to a terminal type negotiation.
*
* Return '0' if no more responses to send; '1' if a response sent.
*/
int
tn3270_ttype(void)
{
/*
* Try to send a 3270 type terminal name. Decide which one based
* on the format of our screen, and (in the future) color
* capaiblities.
*/
InitTerminal(); /* Sets MaxNumberColumns, MaxNumberLines */
if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) {
Sent3270TerminalType = 1;
if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) {
MaxNumberLines = 27;
MaxNumberColumns = 132;
sb_terminal[SBTERMMODEL] = '5';
} else if (MaxNumberLines >= 43) {
MaxNumberLines = 43;
MaxNumberColumns = 80;
sb_terminal[SBTERMMODEL] = '4';
} else if (MaxNumberLines >= 32) {
MaxNumberLines = 32;
MaxNumberColumns = 80;
sb_terminal[SBTERMMODEL] = '3';
} else {
MaxNumberLines = 24;
MaxNumberColumns = 80;
sb_terminal[SBTERMMODEL] = '2';
}
NumberLines = 24; /* before we start out... */
NumberColumns = 80;
ScreenSize = NumberLines*NumberColumns;
if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) {
ExitString("Programming error: MAXSCREENSIZE too small.\n",
1);
/*NOTREACHED*/
}
printsub('>', sb_terminal+2, sizeof sb_terminal-2);
ring_supply_data(&netoring, sb_terminal, sizeof sb_terminal);
return 1;
} else {
return 0;
}
}
int
settranscom(int argc, char *argv[])
{
int i;
if (argc == 1 && transcom) {
transcom = 0;
}
if (argc == 1) {
return 1;
}
transcom = tline;
(void) strlcpy(tline, argv[1], sizeof(tline));
for (i = 2; i < argc; ++i) {
(void) strlcat(tline, " ", sizeof(tline));
(void) strlcat(tline, argv[i], sizeof(tline));
}
return 1;
}
#endif /* defined(TN3270) */

50
usr.bin/telnet/types.h Normal file
View File

@@ -0,0 +1,50 @@
/* $NetBSD: types.h,v 1.6 2003/08/07 11:16:12 agc Exp $ */
/*
* Copyright (c) 1988, 1993
* The 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. 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: @(#)types.h 8.1 (Berkeley) 6/6/93
*/
typedef struct {
char *modedescriptions;
char modetype;
} Modelist;
extern Modelist modelist[];
typedef struct {
int
system, /* what the current time is */
echotoggle, /* last time user entered echo character */
modenegotiated, /* last time operating mode negotiated */
didnetreceive, /* last time we read data from network */
gotDM; /* when did we last see a data mark */
} Clocks;
extern Clocks clocks;

925
usr.bin/telnet/utilities.c Normal file
View File

@@ -0,0 +1,925 @@
/* $NetBSD: utilities.c,v 1.23 2012/01/09 16:08:55 christos Exp $ */
/*
* Copyright (c) 1988, 1993
* The 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. 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.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)utilities.c 8.3 (Berkeley) 5/30/95";
#else
__RCSID("$NetBSD: utilities.c,v 1.23 2012/01/09 16:08:55 christos Exp $");
#endif
#endif /* not lint */
#define TELOPTS
#define TELCMDS
#define SLC_NAMES
#include <arpa/telnet.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <unistd.h>
#include <poll.h>
#include <ctype.h>
#include "general.h"
#include "ring.h"
#include "defines.h"
#include "externs.h"
#ifdef TN3270
#include "../sys_curses/telextrn.h"
#endif
#ifdef AUTHENTICATION
#include <libtelnet/auth.h>
#endif
#ifdef ENCRYPTION
#include <libtelnet/encrypt.h>
#endif
FILE *NetTrace = 0; /* Not in bss, since needs to stay */
int prettydump;
/*
* upcase()
*
* Upcase (in place) the argument.
*/
void
upcase(char *argument)
{
int c;
while ((c = *argument) != 0) {
if (islower(c)) {
*argument = toupper(c);
}
argument++;
}
}
/*
* SetSockOpt()
*
* Compensate for differences in 4.2 and 4.3 systems.
*/
int
SetSockOpt(int fd, int level, int option, int yesno)
{
return setsockopt(fd, level, option, (char *)&yesno, sizeof yesno);
}
/*
* The following are routines used to print out debugging information.
*/
char NetTraceFile[256] = "(standard output)";
void
SetNetTrace(char *file)
{
if (NetTrace && NetTrace != stdout)
fclose(NetTrace);
if (file && (strcmp(file, "-") != 0)) {
NetTrace = fopen(file, "w");
if (NetTrace) {
strlcpy(NetTraceFile, file, sizeof(NetTraceFile));
return;
}
fprintf(stderr, "Cannot open %s.\n", file);
}
NetTrace = stdout;
strlcpy(NetTraceFile, "(standard output)", sizeof(NetTraceFile));
}
void
Dump(int direction, unsigned char *buffer, int length)
{
# define BYTES_PER_LINE 32
# define min(x,y) ((x<y)? x:y)
unsigned char *pThis;
int offset;
offset = 0;
while (length) {
/* print one line */
fprintf(NetTrace, "%c 0x%x\t", direction, offset);
pThis = buffer;
if (prettydump) {
buffer = buffer + min(length, BYTES_PER_LINE/2);
while (pThis < buffer) {
fprintf(NetTrace, "%c%.2x",
(((*pThis)&0xff) == 0xff) ? '*' : ' ',
(*pThis)&0xff);
pThis++;
}
length -= BYTES_PER_LINE/2;
offset += BYTES_PER_LINE/2;
} else {
buffer = buffer + min(length, BYTES_PER_LINE);
while (pThis < buffer) {
fprintf(NetTrace, "%.2x", (*pThis)&0xff);
pThis++;
}
length -= BYTES_PER_LINE;
offset += BYTES_PER_LINE;
}
if (NetTrace == stdout) {
fprintf(NetTrace, "\r\n");
} else {
fprintf(NetTrace, "\n");
}
if (length < 0) {
fflush(NetTrace);
return;
}
/* find next unique line */
}
fflush(NetTrace);
}
void
printoption(const char *direction, int cmd, int option)
{
if (!showoptions)
return;
if (cmd == IAC) {
if (TELCMD_OK(option))
fprintf(NetTrace, "%s IAC %s", direction, TELCMD(option));
else
fprintf(NetTrace, "%s IAC %d", direction, option);
} else {
const char *fmt;
fmt = (cmd == WILL) ? "WILL" : (cmd == WONT) ? "WONT" :
(cmd == DO) ? "DO" : (cmd == DONT) ? "DONT" : 0;
if (fmt) {
fprintf(NetTrace, "%s %s ", direction, fmt);
if (TELOPT_OK(option))
fprintf(NetTrace, "%s", TELOPT(option));
else if (option == TELOPT_EXOPL)
fprintf(NetTrace, "EXOPL");
else
fprintf(NetTrace, "%d", option);
} else
fprintf(NetTrace, "%s %d %d", direction, cmd, option);
}
if (NetTrace == stdout) {
fprintf(NetTrace, "\r\n");
fflush(NetTrace);
} else {
fprintf(NetTrace, "\n");
}
return;
}
void
optionstatus(void)
{
int i;
extern char will_wont_resp[], do_dont_resp[];
for (i = 0; i < 256; i++) {
if (do_dont_resp[i]) {
if (TELOPT_OK(i))
printf("resp DO_DONT %s: %d\n", TELOPT(i), do_dont_resp[i]);
else if (TELCMD_OK(i))
printf("resp DO_DONT %s: %d\n", TELCMD(i), do_dont_resp[i]);
else
printf("resp DO_DONT %d: %d\n", i,
do_dont_resp[i]);
if (my_want_state_is_do(i)) {
if (TELOPT_OK(i))
printf("want DO %s\n", TELOPT(i));
else if (TELCMD_OK(i))
printf("want DO %s\n", TELCMD(i));
else
printf("want DO %d\n", i);
} else {
if (TELOPT_OK(i))
printf("want DONT %s\n", TELOPT(i));
else if (TELCMD_OK(i))
printf("want DONT %s\n", TELCMD(i));
else
printf("want DONT %d\n", i);
}
} else {
if (my_state_is_do(i)) {
if (TELOPT_OK(i))
printf(" DO %s\n", TELOPT(i));
else if (TELCMD_OK(i))
printf(" DO %s\n", TELCMD(i));
else
printf(" DO %d\n", i);
}
}
if (will_wont_resp[i]) {
if (TELOPT_OK(i))
printf("resp WILL_WONT %s: %d\n", TELOPT(i), will_wont_resp[i]);
else if (TELCMD_OK(i))
printf("resp WILL_WONT %s: %d\n", TELCMD(i), will_wont_resp[i]);
else
printf("resp WILL_WONT %d: %d\n",
i, will_wont_resp[i]);
if (my_want_state_is_will(i)) {
if (TELOPT_OK(i))
printf("want WILL %s\n", TELOPT(i));
else if (TELCMD_OK(i))
printf("want WILL %s\n", TELCMD(i));
else
printf("want WILL %d\n", i);
} else {
if (TELOPT_OK(i))
printf("want WONT %s\n", TELOPT(i));
else if (TELCMD_OK(i))
printf("want WONT %s\n", TELCMD(i));
else
printf("want WONT %d\n", i);
}
} else {
if (my_state_is_will(i)) {
if (TELOPT_OK(i))
printf(" WILL %s\n", TELOPT(i));
else if (TELCMD_OK(i))
printf(" WILL %s\n", TELCMD(i));
else
printf(" WILL %d\n", i);
}
}
}
}
void
printsub(
int direction, /* '<' or '>' */
unsigned char *pointer, /* where suboption data sits */
int length) /* length of suboption data */
{
int i;
#ifdef ENCRYPTION
char buf[512];
#endif /* ENCRYPTION */
extern int want_status_response;
if (showoptions || direction == 0 ||
(want_status_response && (pointer[0] == TELOPT_STATUS))) {
if (direction) {
fprintf(NetTrace, "%s IAC SB ",
(direction == '<')? "RCVD":"SENT");
if (length >= 3) {
int j;
i = pointer[length-2];
j = pointer[length-1];
if (i != IAC || j != SE) {
fprintf(NetTrace, "(terminated by ");
if (TELOPT_OK(i))
fprintf(NetTrace, "%s ", TELOPT(i));
else if (TELCMD_OK(i))
fprintf(NetTrace, "%s ", TELCMD(i));
else
fprintf(NetTrace, "%d ", i);
if (TELOPT_OK(j))
fprintf(NetTrace, "%s", TELOPT(j));
else if (TELCMD_OK(j))
fprintf(NetTrace, "%s", TELCMD(j));
else
fprintf(NetTrace, "%d", j);
fprintf(NetTrace, ", not IAC SE!) ");
}
}
length -= 2;
}
if (length < 1) {
fprintf(NetTrace, "(Empty suboption??\?)");
if (NetTrace == stdout)
fflush(NetTrace);
return;
}
switch (pointer[0]) {
case TELOPT_TTYPE:
fprintf(NetTrace, "TERMINAL-TYPE ");
switch (pointer[1]) {
case TELQUAL_IS:
fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2);
break;
case TELQUAL_SEND:
fprintf(NetTrace, "SEND");
break;
default:
fprintf(NetTrace,
"- unknown qualifier %d (0x%x).",
pointer[1], pointer[1]);
}
break;
case TELOPT_TSPEED:
fprintf(NetTrace, "TERMINAL-SPEED");
if (length < 2) {
fprintf(NetTrace, " (empty suboption??\?)");
break;
}
switch (pointer[1]) {
case TELQUAL_IS:
fprintf(NetTrace, " IS ");
fprintf(NetTrace, "%.*s", length-2, (char *)pointer+2);
break;
default:
if (pointer[1] == 1)
fprintf(NetTrace, " SEND");
else
fprintf(NetTrace, " %d (unknown)", pointer[1]);
for (i = 2; i < length; i++)
fprintf(NetTrace, " ?%d?", pointer[i]);
break;
}
break;
case TELOPT_LFLOW:
fprintf(NetTrace, "TOGGLE-FLOW-CONTROL");
if (length < 2) {
fprintf(NetTrace, " (empty suboption??\?)");
break;
}
switch (pointer[1]) {
case LFLOW_OFF:
fprintf(NetTrace, " OFF"); break;
case LFLOW_ON:
fprintf(NetTrace, " ON"); break;
case LFLOW_RESTART_ANY:
fprintf(NetTrace, " RESTART-ANY"); break;
case LFLOW_RESTART_XON:
fprintf(NetTrace, " RESTART-XON"); break;
default:
fprintf(NetTrace, " %d (unknown)", pointer[1]);
}
for (i = 2; i < length; i++)
fprintf(NetTrace, " ?%d?", pointer[i]);
break;
case TELOPT_NAWS:
fprintf(NetTrace, "NAWS");
if (length < 2) {
fprintf(NetTrace, " (empty suboption??\?)");
break;
}
if (length == 2) {
fprintf(NetTrace, " ?%d?", pointer[1]);
break;
}
fprintf(NetTrace, " %d %d (%d)",
pointer[1], pointer[2],
(int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2])));
if (length == 4) {
fprintf(NetTrace, " ?%d?", pointer[3]);
break;
}
fprintf(NetTrace, " %d %d (%d)",
pointer[3], pointer[4],
(int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4])));
for (i = 5; i < length; i++)
fprintf(NetTrace, " ?%d?", pointer[i]);
break;
#ifdef AUTHENTICATION
case TELOPT_AUTHENTICATION:
fprintf(NetTrace, "AUTHENTICATION");
if (length < 2) {
fprintf(NetTrace, " (empty suboption??\?)");
break;
}
switch (pointer[1]) {
case TELQUAL_REPLY:
case TELQUAL_IS:
fprintf(NetTrace, " %s ", (pointer[1] == TELQUAL_IS) ?
"IS" : "REPLY");
if (AUTHTYPE_NAME_OK(pointer[2]))
fprintf(NetTrace, "%s ", AUTHTYPE_NAME(pointer[2]));
else
fprintf(NetTrace, "%d ", pointer[2]);
if (length < 3) {
fprintf(NetTrace, "(partial suboption??\?)");
break;
}
fprintf(NetTrace, "%s|%s",
((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
"CLIENT" : "SERVER",
((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
"MUTUAL" : "ONE-WAY");
auth_printsub(&pointer[1], length - 1, buf, sizeof(buf));
fprintf(NetTrace, "%s", buf);
break;
case TELQUAL_SEND:
i = 2;
fprintf(NetTrace, " SEND ");
while (i < length) {
if (AUTHTYPE_NAME_OK(pointer[i]))
fprintf(NetTrace, "%s ", AUTHTYPE_NAME(pointer[i]));
else
fprintf(NetTrace, "%d ", pointer[i]);
if (++i >= length) {
fprintf(NetTrace, "(partial suboption??\?)");
break;
}
fprintf(NetTrace, "%s|%s ",
((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
"CLIENT" : "SERVER",
((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
"MUTUAL" : "ONE-WAY");
++i;
}
break;
case TELQUAL_NAME:
i = 2;
fprintf(NetTrace, " NAME \"");
while (i < length)
putc(pointer[i++], NetTrace);
putc('"', NetTrace);
break;
default:
for (i = 2; i < length; i++)
fprintf(NetTrace, " ?%d?", pointer[i]);
break;
}
break;
#endif
#ifdef ENCRYPTION
case TELOPT_ENCRYPT:
fprintf(NetTrace, "ENCRYPT");
if (length < 2) {
fprintf(NetTrace, " (empty suboption??\?)");
break;
}
switch (pointer[1]) {
case ENCRYPT_START:
fprintf(NetTrace, " START");
break;
case ENCRYPT_END:
fprintf(NetTrace, " END");
break;
case ENCRYPT_REQSTART:
fprintf(NetTrace, " REQUEST-START");
break;
case ENCRYPT_REQEND:
fprintf(NetTrace, " REQUEST-END");
break;
case ENCRYPT_IS:
case ENCRYPT_REPLY:
fprintf(NetTrace, " %s ", (pointer[1] == ENCRYPT_IS) ?
"IS" : "REPLY");
if (length < 3) {
fprintf(NetTrace, " (partial suboption??\?)");
break;
}
if (ENCTYPE_NAME_OK(pointer[2]))
fprintf(NetTrace, "%s ",
ENCTYPE_NAME(pointer[2]));
else
fprintf(NetTrace, " %d (unknown)", pointer[2]);
encrypt_printsub(&pointer[1], length - 1, buf,
sizeof(buf));
fprintf(NetTrace, "%s", buf);
break;
case ENCRYPT_SUPPORT:
i = 2;
fprintf(NetTrace, " SUPPORT ");
while (i < length) {
if (ENCTYPE_NAME_OK(pointer[i]))
fprintf(NetTrace, "%s ",
ENCTYPE_NAME(pointer[i]));
else
fprintf(NetTrace, "%d ", pointer[i]);
i++;
}
break;
case ENCRYPT_ENC_KEYID:
fprintf(NetTrace, " ENC_KEYID ");
goto encommon;
case ENCRYPT_DEC_KEYID:
fprintf(NetTrace, " DEC_KEYID ");
goto encommon;
default:
fprintf(NetTrace, " %d (unknown)", pointer[1]);
encommon:
for (i = 2; i < length; i++)
fprintf(NetTrace, " %d", pointer[i]);
break;
}
break;
#endif /* ENCRYPTION */
case TELOPT_LINEMODE:
fprintf(NetTrace, "LINEMODE ");
if (length < 2) {
fprintf(NetTrace, " (empty suboption??\?)");
break;
}
switch (pointer[1]) {
case WILL:
fprintf(NetTrace, "WILL ");
goto common;
case WONT:
fprintf(NetTrace, "WONT ");
goto common;
case DO:
fprintf(NetTrace, "DO ");
goto common;
case DONT:
fprintf(NetTrace, "DONT ");
common:
if (length < 3) {
fprintf(NetTrace, "(no option??\?)");
break;
}
switch (pointer[2]) {
case LM_FORWARDMASK:
fprintf(NetTrace, "Forward Mask");
for (i = 3; i < length; i++)
fprintf(NetTrace, " %x", pointer[i]);
break;
default:
fprintf(NetTrace, "%d (unknown)", pointer[2]);
for (i = 3; i < length; i++)
fprintf(NetTrace, " %d", pointer[i]);
break;
}
break;
case LM_SLC:
fprintf(NetTrace, "SLC");
for (i = 2; i < length - 2; i += 3) {
if (SLC_NAME_OK(pointer[i+SLC_FUNC]))
fprintf(NetTrace, " %s", SLC_NAME(pointer[i+SLC_FUNC]));
else
fprintf(NetTrace, " %d", pointer[i+SLC_FUNC]);
switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) {
case SLC_NOSUPPORT:
fprintf(NetTrace, " NOSUPPORT"); break;
case SLC_CANTCHANGE:
fprintf(NetTrace, " CANTCHANGE"); break;
case SLC_VARIABLE:
fprintf(NetTrace, " VARIABLE"); break;
case SLC_DEFAULT:
fprintf(NetTrace, " DEFAULT"); break;
}
fprintf(NetTrace, "%s%s%s",
pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "",
pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "",
pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : "");
if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN|
SLC_FLUSHOUT| SLC_LEVELBITS))
fprintf(NetTrace, "(0x%x)", pointer[i+SLC_FLAGS]);
fprintf(NetTrace, " %d;", pointer[i+SLC_VALUE]);
if ((pointer[i+SLC_VALUE] == IAC) &&
(pointer[i+SLC_VALUE+1] == IAC))
i++;
}
for (; i < length; i++)
fprintf(NetTrace, " ?%d?", pointer[i]);
break;
case LM_MODE:
fprintf(NetTrace, "MODE ");
if (length < 3) {
fprintf(NetTrace, "(no mode??\?)");
break;
}
{
char tbuf[64];
sprintf(tbuf, "%s%s%s%s%s",
pointer[2]&MODE_EDIT ? "|EDIT" : "",
pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "",
pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "",
pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "",
pointer[2]&MODE_ACK ? "|ACK" : "");
fprintf(NetTrace, "%s", tbuf[1] ? &tbuf[1] : "0");
}
if (pointer[2]&~(MODE_MASK))
fprintf(NetTrace, " (0x%x)", pointer[2]);
for (i = 3; i < length; i++)
fprintf(NetTrace, " ?0x%x?", pointer[i]);
break;
default:
fprintf(NetTrace, "%d (unknown)", pointer[1]);
for (i = 2; i < length; i++)
fprintf(NetTrace, " %d", pointer[i]);
}
break;
case TELOPT_STATUS: {
const char *cp;
int j, k;
fprintf(NetTrace, "STATUS");
switch (pointer[1]) {
default:
if (pointer[1] == TELQUAL_SEND)
fprintf(NetTrace, " SEND");
else
fprintf(NetTrace, " %d (unknown)", pointer[1]);
for (i = 2; i < length; i++)
fprintf(NetTrace, " ?%d?", pointer[i]);
break;
case TELQUAL_IS:
if (--want_status_response < 0)
want_status_response = 0;
if (NetTrace == stdout)
fprintf(NetTrace, " IS\r\n");
else
fprintf(NetTrace, " IS\n");
for (i = 2; i < length; i++) {
switch(pointer[i]) {
case DO: cp = "DO"; goto common2;
case DONT: cp = "DONT"; goto common2;
case WILL: cp = "WILL"; goto common2;
case WONT: cp = "WONT"; goto common2;
common2:
i++;
if (TELOPT_OK((int)pointer[i]))
fprintf(NetTrace, " %s %s", cp, TELOPT(pointer[i]));
else
fprintf(NetTrace, " %s %d", cp, pointer[i]);
if (NetTrace == stdout)
fprintf(NetTrace, "\r\n");
else
fprintf(NetTrace, "\n");
break;
case SB:
fprintf(NetTrace, " SB ");
i++;
j = k = i;
while (j < length) {
if (pointer[j] == SE) {
if (j+1 == length)
break;
if (pointer[j+1] == SE)
j++;
else
break;
}
pointer[k++] = pointer[j++];
}
printsub(0, &pointer[i], k - i);
if (i < length) {
fprintf(NetTrace, " SE");
i = j;
} else
i = j - 1;
if (NetTrace == stdout)
fprintf(NetTrace, "\r\n");
else
fprintf(NetTrace, "\n");
break;
default:
fprintf(NetTrace, " %d", pointer[i]);
break;
}
}
break;
}
break;
}
case TELOPT_XDISPLOC:
fprintf(NetTrace, "X-DISPLAY-LOCATION ");
switch (pointer[1]) {
case TELQUAL_IS:
fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2);
break;
case TELQUAL_SEND:
fprintf(NetTrace, "SEND");
break;
default:
fprintf(NetTrace, "- unknown qualifier %d (0x%x).",
pointer[1], pointer[1]);
}
break;
case TELOPT_NEW_ENVIRON:
fprintf(NetTrace, "NEW-ENVIRON ");
#ifdef OLD_ENVIRON
goto env_common1;
case TELOPT_OLD_ENVIRON:
fprintf(NetTrace, "OLD-ENVIRON");
env_common1:
#endif
switch (pointer[1]) {
case TELQUAL_IS:
fprintf(NetTrace, "IS ");
goto env_common;
case TELQUAL_SEND:
fprintf(NetTrace, "SEND ");
goto env_common;
case TELQUAL_INFO:
fprintf(NetTrace, "INFO ");
env_common:
{
static const char NQ[] = "\" ";
const char *noquote = NQ;
#if defined(ENV_HACK) && defined(OLD_ENVIRON)
extern int old_env_var, old_env_value;
#endif
for (i = 2; i < length; i++ ) {
switch (pointer[i]) {
case NEW_ENV_VALUE:
#ifdef OLD_ENVIRON
/* case NEW_ENV_OVAR: */
if (pointer[0] == TELOPT_OLD_ENVIRON) {
# ifdef ENV_HACK
if (old_env_var == OLD_ENV_VALUE)
fprintf(NetTrace, "%s(VALUE) ", noquote);
else
# endif
fprintf(NetTrace, "%sVAR ", noquote);
} else
#endif /* OLD_ENVIRON */
fprintf(NetTrace, "%sVALUE ", noquote);
noquote = NQ;
break;
case NEW_ENV_VAR:
#ifdef OLD_ENVIRON
/* case OLD_ENV_VALUE: */
if (pointer[0] == TELOPT_OLD_ENVIRON) {
# ifdef ENV_HACK
if (old_env_value == OLD_ENV_VAR)
fprintf(NetTrace, "%s(VAR) ", noquote);
else
# endif
fprintf(NetTrace, "%sVALUE ", noquote);
} else
#endif /* OLD_ENVIRON */
fprintf(NetTrace, "%sVAR ", noquote);
noquote = NQ;
break;
case ENV_ESC:
fprintf(NetTrace, "%sESC ", noquote);
noquote = NQ;
break;
case ENV_USERVAR:
fprintf(NetTrace, "%sUSERVAR ", noquote);
noquote = NQ;
break;
default:
if (isprint(pointer[i]) && pointer[i] != '"') {
if (*noquote) {
putc('"', NetTrace);
noquote = "";
}
putc(pointer[i], NetTrace);
} else {
fprintf(NetTrace, "%s%03o ", noquote,
pointer[i]);
noquote = NQ;
}
break;
}
}
if (!noquote)
putc('"', NetTrace);
break;
}
}
break;
default:
if (TELOPT_OK(pointer[0]))
fprintf(NetTrace, "%s (unknown)", TELOPT(pointer[0]));
else
fprintf(NetTrace, "%d (unknown)", pointer[0]);
for (i = 1; i < length; i++)
fprintf(NetTrace, " %d", pointer[i]);
break;
}
if (direction) {
if (NetTrace == stdout)
fprintf(NetTrace, "\r\n");
else
fprintf(NetTrace, "\n");
}
if (NetTrace == stdout)
fflush(NetTrace);
}
}
/* EmptyTerminal - called to make sure that the terminal buffer is empty.
* Note that we consider the buffer to run all the
* way to the kernel (thus the poll).
*/
void
EmptyTerminal(void)
{
struct pollfd set[1];
set[0].fd = tout;
set[0].events = POLLOUT;
if (TTYBYTES() == 0) {
(void) poll(set, 1, INFTIM);
} else {
while (TTYBYTES()) {
(void) ttyflush(0);
(void) poll(set, 1, INFTIM);
}
}
}
void
SetForExit(void)
{
setconnmode(0);
#ifdef TN3270
if (In3270) {
Finish3270();
}
#else /* defined(TN3270) */
do {
(void)telrcv(); /* Process any incoming data */
EmptyTerminal();
} while (ring_full_count(&netiring)); /* While there is any */
#endif /* defined(TN3270) */
setcommandmode();
fflush(stdout);
fflush(stderr);
#ifdef TN3270
if (In3270) {
StopScreen(1);
}
#endif /* defined(TN3270) */
setconnmode(0);
EmptyTerminal(); /* Flush the path to the tty */
setcommandmode();
}
void
Exit(int returnCode)
{
SetForExit();
exit(returnCode);
}
void
ExitString(const char *string, int returnCode)
{
SetForExit();
fwrite(string, 1, strlen(string), stderr);
exit(returnCode);
}