diff options
Diffstat (limited to 'libexec')
-rw-r--r-- | libexec/telnetd/Makefile | 4 | ||||
-rw-r--r-- | libexec/telnetd/authenc.c | 77 | ||||
-rw-r--r-- | libexec/telnetd/defs.h | 72 | ||||
-rw-r--r-- | libexec/telnetd/ext.h | 260 | ||||
-rw-r--r-- | libexec/telnetd/global.c | 81 | ||||
-rw-r--r-- | libexec/telnetd/mini_inetd.c | 136 | ||||
-rw-r--r-- | libexec/telnetd/pathnames.h | 58 | ||||
-rw-r--r-- | libexec/telnetd/slc.c | 476 | ||||
-rw-r--r-- | libexec/telnetd/socket.c | 265 | ||||
-rw-r--r-- | libexec/telnetd/state.c | 2073 | ||||
-rw-r--r-- | libexec/telnetd/sys_term.c | 3080 | ||||
-rw-r--r-- | libexec/telnetd/telnetd.8 | 286 | ||||
-rw-r--r-- | libexec/telnetd/telnetd.c | 2037 | ||||
-rw-r--r-- | libexec/telnetd/telnetd.h | 193 | ||||
-rw-r--r-- | libexec/telnetd/termstat.c | 639 | ||||
-rw-r--r-- | libexec/telnetd/utility.c | 1624 |
16 files changed, 4904 insertions, 6457 deletions
diff --git a/libexec/telnetd/Makefile b/libexec/telnetd/Makefile index 5cc496aa004..a787fa7e97a 100644 --- a/libexec/telnetd/Makefile +++ b/libexec/telnetd/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.12 2001/06/23 02:50:52 hin Exp $ +# $OpenBSD: Makefile,v 1.13 2001/06/23 19:44:31 hin Exp $ # from: @(#)Makefile 8.2 (Berkeley) 12/15/93 # $NetBSD: Makefile,v 1.6 1996/02/24 01:22:12 jtk Exp $ @@ -7,7 +7,7 @@ PROG= telnetd CFLAGS+=-DLINEMODE -DKLUDGELINEMODE -DUSE_TERMIO -DDIAGNOSTICS CFLAGS+=-DOLD_ENVIRON -DENV_HACK -I${.CURDIR} -Wall -Wno-unused SRCS= authenc.c global.c slc.c state.c sys_term.c telnetd.c \ - termstat.c utility.c + termstat.c utility.c mini_inetd.c socket.c DPADD= ${LIBUTIL} ${LIBCURSES} ${LIBTELNET} LDADD+= -lutil -lcurses -ltelnet MAN= telnetd.8 diff --git a/libexec/telnetd/authenc.c b/libexec/telnetd/authenc.c index c75844318f3..9968f4195c2 100644 --- a/libexec/telnetd/authenc.c +++ b/libexec/telnetd/authenc.c @@ -1,6 +1,3 @@ -/* $OpenBSD: authenc.c,v 1.4 2001/05/25 10:25:22 hin Exp $ */ -/* $NetBSD: authenc.c,v 1.3 1996/02/28 20:38:08 thorpej Exp $ */ - /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. @@ -34,66 +31,50 @@ * SUCH DAMAGE. */ -#ifndef lint -#if 0 -static char sccsid[] = "@(#)authenc.c 8.2 (Berkeley) 5/30/95"; -static char rcsid[] = "$NetBSD: authenc.c,v 1.3 1996/02/28 20:38:08 thorpej Exp $"; -#else -static char rcsid[] = "$OpenBSD: authenc.c,v 1.4 2001/05/25 10:25:22 hin Exp $"; -#endif -#endif /* not lint */ - -#if defined(AUTHENTICATION) #include "telnetd.h" -#include <libtelnet/misc.h> - int -telnet_net_write(str, len) - unsigned char *str; - int len; +/* RCSID("$KTH: authenc.c,v 1.10 2000/11/15 23:20:43 assar Exp $"); */ + +#ifdef AUTHENTICATION + +int +telnet_net_write(unsigned char *str, int len) { - if (nfrontp + len < netobuf + BUFSIZ) { - memmove((void *)nfrontp, (void *)str, len); - nfrontp += len; - return(len); - } - return(0); + if (nfrontp + len < netobuf + BUFSIZ) { + memmove(nfrontp, str, len); + nfrontp += len; + return(len); + } + return(0); } - void -net_encrypt() +void +net_encrypt(void) { #ifdef ENCRYPTION - char *s = (nclearto > nbackp) ? nclearto : nbackp; - if (s < nfrontp && encrypt_output) { - (*encrypt_output)((unsigned char *)s, nfrontp - s); - } - nclearto = nfrontp; + char *s = (nclearto > nbackp) ? nclearto : nbackp; + if (s < nfrontp && encrypt_output) { + (*encrypt_output)((unsigned char *)s, nfrontp - s); + } + nclearto = nfrontp; #endif } - int -telnet_spin() +int +telnet_spin(void) { - ttloop(); - return(0); + return ttloop(); } - char * -telnet_getenv(val) - const char *val; +char * +telnet_getenv(const char *val) { - extern char *getenv(const char *); - return(getenv(val)); + return(getenv(val)); } - char * -telnet_gets(prompt, result, length, echo) - char *prompt; - char *result; - int length; - int echo; +char * +telnet_gets(char *prompt, char *result, int length, int echo) { - return NULL; + return NULL; } -#endif /* defined(AUTHENTICATION) */ +#endif diff --git a/libexec/telnetd/defs.h b/libexec/telnetd/defs.h index eb40d035472..d6306d671ba 100644 --- a/libexec/telnetd/defs.h +++ b/libexec/telnetd/defs.h @@ -1,6 +1,3 @@ -/* $OpenBSD: defs.h,v 1.4 1998/05/08 19:47:05 deraadt Exp $ */ -/* $NetBSD: defs.h,v 1.6 1996/02/28 20:38:10 thorpej Exp $ */ - /* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. @@ -33,18 +30,15 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * from: @(#)defs.h 8.1 (Berkeley) 6/4/93 + * @(#)defs.h 8.1 (Berkeley) 6/4/93 */ /* * Telnet server defines */ -#include <sys/types.h> -#include <sys/param.h> -#ifndef BSD -# define BSD 43 -#endif +#ifndef __DEFS_H__ +#define __DEFS_H__ #if defined(PRINTOPTIONS) && defined(DIAGNOSTICS) #define TELOPTS @@ -52,47 +46,6 @@ #define SLC_NAMES #endif -#include <sys/socket.h> -#include <sys/wait.h> -#include <fcntl.h> -#include <sys/file.h> -#include <sys/stat.h> -#include <sys/time.h> -#include <sys/ioctl.h> - -#include <netinet/in.h> - -#include <arpa/telnet.h> - -#include <stdio.h> -#include <stdlib.h> -#include <signal.h> -#include <errno.h> -#include <netdb.h> -#include <syslog.h> -#ifndef LOG_DAEMON -#define LOG_DAEMON 0 -#endif -#ifndef LOG_ODELAY -#define LOG_ODELAY 0 -#endif -#include <ctype.h> -#include <string.h> - -#ifndef USE_TERMIO -#include <sgtty.h> -#else -# ifdef SYSV_TERMIO -# include <termio.h> -# else -# include <termios.h> -# endif -#endif -#if !defined(USE_TERMIO) || defined(NO_CC_T) -typedef unsigned char cc_t; -#endif -#include <unistd.h> - #if !defined(TIOCSCTTY) && defined(TCSETCTTY) # define TIOCSCTTY TCSETCTTY #endif @@ -100,11 +53,11 @@ typedef unsigned char cc_t; #ifndef TIOCPKT_FLUSHWRITE #define TIOCPKT_FLUSHWRITE 0x02 #endif - + #ifndef TIOCPKT_NOSTOP #define TIOCPKT_NOSTOP 0x10 #endif - + #ifndef TIOCPKT_DOSTOP #define TIOCPKT_DOSTOP 0x20 #endif @@ -112,8 +65,8 @@ typedef unsigned char cc_t; /* * I/O data buffers defines */ -#define NETSLOP 4096 -#ifdef CRAY +#define NETSLOP 64 +#ifdef _CRAY #undef BUFSIZ #define BUFSIZ 2048 #endif @@ -127,15 +80,6 @@ typedef unsigned char cc_t; #define sequenceIs(x,y) (clocks.x < clocks.y) /* - * Linemode support states, in decreasing order of importance - */ -#define REAL_LINEMODE 0x04 -#define KLUDGE_OK 0x03 -#define NO_AUTOKLUDGE 0x02 -#define KLUDGE_LINEMODE 0x01 -#define NO_LINEMODE 0x00 - -/* * Structures of information for each special character function. */ typedef struct { @@ -238,3 +182,5 @@ typedef struct { #define his_will_wont_is_changing my_do_dont_is_changing #define his_do_dont_is_changing my_will_wont_is_changing + +#endif /* __DEFS_H__ */ diff --git a/libexec/telnetd/ext.h b/libexec/telnetd/ext.h index f44b69fa427..8454a7a1c41 100644 --- a/libexec/telnetd/ext.h +++ b/libexec/telnetd/ext.h @@ -1,6 +1,3 @@ -/* $OpenBSD: ext.h,v 1.10 2001/05/25 10:25:22 hin Exp $ */ -/* $NetBSD: ext.h,v 1.6 1996/02/28 20:38:13 thorpej Exp $ */ - /* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. @@ -33,40 +30,36 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * from: @(#)ext.h 8.2 (Berkeley) 12/15/93 + * @(#)ext.h 8.2 (Berkeley) 12/15/93 */ +/* $KTH: ext.h,v 1.22 2001/04/24 23:12:11 assar Exp $ */ + +#ifndef __EXT_H__ +#define __EXT_H__ + +#include <arpa/telnet.h> + /* * Telnet server variable declarations */ extern char options[256]; extern char do_dont_resp[256]; extern char will_wont_resp[256]; -extern int linemode; /* linemode on/off */ -#ifdef LINEMODE -extern int uselinemode; /* what linemode to use (on/off) */ -extern int editmode; /* edit modes in use */ -extern int useeditmode; /* edit modes to use */ -extern int alwayslinemode; /* command line option */ -# ifdef KLUDGELINEMODE -extern int lmodetype; /* Client support for linemode */ -# endif /* KLUDGELINEMODE */ -#endif /* LINEMODE */ extern int flowmode; /* current flow control state */ extern int restartany; /* restart output on any character state */ #ifdef DIAGNOSTICS extern int diagnostic; /* telnet diagnostic capabilities */ #endif /* DIAGNOSTICS */ -#ifdef BFTPDAEMON -extern int bftpd; /* behave as bftp daemon */ -#endif /* BFTPDAEMON */ -#if defined(AUTHENTICATION) +extern int require_otp; +#ifdef AUTHENTICATION extern int auth_level; #endif +extern const char *new_login; extern slcfun slctab[NSLC + 1]; /* slc mapping table */ -char *terminaltype; +extern char *terminaltype; /* * I/O data buffers, pointers, and counters. @@ -76,133 +69,103 @@ extern char ptyobuf[BUFSIZ+NETSLOP], *pfrontp, *pbackp; extern char netibuf[BUFSIZ], *netip; extern char netobuf[BUFSIZ+NETSLOP], *nfrontp, *nbackp; -extern char *neturg; /* one past last byte of urgent data */ +extern char *neturg; /* one past last bye of urgent data */ extern int pcc, ncc; -#if defined(CRAY2) && defined(UNICOS5) -extern int unpcc; /* characters left unprocessed by CRAY-2 terminal routine */ -extern char *unptyip; /* pointer to remaining characters in buffer */ -#endif - -extern int pty, net; -extern char line[16]; +extern int ourpty, net; +extern char *line; extern int SYNCHing; /* we are in TELNET SYNCH mode */ -#include <sys/cdefs.h> -#define P __P - -extern void - _termstat P((void)), - add_slc P((int, int, int)), - check_slc P((void)), - change_slc P((int, int, int)), - cleanup P((int)), - clientstat P((int, int, int)), - copy_termbuf P((char *, int)), - deferslc P((void)), - defer_terminit P((void)), - do_opt_slc P((unsigned char *, int)), - doeof P((void)), - dooption P((int)), - dontoption P((int)), - edithost P((char *, char *)), - fatal P((int, char *)), - fatalperror P((int, char *)), - get_slc_defaults P((void)), - init_env P((void)), - init_termbuf P((void)), - interrupt P((void)), - localstat P((void)), - flowstat P((void)), - netclear P((void)), - netflush P((void)), -#ifdef DIAGNOSTICS - printoption P((char *, int)), - printdata P((char *, char *, int)), - printsub P((int, unsigned char *, int)), -#endif - ptyflush P((void)), - putchr P((int)), - putf P((char *, char *)), - recv_ayt P((void)), - send_do P((int, int)), - send_dont P((int, int)), - send_slc P((void)), - send_status P((void)), - send_will P((int, int)), - send_wont P((int, int)), - sendbrk P((void)), - sendsusp P((void)), - set_termbuf P((void)), - start_login P((char *, int, char *)), - start_slc P((int)), -#if defined(AUTHENTICATION) - start_slave P((char *)), -#else - start_slave P((char *, int, char *)), -#endif - suboption P((void)), - telrcv P((void)), - ttloop P((void)), - tty_binaryin P((int)), - tty_binaryout P((int)); - -extern char* - gtgetstr P((char *, char **)); - -extern int - end_slc P((unsigned char **)), - gtgetent P((char *, char *)), - getnpty P((void)), -#ifndef convex - getpty P((int *)), -#endif - login_tty P((int)), - output_data P((const char *, ...)), - spcset P((int, cc_t *, cc_t **)), - stilloob P((int)), - terminit P((void)), - termstat P((void)), - tty_flowmode P((void)), - tty_restartany P((void)), - tty_isbinaryin P((void)), - tty_isbinaryout P((void)), - tty_iscrnl P((void)), - tty_isecho P((void)), - tty_isediting P((void)), - tty_islitecho P((void)), - tty_isnewmap P((void)), - tty_israw P((void)), - tty_issofttab P((void)), - tty_istrapsig P((void)), - tty_linemode P((void)); - -extern void - tty_rspeed P((int)), - tty_setecho P((int)), - tty_setedit P((int)), - tty_setlinemode P((int)), - tty_setlitecho P((int)), - tty_setsig P((int)), - tty_setsofttab P((int)), - tty_tspeed P((int)), - willoption P((int)), - wontoption P((int)), - writenet P((unsigned char *, int)); +int telnet_net_write (unsigned char *str, int len); +void net_encrypt (void); +int telnet_spin (void); +char *telnet_getenv (const char *val); +char *telnet_gets (char *prompt, char *result, int length, int echo); +void get_slc_defaults (void); +void telrcv (void); +void send_do (int option, int init); +void willoption (int option); +void send_dont (int option, int init); +void wontoption (int option); +void send_will (int option, int init); +void dooption (int option); +void send_wont (int option, int init); +void dontoption (int option); +void suboption (void); +void doclientstat (void); +void send_status (void); +void init_termbuf (void); +void set_termbuf (void); +int spcset (int func, cc_t *valp, cc_t **valpp); +void set_utid (void); +int getpty (int *ptynum); +int tty_isecho (void); +int tty_flowmode (void); +int tty_restartany (void); +void tty_setecho (int on); +int tty_israw (void); +void tty_binaryin (int on); +void tty_binaryout (int on); +int tty_isbinaryin (void); +int tty_isbinaryout (void); +int tty_issofttab (void); +void tty_setsofttab (int on); +int tty_islitecho (void); +void tty_setlitecho (int on); +int tty_iscrnl (void); +void tty_tspeed (int val); +void tty_rspeed (int val); +void getptyslave (void); +int cleanopen (char *line); +void startslave (const char *host, const char *, int autologin, char *autoname); +void init_env (void); +void start_login (const char *host, int autologin, char *name); +void cleanup (int sig); +int main (int argc, char **argv); +int getterminaltype (char *name, size_t); +void _gettermname (void); +int terminaltypeok (char *s); +void my_telnet (int f, int p, const char*, const char *, int, char*); +void interrupt (void); +void sendbrk (void); +void sendsusp (void); +void recv_ayt (void); +void doeof (void); +void flowstat (void); +void clientstat (int code, int parm1, int parm2); +int ttloop (void); +int stilloob (int s); +void ptyflush (void); +char *nextitem (char *current); +void netclear (void); +void netflush (void); +void writenet (unsigned char *ptr, int len); +void fatal (int f, char *msg); +void fatalperror (int f, const char *msg); +void fatalperror_errno (int f, const char *msg, int error); +void edithost (char *pat, char *host); +void putstr (char *s); +void putchr (int cc); +void putf (char *cp, char *where); +void printoption (char *fmt, int option); +void printsub (int direction, unsigned char *pointer, int length); +void printdata (char *tag, char *ptr, int cnt); +int login_tty(int t); #ifdef ENCRYPTION -extern void (*encrypt_output) (unsigned char *, int); -extern int (*decrypt_input) (int); -extern char *nclearto; +extern void (*encrypt_output) (unsigned char *, int); +extern int (*decrypt_input) (int); +extern char *nclearto; #endif + /* * The following are some clocks used to decide how to interpret * the relationship between various variables. */ -extern struct { +struct clocks_t{ int system, /* what the current time is */ echotoggle, /* last time user entered echo character */ @@ -215,25 +178,28 @@ extern struct { xdisplocsubopt, /* xdisploc subopt is received */ baseline, /* time started to do timed action */ gotDM; /* when did we last see a data mark */ -} clocks; +}; +extern struct clocks_t clocks; +extern int log_unauth; +extern int no_warn; -#if defined(CRAY2) && defined(UNICOS5) -extern int needtermstat; +#ifdef STREAMSPTY +extern int really_stream; #endif -#ifndef DEFAULT_IM +#ifndef USE_IM # ifdef CRAY -# define DEFAULT_IM "\r\n\r\nCray UNICOS (%h) (%t)\r\n\r\r\n\r" -# else -# ifdef sun -# define DEFAULT_IM "\r\n\r\nSunOS UNIX (%h) (%t)\r\n\r\r\n\r" -# else -# ifdef ultrix -# define DEFAULT_IM "\r\n\r\nULTRIX (%h) (%t)\r\n\r\r\n\r" -# else -# define DEFAULT_IM "\r\n\r\n4.4 BSD UNIX (%h) (%t)\r\n\r\r\n\r" -# endif -# endif +# define USE_IM "Cray UNICOS (%h) (%t)" +# endif +# ifdef _AIX +# define USE_IM "%s %v.%r (%h) (%t)" +# endif +# ifndef USE_IM +# define USE_IM "%s %r (%h) (%t)" # endif #endif + +#define DEFAULT_IM "\r\n\r\n" USE_IM "\r\n\r\n\r\n" + +#endif /* __EXT_H__ */ diff --git a/libexec/telnetd/global.c b/libexec/telnetd/global.c index 2d2d9a03a3f..4b37c22a3c0 100644 --- a/libexec/telnetd/global.c +++ b/libexec/telnetd/global.c @@ -1,6 +1,3 @@ -/* $OpenBSD: global.c,v 1.4 1998/06/23 22:40:29 millert Exp $ */ -/* $NetBSD: global.c,v 1.6 1996/02/28 20:38:14 thorpej Exp $ */ - /* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. @@ -34,27 +31,63 @@ * SUCH DAMAGE. */ -#ifndef lint -#if 0 -static char sccsid[] = "@(#)global.c 8.1 (Berkeley) 6/4/93"; -static char rcsid[] = "$NetBSD: global.c,v 1.6 1996/02/28 20:38:14 thorpej Exp $"; -#else -static char rcsid[] = "$OpenBSD: global.c,v 1.4 1998/06/23 22:40:29 millert Exp $"; -#endif -#endif /* not lint */ +/* a *lot* of ugly global definitions that really should be removed... + */ + +#include "telnetd.h" + +/* RCSID("$KTH: global.c,v 1.12 1997/05/11 06:29:59 assar Exp $"); */ + +/* + * Telnet server variable declarations + */ +char options[256]; +char do_dont_resp[256]; +char will_wont_resp[256]; +int linemode; /* linemode on/off */ +int flowmode; /* current flow control state */ +int restartany; /* restart output on any character state */ +#ifdef DIAGNOSTICS +int diagnostic; /* telnet diagnostic capabilities */ +#endif /* DIAGNOSTICS */ +int require_otp; + +slcfun slctab[NSLC + 1]; /* slc mapping table */ + +char *terminaltype; + +/* + * I/O data buffers, pointers, and counters. + */ +char ptyobuf[BUFSIZ+NETSLOP], *pfrontp, *pbackp; + +char netibuf[BUFSIZ], *netip; + +char netobuf[BUFSIZ+NETSLOP], *nfrontp, *nbackp; +char *neturg; /* one past last bye of urgent data */ + +int pcc, ncc; + +int ourpty, net; +int SYNCHing; /* we are in TELNET SYNCH mode */ /* - * Allocate global variables. We do this - * by including the header file that defines - * them all as externs, but first we define - * the keyword "extern" to be nothing, so that - * we will actually allocate the space. + * The following are some clocks used to decide how to interpret + * the relationship between various variables. */ -#include <stdarg.h> -#include <defs.h> -#define extern -#include <ext.h> +struct clocks_t clocks; + + +/* whether to log unauthenticated login attempts */ +int log_unauth; + +/* do not print warning if connection is not encrypted */ +int no_warn; + +/* + * This function appends data to nfrontp and advances nfrontp. + */ int output_data (const char *format, ...) @@ -65,11 +98,9 @@ output_data (const char *format, ...) va_start(args, format); remaining = BUFSIZ - (nfrontp - netobuf); ret = vsnprintf (nfrontp, - remaining, - format, - args); - if (ret >= remaining) - ret = remaining - 1; + remaining, + format, + args); nfrontp += ret; va_end(args); return ret; diff --git a/libexec/telnetd/mini_inetd.c b/libexec/telnetd/mini_inetd.c new file mode 100644 index 00000000000..a240e306f13 --- /dev/null +++ b/libexec/telnetd/mini_inetd.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 1995 - 2000 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * 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 Institute 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 INSTITUTE 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 INSTITUTE 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. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +RCSID("$KTH: mini_inetd.c,v 1.28 2000/10/08 13:38:47 assar Exp $"); +#endif + +#include "telnetd.h" + +#include <err.h> + +#ifndef max +#define max(a,b) (((a)>(b))?(a):(b)) +#endif + +/* + * accept a connection on `s' and pretend it's served by inetd. + */ + +static void +accept_it (int s) +{ + int s2; + + s2 = accept(s, NULL, NULL); + if(s2 < 0) + err (1, "accept"); + close(s); + dup2(s2, STDIN_FILENO); + dup2(s2, STDOUT_FILENO); + /* dup2(s2, STDERR_FILENO); */ + close(s2); +} + +/* + * Listen on `port' emulating inetd. + */ + +void +mini_inetd (int port) +{ + int error, ret; + struct addrinfo *ai, *a, hints; + char portstr[NI_MAXSERV]; + int n, nalloc, i; + int *fds; + fd_set orig_read_set, read_set; + int max_fd = -1; + + memset (&hints, 0, sizeof(hints)); + hints.ai_flags = AI_PASSIVE; + hints.ai_socktype = SOCK_STREAM; + + snprintf (portstr, sizeof(portstr), "%d", ntohs(port)); + + error = getaddrinfo (NULL, portstr, &hints, &ai); + if (error) + errx (1, "getaddrinfo: %s", gai_strerror (error)); + + for (nalloc = 0, a = ai; a != NULL; a = a->ai_next) + ++nalloc; + + fds = malloc (nalloc * sizeof(*fds)); + if (fds == NULL) + errx (1, "mini_inetd: out of memory"); + + FD_ZERO(&orig_read_set); + + for (i = 0, a = ai; a != NULL; a = a->ai_next) { + fds[i] = socket (a->ai_family, a->ai_socktype, a->ai_protocol); + if (fds[i] < 0) { + warn ("socket"); + continue; + } + socket_set_reuseaddr (fds[i], 1); + if (bind (fds[i], a->ai_addr, a->ai_addrlen) < 0) + err (1, "bind"); + if (listen (fds[i], SOMAXCONN) < 0) + err (1, "listen"); + if (fds[i] >= FD_SETSIZE) + errx (1, "fd too large"); + FD_SET(fds[i], &orig_read_set); + max_fd = max(max_fd, fds[i]); + ++i; + } + freeaddrinfo (ai); + if (i == 0) + errx (1, "no sockets"); + n = i; + + do { + read_set = orig_read_set; + + ret = select (max_fd + 1, &read_set, NULL, NULL, NULL); + if (ret < 0 && errno != EINTR) + err (1, "select"); + } while (ret <= 0); + + for (i = 0; i < n; ++i) + if (FD_ISSET (fds[i], &read_set)) { + accept_it (fds[i]); + return; + } + abort (); +} diff --git a/libexec/telnetd/pathnames.h b/libexec/telnetd/pathnames.h deleted file mode 100644 index 1b4cfe799cd..00000000000 --- a/libexec/telnetd/pathnames.h +++ /dev/null @@ -1,58 +0,0 @@ -/* $OpenBSD: pathnames.h,v 1.2 1996/03/28 23:21:57 niklas Exp $ */ -/* $NetBSD: pathnames.h,v 1.5 1996/02/28 20:38:15 thorpej Exp $ */ - -/* - * Copyright (c) 1989, 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. 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: @(#)pathnames.h 8.1 (Berkeley) 6/4/93 - */ - -#if BSD > 43 - -# include <paths.h> - -# ifndef _PATH_LOGIN -# define _PATH_LOGIN "/usr/bin/login" -# endif - -#else - -# define _PATH_TTY "/dev/tty" -# ifndef _PATH_LOGIN -# define _PATH_LOGIN "/bin/login" -# endif - -#endif - -#ifdef BFTPDAEMON -#define BFTPPATH "/usr/ucb/bftp" -#endif /* BFTPDAEMON */ diff --git a/libexec/telnetd/slc.c b/libexec/telnetd/slc.c index 2c4424b900d..519c0de9bc0 100644 --- a/libexec/telnetd/slc.c +++ b/libexec/telnetd/slc.c @@ -1,6 +1,3 @@ -/* $OpenBSD: slc.c,v 1.3 1998/03/25 18:43:45 art Exp $ */ -/* $NetBSD: slc.c,v 1.5 1996/02/28 20:38:16 thorpej Exp $ */ - /* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. @@ -34,468 +31,27 @@ * SUCH DAMAGE. */ -#ifndef lint -#if 0 -static char sccsid[] = "@(#)slc.c 8.1 (Berkeley) 6/4/93"; -static char rcsid[] = "$NetBSD: slc.c,v 1.5 1996/02/28 20:38:16 thorpej Exp $"; -#else -static char rcsid[] = "$OpenBSD: slc.c,v 1.3 1998/03/25 18:43:45 art Exp $"; -#endif -#endif /* not lint */ - #include "telnetd.h" -#ifdef LINEMODE -/* - * local varibles - */ -static unsigned char *def_slcbuf = (unsigned char *)0; -static int def_slclen = 0; -static int slcchange; /* change to slc is requested */ -static unsigned char *slcptr; /* pointer into slc buffer */ -static unsigned char slcbuf[NSLC*6]; /* buffer for slc negotiation */ - -/* - * send_slc - * - * Write out the current special characters to the client. - */ - void -send_slc() -{ - register int i; - - /* - * Send out list of triplets of special characters - * to client. We only send info on the characters - * that are currently supported. - */ - for (i = 1; i <= NSLC; i++) { - if ((slctab[i].defset.flag & SLC_LEVELBITS) == SLC_NOSUPPORT) - continue; - add_slc((unsigned char)i, slctab[i].current.flag, - slctab[i].current.val); - } - -} /* end of send_slc */ - -/* - * default_slc - * - * Set pty special characters to all the defaults. - */ - void -default_slc() -{ - register int i; - - for (i = 1; i <= NSLC; i++) { - slctab[i].current.val = slctab[i].defset.val; - if (slctab[i].current.val == (cc_t)(_POSIX_VDISABLE)) - slctab[i].current.flag = SLC_NOSUPPORT; - else - slctab[i].current.flag = slctab[i].defset.flag; - if (slctab[i].sptr) { - *(slctab[i].sptr) = slctab[i].defset.val; - } - } - slcchange = 1; - -} /* end of default_slc */ -#endif /* LINEMODE */ +/* RCSID("$KTH: slc.c,v 1.10 1997/05/11 06:30:00 assar Exp $"); */ /* * get_slc_defaults * * Initialize the slc mapping table. */ - void -get_slc_defaults() -{ - register int i; - - init_termbuf(); - - for (i = 1; i <= NSLC; i++) { - slctab[i].defset.flag = - spcset(i, &slctab[i].defset.val, &slctab[i].sptr); - slctab[i].current.flag = SLC_NOSUPPORT; - slctab[i].current.val = 0; - } - -} /* end of get_slc_defaults */ - -#ifdef LINEMODE -/* - * add_slc - * - * Add an slc triplet to the slc buffer. - */ - void -add_slc(func, flag, val) - register char func, flag; - register cc_t val; -{ - - if ((*slcptr++ = (unsigned char)func) == 0xff) - *slcptr++ = 0xff; - - if ((*slcptr++ = (unsigned char)flag) == 0xff) - *slcptr++ = 0xff; - - if ((*slcptr++ = (unsigned char)val) == 0xff) - *slcptr++ = 0xff; - -} /* end of add_slc */ - -/* - * start_slc - * - * Get ready to process incoming slc's and respond to them. - * - * The parameter getit is non-zero if it is necessary to grab a copy - * of the terminal control structures. - */ - void -start_slc(getit) - register int getit; -{ - - slcchange = 0; - if (getit) - init_termbuf(); - (void) sprintf((char *)slcbuf, "%c%c%c%c", - IAC, SB, TELOPT_LINEMODE, LM_SLC); - slcptr = slcbuf + 4; - -} /* end of start_slc */ - -/* - * end_slc - * - * Finish up the slc negotiation. If something to send, then send it. - */ - int -end_slc(bufp) - register unsigned char **bufp; -{ - register int len; - void netflush(); - - /* - * If a change has occured, store the new terminal control - * structures back to the terminal driver. - */ - if (slcchange) { - set_termbuf(); - } - - /* - * If the pty state has not yet been fully processed and there is a - * deferred slc request from the client, then do not send any - * sort of slc negotiation now. We will respond to the client's - * request very soon. - */ - if (def_slcbuf && (terminit() == 0)) { - return(0); - } - - if (slcptr > (slcbuf + 4)) { - if (bufp) { - *bufp = &slcbuf[4]; - return(slcptr - slcbuf - 4); - } else { - (void) sprintf((char *)slcptr, "%c%c", IAC, SE); - slcptr += 2; - len = slcptr - slcbuf; - writenet(slcbuf, len); - netflush(); /* force it out immediately */ - DIAG(TD_OPTIONS, printsub('>', slcbuf+2, len-2);); - } - } - return (0); - -} /* end of end_slc */ - -/* - * process_slc - * - * Figure out what to do about the client's slc - */ - void -process_slc(func, flag, val) - register unsigned char func, flag; - register cc_t val; -{ - register int hislevel, mylevel, ack; - - /* - * Ensure that we know something about this function - */ - if (func > NSLC) { - add_slc(func, SLC_NOSUPPORT, 0); - return; - } - - /* - * Process the special case requests of 0 SLC_DEFAULT 0 - * and 0 SLC_VARIABLE 0. Be a little forgiving here, don't - * worry about whether the value is actually 0 or not. - */ - if (func == 0) { - if ((flag = flag & SLC_LEVELBITS) == SLC_DEFAULT) { - default_slc(); - send_slc(); - } else if (flag == SLC_VARIABLE) { - send_slc(); - } - return; - } - - /* - * Appears to be a function that we know something about. So - * get on with it and see what we know. - */ - - hislevel = flag & SLC_LEVELBITS; - mylevel = slctab[func].current.flag & SLC_LEVELBITS; - ack = flag & SLC_ACK; - /* - * ignore the command if: - * the function value and level are the same as what we already have; - * or the level is the same and the ack bit is set - */ - if (hislevel == mylevel && (val == slctab[func].current.val || ack)) { - return; - } else if (ack) { - /* - * If we get here, we got an ack, but the levels don't match. - * This shouldn't happen. If it does, it is probably because - * we have sent two requests to set a variable without getting - * a response between them, and this is the first response. - * So, ignore it, and wait for the next response. - */ - return; - } else { - change_slc(func, flag, val); - } - -} /* end of process_slc */ - -/* - * change_slc - * - * Process a request to change one of our special characters. - * Compare client's request with what we are capable of supporting. - */ - void -change_slc(func, flag, val) - register int func, flag; - register cc_t val; -{ - register int hislevel, mylevel; - - hislevel = flag & SLC_LEVELBITS; - mylevel = slctab[func].defset.flag & SLC_LEVELBITS; - /* - * If client is setting a function to NOSUPPORT - * or DEFAULT, then we can easily and directly - * accomodate the request. - */ - if (hislevel == SLC_NOSUPPORT) { - slctab[func].current.flag = flag; - slctab[func].current.val = (cc_t)_POSIX_VDISABLE; - flag |= SLC_ACK; - add_slc(func, flag, val); - return; - } - if (hislevel == SLC_DEFAULT) { - /* - * Special case here. If client tells us to use - * the default on a function we don't support, then - * return NOSUPPORT instead of what we may have as a - * default level of DEFAULT. - */ - if (mylevel == SLC_DEFAULT) { - slctab[func].current.flag = SLC_NOSUPPORT; - } else { - slctab[func].current.flag = slctab[func].defset.flag; - } - slctab[func].current.val = slctab[func].defset.val; - add_slc(func, slctab[func].current.flag, - slctab[func].current.val); - return; - } - - /* - * Client wants us to change to a new value or he - * is telling us that he can't change to our value. - * Some of the slc's we support and can change, - * some we do support but can't change, - * and others we don't support at all. - * If we can change it then we have a pointer to - * the place to put the new value, so change it, - * otherwise, continue the negotiation. - */ - if (slctab[func].sptr) { - /* - * We can change this one. - */ - slctab[func].current.val = val; - *(slctab[func].sptr) = val; - slctab[func].current.flag = flag; - flag |= SLC_ACK; - slcchange = 1; - add_slc(func, flag, val); - } else { - /* - * It is not possible for us to support this - * request as he asks. - * - * If our level is DEFAULT, then just ack whatever was - * sent. - * - * If he can't change and we can't change, - * then degenerate to NOSUPPORT. - * - * Otherwise we send our level back to him, (CANTCHANGE - * or NOSUPPORT) and if CANTCHANGE, send - * our value as well. - */ - if (mylevel == SLC_DEFAULT) { - slctab[func].current.flag = flag; - slctab[func].current.val = val; - flag |= SLC_ACK; - } else if (hislevel == SLC_CANTCHANGE && - mylevel == SLC_CANTCHANGE) { - flag &= ~SLC_LEVELBITS; - flag |= SLC_NOSUPPORT; - slctab[func].current.flag = flag; - } else { - flag &= ~SLC_LEVELBITS; - flag |= mylevel; - slctab[func].current.flag = flag; - if (mylevel == SLC_CANTCHANGE) { - slctab[func].current.val = - slctab[func].defset.val; - val = slctab[func].current.val; - } - - } - add_slc(func, flag, val); - } - -} /* end of change_slc */ - -#if defined(USE_TERMIO) && (VEOF == VMIN) -cc_t oldeofc = '\004'; -#endif - -/* - * check_slc - * - * Check the special characters in use and notify the client if any have - * changed. Only those characters that are capable of being changed are - * likely to have changed. If a local change occurs, kick the support level - * and flags up to the defaults. - */ - void -check_slc() -{ - register int i; - - for (i = 1; i <= NSLC; i++) { -#if defined(USE_TERMIO) && (VEOF == VMIN) - /* - * In a perfect world this would be a neat little - * function. But in this world, we should not notify - * client of changes to the VEOF char when - * ICANON is off, because it is not representing - * a special character. - */ - if (i == SLC_EOF) { - if (!tty_isediting()) - continue; - else if (slctab[i].sptr) - oldeofc = *(slctab[i].sptr); - } -#endif /* defined(USE_TERMIO) && defined(SYSV_TERMIO) */ - if (slctab[i].sptr && - (*(slctab[i].sptr) != slctab[i].current.val)) { - slctab[i].current.val = *(slctab[i].sptr); - if (*(slctab[i].sptr) == (cc_t)_POSIX_VDISABLE) - slctab[i].current.flag = SLC_NOSUPPORT; - else - slctab[i].current.flag = slctab[i].defset.flag; - add_slc((unsigned char)i, slctab[i].current.flag, - slctab[i].current.val); - } - } - -} /* check_slc */ - -/* - * do_opt_slc - * - * Process an slc option buffer. Defer processing of incoming slc's - * until after the terminal state has been processed. Save the first slc - * request that comes along, but discard all others. - * - * ptr points to the beginning of the buffer, len is the length. - */ - void -do_opt_slc(ptr, len) - register unsigned char *ptr; - register int len; -{ - register unsigned char func, flag; - cc_t val; - register unsigned char *end = ptr + len; - - if (terminit()) { /* go ahead */ - while (ptr < end) { - func = *ptr++; - if (ptr >= end) break; - flag = *ptr++; - if (ptr >= end) break; - val = (cc_t)*ptr++; - - process_slc(func, flag, val); - - } - } else { - /* - * save this slc buffer if it is the first, otherwise dump - * it. - */ - if (def_slcbuf == (unsigned char *)0) { - def_slclen = len; - def_slcbuf = (unsigned char *)malloc((unsigned)len); - if (def_slcbuf == (unsigned char *)0) - return; /* too bad */ - bcopy(ptr, def_slcbuf, len); - } - } - -} /* end of do_opt_slc */ - -/* - * deferslc - * - * Do slc stuff that was deferred. - */ - void -deferslc() -{ - if (def_slcbuf) { - start_slc(1); - do_opt_slc(def_slcbuf, def_slclen); - (void) end_slc(0); - free(def_slcbuf); - def_slcbuf = (unsigned char *)0; - def_slclen = 0; - } - -} /* end of deferslc */ - -#endif /* LINEMODE */ +void +get_slc_defaults(void) +{ + int i; + + init_termbuf(); + + for (i = 1; i <= NSLC; i++) { + slctab[i].defset.flag = + spcset(i, &slctab[i].defset.val, &slctab[i].sptr); + slctab[i].current.flag = SLC_NOSUPPORT; + slctab[i].current.val = 0; + } + +} diff --git a/libexec/telnetd/socket.c b/libexec/telnetd/socket.c new file mode 100644 index 00000000000..d47970d2376 --- /dev/null +++ b/libexec/telnetd/socket.c @@ -0,0 +1,265 @@ +/* + * Copyright (c) 1999 - 2000 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * 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 Institute 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 INSTITUTE 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 INSTITUTE 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. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +RCSID("$KTH: socket.c,v 1.5 2000/07/27 04:41:06 assar Exp $"); +#endif + +#include <telnetd.h> +#include <err.h> +#include <netinet/in.h> + +/* + * Set `sa' to the unitialized address of address family `af' + */ + +void +socket_set_any (struct sockaddr *sa, int af) +{ + switch (af) { + case AF_INET : { + struct sockaddr_in *sin = (struct sockaddr_in *)sa; + + memset (sin, 0, sizeof(*sin)); + sin->sin_family = AF_INET; + sin->sin_port = 0; + sin->sin_addr.s_addr = INADDR_ANY; + break; + } +#ifdef HAVE_IPV6 + case AF_INET6 : { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; + + memset (sin6, 0, sizeof(*sin6)); + sin6->sin6_family = AF_INET6; + sin6->sin6_port = 0; + sin6->sin6_addr = in6addr_any; + break; + } +#endif + default : + errx (1, "unknown address family %d", sa->sa_family); + break; + } +} + +/* + * set `sa' to (`ptr', `port') + */ + +void +socket_set_address_and_port (struct sockaddr *sa, const void *ptr, int port) +{ + switch (sa->sa_family) { + case AF_INET : { + struct sockaddr_in *sin = (struct sockaddr_in *)sa; + + memset (sin, 0, sizeof(*sin)); + sin->sin_family = AF_INET; + sin->sin_port = port; + memcpy (&sin->sin_addr, ptr, sizeof(struct in_addr)); + break; + } +#ifdef HAVE_IPV6 + case AF_INET6 : { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; + + memset (sin6, 0, sizeof(*sin6)); + sin6->sin6_family = AF_INET6; + sin6->sin6_port = port; + memcpy (&sin6->sin6_addr, ptr, sizeof(struct in6_addr)); + break; + } +#endif + default : + errx (1, "unknown address family %d", sa->sa_family); + break; + } +} + +/* + * Return the size of an address of the type in `sa' + */ + +size_t +socket_addr_size (const struct sockaddr *sa) +{ + switch (sa->sa_family) { + case AF_INET : + return sizeof(struct in_addr); +#ifdef HAVE_IPV6 + case AF_INET6 : + return sizeof(struct in6_addr); +#endif + default : + errx (1, "unknown address family %d", sa->sa_family); + break; + } +} + +/* + * Return the size of a `struct sockaddr' in `sa'. + */ + +size_t +socket_sockaddr_size (const struct sockaddr *sa) +{ + switch (sa->sa_family) { + case AF_INET : + return sizeof(struct sockaddr_in); +#ifdef HAVE_IPV6 + case AF_INET6 : + return sizeof(struct sockaddr_in6); +#endif + default : + errx (1, "unknown address family %d", sa->sa_family); + break; + } +} + +/* + * Return the binary address of `sa'. + */ + +void * +socket_get_address (struct sockaddr *sa) +{ + switch (sa->sa_family) { + case AF_INET : { + struct sockaddr_in *sin = (struct sockaddr_in *)sa; + return &sin->sin_addr; + } +#ifdef HAVE_IPV6 + case AF_INET6 : { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; + return &sin6->sin6_addr; + } +#endif + default : + errx (1, "unknown address family %d", sa->sa_family); + break; + } +} + +/* + * Return the port number from `sa'. + */ + +int +socket_get_port (const struct sockaddr *sa) +{ + switch (sa->sa_family) { + case AF_INET : { + const struct sockaddr_in *sin = (const struct sockaddr_in *)sa; + return sin->sin_port; + } +#ifdef HAVE_IPV6 + case AF_INET6 : { + const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa; + return sin6->sin6_port; + } +#endif + default : + errx (1, "unknown address family %d", sa->sa_family); + break; + } +} + +/* + * Set the port in `sa' to `port'. + */ + +void +socket_set_port (struct sockaddr *sa, int port) +{ + switch (sa->sa_family) { + case AF_INET : { + struct sockaddr_in *sin = (struct sockaddr_in *)sa; + sin->sin_port = port; + break; + } +#ifdef HAVE_IPV6 + case AF_INET6 : { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; + sin6->sin6_port = port; + break; + } +#endif + default : + errx (1, "unknown address family %d", sa->sa_family); + break; + } +} + +/* + * Enable debug on `sock'. + */ + +void +socket_set_debug (int sock) +{ +#if defined(SO_DEBUG) && defined(HAVE_SETSOCKOPT) + int on = 1; + + if (setsockopt (sock, SOL_SOCKET, SO_DEBUG, (void *) &on, sizeof (on)) < 0) + warn ("setsockopt SO_DEBUG (ignored)"); +#endif +} + +/* + * Set the type-of-service of `sock' to `tos'. + */ + +void +socket_set_tos (int sock, int tos) +{ +#if defined(IP_TOS) && defined(HAVE_SETSOCKOPT) + if (setsockopt (sock, IPPROTO_IP, IP_TOS, (void *) &tos, sizeof (int)) < 0) + warn ("setsockopt TOS (ignored)"); +#endif +} + +/* + * set the reuse of addresses on `sock' to `val'. + */ + +void +socket_set_reuseaddr (int sock, int val) +{ +#if defined(SO_REUSEADDR) && defined(HAVE_SETSOCKOPT) + if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&val, + sizeof(val)) < 0) + err (1, "setsockopt SO_REUSEADDR"); +#endif +} diff --git a/libexec/telnetd/state.c b/libexec/telnetd/state.c index 2c9d2bb9a3b..3d8428852b9 100644 --- a/libexec/telnetd/state.c +++ b/libexec/telnetd/state.c @@ -1,6 +1,3 @@ -/* $OpenBSD: state.c,v 1.13 2000/12/08 10:11:42 hin Exp $ */ -/* $NetBSD: state.c,v 1.9 1996/02/28 20:38:19 thorpej Exp $ */ - /* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. @@ -34,22 +31,10 @@ * SUCH DAMAGE. */ -#ifndef lint -#if 0 -static char sccsid[] = "@(#)state.c 8.5 (Berkeley) 5/30/95"; -static char rcsid[] = "$NetBSD: state.c,v 1.9 1996/02/28 20:38:19 thorpej Exp $"; -#else -static char rcsid[] = "$OpenBSD: state.c,v 1.13 2000/12/08 10:11:42 hin Exp $"; -#endif -#endif /* not lint */ - #include "telnetd.h" -#if defined(AUTHENTICATION) -#include <libtelnet/auth.h> -#endif -#if defined(ENCRYPTION) -#include <libtelnet/encrypt.h> -#endif +#include <syslog.h> + +/* RCSID("$KTH: state.c,v 1.14 2000/10/02 05:06:02 assar Exp $"); */ unsigned char doopt[] = { IAC, DO, '%', 'c', 0 }; unsigned char dont[] = { IAC, DONT, '%', 'c', 0 }; @@ -61,13 +46,13 @@ int not42 = 1; * Buffer for sub-options, and macros * for suboptions buffer manipulations */ -unsigned char subbuffer[512], *subpointer= subbuffer, *subend= subbuffer; +unsigned char subbuffer[2048], *subpointer= subbuffer, *subend= subbuffer; #define SB_CLEAR() subpointer = subbuffer #define SB_TERM() { subend = subpointer; SB_CLEAR(); } #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ - *subpointer++ = (c); \ - } + *subpointer++ = (c); \ + } #define SB_GET() ((*subpointer++)&0xff) #define SB_EOF() (subpointer >= subend) #define SB_LEN() (subend - subpointer) @@ -88,286 +73,276 @@ unsigned char *subsave; #define TS_SB 3 /* throw away begin's... */ #define TS_SE 4 /* ...end's (suboption negotiation) */ #define TS_WILL 5 /* will option negotiation */ -#define TS_WONT 6 /* wont " */ -#define TS_DO 7 /* do " */ -#define TS_DONT 8 /* dont " */ +#define TS_WONT 6 /* wont -''- */ +#define TS_DO 7 /* do -''- */ +#define TS_DONT 8 /* dont -''- */ - void -telrcv() +void +telrcv(void) { - register int c; - static int state = TS_DATA; + int c; + static int state = TS_DATA; - while (ncc > 0) { - if ((&ptyobuf[BUFSIZ] - pfrontp) < 2) - break; - c = *netip++ & 0377, ncc--; + while (ncc > 0) { + if ((&ptyobuf[BUFSIZ] - pfrontp) < 2) + break; + c = *netip++ & 0377, ncc--; #ifdef ENCRYPTION - if (decrypt_input) - c = (*decrypt_input)(c); + if (decrypt_input) + c = (*decrypt_input)(c); #endif - switch (state) { + switch (state) { - case TS_CR: - state = TS_DATA; - /* Strip off \n or \0 after a \r */ - if ((c == 0) || (c == '\n')) { - break; - } - /* FALL THROUGH */ + case TS_CR: + state = TS_DATA; + /* Strip off \n or \0 after a \r */ + if ((c == 0) || (c == '\n')) { + break; + } + /* FALL THROUGH */ - case TS_DATA: - if (c == IAC) { - state = TS_IAC; - break; - } - /* - * We now map \r\n ==> \r for pragmatic reasons. - * Many client implementations send \r\n when - * the user hits the CarriageReturn key. - * - * We USED to map \r\n ==> \n, since \r\n says - * that we want to be in column 1 of the next - * printable line, and \n is the standard - * unix way of saying that (\r is only good - * if CRMOD is set, which it normally is). - */ - if ((c == '\r') && his_state_is_wont(TELOPT_BINARY)) { - int nc = *netip; + case TS_DATA: + if (c == IAC) { + state = TS_IAC; + break; + } + /* + * We now map \r\n ==> \r for pragmatic reasons. + * Many client implementations send \r\n when + * the user hits the CarriageReturn key. + * + * We USED to map \r\n ==> \n, since \r\n says + * that we want to be in column 1 of the next + * printable line, and \n is the standard + * unix way of saying that (\r is only good + * if CRMOD is set, which it normally is). + */ + if ((c == '\r') && his_state_is_wont(TELOPT_BINARY)) { + int nc = *netip; #ifdef ENCRYPTION - if (decrypt_input) - nc = (*decrypt_input)(nc & 0xff); -#endif -#ifdef LINEMODE - /* - * If we are operating in linemode, - * convert to local end-of-line. - */ - if (linemode && (ncc > 0) && (('\n' == nc) || - ((0 == nc) && tty_iscrnl())) ) { - netip++; ncc--; - c = '\n'; - } else + if (decrypt_input) + nc = (*decrypt_input)(nc & 0xff); #endif - { + { #ifdef ENCRYPTION - if (decrypt_input) - (void)(*decrypt_input)(-1); + if (decrypt_input) + (void)(*decrypt_input)(-1); #endif - state = TS_CR; - } - } - *pfrontp++ = c; - break; + state = TS_CR; + } + } + *pfrontp++ = c; + break; - case TS_IAC: -gotiac: switch (c) { - - /* - * Send the process on the pty side an - * interrupt. Do this with a NULL or - * interrupt char; depending on the tty mode. - */ - case IP: - DIAG(TD_OPTIONS, - printoption("td: recv IAC", c)); - interrupt(); - break; - - case BREAK: - DIAG(TD_OPTIONS, - printoption("td: recv IAC", c)); - sendbrk(); - break; - - /* - * Are You There? - */ - case AYT: - DIAG(TD_OPTIONS, - printoption("td: recv IAC", c)); - recv_ayt(); - break; - - /* - * Abort Output - */ - case AO: - { - DIAG(TD_OPTIONS, - printoption("td: recv IAC", c)); - ptyflush(); /* half-hearted */ - init_termbuf(); - - if (slctab[SLC_AO].sptr && - *slctab[SLC_AO].sptr != (cc_t)(_POSIX_VDISABLE)) { - *pfrontp++ = - (unsigned char)*slctab[SLC_AO].sptr; - } - - netclear(); /* clear buffer back */ - *nfrontp++ = IAC; - *nfrontp++ = DM; - neturg = nfrontp-1; /* off by one XXX */ - DIAG(TD_OPTIONS, - printoption("td: send IAC", DM)); - break; - } + case TS_IAC: + gotiac: switch (c) { - /* - * Erase Character and - * Erase Line - */ - case EC: - case EL: - { - cc_t ch; - - DIAG(TD_OPTIONS, - printoption("td: recv IAC", c)); - ptyflush(); /* half-hearted */ - init_termbuf(); - if (c == EC) - ch = *slctab[SLC_EC].sptr; - else - ch = *slctab[SLC_EL].sptr; - if (ch != (cc_t)(_POSIX_VDISABLE)) - *pfrontp++ = (unsigned char)ch; - break; - } + /* + * Send the process on the pty side an + * interrupt. Do this with a NULL or + * interrupt char; depending on the tty mode. + */ + case IP: + DIAG(TD_OPTIONS, + printoption("td: recv IAC", c)); + interrupt(); + break; - /* - * Check for urgent data... - */ - case DM: - DIAG(TD_OPTIONS, - printoption("td: recv IAC", c)); - SYNCHing = stilloob(net); - settimer(gotDM); - break; - - - /* - * Begin option subnegotiation... - */ - case SB: - state = TS_SB; - SB_CLEAR(); - continue; - - case WILL: - state = TS_WILL; - continue; - - case WONT: - state = TS_WONT; - continue; - - case DO: - state = TS_DO; - continue; - - case DONT: - state = TS_DONT; - continue; - case EOR: - if (his_state_is_will(TELOPT_EOR)) - doeof(); - break; - - /* - * Handle RFC 10xx Telnet linemode option additions - * to command stream (EOF, SUSP, ABORT). - */ - case xEOF: - doeof(); - break; - - case SUSP: - sendsusp(); - break; - - case ABORT: - sendbrk(); - break; - - case IAC: - *pfrontp++ = c; - break; - } - state = TS_DATA; - break; + case BREAK: + DIAG(TD_OPTIONS, + printoption("td: recv IAC", c)); + sendbrk(); + break; - case TS_SB: - if (c == IAC) { - state = TS_SE; - } else { - SB_ACCUM(c); - } - break; + /* + * Are You There? + */ + case AYT: + DIAG(TD_OPTIONS, + printoption("td: recv IAC", c)); + recv_ayt(); + break; - case TS_SE: - if (c != SE) { - if (c != IAC) { - /* - * bad form of suboption negotiation. - * handle it in such a way as to avoid - * damage to local state. Parse - * suboption buffer found so far, - * then treat remaining stream as - * another command sequence. - */ - - /* for DIAGNOSTICS */ - SB_ACCUM(IAC); - SB_ACCUM(c); - subpointer -= 2; - - SB_TERM(); - suboption(); - state = TS_IAC; - goto gotiac; - } - SB_ACCUM(c); - state = TS_SB; - } else { - /* for DIAGNOSTICS */ - SB_ACCUM(IAC); - SB_ACCUM(SE); - subpointer -= 2; - - SB_TERM(); - suboption(); /* handle sub-option */ - state = TS_DATA; - } - break; + /* + * Abort Output + */ + case AO: + { + DIAG(TD_OPTIONS, + printoption("td: recv IAC", c)); + ptyflush(); /* half-hearted */ + init_termbuf(); + + if (slctab[SLC_AO].sptr && + *slctab[SLC_AO].sptr != (cc_t)(_POSIX_VDISABLE)) { + *pfrontp++ = + (unsigned char)*slctab[SLC_AO].sptr; + } + + netclear(); /* clear buffer back */ + output_data ("%c%c", IAC, DM); + neturg = nfrontp-1; /* off by one XXX */ + DIAG(TD_OPTIONS, + printoption("td: send IAC", DM)); + break; + } - case TS_WILL: - willoption(c); - state = TS_DATA; - continue; - - case TS_WONT: - wontoption(c); - state = TS_DATA; - continue; - - case TS_DO: - dooption(c); - state = TS_DATA; - continue; - - case TS_DONT: - dontoption(c); - state = TS_DATA; - continue; - - default: - syslog(LOG_ERR, "telnetd: panic state=%d", state); - printf("telnetd: panic state=%d\n", state); - exit(1); + /* + * Erase Character and + * Erase Line + */ + case EC: + case EL: + { + cc_t ch; + + DIAG(TD_OPTIONS, + printoption("td: recv IAC", c)); + ptyflush(); /* half-hearted */ + init_termbuf(); + if (c == EC) + ch = *slctab[SLC_EC].sptr; + else + ch = *slctab[SLC_EL].sptr; + if (ch != (cc_t)(_POSIX_VDISABLE)) + *pfrontp++ = (unsigned char)ch; + break; + } + + /* + * Check for urgent data... + */ + case DM: + DIAG(TD_OPTIONS, + printoption("td: recv IAC", c)); + SYNCHing = stilloob(net); + settimer(gotDM); + break; + + + /* + * Begin option subnegotiation... + */ + case SB: + state = TS_SB; + SB_CLEAR(); + continue; + + case WILL: + state = TS_WILL; + continue; + + case WONT: + state = TS_WONT; + continue; + + case DO: + state = TS_DO; + continue; + + case DONT: + state = TS_DONT; + continue; + case EOR: + if (his_state_is_will(TELOPT_EOR)) + doeof(); + break; + + /* + * Handle RFC 10xx Telnet linemode option additions + * to command stream (EOF, SUSP, ABORT). + */ + case xEOF: + doeof(); + break; + + case SUSP: + sendsusp(); + break; + + case ABORT: + sendbrk(); + break; + + case IAC: + *pfrontp++ = c; + break; + } + state = TS_DATA; + break; + + case TS_SB: + if (c == IAC) { + state = TS_SE; + } else { + SB_ACCUM(c); + } + break; + + case TS_SE: + if (c != SE) { + if (c != IAC) { + /* + * bad form of suboption negotiation. + * handle it in such a way as to avoid + * damage to local state. Parse + * suboption buffer found so far, + * then treat remaining stream as + * another command sequence. + */ + + /* for DIAGNOSTICS */ + SB_ACCUM(IAC); + SB_ACCUM(c); + subpointer -= 2; + + SB_TERM(); + suboption(); + state = TS_IAC; + goto gotiac; } + SB_ACCUM(c); + state = TS_SB; + } else { + /* for DIAGNOSTICS */ + SB_ACCUM(IAC); + SB_ACCUM(SE); + subpointer -= 2; + + SB_TERM(); + suboption(); /* handle sub-option */ + state = TS_DATA; + } + break; + + case TS_WILL: + willoption(c); + state = TS_DATA; + continue; + + case TS_WONT: + wontoption(c); + if (c==TELOPT_ENCRYPT && his_do_dont_is_changing(TELOPT_ENCRYPT) ) + dontoption(c); + state = TS_DATA; + continue; + + case TS_DO: + dooption(c); + state = TS_DATA; + continue; + + case TS_DONT: + dontoption(c); + state = TS_DATA; + continue; + + default: + syslog(LOG_ERR, "telnetd: panic state=%d\n", state); + printf("telnetd: panic state=%d\n", state); + exit(1); } + } } /* end of telrcv */ /* @@ -426,322 +401,246 @@ gotiac: switch (c) { * is complete. * */ - void -send_do(option, init) - int option, init; +void +send_do(int option, int init) { - if (init) { - if ((do_dont_resp[option] == 0 && his_state_is_will(option)) || - his_want_state_is_will(option)) - return; - /* - * Special case for TELOPT_TM: We send a DO, but pretend - * that we sent a DONT, so that we can send more DOs if - * we want to. - */ - if (option == TELOPT_TM) - set_his_want_state_wont(option); - else - set_his_want_state_will(option); - do_dont_resp[option]++; - } - (void) sprintf(nfrontp, (char *)doopt, option); - nfrontp += sizeof (dont) - 2; - - DIAG(TD_OPTIONS, printoption("td: send do", option)); + if (init) { + if ((do_dont_resp[option] == 0 && his_state_is_will(option)) || + his_want_state_is_will(option)) + return; + /* + * Special case for TELOPT_TM: We send a DO, but pretend + * that we sent a DONT, so that we can send more DOs if + * we want to. + */ + if (option == TELOPT_TM) + set_his_want_state_wont(option); + else + set_his_want_state_will(option); + do_dont_resp[option]++; + } + output_data((const char *)doopt, option); + + DIAG(TD_OPTIONS, printoption("td: send do", option)); } #ifdef AUTHENTICATION extern void auth_request(void); #endif -#ifdef LINEMODE -extern void doclientstat(); -#endif -#ifdef ENCRYPTION +#ifdef ENCRYPTION extern void encrypt_send_support(); #endif - - void -willoption(option) - int option; +void +willoption(int option) { - int changeok = 0; - void (*func)() = 0; - - /* - * process input from peer. - */ - - DIAG(TD_OPTIONS, printoption("td: recv will", option)); + int changeok = 0; + void (*func)() = 0; + + /* + * process input from peer. + */ + + DIAG(TD_OPTIONS, printoption("td: recv will", option)); + + if (do_dont_resp[option]) { + do_dont_resp[option]--; + if (do_dont_resp[option] && his_state_is_will(option)) + do_dont_resp[option]--; + } + if (do_dont_resp[option] == 0) { + if (his_want_state_is_wont(option)) { + switch (option) { + + case TELOPT_BINARY: + init_termbuf(); + tty_binaryin(1); + set_termbuf(); + changeok++; + break; - if (do_dont_resp[option]) { - do_dont_resp[option]--; - if (do_dont_resp[option] && his_state_is_will(option)) - do_dont_resp[option]--; - } - if (do_dont_resp[option] == 0) { - if (his_want_state_is_wont(option)) { - switch (option) { - - case TELOPT_BINARY: - init_termbuf(); - tty_binaryin(1); - set_termbuf(); - changeok++; - break; + case TELOPT_ECHO: + /* + * See comments below for more info. + */ + not42 = 0; /* looks like a 4.2 system */ + break; - case TELOPT_ECHO: - /* - * See comments below for more info. - */ - not42 = 0; /* looks like a 4.2 system */ - break; + case TELOPT_TM: + /* + * We never respond to a WILL TM, and + * we leave the state WONT. + */ + return; - case TELOPT_TM: -#if defined(LINEMODE) && defined(KLUDGELINEMODE) - /* - * This telnetd implementation does not really - * support timing marks, it just uses them to - * support the kludge linemode stuff. If we - * receive a will or wont TM in response to our - * do TM request that may have been sent to - * determine kludge linemode support, process - * it, otherwise TM should get a negative - * response back. - */ - /* - * Handle the linemode kludge stuff. - * If we are not currently supporting any - * linemode at all, then we assume that this - * is the client telling us to use kludge - * linemode in response to our query. Set the - * linemode type that is to be supported, note - * that the client wishes to use linemode, and - * eat the will TM as though it never arrived. - */ - if (lmodetype < KLUDGE_LINEMODE) { - lmodetype = KLUDGE_LINEMODE; - clientstat(TELOPT_LINEMODE, WILL, 0); - send_wont(TELOPT_SGA, 1); - } else if (lmodetype == NO_AUTOKLUDGE) { - lmodetype = KLUDGE_OK; - } -#endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ - /* - * We never respond to a WILL TM, and - * we leave the state WONT. - */ - return; - - case TELOPT_LFLOW: - /* - * If we are going to support flow control - * option, then don't worry peer that we can't - * change the flow control characters. - */ - slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS; - slctab[SLC_XON].defset.flag |= SLC_DEFAULT; - slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS; - slctab[SLC_XOFF].defset.flag |= SLC_DEFAULT; - case TELOPT_TTYPE: - case TELOPT_SGA: - case TELOPT_NAWS: - case TELOPT_TSPEED: - case TELOPT_XDISPLOC: - case TELOPT_NEW_ENVIRON: - case TELOPT_OLD_ENVIRON: - changeok++; - break; + case TELOPT_LFLOW: + /* + * If we are going to support flow control + * option, then don't worry peer that we can't + * change the flow control characters. + */ + slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS; + slctab[SLC_XON].defset.flag |= SLC_DEFAULT; + slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS; + slctab[SLC_XOFF].defset.flag |= SLC_DEFAULT; + case TELOPT_TTYPE: + case TELOPT_SGA: + case TELOPT_NAWS: + case TELOPT_TSPEED: + case TELOPT_XDISPLOC: + case TELOPT_NEW_ENVIRON: + case TELOPT_OLD_ENVIRON: + changeok++; + break; -#ifdef LINEMODE - case TELOPT_LINEMODE: -# ifdef KLUDGELINEMODE - /* - * Note client's desire to use linemode. - */ - lmodetype = REAL_LINEMODE; -# endif /* KLUDGELINEMODE */ - func = doclientstat; - changeok++; - break; -#endif /* LINEMODE */ #ifdef AUTHENTICATION - case TELOPT_AUTHENTICATION: - func = auth_request; - changeok++; - break; + case TELOPT_AUTHENTICATION: + func = auth_request; + changeok++; + break; #endif -#ifdef ENCRYPTION - case TELOPT_ENCRYPT: - func = encrypt_send_support; - changeok++; - break; +#ifdef ENCRYPTION + case TELOPT_ENCRYPT: + func = encrypt_send_support; + changeok++; + break; #endif - - default: - break; - } - if (changeok) { - set_his_want_state_will(option); - send_do(option, 0); - } else { - do_dont_resp[option]++; - send_dont(option, 0); - } + + default: + break; + } + if (changeok) { + set_his_want_state_will(option); + send_do(option, 0); } else { + do_dont_resp[option]++; + send_dont(option, 0); + } + } else { + /* + * Option processing that should happen when + * we receive conformation of a change in + * state that we had requested. + */ + switch (option) { + case TELOPT_ECHO: + not42 = 0; /* looks like a 4.2 system */ /* - * Option processing that should happen when - * we receive conformation of a change in - * state that we had requested. + * Egads, he responded "WILL ECHO". Turn + * it off right now! */ - switch (option) { - case TELOPT_ECHO: - not42 = 0; /* looks like a 4.2 system */ - /* - * Egads, he responded "WILL ECHO". Turn - * it off right now! - */ - send_dont(option, 1); - /* - * "WILL ECHO". Kludge upon kludge! - * A 4.2 client is now echoing user input at - * the tty. This is probably undesireable and - * it should be stopped. The client will - * respond WONT TM to the DO TM that we send to - * check for kludge linemode. When the WONT TM - * arrives, linemode will be turned off and a - * change propogated to the pty. This change - * will cause us to process the new pty state - * in localstat(), which will notice that - * linemode is off and send a WILL ECHO - * so that we are properly in character mode and - * all is well. - */ - break; -#ifdef LINEMODE - case TELOPT_LINEMODE: -# ifdef KLUDGELINEMODE - /* - * Note client's desire to use linemode. - */ - lmodetype = REAL_LINEMODE; -# endif /* KLUDGELINEMODE */ - func = doclientstat; - break; -#endif /* LINEMODE */ + send_dont(option, 1); + /* + * "WILL ECHO". Kludge upon kludge! + * A 4.2 client is now echoing user input at + * the tty. This is probably undesireable and + * it should be stopped. The client will + * respond WONT TM to the DO TM that we send to + * check for kludge linemode. When the WONT TM + * arrives, linemode will be turned off and a + * change propogated to the pty. This change + * will cause us to process the new pty state + * in localstat(), which will notice that + * linemode is off and send a WILL ECHO + * so that we are properly in character mode and + * all is well. + */ + break; #ifdef AUTHENTICATION - case TELOPT_AUTHENTICATION: - func = auth_request; - break; + case TELOPT_AUTHENTICATION: + func = auth_request; + break; #endif -#ifdef ENCRYPTION - case TELOPT_ENCRYPT: - func = encrypt_send_support; - break; +#ifdef ENCRYPTION + case TELOPT_ENCRYPT: + func = encrypt_send_support; + break; #endif - case TELOPT_LFLOW: - func = flowstat; - break; - } + case TELOPT_LFLOW: + func = flowstat; + break; } } - set_his_state_will(option); - if (func) - (*func)(); + } + set_his_state_will(option); + if (func) + (*func)(); } /* end of willoption */ - void -send_dont(option, init) - int option, init; +void +send_dont(int option, int init) { - if (init) { - if ((do_dont_resp[option] == 0 && his_state_is_wont(option)) || - his_want_state_is_wont(option)) - return; - set_his_want_state_wont(option); - do_dont_resp[option]++; - } - (void) sprintf(nfrontp, (char *)dont, option); - nfrontp += sizeof (doopt) - 2; - - DIAG(TD_OPTIONS, printoption("td: send dont", option)); + if (init) { + if ((do_dont_resp[option] == 0 && his_state_is_wont(option)) || + his_want_state_is_wont(option)) + return; + set_his_want_state_wont(option); + do_dont_resp[option]++; + } + output_data((const char *)dont, option); + + DIAG(TD_OPTIONS, printoption("td: send dont", option)); } - void -wontoption(option) - int option; +void +wontoption(int option) { - /* - * Process client input. + /* + * Process client input. */ - DIAG(TD_OPTIONS, printoption("td: recv wont", option)); + DIAG(TD_OPTIONS, printoption("td: recv wont", option)); + + if (do_dont_resp[option]) { + do_dont_resp[option]--; + if (do_dont_resp[option] && his_state_is_wont(option)) + do_dont_resp[option]--; + } + if (do_dont_resp[option] == 0) { + if (his_want_state_is_will(option)) { + /* it is always ok to change to negative state */ + switch (option) { + case TELOPT_ECHO: + not42 = 1; /* doesn't seem to be a 4.2 system */ + break; - if (do_dont_resp[option]) { - do_dont_resp[option]--; - if (do_dont_resp[option] && his_state_is_wont(option)) - do_dont_resp[option]--; - } - if (do_dont_resp[option] == 0) { - if (his_want_state_is_will(option)) { - /* it is always ok to change to negative state */ - switch (option) { - case TELOPT_ECHO: - not42 = 1; /* doesn't seem to be a 4.2 system */ - break; + case TELOPT_BINARY: + init_termbuf(); + tty_binaryin(0); + set_termbuf(); + break; - case TELOPT_BINARY: - init_termbuf(); - tty_binaryin(0); - set_termbuf(); - break; + case TELOPT_TM: + /* + * If we get a WONT TM, and had sent a DO TM, + * don't respond with a DONT TM, just leave it + * as is. Short circut the state machine to + * achive this. + */ + set_his_want_state_wont(TELOPT_TM); + return; -#ifdef LINEMODE - case TELOPT_LINEMODE: -# ifdef KLUDGELINEMODE - /* - * If real linemode is supported, then client is - * asking to turn linemode off. - */ - if (lmodetype != REAL_LINEMODE) - break; -# endif /* KLUDGELINEMODE */ - clientstat(TELOPT_LINEMODE, WONT, 0); - break; -#endif /* LINEMODE */ - - case TELOPT_TM: - /* - * If we get a WONT TM, and had sent a DO TM, - * don't respond with a DONT TM, just leave it - * as is. Short circut the state machine to - * achive this. - */ - set_his_want_state_wont(TELOPT_TM); - return; - - case TELOPT_LFLOW: - /* - * If we are not going to support flow control - * option, then let peer know that we can't - * change the flow control characters. - */ - slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS; - slctab[SLC_XON].defset.flag |= SLC_CANTCHANGE; - slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS; - slctab[SLC_XOFF].defset.flag |= SLC_CANTCHANGE; - break; + case TELOPT_LFLOW: + /* + * If we are not going to support flow control + * option, then let peer know that we can't + * change the flow control characters. + */ + slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS; + slctab[SLC_XON].defset.flag |= SLC_CANTCHANGE; + slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS; + slctab[SLC_XOFF].defset.flag |= SLC_CANTCHANGE; + break; -#if defined(AUTHENTICATION) - case TELOPT_AUTHENTICATION: - auth_finished(0, AUTH_REJECT); - break; +#ifdef AUTHENTICATION + case TELOPT_AUTHENTICATION: + auth_finished(0, AUTH_REJECT); + break; #endif /* @@ -752,77 +651,66 @@ wontoption(option) * to the sub-negotiation, (by updating the timers) * so that we'll break out of the loop. */ - case TELOPT_TTYPE: - settimer(ttypesubopt); - break; + case TELOPT_TTYPE: + settimer(ttypesubopt); + break; - case TELOPT_TSPEED: - settimer(tspeedsubopt); - break; + case TELOPT_TSPEED: + settimer(tspeedsubopt); + break; - case TELOPT_XDISPLOC: - settimer(xdisplocsubopt); - break; + case TELOPT_XDISPLOC: + settimer(xdisplocsubopt); + break; - case TELOPT_OLD_ENVIRON: - settimer(oenvironsubopt); - break; + case TELOPT_OLD_ENVIRON: + settimer(oenvironsubopt); + break; - case TELOPT_NEW_ENVIRON: - settimer(environsubopt); - break; + case TELOPT_NEW_ENVIRON: + settimer(environsubopt); + break; - default: - break; - } - set_his_want_state_wont(option); - if (his_state_is_will(option)) - send_dont(option, 0); - } else { - switch (option) { - case TELOPT_TM: -#if defined(LINEMODE) && defined(KLUDGELINEMODE) - if (lmodetype < NO_AUTOKLUDGE) { - lmodetype = NO_LINEMODE; - clientstat(TELOPT_LINEMODE, WONT, 0); - send_will(TELOPT_SGA, 1); - send_will(TELOPT_ECHO, 1); - } -#endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ - break; + default: + break; + } + set_his_want_state_wont(option); + if (his_state_is_will(option)) + send_dont(option, 0); + } else { + switch (option) { + case TELOPT_TM: + break; -#if defined(AUTHENTICATION) - case TELOPT_AUTHENTICATION: - auth_finished(0, AUTH_REJECT); - break; +#ifdef AUTHENTICATION + case TELOPT_AUTHENTICATION: + auth_finished(0, AUTH_REJECT); + break; #endif - default: - break; - } + default: + break; } } - set_his_state_wont(option); + } + set_his_state_wont(option); } /* end of wontoption */ - void -send_will(option, init) - int option, init; +void +send_will(int option, int init) { - if (init) { - if ((will_wont_resp[option] == 0 && my_state_is_will(option))|| - my_want_state_is_will(option)) - return; - set_my_want_state_will(option); - will_wont_resp[option]++; - } - (void) sprintf(nfrontp, (char *)will, option); - nfrontp += sizeof (doopt) - 2; - - DIAG(TD_OPTIONS, printoption("td: send will", option)); + if (init) { + if ((will_wont_resp[option] == 0 && my_state_is_will(option))|| + my_want_state_is_will(option)) + return; + set_my_want_state_will(option); + will_wont_resp[option]++; + } + output_data ((const char *)will, option); + + DIAG(TD_OPTIONS, printoption("td: send will", option)); } -#if !defined(LINEMODE) || !defined(KLUDGELINEMODE) /* * When we get a DONT SGA, we will try once to turn it * back on. If the other side responds DONT SGA, we @@ -831,238 +719,169 @@ send_will(option, init) * we'll keep them in char-at-a-time mode. */ int turn_on_sga = 0; -#endif - void -dooption(option) - int option; +void +dooption(int option) { - int changeok = 0; - - /* - * Process client input. - */ + int changeok = 0; + + /* + * Process client input. + */ + + DIAG(TD_OPTIONS, printoption("td: recv do", option)); + + if (will_wont_resp[option]) { + will_wont_resp[option]--; + if (will_wont_resp[option] && my_state_is_will(option)) + will_wont_resp[option]--; + } + if ((will_wont_resp[option] == 0) && (my_want_state_is_wont(option))) { + switch (option) { + case TELOPT_ECHO: + { + init_termbuf(); + tty_setecho(1); + set_termbuf(); + } + changeok++; + break; - DIAG(TD_OPTIONS, printoption("td: recv do", option)); + case TELOPT_BINARY: + init_termbuf(); + tty_binaryout(1); + set_termbuf(); + changeok++; + break; - if (will_wont_resp[option]) { - will_wont_resp[option]--; - if (will_wont_resp[option] && my_state_is_will(option)) - will_wont_resp[option]--; - } - if ((will_wont_resp[option] == 0) && (my_want_state_is_wont(option))) { - switch (option) { - case TELOPT_ECHO: -#ifdef LINEMODE -# ifdef KLUDGELINEMODE - if (lmodetype == NO_LINEMODE) -# else - if (his_state_is_wont(TELOPT_LINEMODE)) -# endif -#endif - { - init_termbuf(); - tty_setecho(1); - set_termbuf(); - } - changeok++; - break; + case TELOPT_SGA: + turn_on_sga = 0; + changeok++; + break; - case TELOPT_BINARY: - init_termbuf(); - tty_binaryout(1); - set_termbuf(); - changeok++; - break; + case TELOPT_STATUS: + changeok++; + break; - case TELOPT_SGA: -#if defined(LINEMODE) && defined(KLUDGELINEMODE) - /* - * If kludge linemode is in use, then we must - * process an incoming do SGA for linemode - * purposes. - */ - if (lmodetype == KLUDGE_LINEMODE) { - /* - * Receipt of "do SGA" in kludge - * linemode is the peer asking us to - * turn off linemode. Make note of - * the request. - */ - clientstat(TELOPT_LINEMODE, WONT, 0); - /* - * If linemode did not get turned off - * then don't tell peer that we did. - * Breaking here forces a wont SGA to - * be returned. - */ - if (linemode) - break; - } -#else - turn_on_sga = 0; -#endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ - changeok++; - break; + case TELOPT_TM: + /* + * Special case for TM. We send a WILL, but + * pretend we sent a WONT. + */ + send_will(option, 0); + set_my_want_state_wont(option); + set_my_state_wont(option); + return; - case TELOPT_STATUS: - changeok++; - break; + case TELOPT_LOGOUT: + /* + * When we get a LOGOUT option, respond + * with a WILL LOGOUT, make sure that + * it gets written out to the network, + * and then just go away... + */ + set_my_want_state_will(TELOPT_LOGOUT); + send_will(TELOPT_LOGOUT, 0); + set_my_state_will(TELOPT_LOGOUT); + netflush(); + cleanup(0); + /* NOT REACHED */ + break; - case TELOPT_TM: - /* - * Special case for TM. We send a WILL, but - * pretend we sent a WONT. - */ - send_will(option, 0); - set_my_want_state_wont(option); - set_my_state_wont(option); - return; - - case TELOPT_LOGOUT: - /* - * When we get a LOGOUT option, respond - * with a WILL LOGOUT, make sure that - * it gets written out to the network, - * and then just go away... - */ - set_my_want_state_will(TELOPT_LOGOUT); - send_will(TELOPT_LOGOUT, 0); - set_my_state_will(TELOPT_LOGOUT); - (void)netflush(); - cleanup(0); - /* NOT REACHED */ - break; #ifdef ENCRYPTION - case TELOPT_ENCRYPT: - changeok++; - break; + case TELOPT_ENCRYPT: + changeok++; + break; #endif - - case TELOPT_LINEMODE: - case TELOPT_TTYPE: - case TELOPT_NAWS: - case TELOPT_TSPEED: - case TELOPT_LFLOW: - case TELOPT_XDISPLOC: + case TELOPT_LINEMODE: + case TELOPT_TTYPE: + case TELOPT_NAWS: + case TELOPT_TSPEED: + case TELOPT_LFLOW: + case TELOPT_XDISPLOC: #ifdef TELOPT_ENVIRON - case TELOPT_NEW_ENVIRON: + case TELOPT_NEW_ENVIRON: #endif - case TELOPT_OLD_ENVIRON: - default: - break; - } - if (changeok) { - set_my_want_state_will(option); - send_will(option, 0); - } else { - will_wont_resp[option]++; - send_wont(option, 0); - } + case TELOPT_OLD_ENVIRON: + default: + break; + } + if (changeok) { + set_my_want_state_will(option); + send_will(option, 0); + } else { + will_wont_resp[option]++; + send_wont(option, 0); } - set_my_state_will(option); + } + set_my_state_will(option); } /* end of dooption */ - void -send_wont(option, init) - int option, init; +void +send_wont(int option, int init) { - if (init) { - if ((will_wont_resp[option] == 0 && my_state_is_wont(option)) || - my_want_state_is_wont(option)) - return; - set_my_want_state_wont(option); - will_wont_resp[option]++; - } - (void) sprintf(nfrontp, (char *)wont, option); - nfrontp += sizeof (wont) - 2; - - DIAG(TD_OPTIONS, printoption("td: send wont", option)); + if (init) { + if ((will_wont_resp[option] == 0 && my_state_is_wont(option)) || + my_want_state_is_wont(option)) + return; + set_my_want_state_wont(option); + will_wont_resp[option]++; + } + output_data ((const char *)wont, option); + + DIAG(TD_OPTIONS, printoption("td: send wont", option)); } - void -dontoption(option) - int option; +void +dontoption(int option) { - /* - * Process client input. + /* + * Process client input. */ - DIAG(TD_OPTIONS, printoption("td: recv dont", option)); + DIAG(TD_OPTIONS, printoption("td: recv dont", option)); - if (will_wont_resp[option]) { - will_wont_resp[option]--; - if (will_wont_resp[option] && my_state_is_wont(option)) - will_wont_resp[option]--; - } - if ((will_wont_resp[option] == 0) && (my_want_state_is_will(option))) { - switch (option) { - case TELOPT_BINARY: - init_termbuf(); - tty_binaryout(0); - set_termbuf(); - break; + if (will_wont_resp[option]) { + will_wont_resp[option]--; + if (will_wont_resp[option] && my_state_is_wont(option)) + will_wont_resp[option]--; + } + if ((will_wont_resp[option] == 0) && (my_want_state_is_will(option))) { + switch (option) { + case TELOPT_BINARY: + init_termbuf(); + tty_binaryout(0); + set_termbuf(); + break; - case TELOPT_ECHO: /* we should stop echoing */ -#ifdef LINEMODE -# ifdef KLUDGELINEMODE - if ((lmodetype != REAL_LINEMODE) && - (lmodetype != KLUDGE_LINEMODE)) -# else - if (his_state_is_wont(TELOPT_LINEMODE)) -# endif -#endif - { - init_termbuf(); - tty_setecho(0); - set_termbuf(); - } - break; + case TELOPT_ECHO: /* we should stop echoing */ + { + init_termbuf(); + tty_setecho(0); + set_termbuf(); + } + break; - case TELOPT_SGA: -#if defined(LINEMODE) && defined(KLUDGELINEMODE) - /* - * If kludge linemode is in use, then we - * must process an incoming do SGA for - * linemode purposes. - */ - if ((lmodetype == KLUDGE_LINEMODE) || - (lmodetype == KLUDGE_OK)) { - /* - * The client is asking us to turn - * linemode on. - */ - lmodetype = KLUDGE_LINEMODE; - clientstat(TELOPT_LINEMODE, WILL, 0); - /* - * If we did not turn line mode on, - * then what do we say? Will SGA? - * This violates design of telnet. - * Gross. Very Gross. - */ - } - break; -#else - set_my_want_state_wont(option); - if (my_state_is_will(option)) - send_wont(option, 0); - set_my_state_wont(option); - if (turn_on_sga ^= 1) - send_will(option, 1); - return; -#endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ - - default: - break; - } + case TELOPT_SGA: + set_my_want_state_wont(option); + if (my_state_is_will(option)) + send_wont(option, 0); + set_my_state_wont(option); + if (turn_on_sga ^= 1) + send_will(option, 1); + return; - set_my_want_state_wont(option); - if (my_state_is_will(option)) - send_wont(option, 0); + default: + break; } - set_my_state_wont(option); + + set_my_want_state_wont(option); + if (my_state_is_will(option)) + send_wont(option, 0); + } + set_my_state_wont(option); } /* end of dontoption */ @@ -1081,38 +900,38 @@ int env_ovalue = -1; * should be dropped. */ char *badenv_table[] = { - "IFS=", - "LD_", - "_RLD_", - "SHLIB_PATH=", - "LIBPATH=", - "KRB", - "ENV=", - "BASH_ENV=", - NULL, + "IFS=", + "LD_", + "_RLD_", + "SHLIB_PATH=", + "LIBPATH=", + "KRB", + "ENV=", + "BASH_ENV=", + NULL, }; /* envvarok(char*) */ /* check that variable is safe to pass to login or shell */ static int envvarok(varp) - char *varp; + char *varp; { - int i; - int len; - - if (strchr(varp, '=')) - return (0); - for (i = 0; badenv_table[i]; i++) { - len = strlen(badenv_table[i]); - if (badenv_table[i][len-1] == '=' && - !strncmp(badenv_table[i], varp, len-1) && - varp[len-2] == '\0') - return (0); - if (!strncmp(badenv_table[i], varp, len-1)) - return (0); - } - return (1); + int i; + int len; + + if (strchr(varp, '=')) + return (0); + for (i = 0; badenv_table[i]; i++) { + len = strlen(badenv_table[i]); + if (badenv_table[i][len-1] == '=' && + !strncmp(badenv_table[i], varp, len-1) && + varp[len-2] == '\0') + return (0); + if (!strncmp(badenv_table[i], varp, len-1)) + return (0); + } + return (1); } /* @@ -1128,31 +947,31 @@ envvarok(varp) * Window size * Terminal speed */ - void -suboption() +void +suboption(void) { - register int subchar; + int subchar; DIAG(TD_OPTIONS, {netflush(); printsub('<', subpointer, SB_LEN()+2);}); subchar = SB_GET(); switch (subchar) { case TELOPT_TSPEED: { - register int xspeed, rspeed; + int xspeed, rspeed; if (his_state_is_wont(TELOPT_TSPEED)) /* Ignore if option disabled */ - break; + break; settimer(tspeedsubopt); if (SB_EOF() || SB_GET() != TELQUAL_IS) - return; + return; xspeed = atoi((char *)subpointer); while (SB_GET() != ',' && !SB_EOF()); if (SB_EOF()) - return; + return; rspeed = atoi((char *)subpointer); clientstat(TELOPT_TSPEED, xspeed, rspeed); @@ -1165,7 +984,7 @@ suboption() static char terminalname[41]; if (his_state_is_wont(TELOPT_TTYPE)) /* Ignore if option disabled */ - break; + break; settimer(ttypesubopt); if (SB_EOF() || SB_GET() != TELQUAL_IS) { @@ -1175,8 +994,8 @@ suboption() terminaltype = terminalname; while ((terminaltype < (terminalname + sizeof terminalname-1)) && - !SB_EOF()) { - register int c; + !SB_EOF()) { + int c; c = SB_GET(); if (isupper(c)) { @@ -1190,22 +1009,22 @@ suboption() } /* end of case TELOPT_TTYPE */ case TELOPT_NAWS: { - register int xwinsize, ywinsize; + int xwinsize, ywinsize; if (his_state_is_wont(TELOPT_NAWS)) /* Ignore if option disabled */ - break; + break; if (SB_EOF()) - return; + return; xwinsize = SB_GET() << 8; if (SB_EOF()) - return; + return; xwinsize |= SB_GET(); if (SB_EOF()) - return; + return; ywinsize = SB_GET() << 8; if (SB_EOF()) - return; + return; ywinsize |= SB_GET(); clientstat(TELOPT_NAWS, xwinsize, ywinsize); @@ -1213,54 +1032,6 @@ suboption() } /* end of case TELOPT_NAWS */ -#ifdef LINEMODE - case TELOPT_LINEMODE: { - register int request; - - if (his_state_is_wont(TELOPT_LINEMODE)) /* Ignore if option disabled */ - break; - /* - * Process linemode suboptions. - */ - if (SB_EOF()) - break; /* garbage was sent */ - request = SB_GET(); /* get will/wont */ - - if (SB_EOF()) - break; /* another garbage check */ - - if (request == LM_SLC) { /* SLC is not preceeded by WILL or WONT */ - /* - * Process suboption buffer of slc's - */ - start_slc(1); - do_opt_slc(subpointer, subend - subpointer); - (void) end_slc(0); - break; - } else if (request == LM_MODE) { - if (SB_EOF()) - return; - useeditmode = SB_GET(); /* get mode flag */ - clientstat(LM_MODE, 0, 0); - break; - } - - if (SB_EOF()) - break; - switch (SB_GET()) { /* what suboption? */ - case LM_FORWARDMASK: - /* - * According to spec, only server can send request for - * forwardmask, and client can only return a positive response. - * So don't worry about it. - */ - - default: - break; - } - break; - } /* end of case TELOPT_LINEMODE */ -#endif case TELOPT_STATUS: { int mode; @@ -1284,11 +1055,10 @@ suboption() case TELOPT_XDISPLOC: { if (SB_EOF() || SB_GET() != TELQUAL_IS) - return; + return; settimer(xdisplocsubopt); subpointer[SB_LEN()] = '\0'; - /* XXX allocation failure? */ - (void)setenv("DISPLAY", (char *)subpointer, 1); + esetenv("DISPLAY", (char *)subpointer, 1); break; } /* end of case TELOPT_XDISPLOC */ @@ -1296,19 +1066,19 @@ suboption() case TELOPT_NEW_ENVIRON: #endif case TELOPT_OLD_ENVIRON: { - register int c; - register char *cp, *varp, *valp; + int c; + char *cp, *varp, *valp; if (SB_EOF()) - return; + return; c = SB_GET(); if (c == TELQUAL_IS) { - if (subchar == TELOPT_OLD_ENVIRON) - settimer(oenvironsubopt); - else - settimer(environsubopt); + if (subchar == TELOPT_OLD_ENVIRON) + settimer(oenvironsubopt); + else + settimer(environsubopt); } else if (c != TELQUAL_INFO) { - return; + return; } #ifdef TELOPT_NEW_ENVIRON @@ -1316,236 +1086,234 @@ suboption() while (!SB_EOF()) { c = SB_GET(); if ((c == NEW_ENV_VAR) || (c == ENV_USERVAR)) - break; + break; } } else #endif - { + { #ifdef ENV_HACK - /* - * We only want to do this if we haven't already decided - * whether or not the other side has its VALUE and VAR - * reversed. - */ - if (env_ovar < 0) { - register int last = -1; /* invalid value */ - int empty = 0; - int got_var = 0, got_value = 0, got_uservar = 0; - /* - * The other side might have its VALUE and VAR values - * reversed. To be interoperable, we need to determine - * which way it is. If the first recognized character - * is a VAR or VALUE, then that will tell us what - * type of client it is. If the fist recognized - * character is a USERVAR, then we continue scanning - * the suboption looking for two consecutive - * VAR or VALUE fields. We should not get two - * consecutive VALUE fields, so finding two - * consecutive VALUE or VAR fields will tell us - * what the client is. + * We only want to do this if we haven't already decided + * whether or not the other side has its VALUE and VAR + * reversed. */ - SB_SAVE(); - while (!SB_EOF()) { + if (env_ovar < 0) { + int last = -1; /* invalid value */ + int empty = 0; + int got_var = 0, got_value = 0, got_uservar = 0; + + /* + * The other side might have its VALUE and VAR values + * reversed. To be interoperable, we need to determine + * which way it is. If the first recognized character + * is a VAR or VALUE, then that will tell us what + * type of client it is. If the fist recognized + * character is a USERVAR, then we continue scanning + * the suboption looking for two consecutive + * VAR or VALUE fields. We should not get two + * consecutive VALUE fields, so finding two + * consecutive VALUE or VAR fields will tell us + * what the client is. + */ + SB_SAVE(); + while (!SB_EOF()) { c = SB_GET(); switch(c) { case OLD_ENV_VAR: - if (last < 0 || last == OLD_ENV_VAR - || (empty && (last == OLD_ENV_VALUE))) - goto env_ovar_ok; - got_var++; - last = OLD_ENV_VAR; - break; + if (last < 0 || last == OLD_ENV_VAR + || (empty && (last == OLD_ENV_VALUE))) + goto env_ovar_ok; + got_var++; + last = OLD_ENV_VAR; + break; case OLD_ENV_VALUE: - if (last < 0 || last == OLD_ENV_VALUE - || (empty && (last == OLD_ENV_VAR))) - goto env_ovar_wrong; - got_value++; - last = OLD_ENV_VALUE; - break; + if (last < 0 || last == OLD_ENV_VALUE + || (empty && (last == OLD_ENV_VAR))) + goto env_ovar_wrong; + got_value++; + last = OLD_ENV_VALUE; + break; case ENV_USERVAR: - /* count strings of USERVAR as one */ - if (last != ENV_USERVAR) - got_uservar++; - if (empty) { - if (last == OLD_ENV_VALUE) - goto env_ovar_ok; - if (last == OLD_ENV_VAR) - goto env_ovar_wrong; - } - last = ENV_USERVAR; - break; + /* count strings of USERVAR as one */ + if (last != ENV_USERVAR) + got_uservar++; + if (empty) { + if (last == OLD_ENV_VALUE) + goto env_ovar_ok; + if (last == OLD_ENV_VAR) + goto env_ovar_wrong; + } + last = ENV_USERVAR; + break; case ENV_ESC: - if (!SB_EOF()) - c = SB_GET(); - /* FALL THROUGH */ + if (!SB_EOF()) + c = SB_GET(); + /* FALL THROUGH */ default: - empty = 0; - continue; + empty = 0; + continue; } empty = 1; - } - if (empty) { + } + if (empty) { if (last == OLD_ENV_VALUE) - goto env_ovar_ok; + goto env_ovar_ok; if (last == OLD_ENV_VAR) - goto env_ovar_wrong; - } - /* - * Ok, the first thing was a USERVAR, and there - * are not two consecutive VAR or VALUE commands, - * and none of the VAR or VALUE commands are empty. - * If the client has sent us a well-formed option, - * then the number of VALUEs received should always - * be less than or equal to the number of VARs and - * USERVARs received. - * - * If we got exactly as many VALUEs as VARs and - * USERVARs, the client has the same definitions. - * - * If we got exactly as many VARs as VALUEs and - * USERVARS, the client has reversed definitions. - */ - if (got_uservar + got_var == got_value) { - env_ovar_ok: + goto env_ovar_wrong; + } + /* + * Ok, the first thing was a USERVAR, and there + * are not two consecutive VAR or VALUE commands, + * and none of the VAR or VALUE commands are empty. + * If the client has sent us a well-formed option, + * then the number of VALUEs received should always + * be less than or equal to the number of VARs and + * USERVARs received. + * + * If we got exactly as many VALUEs as VARs and + * USERVARs, the client has the same definitions. + * + * If we got exactly as many VARs as VALUEs and + * USERVARS, the client has reversed definitions. + */ + if (got_uservar + got_var == got_value) { + env_ovar_ok: env_ovar = OLD_ENV_VAR; env_ovalue = OLD_ENV_VALUE; - } else if (got_uservar + got_value == got_var) { - env_ovar_wrong: + } else if (got_uservar + got_value == got_var) { + env_ovar_wrong: env_ovar = OLD_ENV_VALUE; env_ovalue = OLD_ENV_VAR; - DIAG(TD_OPTIONS, {sprintf(nfrontp, - "ENVIRON VALUE and VAR are reversed!\r\n"); - nfrontp += strlen(nfrontp);}); + DIAG(TD_OPTIONS, { + output_data("ENVIRON VALUE and VAR are reversed!\r\n"); + }); + } } - } - SB_RESTORE(); + SB_RESTORE(); #endif - while (!SB_EOF()) { - c = SB_GET(); - if ((c == env_ovar) || (c == ENV_USERVAR)) + while (!SB_EOF()) { + c = SB_GET(); + if ((c == env_ovar) || (c == ENV_USERVAR)) break; + } } - } if (SB_EOF()) - return; + return; cp = varp = (char *)subpointer; valp = 0; while (!SB_EOF()) { - c = SB_GET(); - if (subchar == TELOPT_OLD_ENVIRON) { - if (c == env_ovar) - c = NEW_ENV_VAR; - else if (c == env_ovalue) - c = NEW_ENV_VALUE; - } - switch (c) { - - case NEW_ENV_VALUE: - *cp = '\0'; - cp = valp = (char *)subpointer; - break; + c = SB_GET(); + if (subchar == TELOPT_OLD_ENVIRON) { + if (c == env_ovar) + c = NEW_ENV_VAR; + else if (c == env_ovalue) + c = NEW_ENV_VALUE; + } + switch (c) { - case NEW_ENV_VAR: - case ENV_USERVAR: - *cp = '\0'; - if (envvarok(varp)) { - if (valp) - /* XXX allocation failure? */ - (void)setenv(varp, valp, 1); - else - unsetenv(varp); - } - cp = varp = (char *)subpointer; - valp = 0; - break; + case NEW_ENV_VALUE: + *cp = '\0'; + cp = valp = (char *)subpointer; + break; - case ENV_ESC: - if (SB_EOF()) - break; - c = SB_GET(); - /* FALL THROUGH */ - default: - *cp++ = c; - break; + case NEW_ENV_VAR: + case ENV_USERVAR: + *cp = '\0'; + if(envvarok(varp)) { + if (valp) + esetenv(varp, valp, 1); + else + unsetenv(varp); } + cp = varp = (char *)subpointer; + valp = 0; + break; + + case ENV_ESC: + if (SB_EOF()) + break; + c = SB_GET(); + /* FALL THROUGH */ + default: + *cp++ = c; + break; + } } *cp = '\0'; - if (envvarok(varp)) { - if (valp) - /* XXX allocation failure? */ - (void)setenv(varp, valp, 1); - else - unsetenv(varp); + if(envvarok(varp)) { + if (valp) + esetenv(varp, valp, 1); + else + unsetenv(varp); } break; } /* end of case TELOPT_NEW_ENVIRON */ -#if defined(AUTHENTICATION) +#ifdef AUTHENTICATION case TELOPT_AUTHENTICATION: if (SB_EOF()) - break; + break; switch(SB_GET()) { case TELQUAL_SEND: case TELQUAL_REPLY: - /* - * These are sent by us and cannot be sent by - * the client. - */ - break; + /* + * These are sent by us and cannot be sent by + * the client. + */ + break; case TELQUAL_IS: - auth_is(subpointer, SB_LEN()); - break; + auth_is(subpointer, SB_LEN()); + break; case TELQUAL_NAME: - auth_name(subpointer, SB_LEN()); - break; + auth_name(subpointer, SB_LEN()); + break; } break; #endif #ifdef ENCRYPTION - case TELOPT_ENCRYPT: - if (SB_EOF()) - break; + case TELOPT_ENCRYPT: + if (SB_EOF()) + break; switch(SB_GET()) { case ENCRYPT_SUPPORT: - encrypt_support(subpointer, SB_LEN()); - break; + encrypt_support(subpointer, SB_LEN()); + break; case ENCRYPT_IS: - encrypt_is(subpointer, SB_LEN()); - break; + encrypt_is(subpointer, SB_LEN()); + break; case ENCRYPT_REPLY: - encrypt_reply(subpointer, SB_LEN()); - break; + encrypt_reply(subpointer, SB_LEN()); + break; case ENCRYPT_START: - encrypt_start(subpointer, SB_LEN()); - break; + encrypt_start(subpointer, SB_LEN()); + break; case ENCRYPT_END: - encrypt_end(); - break; + encrypt_end(); + break; case ENCRYPT_REQSTART: - encrypt_request_start(subpointer, SB_LEN()); - break; + encrypt_request_start(subpointer, SB_LEN()); + break; case ENCRYPT_REQEND: - /* - * We can always send an REQEND so that we cannot - * get stuck encrypting. We should only get this - * if we have been able to get in the correct mode - * anyhow. - */ - encrypt_request_end(); - break; + /* + * We can always send an REQEND so that we cannot + * get stuck encrypting. We should only get this + * if we have been able to get in the correct mode + * anyhow. + */ + encrypt_request_end(); + break; case ENCRYPT_ENC_KEYID: - encrypt_enc_keyid(subpointer, SB_LEN()); - break; + encrypt_enc_keyid(subpointer, SB_LEN()); + break; case ENCRYPT_DEC_KEYID: - encrypt_dec_keyid(subpointer, SB_LEN()); - break; + encrypt_dec_keyid(subpointer, SB_LEN()); + break; default: - break; + break; } break; #endif @@ -1556,100 +1324,79 @@ suboption() } /* end of suboption */ - void -doclientstat() +void +doclientstat(void) { - clientstat(TELOPT_LINEMODE, WILL, 0); + clientstat(TELOPT_LINEMODE, WILL, 0); } #define ADD(c) *ncp++ = c #define ADD_DATA(c) { *ncp++ = c; if (c == SE || c == IAC) *ncp++ = c; } - void -send_status() -{ - unsigned char statusbuf[256]; - register unsigned char *ncp; - register unsigned char i; - ncp = statusbuf; - - netflush(); /* get rid of anything waiting to go out */ +void +send_status(void) +{ + unsigned char statusbuf[256]; + unsigned char *ncp; + unsigned char i; + + ncp = statusbuf; + + netflush(); /* get rid of anything waiting to go out */ + + ADD(IAC); + ADD(SB); + ADD(TELOPT_STATUS); + ADD(TELQUAL_IS); + + /* + * We check the want_state rather than the current state, + * because if we received a DO/WILL for an option that we + * don't support, and the other side didn't send a DONT/WONT + * in response to our WONT/DONT, then the "state" will be + * WILL/DO, and the "want_state" will be WONT/DONT. We + * need to go by the latter. + */ + for (i = 0; i < (unsigned char)NTELOPTS; i++) { + if (my_want_state_is_will(i)) { + ADD(WILL); + ADD_DATA(i); + } + if (his_want_state_is_will(i)) { + ADD(DO); + ADD_DATA(i); + } + } - ADD(IAC); + if (his_want_state_is_will(TELOPT_LFLOW)) { ADD(SB); - ADD(TELOPT_STATUS); - ADD(TELQUAL_IS); - - /* - * We check the want_state rather than the current state, - * because if we received a DO/WILL for an option that we - * don't support, and the other side didn't send a DONT/WONT - * in response to our WONT/DONT, then the "state" will be - * WILL/DO, and the "want_state" will be WONT/DONT. We - * need to go by the latter. - */ - for (i = 0; i < (unsigned char)NTELOPTS; i++) { - if (my_want_state_is_will(i)) { - ADD(WILL); - ADD_DATA(i); - } - if (his_want_state_is_will(i)) { - ADD(DO); - ADD_DATA(i); - } + ADD(TELOPT_LFLOW); + if (flowmode) { + ADD(LFLOW_ON); + } else { + ADD(LFLOW_OFF); } + ADD(SE); - if (his_want_state_is_will(TELOPT_LFLOW)) { - ADD(SB); - ADD(TELOPT_LFLOW); - if (flowmode) { - ADD(LFLOW_ON); - } else { - ADD(LFLOW_OFF); - } - ADD(SE); - - if (restartany >= 0) { - ADD(SB); - ADD(TELOPT_LFLOW); - if (restartany) { - ADD(LFLOW_RESTART_ANY); - } else { - ADD(LFLOW_RESTART_XON); - } - ADD(SE); - } + if (restartany >= 0) { + ADD(SB); + ADD(TELOPT_LFLOW); + if (restartany) { + ADD(LFLOW_RESTART_ANY); + } else { + ADD(LFLOW_RESTART_XON); + } + ADD(SE); } + } -#ifdef LINEMODE - if (his_want_state_is_will(TELOPT_LINEMODE)) { - unsigned char *cp, *cpe; - int len; - - ADD(SB); - ADD(TELOPT_LINEMODE); - ADD(LM_MODE); - ADD_DATA(editmode); - ADD(SE); - - ADD(SB); - ADD(TELOPT_LINEMODE); - ADD(LM_SLC); - start_slc(0); - send_slc(); - len = end_slc(&cp); - for (cpe = cp + len; cp < cpe; cp++) - ADD_DATA(*cp); - ADD(SE); - } -#endif /* LINEMODE */ - ADD(IAC); - ADD(SE); + ADD(IAC); + ADD(SE); - writenet(statusbuf, ncp - statusbuf); - netflush(); /* Send it on its way */ + writenet(statusbuf, ncp - statusbuf); + netflush(); /* Send it on its way */ - DIAG(TD_OPTIONS, - {printsub('>', statusbuf, ncp - statusbuf); netflush();}); + DIAG(TD_OPTIONS, + {printsub('>', statusbuf, ncp - statusbuf); netflush();}); } diff --git a/libexec/telnetd/sys_term.c b/libexec/telnetd/sys_term.c index 5cee73127ac..8ffc44e25a5 100644 --- a/libexec/telnetd/sys_term.c +++ b/libexec/telnetd/sys_term.c @@ -1,6 +1,3 @@ -/* $OpenBSD: sys_term.c,v 1.23 2001/06/11 15:18:52 mickey Exp $ */ -/* $NetBSD: sys_term.c,v 1.9 1996/03/20 04:25:53 tls Exp $ */ - /* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. @@ -34,82 +31,89 @@ * SUCH DAMAGE. */ -#ifndef lint -#if 0 -static char sccsid[] = "@(#)sys_term.c 8.4+1 (Berkeley) 5/30/95"; -static char rcsid[] = "$NetBSD: sys_term.c,v 1.8 1996/02/28 20:38:21 thorpej Exp $"; -#else -static char rcsid[] = "$OpenBSD: sys_term.c,v 1.23 2001/06/11 15:18:52 mickey Exp $"; -#endif -#endif /* not lint */ - #include "telnetd.h" -#include "pathnames.h" -#include <util.h> -#include <sys/cdefs.h> -#define P __P +/* RCSID("$KTH: sys_term.c,v 1.100 2001/04/24 23:11:43 assar Exp $"); */ -#if defined(AUTHENTICATION) -#include <libtelnet/auth.h> +#if defined(_CRAY) || (defined(__hpux) && !defined(HAVE_UTMPX_H)) +# define PARENT_DOES_UTMP #endif -#if defined(CRAY) || defined(__hpux) -# define PARENT_DOES_UTMP +#ifdef HAVE_UTMP_H +#include <utmp.h> #endif -#ifdef NEWINIT -#include <initreq.h> -int utmp_len = MAXHOSTNAMELEN; /* sizeof(init_request.host) */ -#else /* NEWINIT*/ -# ifdef UTMPX -# include <utmpx.h> +#ifdef HAVE_UTMPX_H +#include <utmpx.h> +#endif + +#ifdef HAVE_UTMPX_H struct utmpx wtmp; -# else -# include <utmp.h> +#elif defined(HAVE_UTMP_H) struct utmp wtmp; -# endif /* UTMPX */ +#endif /* HAVE_UTMPX_H */ +#ifdef HAVE_STRUCT_UTMP_UT_HOST int utmp_len = sizeof(wtmp.ut_host); -# ifndef PARENT_DOES_UTMP +#else +int utmp_len = MAXHOSTNAMELEN; +#endif + +#ifndef UTMP_FILE +#ifdef _PATH_UTMP +#define UTMP_FILE _PATH_UTMP +#else +#define UTMP_FILE "/etc/utmp" +#endif +#endif + +#if !defined(WTMP_FILE) && defined(_PATH_WTMP) +#define WTMP_FILE _PATH_WTMP +#endif + +#ifndef PARENT_DOES_UTMP +#ifdef WTMP_FILE +char wtmpf[] = WTMP_FILE; +#else char wtmpf[] = "/usr/adm/wtmp"; -char utmpf[] = "/etc/utmp"; -# else /* PARENT_DOES_UTMP */ +#endif +char utmpf[] = UTMP_FILE; +#else /* PARENT_DOES_UTMP */ +#ifdef WTMP_FILE +char wtmpf[] = WTMP_FILE; +#else char wtmpf[] = "/etc/wtmp"; -# endif /* PARENT_DOES_UTMP */ +#endif +#endif /* PARENT_DOES_UTMP */ -# ifdef CRAY +#ifdef HAVE_TMPDIR_H #include <tmpdir.h> -#include <sys/wait.h> -# if (UNICOS_LVL == '7.0') || (UNICOS_LVL == '7.1') -# define UNICOS7x -# endif - -# ifdef UNICOS7x -#include <sys/sysv.h> -#include <sys/secstat.h> -extern int secflag; -extern struct sysv sysv; -# endif /* UNICOS7x */ -# endif /* CRAY */ -#endif /* NEWINIT */ +#endif /* CRAY */ #ifdef STREAMSPTY + +#ifdef HAVE_SAC_H #include <sac.h> +#endif + +#ifdef HAVE_SYS_STROPTS_H #include <sys/stropts.h> #endif -#define SCPYN(a, b) (void) strncpy(a, b, sizeof(a)) -#define SCMPN(a, b) strncmp(a, b, sizeof(a)) +#endif /* STREAMSPTY */ -#ifdef STREAMS -#include <sys/stream.h> +#ifdef HAVE_SYS_STREAM_H +#ifdef HAVE_SYS_UIO_H +#include <sys/uio.h> #endif #ifdef __hpux -#include <sys/resource.h> -#include <sys/proc.h> +#undef SE #endif +#include <sys/stream.h> +#endif +#if !(defined(__sgi) || defined(__linux) || defined(_AIX)) && defined(HAVE_SYS_TTY) #include <sys/tty.h> +#endif #ifdef t_erase #undef t_erase #undef t_kill @@ -127,26 +131,18 @@ extern struct sysv sysv; #undef t_lnextc #endif -#if defined(UNICOS5) && defined(CRAY2) && !defined(EXTPROC) -# define EXTPROC 0400 -#endif - -#ifndef USE_TERMIO -struct termbuf { - struct sgttyb sg; - struct tchars tc; - struct ltchars ltc; - int state; - int lflags; -} termbuf, termbuf2; -# define cfsetospeed(tp, val) (tp)->sg.sg_ospeed = (val) -# define cfsetispeed(tp, val) (tp)->sg.sg_ispeed = (val) -# define cfgetospeed(tp) (tp)->sg.sg_ospeed -# define cfgetispeed(tp) (tp)->sg.sg_ispeed -#else /* USE_TERMIO */ -# ifdef SYSV_TERMIO -# define termios termio -# endif +#ifdef HAVE_TERMIOS_H +#include <termios.h> +#else +#ifdef HAVE_TERMIO_H +#include <termio.h> +#endif +#endif + +#ifdef HAVE_UTIL_H +#include <util.h> +#endif + # ifndef TCSANOW # ifdef TCSETS # define TCSANOW TCSETS @@ -165,26 +161,25 @@ struct termbuf { # endif # define tcsetattr(f, a, t) ioctl(f, a, t) # define cfsetospeed(tp, val) (tp)->c_cflag &= ~CBAUD; \ - (tp)->c_cflag |= (val) +(tp)->c_cflag |= (val) # define cfgetospeed(tp) ((tp)->c_cflag & CBAUD) # ifdef CIBAUD # define cfsetispeed(tp, val) (tp)->c_cflag &= ~CIBAUD; \ - (tp)->c_cflag |= ((val)<<IBSHIFT) + (tp)->c_cflag |= ((val)<<IBSHIFT) # define cfgetispeed(tp) (((tp)->c_cflag & CIBAUD)>>IBSHIFT) # else # define cfsetispeed(tp, val) (tp)->c_cflag &= ~CBAUD; \ - (tp)->c_cflag |= (val) + (tp)->c_cflag |= (val) # define cfgetispeed(tp) ((tp)->c_cflag & CBAUD) # endif # endif /* TCSANOW */ -struct termios termbuf, termbuf2; /* pty control structure */ + struct termios termbuf, termbuf2; /* pty control structure */ # ifdef STREAMSPTY -int ttyfd = -1; + static int ttyfd = -1; + int really_stream = 0; # endif -#endif /* USE_TERMIO */ -int cleanopen P((char *)); -void scrub_env P((void)); + const char *new_login = _PATH_LOGIN; /* * init_termbuf() @@ -197,68 +192,31 @@ void scrub_env P((void)); * set_termbuf() writes the structure into the kernel. */ - void -init_termbuf() + void + init_termbuf(void) { -#ifndef USE_TERMIO - (void) ioctl(pty, TIOCGETP, (char *)&termbuf.sg); - (void) ioctl(pty, TIOCGETC, (char *)&termbuf.tc); - (void) ioctl(pty, TIOCGLTC, (char *)&termbuf.ltc); -# ifdef TIOCGSTATE - (void) ioctl(pty, TIOCGSTATE, (char *)&termbuf.state); -# endif -#else # ifdef STREAMSPTY - (void) tcgetattr(ttyfd, &termbuf); -# else - (void) tcgetattr(pty, &termbuf); + if (really_stream) + tcgetattr(ttyfd, &termbuf); + else # endif -#endif - termbuf2 = termbuf; -} - -#if defined(LINEMODE) && defined(TIOCPKT_IOCTL) - void -copy_termbuf(cp, len) - char *cp; - int len; -{ - if (len > sizeof(termbuf)) - len = sizeof(termbuf); - memmove((void *)&termbuf, cp, len); - termbuf2 = termbuf; + tcgetattr(ourpty, &termbuf); + termbuf2 = termbuf; } -#endif /* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */ - void -set_termbuf() +void +set_termbuf(void) { - /* - * Only make the necessary changes. + /* + * Only make the necessary changes. */ -#ifndef USE_TERMIO - if (memcmp((void *)&termbuf.sg, (void *)&termbuf2.sg, - sizeof(termbuf.sg))) - (void) ioctl(pty, TIOCSETN, (char *)&termbuf.sg); - if (memcmp((void *)&termbuf.tc, (void *)&termbuf2.tc, - sizeof(termbuf.tc))) - (void) ioctl(pty, TIOCSETC, (char *)&termbuf.tc); - if (memcmp((void *)&termbuf.ltc, (void *)&termbuf2.ltc, - sizeof(termbuf.ltc))) - (void) ioctl(pty, TIOCSLTC, (char *)&termbuf.ltc); - if (termbuf.lflags != termbuf2.lflags) - (void) ioctl(pty, TIOCLSET, (char *)&termbuf.lflags); -#else /* USE_TERMIO */ - if (memcmp((void *)&termbuf, (void *)&termbuf2, sizeof(termbuf))) + if (memcmp(&termbuf, &termbuf2, sizeof(termbuf))) # ifdef STREAMSPTY - (void) tcsetattr(ttyfd, TCSANOW, &termbuf); -# else - (void) tcsetattr(pty, TCSANOW, &termbuf); -# endif -# if defined(CRAY2) && defined(UNICOS5) - needtermstat = 1; + if (really_stream) + tcsetattr(ttyfd, TCSANOW, &termbuf); + else # endif -#endif /* USE_TERMIO */ + tcsetattr(ourpty, TCSANOW, &termbuf); } @@ -273,199 +231,119 @@ set_termbuf() * It returns the SLC_ level of support for this function. */ -#ifndef USE_TERMIO - int -spcset(func, valp, valpp) - int func; - cc_t *valp; - cc_t **valpp; -{ - switch(func) { - case SLC_EOF: - *valp = termbuf.tc.t_eofc; - *valpp = (cc_t *)&termbuf.tc.t_eofc; - return(SLC_VARIABLE); - case SLC_EC: - *valp = termbuf.sg.sg_erase; - *valpp = (cc_t *)&termbuf.sg.sg_erase; - return(SLC_VARIABLE); - case SLC_EL: - *valp = termbuf.sg.sg_kill; - *valpp = (cc_t *)&termbuf.sg.sg_kill; - return(SLC_VARIABLE); - case SLC_IP: - *valp = termbuf.tc.t_intrc; - *valpp = (cc_t *)&termbuf.tc.t_intrc; - return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); - case SLC_ABORT: - *valp = termbuf.tc.t_quitc; - *valpp = (cc_t *)&termbuf.tc.t_quitc; - return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); - case SLC_XON: - *valp = termbuf.tc.t_startc; - *valpp = (cc_t *)&termbuf.tc.t_startc; - return(SLC_VARIABLE); - case SLC_XOFF: - *valp = termbuf.tc.t_stopc; - *valpp = (cc_t *)&termbuf.tc.t_stopc; - return(SLC_VARIABLE); - case SLC_AO: - *valp = termbuf.ltc.t_flushc; - *valpp = (cc_t *)&termbuf.ltc.t_flushc; - return(SLC_VARIABLE); - case SLC_SUSP: - *valp = termbuf.ltc.t_suspc; - *valpp = (cc_t *)&termbuf.ltc.t_suspc; - return(SLC_VARIABLE); - case SLC_EW: - *valp = termbuf.ltc.t_werasc; - *valpp = (cc_t *)&termbuf.ltc.t_werasc; - return(SLC_VARIABLE); - case SLC_RP: - *valp = termbuf.ltc.t_rprntc; - *valpp = (cc_t *)&termbuf.ltc.t_rprntc; - return(SLC_VARIABLE); - case SLC_LNEXT: - *valp = termbuf.ltc.t_lnextc; - *valpp = (cc_t *)&termbuf.ltc.t_lnextc; - return(SLC_VARIABLE); - case SLC_FORW1: - *valp = termbuf.tc.t_brkc; - *valpp = (cc_t *)&termbuf.ltc.t_lnextc; - return(SLC_VARIABLE); - case SLC_BRK: - case SLC_SYNCH: - case SLC_AYT: - case SLC_EOR: - *valp = (cc_t)0; - *valpp = (cc_t *)0; - return(SLC_DEFAULT); - default: - *valp = (cc_t)0; - *valpp = (cc_t *)0; - return(SLC_NOSUPPORT); - } -} -#else /* USE_TERMIO */ - - int -spcset(func, valp, valpp) - int func; - cc_t *valp; - cc_t **valpp; +int +spcset(int func, cc_t *valp, cc_t **valpp) { #define setval(a, b) *valp = termbuf.c_cc[a]; \ - *valpp = &termbuf.c_cc[a]; \ - return(b); + *valpp = &termbuf.c_cc[a]; \ + return(b); #define defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT); - switch(func) { - case SLC_EOF: - setval(VEOF, SLC_VARIABLE); - case SLC_EC: - setval(VERASE, SLC_VARIABLE); - case SLC_EL: - setval(VKILL, SLC_VARIABLE); - case SLC_IP: - setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); - case SLC_ABORT: - setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); - case SLC_XON: + switch(func) { + case SLC_EOF: + setval(VEOF, SLC_VARIABLE); + case SLC_EC: + setval(VERASE, SLC_VARIABLE); + case SLC_EL: + setval(VKILL, SLC_VARIABLE); + case SLC_IP: + setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); + case SLC_ABORT: + setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); + case SLC_XON: #ifdef VSTART - setval(VSTART, SLC_VARIABLE); + setval(VSTART, SLC_VARIABLE); #else - defval(0x13); + defval(0x13); #endif - case SLC_XOFF: + case SLC_XOFF: #ifdef VSTOP - setval(VSTOP, SLC_VARIABLE); + setval(VSTOP, SLC_VARIABLE); #else - defval(0x11); + defval(0x11); #endif - case SLC_EW: + case SLC_EW: #ifdef VWERASE - setval(VWERASE, SLC_VARIABLE); + setval(VWERASE, SLC_VARIABLE); #else - defval(0); + defval(0); #endif - case SLC_RP: + case SLC_RP: #ifdef VREPRINT - setval(VREPRINT, SLC_VARIABLE); + setval(VREPRINT, SLC_VARIABLE); #else - defval(0); + defval(0); #endif - case SLC_LNEXT: + case SLC_LNEXT: #ifdef VLNEXT - setval(VLNEXT, SLC_VARIABLE); + setval(VLNEXT, SLC_VARIABLE); #else - defval(0); + defval(0); #endif - case SLC_AO: + case SLC_AO: #if !defined(VDISCARD) && defined(VFLUSHO) # define VDISCARD VFLUSHO #endif #ifdef VDISCARD - setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT); + setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT); #else - defval(0); + defval(0); #endif - case SLC_SUSP: + case SLC_SUSP: #ifdef VSUSP - setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN); + setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN); #else - defval(0); + defval(0); #endif #ifdef VEOL - case SLC_FORW1: - setval(VEOL, SLC_VARIABLE); + case SLC_FORW1: + setval(VEOL, SLC_VARIABLE); #endif #ifdef VEOL2 - case SLC_FORW2: - setval(VEOL2, SLC_VARIABLE); + case SLC_FORW2: + setval(VEOL2, SLC_VARIABLE); #endif - case SLC_AYT: + case SLC_AYT: #ifdef VSTATUS - setval(VSTATUS, SLC_VARIABLE); + setval(VSTATUS, SLC_VARIABLE); #else - defval(0); + defval(0); #endif - case SLC_BRK: - case SLC_SYNCH: - case SLC_EOR: - defval(0); + case SLC_BRK: + case SLC_SYNCH: + case SLC_EOR: + defval(0); - default: - *valp = 0; - *valpp = 0; - return(SLC_NOSUPPORT); - } + default: + *valp = 0; + *valpp = 0; + return(SLC_NOSUPPORT); + } } -#endif /* USE_TERMIO */ -#ifdef CRAY +#ifdef _CRAY /* * getnpty() * * Return the number of pty's configured into the system. */ - int +int getnpty() { #ifdef _SC_CRAY_NPTY - int numptys; + int numptys; - if ((numptys = sysconf(_SC_CRAY_NPTY)) != -1) - return numptys; - else + if ((numptys = sysconf(_SC_CRAY_NPTY)) != -1) + return numptys; + else #endif /* _SC_CRAY_NPTY */ - return 128; + return 128; } #endif /* CRAY */ -#ifndef convex /* * getpty() * @@ -474,480 +352,312 @@ getnpty() * * Returns the file descriptor of the opened pty. */ -#ifdef CRAY -char myline[16]; -#else -char line[16]; -#endif /* CRAY */ - int -getpty(ptynum) -int *ptynum; -{ - register int p; -#ifdef STREAMSPTY - int t; - char *ptsname(); - - p = open("/dev/ptmx", O_RDWR); - if (p > 0) { - grantpt(p); - unlockpt(p); - strcpy(line, ptsname(p)); - return(p); - } +static char Xline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; +char *line = Xline; -#else /* ! STREAMSPTY */ -#ifndef CRAY - register char *cp, *p1, *p2; - register int i; -#if defined(sun) && defined(TIOCGPGRP) && BSD < 199207 - int dummy; -#endif - -#ifndef __hpux - (void) sprintf(line, "/dev/ptyXX"); - p1 = &line[8]; - p2 = &line[9]; -#else - (void) sprintf(line, "/dev/ptym/ptyXX"); - p1 = &line[13]; - p2 = &line[14]; -#endif - - for (cp = "pqrstuvwxyzPQRST"; *cp; cp++) { - struct stat stb; - - *p1 = *cp; - *p2 = '0'; - /* - * This stat() check is just to keep us from - * looping through all 256 combinations if there - * aren't that many ptys available. - */ - if (stat(line, &stb) < 0) - break; - for (i = 0; i < 16; i++) { - *p2 = "0123456789abcdef"[i]; - p = open(line, O_RDWR); - if (p > 0) { -#ifndef __hpux - line[5] = 't'; -#else - for (p1 = &line[8]; *p1; p1++) - *p1 = *(p1+1); - line[9] = 't'; -#endif - chown(line, 0, 0); - chmod(line, 0600); -#if defined(sun) && defined(TIOCGPGRP) && BSD < 199207 - if (ioctl(p, TIOCGPGRP, &dummy) == 0 - || errno != EIO) { - chmod(line, 0666); - close(p); - line[5] = 'p'; - } else -#endif /* defined(sun) && defined(TIOCGPGRP) && BSD < 199207 */ - return(p); - } - } - } -#else /* CRAY */ - extern lowpty, highpty; - struct stat sb; - - for (*ptynum = lowpty; *ptynum <= highpty; (*ptynum)++) { - (void) sprintf(myline, "/dev/pty/%03d", *ptynum); - p = open(myline, O_RDWR); - if (p < 0) - continue; - (void) sprintf(line, "/dev/ttyp%03d", *ptynum); - /* - * Here are some shenanigans to make sure that there - * are no listeners lurking on the line. - */ - if(stat(line, &sb) < 0) { - (void) close(p); - continue; - } - if(sb.st_uid || sb.st_gid || sb.st_mode != 0600) { - chown(line, 0, 0); - chmod(line, 0600); - (void)close(p); - p = open(myline, O_RDWR); - if (p < 0) - continue; - } - /* - * Now it should be safe...check for accessability. - */ - if (access(line, 6) == 0) - return(p); - else { - /* no tty side to pty so skip it */ - (void) close(p); - } - } +#ifdef _CRAY +char myline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; #endif /* CRAY */ -#endif /* STREAMSPTY */ - return(-1); -} -#endif /* convex */ - -#ifdef LINEMODE -/* - * tty_flowmode() Find out if flow control is enabled or disabled. - * tty_linemode() Find out if linemode (external processing) is enabled. - * tty_setlinemod(on) Turn on/off linemode. - * tty_isecho() Find out if echoing is turned on. - * tty_setecho(on) Enable/disable character echoing. - * tty_israw() Find out if terminal is in RAW mode. - * tty_binaryin(on) Turn on/off BINARY on input. - * tty_binaryout(on) Turn on/off BINARY on output. - * tty_isediting() Find out if line editing is enabled. - * tty_istrapsig() Find out if signal trapping is enabled. - * tty_setedit(on) Turn on/off line editing. - * tty_setsig(on) Turn on/off signal trapping. - * tty_issofttab() Find out if tab expansion is enabled. - * tty_setsofttab(on) Turn on/off soft tab expansion. - * tty_islitecho() Find out if typed control chars are echoed literally - * tty_setlitecho() Turn on/off literal echo of control chars - * tty_tspeed(val) Set transmit speed to val. - * tty_rspeed(val) Set receive speed to val. - */ - -#ifdef convex -static int linestate; -#endif - int -tty_linemode() +#if !defined(HAVE_PTSNAME) && defined(STREAMSPTY) +static char *ptsname(int fd) { -#ifndef convex -#ifndef USE_TERMIO - return(termbuf.state & TS_EXTPROC); +#ifdef HAVE_TTYNAME + return ttyname(fd); #else - return(termbuf.c_lflag & EXTPROC); -#endif -#else - return(linestate); + return NULL; #endif } - - void -tty_setlinemode(on) - int on; -{ -#ifdef TIOCEXT -# ifndef convex - set_termbuf(); -# else - linestate = on; -# endif - (void) ioctl(pty, TIOCEXT, (char *)&on); -# ifndef convex - init_termbuf(); -# endif -#else /* !TIOCEXT */ -# ifdef EXTPROC - if (on) - termbuf.c_lflag |= EXTPROC; - else - termbuf.c_lflag &= ~EXTPROC; -# endif -#endif /* TIOCEXT */ -} -#endif /* LINEMODE */ - - int -tty_isecho() -{ -#ifndef USE_TERMIO - return (termbuf.sg.sg_flags & ECHO); -#else - return (termbuf.c_lflag & ECHO); #endif -} - int -tty_flowmode() +int getpty(int *ptynum) { -#ifndef USE_TERMIO - return(((termbuf.tc.t_startc) > 0 && (termbuf.tc.t_stopc) > 0) ? 1 : 0); +#ifdef __osf__ /* XXX */ + int master; + int slave; + if(openpty(&master, &slave, line, 0, 0) == 0){ + close(slave); + return master; + } + return -1; +#else +#ifdef HAVE__GETPTY + int master, slave; + char *p; + p = _getpty(&master, O_RDWR, 0600, 1); + if(p == NULL) + return -1; + strlcpy(line, p, sizeof(Xline)); + return master; #else - return((termbuf.c_iflag & IXON) ? 1 : 0); -#endif -} - int -tty_restartany() -{ -#ifndef USE_TERMIO -# ifdef DECCTQ - return((termbuf.lflags & DECCTQ) ? 0 : 1); -# else - return(-1); -# endif + int p; + char *cp, *p1, *p2; + int i; +#if SunOS == 40 + int dummy; +#endif +#if 0 /* && defined(HAVE_OPENPTY) */ + int master; + int slave; + if(openpty(&master, &slave, line, 0, 0) == 0){ + close(slave); + return master; + } #else - return((termbuf.c_iflag & IXANY) ? 1 : 0); -#endif -} +#ifdef STREAMSPTY + char *clone[] = { "/dev/ptc", "/dev/ptmx", "/dev/ptm", + "/dev/ptym/clone", 0 }; + + char **q; + for(q=clone; *q; q++){ + p=open(*q, O_RDWR); + if(p >= 0){ +#ifdef HAVE_GRANTPT + grantpt(p); +#endif +#ifdef HAVE_UNLOCKPT + unlockpt(p); +#endif + strlcpy(line, ptsname(p), sizeof(Xline)); + really_stream = 1; + return p; + } + } +#endif /* STREAMSPTY */ +#ifndef _CRAY - void -tty_setecho(on) - int on; -{ -#ifndef USE_TERMIO - if (on) - termbuf.sg.sg_flags |= ECHO|CRMOD; - else - termbuf.sg.sg_flags &= ~(ECHO|CRMOD); +#ifndef __hpux + snprintf(line, sizeof(Xline), "/dev/ptyXX"); + p1 = &line[8]; + p2 = &line[9]; #else - if (on) - termbuf.c_lflag |= ECHO; - else - termbuf.c_lflag &= ~ECHO; + snprintf(line, sizeof(Xline), "/dev/ptym/ptyXX"); + p1 = &line[13]; + p2 = &line[14]; #endif -} - int -tty_israw() -{ -#ifndef USE_TERMIO - return(termbuf.sg.sg_flags & RAW); + + for (cp = "pqrstuvwxyzPQRST"; *cp; cp++) { + struct stat stb; + + *p1 = *cp; + *p2 = '0'; + /* + * This stat() check is just to keep us from + * looping through all 256 combinations if there + * aren't that many ptys available. + */ + if (stat(line, &stb) < 0) + break; + for (i = 0; i < 16; i++) { + *p2 = "0123456789abcdef"[i]; + p = open(line, O_RDWR); + if (p > 0) { +#ifndef __hpux + line[5] = 't'; #else - return(!(termbuf.c_lflag & ICANON)); + for (p1 = &line[8]; *p1; p1++) + *p1 = *(p1+1); + line[9] = 't'; +#endif + chown(line, 0, 0); + chmod(line, 0600); +#if SunOS == 40 + if (ioctl(p, TIOCGPGRP, &dummy) == 0 + || errno != EIO) { + chmod(line, 0666); + close(p); + line[5] = 'p'; + } else +#endif /* SunOS == 40 */ + return(p); + } + } + } +#else /* CRAY */ + extern lowpty, highpty; + struct stat sb; + + for (*ptynum = lowpty; *ptynum <= highpty; (*ptynum)++) { + snprintf(myline, sizeof(myline), "/dev/pty/%03d", *ptynum); + p = open(myline, 2); + if (p < 0) + continue; + snprintf(line, sizeof(Xline), "/dev/ttyp%03d", *ptynum); + /* + * Here are some shenanigans to make sure that there + * are no listeners lurking on the line. + */ + if(stat(line, &sb) < 0) { + close(p); + continue; + } + if(sb.st_uid || sb.st_gid || sb.st_mode != 0600) { + chown(line, 0, 0); + chmod(line, 0600); + close(p); + p = open(myline, 2); + if (p < 0) + continue; + } + /* + * Now it should be safe...check for accessability. + */ + if (access(line, 6) == 0) + return(p); + else { + /* no tty side to pty so skip it */ + close(p); + } + } +#endif /* CRAY */ +#endif /* STREAMSPTY */ +#endif /* OPENPTY */ + return(-1); #endif } -#if defined (AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R) - int -tty_setraw(on) + +int +tty_isecho(void) { -# ifndef USE_TERMIO - if (on) - termbuf.sg.sg_flags |= RAW; - else - termbuf.sg.sg_flags &= ~RAW; -# else - if (on) - termbuf.c_lflag &= ~ICANON; - else - termbuf.c_lflag |= ICANON; -# endif + return (termbuf.c_lflag & ECHO); } -#endif - void -tty_binaryin(on) - int on; +int +tty_flowmode(void) { -#ifndef USE_TERMIO - if (on) - termbuf.lflags |= LPASS8; - else - termbuf.lflags &= ~LPASS8; -#else - if (on) { - termbuf.c_iflag &= ~ISTRIP; - } else { - termbuf.c_iflag |= ISTRIP; - } -#endif + return((termbuf.c_iflag & IXON) ? 1 : 0); } - void -tty_binaryout(on) - int on; +int +tty_restartany(void) { -#ifndef USE_TERMIO - if (on) - termbuf.lflags |= LLITOUT; - else - termbuf.lflags &= ~LLITOUT; -#else - if (on) { - termbuf.c_cflag &= ~(CSIZE|PARENB); - termbuf.c_cflag |= CS8; - termbuf.c_oflag &= ~OPOST; - } else { - termbuf.c_cflag &= ~CSIZE; - termbuf.c_cflag |= CS7|PARENB; - termbuf.c_oflag |= OPOST; - } -#endif + return((termbuf.c_iflag & IXANY) ? 1 : 0); } - int -tty_isbinaryin() +void +tty_setecho(int on) { -#ifndef USE_TERMIO - return(termbuf.lflags & LPASS8); -#else - return(!(termbuf.c_iflag & ISTRIP)); -#endif + if (on) + termbuf.c_lflag |= ECHO; + else + termbuf.c_lflag &= ~ECHO; } - int -tty_isbinaryout() +int +tty_israw(void) { -#ifndef USE_TERMIO - return(termbuf.lflags & LLITOUT); -#else - return(!(termbuf.c_oflag&OPOST)); -#endif + return(!(termbuf.c_lflag & ICANON)); } -#ifdef LINEMODE - int -tty_isediting() +void +tty_binaryin(int on) { -#ifndef USE_TERMIO - return(!(termbuf.sg.sg_flags & (CBREAK|RAW))); -#else - return(termbuf.c_lflag & ICANON); -#endif + if (on) { + termbuf.c_iflag &= ~ISTRIP; + } else { + termbuf.c_iflag |= ISTRIP; + } } - int -tty_istrapsig() +void +tty_binaryout(int on) { -#ifndef USE_TERMIO - return(!(termbuf.sg.sg_flags&RAW)); -#else - return(termbuf.c_lflag & ISIG); -#endif + if (on) { + termbuf.c_cflag &= ~(CSIZE|PARENB); + termbuf.c_cflag |= CS8; + termbuf.c_oflag &= ~OPOST; + } else { + termbuf.c_cflag &= ~CSIZE; + termbuf.c_cflag |= CS7|PARENB; + termbuf.c_oflag |= OPOST; + } } - void -tty_setedit(on) - int on; +int +tty_isbinaryin(void) { -#ifndef USE_TERMIO - if (on) - termbuf.sg.sg_flags &= ~CBREAK; - else - termbuf.sg.sg_flags |= CBREAK; -#else - if (on) - termbuf.c_lflag |= ICANON; - else - termbuf.c_lflag &= ~ICANON; -#endif + return(!(termbuf.c_iflag & ISTRIP)); } - void -tty_setsig(on) - int on; +int +tty_isbinaryout(void) { -#ifndef USE_TERMIO - if (on) - ; -#else - if (on) - termbuf.c_lflag |= ISIG; - else - termbuf.c_lflag &= ~ISIG; -#endif + return(!(termbuf.c_oflag&OPOST)); } -#endif /* LINEMODE */ - int -tty_issofttab() + +int +tty_issofttab(void) { -#ifndef USE_TERMIO - return (termbuf.sg.sg_flags & XTABS); -#else # ifdef OXTABS - return (termbuf.c_oflag & OXTABS); + return (termbuf.c_oflag & OXTABS); # endif # ifdef TABDLY - return ((termbuf.c_oflag & TABDLY) == TAB3); + return ((termbuf.c_oflag & TABDLY) == TAB3); # endif -#endif } - void -tty_setsofttab(on) - int on; +void +tty_setsofttab(int on) { -#ifndef USE_TERMIO - if (on) - termbuf.sg.sg_flags |= XTABS; - else - termbuf.sg.sg_flags &= ~XTABS; -#else - if (on) { + if (on) { # ifdef OXTABS - termbuf.c_oflag |= OXTABS; + termbuf.c_oflag |= OXTABS; # endif # ifdef TABDLY - termbuf.c_oflag &= ~TABDLY; - termbuf.c_oflag |= TAB3; + termbuf.c_oflag &= ~TABDLY; + termbuf.c_oflag |= TAB3; # endif - } else { + } else { # ifdef OXTABS - termbuf.c_oflag &= ~OXTABS; + termbuf.c_oflag &= ~OXTABS; # endif # ifdef TABDLY - termbuf.c_oflag &= ~TABDLY; - termbuf.c_oflag |= TAB0; + termbuf.c_oflag &= ~TABDLY; + termbuf.c_oflag |= TAB0; # endif - } -#endif + } } - int -tty_islitecho() +int +tty_islitecho(void) { -#ifndef USE_TERMIO - return (!(termbuf.lflags & LCTLECH)); -#else # ifdef ECHOCTL - return (!(termbuf.c_lflag & ECHOCTL)); + return (!(termbuf.c_lflag & ECHOCTL)); # endif # ifdef TCTLECH - return (!(termbuf.c_lflag & TCTLECH)); + return (!(termbuf.c_lflag & TCTLECH)); # endif # if !defined(ECHOCTL) && !defined(TCTLECH) - return (0); /* assumes ctl chars are echoed '^x' */ + return (0); /* assumes ctl chars are echoed '^x' */ # endif -#endif } - void -tty_setlitecho(on) - int on; +void +tty_setlitecho(int on) { -#ifndef USE_TERMIO - if (on) - termbuf.lflags &= ~LCTLECH; - else - termbuf.lflags |= LCTLECH; -#else # ifdef ECHOCTL - if (on) - termbuf.c_lflag &= ~ECHOCTL; - else - termbuf.c_lflag |= ECHOCTL; + if (on) + termbuf.c_lflag &= ~ECHOCTL; + else + termbuf.c_lflag |= ECHOCTL; # endif # ifdef TCTLECH - if (on) - termbuf.c_lflag &= ~TCTLECH; - else - termbuf.c_lflag |= TCTLECH; + if (on) + termbuf.c_lflag &= ~TCTLECH; + else + termbuf.c_lflag |= TCTLECH; # endif -#endif } - int -tty_iscrnl() +int +tty_iscrnl(void) { -#ifndef USE_TERMIO - return (termbuf.sg.sg_flags & CRMOD); -#else - return (termbuf.c_iflag & ICRNL); -#endif + return (termbuf.c_iflag & ICRNL); } /* @@ -963,257 +673,284 @@ tty_iscrnl() * A table of available terminal speeds */ struct termspeeds { - int speed; - int value; + int speed; + int value; } termspeeds[] = { - { 0, B0 }, { 50, B50 }, { 75, B75 }, - { 110, B110 }, { 134, B134 }, { 150, B150 }, - { 200, B200 }, { 300, B300 }, { 600, B600 }, - { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 }, - { 4800, B4800 }, + { 0, B0 }, { 50, B50 }, { 75, B75 }, + { 110, B110 }, { 134, B134 }, { 150, B150 }, + { 200, B200 }, { 300, B300 }, { 600, B600 }, + { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 }, + { 4800, B4800 }, #ifdef B7200 - { 7200, B7200 }, + { 7200, B7200 }, #endif - { 9600, B9600 }, + { 9600, B9600 }, #ifdef B14400 - { 14400, B14400 }, + { 14400, B14400 }, #endif #ifdef B19200 - { 19200, B19200 }, + { 19200, B19200 }, #endif #ifdef B28800 - { 28800, B28800 }, + { 28800, B28800 }, #endif #ifdef B38400 - { 38400, B38400 }, + { 38400, B38400 }, #endif #ifdef B57600 - { 57600, B57600 }, + { 57600, B57600 }, #endif #ifdef B115200 - { 115200, B115200 }, + { 115200, B115200 }, #endif #ifdef B230400 - { 230400, B230400 }, + { 230400, B230400 }, #endif - { -1, 0 } + { -1, 0 } }; #endif /* DECODE_BUAD */ - void -tty_tspeed(val) - int val; +void +tty_tspeed(int val) { #ifdef DECODE_BAUD - register struct termspeeds *tp; + struct termspeeds *tp; - for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++) - ; - if (tp->speed == -1) /* back up to last valid value */ - --tp; - cfsetospeed(&termbuf, tp->value); + for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++) + ; + if (tp->speed == -1) /* back up to last valid value */ + --tp; + cfsetospeed(&termbuf, tp->value); #else /* DECODE_BUAD */ - cfsetospeed(&termbuf, val); + cfsetospeed(&termbuf, val); #endif /* DECODE_BUAD */ } - void -tty_rspeed(val) - int val; +void +tty_rspeed(int val) { #ifdef DECODE_BAUD - register struct termspeeds *tp; + struct termspeeds *tp; - for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++) - ; - if (tp->speed == -1) /* back up to last valid value */ - --tp; - cfsetispeed(&termbuf, tp->value); + for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++) + ; + if (tp->speed == -1) /* back up to last valid value */ + --tp; + cfsetispeed(&termbuf, tp->value); #else /* DECODE_BAUD */ - cfsetispeed(&termbuf, val); + cfsetispeed(&termbuf, val); #endif /* DECODE_BAUD */ } -#if defined(CRAY2) && defined(UNICOS5) - int -tty_isnewmap() -{ - return((termbuf.c_oflag & OPOST) && (termbuf.c_oflag & ONLCR) && - !(termbuf.c_oflag & ONLRET)); -} -#endif - #ifdef PARENT_DOES_UTMP -# ifndef NEWINIT extern struct utmp wtmp; extern char wtmpf[]; -# else /* NEWINIT */ -int gotalarm; - /* ARGSUSED */ - void -nologinproc(sig) - int sig; +extern void utmp_sig_init (void); +extern void utmp_sig_reset (void); +extern void utmp_sig_wait (void); +extern void utmp_sig_notify (int); +# endif /* PARENT_DOES_UTMP */ + +#ifdef STREAMSPTY + +/* I_FIND seems to live a life of its own */ +static int my_find(int fd, char *module) { - gotalarm++; +#if defined(I_FIND) && defined(I_LIST) + static int flag; + static struct str_list sl; + int n; + int i; + + if(!flag){ + n = ioctl(fd, I_LIST, 0); + if(n < 0){ + perror("ioctl(fd, I_LIST, 0)"); + return -1; + } + sl.sl_modlist=(struct str_mlist*)malloc(n * sizeof(struct str_mlist)); + sl.sl_nmods = n; + n = ioctl(fd, I_LIST, &sl); + if(n < 0){ + perror("ioctl(fd, I_LIST, n)"); + return -1; + } + flag = 1; + } + + for(i=0; i<sl.sl_nmods; i++) + if(!strcmp(sl.sl_modlist[i].l_name, module)) + return 1; +#endif + return 0; } -# endif /* NEWINIT */ -#endif /* PARENT_DOES_UTMP */ -#ifndef NEWINIT -# ifdef PARENT_DOES_UTMP -extern void utmp_sig_init P((void)); -extern void utmp_sig_reset P((void)); -extern void utmp_sig_wait P((void)); -extern void utmp_sig_notify P((int)); -# endif /* PARENT_DOES_UTMP */ +static void maybe_push_modules(int fd, char **modules) +{ + char **p; + int err; + + for(p=modules; *p; p++){ + err = my_find(fd, *p); + if(err == 1) + break; + if(err < 0 && errno != EINVAL) + fatalperror(net, "my_find()"); + /* module not pushed or does not exist */ + } + /* p points to null or to an already pushed module, now push all + modules before this one */ + + for(p--; p >= modules; p--){ + err = ioctl(fd, I_PUSH, *p); + if(err < 0 && errno != EINVAL) + fatalperror(net, "I_PUSH"); + } +} #endif /* * getptyslave() * * Open the slave side of the pty, and do any initialization - * that is necessary. + * that is necessary. The return value is a file descriptor + * for the slave side. */ - void -getptyslave() +void getptyslave(void) { - register int t = -1; - -#if !defined(CRAY) || !defined(NEWINIT) -# ifdef LINEMODE - int waslm; -# endif -# ifdef TIOCGWINSZ - struct winsize ws; - extern int def_row, def_col; -# endif - extern int def_tspeed, def_rspeed; - /* - * Opening the slave side may cause initilization of the - * kernel tty structure. We need remember the state of - * if linemode was turned on - * terminal window size - * terminal speed - * so that we can re-set them if we need to. - */ -# ifdef LINEMODE - waslm = tty_linemode(); -# endif - - - /* - * Make sure that we don't have a controlling tty, and - * that we are the session (process group) leader. - */ + int t = -1; + + struct winsize ws; + extern int def_row, def_col; + extern int def_tspeed, def_rspeed; + /* + * Opening the slave side may cause initilization of the + * kernel tty structure. We need remember the state of + * if linemode was turned on + * terminal window size + * terminal speed + * so that we can re-set them if we need to. + */ + + + /* + * Make sure that we don't have a controlling tty, and + * that we are the session (process group) leader. + */ + +#ifdef HAVE_SETSID + if(setsid()<0) + fatalperror(net, "setsid()"); +#else # ifdef TIOCNOTTY - t = open(_PATH_TTY, O_RDWR); - if (t >= 0) { - (void) ioctl(t, TIOCNOTTY, (char *)0); - (void) close(t); - } + t = open(_PATH_TTY, O_RDWR); + if (t >= 0) { + ioctl(t, TIOCNOTTY, (char *)0); + close(t); + } # endif - +#endif # ifdef PARENT_DOES_UTMP - /* - * Wait for our parent to get the utmp stuff to get done. - */ - utmp_sig_wait(); + /* + * Wait for our parent to get the utmp stuff to get done. + */ + utmp_sig_wait(); # endif - t = cleanopen(line); - if (t < 0) - fatalperror(net, line); + t = cleanopen(line); + if (t < 0) + fatalperror(net, line); #ifdef STREAMSPTY -#ifdef USE_TERMIO - ttyfd = t; -#endif - if (ioctl(t, I_PUSH, "ptem") < 0) - fatal(net, "I_PUSH ptem"); - if (ioctl(t, I_PUSH, "ldterm") < 0) - fatal(net, "I_PUSH ldterm"); - if (ioctl(t, I_PUSH, "ttcompat") < 0) - fatal(net, "I_PUSH ttcompat"); - if (ioctl(pty, I_PUSH, "pckt") < 0) - fatal(net, "I_PUSH pckt"); -#endif + ttyfd = t; + - /* - * set up the tty modes as we like them to be. - */ - init_termbuf(); -# ifdef TIOCGWINSZ - if (def_row || def_col) { - memset((void *)&ws, 0, sizeof(ws)); - ws.ws_col = def_col; - ws.ws_row = def_row; - (void)ioctl(t, TIOCSWINSZ, (char *)&ws); + /* + * Not all systems have (or need) modules ttcompat and pckt so + * don't flag it as a fatal error if they don't exist. + */ + + if (really_stream) + { + /* these are the streams modules that we want pushed. note + that they are in reverse order, ptem will be pushed + first. maybe_push_modules() will try to push all modules + before the first one that isn't already pushed. i.e if + ldterm is pushed, only ttcompat will be attempted. + + all this is because we don't know which modules are + available, and we don't know which modules are already + pushed (via autopush, for instance). + + */ + + char *ttymodules[] = { "ttcompat", "ldterm", "ptem", NULL }; + char *ptymodules[] = { "pckt", NULL }; + + maybe_push_modules(t, ttymodules); + maybe_push_modules(ourpty, ptymodules); } +#endif + /* + * set up the tty modes as we like them to be. + */ + init_termbuf(); +# ifdef TIOCSWINSZ + if (def_row || def_col) { + memset(&ws, 0, sizeof(ws)); + ws.ws_col = def_col; + ws.ws_row = def_row; + ioctl(t, TIOCSWINSZ, (char *)&ws); + } # endif - /* - * Settings for sgtty based systems - */ -# ifndef USE_TERMIO - termbuf.sg.sg_flags |= CRMOD|ANYP|ECHO|XTABS; -# endif /* USE_TERMIO */ - - /* - * Settings for UNICOS (and HPUX) - */ -# if defined(CRAY) || defined(__hpux) - termbuf.c_oflag = OPOST|ONLCR|TAB3; - termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON; - termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK; - termbuf.c_cflag = EXTB|HUPCL|CS8; + /* + * Settings for sgtty based systems + */ + + /* + * Settings for UNICOS (and HPUX) + */ +# if defined(_CRAY) || defined(__hpux) + termbuf.c_oflag = OPOST|ONLCR|TAB3; + termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON; + termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK; + termbuf.c_cflag = EXTB|HUPCL|CS8; # endif - /* - * Settings for all other termios/termio based - * systems, other than 4.4BSD. In 4.4BSD the - * kernel does the initial terminal setup. - */ -# if defined(USE_TERMIO) && !(defined(CRAY) || defined(__hpux)) && (BSD <= 43) + /* + * Settings for all other termios/termio based + * systems, other than 4.4BSD. In 4.4BSD the + * kernel does the initial terminal setup. + */ +# if !(defined(_CRAY) || defined(__hpux)) && (BSD <= 43) # ifndef OXTABS # define OXTABS 0 # endif - termbuf.c_lflag |= ECHO; - termbuf.c_oflag |= ONLCR|OXTABS; - termbuf.c_iflag |= ICRNL; - termbuf.c_iflag &= ~IXOFF; -# endif /* defined(USE_TERMIO) && !defined(CRAY) && (BSD <= 43) */ - tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600); - tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600); -# ifdef LINEMODE - if (waslm) - tty_setlinemode(1); -# endif /* LINEMODE */ - - /* - * Set the tty modes, and make this our controlling tty. - */ - set_termbuf(); - if (login_tty(t) == -1) - fatalperror(net, "login_tty"); -#endif /* !defined(CRAY) || !defined(NEWINIT) */ - if (net > 2) - (void) close(net); -#if defined(AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R) - /* - * Leave the pty open so that we can write out the rlogin - * protocol for /bin/login, if the authentication works. - */ -#else - if (pty > 2) { - (void) close(pty); - pty = -1; - } -#endif + termbuf.c_lflag |= ECHO; + termbuf.c_oflag |= ONLCR|OXTABS; + termbuf.c_iflag |= ICRNL; + termbuf.c_iflag &= ~IXOFF; +# endif + tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600); + tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600); + + /* + * Set the tty modes, and make this our controlling tty. + */ + set_termbuf(); + if (login_tty(t) == -1) + fatalperror(net, "login_tty"); + if (net > 2) + close(net); + if (ourpty > 2) { + close(ourpty); + ourpty = -1; + } } -#if !defined(CRAY) || !defined(NEWINIT) #ifndef O_NOCTTY #define O_NOCTTY 0 #endif @@ -1221,161 +958,147 @@ getptyslave() * Open the specified slave side of the pty, * making sure that we have a clean tty. */ - int -cleanopen(line) - char *line; + +int cleanopen(char *line) { - register int t; -#ifdef UNICOS7x - struct secstat secbuf; -#endif /* UNICOS7x */ + int t; -#ifndef STREAMSPTY - /* - * Make sure that other people can't open the - * slave side of the connection. - */ - (void) chown(line, 0, 0); - (void) chmod(line, 0600); +#ifdef STREAMSPTY + if (!really_stream) #endif - -# if !defined(CRAY) && (BSD > 43) - (void) revoke(line); -# endif -#ifdef UNICOS7x - if (secflag) { - if (secstat(line, &secbuf) < 0) - return(-1); - if (setulvl(secbuf.st_slevel) < 0) - return(-1); - if (setucmp(secbuf.st_compart) < 0) - return(-1); + { + /* + * Make sure that other people can't open the + * slave side of the connection. + */ + chown(line, 0, 0); + chmod(line, 0600); } -#endif /* UNICOS7x */ - t = open(line, O_RDWR|O_NOCTTY); +#ifdef HAVE_REVOKE + revoke(line); +#endif -#ifdef UNICOS7x - if (secflag) { - if (setulvl(sysv.sy_minlvl) < 0) - return(-1); - if (setucmp(0) < 0) - return(-1); - } -#endif /* UNICOS7x */ + t = open(line, O_RDWR|O_NOCTTY); - if (t < 0) - return(-1); + if (t < 0) + return(-1); - /* - * Hangup anybody else using this ttyp, then reopen it for - * ourselves. - */ -# if !(defined(CRAY) || defined(__hpux)) && (BSD <= 43) && !defined(STREAMSPTY) - (void) signal(SIGHUP, SIG_IGN); - vhangup(); - (void) signal(SIGHUP, SIG_DFL); - t = open(line, O_RDWR|O_NOCTTY); - if (t < 0) - return(-1); + /* + * Hangup anybody else using this ttyp, then reopen it for + * ourselves. + */ +# if !(defined(_CRAY) || defined(__hpux)) && (BSD <= 43) && !defined(STREAMSPTY) + signal(SIGHUP, SIG_IGN); +#ifdef HAVE_VHANGUP + vhangup(); +#else +#endif + signal(SIGHUP, SIG_DFL); + t = open(line, O_RDWR|O_NOCTTY); + if (t < 0) + return(-1); # endif -# if defined(CRAY) && defined(TCVHUP) - { - register int i; - (void) signal(SIGHUP, SIG_IGN); - (void) ioctl(t, TCVHUP, (char *)0); - (void) signal(SIGHUP, SIG_DFL); - -#ifdef UNICOS7x - if (secflag) { - if (secstat(line, &secbuf) < 0) - return(-1); - if (setulvl(secbuf.st_slevel) < 0) - return(-1); - if (setucmp(secbuf.st_compart) < 0) - return(-1); - } -#endif /* UNICOS7x */ - - i = open(line, O_RDWR); - -#ifdef UNICOS7x - if (secflag) { - if (setulvl(sysv.sy_minlvl) < 0) - return(-1); - if (setucmp(0) < 0) - return(-1); - } -#endif /* UNICOS7x */ - - if (i < 0) - return(-1); - (void) close(t); - t = i; - } +# if defined(_CRAY) && defined(TCVHUP) + { + int i; + signal(SIGHUP, SIG_IGN); + ioctl(t, TCVHUP, (char *)0); + signal(SIGHUP, SIG_DFL); + + i = open(line, O_RDWR); + + if (i < 0) + return(-1); + close(t); + t = i; + } # endif /* defined(CRAY) && defined(TCVHUP) */ - return(t); + return(t); } -#endif /* !defined(CRAY) || !defined(NEWINIT) */ -#if BSD <= 43 +#if !defined(BSD4_4) - int -login_tty(t) - int t; +int login_tty(int t) { - if (setsid() < 0) { -#ifdef ultrix - /* - * The setsid() may have failed because we - * already have a pgrp == pid. Zero out - * our pgrp and try again... - */ - if ((setpgrp(0, 0) < 0) || (setsid() < 0)) -#endif - fatalperror(net, "setsid()"); - } -# ifdef TIOCSCTTY - if (ioctl(t, TIOCSCTTY, (char *)0) < 0) - fatalperror(net, "ioctl(sctty)"); -# if defined(CRAY) - /* - * Close the hard fd to /dev/ttypXXX, and re-open through - * the indirect /dev/tty interface. - */ - close(t); - if ((t = open("/dev/tty", O_RDWR)) < 0) - fatalperror(net, "open(/dev/tty)"); +# if defined(TIOCSCTTY) && !defined(__hpux) + if (ioctl(t, TIOCSCTTY, (char *)0) < 0) + fatalperror(net, "ioctl(sctty)"); +# ifdef _CRAY + /* + * Close the hard fd to /dev/ttypXXX, and re-open through + * the indirect /dev/tty interface. + */ + close(t); + if ((t = open("/dev/tty", O_RDWR)) < 0) + fatalperror(net, "open(/dev/tty)"); # endif # else - /* - * We get our controlling tty assigned as a side-effect - * of opening up a tty device. But on BSD based systems, - * this only happens if our process group is zero. The - * setsid() call above may have set our pgrp, so clear - * it out before opening the tty... - */ -# ifndef SOLARIS - (void) setpgrp(0, 0); -# else - (void) setpgrp(); -# endif - close(open(line, O_RDWR)); + /* + * We get our controlling tty assigned as a side-effect + * of opening up a tty device. But on BSD based systems, + * this only happens if our process group is zero. The + * setsid() call above may have set our pgrp, so clear + * it out before opening the tty... + */ +#ifdef HAVE_SETPGID + setpgid(0, 0); +#else + setpgrp(0, 0); /* if setpgid isn't available, setpgrp + probably takes arguments */ +#endif + close(open(line, O_RDWR)); # endif - if (t != 0) - (void) dup2(t, 0); - if (t != 1) - (void) dup2(t, 1); - if (t != 2) - (void) dup2(t, 2); - if (t > 2) - close(t); - return(0); + if (t != 0) + dup2(t, 0); + if (t != 1) + dup2(t, 1); + if (t != 2) + dup2(t, 2); + if (t > 2) + close(t); + return(0); } #endif /* BSD <= 43 */ -#ifdef NEWINIT -char *gen_id = "fe"; +/* + * This comes from ../../bsd/tty.c and should not really be here. + */ + +/* + * Clean the tty name. Return a pointer to the cleaned version. + */ + +static char * +clean_ttyname (char *tty) +{ + char *res = tty; + + if (strncmp (res, _PATH_DEV, strlen(_PATH_DEV)) == 0) + res += strlen(_PATH_DEV); + if (strncmp (res, "pty/", 4) == 0) + res += 4; + if (strncmp (res, "ptym/", 5) == 0) + res += 5; + return res; +} + +/* + * Generate a name usable as an `ut_id', typically without `tty'. + */ + +#ifdef HAVE_STRUCT_UTMP_UT_ID +static char * +make_id (char *tty) +{ + char *res = tty; + + if (strncmp (res, "pts/", 4) == 0) + res += 4; + if (strncmp (res, "tty", 3) == 0) + res += 3; + return res; +} #endif /* @@ -1386,159 +1109,156 @@ char *gen_id = "fe"; */ /* ARGSUSED */ - void -startslave(host, autologin, autoname) - char *host; - int autologin; - char *autoname; +void +startslave(const char *host, const char *utmp_host, + int autologin, char *autoname) { - register int i; -#ifdef NEWINIT - extern char *ptyip; - struct init_request request; - void nologinproc(); - register int n; -#endif /* NEWINIT */ - -#if defined(AUTHENTICATION) - if (!autoname || !autoname[0]) - autologin = 0; - - if (autologin < auth_level) { - fatal(net, "Authorization failed"); - exit(1); - } -#endif + int i; -#ifndef NEWINIT +#ifdef AUTHENTICATION + if (!autoname || !autoname[0]) + autologin = 0; + + if (autologin < auth_level) { + fatal(net, "Authorization failed"); + exit(1); + } +#endif # ifdef PARENT_DOES_UTMP - utmp_sig_init(); + utmp_sig_init(); # endif /* PARENT_DOES_UTMP */ - if ((i = fork()) < 0) - fatalperror(net, "fork"); - if (i) { + if ((i = fork()) < 0) + fatalperror(net, "fork"); + if (i) { # ifdef PARENT_DOES_UTMP - /* - * Cray parent will create utmp entry for child and send - * signal to child to tell when done. Child waits for signal - * before doing anything important. - */ - register int pid = i; - void sigjob P((int)); - - setpgrp(); - utmp_sig_reset(); /* reset handler to default */ - /* - * Create utmp entry for child - */ - (void) time(&wtmp.ut_time); - wtmp.ut_type = LOGIN_PROCESS; - wtmp.ut_pid = pid; - SCPYN(wtmp.ut_user, "LOGIN"); - SCPYN(wtmp.ut_host, host); - SCPYN(wtmp.ut_line, line + sizeof("/dev/") - 1); -#ifndef __hpux - SCPYN(wtmp.ut_id, wtmp.ut_line+3); -#else - SCPYN(wtmp.ut_id, wtmp.ut_line+7); -#endif - pututline(&wtmp); - endutent(); - if ((i = open(wtmpf, O_WRONLY|O_APPEND)) >= 0) { - (void) write(i, (char *)&wtmp, sizeof(struct utmp)); - (void) close(i); - } -#ifdef CRAY - (void) signal(WJSIGNAL, sigjob); -#endif - utmp_sig_notify(pid); -# endif /* PARENT_DOES_UTMP */ - } else { - getptyslave(autologin); - start_login(host, autologin, autoname); - /*NOTREACHED*/ - } -#else /* NEWINIT */ - /* - * Init will start up login process if we ask nicely. We only wait - * for it to start up and begin normal telnet operation. + * Cray parent will create utmp entry for child and send + * signal to child to tell when done. Child waits for signal + * before doing anything important. */ - if ((i = open(INIT_FIFO, O_WRONLY)) < 0) { - char tbuf[128]; - (void) snprintf(tbuf, sizeof tbuf, "Can't open %s\n", INIT_FIFO); - fatalperror(net, tbuf); - } - memset((void *)&request, 0, sizeof(request)); - request.magic = INIT_MAGIC; - SCPYN(request.gen_id, gen_id); - SCPYN(request.tty_id, &line[8]); - SCPYN(request.host, host); - SCPYN(request.term_type, terminaltype ? terminaltype : "network"); -#if !defined(UNICOS5) - request.signal = SIGCLD; - request.pid = getpid(); -#endif -#ifdef BFTPDAEMON + int pid = i; + void sigjob (int); + + setpgrp(); + utmp_sig_reset(); /* reset handler to default */ /* - * Are we working as the bftp daemon? + * Create utmp entry for child */ - if (bftpd) { - SCPYN(request.exec_name, BFTPPATH); + wtmp.ut_time = time(NULL); + wtmp.ut_type = LOGIN_PROCESS; + wtmp.ut_pid = pid; + strncpy(wtmp.ut_user, "LOGIN", sizeof(wtmp.ut_user)); + strncpy(wtmp.ut_host, utmp_host, sizeof(wtmp.ut_host)); + strncpy(wtmp.ut_line, clean_ttyname(line), sizeof(wtmp.ut_line)); +#ifdef HAVE_STRUCT_UTMP_UT_ID + strncpy(wtmp.ut_id, wtmp.ut_line + 3, sizeof(wtmp.ut_id)); +#endif + + pututline(&wtmp); + endutent(); + if ((i = open(wtmpf, O_WRONLY|O_APPEND)) >= 0) { + write(i, &wtmp, sizeof(struct utmp)); + close(i); } -#endif /* BFTPDAEMON */ - if (write(i, (char *)&request, sizeof(request)) < 0) { - char tbuf[128]; - (void) snprintf(tbuf, sizeof tbuf, "Can't write to %s\n", INIT_FIFO); - fatalperror(net, tbuf); - } - (void) close(i); - (void) signal(SIGALRM, nologinproc); - for (i = 0; ; i++) { - char tbuf[128]; - alarm(15); - n = read(pty, ptyip, BUFSIZ); - if (i == 3 || n >= 0 || !gotalarm) - break; - gotalarm = 0; - snprintf(tbuf, sizeof tbuf, - "telnetd: waiting for /etc/init to start login process on %s\r\n", - line); - (void) write(net, tbuf, strlen(tbuf)); - } - if (n < 0 && gotalarm) - fatal(net, "/etc/init didn't start login process"); - pcc += n; - alarm(0); - (void) signal(SIGALRM, SIG_DFL); - - return; -#endif /* NEWINIT */ +#ifdef _CRAY + signal(WJSIGNAL, sigjob); +#endif + utmp_sig_notify(pid); +# endif /* PARENT_DOES_UTMP */ + } else { + getptyslave(); +#if defined(DCE) + /* if we authenticated via K5, try and join the PAG */ + kerberos5_dfspag(); +#endif + start_login(host, autologin, autoname); + /*NOTREACHED*/ + } } char *envinit[3]; extern char **environ; - void -init_env() +void +init_env(void) { - extern char *getenv(); - char **envp; + char **envp; - envp = envinit; - if ((*envp = getenv("TZ"))) - *envp++ -= 3; -#if defined(CRAY) || defined(__hpux) - else - *envp++ = "TZ=GMT0"; + envp = envinit; + if ((*envp = getenv("TZ"))) + *envp++ -= 3; +#if defined(_CRAY) || defined(__hpux) + else + *envp++ = "TZ=GMT0"; #endif - *envp = 0; - environ = envinit; + *envp = 0; + environ = envinit; } -#ifndef NEWINIT +/* We won't agree with the Heimdal people about the right way to check for + * bad environment variables, so we don't use this code. + * See envvarok() in state.c instead. + */ +#if 0 +/* + * scrub_env() + * + * We only accept the environment variables listed below. + */ + +static void +scrub_env(void) +{ + static const char *reject[] = { + "TERMCAP=/", + NULL + }; + + static const char *accept[] = { + "XAUTH=", "XAUTHORITY=", "DISPLAY=", + "TERM=", + "EDITOR=", + "PAGER=", + "PRINTER=", + "LOGNAME=", + "POSIXLY_CORRECT=", + "TERMCAP=", + NULL + }; + + char **cpp, **cpp2; + const char **p; + + for (cpp2 = cpp = environ; *cpp; cpp++) { + int reject_it = 0; + + for(p = reject; *p; p++) + if(strncmp(*cpp, *p, strlen(*p)) == 0) { + reject_it = 1; + break; + } + if (reject_it) + continue; + + for(p = accept; *p; p++) + if(strncmp(*cpp, *p, strlen(*p)) == 0) + break; + if(*p != NULL) + *cpp2++ = *cpp; + } + *cpp2 = NULL; +} +#endif + +struct arg_val { + int size; + int argc; + const char **argv; +}; + +static void addarg(struct arg_val*, const char*); /* * start_login(host) @@ -1547,315 +1267,298 @@ init_env() * function will turn us into the login process. */ - void -start_login(host, autologin, name) - char *host; - int autologin; - char *name; +void +start_login(const char *host, int autologin, char *name) { - register char **argv; - char **addarg(); - extern char *getenv(); - extern char *gettyname; -#define TABBUFSIZ 512 - char defent[TABBUFSIZ]; - char defstrs[TABBUFSIZ]; -#undef TABBUFSIZ - char *loginprog = NULL; -#ifdef UTMPX - register int pid = getpid(); - struct utmpx utmpx; -#endif -#ifdef SOLARIS - char *term; - char termbuf[64]; -#endif - -#ifdef UTMPX - /* - * Create utmp entry for child - */ + struct arg_val argv; + char *user; + int save_errno; - memset((void *)&utmpx, 0, sizeof(utmpx)); - SCPYN(utmpx.ut_user, ".telnet"); - SCPYN(utmpx.ut_line, line + sizeof("/dev/") - 1); - utmpx.ut_pid = pid; - utmpx.ut_id[0] = 't'; - utmpx.ut_id[1] = 'n'; - utmpx.ut_id[2] = SC_WILDC; - utmpx.ut_id[3] = SC_WILDC; - utmpx.ut_type = LOGIN_PROCESS; - (void) time(&utmpx.ut_tv.tv_sec); - if (makeutx(&utmpx) == NULL) - fatal(net, "makeutx failed"); -#endif - - scrub_env(); - - /* - * -h : pass on name of host. - * WARNING: -h is accepted by login if and only if - * getuid() == 0. - * -p : don't clobber the environment (so terminal type stays set). - * - * -f : force this login, he has already been authenticated - */ - argv = addarg(0, "login"); +#ifdef HAVE_UTMPX_H + int pid = getpid(); + struct utmpx utmpx; + char *clean_tty; -#if !defined(NO_LOGIN_H) + /* + * Create utmp entry for child + */ -# if defined (AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R) - /* - * Don't add the "-h host" option if we are going - * to be adding the "-r host" option down below... - */ - if ((auth_level < 0) || (autologin != AUTH_VALID)) -# endif - { - argv = addarg(argv, "-h"); - argv = addarg(argv, host); -#ifdef SOLARIS - /* - * SVR4 version of -h takes TERM= as second arg, or - - */ - term = getenv("TERM"); - if (term == NULL || term[0] == 0) { - term = "-"; - } else { - strcpy(termbuf, "TERM="); - strncat(termbuf, term, sizeof(termbuf) - 6); - term = termbuf; - } - argv = addarg(argv, term); -#endif - } + clean_tty = clean_ttyname(line); + memset(&utmpx, 0, sizeof(utmpx)); + strncpy(utmpx.ut_user, ".telnet", sizeof(utmpx.ut_user)); + strncpy(utmpx.ut_line, clean_tty, sizeof(utmpx.ut_line)); +#ifdef HAVE_STRUCT_UTMP_UT_ID + strncpy(utmpx.ut_id, make_id(clean_tty), sizeof(utmpx.ut_id)); #endif -#if !defined(NO_LOGIN_P) - argv = addarg(argv, "-p"); -#endif -#ifdef LINEMODE - /* - * Set the environment variable "LINEMODE" to either - * "real" or "kludge" if we are operating in either - * real or kludge linemode. - */ - if (lmodetype == REAL_LINEMODE) - setenv("LINEMODE", "real", 1); /* XXX mem */ -# ifdef KLUDGELINEMODE - else if (lmodetype == KLUDGE_LINEMODE || lmodetype == KLUDGE_OK) - setenv("LINEMODE", "kludge", 1); /* XXX mem */ -# endif -#endif -#ifdef BFTPDAEMON - /* - * Are we working as the bftp daemon? If so, then ask login - * to start bftp instead of shell. - */ - if (bftpd) { - argv = addarg(argv, "-e"); - argv = addarg(argv, BFTPPATH); - } else -#endif -#if defined (AUTHENTICATION) - if (auth_level >= 0 && autologin == AUTH_VALID) { -# if !defined(NO_LOGIN_F) - argv = addarg(argv, "-f"); - argv = addarg(argv, "--"); - argv = addarg(argv, name); -# else -# if defined(LOGIN_R) - /* - * We don't have support for "login -f", but we - * can fool /bin/login into thinking that we are - * rlogind, and allow us to log in without a - * password. The rlogin protocol expects - * local-user\0remote-user\0term/speed\0 - */ - - if (pty > 2) { - register char *cp; - char speed[128]; - int isecho, israw, xpty, len; - extern int def_rspeed; -# ifndef LOGIN_HOST - /* - * Tell login that we are coming from "localhost". - * If we passed in the real host name, then the - * user would have to allow .rhost access from - * every machine that they want authenticated - * access to work from, which sort of defeats - * the purpose of an authenticated login... - * So, we tell login that the session is coming - * from "localhost", and the user will only have - * to have "localhost" in their .rhost file. - */ -# define LOGIN_HOST "localhost" -# endif - argv = addarg(argv, "-r"); - argv = addarg(argv, LOGIN_HOST); - - xpty = pty; -# ifndef STREAMSPTY - pty = 0; -# else - ttyfd = 0; -# endif - init_termbuf(); - isecho = tty_isecho(); - israw = tty_israw(); - if (isecho || !israw) { - tty_setecho(0); /* Turn off echo */ - tty_setraw(1); /* Turn on raw */ - set_termbuf(); - } - len = strlen(name)+1; - write(xpty, name, len); - write(xpty, name, len); - snprintf(speed, sizeof speed, - "%s/%d", (cp = getenv("TERM")) ? cp : "", - (def_rspeed > 0) ? def_rspeed : 9600); - len = strlen(speed)+1; - write(xpty, speed, len); - - if (isecho || !israw) { - init_termbuf(); - tty_setecho(isecho); - tty_setraw(israw); - set_termbuf(); - if (!israw) { - /* - * Write a newline to ensure - * that login will be able to - * read the line... - */ - write(xpty, "\n", 1); - } - } - pty = xpty; - } -# else - argv = addarg(argv, "--"); - argv = addarg(argv, name); -# endif -# endif - } else -#endif - if (getenv("USER")) { - argv = addarg(argv, "--"); - argv = addarg(argv, getenv("USER")); -#if defined(LOGIN_ARGS) && defined(NO_LOGIN_P) - { - register char **cpp; - for (cpp = environ; *cpp; cpp++) - argv = addarg(argv, *cpp); - } -#endif - /* - * Assume that login will set the USER variable - * correctly. For SysV systems, this means that - * USER will no longer be set, just LOGNAME by - * login. (The problem is that if the auto-login - * fails, and the user then specifies a different - * account name, he can get logged in with both - * LOGNAME and USER in his environment, but the - * USER value will be wrong. - */ - unsetenv("USER"); - } -#ifdef SOLARIS - else { - char **p; + utmpx.ut_pid = pid; + + utmpx.ut_type = LOGIN_PROCESS; - argv = addarg(argv, ""); /* no login name */ - for (p = environ; *p; p++) { - argv = addarg(argv, *p); - } - } -#endif /* SOLARIS */ -#if defined(AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R) - if (pty > 2) - close(pty); + gettimeofday (&utmpx.ut_tv, NULL); + if (pututxline(&utmpx) == NULL) + fatal(net, "pututxline failed"); #endif - if (gtgetent(defent, gettyname) == 1) { - char *cp = defstrs; - loginprog = gtgetstr("lo", &cp); +#if 0 + scrub_env(); +#endif + /* + * -h : pass on name of host. + * WARNING: -h is accepted by login if and only if + * getuid() == 0. + * -p : don't clobber the environment (so terminal type stays set). + * + * -f : force this login, he has already been authenticated + */ + + /* init argv structure */ + argv.size=0; + argv.argc=0; + argv.argv=malloc(0); /*so we can call realloc later */ + addarg(&argv, "login"); + addarg(&argv, "-h"); + addarg(&argv, host); + addarg(&argv, "-p"); + if(name[0]) + user = name; + else + user = getenv("USER"); +#ifdef AUTHENTICATION + if (auth_level < 0 || autologin != AUTH_VALID) { + if(!no_warn) { + printf("User not authenticated. "); + if (require_otp) + printf("Using one-time password\r\n"); + else + printf("Using plaintext username and password\r\n"); + } + if (require_otp) { + addarg(&argv, "-a"); + addarg(&argv, "otp"); } - if (loginprog == NULL) - loginprog = _PATH_LOGIN; - closelog(); + if(log_unauth) + syslog(LOG_INFO, "unauthenticated access from %s (%s)", + host, user ? user : "unknown user"); + } + if (auth_level >= 0 && autologin == AUTH_VALID) + addarg(&argv, "-f"); +#endif + if(user){ + addarg(&argv, "--"); + addarg(&argv, strdup(user)); + } + if (getenv("USER")) { /* - * This sleep(1) is in here so that telnetd can - * finish up with the tty. There's a race condition - * the login banner message gets lost... + * Assume that login will set the USER variable + * correctly. For SysV systems, this means that + * USER will no longer be set, just LOGNAME by + * login. (The problem is that if the auto-login + * fails, and the user then specifies a different + * account name, he can get logged in with both + * LOGNAME and USER in his environment, but the + * USER value will be wrong. */ - sleep(1); - execv(loginprog, argv); - - syslog(LOG_ERR, "%s: %m", loginprog); - fatalperror(net, loginprog); - /*NOTREACHED*/ + unsetenv("USER"); + } + closelog(); + /* + * This sleep(1) is in here so that telnetd can + * finish up with the tty. There's a race condition + * the login banner message gets lost... + */ + sleep(1); + + execv(new_login, argv.argv); + save_errno = errno; + syslog(LOG_ERR, "%s: %m\n", new_login); + fatalperror_errno(net, new_login, save_errno); + /*NOTREACHED*/ } - char ** -addarg(argv, val) - register char **argv; - register char *val; +static void +addarg(struct arg_val *argv, const char *val) { - register char **cpp; - - if (argv == NULL) { - /* - * 10 entries, a leading length, and a null - */ - argv = (char **)malloc(sizeof(*argv) * 12); - if (argv == NULL) - return(NULL); - *argv++ = (char *)10; - *argv = (char *)0; - } - for (cpp = argv; *cpp; cpp++) - ; - if (cpp == &argv[(long)argv[-1]]) { - --argv; - *argv = (char *)((long)(*argv) + 10); - argv = (char **)realloc(argv, sizeof(*argv)*((long)(*argv) + 2)); - if (argv == NULL) - return(NULL); - argv++; - cpp = &argv[(long)argv[-1] - 10]; - } - *cpp++ = val; - *cpp = 0; - return(argv); + if(argv->size <= argv->argc+1) { + argv->argv = realloc(argv->argv, sizeof(char*) * (argv->size + 10)); + if (argv->argv == NULL) + fatal (net, "realloc: out of memory"); + argv->size+=10; + } + argv->argv[argv->argc++] = val; + argv->argv[argv->argc] = NULL; } -#endif /* NEWINIT */ + /* - * scrub_env() + * rmut() * - * Remove a few things from the environment that - * don't need to be there. + * This is the function called by cleanup() to + * remove the utmp entry for this person. */ - void -scrub_env() + +#ifdef HAVE_UTMPX_H +static void +rmut(void) +{ + struct utmpx utmpx, *non_save_utxp; + char *clean_tty = clean_ttyname(line); + + /* + * This updates the utmpx and utmp entries and make a wtmp/x entry + */ + + setutxent(); + memset(&utmpx, 0, sizeof(utmpx)); + strncpy(utmpx.ut_line, clean_tty, sizeof(utmpx.ut_line)); + utmpx.ut_type = LOGIN_PROCESS; + non_save_utxp = getutxline(&utmpx); + if (non_save_utxp) { + struct utmpx *utxp; + char user0; + + utxp = malloc(sizeof(struct utmpx)); + *utxp = *non_save_utxp; + user0 = utxp->ut_user[0]; + utxp->ut_user[0] = '\0'; + utxp->ut_type = DEAD_PROCESS; +#ifdef HAVE_STRUCT_UTMPX_UT_EXIT +#ifdef _STRUCT___EXIT_STATUS + utxp->ut_exit.__e_termination = 0; + utxp->ut_exit.__e_exit = 0; +#elif defined(__osf__) /* XXX */ + utxp->ut_exit.ut_termination = 0; + utxp->ut_exit.ut_exit = 0; +#else + utxp->ut_exit.e_termination = 0; + utxp->ut_exit.e_exit = 0; +#endif +#endif + gettimeofday(&utxp->ut_tv, NULL); + pututxline(utxp); +#ifdef WTMPX_FILE + utxp->ut_user[0] = user0; + updwtmpx(WTMPX_FILE, utxp); +#elif defined(WTMP_FILE) + /* This is a strange system with a utmpx and a wtmp! */ + { + int f = open(wtmpf, O_WRONLY|O_APPEND); + struct utmp wtmp; + if (f >= 0) { + strncpy(wtmp.ut_line, clean_tty, sizeof(wtmp.ut_line)); + strncpy(wtmp.ut_name, "", sizeof(wtmp.ut_name)); +#ifdef HAVE_STRUCT_UTMP_UT_HOST + strncpy(wtmp.ut_host, "", sizeof(wtmp.ut_host)); +#endif + wtmp.ut_time = time(NULL); + write(f, &wtmp, sizeof(wtmp)); + close(f); + } + } +#endif + free (utxp); + } + endutxent(); +} /* end of rmut */ +#endif + +#if !defined(HAVE_UTMPX_H) && !(defined(_CRAY) || defined(__hpux)) +static void +rmut(void) +{ + int f; + int found = 0; + struct utmp *u, *utmp; + int nutmp; + struct stat statbf; + char *clean_tty = clean_ttyname(line); + + f = open(utmpf, O_RDWR); + if (f >= 0) { + fstat(f, &statbf); + utmp = (struct utmp *)malloc((unsigned)statbf.st_size); + if (!utmp) + syslog(LOG_ERR, "utmp malloc failed"); + if (statbf.st_size && utmp) { + nutmp = read(f, utmp, (int)statbf.st_size); + nutmp /= sizeof(struct utmp); + + for (u = utmp ; u < &utmp[nutmp] ; u++) { + if (strncmp(u->ut_line, + clean_tty, + sizeof(u->ut_line)) || + u->ut_name[0]==0) + continue; + lseek(f, ((long)u)-((long)utmp), L_SET); + strncpy(u->ut_name, "", sizeof(u->ut_name)); +#ifdef HAVE_STRUCT_UTMP_UT_HOST + strncpy(u->ut_host, "", sizeof(u->ut_host)); +#endif + u->ut_time = time(NULL); + write(f, u, sizeof(wtmp)); + found++; + } + } + close(f); + } + if (found) { + f = open(wtmpf, O_WRONLY|O_APPEND); + if (f >= 0) { + strncpy(wtmp.ut_line, clean_tty, sizeof(wtmp.ut_line)); + strncpy(wtmp.ut_name, "", sizeof(wtmp.ut_name)); +#ifdef HAVE_STRUCT_UTMP_UT_HOST + strncpy(wtmp.ut_host, "", sizeof(wtmp.ut_host)); +#endif + wtmp.ut_time = time(NULL); + write(f, &wtmp, sizeof(wtmp)); + close(f); + } + } + chmod(line, 0666); + chown(line, 0, 0); + line[strlen("/dev/")] = 'p'; + chmod(line, 0666); + chown(line, 0, 0); +} /* end of rmut */ +#endif /* CRAY */ + +#if defined(__hpux) && !defined(HAVE_UTMPX_H) +static void +rmut (char *line) { - register char **cpp, **cpp2; - - for (cpp2 = cpp = environ; *cpp; cpp++) { - if (strncmp(*cpp, "LD_", 3) && - strncmp(*cpp, "_RLD_", 5) && - strncmp(*cpp, "LIBPATH=", 8) && - strncmp(*cpp, "TERMINFO=", 9) && - strncmp(*cpp, "TERMINFO_DIRS=", 14) && - strncmp(*cpp, "TERMPATH=", 9) && - strncmp(*cpp, "TERMCAP=/", 9) && - strncmp(*cpp, "ENV=", 4) && - strncmp(*cpp, "IFS=", 4)) - *cpp2++ = *cpp; + struct utmp utmp; + struct utmp *utptr; + int fd; /* for /etc/wtmp */ + + utmp.ut_type = USER_PROCESS; + strncpy(utmp.ut_line, clean_ttyname(line), sizeof(utmp.ut_line)); + setutent(); + utptr = getutline(&utmp); + /* write it out only if it exists */ + if (utptr) { + utptr->ut_type = DEAD_PROCESS; + utptr->ut_time = time(NULL); + pututline(utptr); + /* set wtmp entry if wtmp file exists */ + if ((fd = open(wtmpf, O_WRONLY | O_APPEND)) >= 0) { + write(fd, utptr, sizeof(utmp)); + close(fd); } - *cpp2 = 0; + } + endutent(); + + chmod(line, 0666); + chown(line, 0, 0); + line[14] = line[13]; + line[13] = line[12]; + line[8] = 'm'; + line[9] = '/'; + line[10] = 'p'; + line[11] = 't'; + line[12] = 'y'; + chmod(line, 0666); + chown(line, 0, 0); } +#endif /* * cleanup() @@ -1863,99 +1566,90 @@ scrub_env() * This is the routine to call when we are all through, to * clean up anything that needs to be cleaned up. */ - /* ARGSUSED */ - void -cleanup(sig) - int sig; -{ -#ifndef PARENT_DOES_UTMP -# if (BSD > 43) || defined(convex) - char *p; - - p = line + sizeof("/dev/") - 1; - if (logout(p)) - logwtmp(p, "", ""); - (void)chmod(line, 0666); - (void)chown(line, 0, 0); - *p = 'p'; - (void)chmod(line, 0666); - (void)chown(line, 0, 0); - (void) shutdown(net, 2); - _exit(1); -# else - void rmut(); - rmut(); - vhangup(); /* XXX */ - (void) shutdown(net, 2); - _exit(1); -# endif -#else /* PARENT_DOES_UTMP */ -# ifdef NEWINIT - (void) shutdown(net, 2); - _exit(1); -# else /* NEWINIT */ -# ifdef CRAY - static int incleanup = 0; - register int t; - int child_status; /* status of child process as returned by waitpid */ - int flags = WNOHANG|WUNTRACED; +#ifdef PARENT_DOES_UTMP - /* - * 1: Pick up the zombie, if we are being called - * as the signal handler. - * 2: If we are a nested cleanup(), return. - * 3: Try to clean up TMPDIR. - * 4: Fill in utmp with shutdown of process. - * 5: Close down the network and pty connections. - * 6: Finish up the TMPDIR cleanup, if needed. +void +cleanup(int sig) +{ +#ifdef _CRAY + static int incleanup = 0; + int t; + int child_status; /* status of child process as returned by waitpid */ + int flags = WNOHANG|WUNTRACED; + + /* + * 1: Pick up the zombie, if we are being called + * as the signal handler. + * 2: If we are a nested cleanup(), return. + * 3: Try to clean up TMPDIR. + * 4: Fill in utmp with shutdown of process. + * 5: Close down the network and pty connections. + * 6: Finish up the TMPDIR cleanup, if needed. + */ + if (sig == SIGCHLD) { + while (waitpid(-1, &child_status, flags) > 0) + ; /* VOID */ + /* Check if the child process was stopped + * rather than exited. We want cleanup only if + * the child has died. */ - if (sig == SIGCHLD) { - while (waitpid(-1, &child_status, flags) > 0) - ; /* VOID */ - /* Check if the child process was stopped - * rather than exited. We want cleanup only if - * the child has died. - */ - if (WIFSTOPPED(child_status)) { - return; - } + if (WIFSTOPPED(child_status)) { + return; } - t = sigblock(sigmask(SIGCHLD)); - if (incleanup) { - sigsetmask(t); - return; - } - incleanup = 1; + } + t = sigblock(sigmask(SIGCHLD)); + if (incleanup) { sigsetmask(t); -#ifdef UNICOS7x - if (secflag) { - /* - * We need to set ourselves back to a null - * label to clean up. - */ - - setulvl(sysv.sy_minlvl); - setucmp((long)0); - } -#endif /* UNICOS7x */ - - t = cleantmp(&wtmp); - setutent(); /* just to make sure */ -# endif /* CRAY */ - rmut(line); - close(pty); - (void) shutdown(net, 2); -# ifdef CRAY - if (t == 0) - cleantmp(&wtmp); -# endif /* CRAY */ - _exit(1); -# endif /* NEWINT */ -#endif /* PARENT_DOES_UTMP */ + return; + } + incleanup = 1; + sigsetmask(t); + + t = cleantmp(&wtmp); + setutent(); /* just to make sure */ +#endif /* CRAY */ + rmut(line); + close(ourpty); + shutdown(net, 2); +#ifdef _CRAY + if (t == 0) + cleantmp(&wtmp); +#endif /* CRAY */ + exit(1); } -#if defined(PARENT_DOES_UTMP) && !defined(NEWINIT) +#else /* PARENT_DOES_UTMP */ + +void +cleanup(int sig) +{ +#if defined(HAVE_UTMPX_H) || !defined(HAVE_LOGWTMP) + rmut(); +#ifdef HAVE_VHANGUP +#ifndef __sgi + vhangup(); /* XXX */ +#endif +#endif +#else + char *p; + + p = line + sizeof("/dev/") - 1; + if (logout(p)) + logwtmp(p, "", ""); + chmod(line, 0666); + chown(line, 0, 0); + *p = 'p'; + chmod(line, 0666); + chown(line, 0, 0); +#endif + shutdown(net, 2); + exit(1); +} + +#endif /* PARENT_DOES_UTMP */ + +#ifdef PARENT_DOES_UTMP /* * _utmp_sig_rcv * utmp_sig_init @@ -1969,28 +1663,28 @@ cleanup(sig) static int caught=0; /* NZ when signal intercepted */ static void (*func)(); /* address of previous handler */ - void +void _utmp_sig_rcv(sig) - int sig; + int sig; { - caught = 1; - (void) signal(SIGUSR1, func); + caught = 1; + signal(SIGUSR1, func); } - void +void utmp_sig_init() { - /* - * register signal handler for UTMP creation - */ - if ((int)(func = signal(SIGUSR1, _utmp_sig_rcv)) == -1) - fatalperror(net, "telnetd/signal"); + /* + * register signal handler for UTMP creation + */ + if ((int)(func = signal(SIGUSR1, _utmp_sig_rcv)) == -1) + fatalperror(net, "telnetd/signal"); } - void +void utmp_sig_reset() { - (void) signal(SIGUSR1, func); /* reset handler to default */ + signal(SIGUSR1, func); /* reset handler to default */ } # ifdef __hpux @@ -1998,44 +1692,44 @@ utmp_sig_reset() # define sigon() /* do nothing */ # endif - void +void utmp_sig_wait() { - /* - * Wait for parent to write our utmp entry. + /* + * Wait for parent to write our utmp entry. */ - sigoff(); - while (caught == 0) { - pause(); /* wait until we get a signal (sigon) */ - sigoff(); /* turn off signals while we check caught */ - } - sigon(); /* turn on signals again */ + sigoff(); + while (caught == 0) { + pause(); /* wait until we get a signal (sigon) */ + sigoff(); /* turn off signals while we check caught */ + } + sigon(); /* turn on signals again */ } - void +void utmp_sig_notify(pid) { - kill(pid, SIGUSR1); + kill(pid, SIGUSR1); } -# ifdef CRAY +#ifdef _CRAY static int gotsigjob = 0; /*ARGSUSED*/ - void +void sigjob(sig) - int sig; + int sig; { - register int jid; - register struct jobtemp *jp; - - while ((jid = waitjob(NULL)) != -1) { - if (jid == 0) { - return; - } - gotsigjob++; - jobend(jid, NULL, NULL); + int jid; + struct jobtemp *jp; + + while ((jid = waitjob(NULL)) != -1) { + if (jid == 0) { + return; } + gotsigjob++; + jobend(jid, NULL, NULL); + } } /* @@ -2044,20 +1738,20 @@ sigjob(sig) * to find the correct $TMPDIR to cleanup. */ - struct utmp * +struct utmp * jid_getutid(jid) - int jid; + int jid; { - struct utmp *cur = NULL; + struct utmp *cur = NULL; - setutent(); /* just to make sure */ - while (cur = getutent()) { - if ( (cur->ut_type != NULL) && (jid == cur->ut_jid) ) { - return(cur); - } + setutent(); /* just to make sure */ + while (cur = getutent()) { + if ( (cur->ut_type != NULL) && (jid == cur->ut_jid) ) { + return(cur); } + } - return(0); + return(0); } /* @@ -2068,260 +1762,132 @@ jid_getutid(jid) * when this is called the second time it will wait * for the signal that the job is done. */ - int +int cleantmp(wtp) - register struct utmp *wtp; + struct utmp *wtp; { - struct utmp *utp; - static int first = 1; - register int mask, omask, ret; - extern struct utmp *getutid P((const struct utmp *_Id)); + struct utmp *utp; + static int first = 1; + int mask, omask, ret; + extern struct utmp *getutid (const struct utmp *_Id); - mask = sigmask(WJSIGNAL); + mask = sigmask(WJSIGNAL); - if (first == 0) { - omask = sigblock(mask); - while (gotsigjob == 0) - sigpause(omask); - return(1); - } - first = 0; - setutent(); /* just to make sure */ + if (first == 0) { + omask = sigblock(mask); + while (gotsigjob == 0) + sigpause(omask); + return(1); + } + first = 0; + setutent(); /* just to make sure */ - utp = getutid(wtp); - if (utp == 0) { - syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR"); - return(-1); - } - /* - * Nothing to clean up if the user shell was never started. - */ - if (utp->ut_type != USER_PROCESS || utp->ut_jid == 0) - return(1); + utp = getutid(wtp); + if (utp == 0) { + syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR"); + return(-1); + } + /* + * Nothing to clean up if the user shell was never started. + */ + if (utp->ut_type != USER_PROCESS || utp->ut_jid == 0) + return(1); - /* - * Block the WJSIGNAL while we are in jobend(). - */ - omask = sigblock(mask); - ret = jobend(utp->ut_jid, utp->ut_tpath, utp->ut_user); - sigsetmask(omask); - return(ret); + /* + * Block the WJSIGNAL while we are in jobend(). + */ + omask = sigblock(mask); + ret = jobend(utp->ut_jid, utp->ut_tpath, utp->ut_user); + sigsetmask(omask); + return(ret); } - int +int jobend(jid, path, user) - register int jid; - register char *path; - register char *user; + int jid; + char *path; + char *user; { - static int saved_jid = 0; - static int pty_saved_jid = 0; - static char saved_path[sizeof(wtmp.ut_tpath)+1]; - static char saved_user[sizeof(wtmp.ut_user)+1]; - - /* - * this little piece of code comes into play - * only when ptyreconnect is used to reconnect - * to an previous session. - * - * this is the only time when the - * "saved_jid != jid" code is executed. - */ - - if ( saved_jid && saved_jid != jid ) { - if (!path) { /* called from signal handler */ - pty_saved_jid = jid; - } else { - pty_saved_jid = saved_jid; - } - } - - if (path) { - strlcpy(saved_path, path, sizeof(saved_path)); - strlcpy(saved_user, user, sizeof(saved_user)); - } - if (saved_jid == 0) { - saved_jid = jid; - return(0); + static int saved_jid = 0; + static int pty_saved_jid = 0; + static char saved_path[sizeof(wtmp.ut_tpath)+1]; + static char saved_user[sizeof(wtmp.ut_user)+1]; + + /* + * this little piece of code comes into play + * only when ptyreconnect is used to reconnect + * to an previous session. + * + * this is the only time when the + * "saved_jid != jid" code is executed. + */ + + if ( saved_jid && saved_jid != jid ) { + if (!path) { /* called from signal handler */ + pty_saved_jid = jid; + } else { + pty_saved_jid = saved_jid; } + } + + if (path) { + strncpy(saved_path, path, sizeof(wtmp.ut_tpath)); + strncpy(saved_user, user, sizeof(wtmp.ut_user)); + saved_path[sizeof(saved_path)] = '\0'; + saved_user[sizeof(saved_user)] = '\0'; + } + if (saved_jid == 0) { + saved_jid = jid; + return(0); + } - /* if the jid has changed, get the correct entry from the utmp file */ - - if ( saved_jid != jid ) { - struct utmp *utp = NULL; - struct utmp *jid_getutid(); + /* if the jid has changed, get the correct entry from the utmp file */ - utp = jid_getutid(pty_saved_jid); + if ( saved_jid != jid ) { + struct utmp *utp = NULL; + struct utmp *jid_getutid(); - if (utp == 0) { - syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR"); - return(-1); - } + utp = jid_getutid(pty_saved_jid); - cleantmpdir(jid, utp->ut_tpath, utp->ut_user); - return(1); + if (utp == 0) { + syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR"); + return(-1); } - cleantmpdir(jid, saved_path, saved_user); + cleantmpdir(jid, utp->ut_tpath, utp->ut_user); return(1); + } + + cleantmpdir(jid, saved_path, saved_user); + return(1); } /* * Fork a child process to clean up the TMPDIR */ cleantmpdir(jid, tpath, user) - register int jid; - register char *tpath; - register char *user; + int jid; + char *tpath; + char *user; { - switch(fork()) { - case -1: - syslog(LOG_ERR, "TMPDIR cleanup(%s): fork() failed: %m", - tpath); - break; - case 0: - execl(CLEANTMPCMD, CLEANTMPCMD, user, tpath, 0); - syslog(LOG_ERR, "TMPDIR cleanup(%s): execl(%s) failed: %m", - tpath, CLEANTMPCMD); - exit(1); - default: - /* - * Forget about child. We will exit, and - * /etc/init will pick it up. - */ - break; - } -} -# endif /* CRAY */ -#endif /* defined(PARENT_DOES_UTMP) && !defined(NEWINIT) */ - -/* - * rmut() - * - * This is the function called by cleanup() to - * remove the utmp entry for this person. - */ - -#ifdef UTMPX - void -rmut() -{ - register f; - int found = 0; - struct utmp *u, *utmp; - int nutmp; - struct stat statbf; - - struct utmpx *utxp, utmpx; - + switch(fork()) { + case -1: + syslog(LOG_ERR, "TMPDIR cleanup(%s): fork() failed: %m\n", + tpath); + break; + case 0: + execl(CLEANTMPCMD, CLEANTMPCMD, user, tpath, 0); + syslog(LOG_ERR, "TMPDIR cleanup(%s): execl(%s) failed: %m\n", + tpath, CLEANTMPCMD); + exit(1); + default: /* - * This updates the utmpx and utmp entries and make a wtmp/x entry + * Forget about child. We will exit, and + * /etc/init will pick it up. */ - - SCPYN(utmpx.ut_line, line + sizeof("/dev/") - 1); - utxp = getutxline(&utmpx); - if (utxp) { - utxp->ut_type = DEAD_PROCESS; - utxp->ut_exit.e_termination = 0; - utxp->ut_exit.e_exit = 0; - (void) time(&utmpx.ut_tv.tv_sec); - utmpx.ut_tv.tv_usec = 0; - modutx(utxp); - } - endutxent(); -} /* end of rmut */ -#endif - -#if !defined(UTMPX) && !(defined(CRAY) || defined(__hpux)) && BSD <= 43 - void -rmut() -{ - register f; - int found = 0; - struct utmp *u, *utmp; - int nutmp; - struct stat statbf; - - f = open(utmpf, O_RDWR); - if (f >= 0) { - (void) fstat(f, &statbf); - utmp = (struct utmp *)malloc((unsigned)statbf.st_size); - if (!utmp) - syslog(LOG_ERR, "utmp malloc failed"); - if (statbf.st_size && utmp) { - nutmp = read(f, (char *)utmp, (int)statbf.st_size); - nutmp /= sizeof(struct utmp); - - for (u = utmp ; u < &utmp[nutmp] ; u++) { - if (SCMPN(u->ut_line, line+5) || - u->ut_name[0]==0) - continue; - (void) lseek(f, ((off_t)u)-((off_t)utmp), - SEEK_SET); - SCPYN(u->ut_name, ""); - SCPYN(u->ut_host, ""); - (void) time(&u->ut_time); - (void) write(f, (char *)u, sizeof(wtmp)); - found++; - } - } - (void) close(f); - } - if (found) { - f = open(wtmpf, O_WRONLY|O_APPEND); - if (f >= 0) { - SCPYN(wtmp.ut_line, line+5); - SCPYN(wtmp.ut_name, ""); - SCPYN(wtmp.ut_host, ""); - (void) time(&wtmp.ut_time); - (void) write(f, (char *)&wtmp, sizeof(wtmp)); - (void) close(f); - } - } - (void) chmod(line, 0666); - (void) chown(line, 0, 0); - line[strlen("/dev/")] = 'p'; - (void) chmod(line, 0666); - (void) chown(line, 0, 0); -} /* end of rmut */ -#endif /* CRAY */ - -#ifdef __hpux -rmut (line) -char *line; -{ - struct utmp utmp; - struct utmp *utptr; - int fd; /* for /etc/wtmp */ - - utmp.ut_type = USER_PROCESS; - (void) strncpy(utmp.ut_id, line+12, sizeof(utmp.ut_id)); - (void) setutent(); - utptr = getutid(&utmp); - /* write it out only if it exists */ - if (utptr) { - utptr->ut_type = DEAD_PROCESS; - utptr->ut_time = time((time_t *) 0); - (void) pututline(utptr); - /* set wtmp entry if wtmp file exists */ - if ((fd = open(wtmpf, O_WRONLY | O_APPEND)) >= 0) { - (void) write(fd, utptr, sizeof(utmp)); - (void) close(fd); - } - } - (void) endutent(); - - (void) chmod(line, 0666); - (void) chown(line, 0, 0); - line[14] = line[13]; - line[13] = line[12]; - line[8] = 'm'; - line[9] = '/'; - line[10] = 'p'; - line[11] = 't'; - line[12] = 'y'; - (void) chmod(line, 0666); - (void) chown(line, 0, 0); + break; + } } -#endif +#endif /* CRAY */ +#endif /* defined(PARENT_DOES_UTMP) */ diff --git a/libexec/telnetd/telnetd.8 b/libexec/telnetd/telnetd.8 index 114af084840..1e14425ee1c 100644 --- a/libexec/telnetd/telnetd.8 +++ b/libexec/telnetd/telnetd.8 @@ -1,6 +1,3 @@ -.\" $OpenBSD: telnetd.8,v 1.17 2000/10/30 17:46:29 aaron Exp $ -.\" $NetBSD: telnetd.8,v 1.8 1996/03/20 04:25:55 tls Exp $ -.\" .\" Copyright (c) 1983, 1993 .\" The Regents of the University of California. All rights reserved. .\" @@ -32,11 +29,11 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" from: @(#)telnetd.8 8.3 (Berkeley) 3/1/94 +.\" @(#)telnetd.8 8.4 (Berkeley) 6/1/94 .\" -.Dd March 1, 1994 +.Dd June 1, 1994 .Dt TELNETD 8 -.Os +.Os BSD 4.2 .Sh NAME .Nm telnetd .Nd DARPA @@ -44,25 +41,25 @@ protocol server .Sh SYNOPSIS .Nm telnetd -.Op Fl Uhlkn46 +.Op Fl BUhkln .Op Fl D Ar debugmode -.Op Fl I Ns Ar initid .Op Fl S Ar tos .Op Fl X Ar authtype .Op Fl a Ar authmode -.Op Fl g Ar gettyent .Op Fl r Ns Ar lowpty-highpty .Op Fl u Ar len -.Op Fl debug Op Ar port +.Op Fl debug +.Op Fl L Ar /bin/login +.Op Ar port .Sh DESCRIPTION The -.Nm +.Nm telnetd command is a server which supports the .Tn DARPA standard .Tn TELNET virtual terminal protocol. -.Nm +.Nm Telnetd is normally invoked by the internet server (see .Xr inetd 8 ) for requests to connect to the @@ -74,28 +71,28 @@ file (see The .Fl debug option may be used to start up -.Nm +.Nm telnetd manually, instead of through .Xr inetd 8 . -If started up this way, +If started up this way, .Ar port may be specified to run -.Nm +.Nm telnetd on an alternate .Tn TCP port number. .Pp The -.Nm +.Nm telnetd command accepts the following options: .Bl -tag -width "-a authmode" .It Fl a Ar authmode This option may be used for specifying what mode should be used for authentication. Note that this option is only useful if -.Nm +.Nm telnetd has been compiled with support for the -.Cm AUTHENTICATION +.Dv AUTHENTICATION option. There are several valid values for .Ar authmode : @@ -103,43 +100,59 @@ There are several valid values for .It debug Turns on authentication debugging code. .It user -Only allow connections when the remote user can provide valid authentication -information to identify the remote user, and is allowed access to the -specified account without providing a password. +Only allow connections when the remote user +can provide valid authentication information +to identify the remote user, +and is allowed access to the specified account +without providing a password. .It valid -Only allow connections when the remote user can provide valid authentication -information to identify the remote user. +Only allow connections when the remote user +can provide valid authentication information +to identify the remote user. The .Xr login 1 -command will provide any additional user verification needed if the remote -user is not allowed automatic access to the specified account. +command will provide any additional user verification +needed if the remote user is not allowed automatic +access to the specified account. .It other Only allow connections that supply some authentication information. -This option is currently not supported by any of the existing authentication -mechanisms, and is thus the same as specifying +This option is currently not supported +by any of the existing authentication mechanisms, +and is thus the same as specifying .Fl a .Cm valid . +.It otp +Only allow authenticated connections (as with +.Fl a +.Cm user ) +and also logins with one-time passwords (OTPs). This option will call +login with an option so that only OTPs are accepted. The user can of +course still type secret information at the prompt. .It none This is the default state. Authentication information is not required. -If no or insufficient authentication information is provided, then the +If no or insufficient authentication information +is provided, then the .Xr login 1 -program will provide the necessary user verification. +program will provide the necessary user +verification. .It off This disables the authentication code. All user verification will happen through the .Xr login 1 program. .El +.It Fl B +Ignored. .It Fl D Ar debugmode This option may be used for debugging purposes. This allows -.Nm +.Nm telnetd to print out debugging information to the connection, allowing the user to see what -.Nm +.Nm telnetd is doing. -There are several possible values for +There are several possible values for .Ar debugmode : .Bl -tag -width exercise .It Cm options @@ -147,10 +160,10 @@ Prints information about the negotiation of .Tn TELNET options. .It Cm report -Prints the +Prints the .Cm options -information, plus some additional information about what processing -is going on. +information, plus some additional information +about what processing is going on. .It Cm netdata Displays the data stream received by .Nm telnetd . @@ -159,72 +172,17 @@ Displays data written to the pty. .It Cm exercise Has not been implemented yet. .El -.It Fl debug -Enables debugging on each socket created by -.Nm -(see -.Dv SO_DEBUG -in -.Xr socket 2 ) . -.It Fl g Ar gettyent -Specifies which entry from -.Pa /etc/gettytab -should be used to get banner strings, login program and other information. -The default entry is -.Dq default. .It Fl h Disables the printing of host-specific information before login has been completed. -.It Fl I Ar initid -This option is only applicable to -.Tn UNICOS -systems prior to 7.0. -It specifies the -.Em ID -from -.Pa /etc/inittab -to use when init starts login sessions. -The default ID is -.Dq fe . .It Fl k -This option is only useful if -.Nm -has been compiled with both linemode and kludge linemode support. -If the -.Fl k -option is specified, then if the remote client does not support the -.Cm LINEMODE -option, then -.Nm -will operate in character at a time mode. -It will still support kludge linemode, but will only -go into kludge linemode if the remote client requests -it. -(This is done by the client sending -.Tn DONT SUPPRESS-GO-AHEAD -and -.Tn DONT ECHO . ) -The -.Fl k -option is most useful when there are remote clients -that do not support kludge linemode, but pass the heuristic -(if they respond with -.Tn WILL TIMING-MARK -in response to a -.Tn DO TIMING-MARK) -for kludge linemode support. .It Fl l -Specifies line mode. -Tries to force clients to use line-at-a-time mode. -If the -.Tn LINEMODE -option is not supported, it will go into kludge linemode. +Ignored. .It Fl n Disable -.Tn TCP -keep-alives. -Normally -.Nm +.Dv TCP +keep-alives. Normally +.Nm telnetd enables the .Tn TCP keep-alive mechanism to probe connections that @@ -234,32 +192,32 @@ from machines that have crashed or can no longer be reached may be cleaned up. .It Fl r Ar lowpty-highpty This option is only enabled when -.Nm +.Nm telnetd is compiled for -.Tn UNICOS . -It specifies an inclusive range of pseudo-terminal devices to use. -If the system has sysconf variable +.Dv UNICOS . +It specifies an inclusive range of pseudo-terminal devices to +use. If the system has sysconf variable .Dv _SC_CRAY_NPTY configured, the default pty search range is 0 to -.Dv _SC_CRAY_NPTY; -otherwise, the default range is 0 to 128. -Either +.Dv _SC_CRAY_NPTY ; +otherwise, the default range is 0 to 128. Either .Ar lowpty or .Ar highpty -may be omitted to allow changing either end of the search range. -If +may be omitted to allow changing +either end of the search range. If .Ar lowpty is omitted, the - character is still required so that -.Nm +.Nm telnetd can differentiate .Ar highpty from .Ar lowpty . .It Fl S Ar tos .It Fl u Ar len -This option is used to specify the size of the field in the -.Li utmp +This option is used to specify the size of the field +in the +.Dv utmp structure that holds the remote host name. If the resolved host name is longer than .Ar len , @@ -274,46 +232,36 @@ should be put into the file. .It Fl U This option causes -.Nm -to refuse connections from addresses that cannot be mapped back into a -symbolic name via the +.Nm telnetd +to refuse connections from addresses that +cannot be mapped back into a symbolic name via the .Xr gethostbyaddr 3 routine. .It Fl X Ar authtype This option is only valid if -.Nm +.Nm telnetd has been built with support for the authentication option. It disables the use of .Ar authtype -authentication, and can be used to temporarily disable +authentication, and +can be used to temporarily disable a specific authentication type without having to recompile .Nm telnetd . -.It Fl 4 -.It Fl 6 -Specifies address family to be used on -.Fl debug -mode. -During normal operation -.Po -called from -.Xr inetd 8 -.Pc -.Nm -will use the file descriptor passed from -.Xr inetd 8 . +.It Fl L pathname +Specify pathname to an alternative login program. .El .Pp -.Nm +.Nm Telnetd operates by allocating a pseudo-terminal device (see .Xr pty 4 ) for a client, then creating a login process which has -the slave side of the pseudo-terminal as -.Li stdin , -.Li stdout , +the slave side of the pseudo-terminal as +.Dv stdin , +.Dv stdout and -.Li stderr . -.Nm +.Dv stderr . +.Nm Telnetd manipulates the master side of the pseudo-terminal, implementing the .Tn TELNET @@ -322,8 +270,8 @@ between the remote client and the login process. .Pp When a .Tn TELNET -session is started up, -.Nm +session is started up, +.Nm telnetd sends .Tn TELNET options to the client side indicating @@ -349,34 +297,36 @@ DO TIMING-MARK .Ed .Pp The pseudo-terminal allocated to the client is configured -to operate in \*(lqcooked\*(rq mode, and with +to operate in +.Dq cooked +mode, and with .Dv XTABS and .Dv CRMOD enabled (see .Xr tty 4 ) . .Pp -.Nm +.Nm Telnetd has support for enabling locally the following .Tn TELNET options: .Bl -tag -width "DO AUTHENTICATION" .It "WILL ECHO" When the -.Cm LINEMODE +.Dv LINEMODE option is enabled, a -.Tn WILL ECHO +.Dv WILL ECHO or -.Tn WONT ECHO +.Dv WONT ECHO will be sent to the client to indicate the current state of terminal echoing. When terminal echo is not desired, a -.Tn WILL ECHO +.Dv WILL ECHO is sent to indicate that .Tn telnetd will take care of echoing any data that needs to be echoed to the terminal, and then nothing is echoed. When terminal echo is desired, a -.Tn WONT ECHO +.Dv WONT ECHO is sent to indicate that .Tn telnetd will not be doing any terminal echoing, so the @@ -387,7 +337,7 @@ Indicates that the client is willing to send a of the Network Virtual Terminal. .It "WILL SGA" Indicates that it will not be sending -.Tn IAC GA , +.Dv IAC GA , go ahead, commands. .It "WILL STATUS" Indicates a willingness to send the client, upon @@ -396,27 +346,27 @@ request, of the current status of all options. .It "WILL TIMING-MARK" Whenever a -.Tn DO TIMING-MARK +.Dv DO TIMING-MARK command is received, it is always responded to with a -.Tn WILL TIMING-MARK +.Dv WILL TIMING-MARK .It "WILL LOGOUT" When a -.Tn DO LOGOUT +.Dv DO LOGOUT is received, a -.Tn WILL LOGOUT +.Dv WILL LOGOUT is sent in response, and the .Tn TELNET session is shut down. .It "WILL ENCRYPT" Only sent if -.Nm +.Nm telnetd is compiled with support for data encryption, and indicates a willingness to decrypt the data stream. .El .Pp -.Nm +.Nm Telnetd has support for enabling remotely the following .Tn TELNET options: @@ -429,15 +379,14 @@ is willing to receive an 8 bit data stream. Requests that the client handle flow control characters remotely. .It "DO ECHO" -This is not really supported, but is sent to identify a -.Bx 4.2 +This is not really supported, but is sent to identify a 4.2BSD .Xr telnet 1 client, which will improperly respond with -.Tn WILL ECHO . +.Dv WILL ECHO . If a -.Tn WILL ECHO +.Dv WILL ECHO is received, a -.Tn DONT ECHO +.Dv DONT ECHO will be sent in response. .It "DO TERMINAL-TYPE" Indicates a desire to be able to request the @@ -445,7 +394,7 @@ name of the type of terminal that is attached to the client side of the connection. .It "DO SGA" Indicates that it does not need to receive -.Tn IAC GA , +.Dv IAC GA , the go ahead command. .It "DO NAWS" Requests that the client inform the server when @@ -466,17 +415,17 @@ Indicates a desire to be able to request environment variable information, as described in RFC 1408. .It "DO LINEMODE" Only sent if -.Nm +.Nm telnetd is compiled with support for linemode, and requests that the client do line by line processing. .It "DO TIMING-MARK" Only sent if -.Nm +.Nm telnetd is compiled with support for both linemode and kludge linemode, and the client responded with -.Tn WONT LINEMODE . +.Dv WONT LINEMODE . If the client responds with -.Tn WILL TM , +.Dv WILL TM , the it is assumed that the client supports kludge linemode. Note that the @@ -484,18 +433,18 @@ Note that the option can be used to disable this. .It "DO AUTHENTICATION" Only sent if -.Nm +.Nm telnetd is compiled with support for authentication, and indicates a willingness to receive authentication information for automatic login. .It "DO ENCRYPT" Only sent if -.Nm +.Nm telnetd is compiled with support for data encryption, and indicates a willingness to decrypt the data stream. .El -.\" .Sh ENVIRONMENT +.Sh ENVIRONMENT .Sh FILES .Bl -tag -width /etc/services -compact .It Pa /etc/services @@ -504,9 +453,9 @@ the data stream. .It Pa /etc/iptos (if supported) .El -.Sh SEE ALSO -.Xr login 1 , -.Xr telnet 1 +.Sh "SEE ALSO" +.Xr telnet 1 , +.Xr login 1 .Sh STANDARDS .Bl -tag -compact -width RFC-1572 .It Cm RFC-854 @@ -560,7 +509,7 @@ commands are only partially implemented. .Pp Because of bugs in the original 4.2 BSD .Xr telnet 1 , -.Nm +.Nm telnetd performs some dubious protocol exchanges to try to discover if the remote client is, in fact, a 4.2 BSD .Xr telnet 1 . @@ -572,15 +521,8 @@ has no common interpretation except between similar operating systems The terminal type name received from the remote client is converted to lower case. .Pp -.Nm +.Nm Telnetd never sends .Tn TELNET -.Tn IAC GA +.Dv IAC GA (go ahead) commands. -.Pp -.Tn WONT CRYPT . -.Nm -talks over insecure, unencrypted communications channels. -Please use -.Xr sshd 8 -instead. diff --git a/libexec/telnetd/telnetd.c b/libexec/telnetd/telnetd.c index 5da6b9a4164..0382c14801b 100644 --- a/libexec/telnetd/telnetd.c +++ b/libexec/telnetd/telnetd.c @@ -1,6 +1,3 @@ -/* $OpenBSD: telnetd.c,v 1.29 2001/06/11 15:18:52 mickey Exp $ */ -/* $NetBSD: telnetd.c,v 1.6 1996/03/20 04:25:57 tls Exp $ */ - /* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. @@ -34,79 +31,61 @@ * SUCH DAMAGE. */ -#ifndef lint -static char copyright[] = -"@(#) Copyright (c) 1989, 1993\n\ - The Regents of the University of California. All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -#if 0 -static char sccsid[] = "@(#)telnetd.c 8.4 (Berkeley) 5/30/95"; -static char rcsid[] = "$NetBSD: telnetd.c,v 1.5 1996/02/28 20:38:23 thorpej Exp $"; -#else -static char rcsid[] = "$OpenBSD: telnetd.c,v 1.29 2001/06/11 15:18:52 mickey Exp $"; -#endif -#endif /* not lint */ - -#include <curses.h> -#include <term.h> #include "telnetd.h" -#include "pathnames.h" +#include <sys/socket.h> +#include <netdb.h> +#include <fcntl.h> +#include <syslog.h> +#include <unistd.h> +#include <sys/ioctl.h> -#include <sys/cdefs.h> -#define P __P - -void doit P((struct sockaddr *)); -void startslave P((char *, int, char *)); -int terminaltypeok P((char *)); - - -#if defined(_SC_CRAY_SECURE_SYS) && !defined(SCM_SECURITY) -/* - * UNICOS 6.0/6.1 do not have SCM_SECURITY defined, so we can - * use it to tell us to turn off all the socket security code, - * since that is only used in UNICOS 7.0 and later. - */ -# undef _SC_CRAY_SECURE_SYS -#endif +/* RCSID("$KTH: telnetd.c,v 1.64 2001/02/08 16:06:27 assar Exp $"); */ -#if defined(_SC_CRAY_SECURE_SYS) +#ifdef _SC_CRAY_SECURE_SYS #include <sys/sysv.h> #include <sys/secdev.h> -# ifdef SO_SEC_MULTI /* 8.0 code */ #include <sys/secparm.h> #include <sys/usrv.h> -# endif /* SO_SEC_MULTI */ int secflag; char tty_dev[16]; struct secdev dv; struct sysv sysv; -# ifdef SO_SEC_MULTI /* 8.0 code */ struct socksec ss; -# else /* SO_SEC_MULTI */ /* 7.0 code */ -struct socket_security ss; -# endif /* SO_SEC_MULTI */ #endif /* _SC_CRAY_SECURE_SYS */ -#if defined(AUTHENTICATION) -#include <libtelnet/auth.h> +#ifdef AUTHENTICATION int auth_level = 0; #endif -#if defined(ENCRYPTION) -#include <libtelnet/encrypt.h> -#include <libtelnet/misc-proto.h> -#endif extern int utmp_len; int registerd_host_only = 0; #ifdef STREAMSPTY # include <stropts.h> -# include <termio.h> +# include <termios.h> +#ifdef HAVE_SYS_UIO_H +#include <sys/uio.h> +#endif /* HAVE_SYS_UIO_H */ +#ifdef HAVE_SYS_STREAM_H +#include <sys/stream.h> +#endif +#ifdef _AIX +#include <sys/termio.h> +#endif +# ifdef HAVE_SYS_STRTTY_H +# include <sys/strtty.h> +# endif +# ifdef HAVE_SYS_STR_TTY_H +# include <sys/str_tty.h> +# endif /* make sure we don't get the bsd version */ +/* what is this here for? solaris? /joda */ +# ifdef HAVE_SYS_TTY_H # include "/usr/include/sys/tty.h" +# endif +# ifdef HAVE_SYS_PTYVAR_H # include <sys/ptyvar.h> +# endif /* * Because of the way ptyibuf is used with streams messages, we need @@ -120,7 +99,7 @@ char ptyibuf2[BUFSIZ]; unsigned char ctlbuf[BUFSIZ]; struct strbuf strbufc, strbufd; -int readstream(); +int readstream(int, char*, int); #else /* ! STREAMPTY */ @@ -135,448 +114,377 @@ char ptyibuf2[BUFSIZ]; int hostinfo = 1; /* do we print login banner? */ -#ifdef CRAY +#ifdef _CRAY extern int newmap; /* nonzero if \n maps to ^M^J */ int lowpty = 0, highpty; /* low, high pty numbers */ #endif /* CRAY */ int debug = 0; int keepalive = 1; -char *gettyname = "default"; char *progname; -extern void usage P((void)); +static void usage (void); /* * The string to pass to getopt(). We do it this way so * that only the actual options that we support will be * passed off to getopt(). */ -char valid_opts[] = { - 'd', ':', 'g', ':', 'h', 'k', 'n', 'S', ':', 'u', ':', 'U', - '4', '6', -#ifdef AUTHENTICATION - 'a', ':', 'X', ':', -#endif -#ifdef BFTPDAEMON - 'B', +char valid_opts[] = "Bd:hklnS:u:UL:y" +#ifdef AUTHENTICATION + "a:X:z" #endif #ifdef DIAGNOSTICS - 'D', ':', -#endif -#if defined(CRAY) && defined(NEWINIT) - 'I', ':', + "D:" #endif -#ifdef LINEMODE - 'l', +#ifdef _CRAY + "r:" #endif -#ifdef CRAY - 'r', ':', -#endif - '\0' -}; + ; -int family = AF_INET; +static void doit(struct sockaddr*, int); - int -main(argc, argv) - char *argv[]; +int +main(int argc, char **argv) { - struct sockaddr_storage from; - int on = 1, fromlen; - register int ch; - extern char *optarg; - extern int optind; + struct sockaddr_storage __ss; + struct sockaddr *sa = (struct sockaddr *)&__ss; + int on = 1; + socklen_t sa_size; + int ch; #if defined(IPPROTO_IP) && defined(IP_TOS) - int tos = -1; + int tos = -1; #endif - #ifdef ENCRYPTION - extern int des_check_key; - des_check_key = 1; /* Kludge for Mac NCSA telnet 2.6 /bg */ + extern int des_check_key; + des_check_key = 1; /* Kludge for Mac NCSA telnet 2.6 /bg */ #endif + pfrontp = pbackp = ptyobuf; + netip = netibuf; + nfrontp = nbackp = netobuf; - pfrontp = pbackp = ptyobuf; - netip = netibuf; - nfrontp = nbackp = netobuf; - - progname = *argv; + progname = *argv; #ifdef ENCRYPTION - nclearto = 0; + nclearto = 0; #endif -#ifdef CRAY - /* - * Get number of pty's before trying to process options, - * which may include changing pty range. - */ - highpty = getnpty(); +#ifdef _CRAY + /* + * Get number of pty's before trying to process options, + * which may include changing pty range. + */ + highpty = getnpty(); #endif /* CRAY */ - while ((ch = getopt(argc, argv, valid_opts)) != -1) { - switch(ch) { + while ((ch = getopt(argc, argv, valid_opts)) != -1) { + switch(ch) { #ifdef AUTHENTICATION - case 'a': - /* - * Check for required authentication level - */ - if (strcmp(optarg, "debug") == 0) { - auth_debug_mode = 1; - } else if (strcasecmp(optarg, "none") == 0) { - auth_level = 0; - } else if (strcasecmp(optarg, "other") == 0) { - auth_level = AUTH_OTHER; - } else if (strcasecmp(optarg, "user") == 0) { - auth_level = AUTH_USER; - } else if (strcasecmp(optarg, "valid") == 0) { - auth_level = AUTH_VALID; - } else if (strcasecmp(optarg, "off") == 0) { - /* - * This hack turns off authentication - */ - auth_level = -1; - } else { - fprintf(stderr, - "telnetd: unknown authorization level for -a\n"); - } - break; + case 'a': + /* + * Check for required authentication level + */ + if (strcmp(optarg, "debug") == 0) { + auth_debug_mode = 1; + } else if (strcasecmp(optarg, "none") == 0) { + auth_level = 0; + } else if (strcasecmp(optarg, "otp") == 0) { + auth_level = 0; + require_otp = 1; + } else if (strcasecmp(optarg, "other") == 0) { + auth_level = AUTH_OTHER; + } else if (strcasecmp(optarg, "user") == 0) { + auth_level = AUTH_USER; + } else if (strcasecmp(optarg, "valid") == 0) { + auth_level = AUTH_VALID; + } else if (strcasecmp(optarg, "off") == 0) { + /* + * This hack turns off authentication + */ + auth_level = -1; + } else { + fprintf(stderr, + "telnetd: unknown authorization level for -a\n"); + } + break; #endif /* AUTHENTICATION */ -#ifdef BFTPDAEMON - case 'B': - bftpd++; - break; -#endif /* BFTPDAEMON */ - - case 'd': - if (strcmp(optarg, "ebug") == 0) { - debug++; - break; - } - usage(); - /* NOTREACHED */ - break; + case 'B': /* BFTP mode is not supported any more */ + break; + case 'd': + if (strcmp(optarg, "ebug") == 0) { + debug++; + break; + } + usage(); + /* NOTREACHED */ + break; #ifdef DIAGNOSTICS - case 'D': - /* - * Check for desired diagnostics capabilities. - */ - if (!strcmp(optarg, "report")) { - diagnostic |= TD_REPORT|TD_OPTIONS; - } else if (!strcmp(optarg, "exercise")) { - diagnostic |= TD_EXERCISE; - } else if (!strcmp(optarg, "netdata")) { - diagnostic |= TD_NETDATA; - } else if (!strcmp(optarg, "ptydata")) { - diagnostic |= TD_PTYDATA; - } else if (!strcmp(optarg, "options")) { - diagnostic |= TD_OPTIONS; - } else { - usage(); - /* NOT REACHED */ - } - break; + case 'D': + /* + * Check for desired diagnostics capabilities. + */ + if (!strcmp(optarg, "report")) { + diagnostic |= TD_REPORT|TD_OPTIONS; + } else if (!strcmp(optarg, "exercise")) { + diagnostic |= TD_EXERCISE; + } else if (!strcmp(optarg, "netdata")) { + diagnostic |= TD_NETDATA; + } else if (!strcmp(optarg, "ptydata")) { + diagnostic |= TD_PTYDATA; + } else if (!strcmp(optarg, "options")) { + diagnostic |= TD_OPTIONS; + } else { + usage(); + /* NOT REACHED */ + } + break; #endif /* DIAGNOSTICS */ - case 'g': - gettyname = optarg; - break; - case 'h': - hostinfo = 0; - break; + case 'h': + hostinfo = 0; + break; -#if defined(CRAY) && defined(NEWINIT) - case 'I': - { - extern char *gen_id; - gen_id = optarg; - break; - } -#endif /* defined(CRAY) && defined(NEWINIT) */ + case 'k': /* Linemode is not supported any more */ + case 'l': + break; -#ifdef LINEMODE - case 'l': - alwayslinemode = 1; - break; -#endif /* LINEMODE */ + case 'n': + keepalive = 0; + break; - case 'k': -#if defined(LINEMODE) && defined(KLUDGELINEMODE) - lmodetype = NO_AUTOKLUDGE; -#else - /* ignore -k option if built without kludge linemode */ -#endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ - break; - - case 'n': - keepalive = 0; - break; +#ifdef _CRAY + case 'r': + { + char *strchr(); + char *c; -#ifdef CRAY - case 'r': - { - char *strchr(); - char *c; - - /* - * Allow the specification of alterations - * to the pty search range. It is legal to - * specify only one, and not change the - * other from its default. - */ - c = strchr(optarg, '-'); - if (c) { - *c++ = '\0'; - highpty = atoi(c); - } - if (*optarg != '\0') - lowpty = atoi(optarg); - if ((lowpty > highpty) || (lowpty < 0) || - (highpty > 32767)) { - usage(); - /* NOT REACHED */ - } - break; - } + /* + * Allow the specification of alterations + * to the pty search range. It is legal to + * specify only one, and not change the + * other from its default. + */ + c = strchr(optarg, '-'); + if (c) { + *c++ = '\0'; + highpty = atoi(c); + } + if (*optarg != '\0') + lowpty = atoi(optarg); + if ((lowpty > highpty) || (lowpty < 0) || + (highpty > 32767)) { + usage(); + /* NOT REACHED */ + } + break; + } #endif /* CRAY */ - case 'S': -#ifdef HAS_GETTOS - if ((tos = parsetos(optarg, "tcp")) < 0) - fprintf(stderr, "%s%s%s\n", - "telnetd: Bad TOS argument '", optarg, - "'; will try to use default TOS"); + case 'S': +#ifdef HAVE_PARSETOS + if ((tos = parsetos(optarg, "tcp")) < 0) + fprintf(stderr, "%s%s%s\n", + "telnetd: Bad TOS argument '", optarg, + "'; will try to use default TOS"); #else - fprintf(stderr, "%s%s\n", "TOS option unavailable; ", - "-S flag not supported\n"); + fprintf(stderr, "%s%s\n", "TOS option unavailable; ", + "-S flag not supported\n"); #endif - break; + break; - case 'u': - utmp_len = atoi(optarg); - break; + case 'u': { + char *eptr; - case 'U': - registerd_host_only = 1; - break; + utmp_len = strtol(optarg, &eptr, 0); + if (optarg == eptr) + fprintf(stderr, "telnetd: unknown utmp len (%s)\n", optarg); + break; + } + + case 'U': + registerd_host_only = 1; + break; #ifdef AUTHENTICATION - case 'X': - /* - * Check for invalid authentication types - */ - auth_disable_name(optarg); - break; + case 'X': + /* + * Check for invalid authentication types + */ + auth_disable_name(optarg); + break; +#endif + case 'y': + no_warn = 1; + break; +#ifdef AUTHENTICATION + case 'z': + log_unauth = 1; + break; + #endif /* AUTHENTICATION */ - case '4': - family = AF_INET; - break; + case 'L': + new_login = optarg; + break; - case '6': - family = AF_INET6; - break; - - default: - fprintf(stderr, "telnetd: %c: unknown option\n", ch); - /* FALLTHROUGH */ - case '?': - usage(); - /* NOTREACHED */ - } + default: + fprintf(stderr, "telnetd: %c: unknown option\n", ch); + /* FALLTHROUGH */ + case '?': + usage(); + /* NOTREACHED */ } + } - argc -= optind; - argv += optind; - - if (debug) { - int s, ns, foo, error; - char *service = "telnet"; - struct addrinfo hints, *res; + argc -= optind; + argv += optind; - if (argc > 1) { - usage(); - /* NOT REACHED */ - } else if (argc == 1) - service = *argv; - - memset(&hints, 0, sizeof(hints)); - hints.ai_flags = AI_PASSIVE; - hints.ai_family = family; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = 0; - error = getaddrinfo(NULL, service, &hints, &res); - - if (error) { - fprintf(stderr, "tcp/%s: %s\n", service, gai_strerror(error)); - exit(1); - } + if (debug) { + int port = 0; + struct servent *sp; - s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); - if (s < 0) { - perror("telnetd: socket"); - exit(1); - } - (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, - (char *)&on, sizeof(on)); - if (bind(s, res->ai_addr, res->ai_addrlen) < 0) { - perror("bind"); - exit(1); - } - if (listen(s, 1) < 0) { - perror("listen"); - exit(1); - } - foo = res->ai_addrlen; - ns = accept(s, res->ai_addr, &foo); - if (ns < 0) { - perror("accept"); - exit(1); - } - (void) dup2(ns, 0); - (void) close(ns); - (void) close(s); -#ifdef convex + if (argc > 1) { + usage (); } else if (argc == 1) { - ; /* VOID*/ /* Just ignore the host/port name */ + sp = getservbyname (*argv, "tcp"); + if (sp) + port = sp->s_port; + else + port = htons(atoi(*argv)); + } else { +#ifdef KRB5 + port = krb5_getportbyname (NULL, "telnet", "tcp", 23); +#else + port = k_getportbyname("telnet", "tcp", htons(23)); #endif - } else if (argc > 0) { - usage(); - /* NOT REACHED */ } + mini_inetd (port); + } else if (argc > 0) { + usage(); + /* NOT REACHED */ + } -#if defined(_SC_CRAY_SECURE_SYS) - secflag = sysconf(_SC_CRAY_SECURE_SYS); +#ifdef _SC_CRAY_SECURE_SYS + secflag = sysconf(_SC_CRAY_SECURE_SYS); - /* - * Get socket's security label - */ - if (secflag) { - int szss = sizeof(ss); -#ifdef SO_SEC_MULTI /* 8.0 code */ - int sock_multi; - int szi = sizeof(int); -#endif /* SO_SEC_MULTI */ + /* + * Get socket's security label + */ + if (secflag) { + socklen_t szss = sizeof(ss); + int sock_multi; + socklen_t szi = sizeof(int); - memset((void *)&dv, 0, sizeof(dv)); + memset(&dv, 0, sizeof(dv)); - if (getsysv(&sysv, sizeof(struct sysv)) != 0) { - perror("getsysv"); - exit(1); - } + if (getsysv(&sysv, sizeof(struct sysv)) != 0) + fatalperror(net, "getsysv"); - /* - * Get socket security label and set device values - * {security label to be set on ttyp device} - */ + /* + * Get socket security label and set device values + * {security label to be set on ttyp device} + */ #ifdef SO_SEC_MULTI /* 8.0 code */ - if ((getsockopt(0, SOL_SOCKET, SO_SECURITY, - (char *)&ss, &szss) < 0) || - (getsockopt(0, SOL_SOCKET, SO_SEC_MULTI, - (char *)&sock_multi, &szi) < 0)) { - perror("getsockopt"); - exit(1); - } else { - dv.dv_actlvl = ss.ss_actlabel.lt_level; - dv.dv_actcmp = ss.ss_actlabel.lt_compart; - if (!sock_multi) { - dv.dv_minlvl = dv.dv_maxlvl = dv.dv_actlvl; - dv.dv_valcmp = dv.dv_actcmp; - } else { - dv.dv_minlvl = ss.ss_minlabel.lt_level; - dv.dv_maxlvl = ss.ss_maxlabel.lt_level; - dv.dv_valcmp = ss.ss_maxlabel.lt_compart; - } - dv.dv_devflg = 0; - } + if ((getsockopt(0, SOL_SOCKET, SO_SECURITY, + (void *)&ss, &szss) < 0) || + (getsockopt(0, SOL_SOCKET, SO_SEC_MULTI, + (void *)&sock_multi, &szi) < 0)) + fatalperror(net, "getsockopt"); + else { + dv.dv_actlvl = ss.ss_actlabel.lt_level; + dv.dv_actcmp = ss.ss_actlabel.lt_compart; + if (!sock_multi) { + dv.dv_minlvl = dv.dv_maxlvl = dv.dv_actlvl; + dv.dv_valcmp = dv.dv_actcmp; + } else { + dv.dv_minlvl = ss.ss_minlabel.lt_level; + dv.dv_maxlvl = ss.ss_maxlabel.lt_level; + dv.dv_valcmp = ss.ss_maxlabel.lt_compart; + } + dv.dv_devflg = 0; + } #else /* SO_SEC_MULTI */ /* 7.0 code */ - if (getsockopt(0, SOL_SOCKET, SO_SECURITY, - (char *)&ss, &szss) >= 0) { - dv.dv_actlvl = ss.ss_slevel; - dv.dv_actcmp = ss.ss_compart; - dv.dv_minlvl = ss.ss_minlvl; - dv.dv_maxlvl = ss.ss_maxlvl; - dv.dv_valcmp = ss.ss_maxcmp; - } -#endif /* SO_SEC_MULTI */ + if (getsockopt(0, SOL_SOCKET, SO_SECURITY, + (void *)&ss, &szss) >= 0) { + dv.dv_actlvl = ss.ss_slevel; + dv.dv_actcmp = ss.ss_compart; + dv.dv_minlvl = ss.ss_minlvl; + dv.dv_maxlvl = ss.ss_maxlvl; + dv.dv_valcmp = ss.ss_maxcmp; } +#endif /* SO_SEC_MULTI */ + } #endif /* _SC_CRAY_SECURE_SYS */ - openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON); - fromlen = sizeof (from); - if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) { - fprintf(stderr, "%s: ", progname); - perror("getpeername"); - _exit(1); - } - if (keepalive && - setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, - (char *)&on, sizeof (on)) < 0) { - syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); - } + openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON); + sa_size = sizeof (__ss); + if (getpeername(STDIN_FILENO, sa, &sa_size) < 0) { + fprintf(stderr, "%s: ", progname); + perror("getpeername"); + _exit(1); + } + if (keepalive && + setsockopt(STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE, + (void *)&on, sizeof (on)) < 0) { + syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); + } -#if defined(IPPROTO_IP) && defined(IP_TOS) - if (from.ss_family == AF_INET) { -# if defined(HAS_GETTOS) - struct tosent *tp; - if (tos < 0 && (tp = gettosbyname("telnet", "tcp"))) - tos = tp->t_tos; +#if defined(IPPROTO_IP) && defined(IP_TOS) && defined(HAVE_SETSOCKOPT) + { +# ifdef HAVE_GETTOSBYNAME + struct tosent *tp; + if (tos < 0 && (tp = gettosbyname("telnet", "tcp"))) + tos = tp->t_tos; # endif - if (tos < 0) - tos = 020; /* Low Delay bit */ - if (tos - && (setsockopt(0, IPPROTO_IP, IP_TOS, - (char *)&tos, sizeof(tos)) < 0) - && (errno != ENOPROTOOPT) ) - syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); - } + if (tos < 0) + tos = 020; /* Low Delay bit */ + if (tos + && sa->sa_family == AF_INET + && (setsockopt(STDIN_FILENO, IPPROTO_IP, IP_TOS, + (void *)&tos, sizeof(tos)) < 0) + && (errno != ENOPROTOOPT) ) + syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); + } #endif /* defined(IPPROTO_IP) && defined(IP_TOS) */ - net = 0; - doit((struct sockaddr *)&from); - /* NOTREACHED */ - return (0); + net = STDIN_FILENO; + doit(sa, sa_size); + /* NOTREACHED */ + return 0; } /* end of main */ - void -usage() +static void +usage(void) { - syslog(LOG_ERR, "usage: telnetd" + fprintf(stderr, "Usage: telnetd"); #ifdef AUTHENTICATION - " [-a (debug|other|user|valid|off|none)]" + fprintf(stderr, " [-a (debug|other|otp|user|valid|off|none)]\n\t"); #endif -#ifdef BFTPDAEMON - " [-B]" -#endif - " [-debug]" + fprintf(stderr, " [-debug]"); #ifdef DIAGNOSTICS - " [-D (options|report|exercise|netdata|ptydata)]\n\t" -#endif - " [-h]" -#if defined(CRAY) && defined(NEWINIT) - " [-Iinitid]" + fprintf(stderr, " [-D (options|report|exercise|netdata|ptydata)]\n\t"); #endif -#if defined(LINEMODE) && defined(KLUDGELINEMODE) - " [-k]" -#endif -#ifdef LINEMODE - " [-l]" +#ifdef AUTHENTICATION + fprintf(stderr, " [-edebug]"); #endif - " [-n]" -#ifdef CRAY - " [-r[lowpty]-[highpty]]" + fprintf(stderr, " [-h]"); + fprintf(stderr, " [-L login]"); + fprintf(stderr, " [-n]"); +#ifdef _CRAY + fprintf(stderr, " [-r[lowpty]-[highpty]]"); #endif -#ifdef HAS_GETTOS - " [-S tos]" + fprintf(stderr, "\n\t"); +#ifdef HAVE_GETTOSBYNAME + fprintf(stderr, " [-S tos]"); #endif #ifdef AUTHENTICATION - " [-X auth-type]" + fprintf(stderr, " [-X auth-type] [-y] [-z]"); #endif - " [-u utmp_hostname_length] [-U]" - " [port]"); - exit(2); + fprintf(stderr, " [-u utmp_hostname_length] [-U]"); + fprintf(stderr, " [port]\n"); + exit(1); } /* @@ -586,19 +494,16 @@ usage() * Output is the variable terminaltype filled in. */ static unsigned char ttytype_sbbuf[] = { - IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE + IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE }; - int -getterminaltype(name, name_sz) - char *name; - size_t name_sz; +int +getterminaltype(char *name, size_t name_sz) { int retval = -1; - void _gettermname(); settimer(baseline); -#if defined(AUTHENTICATION) +#ifdef AUTHENTICATION /* * Handle the Authentication option before we do anything else. */ @@ -612,7 +517,7 @@ getterminaltype(name, name_sz) #ifdef ENCRYPTION send_will(TELOPT_ENCRYPT, 1); - send_do(TELOPT_ENCRYPT, 1); /* esc@magic.fi */ + send_do(TELOPT_ENCRYPT, 1); /* esc@magic.fi */ #endif send_do(TELOPT_TTYPE, 1); send_do(TELOPT_TSPEED, 1); @@ -641,42 +546,37 @@ getterminaltype(name, name_sz) #endif if (his_state_is_will(TELOPT_TSPEED)) { static unsigned char sb[] = - { IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE }; + { IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE }; - memmove((void *)nfrontp, (void *)sb, sizeof sb); - nfrontp += sizeof sb; + telnet_net_write (sb, sizeof sb); DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2);); } if (his_state_is_will(TELOPT_XDISPLOC)) { static unsigned char sb[] = - { IAC, SB, TELOPT_XDISPLOC, TELQUAL_SEND, IAC, SE }; + { IAC, SB, TELOPT_XDISPLOC, TELQUAL_SEND, IAC, SE }; - memmove((void *)nfrontp, (void *)sb, sizeof sb); - nfrontp += sizeof sb; + telnet_net_write (sb, sizeof sb); DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2);); } if (his_state_is_will(TELOPT_NEW_ENVIRON)) { static unsigned char sb[] = - { IAC, SB, TELOPT_NEW_ENVIRON, TELQUAL_SEND, IAC, SE }; + { IAC, SB, TELOPT_NEW_ENVIRON, TELQUAL_SEND, IAC, SE }; - memmove((void *)nfrontp, (void *)sb, sizeof sb); - nfrontp += sizeof sb; + telnet_net_write (sb, sizeof sb); DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2);); } else if (his_state_is_will(TELOPT_OLD_ENVIRON)) { static unsigned char sb[] = - { IAC, SB, TELOPT_OLD_ENVIRON, TELQUAL_SEND, IAC, SE }; + { IAC, SB, TELOPT_OLD_ENVIRON, TELQUAL_SEND, IAC, SE }; - memmove((void *)nfrontp, (void *)sb, sizeof sb); - nfrontp += sizeof sb; + telnet_net_write (sb, sizeof sb); DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2);); } if (his_state_is_will(TELOPT_TTYPE)) { - memmove((void *)nfrontp, (void *)ttytype_sbbuf, sizeof ttytype_sbbuf); - nfrontp += sizeof ttytype_sbbuf; + telnet_net_write (ttytype_sbbuf, sizeof ttytype_sbbuf); DIAG(TD_OPTIONS, printsub('>', ttytype_sbbuf + 2, - sizeof ttytype_sbbuf - 2);); + sizeof ttytype_sbbuf - 2);); } if (his_state_is_will(TELOPT_TSPEED)) { while (sequenceIs(tspeedsubopt, baseline)) @@ -727,9 +627,9 @@ getterminaltype(name, name_sz) * RFC1091 compliant telnets will cycle back to * the start of the list. */ - _gettermname(); + _gettermname(); if (strncmp(first, terminaltype, sizeof(first)) != 0) - strlcpy(terminaltype, first, sizeof(terminaltype)); + strcpy(terminaltype, first); break; } } @@ -738,8 +638,8 @@ getterminaltype(name, name_sz) return(retval); } /* end of getterminaltype */ - void -_gettermname() +void +_gettermname(void) { /* * If the client turned off the option, @@ -749,695 +649,539 @@ _gettermname() if (his_state_is_wont(TELOPT_TTYPE)) return; settimer(baseline); - memmove((void *)nfrontp, (void *)ttytype_sbbuf, sizeof ttytype_sbbuf); - nfrontp += sizeof ttytype_sbbuf; + telnet_net_write (ttytype_sbbuf, sizeof ttytype_sbbuf); DIAG(TD_OPTIONS, printsub('>', ttytype_sbbuf + 2, - sizeof ttytype_sbbuf - 2);); + sizeof ttytype_sbbuf - 2);); while (sequenceIs(ttypesubopt, baseline)) ttloop(); } - int -terminaltypeok(s) - char *s; +int +terminaltypeok(char *s) { - int errret; - - if (terminaltype == NULL) - return(1); - - /* - * setupterm() will return OK if the type is known, and - * ERR if it is not known. - * We return 1 on success and 0 on failure. - */ - return(setupterm(s, STDOUT_FILENO, &errret) != ERR); + return 1; } -#ifndef MAXHOSTNAMELEN -#define MAXHOSTNAMELEN 64 -#endif /* MAXHOSTNAMELEN */ -char *hostname; char host_name[MAXHOSTNAMELEN]; char remote_host_name[MAXHOSTNAMELEN]; - -#ifndef convex -extern void telnet P((int, int)); -#else -extern void telnet P((int, int, char *)); -#endif +char remote_utmp_name[MAXHOSTNAMELEN]; /* * Get a pty, scan input lines. */ - void -doit(who) - struct sockaddr *who; +static void +doit(struct sockaddr *who, int who_len) { - char *host = NULL, *inet_ntoa(); - struct hostent *hp; - int level; - int ptynum; - char user_name[256]; - char *ap; - size_t alen; - char hbuf[NI_MAXHOST]; + int level; + int ptynum; + char user_name[256]; + int error; - /* - * Find an available pty to use. - */ -#ifndef convex - pty = getpty(&ptynum); - if (pty < 0) - fatal(net, "No free pseudo-tty devices."); -#else - for (;;) { - char *lp; - - if ((lp = getpty()) == NULL) - fatal(net, "Out of ptys"); - - if ((pty = open(lp, O_RDWR)) >= 0) { - strlcpy(line, lp, sizeof line); - line[5] = 't'; - break; - } - } -#endif + /* + * Find an available pty to use. + */ + ourpty = getpty(&ptynum); + if (ourpty < 0) + fatal(net, "All network ports in use"); -#if defined(_SC_CRAY_SECURE_SYS) - /* - * set ttyp line security label - */ - if (secflag) { - char slave_dev[16]; - - sprintf(tty_dev, "/dev/pty/%03d", ptynum); - if (setdevs(tty_dev, &dv) < 0) - fatal(net, "cannot set pty security"); - sprintf(slave_dev, "/dev/ttyp%03d", ptynum); - if (setdevs(slave_dev, &dv) < 0) - fatal(net, "cannot set tty security"); - } +#ifdef _SC_CRAY_SECURE_SYS + /* + * set ttyp line security label + */ + if (secflag) { + char slave_dev[16]; + + snprintf(tty_dev, sizeof(tty_dev), "/dev/pty/%03d", ptynum); + if (setdevs(tty_dev, &dv) < 0) + fatal(net, "cannot set pty security"); + snprintf(slave_dev, sizeof(slave_dev), "/dev/ttyp%03d", ptynum); + if (setdevs(slave_dev, &dv) < 0) + fatal(net, "cannot set tty security"); + } #endif /* _SC_CRAY_SECURE_SYS */ - /* get name of connected client */ - switch (who->sa_family) { - case AF_INET: - ap = (char *)&((struct sockaddr_in *)who)->sin_addr; - alen = sizeof(struct in_addr); - break; - case AF_INET6: - ap = (char *)&((struct sockaddr_in6 *)who)->sin6_addr; - alen = sizeof(struct in6_addr); - break; - default: - ap = NULL; - alen = 0; - break; - } - if (ap) - hp = gethostbyaddr(ap, alen, who->sa_family); - else - hp = NULL; - - if (hp == NULL && registerd_host_only) { - fatal(net, "Couldn't resolve your address into a host name.\r\n\ - Please contact your net administrator"); - } else if (hp && (strlen(hp->h_name) <= - (u_int)((utmp_len < 0) ? -utmp_len : utmp_len))) { - host = hp->h_name; - } else if (getnameinfo(who, who->sa_len, hbuf, sizeof(hbuf), NULL, 0, - NI_NUMERICHOST) == 0) { - host = hbuf; - } else { - fatal(net, "getnameinfo"); - } - - /* - * We must make a copy because Kerberos is probably going - * to also do a gethost* and overwrite the static data... - */ - strlcpy(remote_host_name, host, sizeof(remote_host_name)); - host = remote_host_name; + error = getnameinfo (who, who_len, + remote_host_name, + sizeof(remote_host_name), + NULL, 0, + registerd_host_only ? NI_NAMEREQD : 0); + if (error) + fatal(net, "Couldn't resolve your address into a host name.\r\n\ +Please contact your net administrator"); + + gethostname(host_name, sizeof (host_name)); + + strlcpy (remote_utmp_name, remote_host_name, sizeof(remote_utmp_name)); + + /* Only trim if too long (and possible) */ + if (strlen(remote_utmp_name) > utmp_len) { + char *domain = strchr(host_name, '.'); + char *p = strchr(remote_utmp_name, '.'); + if (domain != NULL && p != NULL && (strcmp(p, domain) == 0)) + *p = '\0'; /* remove domain part */ + } - (void) gethostname(host_name, sizeof (host_name)); - hostname = host_name; + /* + * If hostname still doesn't fit utmp, use ipaddr. + */ + if (strlen(remote_utmp_name) > utmp_len) { + error = getnameinfo (who, who_len, + remote_utmp_name, + sizeof(remote_utmp_name), + NULL, 0, + NI_NUMERICHOST); + if (error) + fatal(net, "Couldn't get numeric address\r\n"); + } -#if defined(AUTHENTICATION) - auth_encrypt_init(hostname, host, "TELNETD", 1); +#ifdef AUTHENTICATION + auth_encrypt_init(host_name, remote_host_name, "TELNETD", 1); #endif - init_env(); - /* - * get terminal type. - */ - *user_name = 0; - level = getterminaltype(user_name, sizeof(user_name)); - setenv("TERM", terminaltype ? terminaltype : "network", 1); /* XXX mem */ - - /* - * Start up the login process on the slave side of the terminal - */ -#ifndef convex - startslave(host, level, user_name); - -#if defined(_SC_CRAY_SECURE_SYS) - if (secflag) { - if (setulvl(dv.dv_actlvl) < 0) - fatal(net,"cannot setulvl()"); - if (setucmp(dv.dv_actcmp) < 0) - fatal(net, "cannot setucmp()"); - } + init_env(); + /* + * get terminal type. + */ + *user_name = 0; + level = getterminaltype(user_name, sizeof(user_name)); + esetenv("TERM", terminaltype ? terminaltype : "network", 1); + +#ifdef _SC_CRAY_SECURE_SYS + if (secflag) { + if (setulvl(dv.dv_actlvl) < 0) + fatal(net,"cannot setulvl()"); + if (setucmp(dv.dv_actcmp) < 0) + fatal(net, "cannot setucmp()"); + } #endif /* _SC_CRAY_SECURE_SYS */ - telnet(net, pty); /* begin server processing */ -#else - telnet(net, pty, host); -#endif - /*NOTREACHED*/ + /* begin server processing */ + my_telnet(net, ourpty, remote_host_name, remote_utmp_name, + level, user_name); + /*NOTREACHED*/ } /* end of doit */ -#if defined(CRAY2) && defined(UNICOS5) && defined(UNICOS50) - int -Xterm_output(ibufp, obuf, icountp, ocount) - char **ibufp, *obuf; - int *icountp, ocount; +/* output contents of /etc/issue.net, or /etc/issue */ +static void +show_issue(void) { - int ret; - ret = term_output(*ibufp, obuf, *icountp, ocount); - *ibufp += *icountp; - *icountp = 0; - return(ret); + FILE *f; + char buf[128]; + f = fopen("/etc/issue.net", "r"); + if(f == NULL) + f = fopen("/etc/issue", "r"); + if(f){ + while(fgets(buf, sizeof(buf)-2, f)){ + strcpy(buf + strcspn(buf, "\r\n"), "\r\n"); + writenet((unsigned char*)buf, strlen(buf)); + } + fclose(f); + } } -#define term_output Xterm_output -#endif /* defined(CRAY2) && defined(UNICOS5) && defined(UNICOS50) */ /* * Main loop. Select from pty and network, and * hand data to telnet receiver finite state machine. */ - void -#ifndef convex -telnet(f, p) -#else -telnet(f, p, host) -#endif - int f, p; -#ifdef convex - char *host; -#endif +void +my_telnet(int f, int p, const char *host, const char *utmp_host, + int level, char *autoname) { - int on = 1; -#define TABBUFSIZ 512 - char defent[TABBUFSIZ]; - char defstrs[TABBUFSIZ]; -#undef TABBUFSIZ - char *HE; - char *HN; - char *IM; - void netflush(); - int nfd; - - /* - * Initialize the slc mapping table. - */ - get_slc_defaults(); + int on = 1; + char *he; + char *IM; + int nfd; + int startslave_called = 0; + time_t timeout; - /* - * Do some tests where it is desireable to wait for a response. - * Rather than doing them slowly, one at a time, do them all - * at once. - */ - if (my_state_is_wont(TELOPT_SGA)) - send_will(TELOPT_SGA, 1); - /* - * Is the client side a 4.2 (NOT 4.3) system? We need to know this - * because 4.2 clients are unable to deal with TCP urgent data. - * - * To find out, we send out a "DO ECHO". If the remote system - * answers "WILL ECHO" it is probably a 4.2 client, and we note - * that fact ("WILL ECHO" ==> that the client will echo what - * WE, the server, sends it; it does NOT mean that the client will - * echo the terminal input). - */ - send_do(TELOPT_ECHO, 1); + /* + * Initialize the slc mapping table. + */ + get_slc_defaults(); -#ifdef LINEMODE - if (his_state_is_wont(TELOPT_LINEMODE)) { - /* Query the peer for linemode support by trying to negotiate - * the linemode option. - */ - linemode = 0; - editmode = 0; - send_do(TELOPT_LINEMODE, 1); /* send do linemode */ - } -#endif /* LINEMODE */ + /* + * Do some tests where it is desireable to wait for a response. + * Rather than doing them slowly, one at a time, do them all + * at once. + */ + if (my_state_is_wont(TELOPT_SGA)) + send_will(TELOPT_SGA, 1); + /* + * Is the client side a 4.2 (NOT 4.3) system? We need to know this + * because 4.2 clients are unable to deal with TCP urgent data. + * + * To find out, we send out a "DO ECHO". If the remote system + * answers "WILL ECHO" it is probably a 4.2 client, and we note + * that fact ("WILL ECHO" ==> that the client will echo what + * WE, the server, sends it; it does NOT mean that the client will + * echo the terminal input). + */ + send_do(TELOPT_ECHO, 1); - /* - * Send along a couple of other options that we wish to negotiate. - */ - send_do(TELOPT_NAWS, 1); - send_will(TELOPT_STATUS, 1); - flowmode = 1; /* default flow control state */ - restartany = -1; /* uninitialized... */ - send_do(TELOPT_LFLOW, 1); + /* + * Send along a couple of other options that we wish to negotiate. + */ + send_do(TELOPT_NAWS, 1); + send_will(TELOPT_STATUS, 1); + flowmode = 1; /* default flow control state */ + restartany = -1; /* uninitialized... */ + send_do(TELOPT_LFLOW, 1); - /* - * Spin, waiting for a response from the DO ECHO. However, - * some REALLY DUMB telnets out there might not respond - * to the DO ECHO. So, we spin looking for NAWS, (most dumb - * telnets so far seem to respond with WONT for a DO that - * they don't understand...) because by the time we get the - * response, it will already have processed the DO ECHO. - * Kludge upon kludge. - */ - while (his_will_wont_is_changing(TELOPT_NAWS)) - ttloop(); + /* + * Spin, waiting for a response from the DO ECHO. However, + * some REALLY DUMB telnets out there might not respond + * to the DO ECHO. So, we spin looking for NAWS, (most dumb + * telnets so far seem to respond with WONT for a DO that + * they don't understand...) because by the time we get the + * response, it will already have processed the DO ECHO. + * Kludge upon kludge. + */ + while (his_will_wont_is_changing(TELOPT_NAWS)) + ttloop(); - /* - * But... - * The client might have sent a WILL NAWS as part of its - * startup code; if so, we'll be here before we get the - * response to the DO ECHO. We'll make the assumption - * that any implementation that understands about NAWS - * is a modern enough implementation that it will respond - * to our DO ECHO request; hence we'll do another spin - * waiting for the ECHO option to settle down, which is - * what we wanted to do in the first place... - */ - if (his_want_state_is_will(TELOPT_ECHO) && - his_state_is_will(TELOPT_NAWS)) { - while (his_will_wont_is_changing(TELOPT_ECHO)) - ttloop(); - } - /* - * On the off chance that the telnet client is broken and does not - * respond to the DO ECHO we sent, (after all, we did send the - * DO NAWS negotiation after the DO ECHO, and we won't get here - * until a response to the DO NAWS comes back) simulate the - * receipt of a will echo. This will also send a WONT ECHO - * to the client, since we assume that the client failed to - * respond because it believes that it is already in DO ECHO - * mode, which we do not want. - */ - if (his_want_state_is_will(TELOPT_ECHO)) { - DIAG(TD_OPTIONS, - {sprintf(nfrontp, "td: simulating recv\r\n"); - nfrontp += strlen(nfrontp);}); - willoption(TELOPT_ECHO); - } + /* + * But... + * The client might have sent a WILL NAWS as part of its + * startup code; if so, we'll be here before we get the + * response to the DO ECHO. We'll make the assumption + * that any implementation that understands about NAWS + * is a modern enough implementation that it will respond + * to our DO ECHO request; hence we'll do another spin + * waiting for the ECHO option to settle down, which is + * what we wanted to do in the first place... + */ + if (his_want_state_is_will(TELOPT_ECHO) && + his_state_is_will(TELOPT_NAWS)) { + while (his_will_wont_is_changing(TELOPT_ECHO)) + ttloop(); + } + /* + * On the off chance that the telnet client is broken and does not + * respond to the DO ECHO we sent, (after all, we did send the + * DO NAWS negotiation after the DO ECHO, and we won't get here + * until a response to the DO NAWS comes back) simulate the + * receipt of a will echo. This will also send a WONT ECHO + * to the client, since we assume that the client failed to + * respond because it believes that it is already in DO ECHO + * mode, which we do not want. + */ + if (his_want_state_is_will(TELOPT_ECHO)) { + DIAG(TD_OPTIONS, + {output_data("td: simulating recv\r\n"); + }); + willoption(TELOPT_ECHO); + } - /* - * Finally, to clean things up, we turn on our echo. This - * will break stupid 4.2 telnets out of local terminal echo. - */ + /* + * Finally, to clean things up, we turn on our echo. This + * will break stupid 4.2 telnets out of local terminal echo. + */ - if (my_state_is_wont(TELOPT_ECHO)) - send_will(TELOPT_ECHO, 1); + if (my_state_is_wont(TELOPT_ECHO)) + send_will(TELOPT_ECHO, 1); -#ifndef STREAMSPTY +#ifdef TIOCPKT +#ifdef STREAMSPTY + if (!really_stream) +#endif /* * Turn on packet mode */ - (void) ioctl(p, TIOCPKT, (char *)&on); + ioctl(p, TIOCPKT, (char *)&on); #endif -#if defined(LINEMODE) && defined(KLUDGELINEMODE) - /* - * Continuing line mode support. If client does not support - * real linemode, attempt to negotiate kludge linemode by sending - * the do timing mark sequence. - */ - if (lmodetype < REAL_LINEMODE) - send_do(TELOPT_TM, 1); -#endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ - /* - * Call telrcv() once to pick up anything received during - * terminal type negotiation, 4.2/4.3 determination, and - * linemode negotiation. - */ - telrcv(); + /* + * Call telrcv() once to pick up anything received during + * terminal type negotiation, 4.2/4.3 determination, and + * linemode negotiation. + */ + telrcv(); - (void) ioctl(f, FIONBIO, (char *)&on); - (void) ioctl(p, FIONBIO, (char *)&on); -#if defined(CRAY2) && defined(UNICOS5) - init_termdriver(f, p, interrupt, sendbrk); -#endif + ioctl(f, FIONBIO, (char *)&on); + ioctl(p, FIONBIO, (char *)&on); -#if defined(SO_OOBINLINE) - (void) setsockopt(net, SOL_SOCKET, SO_OOBINLINE, - (char *)&on, sizeof on); +#if defined(SO_OOBINLINE) && defined(HAVE_SETSOCKOPT) + setsockopt(net, SOL_SOCKET, SO_OOBINLINE, + (void *)&on, sizeof on); #endif /* defined(SO_OOBINLINE) */ #ifdef SIGTSTP - (void) signal(SIGTSTP, SIG_IGN); + signal(SIGTSTP, SIG_IGN); #endif #ifdef SIGTTOU - /* - * Ignoring SIGTTOU keeps the kernel from blocking us - * in ttioct() in /sys/tty.c. - */ - (void) signal(SIGTTOU, SIG_IGN); + /* + * Ignoring SIGTTOU keeps the kernel from blocking us + * in ttioct() in /sys/tty.c. + */ + signal(SIGTTOU, SIG_IGN); #endif - (void) signal(SIGCHLD, cleanup); - -#if defined(CRAY2) && defined(UNICOS5) - /* - * Cray-2 will send a signal when pty modes are changed by slave - * side. Set up signal handler now. - */ - if ((int)signal(SIGUSR1, termstat) < 0) - perror("signal"); - else if (ioctl(p, TCSIGME, (char *)SIGUSR1) < 0) - perror("ioctl:TCSIGME"); - /* - * Make processing loop check terminal characteristics early on. - */ - termstat(); -#endif + signal(SIGCHLD, cleanup); #ifdef TIOCNOTTY - { - register int t; - t = open(_PATH_TTY, O_RDWR); - if (t >= 0) { - (void) ioctl(t, TIOCNOTTY, (char *)0); - (void) close(t); - } + { + int t; + t = open(_PATH_TTY, O_RDWR); + if (t >= 0) { + ioctl(t, TIOCNOTTY, (char *)0); + close(t); } + } #endif -#if defined(CRAY) && defined(NEWINIT) && defined(TIOCSCTTY) - (void) setsid(); - ioctl(p, TIOCSCTTY, 0); -#endif + show_issue(); + /* + * Show banner that getty never gave. + * + * We put the banner in the pty input buffer. This way, it + * gets carriage return null processing, etc., just like all + * other pty --> client data. + */ - /* - * Show banner that getty never gave. - * - * We put the banner in the pty input buffer. This way, it - * gets carriage return null processing, etc., just like all - * other pty --> client data. - */ + if (getenv("USER")) + hostinfo = 0; -#if !defined(CRAY) || !defined(NEWINIT) - if (getenv("USER")) - hostinfo = 0; -#endif + IM = DEFAULT_IM; + he = 0; + edithost(he, host_name); + if (hostinfo && *IM) + putf(IM, ptyibuf2); - if (gtgetent(defent, gettyname) == 1) { - char *cp=defstrs; + if (pcc) + strncat(ptyibuf2, ptyip, pcc+1); + ptyip = ptyibuf2; + pcc = strlen(ptyip); - HE = gtgetstr("he", &cp); - HN = gtgetstr("hn", &cp); - IM = gtgetstr("im", &cp); - if (HN && *HN) - strlcpy(host_name, HN, sizeof host_name); - if (IM == 0) - IM = ""; - } else { - IM = DEFAULT_IM; - HE = 0; - } - edithost(HE, host_name); - if (hostinfo && *IM) - putf(IM, ptyibuf2); - - if (pcc) - (void) strncat(ptyibuf2, ptyip, pcc+1); - ptyip = ptyibuf2; - pcc = strlen(ptyip); -#ifdef LINEMODE - /* - * Last check to make sure all our states are correct. - */ - init_termbuf(); - localstat(); -#endif /* LINEMODE */ + DIAG(TD_REPORT, { + output_data("td: Entering processing loop\r\n"); + }); - DIAG(TD_REPORT, - {sprintf(nfrontp, "td: Entering processing loop\r\n"); - nfrontp += strlen(nfrontp);}); -#ifdef convex - startslave(host); -#endif + nfd = ((f > p) ? f : p) + 1; + timeout = time(NULL) + 5; + for (;;) { + fd_set ibits, obits, xbits; + int c; - nfd = ((f > p) ? f : p) + 1; - for (;;) { - fd_set ibits, obits, xbits; - register int c; + /* wait for encryption to be turned on, but don't wait + indefinitely */ + if(!startslave_called && (!encrypt_delay() || timeout > time(NULL))){ + startslave_called = 1; + startslave(host, utmp_host, level, autoname); + } - if (ncc < 0 && pcc < 0) - break; + if (ncc < 0 && pcc < 0) + break; -#if defined(CRAY2) && defined(UNICOS5) - if (needtermstat) - _termstat(); -#endif /* defined(CRAY2) && defined(UNICOS5) */ - FD_ZERO(&ibits); - FD_ZERO(&obits); - FD_ZERO(&xbits); - /* - * Never look for input if there's still - * stuff in the corresponding output buffer - */ - if (nfrontp - nbackp || pcc > 0) { - FD_SET(f, &obits); - } else { - FD_SET(p, &ibits); - } - if (pfrontp - pbackp || ncc > 0) { - FD_SET(p, &obits); - } else { - FD_SET(f, &ibits); - } - if (!SYNCHing) { - FD_SET(f, &xbits); - } - if ((c = select(nfd, &ibits, &obits, &xbits, - (struct timeval *)0)) < 1) { - if (c == -1) { - if (errno == EINTR) { - continue; - } - } - sleep(5); - continue; - } + FD_ZERO(&ibits); + FD_ZERO(&obits); + FD_ZERO(&xbits); - /* - * Any urgent data? - */ - if (FD_ISSET(net, &xbits)) { - SYNCHing = 1; + if (f >= FD_SETSIZE + || p >= FD_SETSIZE) + fatal(net, "fd too large"); + + /* + * Never look for input if there's still + * stuff in the corresponding output buffer + */ + if (nfrontp - nbackp || pcc > 0) { + FD_SET(f, &obits); + } else { + FD_SET(p, &ibits); + } + if (pfrontp - pbackp || ncc > 0) { + FD_SET(p, &obits); + } else { + FD_SET(f, &ibits); + } + if (!SYNCHing) { + FD_SET(f, &xbits); + } + if ((c = select(nfd, &ibits, &obits, &xbits, + (struct timeval *)0)) < 1) { + if (c == -1) { + if (errno == EINTR) { + continue; } + } + sleep(5); + continue; + } - /* - * Something to read from the network... - */ - if (FD_ISSET(net, &ibits)) { -#if !defined(SO_OOBINLINE) - /* - * In 4.2 (and 4.3 beta) systems, the - * OOB indication and data handling in the kernel - * is such that if two separate TCP Urgent requests - * come in, one byte of TCP data will be overlaid. - * This is fatal for Telnet, but we try to live - * with it. - * - * In addition, in 4.2 (and...), a special protocol - * is needed to pick up the TCP Urgent data in - * the correct sequence. - * - * What we do is: if we think we are in urgent - * mode, we look to see if we are "at the mark". - * If we are, we do an OOB receive. If we run - * this twice, we will do the OOB receive twice, - * but the second will fail, since the second - * time we were "at the mark", but there wasn't - * any data there (the kernel doesn't reset - * "at the mark" until we do a normal read). - * Once we've read the OOB data, we go ahead - * and do normal reads. - * - * There is also another problem, which is that - * since the OOB byte we read doesn't put us - * out of OOB state, and since that byte is most - * likely the TELNET DM (data mark), we would - * stay in the TELNET SYNCH (SYNCHing) state. - * So, clocks to the rescue. If we've "just" - * received a DM, then we test for the - * presence of OOB data when the receive OOB - * fails (and AFTER we did the normal mode read - * to clear "at the mark"). - */ - if (SYNCHing) { - int atmark; - - (void) ioctl(net, SIOCATMARK, (char *)&atmark); - if (atmark) { - ncc = recv(net, netibuf, sizeof (netibuf), MSG_OOB); - if ((ncc == -1) && (errno == EINVAL)) { - ncc = read(net, netibuf, sizeof (netibuf)); - if (sequenceIs(didnetreceive, gotDM)) { - SYNCHing = stilloob(net); - } - } - } else { - ncc = read(net, netibuf, sizeof (netibuf)); - } - } else { + /* + * Any urgent data? + */ + if (FD_ISSET(net, &xbits)) { + SYNCHing = 1; + } + + /* + * Something to read from the network... + */ + if (FD_ISSET(net, &ibits)) { +#ifndef SO_OOBINLINE + /* + * In 4.2 (and 4.3 beta) systems, the + * OOB indication and data handling in the kernel + * is such that if two separate TCP Urgent requests + * come in, one byte of TCP data will be overlaid. + * This is fatal for Telnet, but we try to live + * with it. + * + * In addition, in 4.2 (and...), a special protocol + * is needed to pick up the TCP Urgent data in + * the correct sequence. + * + * What we do is: if we think we are in urgent + * mode, we look to see if we are "at the mark". + * If we are, we do an OOB receive. If we run + * this twice, we will do the OOB receive twice, + * but the second will fail, since the second + * time we were "at the mark", but there wasn't + * any data there (the kernel doesn't reset + * "at the mark" until we do a normal read). + * Once we've read the OOB data, we go ahead + * and do normal reads. + * + * There is also another problem, which is that + * since the OOB byte we read doesn't put us + * out of OOB state, and since that byte is most + * likely the TELNET DM (data mark), we would + * stay in the TELNET SYNCH (SYNCHing) state. + * So, clocks to the rescue. If we've "just" + * received a DM, then we test for the + * presence of OOB data when the receive OOB + * fails (and AFTER we did the normal mode read + * to clear "at the mark"). + */ + if (SYNCHing) { + int atmark; + + ioctl(net, SIOCATMARK, (char *)&atmark); + if (atmark) { + ncc = recv(net, netibuf, sizeof (netibuf), MSG_OOB); + if ((ncc == -1) && (errno == EINVAL)) { ncc = read(net, netibuf, sizeof (netibuf)); + if (sequenceIs(didnetreceive, gotDM)) { + SYNCHing = stilloob(net); + } } - settimer(didnetreceive); -#else /* !defined(SO_OOBINLINE)) */ + } else { ncc = read(net, netibuf, sizeof (netibuf)); + } + } else { + ncc = read(net, netibuf, sizeof (netibuf)); + } + settimer(didnetreceive); +#else /* !defined(SO_OOBINLINE)) */ + ncc = read(net, netibuf, sizeof (netibuf)); #endif /* !defined(SO_OOBINLINE)) */ - if (ncc < 0 && errno == EWOULDBLOCK) - ncc = 0; - else { - if (ncc <= 0) { - break; - } - netip = netibuf; - } - DIAG((TD_REPORT | TD_NETDATA), - {sprintf(nfrontp, "td: netread %d chars\r\n", ncc); - nfrontp += strlen(nfrontp);}); - DIAG(TD_NETDATA, printdata("nd", netip, ncc)); + if (ncc < 0 && errno == EWOULDBLOCK) + ncc = 0; + else { + if (ncc <= 0) { + break; } + netip = netibuf; + } + DIAG((TD_REPORT | TD_NETDATA), { + output_data("td: netread %d chars\r\n", ncc); + }); + DIAG(TD_NETDATA, printdata("nd", netip, ncc)); + } - /* - * Something to read from the pty... - */ - if (FD_ISSET(p, &ibits)) { -#ifndef STREAMSPTY - pcc = read(p, ptyibuf, BUFSIZ); -#else - pcc = readstream(p, ptyibuf, BUFSIZ); + /* + * Something to read from the pty... + */ + if (FD_ISSET(p, &ibits)) { +#ifdef STREAMSPTY + if (really_stream) + pcc = readstream(p, ptyibuf, BUFSIZ); + else #endif - /* - * On some systems, if we try to read something - * off the master side before the slave side is - * opened, we get EIO. - */ - if (pcc < 0 && (errno == EWOULDBLOCK || + pcc = read(p, ptyibuf, BUFSIZ); + + /* + * On some systems, if we try to read something + * off the master side before the slave side is + * opened, we get EIO. + */ + if (pcc < 0 && (errno == EWOULDBLOCK || #ifdef EAGAIN - errno == EAGAIN || + errno == EAGAIN || #endif - errno == EIO)) { - pcc = 0; - } else { - if (pcc <= 0) - break; -#if !defined(CRAY2) || !defined(UNICOS5) -#ifdef LINEMODE - /* - * If ioctl from pty, pass it through net - */ - if (ptyibuf[0] & TIOCPKT_IOCTL) { - copy_termbuf(ptyibuf+1, pcc-1); - localstat(); - pcc = 1; - } -#endif /* LINEMODE */ - if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) { - netclear(); /* clear buffer back */ + errno == EIO)) { + pcc = 0; + } else { + if (pcc <= 0) + break; + if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) { + netclear(); /* clear buffer back */ #ifndef NO_URGENT - /* - * There are client telnets on some - * operating systems get screwed up - * royally if we send them urgent - * mode data. - */ - *nfrontp++ = IAC; - *nfrontp++ = DM; - neturg = nfrontp-1; /* off by one XXX */ - DIAG(TD_OPTIONS, - printoption("td: send IAC", DM)); + /* + * There are client telnets on some + * operating systems get screwed up + * royally if we send them urgent + * mode data. + */ + output_data ("%c%c", IAC, DM); -#endif - } - if (his_state_is_will(TELOPT_LFLOW) && - (ptyibuf[0] & - (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))) { - int newflow = - ptyibuf[0] & TIOCPKT_DOSTOP ? 1 : 0; - if (newflow != flowmode) { - flowmode = newflow; - (void) sprintf(nfrontp, - "%c%c%c%c%c%c", - IAC, SB, TELOPT_LFLOW, - flowmode ? LFLOW_ON - : LFLOW_OFF, - IAC, SE); - nfrontp += 6; - DIAG(TD_OPTIONS, printsub('>', - (unsigned char *)nfrontp-4, - 4);); - } - } - pcc--; - ptyip = ptyibuf+1; -#else /* defined(CRAY2) && defined(UNICOS5) */ - if (!uselinemode) { - unpcc = pcc; - unptyip = ptyibuf; - pcc = term_output(&unptyip, ptyibuf2, - &unpcc, BUFSIZ); - ptyip = ptyibuf2; - } else - ptyip = ptyibuf; -#endif /* defined(CRAY2) && defined(UNICOS5) */ - } - } + neturg = nfrontp-1; /* off by one XXX */ + DIAG(TD_OPTIONS, + printoption("td: send IAC", DM)); - while (pcc > 0) { - if ((&netobuf[BUFSIZ] - nfrontp) < 2) - break; - c = *ptyip++ & 0377, pcc--; - if (c == IAC) - *nfrontp++ = c; -#if defined(CRAY2) && defined(UNICOS5) - else if (c == '\n' && - my_state_is_wont(TELOPT_BINARY) && newmap) - *nfrontp++ = '\r'; -#endif /* defined(CRAY2) && defined(UNICOS5) */ - *nfrontp++ = c; - if ((c == '\r') && (my_state_is_wont(TELOPT_BINARY))) { - if (pcc > 0 && ((*ptyip & 0377) == '\n')) { - *nfrontp++ = *ptyip++ & 0377; - pcc--; - } else - *nfrontp++ = '\0'; - } +#endif } -#if defined(CRAY2) && defined(UNICOS5) - /* - * If chars were left over from the terminal driver, - * note their existence. - */ - if (!uselinemode && unpcc) { - pcc = unpcc; - unpcc = 0; - ptyip = unptyip; + if (his_state_is_will(TELOPT_LFLOW) && + (ptyibuf[0] & + (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))) { + int newflow = + ptyibuf[0] & TIOCPKT_DOSTOP ? 1 : 0; + if (newflow != flowmode) { + flowmode = newflow; + output_data("%c%c%c%c%c%c", + IAC, SB, TELOPT_LFLOW, + flowmode ? LFLOW_ON + : LFLOW_OFF, + IAC, SE); + DIAG(TD_OPTIONS, printsub('>', + (unsigned char *)nfrontp-4, + 4);); + } } -#endif /* defined(CRAY2) && defined(UNICOS5) */ - - if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0) - netflush(); - if (ncc > 0) - telrcv(); - if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0) - ptyflush(); + pcc--; + ptyip = ptyibuf+1; + } } - cleanup(0); -} /* end of telnet */ + + while (pcc > 0) { + if ((&netobuf[BUFSIZ] - nfrontp) < 3) + break; + c = *ptyip++ & 0377, pcc--; + if (c == IAC) + *nfrontp++ = c; + *nfrontp++ = c; + if ((c == '\r') && (my_state_is_wont(TELOPT_BINARY))) { + if (pcc > 0 && ((*ptyip & 0377) == '\n')) { + *nfrontp++ = *ptyip++ & 0377; + pcc--; + } else + *nfrontp++ = '\0'; + } + } + + if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0) + netflush(); + if (ncc > 0) + telrcv(); + if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0) + ptyflush(); + } + cleanup(0); +} #ifndef TCSIG # ifdef TIOCSIG @@ -1447,91 +1191,95 @@ telnet(f, p, host) #ifdef STREAMSPTY -int flowison = -1; /* current state of flow: -1 is unknown */ + int flowison = -1; /* current state of flow: -1 is unknown */ -int readstream(p, ibuf, bufsize) - int p; - char *ibuf; - int bufsize; +int +readstream(int p, char *ibuf, int bufsize) { - int flags = 0; - int ret = 0; - struct termios *tsp; - struct termio *tp; - struct iocblk *ip; - char vstop, vstart; - int ixon; - int newflow; - - strbufc.maxlen = BUFSIZ; - strbufc.buf = (char *)ctlbuf; - strbufd.maxlen = bufsize-1; - strbufd.len = 0; - strbufd.buf = ibuf+1; - ibuf[0] = 0; - - ret = getmsg(p, &strbufc, &strbufd, &flags); - if (ret < 0) /* error of some sort -- probably EAGAIN */ - return(-1); - - if (strbufc.len <= 0 || ctlbuf[0] == M_DATA) { - /* data message */ - if (strbufd.len > 0) { /* real data */ - return(strbufd.len + 1); /* count header char */ - } else { - /* nothing there */ - errno = EAGAIN; - return(-1); - } + int flags = 0; + int ret = 0; + struct termios *tsp; +#if 0 + struct termio *tp; +#endif + struct iocblk *ip; + char vstop, vstart; + int ixon; + int newflow; + + strbufc.maxlen = BUFSIZ; + strbufc.buf = (char *)ctlbuf; + strbufd.maxlen = bufsize-1; + strbufd.len = 0; + strbufd.buf = ibuf+1; + ibuf[0] = 0; + + ret = getmsg(p, &strbufc, &strbufd, &flags); + if (ret < 0) /* error of some sort -- probably EAGAIN */ + return(-1); + + if (strbufc.len <= 0 || ctlbuf[0] == M_DATA) { + /* data message */ + if (strbufd.len > 0) { /* real data */ + return(strbufd.len + 1); /* count header char */ + } else { + /* nothing there */ + errno = EAGAIN; + return(-1); } + } - /* - * It's a control message. Return 1, to look at the flag we set - */ + /* + * It's a control message. Return 1, to look at the flag we set + */ - switch (ctlbuf[0]) { - case M_FLUSH: - if (ibuf[1] & FLUSHW) - ibuf[0] = TIOCPKT_FLUSHWRITE; - return(1); - - case M_IOCTL: - ip = (struct iocblk *) (ibuf+1); - - switch (ip->ioc_cmd) { - case TCSETS: - case TCSETSW: - case TCSETSF: - tsp = (struct termios *) - (ibuf+1 + sizeof(struct iocblk)); - vstop = tsp->c_cc[VSTOP]; - vstart = tsp->c_cc[VSTART]; - ixon = tsp->c_iflag & IXON; - break; - case TCSETA: - case TCSETAW: - case TCSETAF: - tp = (struct termio *) (ibuf+1 + sizeof(struct iocblk)); - vstop = tp->c_cc[VSTOP]; - vstart = tp->c_cc[VSTART]; - ixon = tp->c_iflag & IXON; - break; - default: - errno = EAGAIN; - return(-1); - } + switch (ctlbuf[0]) { + case M_FLUSH: + if (ibuf[1] & FLUSHW) + ibuf[0] = TIOCPKT_FLUSHWRITE; + return(1); - newflow = (ixon && (vstart == 021) && (vstop == 023)) ? 1 : 0; - if (newflow != flowison) { /* it's a change */ - flowison = newflow; - ibuf[0] = newflow ? TIOCPKT_DOSTOP : TIOCPKT_NOSTOP; - return(1); - } + case M_IOCTL: + ip = (struct iocblk *) (ibuf+1); + + switch (ip->ioc_cmd) { +#ifdef TCSETS + case TCSETS: + case TCSETSW: + case TCSETSF: + tsp = (struct termios *) + (ibuf+1 + sizeof(struct iocblk)); + vstop = tsp->c_cc[VSTOP]; + vstart = tsp->c_cc[VSTART]; + ixon = tsp->c_iflag & IXON; + break; +#endif +#if 0 + case TCSETA: + case TCSETAW: + case TCSETAF: + tp = (struct termio *) (ibuf+1 + sizeof(struct iocblk)); + vstop = tp->c_cc[VSTOP]; + vstart = tp->c_cc[VSTART]; + ixon = tp->c_iflag & IXON; + break; +#endif + default: + errno = EAGAIN; + return(-1); } - /* nothing worth doing anything about */ - errno = EAGAIN; - return(-1); + newflow = (ixon && (vstart == 021) && (vstop == 023)) ? 1 : 0; + if (newflow != flowison) { /* it's a change */ + flowison = newflow; + ibuf[0] = newflow ? TIOCPKT_DOSTOP : TIOCPKT_NOSTOP; + return(1); + } + } + + /* nothing worth doing anything about */ + errno = EAGAIN; + return(-1); } #endif /* STREAMSPTY */ @@ -1540,25 +1288,26 @@ int readstream(p, ibuf, bufsize) * If it is in raw mode, just write NULL; * otherwise, write intr char. */ - void +void interrupt() { - ptyflush(); /* half-hearted */ + ptyflush(); /* half-hearted */ #if defined(STREAMSPTY) && defined(TIOCSIGNAL) - /* Streams PTY style ioctl to post a signal */ + /* Streams PTY style ioctl to post a signal */ + if (really_stream) { - int sig = SIGINT; - (void) ioctl(pty, TIOCSIGNAL, &sig); - (void) ioctl(pty, I_FLUSH, FLUSHR); + int sig = SIGINT; + ioctl(ourpty, TIOCSIGNAL, &sig); + ioctl(ourpty, I_FLUSH, FLUSHR); } #else #ifdef TCSIG - (void) ioctl(pty, TCSIG, (char *)SIGINT); + ioctl(ourpty, TCSIG, (char *)SIGINT); #else /* TCSIG */ - init_termbuf(); - *pfrontp++ = slctab[SLC_IP].sptr ? - (unsigned char)*slctab[SLC_IP].sptr : '\177'; + init_termbuf(); + *pfrontp++ = slctab[SLC_IP].sptr ? + (unsigned char)*slctab[SLC_IP].sptr : '\177'; #endif /* TCSIG */ #endif } @@ -1568,29 +1317,29 @@ interrupt() * If it is in raw mode, just write NULL; * otherwise, write quit char. */ - void +void sendbrk() { - ptyflush(); /* half-hearted */ + ptyflush(); /* half-hearted */ #ifdef TCSIG - (void) ioctl(pty, TCSIG, (char *)SIGQUIT); + ioctl(ourpty, TCSIG, (char *)SIGQUIT); #else /* TCSIG */ - init_termbuf(); - *pfrontp++ = slctab[SLC_ABORT].sptr ? - (unsigned char)*slctab[SLC_ABORT].sptr : '\034'; + init_termbuf(); + *pfrontp++ = slctab[SLC_ABORT].sptr ? + (unsigned char)*slctab[SLC_ABORT].sptr : '\034'; #endif /* TCSIG */ } - void +void sendsusp() { #ifdef SIGTSTP - ptyflush(); /* half-hearted */ + ptyflush(); /* half-hearted */ # ifdef TCSIG - (void) ioctl(pty, TCSIG, (char *)SIGTSTP); + ioctl(ourpty, TCSIG, (char *)SIGTSTP); # else /* TCSIG */ - *pfrontp++ = slctab[SLC_SUSP].sptr ? - (unsigned char)*slctab[SLC_SUSP].sptr : '\032'; + *pfrontp++ = slctab[SLC_SUSP].sptr ? + (unsigned char)*slctab[SLC_SUSP].sptr : '\032'; # endif /* TCSIG */ #endif /* SIGTSTP */ } @@ -1599,31 +1348,23 @@ sendsusp() * When we get an AYT, if ^T is enabled, use that. Otherwise, * just send back "[Yes]". */ - void +void recv_ayt() { #if defined(SIGINFO) && defined(TCSIG) - if (slctab[SLC_AYT].sptr && *slctab[SLC_AYT].sptr != _POSIX_VDISABLE) { - (void) ioctl(pty, TCSIG, (char *)SIGINFO); - return; - } + if (slctab[SLC_AYT].sptr && *slctab[SLC_AYT].sptr != _POSIX_VDISABLE) { + ioctl(ourpty, TCSIG, (char *)SIGINFO); + return; + } #endif - (void) strcpy(nfrontp, "\r\n[Yes]\r\n"); - nfrontp += 9; + output_data("\r\n[Yes]\r\n"); } - void +void doeof() { - init_termbuf(); + init_termbuf(); -#if defined(LINEMODE) && defined(USE_TERMIO) && (VEOF == VMIN) - if (!tty_isediting()) { - extern char oldeofc; - *pfrontp++ = oldeofc; - return; - } -#endif - *pfrontp++ = slctab[SLC_EOF].sptr ? - (unsigned char)*slctab[SLC_EOF].sptr : '\004'; + *pfrontp++ = slctab[SLC_EOF].sptr ? + (unsigned char)*slctab[SLC_EOF].sptr : '\004'; } diff --git a/libexec/telnetd/telnetd.h b/libexec/telnetd/telnetd.h index 38c2f31d8cf..d7817fe2878 100644 --- a/libexec/telnetd/telnetd.h +++ b/libexec/telnetd/telnetd.h @@ -1,6 +1,3 @@ -/* $OpenBSD: telnetd.h,v 1.2 1996/03/28 23:22:04 niklas Exp $ */ -/* $NetBSD: telnetd.h,v 1.5 1996/02/28 20:38:25 thorpej Exp $ */ - /* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. @@ -33,12 +30,187 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * from: @(#)telnetd.h 8.1 (Berkeley) 6/4/93 + * @(#)telnetd.h 8.1 (Berkeley) 6/4/93 */ -#include <defs.h> -#include <ext.h> + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#define HAVE_STDARG_H +#define HAVE_NETDB_H +#define HAVE_SYS_STAT_H +#define HAVE_SYSLOG_H +#define HAVE_UTMP_H +#define HAVE_SYS_TYPES_H +#define HAVE_SYS_SOCKET_H +#define HAVE_FCNTL_H +#define HAVE_SYS_IOCTL_H +#define HAVE_UNISTD_H + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_PARAM_H +#include <sys/param.h> +#endif + +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#ifdef TIME_WITH_SYS_TIME +#include <sys/time.h> +#include <time.h> +#elif defined(HAVE_SYS_TIME_H) +#include <sys/time.h> +#else +#include <time.h> +#endif + +#ifdef HAVE_SYS_RESOURCE_H +#include <sys/resource.h> +#endif /* HAVE_SYS_RESOURCE_H */ + +#ifdef HAVE_SYS_WAIT_H +#include <sys/wait.h> +#endif + +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif +#ifdef HAVE_SYS_FILE_H +#include <sys/file.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif + +/* including both <sys/ioctl.h> and <termios.h> in SunOS 4 generates a + lot of warnings */ + +#if defined(HAVE_SYS_IOCTL_H) && SunOS != 40 +#include <sys/ioctl.h> +#endif +#ifdef HAVE_SYS_FILIO_H +#include <sys/filio.h> +#endif + +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#ifdef HAVE_NETINET_IN6_H +#include <netinet/in6.h> +#endif +#ifdef HAVE_NETINET6_IN6_H +#include <netinet6/in6.h> +#endif + +#ifdef HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif + +#include <signal.h> +#include <errno.h> +#ifdef HAVE_NETDB_H +#include <netdb.h> +#endif +#ifdef HAVE_SYSLOG_H +#include <syslog.h> +#endif +#include <ctype.h> + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include <termios.h> + +#ifdef HAVE_PTY_H +#include <pty.h> +#endif + +#include "defs.h" + +#ifndef _POSIX_VDISABLE +# ifdef VDISABLE +# define _POSIX_VDISABLE VDISABLE +# else +# define _POSIX_VDISABLE ((unsigned char)'\377') +# endif +#endif + + +#ifdef HAVE_SYS_PTY_H +#include <sys/pty.h> +#endif +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif + +#ifdef HAVE_SYS_PTYIO_H +#include <sys/ptyio.h> +#endif + +#ifdef HAVE_SYS_UTSNAME_H +#include <sys/utsname.h> +#endif + +#ifdef HAVE_PATHS_H +#include <paths.h> +#endif + +#ifdef HAVE_ARPA_TELNET_H +#include <arpa/telnet.h> +#endif + +#include "ext.h" + +#ifdef SOCKS +#include <socks.h> +/* This doesn't belong here. */ +struct tm *localtime(const time_t *); +struct hostent *gethostbyname(const char *); +#endif + +#ifdef KRB4 +#include <kerberosIV/krb.h> +#endif + +#ifdef AUTHENTICATION +#include <libtelnet/auth.h> +#include <libtelnet/misc.h> +#ifdef ENCRYPTION +#include <libtelnet/encrypt.h> +#endif +#endif + +#ifdef HAVE_LIBUTIL_H +#include <libutil.h> +#endif + + +/* Don't use the system login, use our version instead */ + +/* BINDIR should be defined somewhere else... */ + +#ifndef BINDIR +#define BINDIR "/usr/bin" +#endif + +#undef _PATH_LOGIN +#define _PATH_LOGIN BINDIR "/login" + +/* fallbacks */ + +#ifndef _PATH_DEV +#define _PATH_DEV "/dev/" +#endif + +#ifndef _PATH_TTY +#define _PATH_TTY "/dev/tty" +#endif /* _PATH_TTY */ #ifdef DIAGNOSTICS #define DIAG(a,b) if (diagnostic & (a)) b @@ -48,5 +220,12 @@ /* other external variables */ extern char **environ; -extern int errno; +/* prototypes */ + +/* appends data to nfrontp and advances */ +int output_data (const char *format, ...) +#ifdef __GNUC__ +__attribute__ ((format (printf, 1, 2))) +#endif +; diff --git a/libexec/telnetd/termstat.c b/libexec/telnetd/termstat.c index fde657b5d49..361cf605241 100644 --- a/libexec/telnetd/termstat.c +++ b/libexec/telnetd/termstat.c @@ -1,6 +1,3 @@ -/* $OpenBSD: termstat.c,v 1.5 2000/11/10 15:33:04 provos Exp $ */ -/* $NetBSD: termstat.c,v 1.5 1996/02/28 20:38:27 thorpej Exp $ */ - /* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. @@ -34,17 +31,10 @@ * SUCH DAMAGE. */ -#ifndef lint -#if 0 -static char sccsid[] = "@(#)termstat.c 8.2 (Berkeley) 5/30/95"; -static char rcsid[] = "$NetBSD: termstat.c,v 1.5 1996/02/28 20:38:27 thorpej Exp $"; -#else -static char rcsid[] = "$OpenBSD: termstat.c,v 1.5 2000/11/10 15:33:04 provos Exp $"; -#endif -#endif /* not lint */ - #include "telnetd.h" +/* RCSID("$KTH: termstat.c,v 1.11 1997/05/11 06:30:04 assar Exp $") */ + /* * local variables */ @@ -52,320 +42,32 @@ int def_tspeed = -1, def_rspeed = -1; #ifdef TIOCSWINSZ int def_row = 0, def_col = 0; #endif -#ifdef LINEMODE -static int _terminit = 0; -#endif /* LINEMODE */ - -#if defined(CRAY2) && defined(UNICOS5) -int newmap = 1; /* nonzero if \n maps to ^M^J */ -#endif - -#ifdef LINEMODE -/* - * localstat - * - * This function handles all management of linemode. - * - * Linemode allows the client to do the local editing of data - * and send only complete lines to the server. Linemode state is - * based on the state of the pty driver. If the pty is set for - * external processing, then we can use linemode. Further, if we - * can use real linemode, then we can look at the edit control bits - * in the pty to determine what editing the client should do. - * - * Linemode support uses the following state flags to keep track of - * current and desired linemode state. - * alwayslinemode : true if -l was specified on the telnetd - * command line. It means to have linemode on as much as - * possible. - * - * lmodetype: signifies whether the client can - * handle real linemode, or if use of kludgeomatic linemode - * is preferred. It will be set to one of the following: - * REAL_LINEMODE : use linemode option - * NO_KLUDGE : don't initiate kludge linemode. - * KLUDGE_LINEMODE : use kludge linemode - * NO_LINEMODE : client is ignorant of linemode - * - * linemode, uselinemode : linemode is true if linemode - * is currently on, uselinemode is the state that we wish - * to be in. If another function wishes to turn linemode - * on or off, it sets or clears uselinemode. - * - * editmode, useeditmode : like linemode/uselinemode, but - * these contain the edit mode states (edit and trapsig). - * - * The state variables correspond to some of the state information - * in the pty. - * linemode: - * In real linemode, this corresponds to whether the pty - * expects external processing of incoming data. - * In kludge linemode, this more closely corresponds to the - * whether normal processing is on or not. (ICANON in - * system V, or COOKED mode in BSD.) - * If the -l option was specified (alwayslinemode), then - * an attempt is made to force external processing on at - * all times. - * - * The following heuristics are applied to determine linemode - * handling within the server. - * 1) Early on in starting up the server, an attempt is made - * to negotiate the linemode option. If this succeeds - * then lmodetype is set to REAL_LINEMODE and all linemode - * processing occurs in the context of the linemode option. - * 2) If the attempt to negotiate the linemode option failed, - * and the "-k" (don't initiate kludge linemode) isn't set, - * then we try to use kludge linemode. We test for this - * capability by sending "do Timing Mark". If a positive - * response comes back, then we assume that the client - * understands kludge linemode (ech!) and the - * lmodetype flag is set to KLUDGE_LINEMODE. - * 3) Otherwise, linemode is not supported at all and - * lmodetype remains set to NO_LINEMODE (which happens - * to be 0 for convenience). - * 4) At any time a command arrives that implies a higher - * state of linemode support in the client, we move to that - * linemode support. - * - * A short explanation of kludge linemode is in order here. - * 1) The heuristic to determine support for kludge linemode - * is to send a do timing mark. We assume that a client - * that supports timing marks also supports kludge linemode. - * A risky proposition at best. - * 2) Further negotiation of linemode is done by changing the - * the server's state regarding SGA. If server will SGA, - * then linemode is off, if server won't SGA, then linemode - * is on. - */ - void -localstat() -{ - void netflush(); - int need_will_echo = 0; - -#if defined(CRAY2) && defined(UNICOS5) - /* - * Keep track of that ol' CR/NL mapping while we're in the - * neighborhood. - */ - newmap = tty_isnewmap(); -#endif /* defined(CRAY2) && defined(UNICOS5) */ - - /* - * Check for state of BINARY options. - */ - if (tty_isbinaryin()) { - if (his_want_state_is_wont(TELOPT_BINARY)) - send_do(TELOPT_BINARY, 1); - } else { - if (his_want_state_is_will(TELOPT_BINARY)) - send_dont(TELOPT_BINARY, 1); - } - - if (tty_isbinaryout()) { - if (my_want_state_is_wont(TELOPT_BINARY)) - send_will(TELOPT_BINARY, 1); - } else { - if (my_want_state_is_will(TELOPT_BINARY)) - send_wont(TELOPT_BINARY, 1); - } - - /* - * Check for changes to flow control if client supports it. - */ - flowstat(); - - /* - * Check linemode on/off state - */ - uselinemode = tty_linemode(); - - /* - * If alwayslinemode is on, and pty is changing to turn it off, then - * force linemode back on. - */ - if (alwayslinemode && linemode && !uselinemode) { - uselinemode = 1; - tty_setlinemode(uselinemode); - } - - - /* - * Do echo mode handling as soon as we know what the - * linemode is going to be. - * If the pty has echo turned off, then tell the client that - * the server will echo. If echo is on, then the server - * will echo if in character mode, but in linemode the - * client should do local echoing. The state machine will - * not send anything if it is unnecessary, so don't worry - * about that here. - * - * If we need to send the WILL ECHO (because echo is off), - * then delay that until after we have changed the MODE. - * This way, when the user is turning off both editing - * and echo, the client will get editing turned off first. - * This keeps the client from going into encryption mode - * and then right back out if it is doing auto-encryption - * when passwords are being typed. - */ - if (uselinemode) { - if (tty_isecho()) - send_wont(TELOPT_ECHO, 1); - else - need_will_echo = 1; -#ifdef KLUDGELINEMODE - if (lmodetype == KLUDGE_OK) - lmodetype = KLUDGE_LINEMODE; -#endif - } - - /* - * If linemode is being turned off, send appropriate - * command and then we're all done. - */ - if (!uselinemode && linemode) { -# ifdef KLUDGELINEMODE - if (lmodetype == REAL_LINEMODE) { -# endif /* KLUDGELINEMODE */ - send_dont(TELOPT_LINEMODE, 1); -# ifdef KLUDGELINEMODE - } else if (lmodetype == KLUDGE_LINEMODE) - send_will(TELOPT_SGA, 1); -# endif /* KLUDGELINEMODE */ - send_will(TELOPT_ECHO, 1); - linemode = uselinemode; - goto done; - } - -# ifdef KLUDGELINEMODE - /* - * If using real linemode check edit modes for possible later use. - * If we are in kludge linemode, do the SGA negotiation. - */ - if (lmodetype == REAL_LINEMODE) { -# endif /* KLUDGELINEMODE */ - useeditmode = 0; - if (tty_isediting()) - useeditmode |= MODE_EDIT; - if (tty_istrapsig()) - useeditmode |= MODE_TRAPSIG; - if (tty_issofttab()) - useeditmode |= MODE_SOFT_TAB; - if (tty_islitecho()) - useeditmode |= MODE_LIT_ECHO; -# ifdef KLUDGELINEMODE - } else if (lmodetype == KLUDGE_LINEMODE) { - if (tty_isediting() && uselinemode) - send_wont(TELOPT_SGA, 1); - else - send_will(TELOPT_SGA, 1); - } -# endif /* KLUDGELINEMODE */ - - /* - * Negotiate linemode on if pty state has changed to turn it on. - * Send appropriate command and send along edit mode, then all done. - */ - if (uselinemode && !linemode) { -# ifdef KLUDGELINEMODE - if (lmodetype == KLUDGE_LINEMODE) { - send_wont(TELOPT_SGA, 1); - } else if (lmodetype == REAL_LINEMODE) { -# endif /* KLUDGELINEMODE */ - send_do(TELOPT_LINEMODE, 1); - /* send along edit modes */ - (void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC, SB, - TELOPT_LINEMODE, LM_MODE, useeditmode, - IAC, SE); - nfrontp += 7; - editmode = useeditmode; -# ifdef KLUDGELINEMODE - } -# endif /* KLUDGELINEMODE */ - linemode = uselinemode; - goto done; - } - -# ifdef KLUDGELINEMODE - /* - * None of what follows is of any value if not using - * real linemode. - */ - if (lmodetype < REAL_LINEMODE) - goto done; -# endif /* KLUDGELINEMODE */ - - if (linemode && his_state_is_will(TELOPT_LINEMODE)) { - /* - * If edit mode changed, send edit mode. - */ - if (useeditmode != editmode) { - /* - * Send along appropriate edit mode mask. - */ - (void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC, SB, - TELOPT_LINEMODE, LM_MODE, useeditmode, - IAC, SE); - nfrontp += 7; - editmode = useeditmode; - } - - - /* - * Check for changes to special characters in use. - */ - start_slc(0); - check_slc(); - (void) end_slc(0); - } - -done: - if (need_will_echo) - send_will(TELOPT_ECHO, 1); - /* - * Some things should be deferred until after the pty state has - * been set by the local process. Do those things that have been - * deferred now. This only happens once. - */ - if (_terminit == 0) { - _terminit = 1; - defer_terminit(); - } - - netflush(); - set_termbuf(); - return; - -} /* end of localstat */ -#endif /* LINEMODE */ /* * flowstat * * Check for changes to flow control */ - void +void flowstat() { - if (his_state_is_will(TELOPT_LFLOW)) { - if (tty_flowmode() != flowmode) { - flowmode = tty_flowmode(); - (void) sprintf(nfrontp, "%c%c%c%c%c%c", - IAC, SB, TELOPT_LFLOW, - flowmode ? LFLOW_ON : LFLOW_OFF, - IAC, SE); - nfrontp += 6; - } - if (tty_restartany() != restartany) { - restartany = tty_restartany(); - (void) sprintf(nfrontp, "%c%c%c%c%c%c", - IAC, SB, TELOPT_LFLOW, - restartany ? LFLOW_RESTART_ANY - : LFLOW_RESTART_XON, - IAC, SE); - nfrontp += 6; - } + if (his_state_is_will(TELOPT_LFLOW)) { + if (tty_flowmode() != flowmode) { + flowmode = tty_flowmode(); + output_data("%c%c%c%c%c%c", + IAC, SB, TELOPT_LFLOW, + flowmode ? LFLOW_ON : LFLOW_OFF, + IAC, SE); + } + if (tty_restartany() != restartany) { + restartany = tty_restartany(); + output_data("%c%c%c%c%c%c", + IAC, SB, TELOPT_LFLOW, + restartany ? LFLOW_RESTART_ANY + : LFLOW_RESTART_XON, + IAC, SE); } + } } /* @@ -376,274 +78,63 @@ flowstat() * at a time, and if using kludge linemode, then only linemode may be * affected. */ - void -clientstat(code, parm1, parm2) - register int code, parm1, parm2; +void +clientstat(int code, int parm1, int parm2) { - void netflush(); - - /* - * Get a copy of terminal characteristics. - */ - init_termbuf(); - - /* - * Process request from client. code tells what it is. - */ - switch (code) { -#ifdef LINEMODE - case TELOPT_LINEMODE: - /* - * Don't do anything unless client is asking us to change - * modes. - */ - uselinemode = (parm1 == WILL); - if (uselinemode != linemode) { -# ifdef KLUDGELINEMODE - /* - * If using kludge linemode, make sure that - * we can do what the client asks. - * We can not turn off linemode if alwayslinemode - * and the ICANON bit is set. - */ - if (lmodetype == KLUDGE_LINEMODE) { - if (alwayslinemode && tty_isediting()) { - uselinemode = 1; - } - } - - /* - * Quit now if we can't do it. - */ - if (uselinemode == linemode) - return; - - /* - * If using real linemode and linemode is being - * turned on, send along the edit mode mask. - */ - if (lmodetype == REAL_LINEMODE && uselinemode) -# else /* KLUDGELINEMODE */ - if (uselinemode) -# endif /* KLUDGELINEMODE */ - { - useeditmode = 0; - if (tty_isediting()) - useeditmode |= MODE_EDIT; - if (tty_istrapsig) - useeditmode |= MODE_TRAPSIG; - if (tty_issofttab()) - useeditmode |= MODE_SOFT_TAB; - if (tty_islitecho()) - useeditmode |= MODE_LIT_ECHO; - (void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC, - SB, TELOPT_LINEMODE, LM_MODE, - useeditmode, IAC, SE); - nfrontp += 7; - editmode = useeditmode; - } - - - tty_setlinemode(uselinemode); - - linemode = uselinemode; - - if (!linemode) - send_will(TELOPT_ECHO, 1); - } - break; - - case LM_MODE: - { - register int ack, changed; - - /* - * Client has sent along a mode mask. If it agrees with - * what we are currently doing, ignore it; if not, it could - * be viewed as a request to change. Note that the server - * will change to the modes in an ack if it is different from - * what we currently have, but we will not ack the ack. - */ - useeditmode &= MODE_MASK; - ack = (useeditmode & MODE_ACK); - useeditmode &= ~MODE_ACK; - - if ((changed = (useeditmode ^ editmode))) { - /* - * This check is for a timing problem. If the - * state of the tty has changed (due to the user - * application) we need to process that info - * before we write in the state contained in the - * ack!!! This gets out the new MODE request, - * and when the ack to that command comes back - * we'll set it and be in the right mode. - */ - if (ack) - localstat(); - if (changed & MODE_EDIT) - tty_setedit(useeditmode & MODE_EDIT); - - if (changed & MODE_TRAPSIG) - tty_setsig(useeditmode & MODE_TRAPSIG); - - if (changed & MODE_SOFT_TAB) - tty_setsofttab(useeditmode & MODE_SOFT_TAB); - - if (changed & MODE_LIT_ECHO) - tty_setlitecho(useeditmode & MODE_LIT_ECHO); - - set_termbuf(); - - if (!ack) { - (void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC, - SB, TELOPT_LINEMODE, LM_MODE, - useeditmode|MODE_ACK, - IAC, SE); - nfrontp += 7; - } - - editmode = useeditmode; - } - - break; - - } /* end of case LM_MODE */ -#endif /* LINEMODE */ - - case TELOPT_NAWS: + void netflush(); + + /* + * Get a copy of terminal characteristics. + */ + init_termbuf(); + + /* + * Process request from client. code tells what it is. + */ + switch (code) { + case TELOPT_NAWS: #ifdef TIOCSWINSZ - { - struct winsize ws; + { + struct winsize ws; - def_col = parm1; - def_row = parm2; -#ifdef LINEMODE - /* - * Defer changing window size until after terminal is - * initialized. - */ - if (terminit() == 0) - return; -#endif /* LINEMODE */ + def_col = parm1; + def_row = parm2; - /* - * Change window size as requested by client. - */ + /* + * Change window size as requested by client. + */ - ws.ws_col = parm1; - ws.ws_row = parm2; - (void) ioctl(pty, TIOCSWINSZ, (char *)&ws); - } + ws.ws_col = parm1; + ws.ws_row = parm2; + ioctl(ourpty, TIOCSWINSZ, (char *)&ws); + } #endif /* TIOCSWINSZ */ - break; + break; - case TELOPT_TSPEED: - { - def_tspeed = parm1; - def_rspeed = parm2; -#ifdef LINEMODE - /* - * Defer changing the terminal speed. - */ - if (terminit() == 0) - return; -#endif /* LINEMODE */ - /* - * Change terminal speed as requested by client. - * We set the receive speed first, so that if we can't - * store separate receive and transmit speeds, the transmit - * speed will take precedence. - */ - tty_rspeed(parm2); - tty_tspeed(parm1); - set_termbuf(); + case TELOPT_TSPEED: + { + def_tspeed = parm1; + def_rspeed = parm2; + /* + * Change terminal speed as requested by client. + * We set the receive speed first, so that if we can't + * store seperate receive and transmit speeds, the transmit + * speed will take precedence. + */ + tty_rspeed(parm2); + tty_tspeed(parm1); + set_termbuf(); - break; + break; - } /* end of case TELOPT_TSPEED */ + } /* end of case TELOPT_TSPEED */ - default: - /* What? */ - break; - } /* end of switch */ + default: + /* What? */ + break; + } /* end of switch */ -#if defined(CRAY2) && defined(UNICOS5) - /* - * Just in case of the likely event that we changed the pty state. - */ - rcv_ioctl(); -#endif /* defined(CRAY2) && defined(UNICOS5) */ + netflush(); - netflush(); - -} /* end of clientstat */ - -#if defined(CRAY2) && defined(UNICOS5) - void -termstat() -{ - needtermstat = 1; } - - void -_termstat() -{ - needtermstat = 0; - init_termbuf(); - localstat(); - rcv_ioctl(); -} -#endif /* defined(CRAY2) && defined(UNICOS5) */ - -#ifdef LINEMODE -/* - * defer_terminit - * - * Some things should not be done until after the login process has started - * and all the pty modes are set to what they are supposed to be. This - * function is called when the pty state has been processed for the first time. - * It calls other functions that do things that were deferred in each module. - */ - void -defer_terminit() -{ - - /* - * local stuff that got deferred. - */ - if (def_tspeed != -1) { - clientstat(TELOPT_TSPEED, def_tspeed, def_rspeed); - def_tspeed = def_rspeed = 0; - } - -#ifdef TIOCSWINSZ - if (def_col || def_row) { - struct winsize ws; - - memset((void *)&ws, 0, sizeof(ws)); - ws.ws_col = def_col; - ws.ws_row = def_row; - (void) ioctl(pty, TIOCSWINSZ, (char *)&ws); - } -#endif - - /* - * The only other module that currently defers anything. - */ - deferslc(); - -} /* end of defer_terminit */ - -/* - * terminit - * - * Returns true if the pty state has been processed yet. - */ - int -terminit() -{ - return(_terminit); - -} /* end of terminit */ -#endif /* LINEMODE */ diff --git a/libexec/telnetd/utility.c b/libexec/telnetd/utility.c index 6f3cc3e1983..b14a10246fc 100644 --- a/libexec/telnetd/utility.c +++ b/libexec/telnetd/utility.c @@ -1,6 +1,3 @@ -/* $OpenBSD: utility.c,v 1.16 2001/06/11 15:18:53 mickey Exp $ */ -/* $NetBSD: utility.c,v 1.9 1996/02/28 20:38:29 thorpej Exp $ */ - /* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. @@ -34,24 +31,10 @@ * SUCH DAMAGE. */ -#ifndef lint -#if 0 -static char sccsid[] = "@(#)utility.c 8.4 (Berkeley) 5/30/95"; -static char rcsid[] = "$NetBSD: utility.c,v 1.9 1996/02/28 20:38:29 thorpej Exp $"; -#else -static char rcsid[] = "$OpenBSD: utility.c,v 1.16 2001/06/11 15:18:53 mickey Exp $"; -#endif -#endif /* not lint */ - -#include <sys/utsname.h> #define PRINTOPTIONS #include "telnetd.h" -#if defined(AUTHENTICATION) -#include <libtelnet/auth.h> -#endif -#if defined(ENCRYPTION) -#include <libtelnet/encrypt.h> -#endif + +/* RCSID("$KTH: utility.c,v 1.25 2001/05/17 00:34:42 assar Exp $"); */ /* * utility functions performing io related tasks @@ -60,60 +43,67 @@ static char rcsid[] = "$OpenBSD: utility.c,v 1.16 2001/06/11 15:18:53 mickey Exp /* * ttloop * - * A small subroutine to flush the network output buffer, get some data - * from the network, and pass it through the telnet state machine. We - * also flush the pty input buffer (by dropping its data) if it becomes - * too full. + * A small subroutine to flush the network output buffer, get some + * data from the network, and pass it through the telnet state + * machine. We also flush the pty input buffer (by dropping its data) + * if it becomes too full. + * + * return 0 if OK or 1 if interrupted by a signal. */ - void -ttloop() +int +ttloop(void) { - void netflush(); - - DIAG(TD_REPORT, {sprintf(nfrontp, "td: ttloop\r\n"); - nfrontp += strlen(nfrontp);}); - if (nfrontp-nbackp) { + void netflush(void); + + DIAG(TD_REPORT, { + output_data("td: ttloop\r\n"); + }); + if (nfrontp-nbackp) netflush(); - } ncc = read(net, netibuf, sizeof netibuf); if (ncc < 0) { - syslog(LOG_INFO, "ttloop: read: %m"); + if (errno == EINTR) + return 1; + syslog(LOG_INFO, "ttloop: read: %m\n"); exit(1); } else if (ncc == 0) { - syslog(LOG_INFO, "ttloop: peer died: %m"); + syslog(LOG_INFO, "ttloop: peer died\n"); exit(1); } - DIAG(TD_REPORT, {sprintf(nfrontp, "td: ttloop read %d chars\r\n", ncc); - nfrontp += strlen(nfrontp);}); + DIAG(TD_REPORT, { + output_data("td: ttloop read %d chars\r\n", ncc); + }); netip = netibuf; telrcv(); /* state machine */ if (ncc > 0) { pfrontp = pbackp = ptyobuf; telrcv(); } + return 0; } /* end of ttloop */ /* * Check a descriptor to see if out of band data exists on it. */ - int -stilloob(s) - int s; /* socket number */ +int +stilloob(int s) { - struct timeval timeout; + static struct timeval timeout = { 0 }; fd_set excepts; int value; + if (s >= FD_SETSIZE) + fatal(ourpty, "fd too large"); + do { FD_ZERO(&excepts); FD_SET(s, &excepts); - memset((void *)&timeout, 0, sizeof timeout); - value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout); + value = select(s+1, 0, 0, &excepts, &timeout); } while ((value == -1) && (errno == EINTR)); if (value < 0) { - fatalperror(pty, "select"); + fatalperror(ourpty, "select"); } if (FD_ISSET(s, &excepts)) { return 1; @@ -122,26 +112,26 @@ stilloob(s) } } - void -ptyflush() +void +ptyflush(void) { - int n; - - if ((n = pfrontp - pbackp) > 0) { - DIAG((TD_REPORT | TD_PTYDATA), - { sprintf(nfrontp, "td: ptyflush %d chars\r\n", n); - nfrontp += strlen(nfrontp); }); - DIAG(TD_PTYDATA, printdata("pd", pbackp, n)); - n = write(pty, pbackp, n); - } - if (n < 0) { - if (errno == EWOULDBLOCK || errno == EINTR) - return; - cleanup(0); - } - pbackp += n; - if (pbackp == pfrontp) - pbackp = pfrontp = ptyobuf; + int n; + + if ((n = pfrontp - pbackp) > 0) { + DIAG((TD_REPORT | TD_PTYDATA), { + output_data("td: ptyflush %d chars\r\n", n); + }); + DIAG(TD_PTYDATA, printdata("pd", pbackp, n)); + n = write(ourpty, pbackp, n); + } + if (n < 0) { + if (errno == EWOULDBLOCK || errno == EINTR) + return; + cleanup(0); + } + pbackp += n; + if (pbackp == pfrontp) + pbackp = pfrontp = ptyobuf; } /* @@ -154,9 +144,8 @@ ptyflush() * if the current address is a TELNET IAC ("I Am a Command") * character. */ - char * -nextitem(current) - char *current; +char * +nextitem(char *current) { if ((*current&0xff) != IAC) { return current+1; @@ -167,22 +156,22 @@ nextitem(current) case WILL: case WONT: return current+3; - case SB: /* loop forever looking for the SE */ - { - register char *look = current+2; - - for (;;) { - if ((*look++&0xff) == IAC) { - if ((*look++&0xff) == SE) { - return look; - } + case SB:{ + /* loop forever looking for the SE */ + char *look = current+2; + + for (;;) { + if ((*look++&0xff) == IAC) { + if ((*look++&0xff) == SE) { + return look; } } } + } default: return current+2; } -} /* end of nextitem */ +} /* @@ -201,51 +190,52 @@ nextitem(current) * caller should be setting the urgent data pointer AFTER calling * us in any case. */ - void -netclear() +void +netclear(void) { - register char *thisitem, *next; + char *thisitem, *next; char *good; #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ - ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) + ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) + #ifdef ENCRYPTION - thisitem = nclearto > netobuf ? nclearto : netobuf; + thisitem = nclearto > netobuf ? nclearto : netobuf; #else - thisitem = netobuf; + thisitem = netobuf; #endif - while ((next = nextitem(thisitem)) <= nbackp) { - thisitem = next; - } + while ((next = nextitem(thisitem)) <= nbackp) { + thisitem = next; + } - /* Now, thisitem is first before/at boundary. */ + /* Now, thisitem is first before/at boundary. */ #ifdef ENCRYPTION - good = nclearto > netobuf ? nclearto : netobuf; + good = nclearto > netobuf ? nclearto : netobuf; #else - good = netobuf; /* where the good bytes go */ + good = netobuf; /* where the good bytes go */ #endif - while (nfrontp > thisitem) { - if (wewant(thisitem)) { - int length; - - next = thisitem; - do { - next = nextitem(next); - } while (wewant(next) && (nfrontp > next)); - length = next-thisitem; - memmove((void *)good, (void *)thisitem, length); - good += length; - thisitem = next; - } else { - thisitem = nextitem(thisitem); + while (nfrontp > thisitem) { + if (wewant(thisitem)) { + int length; + + next = thisitem; + do { + next = nextitem(next); + } while (wewant(next) && (nfrontp > next)); + length = next-thisitem; + memmove(good, thisitem, length); + good += length; + thisitem = next; + } else { + thisitem = nextitem(thisitem); + } } - } - nbackp = netobuf; - nfrontp = good; /* next byte to be sent */ - neturg = 0; + nbackp = netobuf; + nfrontp = good; /* next byte to be sent */ + neturg = 0; } /* end of netclear */ /* @@ -253,18 +243,16 @@ netclear() * Send as much data as possible to the network, * handling requests for urgent data. */ - void -netflush() +void +netflush(void) { int n; extern int not42; if ((n = nfrontp - nbackp) > 0) { DIAG(TD_REPORT, - { sprintf(nfrontp, "td: netflush %d chars\r\n", n); - n += strlen(nfrontp); /* get count first */ - nfrontp += strlen(nfrontp); /* then move pointer */ - }); + { n += output_data("td: netflush %d chars\r\n", n); + }); #ifdef ENCRYPTION if (encrypt_output) { char *s = nclearto ? nclearto : nbackp; @@ -279,8 +267,11 @@ netflush() * old 4.2 client (and thus unable to survive TCP urgent data), * write the entire buffer in non-OOB mode. */ +#if 1 /* remove this to make it work between solaris 2.6 and linux */ if ((neturg == 0) || (not42 == 0)) { +#endif n = write(net, nbackp, n); /* normal write */ +#if 1 /* remove this to make it work between solaris 2.6 and linux */ } else { n = neturg - nbackp; /* @@ -297,10 +288,11 @@ netflush() n = send(net, nbackp, n, MSG_OOB); /* URGENT data */ } } +#endif } if (n < 0) { if (errno == EWOULDBLOCK || errno == EINTR) - return; + return; cleanup(0); } nbackp += n; @@ -318,7 +310,7 @@ netflush() #endif } return; -} /* end of netflush */ +} /* @@ -331,21 +323,18 @@ netflush() * ptr - A pointer to a character string to write * len - How many bytes to write */ - void -writenet(ptr, len) - register unsigned char *ptr; - register int len; +void +writenet(unsigned char *ptr, int len) { - /* flush buffer if no room for new data) */ - if ((&netobuf[BUFSIZ] - nfrontp) < len) { - /* if this fails, don't worry, buffer is a little big */ - netflush(); - } - - memmove((void *)nfrontp, (void *)ptr, len); - nfrontp += len; + /* flush buffer if no room for new data) */ + while ((&netobuf[BUFSIZ] - nfrontp) < len) { + /* if this fails, don't worry, buffer is a little big */ + netflush(); + } -} /* end of writenet */ + memmove(nfrontp, ptr, len); + nfrontp += len; +} /* @@ -353,861 +342,830 @@ writenet(ptr, len) */ - void -fatal(f, msg) - int f; - char *msg; +void fatal(int f, char *msg) { - char buf[BUFSIZ]; + char buf[BUFSIZ]; - snprintf(buf, sizeof(buf), "telnetd: %s.\r\n", msg); + snprintf(buf, sizeof(buf), "telnetd: %s.\r\n", msg); #ifdef ENCRYPTION - if (encrypt_output) { - /* - * Better turn off encryption first.... - * Hope it flushes... - */ - encrypt_send_end(); - netflush(); - } + if (encrypt_output) { + /* + * Better turn off encryption first.... + * Hope it flushes... + */ + encrypt_send_end(); + netflush(); + } #endif - write(f, buf, (int)strlen(buf)); - - sleep(1); /*XXX*/ - exit(1); + write(f, buf, (int)strlen(buf)); + sleep(1); /*XXX*/ + exit(1); } - void -fatalperror(f, msg) - int f; - char *msg; +void +fatalperror_errno(int f, const char *msg, int error) { - char buf[BUFSIZ], *strerror(); + char buf[BUFSIZ]; + + snprintf(buf, sizeof(buf), "%s: %s", msg, strerror(error)); + fatal(f, buf); +} - (void) snprintf(buf, sizeof buf, "%s: %s", msg, strerror(errno)); - fatal(f, buf); +void +fatalperror(int f, const char *msg) +{ + fatalperror_errno(f, msg, errno); } -char editedhost[48]; +char editedhost[32]; - void -edithost(pat, host) - register char *pat; - register char *host; +void edithost(char *pat, char *host) { - register char *res = editedhost; + char *res = editedhost; - if (!pat) - pat = ""; - while (*pat) { - switch (*pat) { + if (!pat) + pat = ""; + while (*pat) { + switch (*pat) { - case '#': - if (*host) - host++; - break; + case '#': + if (*host) + host++; + break; - case '@': - if (*host) - *res++ = *host++; - break; + case '@': + if (*host) + *res++ = *host++; + break; - default: - *res++ = *pat; - break; - } - if (res == &editedhost[sizeof editedhost - 1]) { - *res = '\0'; - return; - } - pat++; + default: + *res++ = *pat; + break; } - if (*host) - strlcpy(res, host, sizeof editedhost - (res - editedhost)); - else - *res = '\0'; + if (res == &editedhost[sizeof editedhost - 1]) { + *res = '\0'; + return; + } + pat++; + } + if (*host) + strlcpy (res, host, + sizeof editedhost - (res - editedhost)); + else + *res = '\0'; + editedhost[sizeof editedhost - 1] = '\0'; } static char *putlocation; - void -putstr(s) - register char *s; +void +putstr(char *s) { - while (*s) - putchr(*s++); + while (*s) + putchr(*s++); } - void -putchr(cc) - int cc; +void +putchr(int cc) { - *putlocation++ = cc; + *putlocation++ = cc; } /* * This is split on two lines so that SCCS will not see the M * between two % signs and expand it... */ -static char fmtstr[] = { "%l:%M\ -%p on %A, %d %B %Y" }; +static char fmtstr[] = { "%l:%M" "%P on %A, %d %B %Y" }; - void -putf(cp, where) - register char *cp; - char *where; +void putf(char *cp, char *where) { - char *slash; - time_t t; - char db[100]; - struct utsname utsinfo; -#ifdef STREAMSPTY - extern char *strchr(); -#else - extern char *strrchr(); +#ifdef HAVE_UNAME + struct utsname name; +#endif + char *slash; + time_t t; + char db[100]; + + /* if we don't have uname, set these to sensible values */ + char *sysname = "Unix", + *machine = "", + *release = "", + *version = ""; + +#ifdef HAVE_UNAME + uname(&name); + sysname=name.sysname; + machine=name.machine; + release=name.release; + version=name.version; #endif - uname(&utsinfo); - - putlocation = where; + putlocation = where; - while (*cp) { - if (*cp != '%') { - putchr(*cp++); - continue; - } - switch (*++cp) { + while (*cp) { + if (*cp != '%') { + putchr(*cp++); + continue; + } + switch (*++cp) { - case 't': + case 't': #ifdef STREAMSPTY - /* names are like /dev/pts/2 -- we want pts/2 */ - slash = strchr(line+1, '/'); + /* names are like /dev/pts/2 -- we want pts/2 */ + slash = strchr(line+1, '/'); #else - slash = strrchr(line, '/'); + slash = strrchr(line, '/'); #endif - if (slash == (char *) 0) - putstr(line); - else - putstr(&slash[1]); - break; + if (slash == (char *) 0) + putstr(line); + else + putstr(&slash[1]); + break; - case 'h': - putstr(editedhost); - break; + case 'h': + putstr(editedhost); + break; - case 'd': - (void)time(&t); - (void)strftime(db, sizeof(db), fmtstr, localtime(&t)); - putstr(db); - break; + case 's': + putstr(sysname); + break; - case '%': - putchr('%'); - break; + case 'm': + putstr(machine); + break; - case 's': - putstr(utsinfo.sysname); - break; + case 'r': + putstr(release); + break; - case 'm': - putstr(utsinfo.machine); - break; + case 'v': + putstr(version); + break; - case 'r': - putstr(utsinfo.release); - break; + case 'd': + time(&t); + strftime(db, sizeof(db), fmtstr, localtime(&t)); + putstr(db); + break; - case 'v': - puts(utsinfo.version); - break; - } - cp++; + case '%': + putchr('%'); + break; } + cp++; + } } #ifdef DIAGNOSTICS /* * Print telnet options and commands in plain text, if possible. */ - void -printoption(fmt, option) - register char *fmt; - register int option; +void +printoption(char *fmt, int option) { - if (TELOPT_OK(option)) - sprintf(nfrontp, "%s %s\r\n", fmt, TELOPT(option)); - else if (TELCMD_OK(option)) - sprintf(nfrontp, "%s %s\r\n", fmt, TELCMD(option)); - else - sprintf(nfrontp, "%s %d\r\n", fmt, option); - nfrontp += strlen(nfrontp); - return; + if (TELOPT_OK(option)) + output_data("%s %s\r\n", + fmt, + TELOPT(option)); + else if (TELCMD_OK(option)) + output_data("%s %s\r\n", + fmt, + TELCMD(option)); + else + output_data("%s %d\r\n", + fmt, + option); + return; } - void -printsub(direction, pointer, length) - char direction; /* '<' or '>' */ - unsigned char *pointer; /* where suboption data sits */ - int length; /* length of suboption data */ +void +printsub(int direction, unsigned char *pointer, int length) + /* '<' or '>' */ + /* where suboption data sits */ + /* length of suboption data */ { - register int i = 0; - char buf[512]; - - if (!(diagnostic & TD_OPTIONS)) - return; - - if (direction) { - sprintf(nfrontp, "td: %s suboption ", - direction == '<' ? "recv" : "send"); - nfrontp += strlen(nfrontp); - if (length >= 3) { - register int j; - - i = pointer[length-2]; - j = pointer[length-1]; - - if (i != IAC || j != SE) { - sprintf(nfrontp, "(terminated by "); - nfrontp += strlen(nfrontp); - if (TELOPT_OK(i)) - sprintf(nfrontp, "%s ", TELOPT(i)); - else if (TELCMD_OK(i)) - sprintf(nfrontp, "%s ", TELCMD(i)); - else - sprintf(nfrontp, "%d ", i); - nfrontp += strlen(nfrontp); - if (TELOPT_OK(j)) - sprintf(nfrontp, "%s", TELOPT(j)); - else if (TELCMD_OK(j)) - sprintf(nfrontp, "%s", TELCMD(j)); - else - sprintf(nfrontp, "%d", j); - nfrontp += strlen(nfrontp); - sprintf(nfrontp, ", not IAC SE!) "); - nfrontp += strlen(nfrontp); - } + int i = 0; + unsigned char buf[512]; + + if (!(diagnostic & TD_OPTIONS)) + return; + + if (direction) { + output_data("td: %s suboption ", + direction == '<' ? "recv" : "send"); + if (length >= 3) { + int j; + + i = pointer[length-2]; + j = pointer[length-1]; + + if (i != IAC || j != SE) { + output_data("(terminated by "); + if (TELOPT_OK(i)) + output_data("%s ", + TELOPT(i)); + else if (TELCMD_OK(i)) + output_data("%s ", + TELCMD(i)); + else + output_data("%d ", + i); + if (TELOPT_OK(j)) + output_data("%s", + TELOPT(j)); + else if (TELCMD_OK(j)) + output_data("%s", + TELCMD(j)); + else + output_data("%d", + j); + output_data(", not IAC SE!) "); } - length -= 2; } - if (length < 1) { - sprintf(nfrontp, "(Empty suboption??\?)"); - nfrontp += strlen(nfrontp); - return; + length -= 2; + } + if (length < 1) { + output_data("(Empty suboption??\?)"); + return; + } + switch (pointer[0]) { + case TELOPT_TTYPE: + output_data("TERMINAL-TYPE "); + switch (pointer[1]) { + case TELQUAL_IS: + output_data("IS \"%.*s\"", + length-2, + (char *)pointer+2); + break; + case TELQUAL_SEND: + output_data("SEND"); + break; + default: + output_data("- unknown qualifier %d (0x%x).", + pointer[1], pointer[1]); } - switch (pointer[0]) { - case TELOPT_TTYPE: - sprintf(nfrontp, "TERMINAL-TYPE "); - nfrontp += strlen(nfrontp); - switch (pointer[1]) { - case TELQUAL_IS: - sprintf(nfrontp, "IS \"%.*s\"", length-2, (char *)pointer+2); - break; - case TELQUAL_SEND: - sprintf(nfrontp, "SEND"); - break; - default: - sprintf(nfrontp, - "- unknown qualifier %d (0x%x).", - pointer[1], pointer[1]); + break; + case TELOPT_TSPEED: + output_data("TERMINAL-SPEED"); + if (length < 2) { + output_data(" (empty suboption??\?)"); + break; + } + switch (pointer[1]) { + case TELQUAL_IS: + output_data(" IS %.*s", length-2, (char *)pointer+2); + break; + default: + if (pointer[1] == 1) + output_data(" SEND"); + else + output_data(" %d (unknown)", pointer[1]); + for (i = 2; i < length; i++) { + output_data(" ?%d?", pointer[i]); } - nfrontp += strlen(nfrontp); break; - case TELOPT_TSPEED: - sprintf(nfrontp, "TERMINAL-SPEED"); - nfrontp += strlen(nfrontp); - if (length < 2) { - sprintf(nfrontp, " (empty suboption??\?)"); - nfrontp += strlen(nfrontp); + } + break; + + case TELOPT_LFLOW: + output_data("TOGGLE-FLOW-CONTROL"); + if (length < 2) { + output_data(" (empty suboption??\?)"); + break; + } + switch (pointer[1]) { + case LFLOW_OFF: + output_data(" OFF"); + break; + case LFLOW_ON: + output_data(" ON"); + break; + case LFLOW_RESTART_ANY: + output_data(" RESTART-ANY"); + break; + case LFLOW_RESTART_XON: + output_data(" RESTART-XON"); + break; + default: + output_data(" %d (unknown)", + pointer[1]); + } + for (i = 2; i < length; i++) { + output_data(" ?%d?", + pointer[i]); + } + break; + + case TELOPT_NAWS: + output_data("NAWS"); + if (length < 2) { + output_data(" (empty suboption??\?)"); + break; + } + if (length == 2) { + output_data(" ?%d?", + pointer[1]); + break; + } + output_data(" %u %u(%u)", + pointer[1], + pointer[2], + (((unsigned int)pointer[1])<<8) + pointer[2]); + if (length == 4) { + output_data(" ?%d?", + pointer[3]); + break; + } + output_data(" %u %u(%u)", + pointer[3], + pointer[4], + (((unsigned int)pointer[3])<<8) + pointer[4]); + for (i = 5; i < length; i++) { + output_data(" ?%d?", + pointer[i]); + } + break; + + case TELOPT_LINEMODE: + output_data("LINEMODE "); + if (length < 2) { + output_data(" (empty suboption??\?)"); + break; + } + switch (pointer[1]) { + case WILL: + output_data("WILL "); + goto common; + case WONT: + output_data("WONT "); + goto common; + case DO: + output_data("DO "); + goto common; + case DONT: + output_data("DONT "); + common: + if (length < 3) { + output_data("(no option??\?)"); break; } - switch (pointer[1]) { - case TELQUAL_IS: - sprintf(nfrontp, " IS %.*s", length-2, (char *)pointer+2); - nfrontp += strlen(nfrontp); + switch (pointer[2]) { + case LM_FORWARDMASK: + output_data("Forward Mask"); + for (i = 3; i < length; i++) { + output_data(" %x", pointer[i]); + } break; default: - if (pointer[1] == 1) - sprintf(nfrontp, " SEND"); - else - sprintf(nfrontp, " %d (unknown)", pointer[1]); - nfrontp += strlen(nfrontp); - for (i = 2; i < length; i++) { - sprintf(nfrontp, " ?%d?", pointer[i]); - nfrontp += strlen(nfrontp); + output_data("%d (unknown)", + pointer[2]); + for (i = 3; i < length; i++) { + output_data(" %d", + pointer[i]); } break; } break; - case TELOPT_LFLOW: - sprintf(nfrontp, "TOGGLE-FLOW-CONTROL"); - nfrontp += strlen(nfrontp); - if (length < 2) { - sprintf(nfrontp, " (empty suboption??\?)"); - nfrontp += strlen(nfrontp); - break; - } - switch (pointer[1]) { - case LFLOW_OFF: - sprintf(nfrontp, " OFF"); break; - case LFLOW_ON: - sprintf(nfrontp, " ON"); break; - case LFLOW_RESTART_ANY: - sprintf(nfrontp, " RESTART-ANY"); break; - case LFLOW_RESTART_XON: - sprintf(nfrontp, " RESTART-XON"); break; - default: - sprintf(nfrontp, " %d (unknown)", pointer[1]); + case LM_SLC: + output_data("SLC"); + for (i = 2; i < length - 2; i += 3) { + if (SLC_NAME_OK(pointer[i+SLC_FUNC])) + output_data(" %s", + SLC_NAME(pointer[i+SLC_FUNC])); + else + output_data(" %d", + pointer[i+SLC_FUNC]); + switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) { + case SLC_NOSUPPORT: + output_data(" NOSUPPORT"); + break; + case SLC_CANTCHANGE: + output_data(" CANTCHANGE"); + break; + case SLC_VARIABLE: + output_data(" VARIABLE"); + break; + case SLC_DEFAULT: + output_data(" DEFAULT"); + break; + } + output_data("%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)) { + output_data("(0x%x)", + pointer[i+SLC_FLAGS]); + } + output_data(" %d;", + pointer[i+SLC_VALUE]); + if ((pointer[i+SLC_VALUE] == IAC) && + (pointer[i+SLC_VALUE+1] == IAC)) + i++; } - nfrontp += strlen(nfrontp); - for (i = 2; i < length; i++) { - sprintf(nfrontp, " ?%d?", pointer[i]); - nfrontp += strlen(nfrontp); + for (; i < length; i++) { + output_data(" ?%d?", + pointer[i]); } break; - case TELOPT_NAWS: - sprintf(nfrontp, "NAWS"); - nfrontp += strlen(nfrontp); - if (length < 2) { - sprintf(nfrontp, " (empty suboption??\?)"); - nfrontp += strlen(nfrontp); + case LM_MODE: + output_data("MODE "); + if (length < 3) { + output_data("(no mode??\?)"); break; } - if (length == 2) { - sprintf(nfrontp, " ?%d?", pointer[1]); - nfrontp += strlen(nfrontp); - break; + { + char tbuf[32]; + snprintf(tbuf, + sizeof(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" : ""); + output_data("%s", + tbuf[1] ? &tbuf[1] : "0"); } - sprintf(nfrontp, " %d %d (%d)", - pointer[1], pointer[2], - (int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2]))); - nfrontp += strlen(nfrontp); - if (length == 4) { - sprintf(nfrontp, " ?%d?", pointer[3]); - nfrontp += strlen(nfrontp); - break; + if (pointer[2]&~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK)) { + output_data(" (0x%x)", + pointer[2]); } - sprintf(nfrontp, " %d %d (%d)", - pointer[3], pointer[4], - (int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4]))); - nfrontp += strlen(nfrontp); - for (i = 5; i < length; i++) { - sprintf(nfrontp, " ?%d?", pointer[i]); - nfrontp += strlen(nfrontp); + for (i = 3; i < length; i++) { + output_data(" ?0x%x?", + pointer[i]); } break; - - case TELOPT_LINEMODE: - sprintf(nfrontp, "LINEMODE "); - nfrontp += strlen(nfrontp); - if (length < 2) { - sprintf(nfrontp, " (empty suboption??\?)"); - nfrontp += strlen(nfrontp); - break; + default: + output_data("%d (unknown)", + pointer[1]); + for (i = 2; i < length; i++) { + output_data(" %d", pointer[i]); } - switch (pointer[1]) { - case WILL: - sprintf(nfrontp, "WILL "); - goto common; - case WONT: - sprintf(nfrontp, "WONT "); - goto common; - case DO: - sprintf(nfrontp, "DO "); - goto common; - case DONT: - sprintf(nfrontp, "DONT "); - common: - nfrontp += strlen(nfrontp); - if (length < 3) { - sprintf(nfrontp, "(no option??\?)"); - nfrontp += strlen(nfrontp); - break; - } - switch (pointer[2]) { - case LM_FORWARDMASK: - sprintf(nfrontp, "Forward Mask"); - nfrontp += strlen(nfrontp); - for (i = 3; i < length; i++) { - sprintf(nfrontp, " %x", pointer[i]); - nfrontp += strlen(nfrontp); - } - break; - default: - sprintf(nfrontp, "%d (unknown)", pointer[2]); - nfrontp += strlen(nfrontp); - for (i = 3; i < length; i++) { - sprintf(nfrontp, " %d", pointer[i]); - nfrontp += strlen(nfrontp); - } - break; - } - break; + } + break; - case LM_SLC: - sprintf(nfrontp, "SLC"); - nfrontp += strlen(nfrontp); - for (i = 2; i < length - 2; i += 3) { - if (SLC_NAME_OK(pointer[i+SLC_FUNC])) - sprintf(nfrontp, " %s", SLC_NAME(pointer[i+SLC_FUNC])); - else - sprintf(nfrontp, " %d", pointer[i+SLC_FUNC]); - nfrontp += strlen(nfrontp); - switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) { - case SLC_NOSUPPORT: - sprintf(nfrontp, " NOSUPPORT"); break; - case SLC_CANTCHANGE: - sprintf(nfrontp, " CANTCHANGE"); break; - case SLC_VARIABLE: - sprintf(nfrontp, " VARIABLE"); break; - case SLC_DEFAULT: - sprintf(nfrontp, " DEFAULT"); break; - } - nfrontp += strlen(nfrontp); - sprintf(nfrontp, "%s%s%s", - pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "", - pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "", - pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : ""); - nfrontp += strlen(nfrontp); - if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN| - SLC_FLUSHOUT| SLC_LEVELBITS)) { - sprintf(nfrontp, "(0x%x)", pointer[i+SLC_FLAGS]); - nfrontp += strlen(nfrontp); - } - sprintf(nfrontp, " %d;", pointer[i+SLC_VALUE]); - nfrontp += strlen(nfrontp); - if ((pointer[i+SLC_VALUE] == IAC) && - (pointer[i+SLC_VALUE+1] == IAC)) - i++; - } - for (; i < length; i++) { - sprintf(nfrontp, " ?%d?", pointer[i]); - nfrontp += strlen(nfrontp); - } - break; + case TELOPT_STATUS: { + char *cp; + int j, k; - case LM_MODE: - sprintf(nfrontp, "MODE "); - nfrontp += strlen(nfrontp); - if (length < 3) { - sprintf(nfrontp, "(no mode??\?)"); - nfrontp += strlen(nfrontp); - break; - } - { - char tbuf[32]; - 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" : ""); - sprintf(nfrontp, "%s", tbuf[1] ? &tbuf[1] : "0"); - nfrontp += strlen(nfrontp); - } - if (pointer[2]&~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK)) { - sprintf(nfrontp, " (0x%x)", pointer[2]); - nfrontp += strlen(nfrontp); - } - for (i = 3; i < length; i++) { - sprintf(nfrontp, " ?0x%x?", pointer[i]); - nfrontp += strlen(nfrontp); - } - break; - default: - sprintf(nfrontp, "%d (unknown)", pointer[1]); - nfrontp += strlen(nfrontp); - for (i = 2; i < length; i++) { - sprintf(nfrontp, " %d", pointer[i]); - nfrontp += strlen(nfrontp); - } + output_data("STATUS"); + + switch (pointer[1]) { + default: + if (pointer[1] == TELQUAL_SEND) + output_data(" SEND"); + else + output_data(" %d (unknown)", + pointer[1]); + for (i = 2; i < length; i++) { + output_data(" ?%d?", + pointer[i]); } break; + case TELQUAL_IS: + output_data(" IS\r\n"); - case TELOPT_STATUS: { - register char *cp; - register int j, k; - - sprintf(nfrontp, "STATUS"); - nfrontp += strlen(nfrontp); - - switch (pointer[1]) { - default: - if (pointer[1] == TELQUAL_SEND) - sprintf(nfrontp, " SEND"); + 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(pointer[i])) + output_data(" %s %s", + cp, + TELOPT(pointer[i])); else - sprintf(nfrontp, " %d (unknown)", pointer[1]); - nfrontp += strlen(nfrontp); - for (i = 2; i < length; i++) { - sprintf(nfrontp, " ?%d?", pointer[i]); - nfrontp += strlen(nfrontp); - } + output_data(" %s %d", + cp, + pointer[i]); + + output_data("\r\n"); break; - case TELQUAL_IS: - sprintf(nfrontp, " IS\r\n"); - nfrontp += strlen(nfrontp); - - 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(pointer[i])) - sprintf(nfrontp, " %s %s", cp, TELOPT(pointer[i])); - else - sprintf(nfrontp, " %s %d", cp, pointer[i]); - nfrontp += strlen(nfrontp); - - sprintf(nfrontp, "\r\n"); - nfrontp += strlen(nfrontp); - break; - case SB: - sprintf(nfrontp, " SB "); - nfrontp += strlen(nfrontp); - 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++]; + case SB: + output_data(" 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; } - printsub(0, &pointer[i], k - i); - if (i < length) { - sprintf(nfrontp, " SE"); - nfrontp += strlen(nfrontp); - i = j; - } else - i = j - 1; + pointer[k++] = pointer[j++]; + } + printsub(0, &pointer[i], k - i); + if (i < length) { + output_data(" SE"); + i = j; + } else + i = j - 1; - sprintf(nfrontp, "\r\n"); - nfrontp += strlen(nfrontp); + output_data("\r\n"); - break; + break; - default: - sprintf(nfrontp, " %d", pointer[i]); - nfrontp += strlen(nfrontp); - break; - } + default: + output_data(" %d", + pointer[i]); + break; } - break; } break; - } - - case TELOPT_XDISPLOC: - sprintf(nfrontp, "X-DISPLAY-LOCATION "); - nfrontp += strlen(nfrontp); - switch (pointer[1]) { - case TELQUAL_IS: - sprintf(nfrontp, "IS \"%.*s\"", length-2, (char *)pointer+2); - break; - case TELQUAL_SEND: - sprintf(nfrontp, "SEND"); - break; - default: - sprintf(nfrontp, "- unknown qualifier %d (0x%x).", - pointer[1], pointer[1]); - } - nfrontp += strlen(nfrontp); + } + break; + } + + case TELOPT_XDISPLOC: + output_data("X-DISPLAY-LOCATION "); + switch (pointer[1]) { + case TELQUAL_IS: + output_data("IS \"%.*s\"", + length-2, + (char *)pointer+2); break; + case TELQUAL_SEND: + output_data("SEND"); + break; + default: + output_data("- unknown qualifier %d (0x%x).", + pointer[1], pointer[1]); + } + break; + + case TELOPT_NEW_ENVIRON: + output_data("NEW-ENVIRON "); + goto env_common1; + case TELOPT_OLD_ENVIRON: + output_data("OLD-ENVIRON"); + env_common1: + switch (pointer[1]) { + case TELQUAL_IS: + output_data("IS "); + goto env_common; + case TELQUAL_SEND: + output_data("SEND "); + goto env_common; + case TELQUAL_INFO: + output_data("INFO "); + env_common: + { + int noquote = 2; + for (i = 2; i < length; i++ ) { + switch (pointer[i]) { + case NEW_ENV_VAR: + output_data("\" VAR " + noquote); + noquote = 2; + break; - case TELOPT_NEW_ENVIRON: - sprintf(nfrontp, "NEW-ENVIRON "); - goto env_common1; - case TELOPT_OLD_ENVIRON: - sprintf(nfrontp, "OLD-ENVIRON"); - env_common1: - nfrontp += strlen(nfrontp); - switch (pointer[1]) { - case TELQUAL_IS: - sprintf(nfrontp, "IS "); - goto env_common; - case TELQUAL_SEND: - sprintf(nfrontp, "SEND "); - goto env_common; - case TELQUAL_INFO: - sprintf(nfrontp, "INFO "); - env_common: - nfrontp += strlen(nfrontp); - { - register int noquote = 2; - for (i = 2; i < length; i++ ) { - switch (pointer[i]) { - case NEW_ENV_VAR: - sprintf(nfrontp, "\" VAR " + noquote); - nfrontp += strlen(nfrontp); - noquote = 2; - break; + case NEW_ENV_VALUE: + output_data("\" VALUE " + noquote); + noquote = 2; + break; - case NEW_ENV_VALUE: - sprintf(nfrontp, "\" VALUE " + noquote); - nfrontp += strlen(nfrontp); - noquote = 2; - break; + case ENV_ESC: + output_data("\" ESC " + noquote); + noquote = 2; + break; - case ENV_ESC: - sprintf(nfrontp, "\" ESC " + noquote); - nfrontp += strlen(nfrontp); - noquote = 2; - break; + case ENV_USERVAR: + output_data("\" USERVAR " + noquote); + noquote = 2; + break; - case ENV_USERVAR: - sprintf(nfrontp, "\" USERVAR " + noquote); - nfrontp += strlen(nfrontp); - noquote = 2; - break; - - default: - if (isprint(pointer[i]) && pointer[i] != '"') { - if (noquote) { - *nfrontp++ = '"'; - noquote = 0; - } - *nfrontp++ = pointer[i]; - } else { - sprintf(nfrontp, "\" %03o " + noquote, - pointer[i]); - nfrontp += strlen(nfrontp); - noquote = 2; + default: + if (isprint(pointer[i]) && pointer[i] != '"') { + if (noquote) { + output_data ("\""); + noquote = 0; } - break; + output_data ("%c", pointer[i]); + } else { + output_data("\" %03o " + noquote, + pointer[i]); + noquote = 2; } + break; } - if (!noquote) - *nfrontp++ = '"'; - break; } + if (!noquote) + output_data ("\""); + break; } - break; + } + break; -#if defined(AUTHENTICATION) - case TELOPT_AUTHENTICATION: - sprintf(nfrontp, "AUTHENTICATION"); - nfrontp += strlen(nfrontp); +#ifdef AUTHENTICATION + case TELOPT_AUTHENTICATION: + output_data("AUTHENTICATION"); - if (length < 2) { - sprintf(nfrontp, " (empty suboption??\?)"); - nfrontp += strlen(nfrontp); + if (length < 2) { + output_data(" (empty suboption??\?)"); + break; + } + switch (pointer[1]) { + case TELQUAL_REPLY: + case TELQUAL_IS: + output_data(" %s ", + (pointer[1] == TELQUAL_IS) ? + "IS" : "REPLY"); + if (AUTHTYPE_NAME_OK(pointer[2])) + output_data("%s ", + AUTHTYPE_NAME(pointer[2])); + else + output_data("%d ", + pointer[2]); + if (length < 3) { + output_data("(partial suboption??\?)"); break; } - switch (pointer[1]) { - case TELQUAL_REPLY: - case TELQUAL_IS: - sprintf(nfrontp, " %s ", (pointer[1] == TELQUAL_IS) ? - "IS" : "REPLY"); - nfrontp += strlen(nfrontp); - if (AUTHTYPE_NAME_OK(pointer[2])) - sprintf(nfrontp, "%s ", AUTHTYPE_NAME(pointer[2])); - else - sprintf(nfrontp, "%d ", pointer[2]); - nfrontp += strlen(nfrontp); - if (length < 3) { - sprintf(nfrontp, "(partial suboption??\?)"); - nfrontp += strlen(nfrontp); - break; - } - sprintf(nfrontp, "%s|%s", + output_data("%s|%s", ((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? "CLIENT" : "SERVER", ((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? "MUTUAL" : "ONE-WAY"); - nfrontp += strlen(nfrontp); - auth_printsub(&pointer[1], length - 1, buf, sizeof(buf)); - sprintf(nfrontp, "%s", buf); - nfrontp += strlen(nfrontp); - break; + auth_printsub(&pointer[1], length - 1, buf, sizeof(buf)); + output_data("%s", + buf); + break; - case TELQUAL_SEND: - i = 2; - sprintf(nfrontp, " SEND "); - nfrontp += strlen(nfrontp); - while (i < length) { - if (AUTHTYPE_NAME_OK(pointer[i])) - sprintf(nfrontp, "%s ", AUTHTYPE_NAME(pointer[i])); - else - sprintf(nfrontp, "%d ", pointer[i]); - nfrontp += strlen(nfrontp); - if (++i >= length) { - sprintf(nfrontp, "(partial suboption??\?)"); - nfrontp += strlen(nfrontp); - break; - } - sprintf(nfrontp, "%s|%s ", - ((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? - "CLIENT" : "SERVER", - ((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? - "MUTUAL" : "ONE-WAY"); - nfrontp += strlen(nfrontp); - ++i; + case TELQUAL_SEND: + i = 2; + output_data(" SEND "); + while (i < length) { + if (AUTHTYPE_NAME_OK(pointer[i])) + output_data("%s ", + AUTHTYPE_NAME(pointer[i])); + else + output_data("%d ", + pointer[i]); + if (++i >= length) { + output_data("(partial suboption??\?)"); + break; } - break; + output_data("%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; - sprintf(nfrontp, " NAME \""); - nfrontp += strlen(nfrontp); - while (i < length) - *nfrontp += pointer[i++]; - *nfrontp += '"'; - break; + case TELQUAL_NAME: + i = 2; + output_data(" NAME \"%.*s\"", + length - 2, + pointer); + break; - default: - for (i = 2; i < length; i++) { - sprintf(nfrontp, " ?%d?", pointer[i]); - nfrontp += strlen(nfrontp); - } - break; + default: + for (i = 2; i < length; i++) { + output_data(" ?%d?", + pointer[i]); } break; + } + break; #endif #ifdef ENCRYPTION - case TELOPT_ENCRYPT: - output_data("ENCRYPT"); - if (length < 2) { - output_data(" (empty suboption?)"); + case TELOPT_ENCRYPT: + output_data("ENCRYPT"); + if (length < 2) { + output_data(" (empty suboption?)"); + break; + } + switch (pointer[1]) { + case ENCRYPT_START: + output_data(" START"); + break; + + case ENCRYPT_END: + output_data(" END"); + break; + + case ENCRYPT_REQSTART: + output_data(" REQUEST-START"); + break; + + case ENCRYPT_REQEND: + output_data(" REQUEST-END"); + break; + + case ENCRYPT_IS: + case ENCRYPT_REPLY: + output_data(" %s ", + (pointer[1] == ENCRYPT_IS) ? + "IS" : "REPLY"); + if (length < 3) { + output_data(" (partial suboption?)"); break; } - switch (pointer[1]) { - case ENCRYPT_START: - output_data(" START"); - break; - - case ENCRYPT_END: - output_data(" END"); - break; - - case ENCRYPT_REQSTART: - output_data(" REQUEST-START"); - break; + if (ENCTYPE_NAME_OK(pointer[2])) + output_data("%s ", + ENCTYPE_NAME(pointer[2])); + else + output_data(" %d (unknown)", + pointer[2]); - case ENCRYPT_REQEND: - output_data(" REQUEST-END"); - break; - - case ENCRYPT_IS: - case ENCRYPT_REPLY: - output_data(" %s ", - (pointer[1] == ENCRYPT_IS) ? - "IS" : "REPLY"); - if (length < 3) { - output_data(" (partial suboption?)"); - break; - } - if (ENCTYPE_NAME_OK(pointer[2])) + encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf)); + output_data("%s", + buf); + break; + + case ENCRYPT_SUPPORT: + i = 2; + output_data(" SUPPORT "); + while (i < length) { + if (ENCTYPE_NAME_OK(pointer[i])) output_data("%s ", - ENCTYPE_NAME(pointer[2])); + ENCTYPE_NAME(pointer[i])); else - output_data(" %d (unknown)", - pointer[2]); - - encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf)); - output_data("%s", - buf); - break; - - case ENCRYPT_SUPPORT: - i = 2; - output_data(" SUPPORT "); - while (i < length) { - if (ENCTYPE_NAME_OK(pointer[i])) - output_data("%s ", - ENCTYPE_NAME(pointer[i])); - else - output_data("%d ", - pointer[i]); - i++; - } - break; - - case ENCRYPT_ENC_KEYID: - output_data(" ENC_KEYID %d", pointer[1]); - goto encommon; - - case ENCRYPT_DEC_KEYID: - output_data(" DEC_KEYID %d", pointer[1]); - goto encommon; - - default: - output_data(" %d (unknown)", pointer[1]); - encommon: - for (i = 2; i < length; i++) { - output_data(" %d", pointer[i]); - } - break; + output_data("%d ", + pointer[i]); + i++; } break; -#endif /* ENCRYPTION */ + + case ENCRYPT_ENC_KEYID: + output_data(" ENC_KEYID %d", pointer[1]); + goto encommon; + + case ENCRYPT_DEC_KEYID: + output_data(" DEC_KEYID %d", pointer[1]); + goto encommon; default: - if (TELOPT_OK(pointer[0])) - sprintf(nfrontp, "%s (unknown)", TELOPT(pointer[0])); - else - sprintf(nfrontp, "%d (unknown)", pointer[i]); - nfrontp += strlen(nfrontp); - for (i = 1; i < length; i++) { - sprintf(nfrontp, " %d", pointer[i]); - nfrontp += strlen(nfrontp); + output_data(" %d (unknown)", pointer[1]); + encommon: + for (i = 2; i < length; i++) { + output_data(" %d", pointer[i]); } break; } - sprintf(nfrontp, "\r\n"); - nfrontp += strlen(nfrontp); + break; +#endif + + default: + if (TELOPT_OK(pointer[0])) + output_data("%s (unknown)", + TELOPT(pointer[0])); + else + output_data("%d (unknown)", + pointer[i]); + for (i = 1; i < length; i++) { + output_data(" %d", pointer[i]); + } + break; + } + output_data("\r\n"); } /* * Dump a data buffer in hex and ascii to the output data stream. */ - void -printdata(tag, ptr, cnt) - register char *tag; - register char *ptr; - register int cnt; +void +printdata(char *tag, char *ptr, int cnt) { - register int i; - char xbuf[30]; + int i; + char xbuf[30]; - while (cnt) { - /* flush net output buffer if no room for new data) */ - if ((&netobuf[BUFSIZ] - nfrontp) < 80) { - netflush(); - } + while (cnt) { + /* flush net output buffer if no room for new data) */ + if ((&netobuf[BUFSIZ] - nfrontp) < 80) { + netflush(); + } - /* add a line of output */ - sprintf(nfrontp, "%s: ", tag); - nfrontp += strlen(nfrontp); - for (i = 0; i < 20 && cnt; i++) { - sprintf(nfrontp, "%02x", *ptr); - nfrontp += strlen(nfrontp); - if (isprint(*ptr)) { - xbuf[i] = *ptr; - } else { - xbuf[i] = '.'; - } - if (i % 2) { - *nfrontp = ' '; - nfrontp++; - } - cnt--; - ptr++; - } - xbuf[i] = '\0'; - sprintf(nfrontp, " %s\r\n", xbuf ); - nfrontp += strlen(nfrontp); + /* add a line of output */ + output_data("%s: ", tag); + for (i = 0; i < 20 && cnt; i++) { + output_data("%02x", *ptr); + if (isprint(*ptr)) { + xbuf[i] = *ptr; + } else { + xbuf[i] = '.'; + } + if (i % 2) { + output_data(" "); + } + cnt--; + ptr++; } + xbuf[i] = '\0'; + output_data(" %s\r\n", xbuf); + } } #endif /* DIAGNOSTICS */ |