diff --git a/contrib/telnet/arpa/telnet.h b/contrib/telnet/arpa/telnet.h index 10155a84a87c..01601f16b24e 100644 --- a/contrib/telnet/arpa/telnet.h +++ b/contrib/telnet/arpa/telnet.h @@ -1,320 +1,340 @@ /* * Copyright (c) 1983, 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. * * @(#)telnet.h 8.2 (Berkeley) 12/15/93 */ -#ifndef _TELNET_H_ -#define _TELNET_H_ +#ifndef _ARPA_TELNET_H_ +#define _ARPA_TELNET_H_ /* * Definitions for the TELNET protocol. */ #define IAC 255 /* interpret as command: */ #define DONT 254 /* you are not to use option */ #define DO 253 /* please, you use option */ #define WONT 252 /* I won't use option */ #define WILL 251 /* I will use option */ #define SB 250 /* interpret as subnegotiation */ #define GA 249 /* you may reverse the line */ #define EL 248 /* erase the current line */ #define EC 247 /* erase the current character */ #define AYT 246 /* are you there */ #define AO 245 /* abort output--but let prog finish */ #define IP 244 /* interrupt process--permanently */ #define BREAK 243 /* break */ #define DM 242 /* data mark--for connect. cleaning */ #define NOP 241 /* nop */ #define SE 240 /* end sub negotiation */ #define EOR 239 /* end of record (transparent mode) */ #define ABORT 238 /* Abort process */ #define SUSP 237 /* Suspend process */ #define xEOF 236 /* End of file: EOF is already used... */ #define SYNCH 242 /* for telfunc calls */ #ifdef TELCMDS char *telcmds[] = { "EOF", "SUSP", "ABORT", "EOR", "SE", "NOP", "DMARK", "BRK", "IP", "AO", "AYT", "EC", - "EL", "GA", "SB", "WILL", "WONT", "DO", "DONT", "IAC", 0, + "EL", "GA", "SB", "WILL", "WONT", "DO", "DONT", "IAC", + 0 }; #else extern char *telcmds[]; #endif #define TELCMD_FIRST xEOF #define TELCMD_LAST IAC #define TELCMD_OK(x) ((unsigned int)(x) <= TELCMD_LAST && \ (unsigned int)(x) >= TELCMD_FIRST) #define TELCMD(x) telcmds[(x)-TELCMD_FIRST] /* telnet options */ #define TELOPT_BINARY 0 /* 8-bit data path */ #define TELOPT_ECHO 1 /* echo */ #define TELOPT_RCP 2 /* prepare to reconnect */ #define TELOPT_SGA 3 /* suppress go ahead */ #define TELOPT_NAMS 4 /* approximate message size */ #define TELOPT_STATUS 5 /* give status */ #define TELOPT_TM 6 /* timing mark */ #define TELOPT_RCTE 7 /* remote controlled transmission and echo */ #define TELOPT_NAOL 8 /* negotiate about output line width */ #define TELOPT_NAOP 9 /* negotiate about output page size */ #define TELOPT_NAOCRD 10 /* negotiate about CR disposition */ #define TELOPT_NAOHTS 11 /* negotiate about horizontal tabstops */ #define TELOPT_NAOHTD 12 /* negotiate about horizontal tab disposition */ #define TELOPT_NAOFFD 13 /* negotiate about formfeed disposition */ #define TELOPT_NAOVTS 14 /* negotiate about vertical tab stops */ #define TELOPT_NAOVTD 15 /* negotiate about vertical tab disposition */ #define TELOPT_NAOLFD 16 /* negotiate about output LF disposition */ #define TELOPT_XASCII 17 /* extended ascic character set */ #define TELOPT_LOGOUT 18 /* force logout */ #define TELOPT_BM 19 /* byte macro */ #define TELOPT_DET 20 /* data entry terminal */ #define TELOPT_SUPDUP 21 /* supdup protocol */ #define TELOPT_SUPDUPOUTPUT 22 /* supdup output */ #define TELOPT_SNDLOC 23 /* send location */ #define TELOPT_TTYPE 24 /* terminal type */ #define TELOPT_EOR 25 /* end or record */ #define TELOPT_TUID 26 /* TACACS user identification */ #define TELOPT_OUTMRK 27 /* output marking */ #define TELOPT_TTYLOC 28 /* terminal location number */ #define TELOPT_3270REGIME 29 /* 3270 regime */ #define TELOPT_X3PAD 30 /* X.3 PAD */ #define TELOPT_NAWS 31 /* window size */ #define TELOPT_TSPEED 32 /* terminal speed */ #define TELOPT_LFLOW 33 /* remote flow control */ #define TELOPT_LINEMODE 34 /* Linemode option */ #define TELOPT_XDISPLOC 35 /* X Display Location */ #define TELOPT_OLD_ENVIRON 36 /* Old - Environment variables */ #define TELOPT_AUTHENTICATION 37/* Authenticate */ #define TELOPT_ENCRYPT 38 /* Encryption option */ #define TELOPT_NEW_ENVIRON 39 /* New - Environment variables */ #define TELOPT_EXOPL 255 /* extended-options-list */ #define NTELOPTS (1+TELOPT_NEW_ENVIRON) #ifdef TELOPTS char *telopts[NTELOPTS+1] = { "BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD", "NAME", "STATUS", "TIMING MARK", "RCTE", "NAOL", "NAOP", "NAOCRD", "NAOHTS", "NAOHTD", "NAOFFD", "NAOVTS", "NAOVTD", "NAOLFD", "EXTEND ASCII", "LOGOUT", "BYTE MACRO", "DATA ENTRY TERMINAL", "SUPDUP", "SUPDUP OUTPUT", "SEND LOCATION", "TERMINAL TYPE", "END OF RECORD", "TACACS UID", "OUTPUT MARKING", "TTYLOC", "3270 REGIME", "X.3 PAD", "NAWS", "TSPEED", "LFLOW", "LINEMODE", "XDISPLOC", "OLD-ENVIRON", "AUTHENTICATION", "ENCRYPT", "NEW-ENVIRON", - 0, + 0 }; #define TELOPT_FIRST TELOPT_BINARY #define TELOPT_LAST TELOPT_NEW_ENVIRON #define TELOPT_OK(x) ((unsigned int)(x) <= TELOPT_LAST) #define TELOPT(x) telopts[(x)-TELOPT_FIRST] #endif /* sub-option qualifiers */ #define TELQUAL_IS 0 /* option is... */ #define TELQUAL_SEND 1 /* send option */ #define TELQUAL_INFO 2 /* ENVIRON: informational version of IS */ #define TELQUAL_REPLY 2 /* AUTHENTICATION: client version of IS */ #define TELQUAL_NAME 3 /* AUTHENTICATION: client version of IS */ #define LFLOW_OFF 0 /* Disable remote flow control */ #define LFLOW_ON 1 /* Enable remote flow control */ #define LFLOW_RESTART_ANY 2 /* Restart output on any char */ #define LFLOW_RESTART_XON 3 /* Restart output only on XON */ /* * LINEMODE suboptions */ #define LM_MODE 1 #define LM_FORWARDMASK 2 #define LM_SLC 3 #define MODE_EDIT 0x01 #define MODE_TRAPSIG 0x02 #define MODE_ACK 0x04 #define MODE_SOFT_TAB 0x08 #define MODE_LIT_ECHO 0x10 #define MODE_MASK 0x1f /* Not part of protocol, but needed to simplify things... */ #define MODE_FLOW 0x0100 #define MODE_ECHO 0x0200 #define MODE_INBIN 0x0400 #define MODE_OUTBIN 0x0800 #define MODE_FORCE 0x1000 #define SLC_SYNCH 1 #define SLC_BRK 2 #define SLC_IP 3 #define SLC_AO 4 #define SLC_AYT 5 #define SLC_EOR 6 #define SLC_ABORT 7 #define SLC_EOF 8 #define SLC_SUSP 9 #define SLC_EC 10 #define SLC_EL 11 #define SLC_EW 12 #define SLC_RP 13 #define SLC_LNEXT 14 #define SLC_XON 15 #define SLC_XOFF 16 #define SLC_FORW1 17 #define SLC_FORW2 18 - -#define NSLC 18 +#define SLC_MCL 19 +#define SLC_MCR 20 +#define SLC_MCWL 21 +#define SLC_MCWR 22 +#define SLC_MCBOL 23 +#define SLC_MCEOL 24 +#define SLC_INSRT 25 +#define SLC_OVER 26 +#define SLC_ECR 27 +#define SLC_EWR 28 +#define SLC_EBOL 29 +#define SLC_EEOL 30 + +#define NSLC 30 /* * For backwards compatability, we define SLC_NAMES to be the * list of names if SLC_NAMES is not defined. */ #define SLC_NAMELIST "0", "SYNCH", "BRK", "IP", "AO", "AYT", "EOR", \ "ABORT", "EOF", "SUSP", "EC", "EL", "EW", "RP", \ - "LNEXT", "XON", "XOFF", "FORW1", "FORW2", 0, + "LNEXT", "XON", "XOFF", "FORW1", "FORW2", \ + "MCL", "MCR", "MCWL", "MCWR", "MCBOL", \ + "MCEOL", "INSRT", "OVER", "ECR", "EWR", \ + "EBOL", "EEOL", \ + 0 + #ifdef SLC_NAMES char *slc_names[] = { SLC_NAMELIST }; #else extern char *slc_names[]; #define SLC_NAMES SLC_NAMELIST #endif #define SLC_NAME_OK(x) ((unsigned int)(x) <= NSLC) #define SLC_NAME(x) slc_names[x] #define SLC_NOSUPPORT 0 #define SLC_CANTCHANGE 1 #define SLC_VARIABLE 2 #define SLC_DEFAULT 3 #define SLC_LEVELBITS 0x03 #define SLC_FUNC 0 #define SLC_FLAGS 1 #define SLC_VALUE 2 #define SLC_ACK 0x80 #define SLC_FLUSHIN 0x40 #define SLC_FLUSHOUT 0x20 #define OLD_ENV_VAR 1 #define OLD_ENV_VALUE 0 #define NEW_ENV_VAR 0 #define NEW_ENV_VALUE 1 #define ENV_ESC 2 #define ENV_USERVAR 3 /* * AUTHENTICATION suboptions */ /* * Who is authenticating who ... */ #define AUTH_WHO_CLIENT 0 /* Client authenticating server */ #define AUTH_WHO_SERVER 1 /* Server authenticating client */ #define AUTH_WHO_MASK 1 /* * amount of authentication done */ #define AUTH_HOW_ONE_WAY 0 #define AUTH_HOW_MUTUAL 2 #define AUTH_HOW_MASK 2 #define AUTHTYPE_NULL 0 #define AUTHTYPE_KERBEROS_V4 1 #define AUTHTYPE_KERBEROS_V5 2 #define AUTHTYPE_SPX 3 #define AUTHTYPE_MINK 4 #define AUTHTYPE_CNT 5 #define AUTHTYPE_TEST 99 #ifdef AUTH_NAMES char *authtype_names[] = { - "NULL", "KERBEROS_V4", "KERBEROS_V5", "SPX", "MINK", 0, + "NULL", "KERBEROS_V4", "KERBEROS_V5", "SPX", "MINK", + 0 }; #else extern char *authtype_names[]; #endif #define AUTHTYPE_NAME_OK(x) ((unsigned int)(x) < AUTHTYPE_CNT) #define AUTHTYPE_NAME(x) authtype_names[x] /* * ENCRYPTion suboptions */ #define ENCRYPT_IS 0 /* I pick encryption type ... */ #define ENCRYPT_SUPPORT 1 /* I support encryption types ... */ #define ENCRYPT_REPLY 2 /* Initial setup response */ #define ENCRYPT_START 3 /* Am starting to send encrypted */ #define ENCRYPT_END 4 /* Am ending encrypted */ #define ENCRYPT_REQSTART 5 /* Request you start encrypting */ -#define ENCRYPT_REQEND 6 /* Request you send encrypting */ +#define ENCRYPT_REQEND 6 /* Request you end encrypting */ #define ENCRYPT_ENC_KEYID 7 #define ENCRYPT_DEC_KEYID 8 #define ENCRYPT_CNT 9 #define ENCTYPE_ANY 0 #define ENCTYPE_DES_CFB64 1 #define ENCTYPE_DES_OFB64 2 #define ENCTYPE_CNT 3 #ifdef ENCRYPT_NAMES char *encrypt_names[] = { "IS", "SUPPORT", "REPLY", "START", "END", "REQUEST-START", "REQUEST-END", "ENC-KEYID", "DEC-KEYID", - 0, + 0 }; char *enctype_names[] = { - "ANY", "DES_CFB64", "DES_OFB64", 0, + "ANY", "DES_CFB64", "DES_OFB64", + 0 }; #else extern char *encrypt_names[]; extern char *enctype_names[]; #endif #define ENCRYPT_NAME_OK(x) ((unsigned int)(x) < ENCRYPT_CNT) #define ENCRYPT_NAME(x) encrypt_names[x] #define ENCTYPE_NAME_OK(x) ((unsigned int)(x) < ENCTYPE_CNT) #define ENCTYPE_NAME(x) enctype_names[x] #endif /* !_TELNET_H_ */ diff --git a/contrib/telnet/libtelnet/auth-proto.h b/contrib/telnet/libtelnet/auth-proto.h index 06bba2b55c1d..a1e9aa410ff6 100644 --- a/contrib/telnet/libtelnet/auth-proto.h +++ b/contrib/telnet/libtelnet/auth-proto.h @@ -1,96 +1,100 @@ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. * * @(#)auth-proto.h 8.1 (Berkeley) 6/4/93 */ /* * Copyright (C) 1990 by the Massachusetts Institute of Technology * * Export of this software from the United States of America is assumed * to require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. */ #if !defined(P) #ifdef __STDC__ #define P(x) x #else #define P(x) () #endif #endif #if defined(AUTHENTICATION) Authenticator *findauthenticator P((int, int)); void auth_init P((char *, int)); int auth_cmd P((int, char **)); void auth_request P((void)); void auth_send P((unsigned char *, int)); void auth_send_retry P((void)); void auth_is P((unsigned char *, int)); void auth_reply P((unsigned char *, int)); void auth_finished P((Authenticator *, int)); int auth_wait P((char *)); void auth_disable_name P((char *)); void auth_gen_printsub P((unsigned char *, int, unsigned char *, int)); +void auth_name P((unsigned char *, int)); +void auth_printsub P((unsigned char *, int, unsigned char *, int)); +int auth_sendname P((unsigned char *, int)); +void auth_encrypt_user P((char *)); #ifdef KRB4 int kerberos4_init P((Authenticator *, int)); int kerberos4_send P((Authenticator *)); void kerberos4_is P((Authenticator *, unsigned char *, int)); void kerberos4_reply P((Authenticator *, unsigned char *, int)); int kerberos4_status P((Authenticator *, char *, int)); void kerberos4_printsub P((unsigned char *, int, unsigned char *, int)); #endif #ifdef KRB5 int kerberos5_init P((Authenticator *, int)); int kerberos5_send P((Authenticator *)); void kerberos5_is P((Authenticator *, unsigned char *, int)); void kerberos5_reply P((Authenticator *, unsigned char *, int)); int kerberos5_status P((Authenticator *, char *, int)); void kerberos5_printsub P((unsigned char *, int, unsigned char *, int)); #endif #endif diff --git a/contrib/telnet/libtelnet/auth.c b/contrib/telnet/libtelnet/auth.c index a8b287c0e5f7..4262b55a100a 100644 --- a/contrib/telnet/libtelnet/auth.c +++ b/contrib/telnet/libtelnet/auth.c @@ -1,671 +1,674 @@ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. */ #ifndef lint -static char sccsid[] = "@(#)auth.c 8.3 (Berkeley) 5/30/95"; +static const char sccsid[] = "@(#)auth.c 8.3 (Berkeley) 5/30/95"; #endif /* not lint */ /* * Copyright (C) 1990 by the Massachusetts Institute of Technology * * Export of this software from the United States of America is assumed * to require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. */ #if defined(AUTHENTICATION) #include #include #include #define AUTH_NAMES #include #ifdef __STDC__ #include +#include #endif #ifdef NO_STRING_H #include #else #include #endif #include "encrypt.h" #include "auth.h" #include "misc-proto.h" #include "auth-proto.h" #define typemask(x) (1<<((x)-1)) #ifdef KRB4_ENCPWD extern krb4encpwd_init(); extern krb4encpwd_send(); extern krb4encpwd_is(); extern krb4encpwd_reply(); extern krb4encpwd_status(); extern krb4encpwd_printsub(); #endif #ifdef RSA_ENCPWD extern rsaencpwd_init(); extern rsaencpwd_send(); extern rsaencpwd_is(); extern rsaencpwd_reply(); extern rsaencpwd_status(); extern rsaencpwd_printsub(); #endif int auth_debug_mode = 0; static char *Name = "Noname"; static int Server = 0; static Authenticator *authenticated = 0; static int authenticating = 0; static int validuser = 0; static unsigned char _auth_send_data[256]; static unsigned char *auth_send_data; static int auth_send_cnt = 0; +int auth_onoff(char *type, int on); +void auth_encrypt_user(char *name); + /* * Authentication types supported. Plese note that these are stored * in priority order, i.e. try the first one first. */ Authenticator authenticators[] = { #ifdef SPX { AUTHTYPE_SPX, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL, spx_init, spx_send, spx_is, spx_reply, spx_status, spx_printsub }, { AUTHTYPE_SPX, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY, spx_init, spx_send, spx_is, spx_reply, spx_status, spx_printsub }, #endif #ifdef KRB5 # ifdef ENCRYPTION { AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL, kerberos5_init, kerberos5_send, kerberos5_is, kerberos5_reply, kerberos5_status, kerberos5_printsub }, # endif /* ENCRYPTION */ { AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY, kerberos5_init, kerberos5_send, kerberos5_is, kerberos5_reply, kerberos5_status, kerberos5_printsub }, #endif #ifdef KRB4 # ifdef ENCRYPTION { AUTHTYPE_KERBEROS_V4, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL, kerberos4_init, kerberos4_send, kerberos4_is, kerberos4_reply, kerberos4_status, kerberos4_printsub }, # endif /* ENCRYPTION */ { AUTHTYPE_KERBEROS_V4, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY, kerberos4_init, kerberos4_send, kerberos4_is, kerberos4_reply, kerberos4_status, kerberos4_printsub }, #endif #ifdef KRB4_ENCPWD { AUTHTYPE_KRB4_ENCPWD, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL, krb4encpwd_init, krb4encpwd_send, krb4encpwd_is, krb4encpwd_reply, krb4encpwd_status, krb4encpwd_printsub }, #endif #ifdef RSA_ENCPWD { AUTHTYPE_RSA_ENCPWD, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY, rsaencpwd_init, rsaencpwd_send, rsaencpwd_is, rsaencpwd_reply, rsaencpwd_status, rsaencpwd_printsub }, #endif { 0, }, }; static Authenticator NoAuth = { 0 }; static int i_support = 0; static int i_wont_support = 0; Authenticator * findauthenticator(type, way) int type; int way; { Authenticator *ap = authenticators; while (ap->type && (ap->type != type || ap->way != way)) ++ap; return(ap->type ? ap : 0); } void auth_init(name, server) char *name; int server; { Authenticator *ap = authenticators; Server = server; Name = name; i_support = 0; authenticated = 0; authenticating = 0; while (ap->type) { if (!ap->init || (*ap->init)(ap, server)) { i_support |= typemask(ap->type); if (auth_debug_mode) printf(">>>%s: I support auth type %d %d\r\n", Name, ap->type, ap->way); } else if (auth_debug_mode) printf(">>>%s: Init failed: auth type %d %d\r\n", Name, ap->type, ap->way); ++ap; } } void auth_disable_name(name) char *name; { int x; for (x = 0; x < AUTHTYPE_CNT; ++x) { if (!strcasecmp(name, AUTHTYPE_NAME(x))) { i_wont_support |= typemask(x); break; } } } int getauthmask(type, maskp) char *type; int *maskp; { register int x; if (!strcasecmp(type, AUTHTYPE_NAME(0))) { *maskp = -1; return(1); } for (x = 1; x < AUTHTYPE_CNT; ++x) { if (!strcasecmp(type, AUTHTYPE_NAME(x))) { *maskp = typemask(x); return(1); } } return(0); } int auth_enable(type) char *type; { return(auth_onoff(type, 1)); } int auth_disable(type) char *type; { return(auth_onoff(type, 0)); } int auth_onoff(type, on) char *type; int on; { int i, mask = -1; Authenticator *ap; if (!strcasecmp(type, "?") || !strcasecmp(type, "help")) { printf("auth %s 'type'\n", on ? "enable" : "disable"); printf("Where 'type' is one of:\n"); printf("\t%s\n", AUTHTYPE_NAME(0)); mask = 0; for (ap = authenticators; ap->type; ap++) { if ((mask & (i = typemask(ap->type))) != 0) continue; mask |= i; printf("\t%s\n", AUTHTYPE_NAME(ap->type)); } return(0); } if (!getauthmask(type, &mask)) { printf("%s: invalid authentication type\n", type); return(0); } if (on) i_wont_support &= ~mask; else i_wont_support |= mask; return(1); } int auth_togdebug(on) int on; { if (on < 0) auth_debug_mode ^= 1; else auth_debug_mode = on; printf("auth debugging %s\n", auth_debug_mode ? "enabled" : "disabled"); return(1); } int auth_status() { Authenticator *ap; int i, mask; if (i_wont_support == -1) printf("Authentication disabled\n"); else printf("Authentication enabled\n"); mask = 0; for (ap = authenticators; ap->type; ap++) { if ((mask & (i = typemask(ap->type))) != 0) continue; mask |= i; printf("%s: %s\n", AUTHTYPE_NAME(ap->type), (i_wont_support & typemask(ap->type)) ? "disabled" : "enabled"); } return(1); } /* * This routine is called by the server to start authentication * negotiation. */ void auth_request() { static unsigned char str_request[64] = { IAC, SB, TELOPT_AUTHENTICATION, TELQUAL_SEND, }; Authenticator *ap = authenticators; unsigned char *e = str_request + 4; if (!authenticating) { authenticating = 1; while (ap->type) { if (i_support & ~i_wont_support & typemask(ap->type)) { if (auth_debug_mode) { printf(">>>%s: Sending type %d %d\r\n", Name, ap->type, ap->way); } *e++ = ap->type; *e++ = ap->way; } ++ap; } *e++ = IAC; *e++ = SE; net_write(str_request, e - str_request); printsub('>', &str_request[2], e - str_request - 2); } } /* * This is called when an AUTH SEND is received. * It should never arrive on the server side (as only the server can * send an AUTH SEND). * You should probably respond to it if you can... * * If you want to respond to the types out of order (i.e. even * if he sends LOGIN KERBEROS and you support both, you respond * with KERBEROS instead of LOGIN (which is against what the * protocol says)) you will have to hack this code... */ void auth_send(data, cnt) unsigned char *data; int cnt; { Authenticator *ap; static unsigned char str_none[] = { IAC, SB, TELOPT_AUTHENTICATION, TELQUAL_IS, AUTHTYPE_NULL, 0, IAC, SE }; if (Server) { if (auth_debug_mode) { printf(">>>%s: auth_send called!\r\n", Name); } return; } if (auth_debug_mode) { printf(">>>%s: auth_send got:", Name); printd(data, cnt); printf("\r\n"); } /* * Save the data, if it is new, so that we can continue looking * at it if the authorization we try doesn't work */ if (data < _auth_send_data || data > _auth_send_data + sizeof(_auth_send_data)) { auth_send_cnt = cnt > sizeof(_auth_send_data) ? sizeof(_auth_send_data) : cnt; memmove((void *)_auth_send_data, (void *)data, auth_send_cnt); auth_send_data = _auth_send_data; } else { /* * This is probably a no-op, but we just make sure */ auth_send_data = data; auth_send_cnt = cnt; } while ((auth_send_cnt -= 2) >= 0) { if (auth_debug_mode) printf(">>>%s: He supports %d\r\n", Name, *auth_send_data); if ((i_support & ~i_wont_support) & typemask(*auth_send_data)) { ap = findauthenticator(auth_send_data[0], auth_send_data[1]); if (ap && ap->send) { if (auth_debug_mode) printf(">>>%s: Trying %d %d\r\n", Name, auth_send_data[0], auth_send_data[1]); if ((*ap->send)(ap)) { /* * Okay, we found one we like * and did it. * we can go home now. */ if (auth_debug_mode) printf(">>>%s: Using type %d\r\n", Name, *auth_send_data); auth_send_data += 2; return; } } /* else * just continue on and look for the * next one if we didn't do anything. */ } auth_send_data += 2; } net_write(str_none, sizeof(str_none)); printsub('>', &str_none[2], sizeof(str_none) - 2); if (auth_debug_mode) printf(">>>%s: Sent failure message\r\n", Name); auth_finished(0, AUTH_REJECT); #ifdef KANNAN /* * We requested strong authentication, however no mechanisms worked. * Therefore, exit on client end. */ printf("Unable to securely authenticate user ... exit\n"); exit(0); #endif /* KANNAN */ } void auth_send_retry() { /* * if auth_send_cnt <= 0 then auth_send will end up rejecting * the authentication and informing the other side of this. */ auth_send(auth_send_data, auth_send_cnt); } void auth_is(data, cnt) unsigned char *data; int cnt; { Authenticator *ap; if (cnt < 2) return; if (data[0] == AUTHTYPE_NULL) { auth_finished(0, AUTH_REJECT); return; } - if (ap = findauthenticator(data[0], data[1])) { + if ((ap = findauthenticator(data[0], data[1]))) { if (ap->is) (*ap->is)(ap, data+2, cnt-2); } else if (auth_debug_mode) printf(">>>%s: Invalid authentication in IS: %d\r\n", Name, *data); } void auth_reply(data, cnt) unsigned char *data; int cnt; { Authenticator *ap; if (cnt < 2) return; - if (ap = findauthenticator(data[0], data[1])) { + if ((ap = findauthenticator(data[0], data[1]))) { if (ap->reply) (*ap->reply)(ap, data+2, cnt-2); } else if (auth_debug_mode) printf(">>>%s: Invalid authentication in SEND: %d\r\n", Name, *data); } void auth_name(data, cnt) unsigned char *data; int cnt; { - Authenticator *ap; unsigned char savename[256]; if (cnt < 1) { if (auth_debug_mode) printf(">>>%s: Empty name in NAME\r\n", Name); return; } if (cnt > sizeof(savename) - 1) { if (auth_debug_mode) printf(">>>%s: Name in NAME (%d) exceeds %d length\r\n", Name, cnt, sizeof(savename)-1); return; } memmove((void *)savename, (void *)data, cnt); savename[cnt] = '\0'; /* Null terminate */ if (auth_debug_mode) printf(">>>%s: Got NAME [%s]\r\n", Name, savename); auth_encrypt_user(savename); } int auth_sendname(cp, len) unsigned char *cp; int len; { static unsigned char str_request[256+6] = { IAC, SB, TELOPT_AUTHENTICATION, TELQUAL_NAME, }; register unsigned char *e = str_request + 4; register unsigned char *ee = &str_request[sizeof(str_request)-2]; while (--len >= 0) { if ((*e++ = *cp++) == IAC) *e++ = IAC; if (e >= ee) return(0); } *e++ = IAC; *e++ = SE; net_write(str_request, e - str_request); printsub('>', &str_request[2], e - &str_request[2]); return(1); } void auth_finished(ap, result) Authenticator *ap; int result; { if (!(authenticated = ap)) authenticated = &NoAuth; validuser = result; } /* ARGSUSED */ static void auth_intr(sig) int sig; { auth_finished(0, AUTH_REJECT); } int auth_wait(name) char *name; { if (auth_debug_mode) printf(">>>%s: in auth_wait.\r\n", Name); if (Server && !authenticating) return(0); (void) signal(SIGALRM, auth_intr); alarm(30); while (!authenticated) if (telnet_spin()) break; alarm(0); (void) signal(SIGALRM, SIG_DFL); /* * Now check to see if the user is valid or not */ if (!authenticated || authenticated == &NoAuth) return(AUTH_REJECT); if (validuser == AUTH_VALID) validuser = AUTH_USER; if (authenticated->status) validuser = (*authenticated->status)(authenticated, name, validuser); return(validuser); } void auth_debug(mode) int mode; { auth_debug_mode = mode; } void auth_printsub(data, cnt, buf, buflen) unsigned char *data, *buf; int cnt, buflen; { Authenticator *ap; if ((ap = findauthenticator(data[1], data[2])) && ap->printsub) (*ap->printsub)(data, cnt, buf, buflen); else auth_gen_printsub(data, cnt, buf, buflen); } void auth_gen_printsub(data, cnt, buf, buflen) unsigned char *data, *buf; int cnt, buflen; { register unsigned char *cp; unsigned char tbuf[16]; cnt -= 3; data += 3; buf[buflen-1] = '\0'; buf[buflen-2] = '*'; buflen -= 2; for (; cnt > 0; cnt--, data++) { sprintf((char *)tbuf, " %d", *data); for (cp = tbuf; *cp && buflen > 0; --buflen) *buf++ = *cp++; if (buflen <= 0) return; } *buf = '\0'; } #endif diff --git a/contrib/telnet/libtelnet/enc-proto.h b/contrib/telnet/libtelnet/enc-proto.h index 2e30908f292d..8e15ffdab8d1 100644 --- a/contrib/telnet/libtelnet/enc-proto.h +++ b/contrib/telnet/libtelnet/enc-proto.h @@ -1,125 +1,126 @@ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. * * @(#)enc-proto.h 8.1 (Berkeley) 6/4/93 */ /* * Copyright (C) 1990 by the Massachusetts Institute of Technology * * Export of this software from the United States of America is assumed * to require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. */ #if !defined(P) #ifdef __STDC__ #define P(x) x #else #define P(x) () #endif #endif #ifdef ENCRYPTION void encrypt_init P((char *, int)); Encryptions *findencryption P((int)); void encrypt_send_supprt P((void)); void encrypt_auto P((int)); void decrypt_auto P((int)); void encrypt_is P((unsigned char *, int)); void encrypt_reply P((unsigned char *, int)); void encrypt_start_input P((int)); void encrypt_session_key P((Session_Key *, int)); void encrypt_end_input P((void)); void encrypt_start_output P((int)); void encrypt_end_output P((void)); void encrypt_send_request_start P((void)); void encrypt_send_request_end P((void)); void encrypt_send_end P((void)); void encrypt_wait P((void)); void encrypt_send_support P((void)); void encrypt_send_keyid P((int, unsigned char *, int, int)); +void encrypt_start P((unsigned char *, int)); +void encrypt_end P((void)); +void encrypt_support P((unsigned char *, int)); +void encrypt_request_start P((unsigned char *, int)); +void encrypt_request_end P((void)); +void encrypt_enc_keyid P((unsigned char *, int)); +void encrypt_dec_keyid P((unsigned char *, int)); +void encrypt_printsub P((unsigned char *, int, unsigned char *, int)); int net_write P((unsigned char *, int)); -#ifdef TELENTD -void encrypt_wait P((void)); -#else +#ifndef TELENTD int encrypt_cmd P((int, char **)); void encrypt_display P((void)); #endif void krbdes_encrypt P((unsigned char *, int)); int krbdes_decrypt P((int)); int krbdes_is P((unsigned char *, int)); int krbdes_reply P((unsigned char *, int)); void krbdes_init P((int)); int krbdes_start P((int, int)); void krbdes_session P((Session_Key *, int)); void krbdes_printsub P((unsigned char *, int, unsigned char *, int)); void cfb64_encrypt P((unsigned char *, int)); int cfb64_decrypt P((int)); void cfb64_init P((int)); int cfb64_start P((int, int)); int cfb64_is P((unsigned char *, int)); int cfb64_reply P((unsigned char *, int)); void cfb64_session P((Session_Key *, int)); int cfb64_keyid P((int, unsigned char *, int *)); void cfb64_printsub P((unsigned char *, int, unsigned char *, int)); void ofb64_encrypt P((unsigned char *, int)); int ofb64_decrypt P((int)); void ofb64_init P((int)); int ofb64_start P((int, int)); int ofb64_is P((unsigned char *, int)); int ofb64_reply P((unsigned char *, int)); void ofb64_session P((Session_Key *, int)); int ofb64_keyid P((int, unsigned char *, int *)); void ofb64_printsub P((unsigned char *, int, unsigned char *, int)); -int des_new_random_key P((Block)); -void des_set_random_generator_seed P((Block)); -void des_key_sched P((Block, Schedule)); -void des_ecb_encrypt P((Block, Block, Schedule, int)); -int des_string_to_key P((char *, Block)); #endif /* ENCRYPTION */ diff --git a/contrib/telnet/libtelnet/enc_des.c b/contrib/telnet/libtelnet/enc_des.c index d6886fd717d4..8e4b9a7f4b78 100644 --- a/contrib/telnet/libtelnet/enc_des.c +++ b/contrib/telnet/libtelnet/enc_des.c @@ -1,724 +1,720 @@ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. */ #ifndef lint -static char sccsid[] = "@(#)enc_des.c 8.3 (Berkeley) 5/30/95"; +static const char sccsid[] = "@(#)enc_des.c 8.3 (Berkeley) 5/30/95"; #endif /* not lint */ #ifdef ENCRYPTION # ifdef AUTHENTICATION # ifdef DES_ENCRYPTION #include #include #ifdef __STDC__ #include #endif +#include +#include #include "encrypt.h" #include "key-proto.h" #include "misc-proto.h" extern encrypt_debug_mode; #define CFB 0 #define OFB 1 #define NO_SEND_IV 1 #define NO_RECV_IV 2 #define NO_KEYID 4 #define IN_PROGRESS (NO_SEND_IV|NO_RECV_IV|NO_KEYID) #define SUCCESS 0 #define FAILED -1 struct fb { Block krbdes_key; Schedule krbdes_sched; Block temp_feed; unsigned char fb_feed[64]; int need_start; int state[2]; int keyid[2]; int once; struct stinfo { Block str_output; Block str_feed; Block str_iv; Block str_ikey; Schedule str_sched; int str_index; int str_flagshift; } streams[2]; }; static struct fb fb[2]; struct keyidlist { char *keyid; int keyidlen; char *key; int keylen; int flags; } keyidlist [] = { { "\0", 1, 0, 0, 0 }, /* default key of zero */ { 0, 0, 0, 0, 0 } }; #define KEYFLAG_MASK 03 #define KEYFLAG_NOINIT 00 #define KEYFLAG_INIT 01 #define KEYFLAG_OK 02 #define KEYFLAG_BAD 03 #define KEYFLAG_SHIFT 2 #define SHIFT_VAL(a,b) (KEYFLAG_SHIFT*((a)+((b)*2))) #define FB64_IV 1 #define FB64_IV_OK 2 #define FB64_IV_BAD 3 void fb64_stream_iv P((Block, struct stinfo *)); void fb64_init P((struct fb *)); static int fb64_start P((struct fb *, int, int)); int fb64_is P((unsigned char *, int, struct fb *)); int fb64_reply P((unsigned char *, int, struct fb *)); static void fb64_session P((Session_Key *, int, struct fb *)); void fb64_stream_key P((Block, struct stinfo *)); int fb64_keyid P((int, unsigned char *, int *, struct fb *)); void cfb64_init(server) int server; { fb64_init(&fb[CFB]); fb[CFB].fb_feed[4] = ENCTYPE_DES_CFB64; fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, CFB); fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, CFB); } void ofb64_init(server) int server; { fb64_init(&fb[OFB]); fb[OFB].fb_feed[4] = ENCTYPE_DES_OFB64; fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, OFB); fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, OFB); } void fb64_init(fbp) register struct fb *fbp; { memset((void *)fbp, 0, sizeof(*fbp)); fbp->state[0] = fbp->state[1] = FAILED; fbp->fb_feed[0] = IAC; fbp->fb_feed[1] = SB; fbp->fb_feed[2] = TELOPT_ENCRYPT; fbp->fb_feed[3] = ENCRYPT_IS; } /* * Returns: * -1: some error. Negotiation is done, encryption not ready. * 0: Successful, initial negotiation all done. * 1: successful, negotiation not done yet. * 2: Not yet. Other things (like getting the key from * Kerberos) have to happen before we can continue. */ int cfb64_start(dir, server) int dir; int server; { return(fb64_start(&fb[CFB], dir, server)); } int ofb64_start(dir, server) int dir; int server; { return(fb64_start(&fb[OFB], dir, server)); } static int fb64_start(fbp, dir, server) struct fb *fbp; int dir; int server; { - Block b; int x; unsigned char *p; register int state; switch (dir) { case DIR_DECRYPT: /* * This is simply a request to have the other side * start output (our input). He will negotiate an * IV so we need not look for it. */ state = fbp->state[dir-1]; if (state == FAILED) state = IN_PROGRESS; break; case DIR_ENCRYPT: state = fbp->state[dir-1]; if (state == FAILED) state = IN_PROGRESS; else if ((state & NO_SEND_IV) == 0) break; if (!VALIDKEY(fbp->krbdes_key)) { fbp->need_start = 1; break; } state &= ~NO_SEND_IV; state |= NO_RECV_IV; if (encrypt_debug_mode) printf("Creating new feed\r\n"); /* * Create a random feed and send it over. */ - des_new_random_key(fbp->temp_feed); - des_ecb_encrypt(fbp->temp_feed, fbp->temp_feed, + des_new_random_key((Block *)fbp->temp_feed); + des_ecb_encrypt((Block *)fbp->temp_feed, (Block *)fbp->temp_feed, fbp->krbdes_sched, 1); p = fbp->fb_feed + 3; *p++ = ENCRYPT_IS; p++; *p++ = FB64_IV; for (x = 0; x < sizeof(Block); ++x) { if ((*p++ = fbp->temp_feed[x]) == IAC) *p++ = IAC; } *p++ = IAC; *p++ = SE; printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]); net_write(fbp->fb_feed, p - fbp->fb_feed); break; default: return(FAILED); } return(fbp->state[dir-1] = state); } /* * Returns: * -1: some error. Negotiation is done, encryption not ready. * 0: Successful, initial negotiation all done. * 1: successful, negotiation not done yet. */ int cfb64_is(data, cnt) unsigned char *data; int cnt; { return(fb64_is(data, cnt, &fb[CFB])); } int ofb64_is(data, cnt) unsigned char *data; int cnt; { return(fb64_is(data, cnt, &fb[OFB])); } int fb64_is(data, cnt, fbp) unsigned char *data; int cnt; struct fb *fbp; { - int x; unsigned char *p; - Block b; register int state = fbp->state[DIR_DECRYPT-1]; if (cnt-- < 1) goto failure; switch (*data++) { case FB64_IV: if (cnt != sizeof(Block)) { if (encrypt_debug_mode) printf("CFB64: initial vector failed on size\r\n"); state = FAILED; goto failure; } if (encrypt_debug_mode) printf("CFB64: initial vector received\r\n"); if (encrypt_debug_mode) printf("Initializing Decrypt stream\r\n"); fb64_stream_iv((void *)data, &fbp->streams[DIR_DECRYPT-1]); p = fbp->fb_feed + 3; *p++ = ENCRYPT_REPLY; p++; *p++ = FB64_IV_OK; *p++ = IAC; *p++ = SE; printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]); net_write(fbp->fb_feed, p - fbp->fb_feed); state = fbp->state[DIR_DECRYPT-1] = IN_PROGRESS; break; default: if (encrypt_debug_mode) { printf("Unknown option type: %d\r\n", *(data-1)); printd(data, cnt); printf("\r\n"); } /* FALL THROUGH */ failure: /* * We failed. Send an FB64_IV_BAD option * to the other side so it will know that * things failed. */ p = fbp->fb_feed + 3; *p++ = ENCRYPT_REPLY; p++; *p++ = FB64_IV_BAD; *p++ = IAC; *p++ = SE; printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]); net_write(fbp->fb_feed, p - fbp->fb_feed); break; } return(fbp->state[DIR_DECRYPT-1] = state); } /* * Returns: * -1: some error. Negotiation is done, encryption not ready. * 0: Successful, initial negotiation all done. * 1: successful, negotiation not done yet. */ int cfb64_reply(data, cnt) unsigned char *data; int cnt; { return(fb64_reply(data, cnt, &fb[CFB])); } int ofb64_reply(data, cnt) unsigned char *data; int cnt; { return(fb64_reply(data, cnt, &fb[OFB])); } int fb64_reply(data, cnt, fbp) unsigned char *data; int cnt; struct fb *fbp; { - int x; - unsigned char *p; - Block b; register int state = fbp->state[DIR_ENCRYPT-1]; if (cnt-- < 1) goto failure; switch (*data++) { case FB64_IV_OK: fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]); if (state == FAILED) state = IN_PROGRESS; state &= ~NO_RECV_IV; encrypt_send_keyid(DIR_ENCRYPT, (unsigned char *)"\0", 1, 1); break; case FB64_IV_BAD: memset(fbp->temp_feed, 0, sizeof(Block)); fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]); state = FAILED; break; default: if (encrypt_debug_mode) { printf("Unknown option type: %d\r\n", data[-1]); printd(data, cnt); printf("\r\n"); } /* FALL THROUGH */ failure: state = FAILED; break; } return(fbp->state[DIR_ENCRYPT-1] = state); } void cfb64_session(key, server) Session_Key *key; int server; { fb64_session(key, server, &fb[CFB]); } void ofb64_session(key, server) Session_Key *key; int server; { fb64_session(key, server, &fb[OFB]); } static void fb64_session(key, server, fbp) Session_Key *key; int server; struct fb *fbp; { if (!key || key->type != SK_DES) { if (encrypt_debug_mode) printf("Can't set krbdes's session key (%d != %d)\r\n", key ? key->type : -1, SK_DES); return; } memmove((void *)fbp->krbdes_key, (void *)key->data, sizeof(Block)); fb64_stream_key(fbp->krbdes_key, &fbp->streams[DIR_ENCRYPT-1]); fb64_stream_key(fbp->krbdes_key, &fbp->streams[DIR_DECRYPT-1]); if (fbp->once == 0) { - des_set_random_generator_seed(fbp->krbdes_key); + des_set_random_generator_seed((Block *)fbp->krbdes_key); fbp->once = 1; } - des_key_sched(fbp->krbdes_key, fbp->krbdes_sched); + des_key_sched((Block *)fbp->krbdes_key, fbp->krbdes_sched); /* * Now look to see if krbdes_start() was was waiting for * the key to show up. If so, go ahead an call it now * that we have the key. */ if (fbp->need_start) { fbp->need_start = 0; fb64_start(fbp, DIR_ENCRYPT, server); } } /* * We only accept a keyid of 0. If we get a keyid of * 0, then mark the state as SUCCESS. */ int cfb64_keyid(dir, kp, lenp) int dir, *lenp; unsigned char *kp; { return(fb64_keyid(dir, kp, lenp, &fb[CFB])); } int ofb64_keyid(dir, kp, lenp) int dir, *lenp; unsigned char *kp; { return(fb64_keyid(dir, kp, lenp, &fb[OFB])); } int fb64_keyid(dir, kp, lenp, fbp) int dir, *lenp; unsigned char *kp; struct fb *fbp; { register int state = fbp->state[dir-1]; if (*lenp != 1 || (*kp != '\0')) { *lenp = 0; return(state); } if (state == FAILED) state = IN_PROGRESS; state &= ~NO_KEYID; return(fbp->state[dir-1] = state); } void fb64_printsub(data, cnt, buf, buflen, type) unsigned char *data, *buf, *type; int cnt, buflen; { char lbuf[32]; register int i; char *cp; buf[buflen-1] = '\0'; /* make sure it's NULL terminated */ buflen -= 1; switch(data[2]) { case FB64_IV: sprintf(lbuf, "%s_IV", type); cp = lbuf; goto common; case FB64_IV_OK: sprintf(lbuf, "%s_IV_OK", type); cp = lbuf; goto common; case FB64_IV_BAD: sprintf(lbuf, "%s_IV_BAD", type); cp = lbuf; goto common; default: sprintf(lbuf, " %d (unknown)", data[2]); cp = lbuf; common: for (; (buflen > 0) && (*buf = *cp++); buf++) buflen--; for (i = 3; i < cnt; i++) { sprintf(lbuf, " %d", data[i]); for (cp = lbuf; (buflen > 0) && (*buf = *cp++); buf++) buflen--; } break; } } void cfb64_printsub(data, cnt, buf, buflen) unsigned char *data, *buf; int cnt, buflen; { fb64_printsub(data, cnt, buf, buflen, "CFB64"); } void ofb64_printsub(data, cnt, buf, buflen) unsigned char *data, *buf; int cnt, buflen; { fb64_printsub(data, cnt, buf, buflen, "OFB64"); } void fb64_stream_iv(seed, stp) Block seed; register struct stinfo *stp; { memmove((void *)stp->str_iv, (void *)seed, sizeof(Block)); memmove((void *)stp->str_output, (void *)seed, sizeof(Block)); - des_key_sched(stp->str_ikey, stp->str_sched); + des_key_sched((Block *)stp->str_ikey, stp->str_sched); stp->str_index = sizeof(Block); } void fb64_stream_key(key, stp) Block key; register struct stinfo *stp; { memmove((void *)stp->str_ikey, (void *)key, sizeof(Block)); - des_key_sched(key, stp->str_sched); + des_key_sched((Block *)key, stp->str_sched); memmove((void *)stp->str_output, (void *)stp->str_iv, sizeof(Block)); stp->str_index = sizeof(Block); } /* * DES 64 bit Cipher Feedback * * key --->+-----+ * +->| DES |--+ * | +-----+ | * | v * INPUT --(--------->(+)+---> DATA * | | * +-------------+ * * * Given: * iV: Initial vector, 64 bits (8 bytes) long. * Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt). * On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output. * * V0 = DES(iV, key) * On = Dn ^ Vn * V(n+1) = DES(On, key) */ void cfb64_encrypt(s, c) register unsigned char *s; int c; { register struct stinfo *stp = &fb[CFB].streams[DIR_ENCRYPT-1]; register int index; index = stp->str_index; while (c-- > 0) { if (index == sizeof(Block)) { Block b; - des_ecb_encrypt(stp->str_output, b, stp->str_sched, 1); + des_ecb_encrypt((Block *)stp->str_output, (Block *)b, stp->str_sched, 1); memmove((void *)stp->str_feed, (void *)b, sizeof(Block)); index = 0; } /* On encryption, we store (feed ^ data) which is cypher */ *s = stp->str_output[index] = (stp->str_feed[index] ^ *s); s++; index++; } stp->str_index = index; } int cfb64_decrypt(data) int data; { register struct stinfo *stp = &fb[CFB].streams[DIR_DECRYPT-1]; int index; if (data == -1) { /* * Back up one byte. It is assumed that we will * never back up more than one byte. If we do, this * may or may not work. */ if (stp->str_index) --stp->str_index; return(0); } index = stp->str_index++; if (index == sizeof(Block)) { Block b; - des_ecb_encrypt(stp->str_output, b, stp->str_sched, 1); + des_ecb_encrypt((Block *)stp->str_output, (Block *)b, stp->str_sched, 1); memmove((void *)stp->str_feed, (void *)b, sizeof(Block)); stp->str_index = 1; /* Next time will be 1 */ index = 0; /* But now use 0 */ } /* On decryption we store (data) which is cypher. */ stp->str_output[index] = data; return(data ^ stp->str_feed[index]); } /* * DES 64 bit Output Feedback * * key --->+-----+ * +->| DES |--+ * | +-----+ | * +-----------+ * v * INPUT -------->(+) ----> DATA * * Given: * iV: Initial vector, 64 bits (8 bytes) long. * Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt). * On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output. * * V0 = DES(iV, key) * V(n+1) = DES(Vn, key) * On = Dn ^ Vn */ void ofb64_encrypt(s, c) register unsigned char *s; int c; { register struct stinfo *stp = &fb[OFB].streams[DIR_ENCRYPT-1]; register int index; index = stp->str_index; while (c-- > 0) { if (index == sizeof(Block)) { Block b; - des_ecb_encrypt(stp->str_feed, b, stp->str_sched, 1); + des_ecb_encrypt((Block *)stp->str_feed, (Block *)b, stp->str_sched, 1); memmove((void *)stp->str_feed, (void *)b, sizeof(Block)); index = 0; } *s++ ^= stp->str_feed[index]; index++; } stp->str_index = index; } int ofb64_decrypt(data) int data; { register struct stinfo *stp = &fb[OFB].streams[DIR_DECRYPT-1]; int index; if (data == -1) { /* * Back up one byte. It is assumed that we will * never back up more than one byte. If we do, this * may or may not work. */ if (stp->str_index) --stp->str_index; return(0); } index = stp->str_index++; if (index == sizeof(Block)) { Block b; - des_ecb_encrypt(stp->str_feed, b, stp->str_sched, 1); + des_ecb_encrypt((Block *)stp->str_feed, (Block *)b, stp->str_sched, 1); memmove((void *)stp->str_feed, (void *)b, sizeof(Block)); stp->str_index = 1; /* Next time will be 1 */ index = 0; /* But now use 0 */ } return(data ^ stp->str_feed[index]); } # endif /* DES_ENCRYPTION */ # endif /* AUTHENTICATION */ #endif /* ENCRYPTION */ diff --git a/contrib/telnet/libtelnet/encrypt.c b/contrib/telnet/libtelnet/encrypt.c index 432df0cbb333..41dd5cc71044 100644 --- a/contrib/telnet/libtelnet/encrypt.c +++ b/contrib/telnet/libtelnet/encrypt.c @@ -1,1000 +1,1016 @@ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. */ #ifndef lint -static char sccsid[] = "@(#)encrypt.c 8.2 (Berkeley) 5/30/95"; +static const char sccsid[] = "@(#)encrypt.c 8.2 (Berkeley) 5/30/95"; #endif /* not lint */ /* * Copyright (C) 1990 by the Massachusetts Institute of Technology * * Export of this software from the United States of America is assumed * to require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. */ #ifdef ENCRYPTION #define ENCRYPT_NAMES +#include #include #include "encrypt.h" #include "misc.h" #ifdef __STDC__ #include #endif #ifdef NO_STRING_H #include #else #include #endif /* * These functions pointers point to the current routines * for encrypting and decrypting data. */ void (*encrypt_output) P((unsigned char *, int)); int (*decrypt_input) P((int)); +int EncryptType(char *type, char *mode); +int EncryptStart(char *mode); +int EncryptStop(char *mode); +int EncryptStartInput(void); +int EncryptStartOutput(void); +int EncryptStopInput(void); +int EncryptStopOutput(void); + +int Ambiguous(char **s); +int isprefix(char *s1, char *s2); +char **genget(char *name, char **table, int stlen); + int encrypt_debug_mode = 0; static int decrypt_mode = 0; static int encrypt_mode = 0; static int encrypt_verbose = 0; static int autoencrypt = 0; static int autodecrypt = 0; static int havesessionkey = 0; static int Server = 0; static char *Name = "Noname"; #define typemask(x) ((x) > 0 ? 1 << ((x)-1) : 0) static long i_support_encrypt = typemask(ENCTYPE_DES_CFB64) | typemask(ENCTYPE_DES_OFB64); static long i_support_decrypt = typemask(ENCTYPE_DES_CFB64) | typemask(ENCTYPE_DES_OFB64); static long i_wont_support_encrypt = 0; static long i_wont_support_decrypt = 0; #define I_SUPPORT_ENCRYPT (i_support_encrypt & ~i_wont_support_encrypt) #define I_SUPPORT_DECRYPT (i_support_decrypt & ~i_wont_support_decrypt) static long remote_supports_encrypt = 0; static long remote_supports_decrypt = 0; static Encryptions encryptions[] = { #ifdef DES_ENCRYPTION { "DES_CFB64", ENCTYPE_DES_CFB64, cfb64_encrypt, cfb64_decrypt, cfb64_init, cfb64_start, cfb64_is, cfb64_reply, cfb64_session, cfb64_keyid, cfb64_printsub }, { "DES_OFB64", ENCTYPE_DES_OFB64, ofb64_encrypt, ofb64_decrypt, ofb64_init, ofb64_start, ofb64_is, ofb64_reply, ofb64_session, ofb64_keyid, ofb64_printsub }, #endif /* DES_ENCRYPTION */ { 0, }, }; static unsigned char str_send[64] = { IAC, SB, TELOPT_ENCRYPT, ENCRYPT_SUPPORT }; static unsigned char str_suplen = 0; static unsigned char str_start[72] = { IAC, SB, TELOPT_ENCRYPT }; static unsigned char str_end[] = { IAC, SB, TELOPT_ENCRYPT, 0, IAC, SE }; Encryptions * findencryption(type) int type; { Encryptions *ep = encryptions; if (!(I_SUPPORT_ENCRYPT & remote_supports_decrypt & typemask(type))) return(0); while (ep->type && ep->type != type) ++ep; return(ep->type ? ep : 0); } Encryptions * finddecryption(type) int type; { Encryptions *ep = encryptions; if (!(I_SUPPORT_DECRYPT & remote_supports_encrypt & typemask(type))) return(0); while (ep->type && ep->type != type) ++ep; return(ep->type ? ep : 0); } #define MAXKEYLEN 64 static struct key_info { unsigned char keyid[MAXKEYLEN]; int keylen; int dir; int *modep; Encryptions *(*getcrypt)(); } ki[2] = { { { 0 }, 0, DIR_ENCRYPT, &encrypt_mode, findencryption }, { { 0 }, 0, DIR_DECRYPT, &decrypt_mode, finddecryption }, }; +static void encrypt_keyid(struct key_info *kp, unsigned char *keyid, int len); + void encrypt_init(name, server) char *name; int server; { Encryptions *ep = encryptions; Name = name; Server = server; i_support_encrypt = i_support_decrypt = 0; remote_supports_encrypt = remote_supports_decrypt = 0; encrypt_mode = 0; decrypt_mode = 0; encrypt_output = 0; decrypt_input = 0; #ifdef notdef encrypt_verbose = !server; #endif str_suplen = 4; while (ep->type) { if (encrypt_debug_mode) printf(">>>%s: I will support %s\r\n", Name, ENCTYPE_NAME(ep->type)); i_support_encrypt |= typemask(ep->type); i_support_decrypt |= typemask(ep->type); if ((i_wont_support_decrypt & typemask(ep->type)) == 0) if ((str_send[str_suplen++] = ep->type) == IAC) str_send[str_suplen++] = IAC; if (ep->init) (*ep->init)(Server); ++ep; } str_send[str_suplen++] = IAC; str_send[str_suplen++] = SE; } void encrypt_list_types() { Encryptions *ep = encryptions; printf("Valid encryption types:\n"); while (ep->type) { printf("\t%s (%d)\r\n", ENCTYPE_NAME(ep->type), ep->type); ++ep; } } int EncryptEnable(type, mode) char *type, *mode; { if (isprefix(type, "help") || isprefix(type, "?")) { printf("Usage: encrypt enable [input|output]\n"); encrypt_list_types(); return(0); } if (EncryptType(type, mode)) return(EncryptStart(mode)); return(0); } int EncryptDisable(type, mode) char *type, *mode; { register Encryptions *ep; int ret = 0; if (isprefix(type, "help") || isprefix(type, "?")) { printf("Usage: encrypt disable [input|output]\n"); encrypt_list_types(); - } else if ((ep = (Encryptions *)genget(type, encryptions, + } else if ((ep = (Encryptions *)genget(type, (char **)encryptions, sizeof(Encryptions))) == 0) { printf("%s: invalid encryption type\n", type); - } else if (Ambiguous(ep)) { + } else if (Ambiguous((char **)ep)) { printf("Ambiguous type '%s'\n", type); } else { if ((mode == 0) || (isprefix(mode, "input") ? 1 : 0)) { if (decrypt_mode == ep->type) EncryptStopInput(); i_wont_support_decrypt |= typemask(ep->type); ret = 1; } if ((mode == 0) || (isprefix(mode, "output"))) { if (encrypt_mode == ep->type) EncryptStopOutput(); i_wont_support_encrypt |= typemask(ep->type); ret = 1; } if (ret == 0) printf("%s: invalid encryption mode\n", mode); } return(ret); } int EncryptType(type, mode) char *type; char *mode; { register Encryptions *ep; int ret = 0; if (isprefix(type, "help") || isprefix(type, "?")) { printf("Usage: encrypt type [input|output]\n"); encrypt_list_types(); - } else if ((ep = (Encryptions *)genget(type, encryptions, + } else if ((ep = (Encryptions *)genget(type, (char **)encryptions, sizeof(Encryptions))) == 0) { printf("%s: invalid encryption type\n", type); - } else if (Ambiguous(ep)) { + } else if (Ambiguous((char **)ep)) { printf("Ambiguous type '%s'\n", type); } else { if ((mode == 0) || isprefix(mode, "input")) { decrypt_mode = ep->type; i_wont_support_decrypt &= ~typemask(ep->type); ret = 1; } if ((mode == 0) || isprefix(mode, "output")) { encrypt_mode = ep->type; i_wont_support_encrypt &= ~typemask(ep->type); ret = 1; } if (ret == 0) printf("%s: invalid encryption mode\n", mode); } return(ret); } int EncryptStart(mode) char *mode; { register int ret = 0; if (mode) { if (isprefix(mode, "input")) return(EncryptStartInput()); if (isprefix(mode, "output")) return(EncryptStartOutput()); if (isprefix(mode, "help") || isprefix(mode, "?")) { printf("Usage: encrypt start [input|output]\n"); return(0); } printf("%s: invalid encryption mode 'encrypt start ?' for help\n", mode); return(0); } ret += EncryptStartInput(); ret += EncryptStartOutput(); return(ret); } int EncryptStartInput() { if (decrypt_mode) { encrypt_send_request_start(); return(1); } printf("No previous decryption mode, decryption not enabled\r\n"); return(0); } int EncryptStartOutput() { if (encrypt_mode) { encrypt_start_output(encrypt_mode); return(1); } printf("No previous encryption mode, encryption not enabled\r\n"); return(0); } int EncryptStop(mode) char *mode; { int ret = 0; if (mode) { if (isprefix(mode, "input")) return(EncryptStopInput()); if (isprefix(mode, "output")) return(EncryptStopOutput()); if (isprefix(mode, "help") || isprefix(mode, "?")) { printf("Usage: encrypt stop [input|output]\n"); return(0); } printf("%s: invalid encryption mode 'encrypt stop ?' for help\n", mode); return(0); } ret += EncryptStopInput(); ret += EncryptStopOutput(); return(ret); } int EncryptStopInput() { encrypt_send_request_end(); return(1); } int EncryptStopOutput() { encrypt_send_end(); return(1); } void encrypt_display() { if (encrypt_output) printf("Currently encrypting output with %s\r\n", ENCTYPE_NAME(encrypt_mode)); if (decrypt_input) printf("Currently decrypting input with %s\r\n", ENCTYPE_NAME(decrypt_mode)); } int EncryptStatus() { if (encrypt_output) printf("Currently encrypting output with %s\r\n", ENCTYPE_NAME(encrypt_mode)); else if (encrypt_mode) { printf("Currently output is clear text.\r\n"); printf("Last encryption mode was %s\r\n", ENCTYPE_NAME(encrypt_mode)); } if (decrypt_input) { printf("Currently decrypting input with %s\r\n", ENCTYPE_NAME(decrypt_mode)); } else if (decrypt_mode) { printf("Currently input is clear text.\r\n"); printf("Last decryption mode was %s\r\n", ENCTYPE_NAME(decrypt_mode)); } return 1; } void encrypt_send_support() { if (str_suplen) { /* * If the user has requested that decryption start * immediatly, then send a "REQUEST START" before * we negotiate the type. */ if (!Server && autodecrypt) encrypt_send_request_start(); net_write(str_send, str_suplen); printsub('>', &str_send[2], str_suplen - 2); str_suplen = 0; } } int EncryptDebug(on) int on; { if (on < 0) encrypt_debug_mode ^= 1; else encrypt_debug_mode = on; printf("Encryption debugging %s\r\n", encrypt_debug_mode ? "enabled" : "disabled"); return(1); } int EncryptVerbose(on) int on; { if (on < 0) encrypt_verbose ^= 1; else encrypt_verbose = on; printf("Encryption %s verbose\r\n", encrypt_verbose ? "is" : "is not"); return(1); } int EncryptAutoEnc(on) int on; { encrypt_auto(on); printf("Automatic encryption of output is %s\r\n", autoencrypt ? "enabled" : "disabled"); return(1); } int EncryptAutoDec(on) int on; { decrypt_auto(on); printf("Automatic decryption of input is %s\r\n", autodecrypt ? "enabled" : "disabled"); return(1); } /* * Called when ENCRYPT SUPPORT is received. */ void encrypt_support(typelist, cnt) unsigned char *typelist; int cnt; { register int type, use_type = 0; Encryptions *ep; /* * Forget anything the other side has previously told us. */ remote_supports_decrypt = 0; while (cnt-- > 0) { type = *typelist++; if (encrypt_debug_mode) printf(">>>%s: He is supporting %s (%d)\r\n", Name, ENCTYPE_NAME(type), type); if ((type < ENCTYPE_CNT) && (I_SUPPORT_ENCRYPT & typemask(type))) { remote_supports_decrypt |= typemask(type); if (use_type == 0) use_type = type; } } if (use_type) { ep = findencryption(use_type); if (!ep) return; type = ep->start ? (*ep->start)(DIR_ENCRYPT, Server) : 0; if (encrypt_debug_mode) printf(">>>%s: (*ep->start)() returned %d\r\n", Name, type); if (type < 0) return; encrypt_mode = use_type; if (type == 0) encrypt_start_output(use_type); } } void encrypt_is(data, cnt) unsigned char *data; int cnt; { Encryptions *ep; register int type, ret; if (--cnt < 0) return; type = *data++; if (type < ENCTYPE_CNT) remote_supports_encrypt |= typemask(type); if (!(ep = finddecryption(type))) { if (encrypt_debug_mode) printf(">>>%s: Can't find type %s (%d) for initial negotiation\r\n", Name, ENCTYPE_NAME_OK(type) ? ENCTYPE_NAME(type) : "(unknown)", type); return; } if (!ep->is) { if (encrypt_debug_mode) printf(">>>%s: No initial negotiation needed for type %s (%d)\r\n", Name, ENCTYPE_NAME_OK(type) ? ENCTYPE_NAME(type) : "(unknown)", type); ret = 0; } else { ret = (*ep->is)(data, cnt); if (encrypt_debug_mode) - printf("(*ep->is)(%x, %d) returned %s(%d)\n", data, cnt, + printf("(*ep->is)(%p, %d) returned %s(%d)\n", data, cnt, (ret < 0) ? "FAIL " : (ret == 0) ? "SUCCESS " : "MORE_TO_DO ", ret); } if (ret < 0) { autodecrypt = 0; } else { decrypt_mode = type; if (ret == 0 && autodecrypt) encrypt_send_request_start(); } } void encrypt_reply(data, cnt) unsigned char *data; int cnt; { Encryptions *ep; register int ret, type; if (--cnt < 0) return; type = *data++; if (!(ep = findencryption(type))) { if (encrypt_debug_mode) printf(">>>%s: Can't find type %s (%d) for initial negotiation\r\n", Name, ENCTYPE_NAME_OK(type) ? ENCTYPE_NAME(type) : "(unknown)", type); return; } if (!ep->reply) { if (encrypt_debug_mode) printf(">>>%s: No initial negotiation needed for type %s (%d)\r\n", Name, ENCTYPE_NAME_OK(type) ? ENCTYPE_NAME(type) : "(unknown)", type); ret = 0; } else { ret = (*ep->reply)(data, cnt); if (encrypt_debug_mode) - printf("(*ep->reply)(%x, %d) returned %s(%d)\n", + printf("(*ep->reply)(%p, %d) returned %s(%d)\n", data, cnt, (ret < 0) ? "FAIL " : (ret == 0) ? "SUCCESS " : "MORE_TO_DO ", ret); } if (encrypt_debug_mode) printf(">>>%s: encrypt_reply returned %d\n", Name, ret); if (ret < 0) { autoencrypt = 0; } else { encrypt_mode = type; if (ret == 0 && autoencrypt) encrypt_start_output(type); } } /* * Called when a ENCRYPT START command is received. */ void encrypt_start(data, cnt) unsigned char *data; int cnt; { Encryptions *ep; if (!decrypt_mode) { /* * Something is wrong. We should not get a START * command without having already picked our * decryption scheme. Send a REQUEST-END to * attempt to clear the channel... */ printf("%s: Warning, Cannot decrypt input stream!!!\r\n", Name); encrypt_send_request_end(); return; } - if (ep = finddecryption(decrypt_mode)) { + if ((ep = finddecryption(decrypt_mode))) { decrypt_input = ep->input; if (encrypt_verbose) printf("[ Input is now decrypted with type %s ]\r\n", ENCTYPE_NAME(decrypt_mode)); if (encrypt_debug_mode) printf(">>>%s: Start to decrypt input with type %s\r\n", Name, ENCTYPE_NAME(decrypt_mode)); } else { printf("%s: Warning, Cannot decrypt type %s (%d)!!!\r\n", Name, ENCTYPE_NAME_OK(decrypt_mode) ? ENCTYPE_NAME(decrypt_mode) : "(unknown)", decrypt_mode); encrypt_send_request_end(); } } void encrypt_session_key(key, server) Session_Key *key; int server; { Encryptions *ep = encryptions; havesessionkey = 1; while (ep->type) { if (ep->session) (*ep->session)(key, server); #ifdef notdef if (!encrypt_output && autoencrypt && !server) encrypt_start_output(ep->type); if (!decrypt_input && autodecrypt && !server) encrypt_send_request_start(); #endif ++ep; } } /* * Called when ENCRYPT END is received. */ void encrypt_end() { decrypt_input = 0; if (encrypt_debug_mode) printf(">>>%s: Input is back to clear text\r\n", Name); if (encrypt_verbose) printf("[ Input is now clear text ]\r\n"); } /* * Called when ENCRYPT REQUEST-END is received. */ void encrypt_request_end() { encrypt_send_end(); } /* * Called when ENCRYPT REQUEST-START is received. If we receive * this before a type is picked, then that indicates that the * other side wants us to start encrypting data as soon as we * can. */ void encrypt_request_start(data, cnt) unsigned char *data; int cnt; { if (encrypt_mode == 0) { if (Server) autoencrypt = 1; return; } encrypt_start_output(encrypt_mode); } static unsigned char str_keyid[(MAXKEYLEN*2)+5] = { IAC, SB, TELOPT_ENCRYPT }; + void encrypt_enc_keyid(keyid, len) unsigned char *keyid; int len; { encrypt_keyid(&ki[1], keyid, len); } + void encrypt_dec_keyid(keyid, len) unsigned char *keyid; int len; { encrypt_keyid(&ki[0], keyid, len); } + void encrypt_keyid(kp, keyid, len) struct key_info *kp; unsigned char *keyid; int len; { Encryptions *ep; - unsigned char *strp, *cp; int dir = kp->dir; register int ret = 0; if (!(ep = (*kp->getcrypt)(*kp->modep))) { if (len == 0) return; kp->keylen = 0; } else if (len == 0) { /* * Empty option, indicates a failure. */ if (kp->keylen == 0) return; kp->keylen = 0; if (ep->keyid) (void)(*ep->keyid)(dir, kp->keyid, &kp->keylen); } else if ((len != kp->keylen) || (memcmp(keyid, kp->keyid, len) != 0)) { /* * Length or contents are different */ kp->keylen = len; memmove(kp->keyid, keyid, len); if (ep->keyid) (void)(*ep->keyid)(dir, kp->keyid, &kp->keylen); } else { if (ep->keyid) ret = (*ep->keyid)(dir, kp->keyid, &kp->keylen); if ((ret == 0) && (dir == DIR_ENCRYPT) && autoencrypt) encrypt_start_output(*kp->modep); return; } encrypt_send_keyid(dir, kp->keyid, kp->keylen, 0); } void encrypt_send_keyid(dir, keyid, keylen, saveit) int dir; unsigned char *keyid; int keylen; int saveit; { unsigned char *strp; str_keyid[3] = (dir == DIR_ENCRYPT) ? ENCRYPT_ENC_KEYID : ENCRYPT_DEC_KEYID; if (saveit) { struct key_info *kp = &ki[(dir == DIR_ENCRYPT) ? 0 : 1]; memmove(kp->keyid, keyid, keylen); kp->keylen = keylen; } for (strp = &str_keyid[4]; keylen > 0; --keylen) { if ((*strp++ = *keyid++) == IAC) *strp++ = IAC; } *strp++ = IAC; *strp++ = SE; net_write(str_keyid, strp - str_keyid); printsub('>', &str_keyid[2], strp - str_keyid - 2); } void encrypt_auto(on) int on; { if (on < 0) autoencrypt ^= 1; else autoencrypt = on ? 1 : 0; } void decrypt_auto(on) int on; { if (on < 0) autodecrypt ^= 1; else autodecrypt = on ? 1 : 0; } void encrypt_start_output(type) int type; { Encryptions *ep; register unsigned char *p; register int i; if (!(ep = findencryption(type))) { if (encrypt_debug_mode) { printf(">>>%s: Can't encrypt with type %s (%d)\r\n", Name, ENCTYPE_NAME_OK(type) ? ENCTYPE_NAME(type) : "(unknown)", type); } return; } if (ep->start) { i = (*ep->start)(DIR_ENCRYPT, Server); if (encrypt_debug_mode) { printf(">>>%s: Encrypt start: %s (%d) %s\r\n", Name, (i < 0) ? "failed" : "initial negotiation in progress", i, ENCTYPE_NAME(type)); } if (i) return; } p = str_start + 3; *p++ = ENCRYPT_START; for (i = 0; i < ki[0].keylen; ++i) { if ((*p++ = ki[0].keyid[i]) == IAC) *p++ = IAC; } *p++ = IAC; *p++ = SE; net_write(str_start, p - str_start); net_encrypt(); printsub('>', &str_start[2], p - &str_start[2]); /* * If we are already encrypting in some mode, then * encrypt the ring (which includes our request) in * the old mode, mark it all as "clear text" and then * switch to the new mode. */ encrypt_output = ep->output; encrypt_mode = type; if (encrypt_debug_mode) printf(">>>%s: Started to encrypt output with type %s\r\n", Name, ENCTYPE_NAME(type)); if (encrypt_verbose) printf("[ Output is now encrypted with type %s ]\r\n", ENCTYPE_NAME(type)); } void encrypt_send_end() { if (!encrypt_output) return; str_end[3] = ENCRYPT_END; net_write(str_end, sizeof(str_end)); net_encrypt(); printsub('>', &str_end[2], sizeof(str_end) - 2); /* * Encrypt the output buffer now because it will not be done by * netflush... */ encrypt_output = 0; if (encrypt_debug_mode) printf(">>>%s: Output is back to clear text\r\n", Name); if (encrypt_verbose) printf("[ Output is now clear text ]\r\n"); } void encrypt_send_request_start() { register unsigned char *p; register int i; p = &str_start[3]; *p++ = ENCRYPT_REQSTART; for (i = 0; i < ki[1].keylen; ++i) { if ((*p++ = ki[1].keyid[i]) == IAC) *p++ = IAC; } *p++ = IAC; *p++ = SE; net_write(str_start, p - str_start); printsub('>', &str_start[2], p - &str_start[2]); if (encrypt_debug_mode) printf(">>>%s: Request input to be encrypted\r\n", Name); } void encrypt_send_request_end() { str_end[3] = ENCRYPT_REQEND; net_write(str_end, sizeof(str_end)); printsub('>', &str_end[2], sizeof(str_end) - 2); if (encrypt_debug_mode) printf(">>>%s: Request input to be clear text\r\n", Name); } void encrypt_wait() { - register int encrypt, decrypt; if (encrypt_debug_mode) printf(">>>%s: in encrypt_wait\r\n", Name); if (!havesessionkey || !(I_SUPPORT_ENCRYPT & remote_supports_decrypt)) return; while (autoencrypt && !encrypt_output) if (telnet_spin()) return; } void encrypt_debug(mode) int mode; { encrypt_debug_mode = mode; } void encrypt_gen_printsub(data, cnt, buf, buflen) unsigned char *data, *buf; int cnt, buflen; { char tbuf[16], *cp; cnt -= 2; data += 2; buf[buflen-1] = '\0'; buf[buflen-2] = '*'; buflen -= 2;; for (; cnt > 0; cnt--, data++) { sprintf(tbuf, " %d", *data); for (cp = tbuf; *cp && buflen > 0; --buflen) *buf++ = *cp++; if (buflen <= 0) return; } *buf = '\0'; } void encrypt_printsub(data, cnt, buf, buflen) unsigned char *data, *buf; int cnt, buflen; { Encryptions *ep; register int type = data[1]; for (ep = encryptions; ep->type && ep->type != type; ep++) ; if (ep->printsub) (*ep->printsub)(data, cnt, buf, buflen); else encrypt_gen_printsub(data, cnt, buf, buflen); } #endif /* ENCRYPTION */ diff --git a/contrib/telnet/libtelnet/encrypt.h b/contrib/telnet/libtelnet/encrypt.h index e0ae385f13f3..1c942dc6e7e8 100644 --- a/contrib/telnet/libtelnet/encrypt.h +++ b/contrib/telnet/libtelnet/encrypt.h @@ -1,108 +1,108 @@ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. * * @(#)encrypt.h 8.1 (Berkeley) 6/4/93 */ /* * Copyright (C) 1990 by the Massachusetts Institute of Technology * * Export of this software from the United States of America is assumed * to require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. */ #ifdef ENCRYPTION # ifndef __ENCRYPTION__ # define __ENCRYPTION__ #define DIR_DECRYPT 1 #define DIR_ENCRYPT 2 typedef unsigned char Block[8]; typedef unsigned char *BlockT; -typedef struct { Block _; } Schedule[16]; +typedef struct { Block __; } Schedule[16]; #define VALIDKEY(key) ( key[0] | key[1] | key[2] | key[3] | \ key[4] | key[5] | key[6] | key[7]) #define SAMEKEY(k1, k2) (!bcmp((void *)k1, (void *)k2, sizeof(Block))) typedef struct { short type; int length; unsigned char *data; } Session_Key; # if !defined(P) # ifdef __STDC__ # define P(x) x # else # define P(x) () # endif # endif typedef struct { char *name; int type; void (*output) P((unsigned char *, int)); int (*input) P((int)); void (*init) P((int)); int (*start) P((int, int)); int (*is) P((unsigned char *, int)); int (*reply) P((unsigned char *, int)); void (*session) P((Session_Key *, int)); int (*keyid) P((int, unsigned char *, int *)); void (*printsub) P((unsigned char *, int, unsigned char *, int)); } Encryptions; #define SK_DES 1 /* Matched Kerberos v5 KEYTYPE_DES */ #include "enc-proto.h" extern int encrypt_debug_mode; extern int (*decrypt_input) P((int)); extern void (*encrypt_output) P((unsigned char *, int)); # endif /* __ENCRYPTION__ */ #endif /* ENCRYPTION */ diff --git a/contrib/telnet/libtelnet/genget.c b/contrib/telnet/libtelnet/genget.c index 7be384647e3f..8668db47a700 100644 --- a/contrib/telnet/libtelnet/genget.c +++ b/contrib/telnet/libtelnet/genget.c @@ -1,105 +1,104 @@ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. */ #ifndef lint -static char sccsid[] = "@(#)genget.c 8.2 (Berkeley) 5/30/95"; +static const char sccsid[] = "@(#)genget.c 8.2 (Berkeley) 5/30/95"; #endif /* not lint */ #include #define LOWER(x) (isupper(x) ? tolower(x) : (x)) /* * The prefix function returns 0 if *s1 is not a prefix * of *s2. If *s1 exactly matches *s2, the negative of * the length is returned. If *s1 is a prefix of *s2, * the length of *s1 is returned. */ int isprefix(s1, s2) register char *s1, *s2; { - register int n = 0; char *os1; register char c1, c2; if (*s1 == '\0') return(-1); os1 = s1; c1 = *s1; c2 = *s2; while (LOWER(c1) == LOWER(c2)) { if (c1 == '\0') break; c1 = *++s1; c2 = *++s2; } return(*s1 ? 0 : (*s2 ? (s1 - os1) : (os1 - s1))); } static char *ambiguous; /* special return value for command routines */ char ** genget(name, table, stlen) char *name; /* name to match */ char **table; /* name entry in table */ int stlen; { register char **c, **found; register int n; if (name == 0) return 0; found = 0; for (c = table; *c != 0; c = (char **)((char *)c + stlen)) { if ((n = isprefix(name, *c)) == 0) continue; if (n < 0) /* exact match */ return(c); if (found) return(&ambiguous); found = c; } return(found); } /* * Function call version of Ambiguous() */ int Ambiguous(s) - char *s; + char **s; { - return((char **)s == &ambiguous); + return(s == &ambiguous); } diff --git a/contrib/telnet/libtelnet/kerberos.c b/contrib/telnet/libtelnet/kerberos.c index dbf495684ab8..738a57f35ce6 100644 --- a/contrib/telnet/libtelnet/kerberos.c +++ b/contrib/telnet/libtelnet/kerberos.c @@ -1,560 +1,550 @@ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. */ #ifndef lint -static char sccsid[] = "@(#)kerberos.c 8.3 (Berkeley) 5/30/95"; +static const char sccsid[] = "@(#)kerberos.c 8.3 (Berkeley) 5/30/95"; #endif /* not lint */ /* * Copyright (C) 1990 by the Massachusetts Institute of Technology * * Export of this software from the United States of America is assumed * to require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. */ #ifdef KRB4 #include #include #include #include /* BSD wont include this in krb.h, so we do it here */ #include #ifdef __STDC__ #include #endif #ifdef NO_STRING_H #include #else #include #endif #include "encrypt.h" #include "auth.h" #include "misc.h" int kerberos4_cksum P((unsigned char *, int)); -int krb_mk_req P((KTEXT, char *, char *, char *, u_long)); -int krb_rd_req P((KTEXT, char *, char *, u_long, AUTH_DAT *, char *)); -int krb_kntoln P((AUTH_DAT *, char *)); -int krb_get_cred P((char *, char *, char *, CREDENTIALS *)); -int krb_get_lrealm P((char *, int)); int kuserok P((AUTH_DAT *, char *)); extern auth_debug_mode; static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0, AUTHTYPE_KERBEROS_V4, }; -static unsigned char str_name[1024] = { IAC, SB, TELOPT_AUTHENTICATION, - TELQUAL_NAME, }; #define KRB_AUTH 0 /* Authentication data follows */ #define KRB_REJECT 1 /* Rejected (reason might follow) */ #define KRB_ACCEPT 2 /* Accepted */ #define KRB_CHALLENGE 3 /* Challenge for mutual auth. */ #define KRB_RESPONSE 4 /* Response for mutual auth. */ #define KRB_SERVICE_NAME "rcmd" static KTEXT_ST auth; static char name[ANAME_SZ]; static AUTH_DAT adat = { 0 }; #ifdef ENCRYPTION static Block session_key = { 0 }; -static Schedule sched; +static des_key_schedule sched; static Block challenge = { 0 }; #endif /* ENCRYPTION */ static int Data(ap, type, d, c) Authenticator *ap; int type; void *d; int c; { unsigned char *p = str_data + 4; unsigned char *cd = (unsigned char *)d; if (c == -1) c = strlen((char *)cd); if (auth_debug_mode) { printf("%s:%d: [%d] (%d)", str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY", str_data[3], type, c); printd(d, c); printf("\r\n"); } *p++ = ap->type; *p++ = ap->way; *p++ = type; while (c-- > 0) { if ((*p++ = *cd++) == IAC) *p++ = IAC; } *p++ = IAC; *p++ = SE; if (str_data[3] == TELQUAL_IS) printsub('>', &str_data[2], p - (&str_data[2])); return(net_write(str_data, p - str_data)); } int kerberos4_init(ap, server) Authenticator *ap; int server; { FILE *fp; if (server) { str_data[3] = TELQUAL_REPLY; if ((fp = fopen(KEYFILE, "r")) == NULL) return(0); fclose(fp); } else { str_data[3] = TELQUAL_IS; } return(1); } char dst_realm_buf[REALM_SZ], *dest_realm = NULL; int dst_realm_sz = REALM_SZ; int kerberos4_send(ap) Authenticator *ap; { KTEXT_ST auth; -#ifdef ENCRYPTION - Block enckey; -#endif /* ENCRYPTION */ char instance[INST_SZ]; char *realm; char *krb_realmofhost(); char *krb_get_phost(); CREDENTIALS cred; int r; printf("[ Trying KERBEROS4 ... ]\n"); if (!UserNameRequested) { if (auth_debug_mode) { printf("Kerberos V4: no user name supplied\r\n"); } return(0); } memset(instance, 0, sizeof(instance)); - if (realm = krb_get_phost(RemoteHostName)) + if ((realm = krb_get_phost(RemoteHostName))) strncpy(instance, realm, sizeof(instance)); instance[sizeof(instance)-1] = '\0'; realm = dest_realm ? dest_realm : krb_realmofhost(RemoteHostName); if (!realm) { printf("Kerberos V4: no realm for %s\r\n", RemoteHostName); return(0); } - if (r = krb_mk_req(&auth, KRB_SERVICE_NAME, instance, realm, 0L)) { + if ((r = krb_mk_req(&auth, KRB_SERVICE_NAME, instance, realm, 0L))) { printf("mk_req failed: %s\r\n", krb_err_txt[r]); return(0); } - if (r = krb_get_cred(KRB_SERVICE_NAME, instance, realm, &cred)) { + if ((r = krb_get_cred(KRB_SERVICE_NAME, instance, realm, &cred))) { printf("get_cred failed: %s\r\n", krb_err_txt[r]); return(0); } if (!auth_sendname(UserNameRequested, strlen(UserNameRequested))) { if (auth_debug_mode) printf("Not enough room for user name\r\n"); return(0); } if (auth_debug_mode) printf("Sent %d bytes of authentication data\r\n", auth.length); if (!Data(ap, KRB_AUTH, (void *)auth.dat, auth.length)) { if (auth_debug_mode) printf("Not enough room for authentication data\r\n"); return(0); } #ifdef ENCRYPTION /* * If we are doing mutual authentication, get set up to send * the challenge, and verify it when the response comes back. */ if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { register int i; - des_key_sched(cred.session, sched); - des_init_random_number_generator(cred.session); - des_new_random_key(session_key); - des_ecb_encrypt(session_key, session_key, sched, 0); - des_ecb_encrypt(session_key, challenge, sched, 0); + des_key_sched(&cred.session, sched); + des_init_random_number_generator(&cred.session); + des_new_random_key(&session_key); + des_ecb_encrypt(&session_key, &session_key, sched, 0); + des_ecb_encrypt(&session_key, &challenge, sched, 0); /* * Increment the challenge by 1, and encrypt it for * later comparison. */ for (i = 7; i >= 0; --i) { register int x; x = (unsigned int)challenge[i] + 1; challenge[i] = x; /* ignore overflow */ if (x < 256) /* if no overflow, all done */ break; } - des_ecb_encrypt(challenge, challenge, sched, 1); + des_ecb_encrypt(&challenge, &challenge, sched, 1); } #endif /* ENCRYPTION */ if (auth_debug_mode) { printf("CK: %d:", kerberos4_cksum(auth.dat, auth.length)); printd(auth.dat, auth.length); printf("\r\n"); printf("Sent Kerberos V4 credentials to server\r\n"); } return(1); } void kerberos4_is(ap, data, cnt) Authenticator *ap; unsigned char *data; int cnt; { #ifdef ENCRYPTION Session_Key skey; Block datablock; #endif /* ENCRYPTION */ char realm[REALM_SZ]; char instance[INST_SZ]; int r; if (cnt-- < 1) return; switch (*data++) { case KRB_AUTH: if (krb_get_lrealm(realm, 1) != KSUCCESS) { Data(ap, KRB_REJECT, (void *)"No local V4 Realm.", -1); auth_finished(ap, AUTH_REJECT); if (auth_debug_mode) printf("No local realm\r\n"); return; } memmove((void *)auth.dat, (void *)data, auth.length = cnt); if (auth_debug_mode) { printf("Got %d bytes of authentication data\r\n", cnt); printf("CK: %d:", kerberos4_cksum(auth.dat, auth.length)); printd(auth.dat, auth.length); printf("\r\n"); } instance[0] = '*'; instance[1] = 0; - if (r = krb_rd_req(&auth, KRB_SERVICE_NAME, - instance, 0, &adat, "")) { + if ((r = krb_rd_req(&auth, KRB_SERVICE_NAME, + instance, 0, &adat, ""))) { if (auth_debug_mode) printf("Kerberos failed him as %s\r\n", name); Data(ap, KRB_REJECT, (void *)krb_err_txt[r], -1); auth_finished(ap, AUTH_REJECT); return; } #ifdef ENCRYPTION memmove((void *)session_key, (void *)adat.session, sizeof(Block)); #endif /* ENCRYPTION */ krb_kntoln(&adat, name); if (UserNameRequested && !kuserok(&adat, UserNameRequested)) Data(ap, KRB_ACCEPT, (void *)0, 0); else Data(ap, KRB_REJECT, (void *)"user is not authorized", -1); auth_finished(ap, AUTH_USER); break; case KRB_CHALLENGE: #ifndef ENCRYPTION Data(ap, KRB_RESPONSE, (void *)0, 0); #else /* ENCRYPTION */ if (!VALIDKEY(session_key)) { /* * We don't have a valid session key, so just * send back a response with an empty session * key. */ Data(ap, KRB_RESPONSE, (void *)0, 0); break; } /* * Initialize the random number generator since it's * used later on by the encryption routine. */ - des_init_random_number_generator(session_key); - des_key_sched(session_key, sched); + des_init_random_number_generator(&session_key); + des_key_sched(&session_key, sched); memmove((void *)datablock, (void *)data, sizeof(Block)); /* * Take the received encrypted challenge, and encrypt * it again to get a unique session_key for the * ENCRYPT option. */ - des_ecb_encrypt(datablock, session_key, sched, 1); + des_ecb_encrypt(&datablock, &session_key, sched, 1); skey.type = SK_DES; skey.length = 8; skey.data = session_key; encrypt_session_key(&skey, 1); /* * Now decrypt the received encrypted challenge, * increment by one, re-encrypt it and send it back. */ - des_ecb_encrypt(datablock, challenge, sched, 0); + des_ecb_encrypt(&datablock, &challenge, sched, 0); for (r = 7; r >= 0; r--) { register int t; t = (unsigned int)challenge[r] + 1; challenge[r] = t; /* ignore overflow */ if (t < 256) /* if no overflow, all done */ break; } - des_ecb_encrypt(challenge, challenge, sched, 1); + des_ecb_encrypt(&challenge, &challenge, sched, 1); Data(ap, KRB_RESPONSE, (void *)challenge, sizeof(challenge)); #endif /* ENCRYPTION */ break; default: if (auth_debug_mode) printf("Unknown Kerberos option %d\r\n", data[-1]); Data(ap, KRB_REJECT, 0, 0); break; } } void kerberos4_reply(ap, data, cnt) Authenticator *ap; unsigned char *data; int cnt; { #ifdef ENCRYPTION Session_Key skey; #endif /* ENCRYPTION */ if (cnt-- < 1) return; switch (*data++) { case KRB_REJECT: if (cnt > 0) { printf("[ Kerberos V4 refuses authentication because %.*s ]\r\n", cnt, data); } else printf("[ Kerberos V4 refuses authentication ]\r\n"); auth_send_retry(); return; case KRB_ACCEPT: printf("[ Kerberos V4 accepts you ]\n"); if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { /* * Send over the encrypted challenge. */ #ifndef ENCRYPTION Data(ap, KRB_CHALLENGE, (void *)0, 0); #else /* ENCRYPTION */ Data(ap, KRB_CHALLENGE, (void *)session_key, sizeof(session_key)); - des_ecb_encrypt(session_key, session_key, sched, 1); + des_ecb_encrypt(&session_key, &session_key, sched, 1); skey.type = SK_DES; skey.length = 8; skey.data = session_key; encrypt_session_key(&skey, 0); #endif /* ENCRYPTION */ return; } auth_finished(ap, AUTH_USER); return; case KRB_RESPONSE: #ifdef ENCRYPTION /* * Verify that the response to the challenge is correct. */ if ((cnt != sizeof(Block)) || (0 != memcmp((void *)data, (void *)challenge, sizeof(challenge)))) { #endif /* ENCRYPTION */ printf("[ Kerberos V4 challenge failed!!! ]\r\n"); auth_send_retry(); return; #ifdef ENCRYPTION } printf("[ Kerberos V4 challenge successful ]\r\n"); auth_finished(ap, AUTH_USER); #endif /* ENCRYPTION */ break; default: if (auth_debug_mode) printf("Unknown Kerberos option %d\r\n", data[-1]); return; } } int kerberos4_status(ap, name, level) Authenticator *ap; char *name; int level; { if (level < AUTH_USER) return(level); if (UserNameRequested && !kuserok(&adat, UserNameRequested)) { strcpy(name, UserNameRequested); return(AUTH_VALID); } else return(AUTH_USER); } #define BUMP(buf, len) while (*(buf)) {++(buf), --(len);} #define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len);} void kerberos4_printsub(data, cnt, buf, buflen) unsigned char *data, *buf; int cnt, buflen; { char lbuf[32]; register int i; buf[buflen-1] = '\0'; /* make sure its NULL terminated */ buflen -= 1; switch(data[3]) { case KRB_REJECT: /* Rejected (reason might follow) */ strncpy((char *)buf, " REJECT ", buflen); goto common; case KRB_ACCEPT: /* Accepted (name might follow) */ strncpy((char *)buf, " ACCEPT ", buflen); common: BUMP(buf, buflen); if (cnt <= 4) break; ADDC(buf, buflen, '"'); for (i = 4; i < cnt; i++) ADDC(buf, buflen, data[i]); ADDC(buf, buflen, '"'); ADDC(buf, buflen, '\0'); break; case KRB_AUTH: /* Authentication data follows */ strncpy((char *)buf, " AUTH", buflen); goto common2; case KRB_CHALLENGE: strncpy((char *)buf, " CHALLENGE", buflen); goto common2; case KRB_RESPONSE: strncpy((char *)buf, " RESPONSE", buflen); goto common2; default: sprintf(lbuf, " %d (unknown)", data[3]); strncpy((char *)buf, lbuf, buflen); common2: BUMP(buf, buflen); for (i = 4; i < cnt; i++) { sprintf(lbuf, " %d", data[i]); strncpy((char *)buf, lbuf, buflen); BUMP(buf, buflen); } break; } } int kerberos4_cksum(d, n) unsigned char *d; int n; { int ck = 0; /* * A comment is probably needed here for those not * well versed in the "C" language. Yes, this is * supposed to be a "switch" with the body of the * "switch" being a "while" statement. The whole * purpose of the switch is to allow us to jump into * the middle of the while() loop, and then not have * to do any more switch()s. * * Some compilers will spit out a warning message * about the loop not being entered at the top. */ switch (n&03) while (n > 0) { case 0: ck ^= (int)*d++ << 24; --n; case 3: ck ^= (int)*d++ << 16; --n; case 2: ck ^= (int)*d++ << 8; --n; case 1: ck ^= (int)*d++; --n; } return(ck); } #endif #ifdef notdef prkey(msg, key) char *msg; unsigned char *key; { register int i; printf("%s:", msg); for (i = 0; i < 8; i++) printf(" %3d", key[i]); printf("\r\n"); } #endif diff --git a/contrib/telnet/libtelnet/krb4encpwd.c b/contrib/telnet/libtelnet/krb4encpwd.c index 6148190dd4f5..cb9523c99205 100644 --- a/contrib/telnet/libtelnet/krb4encpwd.c +++ b/contrib/telnet/libtelnet/krb4encpwd.c @@ -1,446 +1,445 @@ /*- * Copyright (c) 1992, 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. */ #ifndef lint static char sccsid[] = "@(#)krb4encpwd.c 8.3 (Berkeley) 5/30/95"; #endif /* not lint */ #ifdef KRB4_ENCPWD /* * COPYRIGHT (C) 1990 DIGITAL EQUIPMENT CORPORATION * ALL RIGHTS RESERVED * * "Digital Equipment Corporation authorizes the reproduction, * distribution and modification of this software subject to the following * restrictions: * * 1. Any partial or whole copy of this software, or any modification * thereof, must include this copyright notice in its entirety. * * 2. This software is supplied "as is" with no warranty of any kind, * expressed or implied, for any purpose, including any warranty of fitness * or merchantibility. DIGITAL assumes no responsibility for the use or * reliability of this software, nor promises to provide any form of * support for it on any basis. * * 3. Distribution of this software is authorized only if no profit or * remuneration of any kind is received in exchange for such distribution. * * 4. This software produces public key authentication certificates * bearing an expiration date established by DIGITAL and RSA Data * Security, Inc. It may cease to generate certificates after the expiration * date. Any modification of this software that changes or defeats * the expiration date or its effect is unauthorized. * * 5. Software that will renew or extend the expiration date of * authentication certificates produced by this software may be obtained * from RSA Data Security, Inc., 10 Twin Dolphin Drive, Redwood City, CA * 94065, (415)595-8782, or from DIGITAL" * */ #include #include #include #include #include #include #ifdef __STDC__ #include #endif #ifdef NO_STRING_H #include #else #include #endif #include "encrypt.h" #include "auth.h" #include "misc.h" int krb_mk_encpwd_req P((KTEXT, char *, char *, char *, char *, char *, char *)); int krb_rd_encpwd_req P((KTEXT, char *, char *, u_long, AUTH_DAT *, char *, char *, char *, char *)); extern auth_debug_mode; static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0, AUTHTYPE_KRB4_ENCPWD, }; static unsigned char str_name[1024] = { IAC, SB, TELOPT_AUTHENTICATION, TELQUAL_NAME, }; #define KRB4_ENCPWD_AUTH 0 /* Authentication data follows */ #define KRB4_ENCPWD_REJECT 1 /* Rejected (reason might follow) */ #define KRB4_ENCPWD_ACCEPT 2 /* Accepted */ #define KRB4_ENCPWD_CHALLENGE 3 /* Challenge for mutual auth. */ #define KRB4_ENCPWD_ACK 4 /* Acknowledge */ #define KRB_SERVICE_NAME "rcmd" static KTEXT_ST auth; static char name[ANAME_SZ]; static char user_passwd[ANAME_SZ]; static AUTH_DAT adat = { 0 }; #ifdef ENCRYPTION static Block session_key = { 0 }; #endif /* ENCRYPTION */ -static Schedule sched; static char challenge[REALM_SZ]; static int Data(ap, type, d, c) Authenticator *ap; int type; void *d; int c; { unsigned char *p = str_data + 4; unsigned char *cd = (unsigned char *)d; if (c == -1) c = strlen((char *)cd); if (0) { printf("%s:%d: [%d] (%d)", str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY", str_data[3], type, c); printd(d, c); printf("\r\n"); } *p++ = ap->type; *p++ = ap->way; *p++ = type; while (c-- > 0) { if ((*p++ = *cd++) == IAC) *p++ = IAC; } *p++ = IAC; *p++ = SE; if (str_data[3] == TELQUAL_IS) printsub('>', &str_data[2], p - (&str_data[2])); return(net_write(str_data, p - str_data)); } int krb4encpwd_init(ap, server) Authenticator *ap; int server; { char hostname[80], *cp, *realm; C_Block skey; if (server) { str_data[3] = TELQUAL_REPLY; } else { str_data[3] = TELQUAL_IS; gethostname(hostname, sizeof(hostname)); realm = krb_realmofhost(hostname); cp = strchr(hostname, '.'); if (*cp != NULL) *cp = NULL; if (read_service_key(KRB_SERVICE_NAME, hostname, realm, 0, KEYFILE, (char *)skey)) { return(0); } } return(1); } int krb4encpwd_send(ap) Authenticator *ap; { printf("[ Trying KRB4ENCPWD ... ]\n"); if (!UserNameRequested) { return(0); } if (!auth_sendname(UserNameRequested, strlen(UserNameRequested))) { return(0); } if (!Data(ap, KRB4_ENCPWD_ACK, (void *)NULL, 0)) { return(0); } return(1); } void krb4encpwd_is(ap, data, cnt) Authenticator *ap; unsigned char *data; int cnt; { Session_Key skey; Block datablock; char r_passwd[ANAME_SZ], r_user[ANAME_SZ]; char lhostname[ANAME_SZ], *cp; int r; time_t now; if (cnt-- < 1) return; switch (*data++) { case KRB4_ENCPWD_AUTH: memmove((void *)auth.dat, (void *)data, auth.length = cnt); gethostname(lhostname, sizeof(lhostname)); if ((cp = strchr(lhostname, '.')) != 0) *cp = '\0'; if (r = krb_rd_encpwd_req(&auth, KRB_SERVICE_NAME, lhostname, 0, &adat, NULL, challenge, r_user, r_passwd)) { Data(ap, KRB4_ENCPWD_REJECT, (void *)"Auth failed", -1); auth_finished(ap, AUTH_REJECT); return; } auth_encrypt_userpwd(r_passwd); if (passwdok(UserNameRequested, UserPassword) == 0) { /* * illegal username and password */ Data(ap, KRB4_ENCPWD_REJECT, (void *)"Illegal password", -1); auth_finished(ap, AUTH_REJECT); return; } memmove((void *)session_key, (void *)adat.session, sizeof(Block)); Data(ap, KRB4_ENCPWD_ACCEPT, (void *)0, 0); auth_finished(ap, AUTH_USER); break; case KRB4_ENCPWD_CHALLENGE: /* * Take the received random challenge text and save * for future authentication. */ memmove((void *)challenge, (void *)data, sizeof(Block)); break; case KRB4_ENCPWD_ACK: /* * Receive ack, if mutual then send random challenge */ /* * If we are doing mutual authentication, get set up to send * the challenge, and verify it when the response comes back. */ if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { register int i; time(&now); sprintf(challenge, "%x", now); Data(ap, KRB4_ENCPWD_CHALLENGE, (void *)challenge, strlen(challenge)); } break; default: Data(ap, KRB4_ENCPWD_REJECT, 0, 0); break; } } void krb4encpwd_reply(ap, data, cnt) Authenticator *ap; unsigned char *data; int cnt; { Session_Key skey; KTEXT_ST krb_token; Block enckey; CREDENTIALS cred; int r; char randchal[REALM_SZ], instance[ANAME_SZ], *cp; char hostname[80], *realm; if (cnt-- < 1) return; switch (*data++) { case KRB4_ENCPWD_REJECT: if (cnt > 0) { printf("[ KRB4_ENCPWD refuses authentication because %.*s ]\r\n", cnt, data); } else printf("[ KRB4_ENCPWD refuses authentication ]\r\n"); auth_send_retry(); return; case KRB4_ENCPWD_ACCEPT: printf("[ KRB4_ENCPWD accepts you ]\n"); auth_finished(ap, AUTH_USER); return; case KRB4_ENCPWD_CHALLENGE: /* * Verify that the response to the challenge is correct. */ gethostname(hostname, sizeof(hostname)); realm = krb_realmofhost(hostname); memmove((void *)challenge, (void *)data, cnt); memset(user_passwd, 0, sizeof(user_passwd)); local_des_read_pw_string(user_passwd, sizeof(user_passwd)-1, "Password: ", 0); UserPassword = user_passwd; Challenge = challenge; strcpy(instance, RemoteHostName); if ((cp = strchr(instance, '.')) != 0) *cp = '\0'; if (r = krb_mk_encpwd_req(&krb_token, KRB_SERVICE_NAME, instance, realm, Challenge, UserNameRequested, user_passwd)) { krb_token.length = 0; } if (!Data(ap, KRB4_ENCPWD_AUTH, (void *)krb_token.dat, krb_token.length)) { return; } break; default: return; } } int krb4encpwd_status(ap, name, level) Authenticator *ap; char *name; int level; { if (level < AUTH_USER) return(level); if (UserNameRequested && passwdok(UserNameRequested, UserPassword)) { strcpy(name, UserNameRequested); return(AUTH_VALID); } else { return(AUTH_USER); } } #define BUMP(buf, len) while (*(buf)) {++(buf), --(len);} #define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len);} void krb4encpwd_printsub(data, cnt, buf, buflen) unsigned char *data, *buf; int cnt, buflen; { char lbuf[32]; register int i; buf[buflen-1] = '\0'; /* make sure its NULL terminated */ buflen -= 1; switch(data[3]) { case KRB4_ENCPWD_REJECT: /* Rejected (reason might follow) */ strncpy((char *)buf, " REJECT ", buflen); goto common; case KRB4_ENCPWD_ACCEPT: /* Accepted (name might follow) */ strncpy((char *)buf, " ACCEPT ", buflen); common: BUMP(buf, buflen); if (cnt <= 4) break; ADDC(buf, buflen, '"'); for (i = 4; i < cnt; i++) ADDC(buf, buflen, data[i]); ADDC(buf, buflen, '"'); ADDC(buf, buflen, '\0'); break; case KRB4_ENCPWD_AUTH: /* Authentication data follows */ strncpy((char *)buf, " AUTH", buflen); goto common2; case KRB4_ENCPWD_CHALLENGE: strncpy((char *)buf, " CHALLENGE", buflen); goto common2; case KRB4_ENCPWD_ACK: strncpy((char *)buf, " ACK", buflen); goto common2; default: sprintf(lbuf, " %d (unknown)", data[3]); strncpy((char *)buf, lbuf, buflen); common2: BUMP(buf, buflen); for (i = 4; i < cnt; i++) { sprintf(lbuf, " %d", data[i]); strncpy((char *)buf, lbuf, buflen); BUMP(buf, buflen); } break; } } int passwdok(name, passwd) char *name, *passwd; { char *crypt(); char *salt, *p; struct passwd *pwd; int passwdok_status = 0; if (pwd = getpwnam(name)) salt = pwd->pw_passwd; else salt = "xx"; p = crypt(passwd, salt); if (pwd && !strcmp(p, pwd->pw_passwd)) { passwdok_status = 1; } else passwdok_status = 0; return(passwdok_status); } #endif #ifdef notdef prkey(msg, key) char *msg; unsigned char *key; { register int i; printf("%s:", msg); for (i = 0; i < 8; i++) printf(" %3d", key[i]); printf("\r\n"); } #endif diff --git a/contrib/telnet/libtelnet/misc.c b/contrib/telnet/libtelnet/misc.c index 9565900a391e..4f8f8d53644b 100644 --- a/contrib/telnet/libtelnet/misc.c +++ b/contrib/telnet/libtelnet/misc.c @@ -1,94 +1,98 @@ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. */ #ifndef lint -static char sccsid[] = "@(#)misc.c 8.1 (Berkeley) 6/4/93"; +static const char sccsid[] = "@(#)misc.c 8.1 (Berkeley) 6/4/93"; #endif /* not lint */ +#include +#include #include "misc.h" +#include "auth.h" +#include "encrypt.h" char *RemoteHostName; char *LocalHostName; char *UserNameRequested = 0; int ConnectedCount = 0; void auth_encrypt_init(local, remote, name, server) char *local; char *remote; char *name; int server; { RemoteHostName = remote; LocalHostName = local; #if defined(AUTHENTICATION) auth_init(name, server); #endif #ifdef ENCRYPTION encrypt_init(name, server); #endif /* ENCRYPTION */ if (UserNameRequested) { free(UserNameRequested); UserNameRequested = 0; } } void auth_encrypt_user(name) char *name; { extern char *strdup(); if (UserNameRequested) free(UserNameRequested); UserNameRequested = name ? strdup(name) : 0; } void auth_encrypt_connect(cnt) int cnt; { } void printd(data, cnt) unsigned char *data; int cnt; { if (cnt > 16) cnt = 16; while (cnt-- > 0) { printf(" %02x", *data); ++data; } } diff --git a/contrib/telnet/libtelnet/spx.c b/contrib/telnet/libtelnet/spx.c index 86c619787c9b..90c37a47ebd6 100644 --- a/contrib/telnet/libtelnet/spx.c +++ b/contrib/telnet/libtelnet/spx.c @@ -1,588 +1,587 @@ /*- * Copyright (c) 1992, 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. */ #ifndef lint static char sccsid[] = "@(#)spx.c 8.2 (Berkeley) 5/30/95"; #endif /* not lint */ #ifdef SPX /* * COPYRIGHT (C) 1990 DIGITAL EQUIPMENT CORPORATION * ALL RIGHTS RESERVED * * "Digital Equipment Corporation authorizes the reproduction, * distribution and modification of this software subject to the following * restrictions: * * 1. Any partial or whole copy of this software, or any modification * thereof, must include this copyright notice in its entirety. * * 2. This software is supplied "as is" with no warranty of any kind, * expressed or implied, for any purpose, including any warranty of fitness * or merchantibility. DIGITAL assumes no responsibility for the use or * reliability of this software, nor promises to provide any form of * support for it on any basis. * * 3. Distribution of this software is authorized only if no profit or * remuneration of any kind is received in exchange for such distribution. * * 4. This software produces public key authentication certificates * bearing an expiration date established by DIGITAL and RSA Data * Security, Inc. It may cease to generate certificates after the expiration * date. Any modification of this software that changes or defeats * the expiration date or its effect is unauthorized. * * 5. Software that will renew or extend the expiration date of * authentication certificates produced by this software may be obtained * from RSA Data Security, Inc., 10 Twin Dolphin Drive, Redwood City, CA * 94065, (415)595-8782, or from DIGITAL" * */ #include #include #include #include "gssapi_defs.h" #ifdef __STDC__ #include #endif #ifdef NO_STRING_H #include #else #include #endif #include #include "encrypt.h" #include "auth.h" #include "misc.h" extern auth_debug_mode; static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0, AUTHTYPE_SPX, }; static unsigned char str_name[1024] = { IAC, SB, TELOPT_AUTHENTICATION, TELQUAL_NAME, }; #define SPX_AUTH 0 /* Authentication data follows */ #define SPX_REJECT 1 /* Rejected (reason might follow) */ #define SPX_ACCEPT 2 /* Accepted */ #ifdef ENCRYPTION static Block session_key = { 0 }; #endif /* ENCRYPTION */ -static Schedule sched; static Block challenge = { 0 }; /*******************************************************************/ gss_OID_set actual_mechs; gss_OID actual_mech_type, output_name_type; int major_status, status, msg_ctx = 0, new_status; int req_flags = 0, ret_flags, lifetime_rec; gss_cred_id_t gss_cred_handle; gss_ctx_id_t actual_ctxhandle, context_handle; gss_buffer_desc output_token, input_token, input_name_buffer; gss_buffer_desc status_string; gss_name_t desired_targname, src_name; gss_channel_bindings input_chan_bindings; char lhostname[GSS_C_MAX_PRINTABLE_NAME]; char targ_printable[GSS_C_MAX_PRINTABLE_NAME]; int to_addr=0, from_addr=0; char *address; gss_buffer_desc fullname_buffer; gss_OID fullname_type; gss_cred_id_t gss_delegated_cred_handle; /*******************************************************************/ static int Data(ap, type, d, c) Authenticator *ap; int type; void *d; int c; { unsigned char *p = str_data + 4; unsigned char *cd = (unsigned char *)d; if (c == -1) c = strlen((char *)cd); if (0) { printf("%s:%d: [%d] (%d)", str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY", str_data[3], type, c); printd(d, c); printf("\r\n"); } *p++ = ap->type; *p++ = ap->way; *p++ = type; while (c-- > 0) { if ((*p++ = *cd++) == IAC) *p++ = IAC; } *p++ = IAC; *p++ = SE; if (str_data[3] == TELQUAL_IS) printsub('>', &str_data[2], p - (&str_data[2])); return(net_write(str_data, p - str_data)); } int spx_init(ap, server) Authenticator *ap; int server; { gss_cred_id_t tmp_cred_handle; if (server) { str_data[3] = TELQUAL_REPLY; gethostname(lhostname, sizeof(lhostname)); strcpy(targ_printable, "SERVICE:rcmd@"); strcat(targ_printable, lhostname); input_name_buffer.length = strlen(targ_printable); input_name_buffer.value = targ_printable; major_status = gss_import_name(&status, &input_name_buffer, GSS_C_NULL_OID, &desired_targname); major_status = gss_acquire_cred(&status, desired_targname, 0, GSS_C_NULL_OID_SET, GSS_C_ACCEPT, &tmp_cred_handle, &actual_mechs, &lifetime_rec); if (major_status != GSS_S_COMPLETE) return(0); } else { str_data[3] = TELQUAL_IS; } return(1); } int spx_send(ap) Authenticator *ap; { Block enckey; int r; gss_OID actual_mech_type, output_name_type; int msg_ctx = 0, new_status, status; int req_flags = 0, ret_flags, lifetime_rec, major_status; gss_buffer_desc output_token, input_token, input_name_buffer; gss_buffer_desc output_name_buffer, status_string; gss_name_t desired_targname; gss_channel_bindings input_chan_bindings; char targ_printable[GSS_C_MAX_PRINTABLE_NAME]; int from_addr=0, to_addr=0, myhostlen, j; int deleg_flag=1, mutual_flag=0, replay_flag=0, seq_flag=0; char *address; printf("[ Trying SPX ... ]\n"); strcpy(targ_printable, "SERVICE:rcmd@"); strcat(targ_printable, RemoteHostName); input_name_buffer.length = strlen(targ_printable); input_name_buffer.value = targ_printable; if (!UserNameRequested) { return(0); } major_status = gss_import_name(&status, &input_name_buffer, GSS_C_NULL_OID, &desired_targname); major_status = gss_display_name(&status, desired_targname, &output_name_buffer, &output_name_type); printf("target is '%s'\n", output_name_buffer.value); fflush(stdout); major_status = gss_release_buffer(&status, &output_name_buffer); input_chan_bindings = (gss_channel_bindings) malloc(sizeof(gss_channel_bindings_desc)); input_chan_bindings->initiator_addrtype = GSS_C_AF_INET; input_chan_bindings->initiator_address.length = 4; address = (char *) malloc(4); input_chan_bindings->initiator_address.value = (char *) address; address[0] = ((from_addr & 0xff000000) >> 24); address[1] = ((from_addr & 0xff0000) >> 16); address[2] = ((from_addr & 0xff00) >> 8); address[3] = (from_addr & 0xff); input_chan_bindings->acceptor_addrtype = GSS_C_AF_INET; input_chan_bindings->acceptor_address.length = 4; address = (char *) malloc(4); input_chan_bindings->acceptor_address.value = (char *) address; address[0] = ((to_addr & 0xff000000) >> 24); address[1] = ((to_addr & 0xff0000) >> 16); address[2] = ((to_addr & 0xff00) >> 8); address[3] = (to_addr & 0xff); input_chan_bindings->application_data.length = 0; req_flags = 0; if (deleg_flag) req_flags = req_flags | 1; if (mutual_flag) req_flags = req_flags | 2; if (replay_flag) req_flags = req_flags | 4; if (seq_flag) req_flags = req_flags | 8; major_status = gss_init_sec_context(&status, /* minor status */ GSS_C_NO_CREDENTIAL, /* cred handle */ &actual_ctxhandle, /* ctx handle */ desired_targname, /* target name */ GSS_C_NULL_OID, /* mech type */ req_flags, /* req flags */ 0, /* time req */ input_chan_bindings, /* chan binding */ GSS_C_NO_BUFFER, /* input token */ &actual_mech_type, /* actual mech */ &output_token, /* output token */ &ret_flags, /* ret flags */ &lifetime_rec); /* time rec */ if ((major_status != GSS_S_COMPLETE) && (major_status != GSS_S_CONTINUE_NEEDED)) { gss_display_status(&new_status, status, GSS_C_MECH_CODE, GSS_C_NULL_OID, &msg_ctx, &status_string); printf("%s\n", status_string.value); return(0); } if (!auth_sendname(UserNameRequested, strlen(UserNameRequested))) { return(0); } if (!Data(ap, SPX_AUTH, (void *)output_token.value, output_token.length)) { return(0); } return(1); } void spx_is(ap, data, cnt) Authenticator *ap; unsigned char *data; int cnt; { Session_Key skey; Block datablock; int r; if (cnt-- < 1) return; switch (*data++) { case SPX_AUTH: input_token.length = cnt; input_token.value = (char *) data; gethostname(lhostname, sizeof(lhostname)); strcpy(targ_printable, "SERVICE:rcmd@"); strcat(targ_printable, lhostname); input_name_buffer.length = strlen(targ_printable); input_name_buffer.value = targ_printable; major_status = gss_import_name(&status, &input_name_buffer, GSS_C_NULL_OID, &desired_targname); major_status = gss_acquire_cred(&status, desired_targname, 0, GSS_C_NULL_OID_SET, GSS_C_ACCEPT, &gss_cred_handle, &actual_mechs, &lifetime_rec); major_status = gss_release_name(&status, desired_targname); input_chan_bindings = (gss_channel_bindings) malloc(sizeof(gss_channel_bindings_desc)); input_chan_bindings->initiator_addrtype = GSS_C_AF_INET; input_chan_bindings->initiator_address.length = 4; address = (char *) malloc(4); input_chan_bindings->initiator_address.value = (char *) address; address[0] = ((from_addr & 0xff000000) >> 24); address[1] = ((from_addr & 0xff0000) >> 16); address[2] = ((from_addr & 0xff00) >> 8); address[3] = (from_addr & 0xff); input_chan_bindings->acceptor_addrtype = GSS_C_AF_INET; input_chan_bindings->acceptor_address.length = 4; address = (char *) malloc(4); input_chan_bindings->acceptor_address.value = (char *) address; address[0] = ((to_addr & 0xff000000) >> 24); address[1] = ((to_addr & 0xff0000) >> 16); address[2] = ((to_addr & 0xff00) >> 8); address[3] = (to_addr & 0xff); input_chan_bindings->application_data.length = 0; major_status = gss_accept_sec_context(&status, &context_handle, gss_cred_handle, &input_token, input_chan_bindings, &src_name, &actual_mech_type, &output_token, &ret_flags, &lifetime_rec, &gss_delegated_cred_handle); if (major_status != GSS_S_COMPLETE) { major_status = gss_display_name(&status, src_name, &fullname_buffer, &fullname_type); Data(ap, SPX_REJECT, (void *)"auth failed", -1); auth_finished(ap, AUTH_REJECT); return; } major_status = gss_display_name(&status, src_name, &fullname_buffer, &fullname_type); Data(ap, SPX_ACCEPT, (void *)output_token.value, output_token.length); auth_finished(ap, AUTH_USER); break; default: Data(ap, SPX_REJECT, 0, 0); break; } } void spx_reply(ap, data, cnt) Authenticator *ap; unsigned char *data; int cnt; { Session_Key skey; if (cnt-- < 1) return; switch (*data++) { case SPX_REJECT: if (cnt > 0) { printf("[ SPX refuses authentication because %.*s ]\r\n", cnt, data); } else printf("[ SPX refuses authentication ]\r\n"); auth_send_retry(); return; case SPX_ACCEPT: printf("[ SPX accepts you ]\n"); if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { /* * Send over the encrypted challenge. */ input_token.value = (char *) data; input_token.length = cnt; major_status = gss_init_sec_context(&status, /* minor stat */ GSS_C_NO_CREDENTIAL, /* cred handle */ &actual_ctxhandle, /* ctx handle */ desired_targname, /* target name */ GSS_C_NULL_OID, /* mech type */ req_flags, /* req flags */ 0, /* time req */ input_chan_bindings, /* chan binding */ &input_token, /* input token */ &actual_mech_type, /* actual mech */ &output_token, /* output token */ &ret_flags, /* ret flags */ &lifetime_rec); /* time rec */ if (major_status != GSS_S_COMPLETE) { gss_display_status(&new_status, status, GSS_C_MECH_CODE, GSS_C_NULL_OID, &msg_ctx, &status_string); printf("[ SPX mutual response fails ... '%s' ]\r\n", status_string.value); auth_send_retry(); return; } } auth_finished(ap, AUTH_USER); return; default: return; } } int spx_status(ap, name, level) Authenticator *ap; char *name; int level; { gss_buffer_desc fullname_buffer, acl_file_buffer; gss_OID fullname_type; char acl_file[160], fullname[160]; int major_status, status = 0; struct passwd *pwd; /* * hard code fullname to * "SPX:/C=US/O=Digital/OU=LKG/OU=Sphinx/OU=Users/CN=Kannan Alagappan" * and acl_file to "~kannan/.sphinx" */ pwd = getpwnam(UserNameRequested); if (pwd == NULL) { return(AUTH_USER); /* not authenticated */ } strcpy(acl_file, pwd->pw_dir); strcat(acl_file, "/.sphinx"); acl_file_buffer.value = acl_file; acl_file_buffer.length = strlen(acl_file); major_status = gss_display_name(&status, src_name, &fullname_buffer, &fullname_type); if (level < AUTH_USER) return(level); major_status = gss__check_acl(&status, &fullname_buffer, &acl_file_buffer); if (major_status == GSS_S_COMPLETE) { strcpy(name, UserNameRequested); return(AUTH_VALID); } else { return(AUTH_USER); } } #define BUMP(buf, len) while (*(buf)) {++(buf), --(len);} #define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len);} void spx_printsub(data, cnt, buf, buflen) unsigned char *data, *buf; int cnt, buflen; { char lbuf[32]; register int i; buf[buflen-1] = '\0'; /* make sure its NULL terminated */ buflen -= 1; switch(data[3]) { case SPX_REJECT: /* Rejected (reason might follow) */ strncpy((char *)buf, " REJECT ", buflen); goto common; case SPX_ACCEPT: /* Accepted (name might follow) */ strncpy((char *)buf, " ACCEPT ", buflen); common: BUMP(buf, buflen); if (cnt <= 4) break; ADDC(buf, buflen, '"'); for (i = 4; i < cnt; i++) ADDC(buf, buflen, data[i]); ADDC(buf, buflen, '"'); ADDC(buf, buflen, '\0'); break; case SPX_AUTH: /* Authentication data follows */ strncpy((char *)buf, " AUTH", buflen); goto common2; default: sprintf(lbuf, " %d (unknown)", data[3]); strncpy((char *)buf, lbuf, buflen); common2: BUMP(buf, buflen); for (i = 4; i < cnt; i++) { sprintf(lbuf, " %d", data[i]); strncpy((char *)buf, lbuf, buflen); BUMP(buf, buflen); } break; } } #endif #ifdef notdef prkey(msg, key) char *msg; unsigned char *key; { register int i; printf("%s:", msg); for (i = 0; i < 8; i++) printf(" %3d", key[i]); printf("\r\n"); } #endif diff --git a/contrib/telnet/telnet/authenc.c b/contrib/telnet/telnet/authenc.c index 545df780051d..f829b1a741a9 100644 --- a/contrib/telnet/telnet/authenc.c +++ b/contrib/telnet/telnet/authenc.c @@ -1,111 +1,111 @@ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. */ #ifndef lint -static char sccsid[] = "@(#)authenc.c 8.1 (Berkeley) 6/6/93"; +static const char sccsid[] = "@(#)authenc.c 8.1 (Berkeley) 6/6/93"; #endif /* not lint */ #if defined(AUTHENTICATION) || defined(ENCRYPTION) #include #include #include #include #include "general.h" #include "ring.h" #include "externs.h" #include "defines.h" #include "types.h" int net_write(str, len) unsigned char *str; int len; { if (NETROOM() > len) { ring_supply_data(&netoring, str, len); if (str[0] == IAC && str[1] == SE) printsub('>', &str[2], len-2); return(len); } return(0); } void net_encrypt() { #ifdef ENCRYPTION if (encrypt_output) ring_encrypt(&netoring, encrypt_output); else ring_clearto(&netoring); #endif /* ENCRYPTION */ } int telnet_spin() { return(-1); } char * telnet_getenv(val) char *val; { return((char *)env_getvalue((unsigned char *)val)); } char * telnet_gets(prompt, result, length, echo) char *prompt; char *result; int length; int echo; { extern char *getpass(); extern int globalmode; int om = globalmode; char *res; TerminalNewMode(-1); if (echo) { printf("%s", prompt); res = fgets(result, length, stdin); - } else if (res = getpass(prompt)) { + } else if ((res = getpass(prompt))) { strncpy(result, res, length); res = result; } TerminalNewMode(om); return(res); } #endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */ diff --git a/contrib/telnet/telnet/commands.c b/contrib/telnet/telnet/commands.c index 41ef5cdad438..8073fb50f120 100644 --- a/contrib/telnet/telnet/commands.c +++ b/contrib/telnet/telnet/commands.c @@ -1,2945 +1,3002 @@ /* * Copyright (c) 1988, 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. */ #ifndef lint -static char sccsid[] = "@(#)commands.c 8.4 (Berkeley) 5/30/95"; +static const char sccsid[] = "@(#)commands.c 8.4 (Berkeley) 5/30/95"; #endif /* not lint */ #if defined(unix) #include #if defined(CRAY) || defined(sysV88) #include #endif #include #else #include #endif /* defined(unix) */ #include #include #ifdef CRAY #include #endif /* CRAY */ #include #include #include #include #include #include +#include +#include #include #include "general.h" #include "ring.h" #include "externs.h" #include "defines.h" #include "types.h" +#if defined(AUTHENTICATION) +#include +#endif +#if defined(ENCRYPTION) +#include +#endif + #if !defined(CRAY) && !defined(sysV88) #include # if (defined(vax) || defined(tahoe) || defined(hp300)) && !defined(ultrix) # include # endif /* vax */ #endif /* !defined(CRAY) && !defined(sysV88) */ #include #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 64 #endif MAXHOSTNAMELEN #if defined(IPPROTO_IP) && defined(IP_TOS) int tos = -1; #endif /* defined(IPPROTO_IP) && defined(IP_TOS) */ char *hostname; static char _hostname[MAXHOSTNAMELEN]; extern char *getenv(); extern int isprefix(); extern char **genget(); extern int Ambiguous(); -static call(); +static int help(int argc, char *argv[]); +static int call(); +static void cmdrc(char *m1, char *m2); + +int quit(void); typedef struct { char *name; /* command name */ char *help; /* help string (NULL for no help) */ int (*handler)(); /* routine which executes command */ int needconnect; /* Do we need to be connected to execute? */ } Command; static char line[256]; static char saveline[256]; static int margc; static char *margv[20]; +#if defined(SKEY) +#include +#define PATH_SKEY "/usr/bin/key" + int +skey_calc(argc, argv) + int argc; + char **argv; +{ + int status; + + if(argc != 3) { + printf("%s sequence challenge\n", argv[0]); + return; + } + + switch(fork()) { + case 0: + execv(PATH_SKEY, argv); + exit (1); + case -1: + perror("fork"); + break; + default: + (void) wait(&status); + if (WIFEXITED(status)) + return (WEXITSTATUS(status)); + return (0); + } +} +#endif + static void makeargv() { register char *cp, *cp2, c; register char **argp = margv; margc = 0; cp = line; if (*cp == '!') { /* Special case shell escape */ strcpy(saveline, line); /* save for shell command */ *argp++ = "!"; /* No room in string to get this */ margc++; cp++; } - while (c = *cp) { + while ((c = *cp)) { register int inquote = 0; while (isspace(c)) c = *++cp; if (c == '\0') break; *argp++ = cp; margc += 1; for (cp2 = cp; c != '\0'; c = *++cp) { if (inquote) { if (c == inquote) { inquote = 0; continue; } } else { if (c == '\\') { if ((c = *++cp) == '\0') break; } else if (c == '"') { inquote = '"'; continue; } else if (c == '\'') { inquote = '\''; continue; } else if (isspace(c)) break; } *cp2++ = c; } *cp2 = '\0'; if (c == '\0') break; cp++; } *argp++ = 0; } /* * Make a character string into a number. * * Todo: 1. Could take random integers (12, 0x12, 012, 0b1). */ - static + static int special(s) register char *s; { register char c; char b; switch (*s) { case '^': b = *++s; if (b == '?') { c = b | 0x40; /* DEL */ } else { c = b & 0x1f; } break; default: c = *s; break; } return c; } /* * Construct a control character sequence * for a special character. */ static char * control(c) register cc_t c; { static char buf[5]; /* * The only way I could get the Sun 3.5 compiler * to shut up about * if ((unsigned int)c >= 0x80) * was to assign "c" to an unsigned int variable... * Arggg.... */ register unsigned int uic = (unsigned int)c; if (uic == 0x7f) return ("^?"); if (c == (cc_t)_POSIX_VDISABLE) { return "off"; } if (uic >= 0x80) { buf[0] = '\\'; buf[1] = ((c>>6)&07) + '0'; buf[2] = ((c>>3)&07) + '0'; buf[3] = (c&07) + '0'; buf[4] = 0; } else if (uic >= 0x20) { buf[0] = c; buf[1] = 0; } else { buf[0] = '^'; buf[1] = '@'+c; buf[2] = 0; } return (buf); } /* * The following are data structures and routines for * the "send" command. * */ struct sendlist { char *name; /* How user refers to it (case independent) */ char *help; /* Help information (0 ==> no help) */ int needconnect; /* Need to be connected */ int narg; /* Number of arguments */ int (*handler)(); /* Routine to perform (for special ops) */ int nbyte; /* Number of bytes to send this command */ int what; /* Character to be sent (<0 ==> special) */ }; static int send_esc P((void)), send_help P((void)), send_docmd P((char *)), send_dontcmd P((char *)), send_willcmd P((char *)), send_wontcmd P((char *)); static struct sendlist Sendlist[] = { { "ao", "Send Telnet Abort output", 1, 0, 0, 2, AO }, { "ayt", "Send Telnet 'Are You There'", 1, 0, 0, 2, AYT }, { "brk", "Send Telnet Break", 1, 0, 0, 2, BREAK }, { "break", 0, 1, 0, 0, 2, BREAK }, { "ec", "Send Telnet Erase Character", 1, 0, 0, 2, EC }, { "el", "Send Telnet Erase Line", 1, 0, 0, 2, EL }, { "escape", "Send current escape character", 1, 0, send_esc, 1, 0 }, { "ga", "Send Telnet 'Go Ahead' sequence", 1, 0, 0, 2, GA }, { "ip", "Send Telnet Interrupt Process", 1, 0, 0, 2, IP }, { "intp", 0, 1, 0, 0, 2, IP }, { "interrupt", 0, 1, 0, 0, 2, IP }, { "intr", 0, 1, 0, 0, 2, IP }, { "nop", "Send Telnet 'No operation'", 1, 0, 0, 2, NOP }, { "eor", "Send Telnet 'End of Record'", 1, 0, 0, 2, EOR }, { "abort", "Send Telnet 'Abort Process'", 1, 0, 0, 2, ABORT }, { "susp", "Send Telnet 'Suspend Process'", 1, 0, 0, 2, SUSP }, { "eof", "Send Telnet End of File Character", 1, 0, 0, 2, xEOF }, { "synch", "Perform Telnet 'Synch operation'", 1, 0, dosynch, 2, 0 }, { "getstatus", "Send request for STATUS", 1, 0, get_status, 6, 0 }, { "?", "Display send options", 0, 0, send_help, 0, 0 }, { "help", 0, 0, 0, send_help, 0, 0 }, { "do", 0, 0, 1, send_docmd, 3, 0 }, { "dont", 0, 0, 1, send_dontcmd, 3, 0 }, { "will", 0, 0, 1, send_willcmd, 3, 0 }, { "wont", 0, 0, 1, send_wontcmd, 3, 0 }, { 0 } }; #define GETSEND(name) ((struct sendlist *) genget(name, (char **) Sendlist, \ sizeof(struct sendlist))) static int sendcmd(argc, argv) int argc; char **argv; { int count; /* how many bytes we are going to need to send */ int i; - int question = 0; /* was at least one argument a question */ struct sendlist *s; /* pointer to current command */ int success = 0; int needconnect = 0; if (argc < 2) { printf("need at least one argument for 'send' command\n"); printf("'send ?' for help\n"); return 0; } /* * First, validate all the send arguments. * In addition, we see how much space we are going to need, and * whether or not we will be doing a "SYNCH" operation (which * flushes the network queue). */ count = 0; for (i = 1; i < argc; i++) { s = GETSEND(argv[i]); if (s == 0) { printf("Unknown send argument '%s'\n'send ?' for help.\n", argv[i]); return 0; } else if (Ambiguous(s)) { printf("Ambiguous send argument '%s'\n'send ?' for help.\n", argv[i]); return 0; } if (i + s->narg >= argc) { fprintf(stderr, "Need %d argument%s to 'send %s' command. 'send %s ?' for help.\n", s->narg, s->narg == 1 ? "" : "s", s->name, s->name); return 0; } count += s->nbyte; if (s->handler == send_help) { send_help(); return 0; } i += s->narg; needconnect += s->needconnect; } if (!connected && needconnect) { printf("?Need to be connected first.\n"); printf("'send ?' for help\n"); return 0; } /* Now, do we have enough room? */ if (NETROOM() < count) { printf("There is not enough room in the buffer TO the network\n"); printf("to process your request. Nothing will be done.\n"); printf("('send synch' will throw away most data in the network\n"); printf("buffer, if this might help.)\n"); return 0; } /* OK, they are all OK, now go through again and actually send */ count = 0; for (i = 1; i < argc; i++) { if ((s = GETSEND(argv[i])) == 0) { fprintf(stderr, "Telnet 'send' error - argument disappeared!\n"); (void) quit(); /*NOTREACHED*/ } if (s->handler) { count++; success += (*s->handler)((s->narg > 0) ? argv[i+1] : 0, (s->narg > 1) ? argv[i+2] : 0); i += s->narg; } else { NET2ADD(IAC, s->what); printoption("SENT", IAC, s->what); } } return (count == success); } static int send_esc() { NETADD(escape); return 1; } static int send_docmd(name) char *name; { return(send_tncmd(send_do, "do", name)); } static int send_dontcmd(name) char *name; { return(send_tncmd(send_dont, "dont", name)); } static int send_willcmd(name) char *name; { return(send_tncmd(send_will, "will", name)); } static int send_wontcmd(name) char *name; { return(send_tncmd(send_wont, "wont", name)); } int send_tncmd(func, cmd, name) void (*func)(); char *cmd, *name; { char **cpp; extern char *telopts[]; register int val = 0; if (isprefix(name, "help") || isprefix(name, "?")) { register int col, len; printf("Usage: send %s \n", cmd); printf("\"value\" must be from 0 to 255\n"); printf("Valid options are:\n\t"); col = 8; for (cpp = telopts; *cpp; cpp++) { len = strlen(*cpp) + 3; if (col + len > 65) { printf("\n\t"); col = 8; } printf(" \"%s\"", *cpp); col += len; } printf("\n"); return 0; } cpp = (char **)genget(name, telopts, sizeof(char *)); if (Ambiguous(cpp)) { fprintf(stderr,"'%s': ambiguous argument ('send %s ?' for help).\n", name, cmd); return 0; } if (cpp) { val = cpp - telopts; } else { register char *cp = name; while (*cp >= '0' && *cp <= '9') { val *= 10; val += *cp - '0'; cp++; } if (*cp != 0) { fprintf(stderr, "'%s': unknown argument ('send %s ?' for help).\n", name, cmd); return 0; } else if (val < 0 || val > 255) { fprintf(stderr, "'%s': bad value ('send %s ?' for help).\n", name, cmd); return 0; } } if (!connected) { printf("?Need to be connected first.\n"); return 0; } (*func)(val, 1); return 1; } static int send_help() { struct sendlist *s; /* pointer to current command */ for (s = Sendlist; s->name; s++) { if (s->help) printf("%-15s %s\n", s->name, s->help); } return(0); } /* * The following are the routines and data structures referred * to by the arguments to the "toggle" command. */ static int lclchars() { donelclchars = 1; return 1; } static int togdebug() { #ifndef NOT43 if (net > 0 && (SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) { perror("setsockopt (SO_DEBUG)"); } #else /* NOT43 */ if (debug) { - if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) + if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) perror("setsockopt (SO_DEBUG)"); } else printf("Cannot turn off socket debugging\n"); #endif /* NOT43 */ return 1; } static int togcrlf() { if (crlf) { printf("Will send carriage returns as telnet .\n"); } else { printf("Will send carriage returns as telnet .\n"); } return 1; } int binmode; static int togbinary(val) int val; { donebinarytoggle = 1; if (val >= 0) { binmode = val; } else { if (my_want_state_is_will(TELOPT_BINARY) && my_want_state_is_do(TELOPT_BINARY)) { binmode = 1; } else if (my_want_state_is_wont(TELOPT_BINARY) && my_want_state_is_dont(TELOPT_BINARY)) { binmode = 0; } val = binmode ? 0 : 1; } if (val == 1) { if (my_want_state_is_will(TELOPT_BINARY) && my_want_state_is_do(TELOPT_BINARY)) { printf("Already operating in binary mode with remote host.\n"); } else { printf("Negotiating binary mode with remote host.\n"); tel_enter_binary(3); } } else { if (my_want_state_is_wont(TELOPT_BINARY) && my_want_state_is_dont(TELOPT_BINARY)) { printf("Already in network ascii mode with remote host.\n"); } else { printf("Negotiating network ascii mode with remote host.\n"); tel_leave_binary(3); } } return 1; } static int togrbinary(val) int val; { donebinarytoggle = 1; if (val == -1) val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1; if (val == 1) { if (my_want_state_is_do(TELOPT_BINARY)) { printf("Already receiving in binary mode.\n"); } else { printf("Negotiating binary mode on input.\n"); tel_enter_binary(1); } } else { if (my_want_state_is_dont(TELOPT_BINARY)) { printf("Already receiving in network ascii mode.\n"); } else { printf("Negotiating network ascii mode on input.\n"); tel_leave_binary(1); } } return 1; } static int togxbinary(val) int val; { donebinarytoggle = 1; if (val == -1) val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1; if (val == 1) { if (my_want_state_is_will(TELOPT_BINARY)) { printf("Already transmitting in binary mode.\n"); } else { printf("Negotiating binary mode on output.\n"); tel_enter_binary(2); } } else { if (my_want_state_is_wont(TELOPT_BINARY)) { printf("Already transmitting in network ascii mode.\n"); } else { printf("Negotiating network ascii mode on output.\n"); tel_leave_binary(2); } } return 1; } static int togglehelp P((void)); #if defined(AUTHENTICATION) extern int auth_togdebug P((int)); #endif #ifdef ENCRYPTION extern int EncryptAutoEnc P((int)); extern int EncryptAutoDec P((int)); extern int EncryptDebug P((int)); extern int EncryptVerbose P((int)); #endif /* ENCRYPTION */ struct togglelist { char *name; /* name of toggle */ char *help; /* help message */ int (*handler)(); /* routine to do actual setting */ int *variable; char *actionexplanation; }; static struct togglelist Togglelist[] = { { "autoflush", "flushing of output when sending interrupt characters", 0, &autoflush, "flush output when sending interrupt characters" }, { "autosynch", "automatic sending of interrupt characters in urgent mode", 0, &autosynch, "send interrupt characters in urgent mode" }, #if defined(AUTHENTICATION) { "autologin", "automatic sending of login and/or authentication info", 0, &autologin, "send login name and/or authentication information" }, { "authdebug", "Toggle authentication debugging", auth_togdebug, 0, "print authentication debugging information" }, #endif #ifdef ENCRYPTION { "autoencrypt", "automatic encryption of data stream", EncryptAutoEnc, 0, "automatically encrypt output" }, { "autodecrypt", "automatic decryption of data stream", EncryptAutoDec, 0, "automatically decrypt input" }, { "verbose_encrypt", "Toggle verbose encryption output", EncryptVerbose, 0, "print verbose encryption output" }, { "encdebug", "Toggle encryption debugging", EncryptDebug, 0, "print encryption debugging information" }, #endif /* ENCRYPTION */ { "skiprc", "don't read ~/.telnetrc file", 0, &skiprc, "skip reading of ~/.telnetrc file" }, { "binary", "sending and receiving of binary data", togbinary, 0, 0 }, { "inbinary", "receiving of binary data", togrbinary, 0, 0 }, { "outbinary", "sending of binary data", togxbinary, 0, 0 }, { "crlf", "sending carriage returns as telnet ", togcrlf, &crlf, 0 }, { "crmod", "mapping of received carriage returns", 0, &crmod, "map carriage return on output" }, { "localchars", "local recognition of certain control characters", lclchars, &localchars, "recognize certain control characters" }, { " ", "", 0 }, /* empty line */ #if defined(unix) && defined(TN3270) { "apitrace", "(debugging) toggle tracing of API transactions", 0, &apitrace, "trace API transactions" }, { "cursesdata", "(debugging) toggle printing of hexadecimal curses data", 0, &cursesdata, "print hexadecimal representation of curses data" }, #endif /* defined(unix) && defined(TN3270) */ { "debug", "debugging", togdebug, &debug, "turn on socket level debugging" }, { "netdata", "printing of hexadecimal network data (debugging)", 0, &netdata, "print hexadecimal representation of network traffic" }, { "prettydump", "output of \"netdata\" to user readable format (debugging)", 0, &prettydump, "print user readable output for \"netdata\"" }, { "options", "viewing of options processing (debugging)", 0, &showoptions, "show option processing" }, #if defined(unix) { "termdata", "(debugging) toggle printing of hexadecimal terminal data", 0, &termdata, "print hexadecimal representation of terminal traffic" }, #endif /* defined(unix) */ { "?", 0, togglehelp }, { "help", 0, togglehelp }, { 0 } }; static int togglehelp() { struct togglelist *c; for (c = Togglelist; c->name; c++) { if (c->help) { if (*c->help) printf("%-15s toggle %s\n", c->name, c->help); else printf("\n"); } } printf("\n"); printf("%-15s %s\n", "?", "display help information"); return 0; } static void settogglehelp(set) int set; { struct togglelist *c; for (c = Togglelist; c->name; c++) { if (c->help) { if (*c->help) printf("%-15s %s %s\n", c->name, set ? "enable" : "disable", c->help); else printf("\n"); } } } #define GETTOGGLE(name) (struct togglelist *) \ genget(name, (char **) Togglelist, sizeof(struct togglelist)) static int toggle(argc, argv) int argc; char *argv[]; { int retval = 1; char *name; struct togglelist *c; if (argc < 2) { fprintf(stderr, "Need an argument to 'toggle' command. 'toggle ?' for help.\n"); return 0; } argc--; argv++; while (argc--) { name = *argv++; c = GETTOGGLE(name); if (Ambiguous(c)) { fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n", name); return 0; } else if (c == 0) { fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n", name); return 0; } else { if (c->variable) { *c->variable = !*c->variable; /* invert it */ if (c->actionexplanation) { printf("%s %s.\n", *c->variable? "Will" : "Won't", c->actionexplanation); } } if (c->handler) { retval &= (*c->handler)(-1); } } } return retval; } /* * The following perform the "set" command. */ #ifdef USE_TERMIO struct termio new_tc = { 0 }; #endif struct setlist { char *name; /* name */ char *help; /* help information */ void (*handler)(); cc_t *charp; /* where it is located at */ }; static struct setlist Setlist[] = { #ifdef KLUDGELINEMODE { "echo", "character to toggle local echoing on/off", 0, &echoc }, #endif { "escape", "character to escape back to telnet command mode", 0, &escape }, { "rlogin", "rlogin escape character", 0, &rlogin }, { "tracefile", "file to write trace information to", SetNetTrace, (cc_t *)NetTraceFile}, { " ", "" }, { " ", "The following need 'localchars' to be toggled true", 0, 0 }, { "flushoutput", "character to cause an Abort Output", 0, termFlushCharp }, { "interrupt", "character to cause an Interrupt Process", 0, termIntCharp }, { "quit", "character to cause an Abort process", 0, termQuitCharp }, { "eof", "character to cause an EOF ", 0, termEofCharp }, { " ", "" }, { " ", "The following are for local editing in linemode", 0, 0 }, { "erase", "character to use to erase a character", 0, termEraseCharp }, { "kill", "character to use to erase a line", 0, termKillCharp }, { "lnext", "character to use for literal next", 0, termLiteralNextCharp }, { "susp", "character to cause a Suspend Process", 0, termSuspCharp }, { "reprint", "character to use for line reprint", 0, termRprntCharp }, { "worderase", "character to use to erase a word", 0, termWerasCharp }, { "start", "character to use for XON", 0, termStartCharp }, { "stop", "character to use for XOFF", 0, termStopCharp }, { "forw1", "alternate end of line character", 0, termForw1Charp }, { "forw2", "alternate end of line character", 0, termForw2Charp }, { "ayt", "alternate AYT character", 0, termAytCharp }, { 0 } }; #if defined(CRAY) && !defined(__STDC__) /* Work around compiler bug in pcc 4.1.5 */ void _setlist_init() { #ifndef KLUDGELINEMODE #define N 5 #else #define N 6 #endif Setlist[N+0].charp = &termFlushChar; Setlist[N+1].charp = &termIntChar; Setlist[N+2].charp = &termQuitChar; Setlist[N+3].charp = &termEofChar; Setlist[N+6].charp = &termEraseChar; Setlist[N+7].charp = &termKillChar; Setlist[N+8].charp = &termLiteralNextChar; Setlist[N+9].charp = &termSuspChar; Setlist[N+10].charp = &termRprntChar; Setlist[N+11].charp = &termWerasChar; Setlist[N+12].charp = &termStartChar; Setlist[N+13].charp = &termStopChar; Setlist[N+14].charp = &termForw1Char; Setlist[N+15].charp = &termForw2Char; Setlist[N+16].charp = &termAytChar; #undef N } #endif /* defined(CRAY) && !defined(__STDC__) */ static struct setlist * getset(name) char *name; { return (struct setlist *) genget(name, (char **) Setlist, sizeof(struct setlist)); } void set_escape_char(s) char *s; { if (rlogin != _POSIX_VDISABLE) { rlogin = (s && *s) ? special(s) : _POSIX_VDISABLE; printf("Telnet rlogin escape character is '%s'.\n", control(rlogin)); } else { escape = (s && *s) ? special(s) : _POSIX_VDISABLE; printf("Telnet escape character is '%s'.\n", control(escape)); } } static int setcmd(argc, argv) int argc; char *argv[]; { int value; struct setlist *ct; struct togglelist *c; if (argc < 2 || argc > 3) { printf("Format is 'set Name Value'\n'set ?' for help.\n"); return 0; } if ((argc == 2) && (isprefix(argv[1], "?") || isprefix(argv[1], "help"))) { for (ct = Setlist; ct->name; ct++) printf("%-15s %s\n", ct->name, ct->help); printf("\n"); settogglehelp(1); printf("%-15s %s\n", "?", "display help information"); return 0; } ct = getset(argv[1]); if (ct == 0) { c = GETTOGGLE(argv[1]); if (c == 0) { fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n", argv[1]); return 0; } else if (Ambiguous(c)) { fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n", argv[1]); return 0; } if (c->variable) { if ((argc == 2) || (strcmp("on", argv[2]) == 0)) *c->variable = 1; else if (strcmp("off", argv[2]) == 0) *c->variable = 0; else { printf("Format is 'set togglename [on|off]'\n'set ?' for help.\n"); return 0; } if (c->actionexplanation) { printf("%s %s.\n", *c->variable? "Will" : "Won't", c->actionexplanation); } } if (c->handler) (*c->handler)(1); } else if (argc != 3) { printf("Format is 'set Name Value'\n'set ?' for help.\n"); return 0; } else if (Ambiguous(ct)) { fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n", argv[1]); return 0; } else if (ct->handler) { (*ct->handler)(argv[2]); printf("%s set to \"%s\".\n", ct->name, (char *)ct->charp); } else { if (strcmp("off", argv[2])) { value = special(argv[2]); } else { value = _POSIX_VDISABLE; } *(ct->charp) = (cc_t)value; printf("%s character is '%s'.\n", ct->name, control(*(ct->charp))); } slc_check(); return 1; } static int unsetcmd(argc, argv) int argc; char *argv[]; { struct setlist *ct; struct togglelist *c; register char *name; if (argc < 2) { fprintf(stderr, "Need an argument to 'unset' command. 'unset ?' for help.\n"); return 0; } if (isprefix(argv[1], "?") || isprefix(argv[1], "help")) { for (ct = Setlist; ct->name; ct++) printf("%-15s %s\n", ct->name, ct->help); printf("\n"); settogglehelp(0); printf("%-15s %s\n", "?", "display help information"); return 0; } argc--; argv++; while (argc--) { name = *argv++; ct = getset(name); if (ct == 0) { c = GETTOGGLE(name); if (c == 0) { fprintf(stderr, "'%s': unknown argument ('unset ?' for help).\n", name); return 0; } else if (Ambiguous(c)) { fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n", name); return 0; } if (c->variable) { *c->variable = 0; if (c->actionexplanation) { printf("%s %s.\n", *c->variable? "Will" : "Won't", c->actionexplanation); } } if (c->handler) (*c->handler)(0); } else if (Ambiguous(ct)) { fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n", name); return 0; } else if (ct->handler) { (*ct->handler)(0); printf("%s reset to \"%s\".\n", ct->name, (char *)ct->charp); } else { *(ct->charp) = _POSIX_VDISABLE; printf("%s character is '%s'.\n", ct->name, control(*(ct->charp))); } } return 1; } /* * The following are the data structures and routines for the * 'mode' command. */ #ifdef KLUDGELINEMODE extern int kludgelinemode; - static int + static void dokludgemode() { kludgelinemode = 1; send_wont(TELOPT_LINEMODE, 1); send_dont(TELOPT_SGA, 1); send_dont(TELOPT_ECHO, 1); } #endif static int dolinemode() { #ifdef KLUDGELINEMODE if (kludgelinemode) send_dont(TELOPT_SGA, 1); #endif send_will(TELOPT_LINEMODE, 1); send_dont(TELOPT_ECHO, 1); return 1; } static int docharmode() { #ifdef KLUDGELINEMODE if (kludgelinemode) send_do(TELOPT_SGA, 1); else #endif send_wont(TELOPT_LINEMODE, 1); send_do(TELOPT_ECHO, 1); return 1; } static int dolmmode(bit, on) int bit, on; { unsigned char c; extern int linemode; if (my_want_state_is_wont(TELOPT_LINEMODE)) { printf("?Need to have LINEMODE option enabled first.\n"); printf("'mode ?' for help.\n"); return 0; } if (on) c = (linemode | bit); else c = (linemode & ~bit); lm_mode(&c, 1, 1); return 1; } int -setmode(bit) +setmod(bit) { return dolmmode(bit, 1); } int clearmode(bit) { return dolmmode(bit, 0); } struct modelist { char *name; /* command name */ char *help; /* help string */ int (*handler)(); /* routine which executes command */ int needconnect; /* Do we need to be connected to execute? */ int arg1; }; extern int modehelp(); static struct modelist ModeList[] = { { "character", "Disable LINEMODE option", docharmode, 1 }, #ifdef KLUDGELINEMODE { "", "(or disable obsolete line-by-line mode)", 0 }, #endif { "line", "Enable LINEMODE option", dolinemode, 1 }, #ifdef KLUDGELINEMODE { "", "(or enable obsolete line-by-line mode)", 0 }, #endif { "", "", 0 }, { "", "These require the LINEMODE option to be enabled", 0 }, - { "isig", "Enable signal trapping", setmode, 1, MODE_TRAPSIG }, - { "+isig", 0, setmode, 1, MODE_TRAPSIG }, + { "isig", "Enable signal trapping", setmod, 1, MODE_TRAPSIG }, + { "+isig", 0, setmod, 1, MODE_TRAPSIG }, { "-isig", "Disable signal trapping", clearmode, 1, MODE_TRAPSIG }, - { "edit", "Enable character editing", setmode, 1, MODE_EDIT }, - { "+edit", 0, setmode, 1, MODE_EDIT }, + { "edit", "Enable character editing", setmod, 1, MODE_EDIT }, + { "+edit", 0, setmod, 1, MODE_EDIT }, { "-edit", "Disable character editing", clearmode, 1, MODE_EDIT }, - { "softtabs", "Enable tab expansion", setmode, 1, MODE_SOFT_TAB }, - { "+softtabs", 0, setmode, 1, MODE_SOFT_TAB }, + { "softtabs", "Enable tab expansion", setmod, 1, MODE_SOFT_TAB }, + { "+softtabs", 0, setmod, 1, MODE_SOFT_TAB }, { "-softtabs", "Disable character editing", clearmode, 1, MODE_SOFT_TAB }, - { "litecho", "Enable literal character echo", setmode, 1, MODE_LIT_ECHO }, - { "+litecho", 0, setmode, 1, MODE_LIT_ECHO }, + { "litecho", "Enable literal character echo", setmod, 1, MODE_LIT_ECHO }, + { "+litecho", 0, setmod, 1, MODE_LIT_ECHO }, { "-litecho", "Disable literal character echo", clearmode, 1, MODE_LIT_ECHO }, { "help", 0, modehelp, 0 }, #ifdef KLUDGELINEMODE { "kludgeline", 0, dokludgemode, 1 }, #endif { "", "", 0 }, { "?", "Print help information", modehelp, 0 }, { 0 }, }; int modehelp() { struct modelist *mt; printf("format is: 'mode Mode', where 'Mode' is one of:\n\n"); for (mt = ModeList; mt->name; mt++) { if (mt->help) { if (*mt->help) printf("%-15s %s\n", mt->name, mt->help); else printf("\n"); } } return 0; } #define GETMODECMD(name) (struct modelist *) \ genget(name, (char **) ModeList, sizeof(struct modelist)) static int modecmd(argc, argv) int argc; char *argv[]; { struct modelist *mt; if (argc != 2) { printf("'mode' command requires an argument\n"); printf("'mode ?' for help.\n"); } else if ((mt = GETMODECMD(argv[1])) == 0) { fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]); } else if (Ambiguous(mt)) { fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]); } else if (mt->needconnect && !connected) { printf("?Need to be connected first.\n"); printf("'mode ?' for help.\n"); } else if (mt->handler) { return (*mt->handler)(mt->arg1); } return 0; } /* * The following data structures and routines implement the * "display" command. */ static int display(argc, argv) int argc; char *argv[]; { struct togglelist *tl; struct setlist *sl; #define dotog(tl) if (tl->variable && tl->actionexplanation) { \ if (*tl->variable) { \ printf("will"); \ } else { \ printf("won't"); \ } \ printf(" %s.\n", tl->actionexplanation); \ } #define doset(sl) if (sl->name && *sl->name != ' ') { \ if (sl->handler == 0) \ printf("%-15s [%s]\n", sl->name, control(*sl->charp)); \ else \ printf("%-15s \"%s\"\n", sl->name, (char *)sl->charp); \ } if (argc == 1) { for (tl = Togglelist; tl->name; tl++) { dotog(tl); } printf("\n"); for (sl = Setlist; sl->name; sl++) { doset(sl); } } else { int i; for (i = 1; i < argc; i++) { sl = getset(argv[i]); tl = GETTOGGLE(argv[i]); if (Ambiguous(sl) || Ambiguous(tl)) { printf("?Ambiguous argument '%s'.\n", argv[i]); return 0; } else if (!sl && !tl) { printf("?Unknown argument '%s'.\n", argv[i]); return 0; } else { if (tl) { dotog(tl); } if (sl) { doset(sl); } } } } /*@*/optionstatus(); #ifdef ENCRYPTION EncryptStatus(); #endif /* ENCRYPTION */ return 1; #undef doset #undef dotog } /* * The following are the data structures, and many of the routines, * relating to command processing. */ /* * Set the escape character. */ static int setescape(argc, argv) int argc; char *argv[]; { register char *arg; char buf[50]; printf( "Deprecated usage - please use 'set escape%s%s' in the future.\n", (argc > 2)? " ":"", (argc > 2)? argv[1]: ""); if (argc > 2) arg = argv[1]; else { printf("new escape character: "); (void) fgets(buf, sizeof(buf), stdin); arg = buf; } if (arg[0] != '\0') escape = arg[0]; if (!In3270) { printf("Escape character is '%s'.\n", control(escape)); } (void) fflush(stdout); return 1; } /*VARARGS*/ static int togcrmod() { crmod = !crmod; printf("Deprecated usage - please use 'toggle crmod' in the future.\n"); printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't"); (void) fflush(stdout); return 1; } /*VARARGS*/ int suspend() { #ifdef SIGTSTP setcommandmode(); { long oldrows, oldcols, newrows, newcols, err; err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0; (void) kill(0, SIGTSTP); /* * If we didn't get the window size before the SUSPEND, but we * can get them now (?), then send the NAWS to make sure that * we are set up for the right window size. */ if (TerminalWindowSize(&newrows, &newcols) && connected && (err || ((oldrows != newrows) || (oldcols != newcols)))) { sendnaws(); } } /* reget parameters in case they were changed */ TerminalSaveState(); setconnmode(0); #else printf("Suspend is not supported. Try the '!' command instead\n"); #endif return 1; } #if !defined(TN3270) /*ARGSUSED*/ int shell(argc, argv) int argc; char *argv[]; { long oldrows, oldcols, newrows, newcols, err; setcommandmode(); err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0; switch(vfork()) { case -1: perror("Fork failed\n"); break; case 0: { /* * Fire up the shell in the child. */ register char *shellp, *shellname; extern char *strrchr(); shellp = getenv("SHELL"); if (shellp == NULL) shellp = "/bin/sh"; if ((shellname = strrchr(shellp, '/')) == 0) shellname = shellp; else shellname++; if (argc > 1) execl(shellp, shellname, "-c", &saveline[1], 0); else execl(shellp, shellname, 0); perror("Execl"); _exit(1); } default: (void)wait((int *)0); /* Wait for the shell to complete */ if (TerminalWindowSize(&newrows, &newcols) && connected && (err || ((oldrows != newrows) || (oldcols != newcols)))) { sendnaws(); } break; } return 1; } #else /* !defined(TN3270) */ extern int shell(); #endif /* !defined(TN3270) */ /*VARARGS*/ - static + static int bye(argc, argv) int argc; /* Number of arguments */ char *argv[]; /* arguments */ { extern int resettermname; if (connected) { (void) shutdown(net, 2); printf("Connection closed.\n"); (void) NetClose(net); connected = 0; resettermname = 1; #if defined(AUTHENTICATION) || defined(ENCRYPTION) auth_encrypt_connect(connected); #endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */ /* reset options */ tninit(); #if defined(TN3270) SetIn3270(); /* Get out of 3270 mode */ #endif /* defined(TN3270) */ } if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) { longjmp(toplevel, 1); /* NOTREACHED */ } return 1; /* Keep lint, etc., happy */ } /*VARARGS*/ + int quit() { (void) call(bye, "bye", "fromquit", 0); Exit(0); /*NOTREACHED*/ } /*VARARGS*/ int logout() { send_do(TELOPT_LOGOUT, 1); (void) netflush(); return 1; } /* * The SLC command. */ struct slclist { char *name; char *help; void (*handler)(); int arg; }; static void slc_help(); struct slclist SlcList[] = { { "export", "Use local special character definitions", slc_mode_export, 0 }, { "import", "Use remote special character definitions", slc_mode_import, 1 }, { "check", "Verify remote special character definitions", slc_mode_import, 0 }, { "help", 0, slc_help, 0 }, { "?", "Print help information", slc_help, 0 }, { 0 }, }; static void slc_help() { struct slclist *c; for (c = SlcList; c->name; c++) { if (c->help) { if (*c->help) printf("%-15s %s\n", c->name, c->help); else printf("\n"); } } } static struct slclist * getslc(name) char *name; { return (struct slclist *) genget(name, (char **) SlcList, sizeof(struct slclist)); } - static + static int slccmd(argc, argv) int argc; char *argv[]; { struct slclist *c; if (argc != 2) { fprintf(stderr, "Need an argument to 'slc' command. 'slc ?' for help.\n"); return 0; } c = getslc(argv[1]); if (c == 0) { fprintf(stderr, "'%s': unknown argument ('slc ?' for help).\n", argv[1]); return 0; } if (Ambiguous(c)) { fprintf(stderr, "'%s': ambiguous argument ('slc ?' for help).\n", argv[1]); return 0; } (*c->handler)(c->arg); slcstate(); return 1; } /* * The ENVIRON command. */ struct envlist { char *name; char *help; void (*handler)(); int narg; }; extern struct env_lst * env_define P((unsigned char *, unsigned char *)); extern void env_undefine P((unsigned char *)), env_export P((unsigned char *)), env_unexport P((unsigned char *)), env_send P((unsigned char *)), #if defined(OLD_ENVIRON) && defined(ENV_HACK) env_varval P((unsigned char *)), #endif env_list P((void)); static void env_help P((void)); struct envlist EnvList[] = { { "define", "Define an environment variable", (void (*)())env_define, 2 }, { "undefine", "Undefine an environment variable", env_undefine, 1 }, { "export", "Mark an environment variable for automatic export", env_export, 1 }, { "unexport", "Don't mark an environment variable for automatic export", env_unexport, 1 }, { "send", "Send an environment variable", env_send, 1 }, { "list", "List the current environment variables", env_list, 0 }, #if defined(OLD_ENVIRON) && defined(ENV_HACK) { "varval", "Reverse VAR and VALUE (auto, right, wrong, status)", env_varval, 1 }, #endif { "help", 0, env_help, 0 }, { "?", "Print help information", env_help, 0 }, { 0 }, }; static void env_help() { struct envlist *c; for (c = EnvList; c->name; c++) { if (c->help) { if (*c->help) printf("%-15s %s\n", c->name, c->help); else printf("\n"); } } } static struct envlist * getenvcmd(name) char *name; { return (struct envlist *) genget(name, (char **) EnvList, sizeof(struct envlist)); } + int env_cmd(argc, argv) int argc; char *argv[]; { struct envlist *c; if (argc < 2) { fprintf(stderr, "Need an argument to 'environ' command. 'environ ?' for help.\n"); return 0; } c = getenvcmd(argv[1]); if (c == 0) { fprintf(stderr, "'%s': unknown argument ('environ ?' for help).\n", argv[1]); return 0; } if (Ambiguous(c)) { fprintf(stderr, "'%s': ambiguous argument ('environ ?' for help).\n", argv[1]); return 0; } if (c->narg + 2 != argc) { fprintf(stderr, "Need %s%d argument%s to 'environ %s' command. 'environ ?' for help.\n", c->narg < argc + 2 ? "only " : "", c->narg, c->narg == 1 ? "" : "s", c->name); return 0; } (*c->handler)(argv[2], argv[3]); return 1; } struct env_lst { struct env_lst *next; /* pointer to next structure */ struct env_lst *prev; /* pointer to previous structure */ unsigned char *var; /* pointer to variable name */ unsigned char *value; /* pointer to variable value */ int export; /* 1 -> export with default list of variables */ int welldefined; /* A well defined variable */ }; struct env_lst envlisthead; struct env_lst * env_find(var) unsigned char *var; { register struct env_lst *ep; for (ep = envlisthead.next; ep; ep = ep->next) { if (strcmp((char *)ep->var, (char *)var) == 0) return(ep); } return(NULL); } void env_init() { extern char **environ; register char **epp, *cp; register struct env_lst *ep; extern char *strchr(); for (epp = environ; *epp; epp++) { - if (cp = strchr(*epp, '=')) { + if ((cp = strchr(*epp, '='))) { *cp = '\0'; ep = env_define((unsigned char *)*epp, (unsigned char *)cp+1); ep->export = 0; *cp = '='; } } /* * Special case for DISPLAY variable. If it is ":0.0" or * "unix:0.0", we have to get rid of "unix" and insert our * hostname. */ if ((ep = env_find("DISPLAY")) && ((*ep->value == ':') || (strncmp((char *)ep->value, "unix:", 5) == 0))) { char hbuf[256+1]; char *cp2 = strchr((char *)ep->value, ':'); gethostname(hbuf, 256); hbuf[256] = '\0'; cp = (char *)malloc(strlen(hbuf) + strlen(cp2) + 1); sprintf((char *)cp, "%s%s", hbuf, cp2); free(ep->value); ep->value = (unsigned char *)cp; } /* * If USER is not defined, but LOGNAME is, then add * USER with the value from LOGNAME. By default, we * don't export the USER variable. */ if ((env_find("USER") == NULL) && (ep = env_find("LOGNAME"))) { env_define((unsigned char *)"USER", ep->value); env_unexport((unsigned char *)"USER"); } env_export((unsigned char *)"DISPLAY"); env_export((unsigned char *)"PRINTER"); } struct env_lst * env_define(var, value) unsigned char *var, *value; { register struct env_lst *ep; - if (ep = env_find(var)) { + if ((ep = env_find(var))) { if (ep->var) free(ep->var); if (ep->value) free(ep->value); } else { ep = (struct env_lst *)malloc(sizeof(struct env_lst)); ep->next = envlisthead.next; envlisthead.next = ep; ep->prev = &envlisthead; if (ep->next) ep->next->prev = ep; } ep->welldefined = opt_welldefined(var); ep->export = 1; ep->var = (unsigned char *)strdup((char *)var); ep->value = (unsigned char *)strdup((char *)value); return(ep); } void env_undefine(var) unsigned char *var; { register struct env_lst *ep; - if (ep = env_find(var)) { + if ((ep = env_find(var))) { ep->prev->next = ep->next; if (ep->next) ep->next->prev = ep->prev; if (ep->var) free(ep->var); if (ep->value) free(ep->value); free(ep); } } void env_export(var) unsigned char *var; { register struct env_lst *ep; - if (ep = env_find(var)) + if ((ep = env_find(var))) ep->export = 1; } void env_unexport(var) unsigned char *var; { register struct env_lst *ep; - if (ep = env_find(var)) + if ((ep = env_find(var))) ep->export = 0; } void env_send(var) unsigned char *var; { register struct env_lst *ep; if (my_state_is_wont(TELOPT_NEW_ENVIRON) #ifdef OLD_ENVIRON && my_state_is_wont(TELOPT_OLD_ENVIRON) #endif ) { fprintf(stderr, "Cannot send '%s': Telnet ENVIRON option not enabled\n", var); return; } ep = env_find(var); if (ep == 0) { fprintf(stderr, "Cannot send '%s': variable not defined\n", var); return; } env_opt_start_info(); env_opt_add(ep->var); env_opt_end(0); } void env_list() { register struct env_lst *ep; for (ep = envlisthead.next; ep; ep = ep->next) { printf("%c %-20s %s\n", ep->export ? '*' : ' ', ep->var, ep->value); } } unsigned char * env_default(init, welldefined) int init; { static struct env_lst *nep = NULL; if (init) { nep = &envlisthead; - return; + return(NULL); } if (nep) { - while (nep = nep->next) { + while ((nep = nep->next)) { if (nep->export && (nep->welldefined == welldefined)) return(nep->var); } } return(NULL); } unsigned char * env_getvalue(var) unsigned char *var; { register struct env_lst *ep; - if (ep = env_find(var)) + if ((ep = env_find(var))) return(ep->value); return(NULL); } #if defined(OLD_ENVIRON) && defined(ENV_HACK) void env_varval(what) unsigned char *what; { extern int old_env_var, old_env_value, env_auto; int len = strlen((char *)what); if (len == 0) goto unknown; if (strncasecmp((char *)what, "status", len) == 0) { if (env_auto) printf("%s%s", "VAR and VALUE are/will be ", "determined automatically\n"); if (old_env_var == OLD_ENV_VAR) printf("VAR and VALUE set to correct definitions\n"); else printf("VAR and VALUE definitions are reversed\n"); } else if (strncasecmp((char *)what, "auto", len) == 0) { env_auto = 1; old_env_var = OLD_ENV_VALUE; old_env_value = OLD_ENV_VAR; } else if (strncasecmp((char *)what, "right", len) == 0) { env_auto = 0; old_env_var = OLD_ENV_VAR; old_env_value = OLD_ENV_VALUE; } else if (strncasecmp((char *)what, "wrong", len) == 0) { env_auto = 0; old_env_var = OLD_ENV_VALUE; old_env_value = OLD_ENV_VAR; } else { unknown: printf("Unknown \"varval\" command. (\"auto\", \"right\", \"wrong\", \"status\")\n"); } } #endif #if defined(AUTHENTICATION) /* * The AUTHENTICATE command. */ struct authlist { char *name; char *help; int (*handler)(); int narg; }; extern int auth_enable P((char *)), auth_disable P((char *)), auth_status P((void)); static int auth_help P((void)); struct authlist AuthList[] = { { "status", "Display current status of authentication information", auth_status, 0 }, { "disable", "Disable an authentication type ('auth disable ?' for more)", auth_disable, 1 }, { "enable", "Enable an authentication type ('auth enable ?' for more)", auth_enable, 1 }, { "help", 0, auth_help, 0 }, { "?", "Print help information", auth_help, 0 }, { 0 }, }; static int auth_help() { struct authlist *c; for (c = AuthList; c->name; c++) { if (c->help) { if (*c->help) printf("%-15s %s\n", c->name, c->help); else printf("\n"); } } return 0; } + int auth_cmd(argc, argv) int argc; char *argv[]; { struct authlist *c; if (argc < 2) { fprintf(stderr, "Need an argument to 'auth' command. 'auth ?' for help.\n"); return 0; } c = (struct authlist *) genget(argv[1], (char **) AuthList, sizeof(struct authlist)); if (c == 0) { fprintf(stderr, "'%s': unknown argument ('auth ?' for help).\n", argv[1]); return 0; } if (Ambiguous(c)) { fprintf(stderr, "'%s': ambiguous argument ('auth ?' for help).\n", argv[1]); return 0; } if (c->narg + 2 != argc) { fprintf(stderr, "Need %s%d argument%s to 'auth %s' command. 'auth ?' for help.\n", c->narg < argc + 2 ? "only " : "", c->narg, c->narg == 1 ? "" : "s", c->name); return 0; } return((*c->handler)(argv[2], argv[3])); } #endif #ifdef ENCRYPTION /* * The ENCRYPT command. */ struct encryptlist { char *name; char *help; int (*handler)(); int needconnect; int minarg; int maxarg; }; extern int EncryptEnable P((char *, char *)), EncryptDisable P((char *, char *)), EncryptType P((char *, char *)), EncryptStart P((char *)), EncryptStartInput P((void)), EncryptStartOutput P((void)), EncryptStop P((char *)), EncryptStopInput P((void)), EncryptStopOutput P((void)), EncryptStatus P((void)); static int EncryptHelp P((void)); struct encryptlist EncryptList[] = { { "enable", "Enable encryption. ('encrypt enable ?' for more)", EncryptEnable, 1, 1, 2 }, { "disable", "Disable encryption. ('encrypt enable ?' for more)", EncryptDisable, 0, 1, 2 }, { "type", "Set encryption type. ('encrypt type ?' for more)", EncryptType, 0, 1, 1 }, { "start", "Start encryption. ('encrypt start ?' for more)", EncryptStart, 1, 0, 1 }, { "stop", "Stop encryption. ('encrypt stop ?' for more)", EncryptStop, 1, 0, 1 }, { "input", "Start encrypting the input stream", EncryptStartInput, 1, 0, 0 }, { "-input", "Stop encrypting the input stream", EncryptStopInput, 1, 0, 0 }, { "output", "Start encrypting the output stream", EncryptStartOutput, 1, 0, 0 }, { "-output", "Stop encrypting the output stream", EncryptStopOutput, 1, 0, 0 }, { "status", "Display current status of authentication information", EncryptStatus, 0, 0, 0 }, { "help", 0, EncryptHelp, 0, 0, 0 }, { "?", "Print help information", EncryptHelp, 0, 0, 0 }, { 0 }, }; static int EncryptHelp() { struct encryptlist *c; for (c = EncryptList; c->name; c++) { if (c->help) { if (*c->help) printf("%-15s %s\n", c->name, c->help); else printf("\n"); } } return 0; } + int encrypt_cmd(argc, argv) int argc; char *argv[]; { struct encryptlist *c; if (argc < 2) { fprintf(stderr, "Need an argument to 'encrypt' command. 'encrypt ?' for help.\n"); return 0; } c = (struct encryptlist *) genget(argv[1], (char **) EncryptList, sizeof(struct encryptlist)); if (c == 0) { fprintf(stderr, "'%s': unknown argument ('encrypt ?' for help).\n", argv[1]); return 0; } if (Ambiguous(c)) { fprintf(stderr, "'%s': ambiguous argument ('encrypt ?' for help).\n", argv[1]); return 0; } argc -= 2; if (argc < c->minarg || argc > c->maxarg) { if (c->minarg == c->maxarg) { fprintf(stderr, "Need %s%d argument%s ", c->minarg < argc ? "only " : "", c->minarg, c->minarg == 1 ? "" : "s"); } else { fprintf(stderr, "Need %s%d-%d arguments ", c->maxarg < argc ? "only " : "", c->minarg, c->maxarg); } fprintf(stderr, "to 'encrypt %s' command. 'encrypt ?' for help.\n", c->name); return 0; } if (c->needconnect && !connected) { if (!(argc && (isprefix(argv[2], "help") || isprefix(argv[2], "?")))) { printf("?Need to be connected first.\n"); return 0; } } return ((*c->handler)(argc > 0 ? argv[2] : 0, argc > 1 ? argv[3] : 0, argc > 2 ? argv[4] : 0)); } #endif /* ENCRYPTION */ #if defined(unix) && defined(TN3270) static void filestuff(fd) int fd; { int res; #ifdef F_GETOWN setconnmode(0); res = fcntl(fd, F_GETOWN, 0); setcommandmode(); if (res == -1) { perror("fcntl"); return; } printf("\tOwner is %d.\n", res); #endif setconnmode(0); res = fcntl(fd, F_GETFL, 0); setcommandmode(); if (res == -1) { perror("fcntl"); return; } #ifdef notdef printf("\tFlags are 0x%x: %s\n", res, decodeflags(res)); #endif } #endif /* defined(unix) && defined(TN3270) */ /* * Print status about the connection. */ /*ARGSUSED*/ - static + static int status(argc, argv) int argc; char *argv[]; { if (connected) { printf("Connected to %s.\n", hostname); if ((argc < 2) || strcmp(argv[1], "notmuch")) { int mode = getconnmode(); if (my_want_state_is_will(TELOPT_LINEMODE)) { printf("Operating with LINEMODE option\n"); printf("%s line editing\n", (mode&MODE_EDIT) ? "Local" : "No"); printf("%s catching of signals\n", (mode&MODE_TRAPSIG) ? "Local" : "No"); slcstate(); #ifdef KLUDGELINEMODE } else if (kludgelinemode && my_want_state_is_dont(TELOPT_SGA)) { printf("Operating in obsolete linemode\n"); #endif } else { printf("Operating in single character mode\n"); if (localchars) printf("Catching signals locally\n"); } printf("%s character echo\n", (mode&MODE_ECHO) ? "Local" : "Remote"); if (my_want_state_is_will(TELOPT_LFLOW)) printf("%s flow control\n", (mode&MODE_FLOW) ? "Local" : "No"); #ifdef ENCRYPTION encrypt_display(); #endif /* ENCRYPTION */ } } else { printf("No connection.\n"); } # if !defined(TN3270) printf("Escape character is '%s'.\n", control(escape)); (void) fflush(stdout); # else /* !defined(TN3270) */ if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) { printf("Escape character is '%s'.\n", control(escape)); } # if defined(unix) if ((argc >= 2) && !strcmp(argv[1], "everything")) { printf("SIGIO received %d time%s.\n", sigiocount, (sigiocount == 1)? "":"s"); if (In3270) { printf("Process ID %d, process group %d.\n", getpid(), getpgrp(getpid())); printf("Terminal input:\n"); filestuff(tin); printf("Terminal output:\n"); filestuff(tout); printf("Network socket:\n"); filestuff(net); } } if (In3270 && transcom) { printf("Transparent mode command is '%s'.\n", transcom); } # endif /* defined(unix) */ (void) fflush(stdout); if (In3270) { return 0; } # endif /* defined(TN3270) */ return 1; } #ifdef SIGINFO /* * Function that gets called when SIGINFO is received. */ + void ayt_status() { (void) call(status, "status", "notmuch", 0); } #endif unsigned long inet_addr(); int tn(argc, argv) int argc; char *argv[]; { register struct hostent *host = 0; struct sockaddr_in sin; struct servent *sp = 0; unsigned long temp; extern char *inet_ntoa(); #if defined(IP_OPTIONS) && defined(IPPROTO_IP) char *srp = 0, *strrchr(); unsigned long sourceroute(), srlen; #endif char *cmd, *hostp = 0, *portp = 0, *user = 0; /* clear the socket address prior to use */ memset((char *)&sin, 0, sizeof(sin)); if (connected) { printf("?Already connected to %s\n", hostname); setuid(getuid()); return 0; } if (argc < 2) { (void) strcpy(line, "open "); printf("(to) "); (void) fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin); makeargv(); argc = margc; argv = margv; } cmd = *argv; --argc; ++argv; while (argc) { if (strcmp(*argv, "help") == 0 || isprefix(*argv, "?")) goto usage; if (strcmp(*argv, "-l") == 0) { --argc; ++argv; if (argc == 0) goto usage; user = *argv++; --argc; continue; } if (strcmp(*argv, "-a") == 0) { --argc; ++argv; autologin = 1; continue; } if (hostp == 0) { hostp = *argv++; --argc; continue; } if (portp == 0) { portp = *argv++; --argc; continue; } usage: printf("usage: %s [-l user] [-a] host-name [port]\n", cmd); setuid(getuid()); return 0; } if (hostp == 0) goto usage; #if defined(IP_OPTIONS) && defined(IPPROTO_IP) if (hostp[0] == '@' || hostp[0] == '!') { if ((hostname = strrchr(hostp, ':')) == NULL) hostname = strrchr(hostp, '@'); hostname++; srp = 0; temp = sourceroute(hostp, &srp, &srlen); if (temp == 0) { herror(srp); setuid(getuid()); return 0; } else if (temp == -1) { printf("Bad source route option: %s\n", hostp); setuid(getuid()); return 0; } else { sin.sin_addr.s_addr = temp; sin.sin_family = AF_INET; } } else { #endif temp = inet_addr(hostp); - if (temp != (unsigned long) -1) { + if (temp != INADDR_NONE) { sin.sin_addr.s_addr = temp; sin.sin_family = AF_INET; - (void) strcpy(_hostname, hostp); + host = gethostbyaddr((char *)&temp, sizeof(temp), AF_INET); + if (host) + (void) strncpy(_hostname, host->h_name, sizeof(_hostname)); + else + (void) strncpy(_hostname, hostp, sizeof(_hostname)); + _hostname[sizeof(_hostname)-1] = '\0'; hostname = _hostname; } else { host = gethostbyname(hostp); if (host) { sin.sin_family = host->h_addrtype; #if defined(h_addr) /* In 4.3, this is a #define */ memmove((caddr_t)&sin.sin_addr, host->h_addr_list[0], host->h_length); #else /* defined(h_addr) */ memmove((caddr_t)&sin.sin_addr, host->h_addr, host->h_length); #endif /* defined(h_addr) */ strncpy(_hostname, host->h_name, sizeof(_hostname)); _hostname[sizeof(_hostname)-1] = '\0'; hostname = _hostname; } else { herror(hostp); setuid(getuid()); return 0; } } #if defined(IP_OPTIONS) && defined(IPPROTO_IP) } #endif if (portp) { if (*portp == '-') { portp++; telnetport = 1; } else telnetport = 0; sin.sin_port = atoi(portp); if (sin.sin_port == 0) { sp = getservbyname(portp, "tcp"); if (sp) sin.sin_port = sp->s_port; else { printf("%s: bad port number\n", portp); setuid(getuid()); return 0; } } else { #if !defined(htons) u_short htons P((unsigned short)); #endif /* !defined(htons) */ sin.sin_port = htons(sin.sin_port); } } else { if (sp == 0) { sp = getservbyname("telnet", "tcp"); if (sp == 0) { fprintf(stderr, "telnet: tcp/telnet: unknown service\n"); setuid(getuid()); return 0; } sin.sin_port = sp->s_port; } telnetport = 1; } printf("Trying %s...\n", inet_ntoa(sin.sin_addr)); do { net = socket(AF_INET, SOCK_STREAM, 0); setuid(getuid()); if (net < 0) { perror("telnet: socket"); return 0; } #if defined(IP_OPTIONS) && defined(IPPROTO_IP) if (srp && setsockopt(net, IPPROTO_IP, IP_OPTIONS, (char *)srp, srlen) < 0) perror("setsockopt (IP_OPTIONS)"); #endif #if defined(IPPROTO_IP) && defined(IP_TOS) { # if defined(HAS_GETTOS) 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(net, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0) && (errno != ENOPROTOOPT)) perror("telnet: setsockopt (IP_TOS) (ignored)"); } #endif /* defined(IPPROTO_IP) && defined(IP_TOS) */ if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) { perror("setsockopt (SO_DEBUG)"); } if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) { #if defined(h_addr) /* In 4.3, this is a #define */ if (host && host->h_addr_list[1]) { int oerrno = errno; fprintf(stderr, "telnet: connect to address %s: ", inet_ntoa(sin.sin_addr)); errno = oerrno; perror((char *)0); host->h_addr_list++; memmove((caddr_t)&sin.sin_addr, host->h_addr_list[0], host->h_length); (void) NetClose(net); continue; } #endif /* defined(h_addr) */ perror("telnet: Unable to connect to remote host"); return 0; } connected++; #if defined(AUTHENTICATION) || defined(ENCRYPTION) auth_encrypt_connect(connected); #endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */ } while (connected == 0); cmdrc(hostp, hostname); if (autologin && user == NULL) { struct passwd *pw; user = getenv("USER"); if (user == NULL || - (pw = getpwnam(user)) && pw->pw_uid != getuid()) { - if (pw = getpwuid(getuid())) + ((pw = getpwnam(user)) && pw->pw_uid != getuid())) { + if ((pw = getpwuid(getuid()))) user = pw->pw_name; else user = NULL; } } if (user) { env_define((unsigned char *)"USER", (unsigned char *)user); env_export((unsigned char *)"USER"); } (void) call(status, "status", "notmuch", 0); if (setjmp(peerdied) == 0) telnet(user); (void) NetClose(net); ExitString("Connection closed by foreign host.\n",1); /*NOTREACHED*/ } #define HELPINDENT (sizeof ("connect")) static char openhelp[] = "connect to a site", closehelp[] = "close current connection", logouthelp[] = "forcibly logout remote user and close the connection", quithelp[] = "exit telnet", statushelp[] = "print status information", helphelp[] = "print help information", sendhelp[] = "transmit special characters ('send ?' for more)", sethelp[] = "set operating parameters ('set ?' for more)", unsethelp[] = "unset operating parameters ('unset ?' for more)", togglestring[] ="toggle operating parameters ('toggle ?' for more)", slchelp[] = "change state of special charaters ('slc ?' for more)", displayhelp[] = "display operating parameters", #if defined(TN3270) && defined(unix) transcomhelp[] = "specify Unix command for transparent mode pipe", #endif /* defined(TN3270) && defined(unix) */ #if defined(AUTHENTICATION) authhelp[] = "turn on (off) authentication ('auth ?' for more)", #endif #ifdef ENCRYPTION encrypthelp[] = "turn on (off) encryption ('encrypt ?' for more)", #endif /* ENCRYPTION */ #if defined(unix) zhelp[] = "suspend telnet", #endif /* defined(unix) */ +#if defined(SKEY) + skeyhelp[] = "compute response to s/key challenge", +#endif shellhelp[] = "invoke a subshell", envhelp[] = "change environment variables ('environ ?' for more)", modestring[] = "try to enter line or character mode ('mode ?' for more)"; -static int help(); - static Command cmdtab[] = { { "close", closehelp, bye, 1 }, { "logout", logouthelp, logout, 1 }, { "display", displayhelp, display, 0 }, { "mode", modestring, modecmd, 0 }, { "open", openhelp, tn, 0 }, { "quit", quithelp, quit, 0 }, { "send", sendhelp, sendcmd, 0 }, { "set", sethelp, setcmd, 0 }, { "unset", unsethelp, unsetcmd, 0 }, { "status", statushelp, status, 0 }, { "toggle", togglestring, toggle, 0 }, { "slc", slchelp, slccmd, 0 }, #if defined(TN3270) && defined(unix) { "transcom", transcomhelp, settranscom, 0 }, #endif /* defined(TN3270) && defined(unix) */ #if defined(AUTHENTICATION) { "auth", authhelp, auth_cmd, 0 }, #endif #ifdef ENCRYPTION { "encrypt", encrypthelp, encrypt_cmd, 0 }, #endif /* ENCRYPTION */ #if defined(unix) { "z", zhelp, suspend, 0 }, #endif /* defined(unix) */ #if defined(TN3270) { "!", shellhelp, shell, 1 }, #else { "!", shellhelp, shell, 0 }, #endif { "environ", envhelp, env_cmd, 0 }, { "?", helphelp, help, 0 }, - 0 +#if defined(SKEY) + { "skey", skeyhelp, skey_calc, 0 }, +#endif + { 0, 0, 0, 0 } }; static char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead"; static char escapehelp[] = "deprecated command -- use 'set escape' instead"; static Command cmdtab2[] = { { "help", 0, help, 0 }, { "escape", escapehelp, setescape, 0 }, { "crmod", crmodhelp, togcrmod, 0 }, - 0 + { 0, 0, 0, 0 } }; /* * Call routine with argc, argv set from args (terminated by 0). */ /*VARARGS1*/ - static + static int call(va_alist) va_dcl { va_list ap; typedef int (*intrtn_t)(); intrtn_t routine; char *args[100]; int argno = 0; va_start(ap); routine = (va_arg(ap, intrtn_t)); while ((args[argno++] = va_arg(ap, char *)) != 0) { ; } va_end(ap); return (*routine)(argno-1, args); } static Command * getcmd(name) char *name; { Command *cm; - if (cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command))) + if ((cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command)))) return cm; return (Command *) genget(name, (char **) cmdtab2, sizeof(Command)); } void command(top, tbuf, cnt) int top; char *tbuf; int cnt; { register Command *c; setcommandmode(); if (!top) { putchar('\n'); #if defined(unix) } else { (void) signal(SIGINT, SIG_DFL); (void) signal(SIGQUIT, SIG_DFL); #endif /* defined(unix) */ } for (;;) { if (rlogin == _POSIX_VDISABLE) printf("%s> ", prompt); if (tbuf) { register char *cp; cp = line; while (cnt > 0 && (*cp++ = *tbuf++) != '\n') cnt--; tbuf = 0; if (cp == line || *--cp != '\n' || cp == line) goto getline; *cp = '\0'; if (rlogin == _POSIX_VDISABLE) printf("%s\n", line); } else { getline: if (rlogin != _POSIX_VDISABLE) printf("%s> ", prompt); if (fgets(line, sizeof(line), stdin) == NULL) { if (feof(stdin) || ferror(stdin)) { (void) quit(); /*NOTREACHED*/ } break; } } if (line[0] == 0) break; makeargv(); if (margv[0] == 0) { break; } c = getcmd(margv[0]); if (Ambiguous(c)) { printf("?Ambiguous command\n"); continue; } if (c == 0) { printf("?Invalid command\n"); continue; } if (c->needconnect && !connected) { printf("?Need to be connected first.\n"); continue; } if ((*c->handler)(margc, margv)) { break; } } if (!top) { if (!connected) { longjmp(toplevel, 1); /*NOTREACHED*/ } #if defined(TN3270) if (shell_active == 0) { setconnmode(0); } #else /* defined(TN3270) */ setconnmode(0); #endif /* defined(TN3270) */ } } /* * Help command. */ - static + static int help(argc, argv) int argc; char *argv[]; { register Command *c; if (argc == 1) { printf("Commands may be abbreviated. Commands are:\n\n"); for (c = cmdtab; c->name; c++) if (c->help) { printf("%-*s\t%s\n", HELPINDENT, c->name, c->help); } - return 0; } - while (--argc > 0) { + else while (--argc > 0) { register char *arg; arg = *++argv; c = getcmd(arg); if (Ambiguous(c)) printf("?Ambiguous help command %s\n", arg); else if (c == (Command *)0) printf("?Invalid help command %s\n", arg); else printf("%s\n", c->help); } - return 0; + return(0); } static char *rcname = 0; static char rcbuf[128]; + void cmdrc(m1, m2) char *m1, *m2; { register Command *c; FILE *rcfile; int gotmachine = 0; int l1 = strlen(m1); int l2 = strlen(m2); char m1save[64]; if (skiprc) return; strcpy(m1save, m1); m1 = m1save; if (rcname == 0) { rcname = getenv("HOME"); - if (rcname) + if (rcname && (strlen(rcname) + 10) < sizeof(rcbuf)) strcpy(rcbuf, rcname); else rcbuf[0] = '\0'; strcat(rcbuf, "/.telnetrc"); rcname = rcbuf; } if ((rcfile = fopen(rcname, "r")) == 0) { return; } for (;;) { if (fgets(line, sizeof(line), rcfile) == NULL) break; if (line[0] == 0) break; if (line[0] == '#') continue; if (gotmachine) { if (!isspace(line[0])) gotmachine = 0; } if (gotmachine == 0) { if (isspace(line[0])) continue; if (strncasecmp(line, m1, l1) == 0) strncpy(line, &line[l1], sizeof(line) - l1); else if (strncasecmp(line, m2, l2) == 0) strncpy(line, &line[l2], sizeof(line) - l2); else if (strncasecmp(line, "DEFAULT", 7) == 0) strncpy(line, &line[7], sizeof(line) - 7); else continue; if (line[0] != ' ' && line[0] != '\t' && line[0] != '\n') continue; gotmachine = 1; } makeargv(); if (margv[0] == 0) continue; c = getcmd(margv[0]); if (Ambiguous(c)) { printf("?Ambiguous command: %s\n", margv[0]); continue; } if (c == 0) { printf("?Invalid command: %s\n", margv[0]); continue; } /* * This should never happen... */ if (c->needconnect && !connected) { printf("?Need to be connected first for %s.\n", margv[0]); continue; } (*c->handler)(margc, margv); } fclose(rcfile); } #if defined(IP_OPTIONS) && defined(IPPROTO_IP) /* * Source route is handed in as * [!]@hop1@hop2...[@|:]dst * If the leading ! is present, it is a * strict source route, otherwise it is * assmed to be a loose source route. * * We fill in the source route option as * hop1,hop2,hop3...dest * and return a pointer to hop1, which will * be the address to connect() to. * * Arguments: * arg: pointer to route list to decipher * * cpp: If *cpp is not equal to NULL, this is a * pointer to a pointer to a character array * that should be filled in with the option. * * lenp: pointer to an integer that contains the * length of *cpp if *cpp != NULL. * * Return values: * * Returns the address of the host to connect to. If the * return value is -1, there was a syntax error in the * option, either unknown characters, or too many hosts. * If the return value is 0, one of the hostnames in the * path is unknown, and *cpp is set to point to the bad * hostname. * * *cpp: If *cpp was equal to NULL, it will be filled * in with a pointer to our static area that has * the option filled in. This will be 32bit aligned. * * *lenp: This will be filled in with how long the option * pointed to by *cpp is. * */ unsigned long sourceroute(arg, cpp, lenp) char *arg; char **cpp; int *lenp; { static char lsr[44]; #ifdef sysV88 static IOPTN ipopt; #endif char *cp, *cp2, *lsrp, *lsrep; register int tmp; struct in_addr sin_addr; register struct hostent *host = 0; register char c; /* * Verify the arguments, and make sure we have * at least 7 bytes for the option. */ if (cpp == NULL || lenp == NULL) return((unsigned long)-1); if (*cpp != NULL && *lenp < 7) return((unsigned long)-1); /* * Decide whether we have a buffer passed to us, * or if we need to use our own static buffer. */ if (*cpp) { lsrp = *cpp; lsrep = lsrp + *lenp; } else { *cpp = lsrp = lsr; lsrep = lsrp + 44; } cp = arg; /* * Next, decide whether we have a loose source * route or a strict source route, and fill in * the begining of the option. */ #ifndef sysV88 if (*cp == '!') { cp++; *lsrp++ = IPOPT_SSRR; } else *lsrp++ = IPOPT_LSRR; #else if (*cp == '!') { cp++; ipopt.io_type = IPOPT_SSRR; } else ipopt.io_type = IPOPT_LSRR; #endif if (*cp != '@') return((unsigned long)-1); #ifndef sysV88 lsrp++; /* skip over length, we'll fill it in later */ *lsrp++ = 4; #endif cp++; sin_addr.s_addr = 0; for (c = 0;;) { if (c == ':') cp2 = 0; - else for (cp2 = cp; c = *cp2; cp2++) { + else for (cp2 = cp; (c = *cp2); cp2++) { if (c == ',') { *cp2++ = '\0'; if (*cp2 == '@') cp2++; } else if (c == '@') { *cp2++ = '\0'; } else if (c == ':') { *cp2++ = '\0'; } else continue; break; } if (!c) cp2 = 0; if ((tmp = inet_addr(cp)) != -1) { sin_addr.s_addr = tmp; - } else if (host = gethostbyname(cp)) { + } else if ((host = gethostbyname(cp))) { #if defined(h_addr) memmove((caddr_t)&sin_addr, host->h_addr_list[0], host->h_length); #else memmove((caddr_t)&sin_addr, host->h_addr, host->h_length); #endif } else { *cpp = cp; return(0); } memmove(lsrp, (char *)&sin_addr, 4); lsrp += 4; if (cp2) cp = cp2; else break; /* * Check to make sure there is space for next address */ if (lsrp + 4 > lsrep) return((unsigned long)-1); } #ifndef sysV88 if ((*(*cpp+IPOPT_OLEN) = lsrp - *cpp) <= 7) { *cpp = 0; *lenp = 0; return((unsigned long)-1); } *lsrp++ = IPOPT_NOP; /* 32 bit word align it */ *lenp = lsrp - *cpp; #else ipopt.io_len = lsrp - *cpp; if (ipopt.io_len <= 5) { /* Is 3 better ? */ *cpp = 0; *lenp = 0; return((unsigned long)-1); } *lenp = sizeof(ipopt); *cpp = (char *) &ipopt; #endif return(sin_addr.s_addr); } #endif diff --git a/contrib/telnet/telnet/externs.h b/contrib/telnet/telnet/externs.h index 83ba07b2d486..a834c61c39df 100644 --- a/contrib/telnet/telnet/externs.h +++ b/contrib/telnet/telnet/externs.h @@ -1,482 +1,491 @@ /* * Copyright (c) 1988, 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. * * @(#)externs.h 8.3 (Berkeley) 5/30/95 */ #ifndef BSD # define BSD 43 #endif /* * ucb stdio.h defines BSD as something wierd */ #if defined(sun) && defined(__svr4__) #define BSD 43 #endif #ifndef USE_TERMIO # if BSD > 43 || defined(SYSV_TERMIO) # define USE_TERMIO # endif #endif #include #include #if defined(CRAY) && !defined(NO_BSD_SETJMP) #include #endif #ifndef FILIO_H #include #else #include #endif #ifdef CRAY # include #endif /* CRAY */ #ifdef USE_TERMIO # ifndef VINTR # ifdef SYSV_TERMIO # include # else # include # define termio termios # endif # endif #endif #if defined(NO_CC_T) || !defined(USE_TERMIO) # if !defined(USE_TERMIO) typedef char cc_t; # else typedef unsigned char cc_t; # endif #endif #ifndef NO_STRING_H #include #else #include #endif #ifndef _POSIX_VDISABLE # ifdef sun # include /* pick up VDISABLE definition, mayby */ # endif # ifdef VDISABLE # define _POSIX_VDISABLE VDISABLE # else # define _POSIX_VDISABLE ((cc_t)'\377') # endif #endif #define SUBBUFSIZE 256 #ifndef CRAY extern int errno; /* outside this world */ #endif /* !CRAY */ #if !defined(P) # ifdef __STDC__ # define P(x) x # else # define P(x) () # endif #endif extern int autologin, /* Autologin enabled */ skiprc, /* Don't process the ~/.telnetrc file */ eight, /* use eight bit mode (binary in and/or out */ flushout, /* flush output */ connected, /* Are we connected to the other side? */ globalmode, /* Mode tty should be in */ In3270, /* Are we in 3270 mode? */ telnetport, /* Are we connected to the telnet port? */ localflow, /* Flow control handled locally */ restartany, /* If flow control, restart output on any character */ localchars, /* we recognize interrupt/quit */ donelclchars, /* the user has set "localchars" */ showoptions, net, /* Network file descriptor */ tin, /* Terminal input file descriptor */ tout, /* Terminal output file descriptor */ crlf, /* Should '\r' be mapped to (or )? */ autoflush, /* flush output when interrupting? */ autosynch, /* send interrupt characters with SYNCH? */ SYNCHing, /* Is the stream in telnet SYNCH mode? */ donebinarytoggle, /* the user has put us in binary */ dontlecho, /* do we suppress local echoing right now? */ crmod, netdata, /* Print out network data flow */ prettydump, /* Print "netdata" output in user readable format */ #if defined(unix) #if defined(TN3270) cursesdata, /* Print out curses data flow */ apitrace, /* Trace API transactions */ #endif /* defined(TN3270) */ termdata, /* Print out terminal data flow */ #endif /* defined(unix) */ - debug; /* Debug level */ + debug, /* Debug level */ + clienteof; /* Client received EOF */ extern cc_t escape; /* Escape to command mode */ extern cc_t rlogin; /* Rlogin mode escape character */ #ifdef KLUDGELINEMODE extern cc_t echoc; /* Toggle local echoing */ #endif extern char *prompt; /* Prompt for command. */ extern char doopt[], dont[], will[], wont[], options[], /* All the little options */ *hostname; /* Who are we connected to? */ #ifdef ENCRYPTION extern void (*encrypt_output) P((unsigned char *, int)); extern int (*decrypt_input) P((int)); #endif /* ENCRYPTION */ /* * We keep track of each side of the option negotiation. */ #define MY_STATE_WILL 0x01 #define MY_WANT_STATE_WILL 0x02 #define MY_STATE_DO 0x04 #define MY_WANT_STATE_DO 0x08 /* * Macros to check the current state of things */ #define my_state_is_do(opt) (options[opt]&MY_STATE_DO) #define my_state_is_will(opt) (options[opt]&MY_STATE_WILL) #define my_want_state_is_do(opt) (options[opt]&MY_WANT_STATE_DO) #define my_want_state_is_will(opt) (options[opt]&MY_WANT_STATE_WILL) #define my_state_is_dont(opt) (!my_state_is_do(opt)) #define my_state_is_wont(opt) (!my_state_is_will(opt)) #define my_want_state_is_dont(opt) (!my_want_state_is_do(opt)) #define my_want_state_is_wont(opt) (!my_want_state_is_will(opt)) #define set_my_state_do(opt) {options[opt] |= MY_STATE_DO;} #define set_my_state_will(opt) {options[opt] |= MY_STATE_WILL;} #define set_my_want_state_do(opt) {options[opt] |= MY_WANT_STATE_DO;} #define set_my_want_state_will(opt) {options[opt] |= MY_WANT_STATE_WILL;} #define set_my_state_dont(opt) {options[opt] &= ~MY_STATE_DO;} #define set_my_state_wont(opt) {options[opt] &= ~MY_STATE_WILL;} #define set_my_want_state_dont(opt) {options[opt] &= ~MY_WANT_STATE_DO;} #define set_my_want_state_wont(opt) {options[opt] &= ~MY_WANT_STATE_WILL;} /* * Make everything symetrical */ #define HIS_STATE_WILL MY_STATE_DO #define HIS_WANT_STATE_WILL MY_WANT_STATE_DO #define HIS_STATE_DO MY_STATE_WILL #define HIS_WANT_STATE_DO MY_WANT_STATE_WILL #define his_state_is_do my_state_is_will #define his_state_is_will my_state_is_do #define his_want_state_is_do my_want_state_is_will #define his_want_state_is_will my_want_state_is_do #define his_state_is_dont my_state_is_wont #define his_state_is_wont my_state_is_dont #define his_want_state_is_dont my_want_state_is_wont #define his_want_state_is_wont my_want_state_is_dont #define set_his_state_do set_my_state_will #define set_his_state_will set_my_state_do #define set_his_want_state_do set_my_want_state_will #define set_his_want_state_will set_my_want_state_do #define set_his_state_dont set_my_state_wont #define set_his_state_wont set_my_state_dont #define set_his_want_state_dont set_my_want_state_wont #define set_his_want_state_wont set_my_want_state_dont extern FILE *NetTrace; /* Where debugging output goes */ extern unsigned char NetTraceFile[]; /* Name of file where debugging output goes */ extern void SetNetTrace P((char *)); /* Function to change where debugging goes */ extern jmp_buf peerdied, toplevel; /* For error conditions. */ extern void command P((int, char *, int)), Dump P((int, unsigned char *, int)), + ExitString P((char *, int)), init_3270 P((void)), printoption P((char *, int, int)), printsub P((int, unsigned char *, int)), sendnaws P((void)), setconnmode P((int)), setcommandmode P((void)), setneturg P((void)), sys_telnet_init P((void)), telnet P((char *)), tel_enter_binary P((int)), TerminalFlushOutput P((void)), TerminalNewMode P((int)), TerminalRestoreState P((void)), TerminalSaveState P((void)), tninit P((void)), upcase P((char *)), willoption P((int)), wontoption P((int)); extern void send_do P((int, int)), send_dont P((int, int)), send_will P((int, int)), send_wont P((int, int)); extern void lm_will P((unsigned char *, int)), lm_wont P((unsigned char *, int)), lm_do P((unsigned char *, int)), lm_dont P((unsigned char *, int)), lm_mode P((unsigned char *, int, int)); extern void slc_init P((void)), slcstate P((void)), slc_mode_export P((void)), slc_mode_import P((int)), slc_import P((int)), slc_export P((void)), slc P((unsigned char *, int)), slc_check P((void)), slc_start_reply P((void)), slc_add_reply P((int, int, int)), slc_end_reply P((void)); extern int - slc_update P((void)); + NetClose P((int)), + netflush P((void)), + SetSockOpt P((int, int, int, int)), + slc_update P((void)), + telrcv P((void)), + TerminalWrite P((char *, int)), + TerminalAutoFlush P((void)), + ttyflush P((int)); extern void env_opt P((unsigned char *, int)), env_opt_start P((void)), env_opt_start_info P((void)), env_opt_add P((unsigned char *)), env_opt_end P((int)); extern unsigned char *env_default P((int, int)), *env_getvalue P((unsigned char *)); extern int get_status P((void)), dosynch P((void)); extern cc_t *tcval P((int)); #ifndef USE_TERMIO extern struct tchars ntc; extern struct ltchars nltc; extern struct sgttyb nttyb; # define termEofChar ntc.t_eofc # define termEraseChar nttyb.sg_erase # define termFlushChar nltc.t_flushc # define termIntChar ntc.t_intrc # define termKillChar nttyb.sg_kill # define termLiteralNextChar nltc.t_lnextc # define termQuitChar ntc.t_quitc # define termSuspChar nltc.t_suspc # define termRprntChar nltc.t_rprntc # define termWerasChar nltc.t_werasc # define termStartChar ntc.t_startc # define termStopChar ntc.t_stopc # define termForw1Char ntc.t_brkc extern cc_t termForw2Char; extern cc_t termAytChar; # define termEofCharp (cc_t *)&ntc.t_eofc # define termEraseCharp (cc_t *)&nttyb.sg_erase # define termFlushCharp (cc_t *)&nltc.t_flushc # define termIntCharp (cc_t *)&ntc.t_intrc # define termKillCharp (cc_t *)&nttyb.sg_kill # define termLiteralNextCharp (cc_t *)&nltc.t_lnextc # define termQuitCharp (cc_t *)&ntc.t_quitc # define termSuspCharp (cc_t *)&nltc.t_suspc # define termRprntCharp (cc_t *)&nltc.t_rprntc # define termWerasCharp (cc_t *)&nltc.t_werasc # define termStartCharp (cc_t *)&ntc.t_startc # define termStopCharp (cc_t *)&ntc.t_stopc # define termForw1Charp (cc_t *)&ntc.t_brkc # define termForw2Charp (cc_t *)&termForw2Char # define termAytCharp (cc_t *)&termAytChar # else extern struct termio new_tc; # define termEofChar new_tc.c_cc[VEOF] # define termEraseChar new_tc.c_cc[VERASE] # define termIntChar new_tc.c_cc[VINTR] # define termKillChar new_tc.c_cc[VKILL] # define termQuitChar new_tc.c_cc[VQUIT] # ifndef VSUSP extern cc_t termSuspChar; # else # define termSuspChar new_tc.c_cc[VSUSP] # endif # if defined(VFLUSHO) && !defined(VDISCARD) # define VDISCARD VFLUSHO # endif # ifndef VDISCARD extern cc_t termFlushChar; # else # define termFlushChar new_tc.c_cc[VDISCARD] # endif # ifndef VWERASE extern cc_t termWerasChar; # else # define termWerasChar new_tc.c_cc[VWERASE] # endif # ifndef VREPRINT extern cc_t termRprntChar; # else # define termRprntChar new_tc.c_cc[VREPRINT] # endif # ifndef VLNEXT extern cc_t termLiteralNextChar; # else # define termLiteralNextChar new_tc.c_cc[VLNEXT] # endif # ifndef VSTART extern cc_t termStartChar; # else # define termStartChar new_tc.c_cc[VSTART] # endif # ifndef VSTOP extern cc_t termStopChar; # else # define termStopChar new_tc.c_cc[VSTOP] # endif # ifndef VEOL extern cc_t termForw1Char; # else # define termForw1Char new_tc.c_cc[VEOL] # endif # ifndef VEOL2 extern cc_t termForw2Char; # else # define termForw2Char new_tc.c_cc[VEOL] # endif # ifndef VSTATUS extern cc_t termAytChar; #else # define termAytChar new_tc.c_cc[VSTATUS] #endif # if !defined(CRAY) || defined(__STDC__) # define termEofCharp &termEofChar # define termEraseCharp &termEraseChar # define termIntCharp &termIntChar # define termKillCharp &termKillChar # define termQuitCharp &termQuitChar # define termSuspCharp &termSuspChar # define termFlushCharp &termFlushChar # define termWerasCharp &termWerasChar # define termRprntCharp &termRprntChar # define termLiteralNextCharp &termLiteralNextChar # define termStartCharp &termStartChar # define termStopCharp &termStopChar # define termForw1Charp &termForw1Char # define termForw2Charp &termForw2Char # define termAytCharp &termAytChar # else /* Work around a compiler bug */ # define termEofCharp 0 # define termEraseCharp 0 # define termIntCharp 0 # define termKillCharp 0 # define termQuitCharp 0 # define termSuspCharp 0 # define termFlushCharp 0 # define termWerasCharp 0 # define termRprntCharp 0 # define termLiteralNextCharp 0 # define termStartCharp 0 # define termStopCharp 0 # define termForw1Charp 0 # define termForw2Charp 0 # define termAytCharp 0 # endif #endif /* Ring buffer structures which are shared */ extern Ring netoring, netiring, ttyoring, ttyiring; /* Tn3270 section */ #if defined(TN3270) extern int HaveInput, /* Whether an asynchronous I/O indication came in */ noasynchtty, /* Don't do signals on I/O (SIGURG, SIGIO) */ noasynchnet, /* Don't do signals on I/O (SIGURG, SIGIO) */ sigiocount, /* Count of SIGIO receptions */ shell_active; /* Subshell is active */ extern char *Ibackp, /* Oldest byte of 3270 data */ Ibuf[], /* 3270 buffer */ *Ifrontp, /* Where next 3270 byte goes */ tline[], *transcom; /* Transparent command */ extern int settranscom P((int, char**)); extern void inputAvailable P((int)); #endif /* defined(TN3270) */ diff --git a/contrib/telnet/telnet/main.c b/contrib/telnet/telnet/main.c index 6073dbf8ec4a..9049385e200f 100644 --- a/contrib/telnet/telnet/main.c +++ b/contrib/telnet/telnet/main.c @@ -1,322 +1,337 @@ /* * Copyright (c) 1988, 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. */ #ifndef lint -static char copyright[] = +static const char copyright[] = "@(#) Copyright (c) 1988, 1990, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)main.c 8.3 (Berkeley) 5/30/95"; +static const char sccsid[] = "@(#)main.c 8.3 (Berkeley) 5/30/95"; #endif /* not lint */ #include +#include #include "ring.h" #include "externs.h" #include "defines.h" +#if defined(AUTHENTICATION) +#include +#endif +#if defined(ENCRYPTION) +#include +#endif + /* These values need to be the same as defined in libtelnet/kerberos5.c */ /* Either define them in both places, or put in some common header file. */ #define OPTS_FORWARD_CREDS 0x00000002 #define OPTS_FORWARDABLE_CREDS 0x00000001 #if 0 #define FORWARD #endif +void init_terminal(void); +void init_network(void); +void init_telnet(void); +void init_sys(void); +void init_3270(void); + /* * Initialize variables. */ void tninit() { init_terminal(); init_network(); init_telnet(); init_sys(); #if defined(TN3270) init_3270(); #endif } void usage() { fprintf(stderr, "Usage: %s %s%s%s%s\n", prompt, #ifdef AUTHENTICATION "[-8] [-E] [-K] [-L] [-S tos] [-X atype] [-a] [-c] [-d] [-e char]", "\n\t[-k realm] [-l user] [-f/-F] [-n tracefile] ", #else "[-8] [-E] [-L] [-S tos] [-a] [-c] [-d] [-e char] [-l user]", "\n\t[-n tracefile]", #endif #if defined(TN3270) && defined(unix) # ifdef AUTHENTICATION "[-noasynch] [-noasynctty]\n\t[-noasyncnet] [-r] [-t transcom] ", # else "[-noasynch] [-noasynctty] [-noasyncnet] [-r]\n\t[-t transcom]", # endif #else "[-r] ", #endif #ifdef ENCRYPTION "[-x] [host-name [port]]" #else /* ENCRYPTION */ "[host-name [port]]" #endif /* ENCRYPTION */ ); exit(1); } /* * main. Parse arguments, invoke the protocol or command parser. */ - + int main(argc, argv) int argc; char *argv[]; { extern char *optarg; extern int optind; int ch; char *user, *strrchr(); #ifdef FORWARD extern int forward_flags; #endif /* FORWARD */ tninit(); /* Clear out things */ #if defined(CRAY) && !defined(__STDC__) _setlist_init(); /* Work around compiler bug */ #endif TerminalSaveState(); - if (prompt = strrchr(argv[0], '/')) + if ((prompt = strrchr(argv[0], '/'))) ++prompt; else prompt = argv[0]; user = NULL; rlogin = (strncmp(prompt, "rlog", 4) == 0) ? '~' : _POSIX_VDISABLE; autologin = -1; while ((ch = getopt(argc, argv, "8EKLS:X:acde:fFk:l:n:rt:x")) != EOF) { switch(ch) { case '8': eight = 3; /* binary output and input */ break; case 'E': rlogin = escape = _POSIX_VDISABLE; break; case 'K': #ifdef AUTHENTICATION autologin = 0; #endif break; case 'L': eight |= 2; /* binary output only */ break; case 'S': { #ifdef HAS_GETTOS extern int tos; if ((tos = parsetos(optarg, "tcp")) < 0) fprintf(stderr, "%s%s%s%s\n", prompt, ": Bad TOS argument '", optarg, "; will try to use default TOS"); #else fprintf(stderr, "%s: Warning: -S ignored, no parsetos() support.\n", prompt); #endif } break; case 'X': #ifdef AUTHENTICATION auth_disable_name(optarg); #endif break; case 'a': autologin = 1; break; case 'c': skiprc = 1; break; case 'd': debug = 1; break; case 'e': set_escape_char(optarg); break; case 'f': #if defined(AUTHENTICATION) && defined(KRB5) && defined(FORWARD) if (forward_flags & OPTS_FORWARD_CREDS) { fprintf(stderr, "%s: Only one of -f and -F allowed.\n", prompt); usage(); } forward_flags |= OPTS_FORWARD_CREDS; #else fprintf(stderr, "%s: Warning: -f ignored, no Kerberos V5 support.\n", prompt); #endif break; case 'F': #if defined(AUTHENTICATION) && defined(KRB5) && defined(FORWARD) if (forward_flags & OPTS_FORWARD_CREDS) { fprintf(stderr, "%s: Only one of -f and -F allowed.\n", prompt); usage(); } forward_flags |= OPTS_FORWARD_CREDS; forward_flags |= OPTS_FORWARDABLE_CREDS; #else fprintf(stderr, "%s: Warning: -F ignored, no Kerberos V5 support.\n", prompt); #endif break; case 'k': #if defined(AUTHENTICATION) && defined(KRB4) { extern char *dest_realm, dst_realm_buf[], dst_realm_sz; dest_realm = dst_realm_buf; (void)strncpy(dest_realm, optarg, dst_realm_sz); } #else fprintf(stderr, "%s: Warning: -k ignored, no Kerberos V4 support.\n", prompt); #endif break; case 'l': autologin = 1; user = optarg; break; case 'n': #if defined(TN3270) && defined(unix) /* distinguish between "-n oasynch" and "-noasynch" */ if (argv[optind - 1][0] == '-' && argv[optind - 1][1] == 'n' && argv[optind - 1][2] == 'o') { if (!strcmp(optarg, "oasynch")) { noasynchtty = 1; noasynchnet = 1; } else if (!strcmp(optarg, "oasynchtty")) noasynchtty = 1; else if (!strcmp(optarg, "oasynchnet")) noasynchnet = 1; } else #endif /* defined(TN3270) && defined(unix) */ SetNetTrace(optarg); break; case 'r': rlogin = '~'; break; case 't': #if defined(TN3270) && defined(unix) transcom = tline; (void)strcpy(transcom, optarg); #else fprintf(stderr, "%s: Warning: -t ignored, no TN3270 support.\n", prompt); #endif break; case 'x': #ifdef ENCRYPTION encrypt_auto(1); decrypt_auto(1); #else /* ENCRYPTION */ fprintf(stderr, "%s: Warning: -x ignored, no ENCRYPT support.\n", prompt); #endif /* ENCRYPTION */ break; case '?': default: usage(); /* NOTREACHED */ } } if (autologin == -1) autologin = (rlogin == _POSIX_VDISABLE) ? 0 : 1; argc -= optind; argv += optind; if (argc) { char *args[7], **argp = args; if (argc > 2) usage(); *argp++ = prompt; if (user) { *argp++ = "-l"; *argp++ = user; } *argp++ = argv[0]; /* host */ if (argc > 1) *argp++ = argv[1]; /* port */ *argp = 0; if (setjmp(toplevel) != 0) Exit(0); if (tn(argp - args, args) == 1) return (0); else return (1); } (void)setjmp(toplevel); for (;;) { #ifdef TN3270 if (shell_active) shell_continue(); else #endif command(1, 0, 0); } + return 0; } diff --git a/contrib/telnet/telnet/network.c b/contrib/telnet/telnet/network.c index 0fe5cee0be4c..9964bc205cef 100644 --- a/contrib/telnet/telnet/network.c +++ b/contrib/telnet/telnet/network.c @@ -1,177 +1,178 @@ /* * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. */ #ifndef lint -static char sccsid[] = "@(#)network.c 8.2 (Berkeley) 12/15/93"; +static const char sccsid[] = "@(#)network.c 8.2 (Berkeley) 12/15/93"; #endif /* not lint */ #include #include #include #include #include +#include #include "ring.h" #include "defines.h" #include "externs.h" #include "fdset.h" Ring netoring, netiring; unsigned char netobuf[2*BUFSIZ], netibuf[BUFSIZ]; /* * Initialize internal network data structures. */ void init_network() { if (ring_init(&netoring, netobuf, sizeof netobuf) != 1) { exit(1); } if (ring_init(&netiring, netibuf, sizeof netibuf) != 1) { exit(1); } NetTrace = stdout; } /* * Check to see if any out-of-band data exists on a socket (for * Telnet "synch" processing). */ int stilloob() { static struct timeval timeout = { 0 }; fd_set excepts; int value; do { FD_ZERO(&excepts); FD_SET(net, &excepts); value = select(net+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout); } while ((value == -1) && (errno == EINTR)); if (value < 0) { perror("select"); (void) quit(); /* NOTREACHED */ } if (FD_ISSET(net, &excepts)) { return 1; } else { return 0; } } /* * setneturg() * * Sets "neturg" to the current location. */ void setneturg() { ring_mark(&netoring); } /* * netflush * Send as much data as possible to the network, * handling requests for urgent data. * * The return value indicates whether we did any * useful work. */ int netflush() { register int n, n1; #ifdef ENCRYPTION if (encrypt_output) ring_encrypt(&netoring, encrypt_output); #endif /* ENCRYPTION */ if ((n1 = n = ring_full_consecutive(&netoring)) > 0) { if (!ring_at_mark(&netoring)) { n = send(net, (char *)netoring.consume, n, 0); /* normal write */ } else { /* * In 4.2 (and 4.3) systems, there is some question about * what byte in a sendOOB operation is the "OOB" data. * To make ourselves compatible, we only send ONE byte * out of band, the one WE THINK should be OOB (though * we really have more the TCP philosophy of urgent data * rather than the Unix philosophy of OOB data). */ n = send(net, (char *)netoring.consume, 1, MSG_OOB);/* URGENT data */ } } if (n < 0) { if (errno != ENOBUFS && errno != EWOULDBLOCK) { setcommandmode(); perror(hostname); (void)NetClose(net); ring_clear_mark(&netoring); longjmp(peerdied, -1); /*NOTREACHED*/ } n = 0; } if (netdata && n) { Dump('>', netoring.consume, n); } if (n) { ring_consumed(&netoring, n); /* * If we sent all, and more to send, then recurse to pick * up the other half. */ if ((n1 == n) && ring_full_consecutive(&netoring)) { (void) netflush(); } return 1; } else { return 0; } } diff --git a/contrib/telnet/telnet/ring.c b/contrib/telnet/telnet/ring.c index 37dfda8bc499..13fe6c2b79cb 100644 --- a/contrib/telnet/telnet/ring.c +++ b/contrib/telnet/telnet/ring.c @@ -1,362 +1,364 @@ /* * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. */ #ifndef lint -static char sccsid[] = "@(#)ring.c 8.2 (Berkeley) 5/30/95"; +static const char sccsid[] = "@(#)ring.c 8.2 (Berkeley) 5/30/95"; #endif /* not lint */ /* * This defines a structure for a ring buffer. * * The circular buffer has two parts: *((( * full: [consume, supply) * empty: [supply, consume) *]]] * */ #include #include +#include #ifdef size_t #undef size_t #endif #include #ifndef FILIO_H #include #endif #include #include "ring.h" #include "general.h" /* Internal macros */ #if !defined(MIN) #define MIN(a,b) (((a)<(b))? (a):(b)) #endif /* !defined(MIN) */ #define ring_subtract(d,a,b) (((a)-(b) >= 0)? \ (a)-(b): (((a)-(b))+(d)->size)) #define ring_increment(d,a,c) (((a)+(c) < (d)->top)? \ (a)+(c) : (((a)+(c))-(d)->size)) #define ring_decrement(d,a,c) (((a)-(c) >= (d)->bottom)? \ (a)-(c) : (((a)-(c))-(d)->size)) /* * The following is a clock, used to determine full, empty, etc. * * There is some trickiness here. Since the ring buffers are initialized * to ZERO on allocation, we need to make sure, when interpreting the * clock, that when the times are EQUAL, then the buffer is FULL. */ static u_long ring_clock = 0; #define ring_empty(d) (((d)->consume == (d)->supply) && \ ((d)->consumetime >= (d)->supplytime)) #define ring_full(d) (((d)->supply == (d)->consume) && \ ((d)->supplytime > (d)->consumetime)) /* Buffer state transition routines */ + int ring_init(ring, buffer, count) Ring *ring; unsigned char *buffer; int count; { memset((char *)ring, 0, sizeof *ring); ring->size = count; ring->supply = ring->consume = ring->bottom = buffer; ring->top = ring->bottom+ring->size; #ifdef ENCRYPTION ring->clearto = 0; #endif /* ENCRYPTION */ return 1; } /* Mark routines */ /* * Mark the most recently supplied byte. */ void ring_mark(ring) Ring *ring; { ring->mark = ring_decrement(ring, ring->supply, 1); } /* * Is the ring pointing to the mark? */ int ring_at_mark(ring) Ring *ring; { if (ring->mark == ring->consume) { return 1; } else { return 0; } } /* * Clear any mark set on the ring. */ void ring_clear_mark(ring) Ring *ring; { ring->mark = 0; } /* * Add characters from current segment to ring buffer. */ void ring_supplied(ring, count) Ring *ring; int count; { ring->supply = ring_increment(ring, ring->supply, count); ring->supplytime = ++ring_clock; } /* * We have just consumed "c" bytes. */ void ring_consumed(ring, count) Ring *ring; int count; { if (count == 0) /* don't update anything */ return; if (ring->mark && (ring_subtract(ring, ring->mark, ring->consume) < count)) { ring->mark = 0; } #ifdef ENCRYPTION if (ring->consume < ring->clearto && ring->clearto <= ring->consume + count) ring->clearto = 0; else if (ring->consume + count > ring->top && ring->bottom <= ring->clearto && ring->bottom + ((ring->consume + count) - ring->top)) ring->clearto = 0; #endif /* ENCRYPTION */ ring->consume = ring_increment(ring, ring->consume, count); ring->consumetime = ++ring_clock; /* * Try to encourage "ring_empty_consecutive()" to be large. */ if (ring_empty(ring)) { ring->consume = ring->supply = ring->bottom; } } /* Buffer state query routines */ /* Number of bytes that may be supplied */ int ring_empty_count(ring) Ring *ring; { if (ring_empty(ring)) { /* if empty */ return ring->size; } else { return ring_subtract(ring, ring->consume, ring->supply); } } /* number of CONSECUTIVE bytes that may be supplied */ int ring_empty_consecutive(ring) Ring *ring; { if ((ring->consume < ring->supply) || ring_empty(ring)) { /* * if consume is "below" supply, or empty, then * return distance to the top */ return ring_subtract(ring, ring->top, ring->supply); } else { /* * else, return what we may. */ return ring_subtract(ring, ring->consume, ring->supply); } } /* Return the number of bytes that are available for consuming * (but don't give more than enough to get to cross over set mark) */ int ring_full_count(ring) Ring *ring; { if ((ring->mark == 0) || (ring->mark == ring->consume)) { if (ring_full(ring)) { return ring->size; /* nothing consumed, but full */ } else { return ring_subtract(ring, ring->supply, ring->consume); } } else { return ring_subtract(ring, ring->mark, ring->consume); } } /* * Return the number of CONSECUTIVE bytes available for consuming. * However, don't return more than enough to cross over set mark. */ int ring_full_consecutive(ring) Ring *ring; { if ((ring->mark == 0) || (ring->mark == ring->consume)) { if ((ring->supply < ring->consume) || ring_full(ring)) { return ring_subtract(ring, ring->top, ring->consume); } else { return ring_subtract(ring, ring->supply, ring->consume); } } else { if (ring->mark < ring->consume) { return ring_subtract(ring, ring->top, ring->consume); } else { /* Else, distance to mark */ return ring_subtract(ring, ring->mark, ring->consume); } } } /* * Move data into the "supply" portion of of the ring buffer. */ void ring_supply_data(ring, buffer, count) Ring *ring; unsigned char *buffer; int count; { int i; while (count) { i = MIN(count, ring_empty_consecutive(ring)); memmove(ring->supply, buffer, i); ring_supplied(ring, i); count -= i; buffer += i; } } #ifdef notdef /* * Move data from the "consume" portion of the ring buffer */ void ring_consume_data(ring, buffer, count) Ring *ring; unsigned char *buffer; int count; { int i; while (count) { i = MIN(count, ring_full_consecutive(ring)); memmove(buffer, ring->consume, i); ring_consumed(ring, i); count -= i; buffer += i; } } #endif #ifdef ENCRYPTION void ring_encrypt(ring, encryptor) Ring *ring; void (*encryptor)(); { unsigned char *s, *c; if (ring_empty(ring) || ring->clearto == ring->supply) return; if (!(c = ring->clearto)) c = ring->consume; s = ring->supply; if (s <= c) { (*encryptor)(c, ring->top - c); (*encryptor)(ring->bottom, s - ring->bottom); } else (*encryptor)(c, s - c); ring->clearto = ring->supply; } void ring_clearto(ring) Ring *ring; { if (!ring_empty(ring)) ring->clearto = ring->supply; else ring->clearto = 0; } #endif /* ENCRYPTION */ diff --git a/contrib/telnet/telnet/sys_bsd.c b/contrib/telnet/telnet/sys_bsd.c index f2769acbade7..ed5f459e957c 100644 --- a/contrib/telnet/telnet/sys_bsd.c +++ b/contrib/telnet/telnet/sys_bsd.c @@ -1,1220 +1,1221 @@ /* * Copyright (c) 1988, 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. */ #ifndef lint -static char sccsid[] = "@(#)sys_bsd.c 8.4 (Berkeley) 5/30/95"; +static const char sccsid[] = "@(#)sys_bsd.c 8.4 (Berkeley) 5/30/95"; #endif /* not lint */ /* * The following routines try to encapsulate what is system dependent * (at least between 4.x and dos) which is used in telnet.c. */ #include #include #include #include #include #include #include +#include #include "ring.h" #include "fdset.h" #include "defines.h" #include "externs.h" #include "types.h" #if defined(CRAY) || (defined(USE_TERMIO) && !defined(SYSV_TERMIO)) #define SIG_FUNC_RET void #else #define SIG_FUNC_RET int #endif #ifdef SIGINFO extern SIG_FUNC_RET ayt_status(); #endif int tout, /* Output file descriptor */ tin, /* Input file descriptor */ net; #ifndef USE_TERMIO struct tchars otc = { 0 }, ntc = { 0 }; struct ltchars oltc = { 0 }, nltc = { 0 }; struct sgttyb ottyb = { 0 }, nttyb = { 0 }; int olmode = 0; # define cfgetispeed(ptr) (ptr)->sg_ispeed # define cfgetospeed(ptr) (ptr)->sg_ospeed # define old_tc ottyb #else /* USE_TERMIO */ struct termio old_tc = { 0 }; extern struct termio new_tc; # ifndef TCSANOW # ifdef TCSETS # define TCSANOW TCSETS # define TCSADRAIN TCSETSW # define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t) # else # ifdef TCSETA # define TCSANOW TCSETA # define TCSADRAIN TCSETAW # define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t) # else # define TCSANOW TIOCSETA # define TCSADRAIN TIOCSETAW # define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t) # endif # endif # define tcsetattr(f, a, t) ioctl(f, a, (char *)t) # define cfgetospeed(ptr) ((ptr)->c_cflag&CBAUD) # ifdef CIBAUD # define cfgetispeed(ptr) (((ptr)->c_cflag&CIBAUD) >> IBSHIFT) # else # define cfgetispeed(ptr) cfgetospeed(ptr) # endif # endif /* TCSANOW */ # ifdef sysV88 # define TIOCFLUSH TC_PX_DRAIN # endif #endif /* USE_TERMIO */ static fd_set ibits, obits, xbits; void init_sys() { tout = fileno(stdout); tin = fileno(stdin); FD_ZERO(&ibits); FD_ZERO(&obits); FD_ZERO(&xbits); errno = 0; } int TerminalWrite(buf, n) char *buf; int n; { return write(tout, buf, n); } int TerminalRead(buf, n) - unsigned char *buf; + char *buf; int n; { return read(tin, buf, n); } /* * */ int TerminalAutoFlush() { #if defined(LNOFLSH) int flush; ioctl(0, TIOCLGET, (char *)&flush); return !(flush&LNOFLSH); /* if LNOFLSH, no autoflush */ #else /* LNOFLSH */ return 1; #endif /* LNOFLSH */ } #ifdef KLUDGELINEMODE extern int kludgelinemode; #endif /* * TerminalSpecialChars() * * Look at an input character to see if it is a special character * and decide what to do. * * Output: * * 0 Don't add this character. * 1 Do add this character */ extern void xmitAO(), xmitEL(), xmitEC(), intp(), sendbrk(); int TerminalSpecialChars(c) int c; { if (c == termIntChar) { intp(); return 0; } else if (c == termQuitChar) { #ifdef KLUDGELINEMODE if (kludgelinemode) sendbrk(); else #endif sendabort(); return 0; } else if (c == termEofChar) { if (my_want_state_is_will(TELOPT_LINEMODE)) { sendeof(); return 0; } return 1; } else if (c == termSuspChar) { sendsusp(); return(0); } else if (c == termFlushChar) { xmitAO(); /* Transmit Abort Output */ return 0; } else if (!MODE_LOCAL_CHARS(globalmode)) { if (c == termKillChar) { xmitEL(); return 0; } else if (c == termEraseChar) { xmitEC(); /* Transmit Erase Character */ return 0; } } return 1; } /* * Flush output to the terminal */ void TerminalFlushOutput() { #ifdef TIOCFLUSH (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0); #else (void) ioctl(fileno(stdout), TCFLSH, (char *) 0); #endif } void TerminalSaveState() { #ifndef USE_TERMIO ioctl(0, TIOCGETP, (char *)&ottyb); ioctl(0, TIOCGETC, (char *)&otc); ioctl(0, TIOCGLTC, (char *)&oltc); ioctl(0, TIOCLGET, (char *)&olmode); ntc = otc; nltc = oltc; nttyb = ottyb; #else /* USE_TERMIO */ tcgetattr(0, &old_tc); new_tc = old_tc; #ifndef VDISCARD termFlushChar = CONTROL('O'); #endif #ifndef VWERASE termWerasChar = CONTROL('W'); #endif #ifndef VREPRINT termRprntChar = CONTROL('R'); #endif #ifndef VLNEXT termLiteralNextChar = CONTROL('V'); #endif #ifndef VSTART termStartChar = CONTROL('Q'); #endif #ifndef VSTOP termStopChar = CONTROL('S'); #endif #ifndef VSTATUS termAytChar = CONTROL('T'); #endif #endif /* USE_TERMIO */ } cc_t * tcval(func) register int func; { switch(func) { case SLC_IP: return(&termIntChar); case SLC_ABORT: return(&termQuitChar); case SLC_EOF: return(&termEofChar); case SLC_EC: return(&termEraseChar); case SLC_EL: return(&termKillChar); case SLC_XON: return(&termStartChar); case SLC_XOFF: return(&termStopChar); case SLC_FORW1: return(&termForw1Char); #ifdef USE_TERMIO case SLC_FORW2: return(&termForw2Char); # ifdef VDISCARD case SLC_AO: return(&termFlushChar); # endif # ifdef VSUSP case SLC_SUSP: return(&termSuspChar); # endif # ifdef VWERASE case SLC_EW: return(&termWerasChar); # endif # ifdef VREPRINT case SLC_RP: return(&termRprntChar); # endif # ifdef VLNEXT case SLC_LNEXT: return(&termLiteralNextChar); # endif # ifdef VSTATUS case SLC_AYT: return(&termAytChar); # endif #endif case SLC_SYNCH: case SLC_BRK: case SLC_EOR: default: return((cc_t *)0); } } void TerminalDefaultChars() { #ifndef USE_TERMIO ntc = otc; nltc = oltc; nttyb.sg_kill = ottyb.sg_kill; nttyb.sg_erase = ottyb.sg_erase; #else /* USE_TERMIO */ memmove(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc)); # ifndef VDISCARD termFlushChar = CONTROL('O'); # endif # ifndef VWERASE termWerasChar = CONTROL('W'); # endif # ifndef VREPRINT termRprntChar = CONTROL('R'); # endif # ifndef VLNEXT termLiteralNextChar = CONTROL('V'); # endif # ifndef VSTART termStartChar = CONTROL('Q'); # endif # ifndef VSTOP termStopChar = CONTROL('S'); # endif # ifndef VSTATUS termAytChar = CONTROL('T'); # endif #endif /* USE_TERMIO */ } #ifdef notdef void TerminalRestoreState() { } #endif /* * TerminalNewMode - set up terminal to a specific mode. * MODE_ECHO: do local terminal echo * MODE_FLOW: do local flow control * MODE_TRAPSIG: do local mapping to TELNET IAC sequences * MODE_EDIT: do local line editing * * Command mode: * MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG * local echo * local editing * local xon/xoff * local signal mapping * * Linemode: * local/no editing * Both Linemode and Single Character mode: * local/remote echo * local/no xon/xoff * local/no signal mapping */ void TerminalNewMode(f) register int f; { static int prevmode = 0; #ifndef USE_TERMIO struct tchars tc; struct ltchars ltc; struct sgttyb sb; int lmode; #else /* USE_TERMIO */ struct termio tmp_tc; #endif /* USE_TERMIO */ int onoff; int old; cc_t esc; globalmode = f&~MODE_FORCE; if (prevmode == f) return; /* * Write any outstanding data before switching modes * ttyflush() returns 0 only when there is no more data * left to write out, it returns -1 if it couldn't do * anything at all, otherwise it returns 1 + the number * of characters left to write. #ifndef USE_TERMIO * We would really like ask the kernel to wait for the output * to drain, like we can do with the TCSADRAIN, but we don't have * that option. The only ioctl that waits for the output to * drain, TIOCSETP, also flushes the input queue, which is NOT * what we want (TIOCSETP is like TCSADFLUSH). #endif */ old = ttyflush(SYNCHing|flushout); if (old < 0 || old > 1) { #ifdef USE_TERMIO tcgetattr(tin, &tmp_tc); #endif /* USE_TERMIO */ do { /* * Wait for data to drain, then flush again. */ #ifdef USE_TERMIO tcsetattr(tin, TCSADRAIN, &tmp_tc); #endif /* USE_TERMIO */ old = ttyflush(SYNCHing|flushout); } while (old < 0 || old > 1); } old = prevmode; prevmode = f&~MODE_FORCE; #ifndef USE_TERMIO sb = nttyb; tc = ntc; ltc = nltc; lmode = olmode; #else tmp_tc = new_tc; #endif if (f&MODE_ECHO) { #ifndef USE_TERMIO sb.sg_flags |= ECHO; #else tmp_tc.c_lflag |= ECHO; tmp_tc.c_oflag |= ONLCR; if (crlf) tmp_tc.c_iflag |= ICRNL; #endif } else { #ifndef USE_TERMIO sb.sg_flags &= ~ECHO; #else tmp_tc.c_lflag &= ~ECHO; tmp_tc.c_oflag &= ~ONLCR; # ifdef notdef if (crlf) tmp_tc.c_iflag &= ~ICRNL; # endif #endif } if ((f&MODE_FLOW) == 0) { #ifndef USE_TERMIO tc.t_startc = _POSIX_VDISABLE; tc.t_stopc = _POSIX_VDISABLE; #else tmp_tc.c_iflag &= ~(IXOFF|IXON); /* Leave the IXANY bit alone */ } else { if (restartany < 0) { tmp_tc.c_iflag |= IXOFF|IXON; /* Leave the IXANY bit alone */ } else if (restartany > 0) { tmp_tc.c_iflag |= IXOFF|IXON|IXANY; } else { tmp_tc.c_iflag |= IXOFF|IXON; tmp_tc.c_iflag &= ~IXANY; } #endif } if ((f&MODE_TRAPSIG) == 0) { #ifndef USE_TERMIO tc.t_intrc = _POSIX_VDISABLE; tc.t_quitc = _POSIX_VDISABLE; tc.t_eofc = _POSIX_VDISABLE; ltc.t_suspc = _POSIX_VDISABLE; ltc.t_dsuspc = _POSIX_VDISABLE; #else tmp_tc.c_lflag &= ~ISIG; #endif localchars = 0; } else { #ifdef USE_TERMIO tmp_tc.c_lflag |= ISIG; #endif localchars = 1; } if (f&MODE_EDIT) { #ifndef USE_TERMIO sb.sg_flags &= ~CBREAK; sb.sg_flags |= CRMOD; #else tmp_tc.c_lflag |= ICANON; #endif } else { #ifndef USE_TERMIO sb.sg_flags |= CBREAK; if (f&MODE_ECHO) sb.sg_flags |= CRMOD; else sb.sg_flags &= ~CRMOD; #else tmp_tc.c_lflag &= ~ICANON; tmp_tc.c_iflag &= ~ICRNL; tmp_tc.c_cc[VMIN] = 1; tmp_tc.c_cc[VTIME] = 0; #endif } if ((f&(MODE_EDIT|MODE_TRAPSIG)) == 0) { #ifndef USE_TERMIO ltc.t_lnextc = _POSIX_VDISABLE; #else # ifdef VLNEXT tmp_tc.c_cc[VLNEXT] = (cc_t)(_POSIX_VDISABLE); # endif #endif } if (f&MODE_SOFT_TAB) { #ifndef USE_TERMIO sb.sg_flags |= XTABS; #else # ifdef OXTABS tmp_tc.c_oflag |= OXTABS; # endif # ifdef TABDLY tmp_tc.c_oflag &= ~TABDLY; tmp_tc.c_oflag |= TAB3; # endif #endif } else { #ifndef USE_TERMIO sb.sg_flags &= ~XTABS; #else # ifdef OXTABS tmp_tc.c_oflag &= ~OXTABS; # endif # ifdef TABDLY tmp_tc.c_oflag &= ~TABDLY; # endif #endif } if (f&MODE_LIT_ECHO) { #ifndef USE_TERMIO lmode &= ~LCTLECH; #else # ifdef ECHOCTL tmp_tc.c_lflag &= ~ECHOCTL; # endif #endif } else { #ifndef USE_TERMIO lmode |= LCTLECH; #else # ifdef ECHOCTL tmp_tc.c_lflag |= ECHOCTL; # endif #endif } if (f == -1) { onoff = 0; } else { #ifndef USE_TERMIO if (f & MODE_OUTBIN) lmode |= LLITOUT; else lmode &= ~LLITOUT; if (f & MODE_INBIN) lmode |= LPASS8; else lmode &= ~LPASS8; #else if (f & MODE_INBIN) tmp_tc.c_iflag &= ~ISTRIP; else tmp_tc.c_iflag |= ISTRIP; if (f & MODE_OUTBIN) { tmp_tc.c_cflag &= ~(CSIZE|PARENB); tmp_tc.c_cflag |= CS8; tmp_tc.c_oflag &= ~OPOST; } else { tmp_tc.c_cflag &= ~(CSIZE|PARENB); tmp_tc.c_cflag |= old_tc.c_cflag & (CSIZE|PARENB); tmp_tc.c_oflag |= OPOST; } #endif onoff = 1; } if (f != -1) { #ifdef SIGTSTP SIG_FUNC_RET susp(); #endif /* SIGTSTP */ #ifdef SIGINFO SIG_FUNC_RET ayt(); #endif #ifdef SIGTSTP (void) signal(SIGTSTP, susp); #endif /* SIGTSTP */ #ifdef SIGINFO (void) signal(SIGINFO, ayt); #endif #if defined(USE_TERMIO) && defined(NOKERNINFO) tmp_tc.c_lflag |= NOKERNINFO; #endif /* * We don't want to process ^Y here. It's just another * character that we'll pass on to the back end. It has * to process it because it will be processed when the * user attempts to read it, not when we send it. */ #ifndef USE_TERMIO ltc.t_dsuspc = _POSIX_VDISABLE; #else # ifdef VDSUSP tmp_tc.c_cc[VDSUSP] = (cc_t)(_POSIX_VDISABLE); # endif #endif #ifdef USE_TERMIO /* * If the VEOL character is already set, then use VEOL2, * otherwise use VEOL. */ esc = (rlogin != _POSIX_VDISABLE) ? rlogin : escape; if ((tmp_tc.c_cc[VEOL] != esc) # ifdef VEOL2 && (tmp_tc.c_cc[VEOL2] != esc) # endif ) { if (tmp_tc.c_cc[VEOL] == (cc_t)(_POSIX_VDISABLE)) tmp_tc.c_cc[VEOL] = esc; # ifdef VEOL2 else if (tmp_tc.c_cc[VEOL2] == (cc_t)(_POSIX_VDISABLE)) tmp_tc.c_cc[VEOL2] = esc; # endif } #else if (tc.t_brkc == (cc_t)(_POSIX_VDISABLE)) tc.t_brkc = esc; #endif } else { #ifdef SIGINFO SIG_FUNC_RET ayt_status(); (void) signal(SIGINFO, ayt_status); #endif #ifdef SIGTSTP (void) signal(SIGTSTP, SIG_DFL); # ifndef SOLARIS (void) sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1))); # else SOLARIS (void) sigrelse(SIGTSTP); # endif SOLARIS #endif /* SIGTSTP */ #ifndef USE_TERMIO ltc = oltc; tc = otc; sb = ottyb; lmode = olmode; #else tmp_tc = old_tc; #endif } #ifndef USE_TERMIO ioctl(tin, TIOCLSET, (char *)&lmode); ioctl(tin, TIOCSLTC, (char *)<c); ioctl(tin, TIOCSETC, (char *)&tc); ioctl(tin, TIOCSETN, (char *)&sb); #else if (tcsetattr(tin, TCSADRAIN, &tmp_tc) < 0) tcsetattr(tin, TCSANOW, &tmp_tc); #endif #if (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) # if !defined(sysV88) ioctl(tin, FIONBIO, (char *)&onoff); ioctl(tout, FIONBIO, (char *)&onoff); # endif #endif /* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */ #if defined(TN3270) if (noasynchtty == 0) { ioctl(tin, FIOASYNC, (char *)&onoff); } #endif /* defined(TN3270) */ } /* * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD). */ #if B4800 != 4800 #define DECODE_BAUD #endif #ifdef DECODE_BAUD #ifndef B7200 #define B7200 B4800 #endif #ifndef B14400 #define B14400 B9600 #endif #ifndef B19200 # define B19200 B14400 #endif #ifndef B28800 #define B28800 B19200 #endif #ifndef B38400 # define B38400 B28800 #endif #ifndef B57600 #define B57600 B38400 #endif #ifndef B76800 #define B76800 B57600 #endif #ifndef B115200 #define B115200 B76800 #endif #ifndef B230400 #define B230400 B115200 #endif /* * This code assumes that the values B0, B50, B75... * are in ascending order. They do not have to be * contiguous. */ struct termspeeds { long speed; long 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 }, { 7200, B7200 }, { 9600, B9600 }, { 14400, B14400 }, { 19200, B19200 }, { 28800, B28800 }, { 38400, B38400 }, { 57600, B57600 }, { 115200, B115200 }, { 230400, B230400 }, { -1, B230400 } }; #endif /* DECODE_BAUD */ void TerminalSpeeds(ispeed, ospeed) long *ispeed; long *ospeed; { #ifdef DECODE_BAUD register struct termspeeds *tp; #endif /* DECODE_BAUD */ register long in, out; out = cfgetospeed(&old_tc); in = cfgetispeed(&old_tc); if (in == 0) in = out; #ifdef DECODE_BAUD tp = termspeeds; while ((tp->speed != -1) && (tp->value < in)) tp++; *ispeed = tp->speed; tp = termspeeds; while ((tp->speed != -1) && (tp->value < out)) tp++; *ospeed = tp->speed; #else /* DECODE_BAUD */ *ispeed = in; *ospeed = out; #endif /* DECODE_BAUD */ } int TerminalWindowSize(rows, cols) long *rows, *cols; { #ifdef TIOCGWINSZ struct winsize ws; if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) >= 0) { *rows = ws.ws_row; *cols = ws.ws_col; return 1; } #endif /* TIOCGWINSZ */ return 0; } int NetClose(fd) int fd; { return close(fd); } void NetNonblockingIO(fd, onoff) int fd; int onoff; { ioctl(fd, FIONBIO, (char *)&onoff); } #if defined(TN3270) void NetSigIO(fd, onoff) int fd; int onoff; { ioctl(fd, FIOASYNC, (char *)&onoff); /* hear about input */ } void NetSetPgrp(fd) int fd; { int myPid; myPid = getpid(); fcntl(fd, F_SETOWN, myPid); } #endif /*defined(TN3270)*/ /* * Various signal handling routines. */ /* ARGSUSED */ SIG_FUNC_RET deadpeer(sig) int sig; { setcommandmode(); longjmp(peerdied, -1); } /* ARGSUSED */ SIG_FUNC_RET intr(sig) int sig; { if (localchars) { intp(); return; } setcommandmode(); longjmp(toplevel, -1); } /* ARGSUSED */ SIG_FUNC_RET intr2(sig) int sig; { if (localchars) { #ifdef KLUDGELINEMODE if (kludgelinemode) sendbrk(); else #endif sendabort(); return; } } #ifdef SIGTSTP /* ARGSUSED */ SIG_FUNC_RET susp(sig) int sig; { if ((rlogin != _POSIX_VDISABLE) && rlogin_susp()) return; if (localchars) sendsusp(); } #endif #ifdef SIGWINCH /* ARGSUSED */ SIG_FUNC_RET sendwin(sig) int sig; { if (connected) { sendnaws(); } } #endif #ifdef SIGINFO /* ARGSUSED */ SIG_FUNC_RET ayt(sig) int sig; { if (connected) sendayt(); else ayt_status(); } #endif void sys_telnet_init() { (void) signal(SIGINT, intr); (void) signal(SIGQUIT, intr2); (void) signal(SIGPIPE, deadpeer); #ifdef SIGWINCH (void) signal(SIGWINCH, sendwin); #endif #ifdef SIGTSTP (void) signal(SIGTSTP, susp); #endif #ifdef SIGINFO (void) signal(SIGINFO, ayt); #endif setconnmode(0); NetNonblockingIO(net, 1); #if defined(TN3270) if (noasynchnet == 0) { /* DBX can't handle! */ NetSigIO(net, 1); NetSetPgrp(net); } #endif /* defined(TN3270) */ #if defined(SO_OOBINLINE) if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) { perror("SetSockOpt"); } #endif /* defined(SO_OOBINLINE) */ } /* * Process rings - * * This routine tries to fill up/empty our various rings. * * The parameter specifies whether this is a poll operation, * or a block-until-something-happens operation. * * The return value is 1 if something happened, 0 if not. */ int process_rings(netin, netout, netex, ttyin, ttyout, poll) int poll; /* If 0, then block until something to do */ { register int c; /* One wants to be a bit careful about setting returnValue * to one, since a one implies we did some useful work, * and therefore probably won't be called to block next * time (TN3270 mode only). */ int returnValue = 0; static struct timeval TimeValue = { 0 }; if (netout) { FD_SET(net, &obits); } if (ttyout) { FD_SET(tout, &obits); } #if defined(TN3270) if (ttyin) { FD_SET(tin, &ibits); } #else /* defined(TN3270) */ if (ttyin) { FD_SET(tin, &ibits); } #endif /* defined(TN3270) */ #if defined(TN3270) if (netin) { FD_SET(net, &ibits); } # else /* !defined(TN3270) */ if (netin) { FD_SET(net, &ibits); } # endif /* !defined(TN3270) */ if (netex) { FD_SET(net, &xbits); } if ((c = select(16, &ibits, &obits, &xbits, (poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) { if (c == -1) { /* * we can get EINTR if we are in line mode, * and the user does an escape (TSTP), or * some other signal generator. */ if (errno == EINTR) { return 0; } # if defined(TN3270) /* * we can get EBADF if we were in transparent * mode, and the transcom process died. */ if (errno == EBADF) { /* * zero the bits (even though kernel does it) * to make sure we are selecting on the right * ones. */ FD_ZERO(&ibits); FD_ZERO(&obits); FD_ZERO(&xbits); return 0; } # endif /* defined(TN3270) */ /* I don't like this, does it ever happen? */ - printf("sleep(5) from telnet, after select\r\n"); + printf("sleep(5) from telnet, after select: %s\r\n", strerror(errno)); sleep(5); } return 0; } /* * Any urgent data? */ if (FD_ISSET(net, &xbits)) { FD_CLR(net, &xbits); SYNCHing = 1; (void) ttyflush(1); /* flush already enqueued data */ } /* * Something to read from the network... */ if (FD_ISSET(net, &ibits)) { int canread; FD_CLR(net, &ibits); canread = ring_empty_consecutive(&netiring); #if !defined(SO_OOBINLINE) /* * In 4.2 (and some early 4.3) 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; static int bogus_oob = 0, first = 1; ioctl(net, SIOCATMARK, (char *)&atmark); if (atmark) { c = recv(net, netiring.supply, canread, MSG_OOB); if ((c == -1) && (errno == EINVAL)) { c = recv(net, netiring.supply, canread, 0); if (clocks.didnetreceive < clocks.gotDM) { SYNCHing = stilloob(net); } } else if (first && c > 0) { /* * Bogosity check. Systems based on 4.2BSD * do not return an error if you do a second * recv(MSG_OOB). So, we do one. If it * succeeds and returns exactly the same * data, then assume that we are running * on a broken system and set the bogus_oob * flag. (If the data was different, then * we probably got some valid new data, so * increment the count...) */ int i; i = recv(net, netiring.supply + c, canread - c, MSG_OOB); if (i == c && memcmp(netiring.supply, netiring.supply + c, i) == 0) { bogus_oob = 1; first = 0; } else if (i < 0) { bogus_oob = 0; first = 0; } else c += i; } if (bogus_oob && c > 0) { int i; /* * Bogosity. We have to do the read * to clear the atmark to get out of * an infinate loop. */ i = read(net, netiring.supply + c, canread - c); if (i > 0) c += i; } } else { c = recv(net, netiring.supply, canread, 0); } } else { c = recv(net, netiring.supply, canread, 0); } settimer(didnetreceive); #else /* !defined(SO_OOBINLINE) */ c = recv(net, (char *)netiring.supply, canread, 0); #endif /* !defined(SO_OOBINLINE) */ if (c < 0 && errno == EWOULDBLOCK) { c = 0; } else if (c <= 0) { return -1; } if (netdata) { Dump('<', netiring.supply, c); } if (c) ring_supplied(&netiring, c); returnValue = 1; } /* * Something to read from the tty... */ if (FD_ISSET(tin, &ibits)) { FD_CLR(tin, &ibits); c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring)); if (c < 0 && errno == EIO) c = 0; if (c < 0 && errno == EWOULDBLOCK) { c = 0; } else { /* EOF detection for line mode!!!! */ if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) { /* must be an EOF... */ *ttyiring.supply = termEofChar; c = 1; } if (c <= 0) { return -1; } if (termdata) { Dump('<', ttyiring.supply, c); } ring_supplied(&ttyiring, c); } returnValue = 1; /* did something useful */ } if (FD_ISSET(net, &obits)) { FD_CLR(net, &obits); returnValue |= netflush(); } if (FD_ISSET(tout, &obits)) { FD_CLR(tout, &obits); returnValue |= (ttyflush(SYNCHing|flushout) > 0); } return returnValue; } diff --git a/contrib/telnet/telnet/telnet.c b/contrib/telnet/telnet/telnet.c index e7922624e6e6..1c1ee333fa72 100644 --- a/contrib/telnet/telnet/telnet.c +++ b/contrib/telnet/telnet/telnet.c @@ -1,2650 +1,2662 @@ /* * Copyright (c) 1988, 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. */ #ifndef lint -static char sccsid[] = "@(#)telnet.c 8.4 (Berkeley) 5/30/95"; +static const char sccsid[] = "@(#)telnet.c 8.4 (Berkeley) 5/30/95"; #endif /* not lint */ #include #if defined(unix) #include /* By the way, we need to include curses.h before telnet.h since, * among other things, telnet.h #defines 'DO', which is a variable * declared in curses.h. */ #endif /* defined(unix) */ #include #include +#include +#include +#include + #include "ring.h" #include "defines.h" #include "externs.h" #include "types.h" #include "general.h" +#if defined(AUTHENTICATION) +#include +#endif +#if defined(ENCRYPTION) +#include +#endif +#include #define strip(x) ((my_want_state_is_wont(TELOPT_BINARY)) ? ((x)&0x7f) : (x)) static unsigned char subbuffer[SUBBUFSIZE], *subpointer, *subend; /* buffer for sub-options */ #define SB_CLEAR() subpointer = subbuffer; #define SB_TERM() { subend = subpointer; SB_CLEAR(); } #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ *subpointer++ = (c); \ } #define SB_GET() ((*subpointer++)&0xff) #define SB_PEEK() ((*subpointer)&0xff) #define SB_EOF() (subpointer >= subend) #define SB_LEN() (subend - subpointer) char options[256]; /* The combined options */ char do_dont_resp[256]; char will_wont_resp[256]; int eight = 0, autologin = 0, /* Autologin anyone? */ skiprc = 0, connected, showoptions, In3270, /* Are we in 3270 mode? */ ISend, /* trying to send network data in */ debug = 0, crmod, netdata, /* Print out network data flow */ crlf, /* Should '\r' be mapped to (or )? */ #if defined(TN3270) noasynchtty = 0,/* User specified "-noasynch" on command line */ noasynchnet = 0,/* User specified "-noasynch" on command line */ askedSGA = 0, /* We have talked about suppress go ahead */ #endif /* defined(TN3270) */ telnetport, SYNCHing, /* we are in TELNET SYNCH mode */ flushout, /* flush output */ autoflush = 0, /* flush output when interrupting? */ autosynch, /* send interrupt characters with SYNCH? */ localflow, /* we handle flow control locally */ restartany, /* if flow control enabled, restart on any character */ localchars, /* we recognize interrupt/quit */ donelclchars, /* the user has set "localchars" */ donebinarytoggle, /* the user has put us in binary */ dontlecho, /* do we suppress local echoing right now? */ - globalmode; + globalmode, + clienteof = 0; char *prompt = 0; cc_t escape; cc_t rlogin; #ifdef KLUDGELINEMODE cc_t echoc; #endif /* * Telnet receiver states for fsm */ #define TS_DATA 0 #define TS_IAC 1 #define TS_WILL 2 #define TS_WONT 3 #define TS_DO 4 #define TS_DONT 5 #define TS_CR 6 #define TS_SB 7 /* sub-option collection */ #define TS_SE 8 /* looking for sub-option end */ static int telrcv_state; #ifdef OLD_ENVIRON unsigned char telopt_environ = TELOPT_NEW_ENVIRON; #else # define telopt_environ TELOPT_NEW_ENVIRON #endif jmp_buf toplevel = { 0 }; jmp_buf peerdied; int flushline; int linemode; #ifdef KLUDGELINEMODE int kludgelinemode = 1; #endif /* * The following are some clocks used to decide how to interpret * the relationship between various variables. */ Clocks clocks; #ifdef notdef Modelist modelist[] = { { "telnet command mode", COMMAND_LINE }, { "character-at-a-time mode", 0 }, { "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS }, { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS }, { "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS }, { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS }, { "3270 mode", 0 }, }; #endif /* * Initialize telnet environment. */ void init_telnet() { env_init(); SB_CLEAR(); ClearArray(options); connected = In3270 = ISend = localflow = donebinarytoggle = 0; #if defined(AUTHENTICATION) || defined(ENCRYPTION) auth_encrypt_connect(connected); #endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */ restartany = -1; SYNCHing = 0; /* Don't change NetTrace */ escape = CONTROL(']'); rlogin = _POSIX_VDISABLE; #ifdef KLUDGELINEMODE echoc = CONTROL('E'); #endif flushline = 1; telrcv_state = TS_DATA; } #ifdef notdef #include /*VARARGS*/ static void printring(va_alist) va_dcl { va_list ap; char buffer[100]; /* where things go */ char *ptr; char *format; char *string; Ring *ring; int i; va_start(ap); ring = va_arg(ap, Ring *); format = va_arg(ap, char *); ptr = buffer; while ((i = *format++) != 0) { if (i == '%') { i = *format++; switch (i) { case 'c': *ptr++ = va_arg(ap, int); break; case 's': string = va_arg(ap, char *); ring_supply_data(ring, buffer, ptr-buffer); ring_supply_data(ring, string, strlen(string)); ptr = buffer; break; case 0: ExitString("printring: trailing %%.\n", 1); /*NOTREACHED*/ default: ExitString("printring: unknown format character.\n", 1); /*NOTREACHED*/ } } else { *ptr++ = i; } } ring_supply_data(ring, buffer, ptr-buffer); } #endif /* * These routines are in charge of sending option negotiations * to the other side. * * The basic idea is that we send the negotiation if either side * is in disagreement as to what the current state should be. */ void send_do(c, init) register int c, init; { if (init) { if (((do_dont_resp[c] == 0) && my_state_is_do(c)) || my_want_state_is_do(c)) return; set_my_want_state_do(c); do_dont_resp[c]++; } NET2ADD(IAC, DO); NETADD(c); printoption("SENT", DO, c); } void send_dont(c, init) register int c, init; { if (init) { if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) || my_want_state_is_dont(c)) return; set_my_want_state_dont(c); do_dont_resp[c]++; } NET2ADD(IAC, DONT); NETADD(c); printoption("SENT", DONT, c); } void send_will(c, init) register int c, init; { if (init) { if (((will_wont_resp[c] == 0) && my_state_is_will(c)) || my_want_state_is_will(c)) return; set_my_want_state_will(c); will_wont_resp[c]++; } NET2ADD(IAC, WILL); NETADD(c); printoption("SENT", WILL, c); } void send_wont(c, init) register int c, init; { if (init) { if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) || my_want_state_is_wont(c)) return; set_my_want_state_wont(c); will_wont_resp[c]++; } NET2ADD(IAC, WONT); NETADD(c); printoption("SENT", WONT, c); } void willoption(option) int option; { int new_state_ok = 0; if (do_dont_resp[option]) { --do_dont_resp[option]; if (do_dont_resp[option] && my_state_is_do(option)) --do_dont_resp[option]; } if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) { switch (option) { case TELOPT_ECHO: # if defined(TN3270) /* * The following is a pain in the rear-end. * Various IBM servers (some versions of Wiscnet, * possibly Fibronics/Spartacus, and who knows who * else) will NOT allow us to send "DO SGA" too early * in the setup proceedings. On the other hand, * 4.2 servers (telnetd) won't set SGA correctly. * So, we are stuck. Empirically (but, based on * a VERY small sample), the IBM servers don't send * out anything about ECHO, so we postpone our sending * "DO SGA" until we see "WILL ECHO" (which 4.2 servers * DO send). */ { if (askedSGA == 0) { askedSGA = 1; if (my_want_state_is_dont(TELOPT_SGA)) send_do(TELOPT_SGA, 1); } } /* Fall through */ case TELOPT_EOR: #endif /* defined(TN3270) */ case TELOPT_BINARY: case TELOPT_SGA: settimer(modenegotiated); /* FALL THROUGH */ case TELOPT_STATUS: #if defined(AUTHENTICATION) case TELOPT_AUTHENTICATION: #endif #ifdef ENCRYPTION case TELOPT_ENCRYPT: #endif /* ENCRYPTION */ new_state_ok = 1; break; case TELOPT_TM: if (flushout) flushout = 0; /* * Special case for TM. If we get back a WILL, * pretend we got back a WONT. */ set_my_want_state_dont(option); set_my_state_dont(option); return; /* Never reply to TM will's/wont's */ case TELOPT_LINEMODE: default: break; } if (new_state_ok) { set_my_want_state_do(option); send_do(option, 0); setconnmode(0); /* possibly set new tty mode */ } else { do_dont_resp[option]++; send_dont(option, 0); } } set_my_state_do(option); #ifdef ENCRYPTION if (option == TELOPT_ENCRYPT) encrypt_send_support(); #endif /* ENCRYPTION */ } void wontoption(option) int option; { if (do_dont_resp[option]) { --do_dont_resp[option]; if (do_dont_resp[option] && my_state_is_dont(option)) --do_dont_resp[option]; } if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) { switch (option) { #ifdef KLUDGELINEMODE case TELOPT_SGA: if (!kludgelinemode) break; /* FALL THROUGH */ #endif case TELOPT_ECHO: settimer(modenegotiated); break; case TELOPT_TM: if (flushout) flushout = 0; set_my_want_state_dont(option); set_my_state_dont(option); return; /* Never reply to TM will's/wont's */ default: break; } set_my_want_state_dont(option); if (my_state_is_do(option)) send_dont(option, 0); setconnmode(0); /* Set new tty mode */ } else if (option == TELOPT_TM) { /* * Special case for TM. */ if (flushout) flushout = 0; set_my_want_state_dont(option); } set_my_state_dont(option); } static void dooption(option) int option; { int new_state_ok = 0; 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) { if (my_want_state_is_wont(option)) { switch (option) { case TELOPT_TM: /* * Special case for TM. We send a WILL, but pretend * we sent WONT. */ send_will(option, 0); set_my_want_state_wont(TELOPT_TM); set_my_state_wont(TELOPT_TM); return; # if defined(TN3270) case TELOPT_EOR: /* end of record */ # endif /* defined(TN3270) */ case TELOPT_BINARY: /* binary mode */ case TELOPT_NAWS: /* window size */ case TELOPT_TSPEED: /* terminal speed */ case TELOPT_LFLOW: /* local flow control */ case TELOPT_TTYPE: /* terminal type option */ case TELOPT_SGA: /* no big deal */ #ifdef ENCRYPTION case TELOPT_ENCRYPT: /* encryption variable option */ #endif /* ENCRYPTION */ new_state_ok = 1; break; case TELOPT_NEW_ENVIRON: /* New environment variable option */ #ifdef OLD_ENVIRON if (my_state_is_will(TELOPT_OLD_ENVIRON)) send_wont(TELOPT_OLD_ENVIRON, 1); /* turn off the old */ goto env_common; case TELOPT_OLD_ENVIRON: /* Old environment variable option */ if (my_state_is_will(TELOPT_NEW_ENVIRON)) break; /* Don't enable if new one is in use! */ env_common: telopt_environ = option; #endif new_state_ok = 1; break; #if defined(AUTHENTICATION) case TELOPT_AUTHENTICATION: if (autologin) new_state_ok = 1; break; #endif case TELOPT_XDISPLOC: /* X Display location */ if (env_getvalue((unsigned char *)"DISPLAY")) new_state_ok = 1; break; case TELOPT_LINEMODE: #ifdef KLUDGELINEMODE kludgelinemode = 0; send_do(TELOPT_SGA, 1); #endif set_my_want_state_will(TELOPT_LINEMODE); send_will(option, 0); set_my_state_will(TELOPT_LINEMODE); slc_init(); return; case TELOPT_ECHO: /* We're never going to echo... */ default: break; } if (new_state_ok) { set_my_want_state_will(option); send_will(option, 0); setconnmode(0); /* Set new tty mode */ } else { will_wont_resp[option]++; send_wont(option, 0); } } else { /* * Handle options that need more things done after the * other side has acknowledged the option. */ switch (option) { case TELOPT_LINEMODE: #ifdef KLUDGELINEMODE kludgelinemode = 0; send_do(TELOPT_SGA, 1); #endif set_my_state_will(option); slc_init(); send_do(TELOPT_SGA, 0); return; } } } set_my_state_will(option); } static void dontoption(option) int 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_LINEMODE: linemode = 0; /* put us back to the default state */ break; #ifdef OLD_ENVIRON case TELOPT_NEW_ENVIRON: /* * The new environ option wasn't recognized, try * the old one. */ send_will(TELOPT_OLD_ENVIRON, 1); telopt_environ = TELOPT_OLD_ENVIRON; break; #endif } /* we always accept a DONT */ set_my_want_state_wont(option); if (my_state_is_will(option)) send_wont(option, 0); setconnmode(0); /* Set new tty mode */ } set_my_state_wont(option); } /* * Given a buffer returned by tgetent(), this routine will turn * the pipe seperated list of names in the buffer into an array * of pointers to null terminated names. We toss out any bad, * duplicate, or verbose names (names with spaces). */ static char *name_unknown = "UNKNOWN"; static char *unknown[] = { 0, 0 }; char ** mklist(buf, name) char *buf, *name; { register int n; register char c, *cp, **argvp, *cp2, **argv, **avt; if (name) { if ((int)strlen(name) > 40) { name = 0; unknown[0] = name_unknown; } else { unknown[0] = name; upcase(name); } } else unknown[0] = name_unknown; /* * Count up the number of names. */ for (n = 1, cp = buf; *cp && *cp != ':'; cp++) { if (*cp == '|') n++; } /* * Allocate an array to put the name pointers into */ argv = (char **)malloc((n+3)*sizeof(char *)); if (argv == 0) return(unknown); /* * Fill up the array of pointers to names. */ *argv = 0; argvp = argv+1; n = 0; for (cp = cp2 = buf; (c = *cp); cp++) { if (c == '|' || c == ':') { *cp++ = '\0'; /* * Skip entries that have spaces or are over 40 * characters long. If this is our environment * name, then put it up front. Otherwise, as * long as this is not a duplicate name (case * insensitive) add it to the list. */ if (n || (cp - cp2 > 41)) ; else if (name && (strncasecmp(name, cp2, cp-cp2) == 0)) *argv = cp2; else if (is_unique(cp2, argv+1, argvp)) *argvp++ = cp2; if (c == ':') break; /* * Skip multiple delimiters. Reset cp2 to * the beginning of the next name. Reset n, * the flag for names with spaces. */ while ((c = *cp) == '|') cp++; cp2 = cp; n = 0; } /* * Skip entries with spaces or non-ascii values. * Convert lower case letters to upper case. */ if ((c == ' ') || !isascii(c)) n = 1; else if (islower(c)) *cp = toupper(c); } /* * Check for an old V6 2 character name. If the second * name points to the beginning of the buffer, and is * only 2 characters long, move it to the end of the array. */ if ((argv[1] == buf) && (strlen(argv[1]) == 2)) { --argvp; for (avt = &argv[1]; avt < argvp; avt++) *avt = *(avt+1); *argvp++ = buf; } /* * Duplicate last name, for TTYPE option, and null * terminate the array. If we didn't find a match on * our terminal name, put that name at the beginning. */ cp = *(argvp-1); *argvp++ = cp; *argvp = 0; if (*argv == 0) { if (name) *argv = name; else { --argvp; for (avt = argv; avt < argvp; avt++) *avt = *(avt+1); } } if (*argv) return(argv); else return(unknown); } int is_unique(name, as, ae) register char *name, **as, **ae; { register char **ap; register int n; n = strlen(name) + 1; for (ap = as; ap < ae; ap++) if (strncasecmp(*ap, name, n) == 0) return(0); return (1); } #ifdef TERMCAP char termbuf[1024]; /*ARGSUSED*/ int setupterm(tname, fd, errp) char *tname; int fd, *errp; { if (tgetent(termbuf, tname) == 1) { termbuf[1023] = '\0'; if (errp) *errp = 1; return(0); } if (errp) *errp = 0; return(-1); } #else #define termbuf ttytype extern char ttytype[]; #endif int resettermname = 1; char * gettermname() { char *tname; static char **tnamep = 0; static char **next; int err; if (resettermname) { resettermname = 0; if (tnamep && tnamep != unknown) free(tnamep); if ((tname = (char *)env_getvalue((unsigned char *)"TERM")) && (setupterm(tname, 1, &err) == 0)) { tnamep = mklist(termbuf, tname); } else { if (tname && ((int)strlen(tname) <= 40)) { unknown[0] = tname; upcase(tname); } else unknown[0] = name_unknown; tnamep = unknown; } next = tnamep; } if (*next == 0) next = tnamep; return(*next++); } /* * suboption() * * Look at the sub-option buffer, and try to be helpful to the other * side. * * Currently we recognize: * * Terminal type, send request. * Terminal speed (send request). * Local flow control (is request). * Linemode */ static void suboption() { unsigned char subchar; printsub('<', subbuffer, SB_LEN()+2); switch (subchar = SB_GET()) { case TELOPT_TTYPE: if (my_want_state_is_wont(TELOPT_TTYPE)) return; if (SB_EOF() || SB_GET() != TELQUAL_SEND) { return; } else { char *name; unsigned char temp[50]; int len; #if defined(TN3270) if (tn3270_ttype()) { return; } #endif /* defined(TN3270) */ name = gettermname(); len = strlen(name) + 4 + 2; if (len < NETROOM()) { sprintf((char *)temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, TELQUAL_IS, name, IAC, SE); ring_supply_data(&netoring, temp, len); printsub('>', &temp[2], len-2); } else { ExitString("No room in buffer for terminal type.\n", 1); /*NOTREACHED*/ } } break; case TELOPT_TSPEED: if (my_want_state_is_wont(TELOPT_TSPEED)) return; if (SB_EOF()) return; if (SB_GET() == TELQUAL_SEND) { long ospeed, ispeed; unsigned char temp[50]; int len; TerminalSpeeds(&ispeed, &ospeed); - sprintf((char *)temp, "%c%c%c%c%d,%d%c%c", IAC, SB, TELOPT_TSPEED, + sprintf((char *)temp, "%c%c%c%c%ld,%ld%c%c", IAC, SB, TELOPT_TSPEED, TELQUAL_IS, ospeed, ispeed, IAC, SE); len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */ if (len < NETROOM()) { ring_supply_data(&netoring, temp, len); printsub('>', temp+2, len - 2); } /*@*/ else printf("lm_will: not enough room in buffer\n"); } break; case TELOPT_LFLOW: if (my_want_state_is_wont(TELOPT_LFLOW)) return; if (SB_EOF()) return; switch(SB_GET()) { case LFLOW_RESTART_ANY: restartany = 1; break; case LFLOW_RESTART_XON: restartany = 0; break; case LFLOW_ON: localflow = 1; break; case LFLOW_OFF: localflow = 0; break; default: return; } setcommandmode(); setconnmode(0); break; case TELOPT_LINEMODE: if (my_want_state_is_wont(TELOPT_LINEMODE)) return; if (SB_EOF()) return; switch (SB_GET()) { case WILL: lm_will(subpointer, SB_LEN()); break; case WONT: lm_wont(subpointer, SB_LEN()); break; case DO: lm_do(subpointer, SB_LEN()); break; case DONT: lm_dont(subpointer, SB_LEN()); break; case LM_SLC: slc(subpointer, SB_LEN()); break; case LM_MODE: lm_mode(subpointer, SB_LEN(), 0); break; default: break; } break; #ifdef OLD_ENVIRON case TELOPT_OLD_ENVIRON: #endif case TELOPT_NEW_ENVIRON: if (SB_EOF()) return; switch(SB_PEEK()) { case TELQUAL_IS: case TELQUAL_INFO: if (my_want_state_is_dont(subchar)) return; break; case TELQUAL_SEND: if (my_want_state_is_wont(subchar)) { return; } break; default: return; } env_opt(subpointer, SB_LEN()); break; case TELOPT_XDISPLOC: if (my_want_state_is_wont(TELOPT_XDISPLOC)) return; if (SB_EOF()) return; if (SB_GET() == TELQUAL_SEND) { unsigned char temp[50], *dp; int len; if ((dp = env_getvalue((unsigned char *)"DISPLAY")) == NULL) { /* * Something happened, we no longer have a DISPLAY * variable. So, turn off the option. */ send_wont(TELOPT_XDISPLOC, 1); break; } sprintf((char *)temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC, TELQUAL_IS, dp, IAC, SE); len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */ if (len < NETROOM()) { ring_supply_data(&netoring, temp, len); printsub('>', temp+2, len - 2); } /*@*/ else printf("lm_will: not enough room in buffer\n"); } break; #if defined(AUTHENTICATION) case TELOPT_AUTHENTICATION: { if (!autologin) break; if (SB_EOF()) return; switch(SB_GET()) { case TELQUAL_IS: if (my_want_state_is_dont(TELOPT_AUTHENTICATION)) return; auth_is(subpointer, SB_LEN()); break; case TELQUAL_SEND: if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) return; auth_send(subpointer, SB_LEN()); break; case TELQUAL_REPLY: if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) return; auth_reply(subpointer, SB_LEN()); break; case TELQUAL_NAME: if (my_want_state_is_dont(TELOPT_AUTHENTICATION)) return; auth_name(subpointer, SB_LEN()); break; } } break; #endif #ifdef ENCRYPTION case TELOPT_ENCRYPT: if (SB_EOF()) return; switch(SB_GET()) { case ENCRYPT_START: if (my_want_state_is_dont(TELOPT_ENCRYPT)) return; encrypt_start(subpointer, SB_LEN()); break; case ENCRYPT_END: if (my_want_state_is_dont(TELOPT_ENCRYPT)) return; encrypt_end(); break; case ENCRYPT_SUPPORT: if (my_want_state_is_wont(TELOPT_ENCRYPT)) return; encrypt_support(subpointer, SB_LEN()); break; case ENCRYPT_REQSTART: if (my_want_state_is_wont(TELOPT_ENCRYPT)) return; encrypt_request_start(subpointer, SB_LEN()); break; case ENCRYPT_REQEND: if (my_want_state_is_wont(TELOPT_ENCRYPT)) return; /* * 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_IS: if (my_want_state_is_dont(TELOPT_ENCRYPT)) return; encrypt_is(subpointer, SB_LEN()); break; case ENCRYPT_REPLY: if (my_want_state_is_wont(TELOPT_ENCRYPT)) return; encrypt_reply(subpointer, SB_LEN()); break; case ENCRYPT_ENC_KEYID: if (my_want_state_is_dont(TELOPT_ENCRYPT)) return; encrypt_enc_keyid(subpointer, SB_LEN()); break; case ENCRYPT_DEC_KEYID: if (my_want_state_is_wont(TELOPT_ENCRYPT)) return; encrypt_dec_keyid(subpointer, SB_LEN()); break; default: break; } break; #endif /* ENCRYPTION */ default: break; } } static unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE }; void lm_will(cmd, len) unsigned char *cmd; int len; { if (len < 1) { /*@*/ printf("lm_will: no command!!!\n"); /* Should not happen... */ return; } switch(cmd[0]) { case LM_FORWARDMASK: /* We shouldn't ever get this... */ default: str_lm[3] = DONT; str_lm[4] = cmd[0]; if (NETROOM() > sizeof(str_lm)) { ring_supply_data(&netoring, str_lm, sizeof(str_lm)); printsub('>', &str_lm[2], sizeof(str_lm)-2); } /*@*/ else printf("lm_will: not enough room in buffer\n"); break; } } void lm_wont(cmd, len) unsigned char *cmd; int len; { if (len < 1) { /*@*/ printf("lm_wont: no command!!!\n"); /* Should not happen... */ return; } switch(cmd[0]) { case LM_FORWARDMASK: /* We shouldn't ever get this... */ default: /* We are always DONT, so don't respond */ return; } } void lm_do(cmd, len) unsigned char *cmd; int len; { if (len < 1) { /*@*/ printf("lm_do: no command!!!\n"); /* Should not happen... */ return; } switch(cmd[0]) { case LM_FORWARDMASK: default: str_lm[3] = WONT; str_lm[4] = cmd[0]; if (NETROOM() > sizeof(str_lm)) { ring_supply_data(&netoring, str_lm, sizeof(str_lm)); printsub('>', &str_lm[2], sizeof(str_lm)-2); } /*@*/ else printf("lm_do: not enough room in buffer\n"); break; } } void lm_dont(cmd, len) unsigned char *cmd; int len; { if (len < 1) { /*@*/ printf("lm_dont: no command!!!\n"); /* Should not happen... */ return; } switch(cmd[0]) { case LM_FORWARDMASK: default: /* we are always WONT, so don't respond */ break; } } static unsigned char str_lm_mode[] = { IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE }; void lm_mode(cmd, len, init) unsigned char *cmd; int len, init; { if (len != 1) return; if ((linemode&MODE_MASK&~MODE_ACK) == *cmd) return; if (*cmd&MODE_ACK) return; linemode = *cmd&(MODE_MASK&~MODE_ACK); str_lm_mode[4] = linemode; if (!init) str_lm_mode[4] |= MODE_ACK; if (NETROOM() > sizeof(str_lm_mode)) { ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode)); printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2); } /*@*/ else printf("lm_mode: not enough room in buffer\n"); setconnmode(0); /* set changed mode */ } /* * slc() * Handle special character suboption of LINEMODE. */ struct spc { cc_t val; cc_t *valp; char flags; /* Current flags & level */ char mylevel; /* Maximum level & flags */ } spc_data[NSLC+1]; #define SLC_IMPORT 0 #define SLC_EXPORT 1 #define SLC_RVALUE 2 static int slc_mode = SLC_EXPORT; void slc_init() { register struct spc *spcp; localchars = 1; for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) { spcp->val = 0; spcp->valp = 0; spcp->flags = spcp->mylevel = SLC_NOSUPPORT; } #define initfunc(func, flags) { \ spcp = &spc_data[func]; \ - if (spcp->valp = tcval(func)) { \ + if ((spcp->valp = tcval(func))) { \ spcp->val = *spcp->valp; \ spcp->mylevel = SLC_VARIABLE|flags; \ } else { \ spcp->val = 0; \ spcp->mylevel = SLC_DEFAULT; \ } \ } initfunc(SLC_SYNCH, 0); /* No BRK */ initfunc(SLC_AO, 0); initfunc(SLC_AYT, 0); /* No EOR */ initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT); initfunc(SLC_EOF, 0); #ifndef SYSV_TERMIO initfunc(SLC_SUSP, SLC_FLUSHIN); #endif initfunc(SLC_EC, 0); initfunc(SLC_EL, 0); #ifndef SYSV_TERMIO initfunc(SLC_EW, 0); initfunc(SLC_RP, 0); initfunc(SLC_LNEXT, 0); #endif initfunc(SLC_XON, 0); initfunc(SLC_XOFF, 0); #ifdef SYSV_TERMIO spc_data[SLC_XON].mylevel = SLC_CANTCHANGE; spc_data[SLC_XOFF].mylevel = SLC_CANTCHANGE; #endif initfunc(SLC_FORW1, 0); #ifdef USE_TERMIO initfunc(SLC_FORW2, 0); /* No FORW2 */ #endif initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT); #undef initfunc if (slc_mode == SLC_EXPORT) slc_export(); else slc_import(1); } void slcstate() { printf("Special characters are %s values\n", slc_mode == SLC_IMPORT ? "remote default" : slc_mode == SLC_EXPORT ? "local" : "remote"); } void slc_mode_export() { slc_mode = SLC_EXPORT; if (my_state_is_will(TELOPT_LINEMODE)) slc_export(); } void slc_mode_import(def) int def; { slc_mode = def ? SLC_IMPORT : SLC_RVALUE; if (my_state_is_will(TELOPT_LINEMODE)) slc_import(def); } unsigned char slc_import_val[] = { IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE }; unsigned char slc_import_def[] = { IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE }; void slc_import(def) int def; { if (NETROOM() > sizeof(slc_import_val)) { if (def) { ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def)); printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2); } else { ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val)); printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2); } } /*@*/ else printf("slc_import: not enough room\n"); } void slc_export() { register struct spc *spcp; TerminalDefaultChars(); slc_start_reply(); for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { if (spcp->mylevel != SLC_NOSUPPORT) { if (spcp->val == (cc_t)(_POSIX_VDISABLE)) spcp->flags = SLC_NOSUPPORT; else spcp->flags = spcp->mylevel; if (spcp->valp) spcp->val = *spcp->valp; slc_add_reply(spcp - spc_data, spcp->flags, spcp->val); } } slc_end_reply(); (void)slc_update(); setconnmode(1); /* Make sure the character values are set */ } void slc(cp, len) register unsigned char *cp; int len; { register struct spc *spcp; register int func,level; slc_start_reply(); for (; len >= 3; len -=3, cp +=3) { func = cp[SLC_FUNC]; if (func == 0) { /* * Client side: always ignore 0 function. */ continue; } if (func > NSLC) { if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT) slc_add_reply(func, SLC_NOSUPPORT, 0); continue; } spcp = &spc_data[func]; level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK); if ((cp[SLC_VALUE] == (unsigned char)spcp->val) && ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) { continue; } if (level == (SLC_DEFAULT|SLC_ACK)) { /* * This is an error condition, the SLC_ACK * bit should never be set for the SLC_DEFAULT * level. Our best guess to recover is to * ignore the SLC_ACK bit. */ cp[SLC_FLAGS] &= ~SLC_ACK; } if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) { spcp->val = (cc_t)cp[SLC_VALUE]; spcp->flags = cp[SLC_FLAGS]; /* include SLC_ACK */ continue; } level &= ~SLC_ACK; if (level <= (spcp->mylevel&SLC_LEVELBITS)) { spcp->flags = cp[SLC_FLAGS]|SLC_ACK; spcp->val = (cc_t)cp[SLC_VALUE]; } if (level == SLC_DEFAULT) { if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT) spcp->flags = spcp->mylevel; else spcp->flags = SLC_NOSUPPORT; } slc_add_reply(func, spcp->flags, spcp->val); } slc_end_reply(); if (slc_update()) setconnmode(1); /* set the new character values */ } void slc_check() { register struct spc *spcp; slc_start_reply(); for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { if (spcp->valp && spcp->val != *spcp->valp) { spcp->val = *spcp->valp; if (spcp->val == (cc_t)(_POSIX_VDISABLE)) spcp->flags = SLC_NOSUPPORT; else spcp->flags = spcp->mylevel; slc_add_reply(spcp - spc_data, spcp->flags, spcp->val); } } slc_end_reply(); setconnmode(1); } unsigned char slc_reply[128]; unsigned char *slc_replyp; void slc_start_reply() { slc_replyp = slc_reply; *slc_replyp++ = IAC; *slc_replyp++ = SB; *slc_replyp++ = TELOPT_LINEMODE; *slc_replyp++ = LM_SLC; } void slc_add_reply(func, flags, value) unsigned char func; unsigned char flags; cc_t value; { if ((*slc_replyp++ = func) == IAC) *slc_replyp++ = IAC; if ((*slc_replyp++ = flags) == IAC) *slc_replyp++ = IAC; if ((*slc_replyp++ = (unsigned char)value) == IAC) *slc_replyp++ = IAC; } void slc_end_reply() { register int len; *slc_replyp++ = IAC; *slc_replyp++ = SE; len = slc_replyp - slc_reply; if (len <= 6) return; if (NETROOM() > len) { ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply); printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2); } /*@*/else printf("slc_end_reply: not enough room\n"); } int slc_update() { register struct spc *spcp; int need_update = 0; for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { if (!(spcp->flags&SLC_ACK)) continue; spcp->flags &= ~SLC_ACK; if (spcp->valp && (*spcp->valp != spcp->val)) { *spcp->valp = spcp->val; need_update = 1; } } return(need_update); } #ifdef OLD_ENVIRON # ifdef ENV_HACK /* * Earlier version of telnet/telnetd from the BSD code had * the definitions of VALUE and VAR reversed. To ensure * maximum interoperability, we assume that the server is * an older BSD server, until proven otherwise. The newer * BSD servers should be able to handle either definition, * so it is better to use the wrong values if we don't * know what type of server it is. */ int env_auto = 1; int old_env_var = OLD_ENV_VAR; int old_env_value = OLD_ENV_VALUE; # else # define old_env_var OLD_ENV_VAR # define old_env_value OLD_ENV_VALUE # endif #endif void env_opt(buf, len) register unsigned char *buf; register int len; { register unsigned char *ep = 0, *epc = 0; register int i; switch(buf[0]&0xff) { case TELQUAL_SEND: env_opt_start(); if (len == 1) { env_opt_add(NULL); } else for (i = 1; i < len; i++) { switch (buf[i]&0xff) { #ifdef OLD_ENVIRON case OLD_ENV_VAR: # ifdef ENV_HACK if (telopt_environ == TELOPT_OLD_ENVIRON && env_auto) { /* Server has the same definitions */ old_env_var = OLD_ENV_VAR; old_env_value = OLD_ENV_VALUE; } /* FALL THROUGH */ # endif case OLD_ENV_VALUE: /* * Although OLD_ENV_VALUE is not legal, we will * still recognize it, just in case it is an * old server that has VAR & VALUE mixed up... */ /* FALL THROUGH */ #else case NEW_ENV_VAR: #endif case ENV_USERVAR: if (ep) { *epc = 0; env_opt_add(ep); } ep = epc = &buf[i+1]; break; case ENV_ESC: i++; /*FALL THROUGH*/ default: if (epc) *epc++ = buf[i]; break; } } if (ep) { *epc = 0; env_opt_add(ep); } env_opt_end(1); break; case TELQUAL_IS: case TELQUAL_INFO: /* Ignore for now. We shouldn't get it anyway. */ break; default: break; } } #define OPT_REPLY_SIZE 256 unsigned char *opt_reply; unsigned char *opt_replyp; unsigned char *opt_replyend; void env_opt_start() { if (opt_reply) opt_reply = (unsigned char *)realloc(opt_reply, OPT_REPLY_SIZE); else opt_reply = (unsigned char *)malloc(OPT_REPLY_SIZE); if (opt_reply == NULL) { /*@*/ printf("env_opt_start: malloc()/realloc() failed!!!\n"); opt_reply = opt_replyp = opt_replyend = NULL; return; } opt_replyp = opt_reply; opt_replyend = opt_reply + OPT_REPLY_SIZE; *opt_replyp++ = IAC; *opt_replyp++ = SB; *opt_replyp++ = telopt_environ; *opt_replyp++ = TELQUAL_IS; } void env_opt_start_info() { env_opt_start(); if (opt_replyp) opt_replyp[-1] = TELQUAL_INFO; } void env_opt_add(ep) register unsigned char *ep; { register unsigned char *vp, c; if (opt_reply == NULL) /*XXX*/ return; /*XXX*/ if (ep == NULL || *ep == '\0') { /* Send user defined variables first. */ env_default(1, 0); - while (ep = env_default(0, 0)) + while ((ep = env_default(0, 0))) env_opt_add(ep); /* Now add the list of well know variables. */ env_default(1, 1); - while (ep = env_default(0, 1)) + while ((ep = env_default(0, 1))) env_opt_add(ep); return; } vp = env_getvalue(ep); if (opt_replyp + (vp ? strlen((char *)vp) : 0) + strlen((char *)ep) + 6 > opt_replyend) { register int len; opt_replyend += OPT_REPLY_SIZE; len = opt_replyend - opt_reply; opt_reply = (unsigned char *)realloc(opt_reply, len); if (opt_reply == NULL) { /*@*/ printf("env_opt_add: realloc() failed!!!\n"); opt_reply = opt_replyp = opt_replyend = NULL; return; } opt_replyp = opt_reply + len - (opt_replyend - opt_replyp); opt_replyend = opt_reply + len; } if (opt_welldefined(ep)) #ifdef OLD_ENVIRON if (telopt_environ == TELOPT_OLD_ENVIRON) *opt_replyp++ = old_env_var; else #endif *opt_replyp++ = NEW_ENV_VAR; else *opt_replyp++ = ENV_USERVAR; for (;;) { - while (c = *ep++) { + while ((c = *ep++)) { switch(c&0xff) { case IAC: *opt_replyp++ = IAC; break; case NEW_ENV_VAR: case NEW_ENV_VALUE: case ENV_ESC: case ENV_USERVAR: *opt_replyp++ = ENV_ESC; break; } *opt_replyp++ = c; } - if (ep = vp) { + if ((ep = vp)) { #ifdef OLD_ENVIRON if (telopt_environ == TELOPT_OLD_ENVIRON) *opt_replyp++ = old_env_value; else #endif *opt_replyp++ = NEW_ENV_VALUE; vp = NULL; } else break; } } int opt_welldefined(ep) char *ep; { if ((strcmp(ep, "USER") == 0) || (strcmp(ep, "DISPLAY") == 0) || (strcmp(ep, "PRINTER") == 0) || (strcmp(ep, "SYSTEMTYPE") == 0) || (strcmp(ep, "JOB") == 0) || (strcmp(ep, "ACCT") == 0)) return(1); return(0); } void env_opt_end(emptyok) register int emptyok; { register int len; len = opt_replyp - opt_reply + 2; if (emptyok || len > 6) { *opt_replyp++ = IAC; *opt_replyp++ = SE; if (NETROOM() > len) { ring_supply_data(&netoring, opt_reply, len); printsub('>', &opt_reply[2], len - 2); } /*@*/ else printf("slc_end_reply: not enough room\n"); } if (opt_reply) { free(opt_reply); opt_reply = opt_replyp = opt_replyend = NULL; } } int telrcv() { register int c; register int scc; register unsigned char *sbp; int count; int returnValue = 0; scc = 0; count = 0; while (TTYROOM() > 2) { if (scc == 0) { if (count) { ring_consumed(&netiring, count); returnValue = 1; count = 0; } sbp = netiring.consume; scc = ring_full_consecutive(&netiring); if (scc == 0) { /* No more data coming in */ break; } } c = *sbp++ & 0xff, scc--; count++; #ifdef ENCRYPTION if (decrypt_input) c = (*decrypt_input)(c); #endif /* ENCRYPTION */ switch (telrcv_state) { case TS_CR: telrcv_state = TS_DATA; if (c == '\0') { break; /* Ignore \0 after CR */ } else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) { TTYADD(c); break; } /* Else, fall through */ case TS_DATA: if (c == IAC) { telrcv_state = TS_IAC; break; } # if defined(TN3270) if (In3270) { *Ifrontp++ = c; while (scc > 0) { c = *sbp++ & 0377, scc--; count++; #ifdef ENCRYPTION if (decrypt_input) c = (*decrypt_input)(c); #endif /* ENCRYPTION */ if (c == IAC) { telrcv_state = TS_IAC; break; } *Ifrontp++ = c; } } else # endif /* defined(TN3270) */ /* * The 'crmod' hack (see following) is needed * since we can't * set CRMOD on output only. * Machines like MULTICS like to send \r without * \n; since we must turn off CRMOD to get proper * input, the mapping is done here (sigh). */ if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) { if (scc > 0) { c = *sbp&0xff; #ifdef ENCRYPTION if (decrypt_input) c = (*decrypt_input)(c); #endif /* ENCRYPTION */ if (c == 0) { sbp++, scc--; count++; /* a "true" CR */ TTYADD('\r'); } else if (my_want_state_is_dont(TELOPT_ECHO) && (c == '\n')) { sbp++, scc--; count++; TTYADD('\n'); } else { #ifdef ENCRYPTION if (decrypt_input) (*decrypt_input)(-1); #endif /* ENCRYPTION */ TTYADD('\r'); if (crmod) { TTYADD('\n'); } } } else { telrcv_state = TS_CR; TTYADD('\r'); if (crmod) { TTYADD('\n'); } } } else { TTYADD(c); } continue; case TS_IAC: process_iac: switch (c) { case WILL: telrcv_state = TS_WILL; continue; case WONT: telrcv_state = TS_WONT; continue; case DO: telrcv_state = TS_DO; continue; case DONT: telrcv_state = TS_DONT; continue; case DM: /* * We may have missed an urgent notification, * so make sure we flush whatever is in the * buffer currently. */ printoption("RCVD", IAC, DM); SYNCHing = 1; (void) ttyflush(1); SYNCHing = stilloob(); settimer(gotDM); break; case SB: SB_CLEAR(); telrcv_state = TS_SB; continue; # if defined(TN3270) case EOR: if (In3270) { if (Ibackp == Ifrontp) { Ibackp = Ifrontp = Ibuf; ISend = 0; /* should have been! */ } else { Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1); ISend = 1; } } printoption("RCVD", IAC, EOR); break; # endif /* defined(TN3270) */ case IAC: # if !defined(TN3270) TTYADD(IAC); # else /* !defined(TN3270) */ if (In3270) { *Ifrontp++ = IAC; } else { TTYADD(IAC); } # endif /* !defined(TN3270) */ break; case NOP: case GA: default: printoption("RCVD", IAC, c); break; } telrcv_state = TS_DATA; continue; case TS_WILL: printoption("RCVD", WILL, c); willoption(c); SetIn3270(); telrcv_state = TS_DATA; continue; case TS_WONT: printoption("RCVD", WONT, c); wontoption(c); SetIn3270(); telrcv_state = TS_DATA; continue; case TS_DO: printoption("RCVD", DO, c); dooption(c); SetIn3270(); if (c == TELOPT_NAWS) { sendnaws(); } else if (c == TELOPT_LFLOW) { localflow = 1; setcommandmode(); setconnmode(0); } telrcv_state = TS_DATA; continue; case TS_DONT: printoption("RCVD", DONT, c); dontoption(c); flushline = 1; setconnmode(0); /* set new tty mode (maybe) */ SetIn3270(); telrcv_state = TS_DATA; continue; case TS_SB: if (c == IAC) { telrcv_state = TS_SE; } else { SB_ACCUM(c); } continue; case TS_SE: if (c != SE) { if (c != IAC) { /* * This is an error. We only expect to get * "IAC IAC" or "IAC SE". Several things may * have happend. An IAC was not doubled, the * IAC SE was left off, or another option got * inserted into the suboption are all possibilities. * If we assume that the IAC was not doubled, * and really the IAC SE was left off, we could * get into an infinate loop here. So, instead, * we terminate the suboption, and process the * partial suboption if we can. */ SB_ACCUM(IAC); SB_ACCUM(c); subpointer -= 2; SB_TERM(); printoption("In SUBOPTION processing, RCVD", IAC, c); suboption(); /* handle sub-option */ SetIn3270(); telrcv_state = TS_IAC; goto process_iac; } SB_ACCUM(c); telrcv_state = TS_SB; } else { SB_ACCUM(IAC); SB_ACCUM(SE); subpointer -= 2; SB_TERM(); suboption(); /* handle sub-option */ SetIn3270(); telrcv_state = TS_DATA; } } } if (count) ring_consumed(&netiring, count); return returnValue||count; } static int bol = 1, local = 0; int rlogin_susp() { if (local) { local = 0; bol = 1; command(0, "z\n", 2); return(1); } return(0); } static int telsnd() { int tcc; int count; int returnValue = 0; unsigned char *tbp; tcc = 0; count = 0; while (NETROOM() > 2) { register int sc; register int c; if (tcc == 0) { if (count) { ring_consumed(&ttyiring, count); returnValue = 1; count = 0; } tbp = ttyiring.consume; tcc = ring_full_consecutive(&ttyiring); if (tcc == 0) { break; } } c = *tbp++ & 0xff, sc = strip(c), tcc--; count++; if (rlogin != _POSIX_VDISABLE) { if (bol) { bol = 0; if (sc == rlogin) { local = 1; continue; } } else if (local) { local = 0; if (sc == '.' || c == termEofChar) { bol = 1; command(0, "close\n", 6); continue; } if (sc == termSuspChar) { bol = 1; command(0, "z\n", 2); continue; } if (sc == escape) { command(0, (char *)tbp, tcc); bol = 1; count += tcc; tcc = 0; flushline = 1; break; } if (sc != rlogin) { ++tcc; --tbp; --count; c = sc = rlogin; } } if ((sc == '\n') || (sc == '\r')) bol = 1; } else if (sc == escape) { /* * Double escape is a pass through of a single escape character. */ if (tcc && strip(*tbp) == escape) { tbp++; tcc--; count++; bol = 0; } else { command(0, (char *)tbp, tcc); bol = 1; count += tcc; tcc = 0; flushline = 1; break; } } else bol = 0; #ifdef KLUDGELINEMODE if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) { if (tcc > 0 && strip(*tbp) == echoc) { tcc--; tbp++; count++; } else { dontlecho = !dontlecho; settimer(echotoggle); setconnmode(0); flushline = 1; break; } } #endif if (MODE_LOCAL_CHARS(globalmode)) { if (TerminalSpecialChars(sc) == 0) { bol = 1; break; } } if (my_want_state_is_wont(TELOPT_BINARY)) { switch (c) { case '\n': /* * If we are in CRMOD mode (\r ==> \n) * on our local machine, then probably * a newline (unix) is CRLF (TELNET). */ if (MODE_LOCAL_CHARS(globalmode)) { NETADD('\r'); } NETADD('\n'); bol = flushline = 1; break; case '\r': if (!crlf) { NET2ADD('\r', '\0'); } else { NET2ADD('\r', '\n'); } bol = flushline = 1; break; case IAC: NET2ADD(IAC, IAC); break; default: NETADD(c); break; } } else if (c == IAC) { NET2ADD(IAC, IAC); } else { NETADD(c); } } if (count) ring_consumed(&ttyiring, count); return returnValue||count; /* Non-zero if we did anything */ } /* * Scheduler() * * Try to do something. * * If we do something useful, return 1; else return 0. * */ int Scheduler(block) int block; /* should we block in the select ? */ { /* One wants to be a bit careful about setting returnValue * to one, since a one implies we did some useful work, * and therefore probably won't be called to block next * time (TN3270 mode only). */ int returnValue; int netin, netout, netex, ttyin, ttyout; /* Decide which rings should be processed */ netout = ring_full_count(&netoring) && (flushline || (my_want_state_is_wont(TELOPT_LINEMODE) #ifdef KLUDGELINEMODE && (!kludgelinemode || my_want_state_is_do(TELOPT_SGA)) #endif ) || my_want_state_is_will(TELOPT_BINARY)); ttyout = ring_full_count(&ttyoring); #if defined(TN3270) - ttyin = ring_empty_count(&ttyiring) && (shell_active == 0); + ttyin = ring_empty_count(&ttyiring) && (clienteof == 0) && (shell_active == 0); #else /* defined(TN3270) */ - ttyin = ring_empty_count(&ttyiring); + ttyin = ring_empty_count(&ttyiring) && (clienteof == 0); #endif /* defined(TN3270) */ #if defined(TN3270) netin = ring_empty_count(&netiring); # else /* !defined(TN3270) */ netin = !ISend && ring_empty_count(&netiring); # endif /* !defined(TN3270) */ netex = !SYNCHing; /* If we have seen a signal recently, reset things */ # if defined(TN3270) && defined(unix) if (HaveInput) { HaveInput = 0; (void) signal(SIGIO, inputAvailable); } #endif /* defined(TN3270) && defined(unix) */ /* Call to system code to process rings */ returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block); /* Now, look at the input rings, looking for work to do. */ if (ring_full_count(&ttyiring)) { # if defined(TN3270) if (In3270) { int c; c = DataFromTerminal(ttyiring.consume, ring_full_consecutive(&ttyiring)); if (c) { returnValue = 1; ring_consumed(&ttyiring, c); } } else { # endif /* defined(TN3270) */ returnValue |= telsnd(); # if defined(TN3270) } # endif /* defined(TN3270) */ } if (ring_full_count(&netiring)) { # if !defined(TN3270) returnValue |= telrcv(); # else /* !defined(TN3270) */ returnValue = Push3270(); # endif /* !defined(TN3270) */ } return returnValue; } /* * Select from tty and network... */ void telnet(user) char *user; { sys_telnet_init(); #if defined(AUTHENTICATION) || defined(ENCRYPTION) { static char local_host[256] = { 0 }; if (!local_host[0]) { gethostname(local_host, sizeof(local_host)); local_host[sizeof(local_host)-1] = 0; } auth_encrypt_init(local_host, hostname, "TELNET", 0); auth_encrypt_user(user); } #endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */ # if !defined(TN3270) if (telnetport) { #if defined(AUTHENTICATION) if (autologin) send_will(TELOPT_AUTHENTICATION, 1); #endif #ifdef ENCRYPTION send_do(TELOPT_ENCRYPT, 1); send_will(TELOPT_ENCRYPT, 1); #endif /* ENCRYPTION */ send_do(TELOPT_SGA, 1); send_will(TELOPT_TTYPE, 1); send_will(TELOPT_NAWS, 1); send_will(TELOPT_TSPEED, 1); send_will(TELOPT_LFLOW, 1); send_will(TELOPT_LINEMODE, 1); send_will(TELOPT_NEW_ENVIRON, 1); send_do(TELOPT_STATUS, 1); if (env_getvalue((unsigned char *)"DISPLAY")) send_will(TELOPT_XDISPLOC, 1); if (eight) tel_enter_binary(eight); } # endif /* !defined(TN3270) */ # if !defined(TN3270) for (;;) { int schedValue; while ((schedValue = Scheduler(0)) != 0) { if (schedValue == -1) { setcommandmode(); return; } } if (Scheduler(1) == -1) { setcommandmode(); return; } } # else /* !defined(TN3270) */ for (;;) { int schedValue; while (!In3270 && !shell_active) { if (Scheduler(1) == -1) { setcommandmode(); return; } } while ((schedValue = Scheduler(0)) != 0) { if (schedValue == -1) { setcommandmode(); return; } } /* If there is data waiting to go out to terminal, don't * schedule any more data for the terminal. */ if (ring_full_count(&ttyoring)) { schedValue = 1; } else { if (shell_active) { if (shell_continue() == 0) { ConnectScreen(); } } else if (In3270) { schedValue = DoTerminalOutput(); } } if (schedValue && (shell_active == 0)) { if (Scheduler(1) == -1) { setcommandmode(); return; } } } # endif /* !defined(TN3270) */ } #if 0 /* XXX - this not being in is a bug */ /* * nextitem() * * Return the address of the next "item" in the TELNET data * stream. This will be the address of the next character if * the current address is a user data character, or it will * be the address of the character following the TELNET command * if the current address is a TELNET IAC ("I Am a Command") * character. */ static char * nextitem(current) char *current; { if ((*current&0xff) != IAC) { return current+1; } switch (*(current+1)&0xff) { case DO: case DONT: case WILL: case WONT: return current+3; case SB: /* loop forever looking for the SE */ { register char *look = current+2; for (;;) { if ((*look++&0xff) == IAC) { if ((*look++&0xff) == SE) { return look; } } } } default: return current+2; } } #endif /* 0 */ /* * netclear() * * We are about to do a TELNET SYNCH operation. Clear * the path to the network. * * Things are a bit tricky since we may have sent the first * byte or so of a previous TELNET command into the network. * So, we have to scan the network buffer from the beginning * until we are up to where we want to be. * * A side effect of what we do, just to keep things * simple, is to clear the urgent data pointer. The principal * caller should be setting the urgent data pointer AFTER calling * us in any case. */ static void netclear() { #if 0 /* XXX */ register char *thisitem, *next; char *good; #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) thisitem = netobuf; while ((next = nextitem(thisitem)) <= netobuf.send) { thisitem = next; } /* Now, thisitem is first before/at boundary. */ good = netobuf; /* where the good bytes go */ while (netoring.add > 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); } } #endif /* 0 */ } /* * These routines add various telnet commands to the data stream. */ static void doflush() { NET2ADD(IAC, DO); NETADD(TELOPT_TM); flushline = 1; flushout = 1; (void) ttyflush(1); /* Flush/drop output */ /* do printoption AFTER flush, otherwise the output gets tossed... */ printoption("SENT", DO, TELOPT_TM); } void xmitAO() { NET2ADD(IAC, AO); printoption("SENT", IAC, AO); if (autoflush) { doflush(); } } void xmitEL() { NET2ADD(IAC, EL); printoption("SENT", IAC, EL); } void xmitEC() { NET2ADD(IAC, EC); printoption("SENT", IAC, EC); } int dosynch() { netclear(); /* clear the path to the network */ NETADD(IAC); setneturg(); NETADD(DM); printoption("SENT", IAC, DM); return 1; } int want_status_response = 0; int get_status() { unsigned char tmp[16]; register unsigned char *cp; if (my_want_state_is_dont(TELOPT_STATUS)) { printf("Remote side does not support STATUS option\n"); return 0; } cp = tmp; *cp++ = IAC; *cp++ = SB; *cp++ = TELOPT_STATUS; *cp++ = TELQUAL_SEND; *cp++ = IAC; *cp++ = SE; if (NETROOM() >= cp - tmp) { ring_supply_data(&netoring, tmp, cp-tmp); printsub('>', tmp+2, cp - tmp - 2); } ++want_status_response; return 1; } void intp() { NET2ADD(IAC, IP); printoption("SENT", IAC, IP); flushline = 1; if (autoflush) { doflush(); } if (autosynch) { dosynch(); } } void sendbrk() { NET2ADD(IAC, BREAK); printoption("SENT", IAC, BREAK); flushline = 1; if (autoflush) { doflush(); } if (autosynch) { dosynch(); } } void sendabort() { NET2ADD(IAC, ABORT); printoption("SENT", IAC, ABORT); flushline = 1; if (autoflush) { doflush(); } if (autosynch) { dosynch(); } } void sendsusp() { NET2ADD(IAC, SUSP); printoption("SENT", IAC, SUSP); flushline = 1; if (autoflush) { doflush(); } if (autosynch) { dosynch(); } } void sendeof() { NET2ADD(IAC, xEOF); printoption("SENT", IAC, xEOF); } void sendayt() { NET2ADD(IAC, AYT); printoption("SENT", IAC, AYT); } /* * Send a window size update to the remote system. */ void sendnaws() { long rows, cols; unsigned char tmp[16]; register unsigned char *cp; if (my_state_is_wont(TELOPT_NAWS)) return; #define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \ if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; } if (TerminalWindowSize(&rows, &cols) == 0) { /* Failed */ return; } cp = tmp; *cp++ = IAC; *cp++ = SB; *cp++ = TELOPT_NAWS; PUTSHORT(cp, cols); PUTSHORT(cp, rows); *cp++ = IAC; *cp++ = SE; if (NETROOM() >= cp - tmp) { ring_supply_data(&netoring, tmp, cp-tmp); printsub('>', tmp+2, cp - tmp - 2); } } void tel_enter_binary(rw) int rw; { if (rw&1) send_do(TELOPT_BINARY, 1); if (rw&2) send_will(TELOPT_BINARY, 1); } void tel_leave_binary(rw) int rw; { if (rw&1) send_dont(TELOPT_BINARY, 1); if (rw&2) send_wont(TELOPT_BINARY, 1); } diff --git a/contrib/telnet/telnet/terminal.c b/contrib/telnet/telnet/terminal.c index b5ceeda2b525..a2383d9e6696 100644 --- a/contrib/telnet/telnet/terminal.c +++ b/contrib/telnet/telnet/terminal.c @@ -1,240 +1,244 @@ /* * Copyright (c) 1988, 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. */ #ifndef lint -static char sccsid[] = "@(#)terminal.c 8.2 (Berkeley) 2/16/95"; +static const char sccsid[] = "@(#)terminal.c 8.2 (Berkeley) 2/16/95"; #endif /* not lint */ #include #include #include "ring.h" #include "externs.h" #include "types.h" +#if defined(ENCRYPTION) +#include +#endif + Ring ttyoring, ttyiring; unsigned char ttyobuf[2*BUFSIZ], ttyibuf[BUFSIZ]; int termdata; /* Debugging flag */ #ifdef USE_TERMIO # ifndef VDISCARD cc_t termFlushChar; # endif # ifndef VLNEXT cc_t termLiteralNextChar; # endif # ifndef VSUSP cc_t termSuspChar; # endif # ifndef VWERASE cc_t termWerasChar; # endif # ifndef VREPRINT cc_t termRprntChar; # endif # ifndef VSTART cc_t termStartChar; # endif # ifndef VSTOP cc_t termStopChar; # endif # ifndef VEOL cc_t termForw1Char; # endif # ifndef VEOL2 cc_t termForw2Char; # endif # ifndef VSTATUS cc_t termAytChar; # endif #else cc_t termForw2Char; cc_t termAytChar; #endif /* * initialize the terminal data structures. */ void init_terminal() { if (ring_init(&ttyoring, ttyobuf, sizeof ttyobuf) != 1) { exit(1); } if (ring_init(&ttyiring, ttyibuf, sizeof ttyibuf) != 1) { exit(1); } autoflush = TerminalAutoFlush(); } /* * Send as much data as possible to the terminal. * * Return value: * -1: No useful work done, data waiting to go out. * 0: No data was waiting, so nothing was done. * 1: All waiting data was written out. * n: All data - n was written out. */ int ttyflush(drop) int drop; { register int n, n0, n1; n0 = ring_full_count(&ttyoring); if ((n1 = n = ring_full_consecutive(&ttyoring)) > 0) { if (drop) { TerminalFlushOutput(); /* we leave 'n' alone! */ } else { n = TerminalWrite(ttyoring.consume, n); } } if (n > 0) { if (termdata && n) { Dump('>', ttyoring.consume, n); } /* * If we wrote everything, and the full count is * larger than what we wrote, then write the * rest of the buffer. */ if (n1 == n && n0 > n) { n1 = n0 - n; if (!drop) n1 = TerminalWrite(ttyoring.bottom, n1); if (n1 > 0) n += n1; } ring_consumed(&ttyoring, n); } if (n < 0) return -1; if (n == n0) { if (n0) return -1; return 0; } return n0 - n + 1; } /* * These routines decides on what the mode should be (based on the values * of various global variables). */ int getconnmode() { extern int linemode; int mode = 0; #ifdef KLUDGELINEMODE extern int kludgelinemode; #endif if (In3270) return(MODE_FLOW); if (my_want_state_is_dont(TELOPT_ECHO)) mode |= MODE_ECHO; if (localflow) mode |= MODE_FLOW; if (my_want_state_is_will(TELOPT_BINARY)) mode |= MODE_INBIN; if (his_want_state_is_will(TELOPT_BINARY)) mode |= MODE_OUTBIN; #ifdef KLUDGELINEMODE if (kludgelinemode) { if (my_want_state_is_dont(TELOPT_SGA)) { mode |= (MODE_TRAPSIG|MODE_EDIT); if (dontlecho && (clocks.echotoggle > clocks.modenegotiated)) { mode &= ~MODE_ECHO; } } return(mode); } #endif if (my_want_state_is_will(TELOPT_LINEMODE)) mode |= linemode; return(mode); } void setconnmode(force) int force; { #ifdef ENCRYPTION static int enc_passwd = 0; #endif /* ENCRYPTION */ register int newmode; newmode = getconnmode()|(force?MODE_FORCE:0); TerminalNewMode(newmode); #ifdef ENCRYPTION if ((newmode & (MODE_ECHO|MODE_EDIT)) == MODE_EDIT) { if (my_want_state_is_will(TELOPT_ENCRYPT) && (enc_passwd == 0) && !encrypt_output) { encrypt_request_start(0, 0); enc_passwd = 1; } } else { if (enc_passwd) { encrypt_request_end(); enc_passwd = 0; } } #endif /* ENCRYPTION */ } void setcommandmode() { TerminalNewMode(-1); } diff --git a/contrib/telnet/telnet/tn3270.c b/contrib/telnet/telnet/tn3270.c index a75cd1ecb5a9..5a453d98cc5b 100644 --- a/contrib/telnet/telnet/tn3270.c +++ b/contrib/telnet/telnet/tn3270.c @@ -1,411 +1,411 @@ /* * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. */ #ifndef lint -static char sccsid[] = "@(#)tn3270.c 8.2 (Berkeley) 5/30/95"; +static const char sccsid[] = "@(#)tn3270.c 8.2 (Berkeley) 5/30/95"; #endif /* not lint */ #include #include #include "general.h" #include "defines.h" #include "ring.h" #include "externs.h" #include "fdset.h" #if defined(TN3270) #include "../ctlr/screen.h" #include "../general/globals.h" #include "../sys_curses/telextrn.h" #include "../ctlr/externs.h" #if defined(unix) int HaveInput, /* There is input available to scan */ cursesdata, /* Do we dump curses data? */ sigiocount; /* Number of times we got a SIGIO */ char tline[200]; char *transcom = 0; /* transparent mode command (default: none) */ #endif /* defined(unix) */ char Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp; static char sb_terminal[] = { IAC, SB, TELOPT_TTYPE, TELQUAL_IS, 'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2', IAC, SE }; #define SBTERMMODEL 13 static int Sent3270TerminalType; /* Have we said we are a 3270? */ #endif /* defined(TN3270) */ void init_3270() { #if defined(TN3270) #if defined(unix) HaveInput = 0; sigiocount = 0; #endif /* defined(unix) */ Sent3270TerminalType = 0; Ifrontp = Ibackp = Ibuf; init_ctlr(); /* Initialize some things */ init_keyboard(); init_screen(); init_system(); #endif /* defined(TN3270) */ } #if defined(TN3270) /* * DataToNetwork - queue up some data to go to network. If "done" is set, * then when last byte is queued, we add on an IAC EOR sequence (so, * don't call us with "done" until you want that done...) * * We actually do send all the data to the network buffer, since our * only client needs for us to do that. */ int DataToNetwork(buffer, count, done) register char *buffer; /* where the data is */ register int count; /* how much to send */ int done; /* is this the last of a logical block */ { register int loop, c; int origCount; origCount = count; while (count) { /* If not enough room for EORs, IACs, etc., wait */ if (NETROOM() < 6) { fd_set o; FD_ZERO(&o); netflush(); while (NETROOM() < 6) { FD_SET(net, &o); (void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0, (struct timeval *) 0); netflush(); } } c = ring_empty_count(&netoring); if (c > count) { c = count; } loop = c; while (loop) { if (((unsigned char)*buffer) == IAC) { break; } buffer++; loop--; } if ((c = c-loop)) { ring_supply_data(&netoring, buffer-c, c); count -= c; } if (loop) { NET2ADD(IAC, IAC); count--; buffer++; } } if (done) { NET2ADD(IAC, EOR); netflush(); /* try to move along as quickly as ... */ } return(origCount - count); } #if defined(unix) void inputAvailable(signo) int signo; { HaveInput = 1; sigiocount++; } #endif /* defined(unix) */ void outputPurge() { (void) ttyflush(1); } /* * The following routines are places where the various tn3270 * routines make calls into telnet.c. */ /* * DataToTerminal - queue up some data to go to terminal. * * Note: there are people who call us and depend on our processing * *all* the data at one time (thus the select). */ int DataToTerminal(buffer, count) register char *buffer; /* where the data is */ register int count; /* how much to send */ { register int c; int origCount; origCount = count; while (count) { if (TTYROOM() == 0) { #if defined(unix) fd_set o; FD_ZERO(&o); #endif /* defined(unix) */ (void) ttyflush(0); while (TTYROOM() == 0) { #if defined(unix) FD_SET(tout, &o); (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0, (struct timeval *) 0); #endif /* defined(unix) */ (void) ttyflush(0); } } c = TTYROOM(); if (c > count) { c = count; } ring_supply_data(&ttyoring, buffer, c); count -= c; buffer += c; } return(origCount); } /* * Push3270 - Try to send data along the 3270 output (to screen) direction. */ int Push3270() { int save = ring_full_count(&netiring); if (save) { if (Ifrontp+save > Ibuf+sizeof Ibuf) { if (Ibackp != Ibuf) { memmove(Ibuf, Ibackp, Ifrontp-Ibackp); Ifrontp -= (Ibackp-Ibuf); Ibackp = Ibuf; } } if (Ifrontp+save < Ibuf+sizeof Ibuf) { (void)telrcv(); } } return save != ring_full_count(&netiring); } /* * Finish3270 - get the last dregs of 3270 data out to the terminal * before quitting. */ void Finish3270() { while (Push3270() || !DoTerminalOutput()) { #if defined(unix) HaveInput = 0; #endif /* defined(unix) */ ; } } /* StringToTerminal - output a null terminated string to the terminal */ void StringToTerminal(s) char *s; { int count; count = strlen(s); if (count) { (void) DataToTerminal(s, count); /* we know it always goes... */ } } #if ((!defined(NOT43)) || defined(PUTCHAR)) /* _putchar - output a single character to the terminal. This name is so that * curses(3x) can call us to send out data. */ void _putchar(c) char c; { #if defined(sun) /* SunOS 4.0 bug */ c &= 0x7f; #endif /* defined(sun) */ if (cursesdata) { Dump('>', &c, 1); } if (!TTYROOM()) { (void) DataToTerminal(&c, 1); } else { TTYADD(c); } } #endif /* ((!defined(NOT43)) || defined(PUTCHAR)) */ void SetIn3270() { if (Sent3270TerminalType && my_want_state_is_will(TELOPT_BINARY) && my_want_state_is_do(TELOPT_BINARY) && !donebinarytoggle) { if (!In3270) { In3270 = 1; Init3270(); /* Initialize 3270 functions */ /* initialize terminal key mapping */ InitTerminal(); /* Start terminal going */ setconnmode(0); } } else { if (In3270) { StopScreen(1); In3270 = 0; Stop3270(); /* Tell 3270 we aren't here anymore */ setconnmode(0); } } } /* * tn3270_ttype() * * Send a response to a terminal type negotiation. * * Return '0' if no more responses to send; '1' if a response sent. */ int tn3270_ttype() { /* * Try to send a 3270 type terminal name. Decide which one based * on the format of our screen, and (in the future) color * capaiblities. */ InitTerminal(); /* Sets MaxNumberColumns, MaxNumberLines */ if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) { Sent3270TerminalType = 1; if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) { MaxNumberLines = 27; MaxNumberColumns = 132; sb_terminal[SBTERMMODEL] = '5'; } else if (MaxNumberLines >= 43) { MaxNumberLines = 43; MaxNumberColumns = 80; sb_terminal[SBTERMMODEL] = '4'; } else if (MaxNumberLines >= 32) { MaxNumberLines = 32; MaxNumberColumns = 80; sb_terminal[SBTERMMODEL] = '3'; } else { MaxNumberLines = 24; MaxNumberColumns = 80; sb_terminal[SBTERMMODEL] = '2'; } NumberLines = 24; /* before we start out... */ NumberColumns = 80; ScreenSize = NumberLines*NumberColumns; if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) { ExitString("Programming error: MAXSCREENSIZE too small.\n", 1); /*NOTREACHED*/ } printsub('>', sb_terminal+2, sizeof sb_terminal-2); ring_supply_data(&netoring, sb_terminal, sizeof sb_terminal); return 1; } else { return 0; } } #if defined(unix) int settranscom(argc, argv) int argc; char *argv[]; { int i; if (argc == 1 && transcom) { transcom = 0; } if (argc == 1) { return 1; } transcom = tline; (void) strcpy(transcom, argv[1]); for (i = 2; i < argc; ++i) { (void) strcat(transcom, " "); (void) strcat(transcom, argv[i]); } return 1; } #endif /* defined(unix) */ #endif /* defined(TN3270) */ diff --git a/contrib/telnet/telnet/utilities.c b/contrib/telnet/telnet/utilities.c index 06d08a45120c..0ee882ebd87c 100644 --- a/contrib/telnet/telnet/utilities.c +++ b/contrib/telnet/telnet/utilities.c @@ -1,939 +1,946 @@ /* * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. */ #ifndef lint -static char sccsid[] = "@(#)utilities.c 8.3 (Berkeley) 5/30/95"; +static const char sccsid[] = "@(#)utilities.c 8.3 (Berkeley) 5/30/95"; #endif /* not lint */ #define TELOPTS #define TELCMDS #define SLC_NAMES #include #include +#include #include +#include #include #include "general.h" #include "fdset.h" #include "ring.h" #include "defines.h" #include "externs.h" +#if defined(AUTHENTICATION) +#include +#endif +#if defined(ENCRYPTION) +#include +#endif + FILE *NetTrace = 0; /* Not in bss, since needs to stay */ int prettydump; /* * upcase() * * Upcase (in place) the argument. */ void upcase(argument) register char *argument; { register int c; while ((c = *argument) != 0) { if (islower(c)) { *argument = toupper(c); } argument++; } } /* * SetSockOpt() * * Compensate for differences in 4.2 and 4.3 systems. */ int SetSockOpt(fd, level, option, yesno) int fd, level, option, yesno; { #ifndef NOT43 return setsockopt(fd, level, option, (char *)&yesno, sizeof yesno); #else /* NOT43 */ if (yesno == 0) { /* Can't do that in 4.2! */ fprintf(stderr, "Error: attempt to turn off an option 0x%x.\n", option); return -1; } return setsockopt(fd, level, option, 0, 0); #endif /* NOT43 */ } /* * The following are routines used to print out debugging information. */ unsigned char NetTraceFile[256] = "(standard output)"; void SetNetTrace(file) register char *file; { if (NetTrace && NetTrace != stdout) fclose(NetTrace); if (file && (strcmp(file, "-") != 0)) { NetTrace = fopen(file, "w"); if (NetTrace) { strcpy((char *)NetTraceFile, file); return; } fprintf(stderr, "Cannot open %s.\n", file); } NetTrace = stdout; strcpy((char *)NetTraceFile, "(standard output)"); } void Dump(direction, buffer, length) char direction; unsigned char *buffer; int length; { # define BYTES_PER_LINE 32 # define min(x,y) ((x' */ unsigned char *pointer; /* where suboption data sits */ int length; /* length of suboption data */ { register int i; char buf[512]; extern int want_status_response; if (showoptions || direction == 0 || (want_status_response && (pointer[0] == TELOPT_STATUS))) { if (direction) { fprintf(NetTrace, "%s IAC SB ", (direction == '<')? "RCVD":"SENT"); if (length >= 3) { register int j; i = pointer[length-2]; j = pointer[length-1]; if (i != IAC || j != SE) { fprintf(NetTrace, "(terminated by "); if (TELOPT_OK(i)) fprintf(NetTrace, "%s ", TELOPT(i)); else if (TELCMD_OK(i)) fprintf(NetTrace, "%s ", TELCMD(i)); else fprintf(NetTrace, "%d ", i); if (TELOPT_OK(j)) fprintf(NetTrace, "%s", TELOPT(j)); else if (TELCMD_OK(j)) fprintf(NetTrace, "%s", TELCMD(j)); else fprintf(NetTrace, "%d", j); fprintf(NetTrace, ", not IAC SE!) "); } } length -= 2; } if (length < 1) { fprintf(NetTrace, "(Empty suboption??\?)"); if (NetTrace == stdout) fflush(NetTrace); return; } switch (pointer[0]) { case TELOPT_TTYPE: fprintf(NetTrace, "TERMINAL-TYPE "); switch (pointer[1]) { case TELQUAL_IS: fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2); break; case TELQUAL_SEND: fprintf(NetTrace, "SEND"); break; default: fprintf(NetTrace, "- unknown qualifier %d (0x%x).", pointer[1], pointer[1]); } break; case TELOPT_TSPEED: fprintf(NetTrace, "TERMINAL-SPEED"); if (length < 2) { fprintf(NetTrace, " (empty suboption??\?)"); break; } switch (pointer[1]) { case TELQUAL_IS: fprintf(NetTrace, " IS "); fprintf(NetTrace, "%.*s", length-2, (char *)pointer+2); break; default: if (pointer[1] == 1) fprintf(NetTrace, " SEND"); else fprintf(NetTrace, " %d (unknown)", pointer[1]); for (i = 2; i < length; i++) fprintf(NetTrace, " ?%d?", pointer[i]); break; } break; case TELOPT_LFLOW: fprintf(NetTrace, "TOGGLE-FLOW-CONTROL"); if (length < 2) { fprintf(NetTrace, " (empty suboption??\?)"); break; } switch (pointer[1]) { case LFLOW_OFF: fprintf(NetTrace, " OFF"); break; case LFLOW_ON: fprintf(NetTrace, " ON"); break; case LFLOW_RESTART_ANY: fprintf(NetTrace, " RESTART-ANY"); break; case LFLOW_RESTART_XON: fprintf(NetTrace, " RESTART-XON"); break; default: fprintf(NetTrace, " %d (unknown)", pointer[1]); } for (i = 2; i < length; i++) fprintf(NetTrace, " ?%d?", pointer[i]); break; case TELOPT_NAWS: fprintf(NetTrace, "NAWS"); if (length < 2) { fprintf(NetTrace, " (empty suboption??\?)"); break; } if (length == 2) { fprintf(NetTrace, " ?%d?", pointer[1]); break; } fprintf(NetTrace, " %d %d (%d)", pointer[1], pointer[2], (int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2]))); if (length == 4) { fprintf(NetTrace, " ?%d?", pointer[3]); break; } fprintf(NetTrace, " %d %d (%d)", pointer[3], pointer[4], (int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4]))); for (i = 5; i < length; i++) fprintf(NetTrace, " ?%d?", pointer[i]); break; #if defined(AUTHENTICATION) case TELOPT_AUTHENTICATION: fprintf(NetTrace, "AUTHENTICATION"); if (length < 2) { fprintf(NetTrace, " (empty suboption??\?)"); break; } switch (pointer[1]) { case TELQUAL_REPLY: case TELQUAL_IS: fprintf(NetTrace, " %s ", (pointer[1] == TELQUAL_IS) ? "IS" : "REPLY"); if (AUTHTYPE_NAME_OK(pointer[2])) fprintf(NetTrace, "%s ", AUTHTYPE_NAME(pointer[2])); else fprintf(NetTrace, "%d ", pointer[2]); if (length < 3) { fprintf(NetTrace, "(partial suboption??\?)"); break; } fprintf(NetTrace, "%s|%s", ((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? "CLIENT" : "SERVER", ((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? "MUTUAL" : "ONE-WAY"); auth_printsub(&pointer[1], length - 1, buf, sizeof(buf)); fprintf(NetTrace, "%s", buf); break; case TELQUAL_SEND: i = 2; fprintf(NetTrace, " SEND "); while (i < length) { if (AUTHTYPE_NAME_OK(pointer[i])) fprintf(NetTrace, "%s ", AUTHTYPE_NAME(pointer[i])); else fprintf(NetTrace, "%d ", pointer[i]); if (++i >= length) { fprintf(NetTrace, "(partial suboption??\?)"); break; } fprintf(NetTrace, "%s|%s ", ((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? "CLIENT" : "SERVER", ((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? "MUTUAL" : "ONE-WAY"); ++i; } break; case TELQUAL_NAME: i = 2; fprintf(NetTrace, " NAME \""); while (i < length) putc(pointer[i++], NetTrace); putc('"', NetTrace); break; default: for (i = 2; i < length; i++) fprintf(NetTrace, " ?%d?", pointer[i]); break; } break; #endif #ifdef ENCRYPTION case TELOPT_ENCRYPT: fprintf(NetTrace, "ENCRYPT"); if (length < 2) { fprintf(NetTrace, " (empty suboption??\?)"); break; } switch (pointer[1]) { case ENCRYPT_START: fprintf(NetTrace, " START"); break; case ENCRYPT_END: fprintf(NetTrace, " END"); break; case ENCRYPT_REQSTART: fprintf(NetTrace, " REQUEST-START"); break; case ENCRYPT_REQEND: fprintf(NetTrace, " REQUEST-END"); break; case ENCRYPT_IS: case ENCRYPT_REPLY: fprintf(NetTrace, " %s ", (pointer[1] == ENCRYPT_IS) ? "IS" : "REPLY"); if (length < 3) { fprintf(NetTrace, " (partial suboption??\?)"); break; } if (ENCTYPE_NAME_OK(pointer[2])) fprintf(NetTrace, "%s ", ENCTYPE_NAME(pointer[2])); else fprintf(NetTrace, " %d (unknown)", pointer[2]); encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf)); fprintf(NetTrace, "%s", buf); break; case ENCRYPT_SUPPORT: i = 2; fprintf(NetTrace, " SUPPORT "); while (i < length) { if (ENCTYPE_NAME_OK(pointer[i])) fprintf(NetTrace, "%s ", ENCTYPE_NAME(pointer[i])); else fprintf(NetTrace, "%d ", pointer[i]); i++; } break; case ENCRYPT_ENC_KEYID: fprintf(NetTrace, " ENC_KEYID "); goto encommon; case ENCRYPT_DEC_KEYID: fprintf(NetTrace, " DEC_KEYID "); goto encommon; default: fprintf(NetTrace, " %d (unknown)", pointer[1]); encommon: for (i = 2; i < length; i++) fprintf(NetTrace, " %d", pointer[i]); break; } break; #endif /* ENCRYPTION */ case TELOPT_LINEMODE: fprintf(NetTrace, "LINEMODE "); if (length < 2) { fprintf(NetTrace, " (empty suboption??\?)"); break; } switch (pointer[1]) { case WILL: fprintf(NetTrace, "WILL "); goto common; case WONT: fprintf(NetTrace, "WONT "); goto common; case DO: fprintf(NetTrace, "DO "); goto common; case DONT: fprintf(NetTrace, "DONT "); common: if (length < 3) { fprintf(NetTrace, "(no option??\?)"); break; } switch (pointer[2]) { case LM_FORWARDMASK: fprintf(NetTrace, "Forward Mask"); for (i = 3; i < length; i++) fprintf(NetTrace, " %x", pointer[i]); break; default: fprintf(NetTrace, "%d (unknown)", pointer[2]); for (i = 3; i < length; i++) fprintf(NetTrace, " %d", pointer[i]); break; } break; case LM_SLC: fprintf(NetTrace, "SLC"); for (i = 2; i < length - 2; i += 3) { if (SLC_NAME_OK(pointer[i+SLC_FUNC])) fprintf(NetTrace, " %s", SLC_NAME(pointer[i+SLC_FUNC])); else fprintf(NetTrace, " %d", pointer[i+SLC_FUNC]); switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) { case SLC_NOSUPPORT: fprintf(NetTrace, " NOSUPPORT"); break; case SLC_CANTCHANGE: fprintf(NetTrace, " CANTCHANGE"); break; case SLC_VARIABLE: fprintf(NetTrace, " VARIABLE"); break; case SLC_DEFAULT: fprintf(NetTrace, " DEFAULT"); break; } fprintf(NetTrace, "%s%s%s", pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "", pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "", pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : ""); if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN| SLC_FLUSHOUT| SLC_LEVELBITS)) fprintf(NetTrace, "(0x%x)", pointer[i+SLC_FLAGS]); fprintf(NetTrace, " %d;", pointer[i+SLC_VALUE]); if ((pointer[i+SLC_VALUE] == IAC) && (pointer[i+SLC_VALUE+1] == IAC)) i++; } for (; i < length; i++) fprintf(NetTrace, " ?%d?", pointer[i]); break; case LM_MODE: fprintf(NetTrace, "MODE "); if (length < 3) { fprintf(NetTrace, "(no mode??\?)"); break; } { char tbuf[64]; sprintf(tbuf, "%s%s%s%s%s", pointer[2]&MODE_EDIT ? "|EDIT" : "", pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "", pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "", pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "", pointer[2]&MODE_ACK ? "|ACK" : ""); fprintf(NetTrace, "%s", tbuf[1] ? &tbuf[1] : "0"); } if (pointer[2]&~(MODE_MASK)) fprintf(NetTrace, " (0x%x)", pointer[2]); for (i = 3; i < length; i++) fprintf(NetTrace, " ?0x%x?", pointer[i]); break; default: fprintf(NetTrace, "%d (unknown)", pointer[1]); for (i = 2; i < length; i++) fprintf(NetTrace, " %d", pointer[i]); } break; case TELOPT_STATUS: { register char *cp; register int j, k; fprintf(NetTrace, "STATUS"); switch (pointer[1]) { default: if (pointer[1] == TELQUAL_SEND) fprintf(NetTrace, " SEND"); else fprintf(NetTrace, " %d (unknown)", pointer[1]); for (i = 2; i < length; i++) fprintf(NetTrace, " ?%d?", pointer[i]); break; case TELQUAL_IS: if (--want_status_response < 0) want_status_response = 0; if (NetTrace == stdout) fprintf(NetTrace, " IS\r\n"); else fprintf(NetTrace, " IS\n"); for (i = 2; i < length; i++) { switch(pointer[i]) { case DO: cp = "DO"; goto common2; case DONT: cp = "DONT"; goto common2; case WILL: cp = "WILL"; goto common2; case WONT: cp = "WONT"; goto common2; common2: i++; if (TELOPT_OK((int)pointer[i])) fprintf(NetTrace, " %s %s", cp, TELOPT(pointer[i])); else fprintf(NetTrace, " %s %d", cp, pointer[i]); if (NetTrace == stdout) fprintf(NetTrace, "\r\n"); else fprintf(NetTrace, "\n"); break; case SB: fprintf(NetTrace, " SB "); i++; j = k = i; while (j < length) { if (pointer[j] == SE) { if (j+1 == length) break; if (pointer[j+1] == SE) j++; else break; } pointer[k++] = pointer[j++]; } printsub(0, &pointer[i], k - i); if (i < length) { fprintf(NetTrace, " SE"); i = j; } else i = j - 1; if (NetTrace == stdout) fprintf(NetTrace, "\r\n"); else fprintf(NetTrace, "\n"); break; default: fprintf(NetTrace, " %d", pointer[i]); break; } } break; } break; } case TELOPT_XDISPLOC: fprintf(NetTrace, "X-DISPLAY-LOCATION "); switch (pointer[1]) { case TELQUAL_IS: fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2); break; case TELQUAL_SEND: fprintf(NetTrace, "SEND"); break; default: fprintf(NetTrace, "- unknown qualifier %d (0x%x).", pointer[1], pointer[1]); } break; case TELOPT_NEW_ENVIRON: fprintf(NetTrace, "NEW-ENVIRON "); #ifdef OLD_ENVIRON goto env_common1; case TELOPT_OLD_ENVIRON: fprintf(NetTrace, "OLD-ENVIRON"); env_common1: #endif switch (pointer[1]) { case TELQUAL_IS: fprintf(NetTrace, "IS "); goto env_common; case TELQUAL_SEND: fprintf(NetTrace, "SEND "); goto env_common; case TELQUAL_INFO: fprintf(NetTrace, "INFO "); env_common: { register int noquote = 2; #if defined(ENV_HACK) && defined(OLD_ENVIRON) extern int old_env_var, old_env_value; #endif for (i = 2; i < length; i++ ) { switch (pointer[i]) { case NEW_ENV_VALUE: #ifdef OLD_ENVIRON /* case NEW_ENV_OVAR: */ if (pointer[0] == TELOPT_OLD_ENVIRON) { # ifdef ENV_HACK if (old_env_var == OLD_ENV_VALUE) fprintf(NetTrace, "\" (VALUE) " + noquote); else # endif fprintf(NetTrace, "\" VAR " + noquote); } else #endif /* OLD_ENVIRON */ fprintf(NetTrace, "\" VALUE " + noquote); noquote = 2; break; case NEW_ENV_VAR: #ifdef OLD_ENVIRON /* case OLD_ENV_VALUE: */ if (pointer[0] == TELOPT_OLD_ENVIRON) { # ifdef ENV_HACK if (old_env_value == OLD_ENV_VAR) fprintf(NetTrace, "\" (VAR) " + noquote); else # endif fprintf(NetTrace, "\" VALUE " + noquote); } else #endif /* OLD_ENVIRON */ fprintf(NetTrace, "\" VAR " + noquote); noquote = 2; break; case ENV_ESC: fprintf(NetTrace, "\" ESC " + noquote); noquote = 2; break; case ENV_USERVAR: fprintf(NetTrace, "\" USERVAR " + noquote); noquote = 2; break; default: - def_case: if (isprint(pointer[i]) && pointer[i] != '"') { if (noquote) { putc('"', NetTrace); noquote = 0; } putc(pointer[i], NetTrace); } else { fprintf(NetTrace, "\" %03o " + noquote, pointer[i]); noquote = 2; } break; } } if (!noquote) putc('"', NetTrace); break; } } break; default: if (TELOPT_OK(pointer[0])) fprintf(NetTrace, "%s (unknown)", TELOPT(pointer[0])); else fprintf(NetTrace, "%d (unknown)", pointer[0]); for (i = 1; i < length; i++) fprintf(NetTrace, " %d", pointer[i]); break; } if (direction) { if (NetTrace == stdout) fprintf(NetTrace, "\r\n"); else fprintf(NetTrace, "\n"); } if (NetTrace == stdout) fflush(NetTrace); } } /* EmptyTerminal - called to make sure that the terminal buffer is empty. * Note that we consider the buffer to run all the * way to the kernel (thus the select). */ void EmptyTerminal() { #if defined(unix) fd_set o; FD_ZERO(&o); #endif /* defined(unix) */ if (TTYBYTES() == 0) { #if defined(unix) FD_SET(tout, &o); (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0, (struct timeval *) 0); /* wait for TTLOWAT */ #endif /* defined(unix) */ } else { while (TTYBYTES()) { (void) ttyflush(0); #if defined(unix) FD_SET(tout, &o); (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0, (struct timeval *) 0); /* wait for TTLOWAT */ #endif /* defined(unix) */ } } } void SetForExit() { setconnmode(0); #if defined(TN3270) if (In3270) { Finish3270(); } #else /* defined(TN3270) */ do { (void)telrcv(); /* Process any incoming data */ EmptyTerminal(); } while (ring_full_count(&netiring)); /* While there is any */ #endif /* defined(TN3270) */ setcommandmode(); fflush(stdout); fflush(stderr); #if defined(TN3270) if (In3270) { StopScreen(1); } #endif /* defined(TN3270) */ setconnmode(0); EmptyTerminal(); /* Flush the path to the tty */ setcommandmode(); } void Exit(returnCode) int returnCode; { SetForExit(); exit(returnCode); } void ExitString(string, returnCode) char *string; int returnCode; { SetForExit(); fwrite(string, 1, strlen(string), stderr); exit(returnCode); } diff --git a/contrib/telnet/telnetd/authenc.c b/contrib/telnet/telnetd/authenc.c index ccb463c94d1e..bff80a2b5879 100644 --- a/contrib/telnet/telnetd/authenc.c +++ b/contrib/telnet/telnetd/authenc.c @@ -1,91 +1,91 @@ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. */ #ifndef lint -static char sccsid[] = "@(#)authenc.c 8.2 (Berkeley) 5/30/95"; +static const char sccsid[] = "@(#)authenc.c 8.2 (Berkeley) 5/30/95"; #endif /* not lint */ #if defined(AUTHENTICATION) || defined(ENCRYPTION) #include "telnetd.h" #include int net_write(str, len) unsigned char *str; int len; { if (nfrontp + len < netobuf + BUFSIZ) { memmove((void *)nfrontp, (void *)str, len); nfrontp += len; return(len); } return(0); } void net_encrypt() { #ifdef ENCRYPTION char *s = (nclearto > nbackp) ? nclearto : nbackp; if (s < nfrontp && encrypt_output) { (*encrypt_output)((unsigned char *)s, nfrontp - s); } nclearto = nfrontp; #endif /* ENCRYPTION */ } int telnet_spin() { ttloop(); return(0); } char * telnet_getenv(val) char *val; { extern char *getenv(); return(getenv(val)); } char * telnet_gets(prompt, result, length, echo) char *prompt; char *result; int length; int echo; { return((char *)0); } #endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */ diff --git a/contrib/telnet/telnetd/ext.h b/contrib/telnet/telnetd/ext.h index 19bc0d638296..f60139e078ac 100644 --- a/contrib/telnet/telnetd/ext.h +++ b/contrib/telnet/telnetd/ext.h @@ -1,240 +1,242 @@ /* * 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. * * @(#)ext.h 8.2 (Berkeley) 12/15/93 */ /* * 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(SecurID) extern int require_SecurID; #endif #if defined(AUTHENTICATION) extern int auth_level; #endif extern slcfun slctab[NSLC + 1]; /* slc mapping table */ char *terminaltype; /* * I/O data buffers, pointers, and counters. */ 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 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; extern int SYNCHing; /* we are in TELNET SYNCH mode */ #ifndef P # ifdef __STDC__ # define P(x) x # else # define P(x) () # endif #endif 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 int end_slc P((unsigned char **)), getnpty P((void)), #ifndef convex getpty P((int *)), #endif login_tty P((int)), 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)); #ifdef ENCRYPTION extern void (*encrypt_output) P((unsigned char *, int)); extern int (*decrypt_input) P((int)); extern char *nclearto; #endif /* ENCRYPTION */ /* * The following are some clocks used to decide how to interpret * the relationship between various variables. */ extern struct { int system, /* what the current time is */ echotoggle, /* last time user entered echo character */ modenegotiated, /* last time operating mode negotiated */ didnetreceive, /* last time we read data from network */ ttypesubopt, /* ttype subopt is received */ tspeedsubopt, /* tspeed subopt is received */ environsubopt, /* environ subopt is received */ oenvironsubopt, /* old environ subopt is received */ xdisplocsubopt, /* xdisploc subopt is received */ baseline, /* time started to do timed action */ gotDM; /* when did we last see a data mark */ } clocks; #if defined(CRAY2) && defined(UNICOS5) extern int needtermstat; #endif #ifndef DEFAULT_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 +# ifdef __FreeBSD__ +# define DEFAULT_IM "\r\n\r\nFreeBSD (%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 # endif # endif #endif diff --git a/contrib/telnet/telnetd/global.c b/contrib/telnet/telnetd/global.c index af21acc69fb1..0699d005d48b 100644 --- a/contrib/telnet/telnetd/global.c +++ b/contrib/telnet/telnetd/global.c @@ -1,48 +1,48 @@ /* * 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. */ #ifndef lint -static char sccsid[] = "@(#)global.c 8.1 (Berkeley) 6/4/93"; +static const char sccsid[] = "@(#)global.c 8.1 (Berkeley) 6/4/93"; #endif /* not lint */ /* * 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. */ #include "defs.h" #define extern #include "ext.h" diff --git a/contrib/telnet/telnetd/slc.c b/contrib/telnet/telnetd/slc.c index 6cbb7ababa1b..9579d0df32ff 100644 --- a/contrib/telnet/telnetd/slc.c +++ b/contrib/telnet/telnetd/slc.c @@ -1,491 +1,491 @@ /* * 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. */ #ifndef lint -static char sccsid[] = "@(#)slc.c 8.2 (Berkeley) 5/30/95"; +static const char sccsid[] = "@(#)slc.c 8.2 (Berkeley) 5/30/95"; #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 */ /* * 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 char func, flag; register cc_t val; { register int hislevel, mylevel; hislevel = flag & SLC_LEVELBITS; - mylevel = slctab[func].defset.flag & SLC_LEVELBITS; + mylevel = slctab[(int)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; + slctab[(int)func].current.flag = flag; + slctab[(int)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; + slctab[(int)func].current.flag = SLC_NOSUPPORT; } else { - slctab[func].current.flag = slctab[func].defset.flag; + slctab[(int)func].current.flag = slctab[(int)func].defset.flag; } - slctab[func].current.val = slctab[func].defset.val; - add_slc(func, slctab[func].current.flag, - slctab[func].current.val); + slctab[(int)func].current.val = slctab[(int)func].defset.val; + add_slc(func, slctab[(int)func].current.flag, + slctab[(int)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) { + if (slctab[(int)func].sptr) { /* * We can change this one. */ - slctab[func].current.val = val; - *(slctab[func].sptr) = val; - slctab[func].current.flag = flag; + slctab[(int)func].current.val = val; + *(slctab[(int)func].sptr) = val; + slctab[(int)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; + slctab[(int)func].current.flag = flag; + slctab[(int)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; + slctab[(int)func].current.flag = flag; } else { flag &= ~SLC_LEVELBITS; flag |= mylevel; - slctab[func].current.flag = flag; + slctab[(int)func].current.flag = flag; if (mylevel == SLC_CANTCHANGE) { - slctab[func].current.val = - slctab[func].defset.val; - val = slctab[func].current.val; + slctab[(int)func].current.val = + slctab[(int)func].defset.val; + val = slctab[(int)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 */ memmove(def_slcbuf, ptr, 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 */ diff --git a/contrib/telnet/telnetd/state.c b/contrib/telnet/telnetd/state.c index 4ee8bea66f97..faf4088b537f 100644 --- a/contrib/telnet/telnetd/state.c +++ b/contrib/telnet/telnetd/state.c @@ -1,1612 +1,1615 @@ /* * 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. */ #ifndef lint -static char sccsid[] = "@(#)state.c 8.5 (Berkeley) 5/30/95"; +static const char sccsid[] = "@(#)state.c 8.5 (Berkeley) 5/30/95"; #endif /* not lint */ #include "telnetd.h" #if defined(AUTHENTICATION) #include #endif +#if defined(ENCRYPTION) +#include +#endif unsigned char doopt[] = { IAC, DO, '%', 'c', 0 }; unsigned char dont[] = { IAC, DONT, '%', 'c', 0 }; unsigned char will[] = { IAC, WILL, '%', 'c', 0 }; unsigned char wont[] = { IAC, WONT, '%', 'c', 0 }; int not42 = 1; /* * Buffer for sub-options, and macros * for suboptions buffer manipulations */ unsigned char subbuffer[512], *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); \ } #define SB_GET() ((*subpointer++)&0xff) #define SB_EOF() (subpointer >= subend) #define SB_LEN() (subend - subpointer) #ifdef ENV_HACK unsigned char *subsave; #define SB_SAVE() subsave = subpointer; #define SB_RESTORE() subpointer = subsave; #endif /* * State for recv fsm */ #define TS_DATA 0 /* base state */ #define TS_IAC 1 /* look for double IAC's */ #define TS_CR 2 /* CR-LF ->'s CR */ #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 " */ void telrcv() { register int c; static int state = TS_DATA; #if defined(CRAY2) && defined(UNICOS5) char *opfrontp = pfrontp; #endif while (ncc > 0) { if ((&ptyobuf[BUFSIZ] - pfrontp) < 2) break; c = *netip++ & 0377, ncc--; #ifdef ENCRYPTION if (decrypt_input) c = (*decrypt_input)(c); #endif /* ENCRYPTION */ 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_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 /* ENCRYPTION */ #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 #endif { #ifdef ENCRYPTION if (decrypt_input) (void)(*decrypt_input)(-1); #endif /* ENCRYPTION */ 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; } /* * 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); 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); } } #if defined(CRAY2) && defined(UNICOS5) if (!linemode) { char xptyobuf[BUFSIZ+NETSLOP]; char xbuf2[BUFSIZ]; register char *cp; int n = pfrontp - opfrontp, oc; memmove(xptyobuf, opfrontp, n); pfrontp = opfrontp; pfrontp += term_input(xptyobuf, pfrontp, n, BUFSIZ+NETSLOP, xbuf2, &oc, BUFSIZ); for (cp = xbuf2; oc > 0; --oc) if ((*nfrontp++ = *cp++) == IAC) *nfrontp++ = IAC; } #endif /* defined(CRAY2) && defined(UNICOS5) */ } /* end of telrcv */ /* * The will/wont/do/dont state machines are based on Dave Borman's * Telnet option processing state machine. * * These correspond to the following states: * my_state = the last negotiated state * want_state = what I want the state to go to * want_resp = how many requests I have sent * All state defaults are negative, and resp defaults to 0. * * When initiating a request to change state to new_state: * * if ((want_resp == 0 && new_state == my_state) || want_state == new_state) { * do nothing; * } else { * want_state = new_state; * send new_state; * want_resp++; * } * * When receiving new_state: * * if (want_resp) { * want_resp--; * if (want_resp && (new_state == my_state)) * want_resp--; * } * if ((want_resp == 0) && (new_state != want_state)) { * if (ok_to_switch_to new_state) * want_state = new_state; * else * want_resp++; * send want_state; * } * my_state = new_state; * * Note that new_state is implied in these functions by the function itself. * will and do imply positive new_state, wont and dont imply negative. * * Finally, there is one catch. If we send a negative response to a * positive request, my_state will be the positive while want_state will * remain negative. my_state will revert to negative when the negative * acknowlegment arrives from the peer. Thus, my_state generally tells * us not only the last negotiated state, but also tells us what the peer * wants to be doing as well. It is important to understand this difference * as we may wish to be processing data streams based on our desired state * (want_state) or based on what the peer thinks the state is (my_state). * * This all works fine because if the peer sends a positive request, the data * that we receive prior to negative acknowlegment will probably be affected * by the positive state, and we can process it as such (if we can; if we * can't then it really doesn't matter). If it is that important, then the * peer probably should be buffering until this option state negotiation * is complete. * */ void send_do(option, init) int option, 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)); } #ifdef AUTHENTICATION extern void auth_request(); #endif #ifdef LINEMODE extern void doclientstat(); #endif #ifdef ENCRYPTION extern void encrypt_send_support(); #endif /* ENCRYPTION */ void willoption(option) int 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; case TELOPT_ECHO: /* * See comments below for more info. */ not42 = 0; /* looks like a 4.2 system */ break; 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; #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; #endif #ifdef ENCRYPTION case TELOPT_ENCRYPT: func = encrypt_send_support; changeok++; break; #endif /* ENCRYPTION */ 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 */ /* * 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 */ #ifdef AUTHENTICATION case TELOPT_AUTHENTICATION: func = auth_request; break; #endif #ifdef ENCRYPTION case TELOPT_ENCRYPT: func = encrypt_send_support; break; #endif /* ENCRYPTION */ case TELOPT_LFLOW: func = flowstat; break; } } } set_his_state_will(option); if (func) (*func)(); } /* end of willoption */ void send_dont(option, init) int option, 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)); } void wontoption(option) int option; { /* * Process client input. */ 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; case TELOPT_BINARY: init_termbuf(); tty_binaryin(0); set_termbuf(); break; #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; #if defined(AUTHENTICATION) case TELOPT_AUTHENTICATION: auth_finished(0, AUTH_REJECT); break; #endif /* * For options that we might spin waiting for * sub-negotiation, if the client turns off the * option rather than responding to the request, * we have to treat it here as if we got a response * 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_TSPEED: settimer(tspeedsubopt); break; case TELOPT_XDISPLOC: settimer(xdisplocsubopt); break; case TELOPT_OLD_ENVIRON: settimer(oenvironsubopt); 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; #if defined(AUTHENTICATION) case TELOPT_AUTHENTICATION: auth_finished(0, AUTH_REJECT); break; #endif default: break; } } } set_his_state_wont(option); } /* end of wontoption */ void send_will(option, init) int option, 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 !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 * leave it at that. This is so that when we talk to * clients that understand KLUDGELINEMODE but not LINEMODE, * we'll keep them in char-at-a-time mode. */ int turn_on_sga = 0; #endif void dooption(option) int option; { 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: #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_BINARY: init_termbuf(); tty_binaryout(1); set_termbuf(); 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_STATUS: 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_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; #endif /* ENCRYPTION */ 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: #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); } } set_my_state_will(option); } /* end of dooption */ void send_wont(option, init) int option, 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)); } void dontoption(option) int option; { /* * Process client input. */ 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; 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_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; } set_my_want_state_wont(option); if (my_state_is_will(option)) send_wont(option, 0); } set_my_state_wont(option); } /* end of dontoption */ #ifdef ENV_HACK int env_ovar = -1; int env_ovalue = -1; #else /* ENV_HACK */ # define env_ovar OLD_ENV_VAR # define env_ovalue OLD_ENV_VALUE #endif /* ENV_HACK */ /* * suboption() * * Look at the sub-option buffer, and try to be helpful to the other * side. * * Currently we recognize: * * Terminal type is * Linemode * Window size * Terminal speed */ void suboption() { register int subchar; DIAG(TD_OPTIONS, {netflush(); printsub('<', subpointer, SB_LEN()+2);}); subchar = SB_GET(); switch (subchar) { case TELOPT_TSPEED: { register int xspeed, rspeed; if (his_state_is_wont(TELOPT_TSPEED)) /* Ignore if option disabled */ break; settimer(tspeedsubopt); if (SB_EOF() || SB_GET() != TELQUAL_IS) return; xspeed = atoi((char *)subpointer); while (SB_GET() != ',' && !SB_EOF()); if (SB_EOF()) return; rspeed = atoi((char *)subpointer); clientstat(TELOPT_TSPEED, xspeed, rspeed); break; } /* end of case TELOPT_TSPEED */ case TELOPT_TTYPE: { /* Yaaaay! */ static char terminalname[41]; if (his_state_is_wont(TELOPT_TTYPE)) /* Ignore if option disabled */ break; settimer(ttypesubopt); if (SB_EOF() || SB_GET() != TELQUAL_IS) { return; /* ??? XXX but, this is the most robust */ } terminaltype = terminalname; while ((terminaltype < (terminalname + sizeof terminalname-1)) && !SB_EOF()) { register int c; c = SB_GET(); if (isupper(c)) { c = tolower(c); } *terminaltype++ = c; /* accumulate name */ } *terminaltype = 0; terminaltype = terminalname; break; } /* end of case TELOPT_TTYPE */ case TELOPT_NAWS: { register int xwinsize, ywinsize; if (his_state_is_wont(TELOPT_NAWS)) /* Ignore if option disabled */ break; if (SB_EOF()) return; xwinsize = SB_GET() << 8; if (SB_EOF()) return; xwinsize |= SB_GET(); if (SB_EOF()) return; ywinsize = SB_GET() << 8; if (SB_EOF()) return; ywinsize |= SB_GET(); clientstat(TELOPT_NAWS, xwinsize, ywinsize); break; } /* 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; if (SB_EOF()) break; mode = SB_GET(); switch (mode) { case TELQUAL_SEND: if (my_state_is_will(TELOPT_STATUS)) send_status(); break; case TELQUAL_IS: break; default: break; } break; } /* end of case TELOPT_STATUS */ case TELOPT_XDISPLOC: { if (SB_EOF() || SB_GET() != TELQUAL_IS) return; settimer(xdisplocsubopt); subpointer[SB_LEN()] = '\0'; (void)setenv("DISPLAY", (char *)subpointer, 1); break; } /* end of case TELOPT_XDISPLOC */ #ifdef TELOPT_NEW_ENVIRON case TELOPT_NEW_ENVIRON: #endif case TELOPT_OLD_ENVIRON: { register int c; register char *cp, *varp, *valp; if (SB_EOF()) return; c = SB_GET(); if (c == TELQUAL_IS) { if (subchar == TELOPT_OLD_ENVIRON) settimer(oenvironsubopt); else settimer(environsubopt); } else if (c != TELQUAL_INFO) { return; } #ifdef TELOPT_NEW_ENVIRON if (subchar == TELOPT_NEW_ENVIRON) { while (!SB_EOF()) { c = SB_GET(); if ((c == NEW_ENV_VAR) || (c == ENV_USERVAR)) 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. */ 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; 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; 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; case ENV_ESC: if (!SB_EOF()) c = SB_GET(); /* FALL THROUGH */ default: empty = 0; continue; } empty = 1; } if (empty) { if (last == OLD_ENV_VALUE) 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: env_ovar = OLD_ENV_VAR; env_ovalue = OLD_ENV_VALUE; } 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);}); } } SB_RESTORE(); #endif while (!SB_EOF()) { c = SB_GET(); if ((c == env_ovar) || (c == ENV_USERVAR)) break; } } if (SB_EOF()) 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; case NEW_ENV_VAR: case ENV_USERVAR: *cp = '\0'; if (valp) (void)setenv(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 (valp) (void)setenv(varp, valp, 1); else unsetenv(varp); break; } /* end of case TELOPT_NEW_ENVIRON */ #if defined(AUTHENTICATION) case TELOPT_AUTHENTICATION: if (SB_EOF()) break; switch(SB_GET()) { case TELQUAL_SEND: case TELQUAL_REPLY: /* * These are sent by us and cannot be sent by * the client. */ break; case TELQUAL_IS: auth_is(subpointer, SB_LEN()); break; case TELQUAL_NAME: auth_name(subpointer, SB_LEN()); break; } break; #endif #ifdef ENCRYPTION case TELOPT_ENCRYPT: if (SB_EOF()) break; switch(SB_GET()) { case ENCRYPT_SUPPORT: encrypt_support(subpointer, SB_LEN()); break; case ENCRYPT_IS: encrypt_is(subpointer, SB_LEN()); break; case ENCRYPT_REPLY: encrypt_reply(subpointer, SB_LEN()); break; case ENCRYPT_START: encrypt_start(subpointer, SB_LEN()); break; case ENCRYPT_END: encrypt_end(); break; case ENCRYPT_REQSTART: 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; case ENCRYPT_ENC_KEYID: encrypt_enc_keyid(subpointer, SB_LEN()); break; case ENCRYPT_DEC_KEYID: encrypt_dec_keyid(subpointer, SB_LEN()); break; default: break; } break; #endif /* ENCRYPTION */ default: break; } /* end of switch */ } /* end of suboption */ void doclientstat() { 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 */ 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); } } 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); } } #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); writenet(statusbuf, ncp - statusbuf); netflush(); /* Send it on its way */ DIAG(TD_OPTIONS, {printsub('>', statusbuf, ncp - statusbuf); netflush();}); } diff --git a/contrib/telnet/telnetd/sys_term.c b/contrib/telnet/telnetd/sys_term.c index 67a2f942d347..fe9509e9e508 100644 --- a/contrib/telnet/telnetd/sys_term.c +++ b/contrib/telnet/telnetd/sys_term.c @@ -1,2303 +1,2325 @@ /* * 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. */ #ifndef lint -static char sccsid[] = "@(#)sys_term.c 8.4+1 (Berkeley) 5/30/95"; +static const char sccsid[] = "@(#)sys_term.c 8.4+1 (Berkeley) 5/30/95"; #endif /* not lint */ #include "telnetd.h" #include "pathnames.h" #if defined(AUTHENTICATION) #include #endif +extern char *altlogin; +int cleanopen(char *line); +void scrub_env(void); + #if defined(CRAY) || defined(__hpux) # define PARENT_DOES_UTMP #endif +int utmp_len = MAXHOSTNAMELEN; #ifdef NEWINIT #include -int utmp_len = MAXHOSTNAMELEN; /* sizeof(init_request.host) */ #else /* NEWINIT*/ # ifdef UTMPX # include struct utmpx wtmp; # else # include struct utmp wtmp; # endif /* UTMPX */ -int utmp_len = sizeof(wtmp.ut_host); # ifndef PARENT_DOES_UTMP +#ifdef _PATH_WTMP +char wtmpf[] = _PATH_WTMP; +#else char wtmpf[] = "/usr/adm/wtmp"; +#endif +#ifdef _PATH_UTMP +char utmpf[] = _PATH_UTMP; +#else char utmpf[] = "/etc/utmp"; +#endif # else /* PARENT_DOES_UTMP */ char wtmpf[] = "/etc/wtmp"; # endif /* PARENT_DOES_UTMP */ +#include + # ifdef CRAY #include #include # if (UNICOS_LVL == '7.0') || (UNICOS_LVL == '7.1') # define UNICOS7x # endif # ifdef UNICOS7x #include #include extern int secflag; extern struct sysv sysv; # endif /* UNICOS7x */ # endif /* CRAY */ #endif /* NEWINIT */ #ifdef STREAMSPTY #include #include #endif #define SCPYN(a, b) (void) strncpy(a, b, sizeof(a)) #define SCMPN(a, b) strncmp(a, b, sizeof(a)) #ifdef STREAMS #include #endif #ifdef __hpux #include #include #endif #include #ifdef t_erase #undef t_erase #undef t_kill #undef t_intrc #undef t_quitc #undef t_startc #undef t_stopc #undef t_eofc #undef t_brkc #undef t_suspc #undef t_dsuspc #undef t_rprntc #undef t_flushc #undef t_werasc #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 # ifndef TCSANOW # ifdef TCSETS # define TCSANOW TCSETS # define TCSADRAIN TCSETSW # define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t) # else # ifdef TCSETA # define TCSANOW TCSETA # define TCSADRAIN TCSETAW # define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t) # else # define TCSANOW TIOCSETA # define TCSADRAIN TIOCSETAW # define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t) # endif # endif # define tcsetattr(f, a, t) ioctl(f, a, t) # define cfsetospeed(tp, val) (tp)->c_cflag &= ~CBAUD; \ (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)<c_cflag & CIBAUD)>>IBSHIFT) # else # define cfsetispeed(tp, val) (tp)->c_cflag &= ~CBAUD; \ (tp)->c_cflag |= (val) # define cfgetispeed(tp) ((tp)->c_cflag & CBAUD) # endif # endif /* TCSANOW */ struct termios termbuf, termbuf2; /* pty control structure */ # ifdef STREAMSPTY int ttyfd = -1; # endif #endif /* USE_TERMIO */ /* * init_termbuf() * copy_termbuf(cp) * set_termbuf() * * These three routines are used to get and set the "termbuf" structure * to and from the kernel. init_termbuf() gets the current settings. * copy_termbuf() hands in a new "termbuf" to write to the kernel, and * set_termbuf() writes the structure into the kernel. */ void init_termbuf() { #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); # 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((char *)&termbuf, cp, len); termbuf2 = termbuf; } #endif /* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */ void set_termbuf() { /* * Only make the necessary changes. */ #ifndef USE_TERMIO if (memcmp((char *)&termbuf.sg, (char *)&termbuf2.sg, sizeof(termbuf.sg))) (void) ioctl(pty, TIOCSETN, (char *)&termbuf.sg); if (memcmp((char *)&termbuf.tc, (char *)&termbuf2.tc, sizeof(termbuf.tc))) (void) ioctl(pty, TIOCSETC, (char *)&termbuf.tc); if (memcmp((char *)&termbuf.ltc, (char *)&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((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf))) # ifdef STREAMSPTY (void) tcsetattr(ttyfd, TCSANOW, &termbuf); # else (void) tcsetattr(pty, TCSANOW, &termbuf); # endif # if defined(CRAY2) && defined(UNICOS5) needtermstat = 1; # endif #endif /* USE_TERMIO */ } /* * spcset(func, valp, valpp) * * This function takes various special characters (func), and * sets *valp to the current value of that character, and * *valpp to point to where in the "termbuf" structure that * value is kept. * * 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; { #define setval(a, b) *valp = termbuf.c_cc[a]; \ *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: #ifdef VSTART setval(VSTART, SLC_VARIABLE); #else defval(0x13); #endif case SLC_XOFF: #ifdef VSTOP setval(VSTOP, SLC_VARIABLE); #else defval(0x11); #endif case SLC_EW: #ifdef VWERASE setval(VWERASE, SLC_VARIABLE); #else defval(0); #endif case SLC_RP: #ifdef VREPRINT setval(VREPRINT, SLC_VARIABLE); #else defval(0); #endif case SLC_LNEXT: #ifdef VLNEXT setval(VLNEXT, SLC_VARIABLE); #else defval(0); #endif case SLC_AO: #if !defined(VDISCARD) && defined(VFLUSHO) # define VDISCARD VFLUSHO #endif #ifdef VDISCARD setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT); #else defval(0); #endif case SLC_SUSP: #ifdef VSUSP setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN); #else defval(0); #endif #ifdef VEOL case SLC_FORW1: setval(VEOL, SLC_VARIABLE); #endif #ifdef VEOL2 case SLC_FORW2: setval(VEOL2, SLC_VARIABLE); #endif case SLC_AYT: #ifdef VSTATUS setval(VSTATUS, SLC_VARIABLE); #else defval(0); #endif case SLC_BRK: case SLC_SYNCH: case SLC_EOR: defval(0); default: *valp = 0; *valpp = 0; return(SLC_NOSUPPORT); } } #endif /* USE_TERMIO */ #ifdef CRAY /* * getnpty() * * Return the number of pty's configured into the system. */ int getnpty() { #ifdef _SC_CRAY_NPTY int numptys; if ((numptys = sysconf(_SC_CRAY_NPTY)) != -1) return numptys; else #endif /* _SC_CRAY_NPTY */ return 128; } #endif /* CRAY */ #ifndef convex /* * getpty() * * Allocate a pty. As a side effect, the external character * array "line" contains the name of the slave side. * * Returns the file descriptor of the opened pty. */ #ifndef __GNUC__ char *line = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; #else static char Xline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; char *line = Xline; #endif #ifdef CRAY char *myline = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; #endif /* CRAY */ int getpty(ptynum) int *ptynum; { register int p; #ifdef STREAMSPTY int t; char *ptsname(); p = open("/dev/ptmx", 2); if (p > 0) { grantpt(p); unlockpt(p); strcpy(line, ptsname(p)); return(p); } #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++) { + for (cp = "pqrsPQRS"; *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]; + for (i = 0; i < 32; i++) { + *p2 = "0123456789abcdefghijklmnopqrstuv"[i]; p = open(line, 2); 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, 2); 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, 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 */ (void) close(p); } } #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() { #ifndef convex #ifndef USE_TERMIO return(termbuf.state & TS_EXTPROC); #else return(termbuf.c_lflag & EXTPROC); #endif #else return(linestate); #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() { #ifndef USE_TERMIO return(((termbuf.tc.t_startc) > 0 && (termbuf.tc.t_stopc) > 0) ? 1 : 0); #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 #else return((termbuf.c_iflag & IXANY) ? 1 : 0); #endif } void tty_setecho(on) int on; { #ifndef USE_TERMIO if (on) termbuf.sg.sg_flags |= ECHO|CRMOD; else termbuf.sg.sg_flags &= ~(ECHO|CRMOD); #else if (on) termbuf.c_lflag |= ECHO; else termbuf.c_lflag &= ~ECHO; #endif } int tty_israw() { #ifndef USE_TERMIO return(termbuf.sg.sg_flags & RAW); #else return(!(termbuf.c_lflag & ICANON)); #endif } #if defined (AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R) int tty_setraw(on) { # 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 } #endif void tty_binaryin(on) int on; { #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 } void tty_binaryout(on) int on; { #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 } int tty_isbinaryin() { #ifndef USE_TERMIO return(termbuf.lflags & LPASS8); #else return(!(termbuf.c_iflag & ISTRIP)); #endif } int tty_isbinaryout() { #ifndef USE_TERMIO return(termbuf.lflags & LLITOUT); #else return(!(termbuf.c_oflag&OPOST)); #endif } #ifdef LINEMODE int tty_isediting() { #ifndef USE_TERMIO return(!(termbuf.sg.sg_flags & (CBREAK|RAW))); #else return(termbuf.c_lflag & ICANON); #endif } int tty_istrapsig() { #ifndef USE_TERMIO return(!(termbuf.sg.sg_flags&RAW)); #else return(termbuf.c_lflag & ISIG); #endif } void tty_setedit(on) int on; { #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 } void tty_setsig(on) int on; { #ifndef USE_TERMIO if (on) ; #else if (on) termbuf.c_lflag |= ISIG; else termbuf.c_lflag &= ~ISIG; #endif } #endif /* LINEMODE */ int tty_issofttab() { #ifndef USE_TERMIO return (termbuf.sg.sg_flags & XTABS); #else # ifdef OXTABS return (termbuf.c_oflag & OXTABS); # endif # ifdef TABDLY return ((termbuf.c_oflag & TABDLY) == TAB3); # endif #endif } void tty_setsofttab(on) int on; { #ifndef USE_TERMIO if (on) termbuf.sg.sg_flags |= XTABS; else termbuf.sg.sg_flags &= ~XTABS; #else if (on) { # ifdef OXTABS termbuf.c_oflag |= OXTABS; # endif # ifdef TABDLY termbuf.c_oflag &= ~TABDLY; termbuf.c_oflag |= TAB3; # endif } else { # ifdef OXTABS termbuf.c_oflag &= ~OXTABS; # endif # ifdef TABDLY termbuf.c_oflag &= ~TABDLY; termbuf.c_oflag |= TAB0; # endif } #endif } int tty_islitecho() { #ifndef USE_TERMIO return (!(termbuf.lflags & LCTLECH)); #else # ifdef ECHOCTL return (!(termbuf.c_lflag & ECHOCTL)); # endif # ifdef TCTLECH return (!(termbuf.c_lflag & TCTLECH)); # endif # if !defined(ECHOCTL) && !defined(TCTLECH) return (0); /* assumes ctl chars are echoed '^x' */ # endif #endif } void tty_setlitecho(on) 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; # endif # ifdef TCTLECH if (on) termbuf.c_lflag &= ~TCTLECH; else termbuf.c_lflag |= TCTLECH; # endif #endif } int tty_iscrnl() { #ifndef USE_TERMIO return (termbuf.sg.sg_flags & CRMOD); #else return (termbuf.c_iflag & ICRNL); #endif } /* * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD). */ #if B4800 != 4800 #define DECODE_BAUD #endif #ifdef DECODE_BAUD /* * A table of available terminal speeds */ struct termspeeds { 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 }, #ifdef B7200 { 7200, B7200 }, #endif { 9600, B9600 }, #ifdef B14400 { 14400, B14400 }, #endif #ifdef B19200 { 19200, B19200 }, #endif #ifdef B28800 { 28800, B28800 }, #endif #ifdef B38400 { 38400, B38400 }, #endif #ifdef B57600 { 57600, B57600 }, #endif #ifdef B115200 { 115200, B115200 }, #endif #ifdef B230400 { 230400, B230400 }, #endif { -1, 0 } }; #endif /* DECODE_BUAD */ void tty_tspeed(val) int val; { #ifdef DECODE_BAUD register 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); #else /* DECODE_BUAD */ cfsetospeed(&termbuf, val); #endif /* DECODE_BUAD */ } void tty_rspeed(val) int val; { #ifdef DECODE_BAUD register 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); #else /* DECODE_BAUD */ 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; { gotalarm++; } # 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 */ #endif /* * getptyslave() * * Open the slave side of the pty, and do any initialization * that is necessary. The return value is a file descriptor * for the slave side. */ - int + void getptyslave() { register int t = -1; + char erase; #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 + * erase character * so that we can re-set them if we need to. */ # ifdef LINEMODE waslm = tty_linemode(); # endif - + erase = termbuf.c_cc[VERASE]; /* * Make sure that we don't have a controlling tty, and * that we are the session (process group) leader. */ # ifdef TIOCNOTTY t = open(_PATH_TTY, O_RDWR); if (t >= 0) { (void) ioctl(t, TIOCNOTTY, (char *)0); (void) close(t); } # endif # ifdef PARENT_DOES_UTMP /* * 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); #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 /* * set up the tty modes as we like them to be. */ init_termbuf(); # ifdef TIOCGWINSZ if (def_row || def_col) { memset((char *)&ws, 0, sizeof(ws)); ws.ws_col = def_col; ws.ws_row = def_row; (void)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; # 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) # 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); + if (erase) + termbuf.c_cc[VERASE] = erase; # 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 } #if !defined(CRAY) || !defined(NEWINIT) #ifndef O_NOCTTY #define O_NOCTTY 0 #endif /* * Open the specified slave side of the pty, * making sure that we have a clean tty. */ int cleanopen(line) char *line; { register int t; #ifdef UNICOS7x struct secstat secbuf; #endif /* UNICOS7x */ #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); #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); } #endif /* UNICOS7x */ t = open(line, O_RDWR|O_NOCTTY); #ifdef UNICOS7x if (secflag) { if (setulvl(sysv.sy_minlvl) < 0) return(-1); if (setucmp(0) < 0) return(-1); } #endif /* UNICOS7x */ 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); # 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; } # endif /* defined(CRAY) && defined(TCVHUP) */ return(t); } #endif /* !defined(CRAY) || !defined(NEWINIT) */ #if BSD <= 43 int login_tty(t) 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)"); # 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)); # 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); } #endif /* BSD <= 43 */ #ifdef NEWINIT char *gen_id = "fe"; #endif /* * startslave(host) * * Given a hostname, do whatever * is necessary to startup the login process on the slave side of the pty. */ /* ARGSUSED */ void startslave(host, autologin, autoname) char *host; int autologin; char *autoname; { register int i; long time(); - char name[256]; #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 #ifndef NEWINIT # ifdef PARENT_DOES_UTMP utmp_sig_init(); # endif /* PARENT_DOES_UTMP */ 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. */ if ((i = open(INIT_FIFO, O_WRONLY)) < 0) { char tbuf[128]; (void) sprintf(tbuf, "Can't open %s\n", INIT_FIFO); fatalperror(net, tbuf); } memset((char *)&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 /* * Are we working as the bftp daemon? */ if (bftpd) { SCPYN(request.exec_name, BFTPPATH); } #endif /* BFTPDAEMON */ if (write(i, (char *)&request, sizeof(request)) < 0) { char tbuf[128]; (void) sprintf(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; sprintf(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 */ } char *envinit[3]; extern char **environ; void init_env() { extern char *getenv(); char **envp; envp = envinit; - if (*envp = getenv("TZ")) + if ((*envp = getenv("TZ"))) *envp++ -= 3; #if defined(CRAY) || defined(__hpux) else *envp++ = "TZ=GMT0"; #endif *envp = 0; environ = envinit; } #ifndef NEWINIT /* * start_login(host) * * Assuming that we are now running as a child processes, this * function will turn us into the login process. */ void start_login(host, autologin, name) char *host; int autologin; char *name; { - register char *cp; register char **argv; - char **addarg(); + char **addarg(), *user; extern char *getenv(); #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 */ memset(&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"); #if !defined(NO_LOGIN_H) # 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 } #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); # ifdef KLUDGELINEMODE else if (lmodetype == KLUDGE_LINEMODE || lmodetype == KLUDGE_OK) setenv("LINEMODE", "kludge", 1); # 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 (SecurID) /* * don't worry about the -f that might get sent. * A -s is supposed to override it anyhow. */ if (require_SecurID) argv = addarg(argv, "-s"); #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); sprintf(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; 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); #endif 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(_PATH_LOGIN, argv); - syslog(LOG_ERR, "%s: %m\n", _PATH_LOGIN); - fatalperror(net, _PATH_LOGIN); + if (altlogin == NULL) { + altlogin = _PATH_LOGIN; + } + execv(altlogin, argv); + + syslog(LOG_ERR, "%s: %m\n", altlogin); + fatalperror(net, altlogin); /*NOTREACHED*/ } char ** addarg(argv, val) register char **argv; register 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[(int)argv[-1]]) { --argv; *argv = (char *)((int)(*argv) + 10); argv = (char **)realloc(argv, sizeof(*argv)*((int)(*argv) + 2)); if (argv == NULL) return(NULL); argv++; cpp = &argv[(int)argv[-1] - 10]; } *cpp++ = val; *cpp = 0; return(argv); } #endif /* NEWINIT */ /* * scrub_env() * * Remove a few things from the environment that * don't need to be there. */ + void scrub_env() { register char **cpp, **cpp2; for (cpp2 = cpp = environ; *cpp; cpp++) { +#ifdef __FreeBSD__ + if (strncmp(*cpp, "LD_LIBRARY_PATH=", 16) && + strncmp(*cpp, "LD_PRELOAD=", 11) && +#else if (strncmp(*cpp, "LD_", 3) && strncmp(*cpp, "_RLD_", 5) && strncmp(*cpp, "LIBPATH=", 8) && +#endif strncmp(*cpp, "IFS=", 4)) *cpp2++ = *cpp; } *cpp2 = 0; } /* * cleanup() * * 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; /* * 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 (WIFSTOPPED(child_status)) { return; } } t = sigblock(sigmask(SIGCHLD)); if (incleanup) { sigsetmask(t); return; } incleanup = 1; 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 */ } #if defined(PARENT_DOES_UTMP) && !defined(NEWINIT) /* * _utmp_sig_rcv * utmp_sig_init * utmp_sig_wait * These three functions are used to coordinate the handling of * the utmp file between the server and the soon-to-be-login shell. * The server actually creates the utmp structure, the child calls * utmp_sig_wait(), until the server calls utmp_sig_notify() and * signals the future-login shell to proceed. */ static int caught=0; /* NZ when signal intercepted */ static void (*func)(); /* address of previous handler */ void _utmp_sig_rcv(sig) int sig; { caught = 1; (void) signal(SIGUSR1, func); } void utmp_sig_init() { /* * register signal handler for UTMP creation */ if ((int)(func = signal(SIGUSR1, _utmp_sig_rcv)) == -1) fatalperror(net, "telnetd/signal"); } void utmp_sig_reset() { (void) signal(SIGUSR1, func); /* reset handler to default */ } # ifdef __hpux # define sigoff() /* do nothing */ # define sigon() /* do nothing */ # endif void utmp_sig_wait() { /* * 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 */ } void utmp_sig_notify(pid) { kill(pid, SIGUSR1); } # ifdef CRAY static int gotsigjob = 0; /*ARGSUSED*/ void sigjob(sig) int sig; { register int jid; register struct jobtemp *jp; while ((jid = waitjob(NULL)) != -1) { if (jid == 0) { return; } gotsigjob++; jobend(jid, NULL, NULL); } } /* * jid_getutid: * called by jobend() before calling cleantmp() * to find the correct $TMPDIR to cleanup. */ struct utmp * jid_getutid(jid) int jid; { struct utmp *cur = NULL; setutent(); /* just to make sure */ while (cur = getutent()) { if ( (cur->ut_type != NULL) && (jid == cur->ut_jid) ) { return(cur); } } return(0); } /* * Clean up the TMPDIR that login created. * The first time this is called we pick up the info * from the utmp. If the job has already gone away, * then we'll clean up and be done. If not, then * when this is called the second time it will wait * for the signal that the job is done. */ int cleantmp(wtp) register struct utmp *wtp; { struct utmp *utp; static int first = 1; register int mask, omask, ret; extern struct utmp *getutid P((const struct utmp *_Id)); mask = sigmask(WJSIGNAL); 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); /* * 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 jobend(jid, path, user) register int jid; register char *path; register 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) { 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(); utp = jid_getutid(pty_saved_jid); if (utp == 0) { syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR"); return(-1); } 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; { 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: /* * 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; /* * This updates the utmpx and utmp entries and make a wtmp/x entry */ 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, ((long)u)-((long)utmp), L_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((long *) 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); } #endif diff --git a/contrib/telnet/telnetd/telnetd.8 b/contrib/telnet/telnetd/telnetd.8 index f618385ed09b..e77443e6e010 100644 --- a/contrib/telnet/telnetd/telnetd.8 +++ b/contrib/telnet/telnetd/telnetd.8 @@ -1,607 +1,613 @@ .\" Copyright (c) 1983, 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. .\" .\" @(#)telnetd.8 8.4 (Berkeley) 6/1/94 .\" .Dd June 1, 1994 .Dt TELNETD 8 .Os BSD 4.2 .Sh NAME .Nm telnetd .Nd DARPA .Tn TELNET protocol server .Sh SYNOPSIS .Nm /usr/libexec/telnetd .Op Fl BUhlkns .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 edebug +.Op Fl P Ar loginprog .Op Fl r Ns Ar lowpty-highpty .Op Fl u Ar len .Op Fl debug Op Ar port .Sh DESCRIPTION The .Nm telnetd command is a server which supports the .Tn DARPA standard .Tn TELNET virtual terminal protocol. .Nm Telnetd is normally invoked by the internet server (see .Xr inetd 8 ) for requests to connect to the .Tn TELNET port as indicated by the .Pa /etc/services file (see .Xr services 5 ) . The .Fl debug option may be used to start up .Nm telnetd manually, instead of through .Xr inetd 8 . If started up this way, .Ar port may be specified to run .Nm telnetd on an alternate .Tn TCP port number. .Pp The .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 telnetd has been compiled with support for the .Dv AUTHENTICATION option. There are several valid values for .Ar authmode: .Bl -tag -width debug .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. .It valid 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. .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 .Fl a .Cm valid . .It none This is the default state. Authentication information is not required. If no or insufficient authentication information is provided, then the .Xr login 1 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 Specifies bftp server mode. In this mode, .Nm telnetd causes login to start a .Xr bftp 1 session rather than the user's normal shell. In bftp daemon mode normal logins are not supported, and it must be used on a port other than the normal .Tn TELNET port. .It Fl D Ar debugmode This option may be used for debugging purposes. This allows .Nm telnetd to print out debugging information to the connection, allowing the user to see what .Nm telnetd is doing. There are several possible values for .Ar debugmode: .Bl -tag -width exercise .It Cm options Prints information about the negotiation of .Tn TELNET options. .It Cm report Prints the .Cm options information, plus some additional information about what processing is going on. .It Cm netdata Displays the data stream received by .Nm telnetd. .It Cm ptydata 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 telnetd (see .Dv SO_DEBUG in .Xr socket 2 ) . .It Fl edebug If .Nm telnetd has been compiled with support for data encryption, then the .Fl edebug option may be used to enable encryption debugging code. +.It Fl P Ar loginprog +Specifies an alternate +.Xr login 1 +command to run to complete the login. The alternate command must +understand the same command arguments as the standard login. .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 .Dv ID from .Pa /etc/inittab to use when init starts login sessions. The default .Dv ID is .Dv fe. .It Fl k This option is only useful if .Nm telnetd 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 .Dv LINEMODE option, then .Nm telnetd 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 by the client sending .Dv DONT SUPPRESS-GO-AHEAD and .Dv 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 .Dv WILL TIMING-MARK in response to a .Dv 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 .Dv LINEMODE option is not supported, it will go into kludge linemode. .It Fl n Disable .Dv TCP keep-alives. Normally .Nm telnetd enables the .Tn TCP keep-alive mechanism to probe connections that have been idle for some period of time to determine if the client is still there, so that idle connections 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 telnetd is compiled for .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 .Ar lowpty or .Ar highpty 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 telnetd can differentiate .Ar highpty from .Ar lowpty . .It Fl s This option is only enabled if .Nm telnetd is compiled with support for .Tn SecurID cards. It causes the .Fl s option to be passed on to .Xr login 1 , and thus is only useful if .Xr login 1 supports the .Fl s flag to indicate that only .Tn SecurID validated logins are allowed, and is usually useful for controlling remote logins from outside of a firewall. .It Fl S Ar tos .It Fl u Ar len 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 , the dotted decimal value will be used instead. This allows hosts with very long host names that overflow this field to still be uniquely identified. Specifying .Fl u0 indicates that only dotted decimal addresses should be put into the .Pa utmp file. .ne 1i .It Fl U This option causes .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 telnetd has been built with support for the authentication option. It disables the use of .Ar authtype authentication, and can be used to temporarily disable a specific authentication type without having to recompile .Nm telnetd . .El .Pp .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 .Dv stdin , .Dv stdout and .Dv stderr . .Nm Telnetd manipulates the master side of the pseudo-terminal, implementing the .Tn TELNET protocol and passing characters between the remote client and the login process. .Pp When a .Tn TELNET session is started up, .Nm telnetd sends .Tn TELNET options to the client side indicating a willingness to do the following .Tn TELNET options, which are described in more detail below: .Bd -literal -offset indent DO AUTHENTICATION WILL ENCRYPT DO TERMINAL TYPE DO TSPEED DO XDISPLOC DO NEW-ENVIRON DO ENVIRON WILL SUPPRESS GO AHEAD DO ECHO DO LINEMODE DO NAWS WILL STATUS DO LFLOW DO TIMING-MARK .Ed .Pp The pseudo-terminal allocated to the client is configured to operate in \*(lqcooked\*(rq mode, and with .Dv XTABS and .Dv CRMOD enabled (see .Xr tty 4 ) . .Pp .Nm Telnetd has support for enabling locally the following .Tn TELNET options: .Bl -tag -width "DO AUTHENTICATION" .It "WILL ECHO" When the .Dv LINEMODE option is enabled, a .Dv WILL ECHO or .Dv WONT ECHO will be sent to the client to indicate the current state of terminal echoing. When terminal echo is not desired, a .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 .Dv WONT ECHO is sent to indicate that .Tn telnetd will not be doing any terminal echoing, so the client should do any terminal echoing that is needed. .It "WILL BINARY" Indicates that the client is willing to send a 8 bits of data, rather than the normal 7 bits of the Network Virtual Terminal. .It "WILL SGA" Indicates that it will not be sending .Dv IAC GA, go ahead, commands. .It "WILL STATUS" Indicates a willingness to send the client, upon request, of the current status of all .Tn TELNET options. .It "WILL TIMING-MARK" Whenever a .Dv DO TIMING-MARK command is received, it is always responded to with a .Dv WILL TIMING-MARK .ne 1i .It "WILL LOGOUT" When a .Dv DO LOGOUT is received, a .Dv WILL LOGOUT is sent in response, and the .Tn TELNET session is shut down. .It "WILL ENCRYPT" Only sent if .Nm telnetd is compiled with support for data encryption, and indicates a willingness to decrypt the data stream. .El .Pp .Nm Telnetd has support for enabling remotely the following .Tn TELNET options: .Bl -tag -width "DO AUTHENTICATION" .It "DO BINARY" Sent to indicate that .Tn telnetd is willing to receive an 8 bit data stream. .It "DO LFLOW" Requests that the client handle flow control characters remotely. .It "DO ECHO" This is not really supported, but is sent to identify a 4.2BSD .Xr telnet 1 client, which will improperly respond with .Dv WILL ECHO. If a .Dv WILL ECHO is received, a .Dv DONT ECHO will be sent in response. .It "DO TERMINAL-TYPE" Indicates a desire to be able to request the 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 .Dv IAC GA, the go ahead command. .It "DO NAWS" Requests that the client inform the server when the window (display) size changes. .It "DO TERMINAL-SPEED" Indicates a desire to be able to request information about the speed of the serial line to which the client is attached. .It "DO XDISPLOC" Indicates a desire to be able to request the name of the X windows display that is associated with the telnet client. .It "DO NEW-ENVIRON" Indicates a desire to be able to request environment variable information, as described in RFC 1572. .It "DO ENVIRON" Indicates a desire to be able to request environment variable information, as described in RFC 1408. .It "DO LINEMODE" Only sent if .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 telnetd is compiled with support for both linemode and kludge linemode, and the client responded with .Dv WONT LINEMODE. If the client responds with .Dv WILL TM, the it is assumed that the client supports kludge linemode. Note that the .Op Fl k option can be used to disable this. .It "DO AUTHENTICATION" Only sent if .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 telnetd is compiled with support for data encryption, and indicates a willingness to decrypt the data stream. .Sh ENVIRONMENT .Sh FILES .Pa /etc/services .br .Pa /etc/inittab (UNICOS systems only) .br .Pa /etc/iptos (if supported) .br .Pa /usr/ucb/bftp (if supported) .Sh "SEE ALSO" -.Xr telnet 1 , +.Xr bftp 1 , .Xr login 1 , -.Xr bftp 1 +.Xr telnet 1 (if supported) .Sh STANDARDS .Bl -tag -compact -width RFC-1572 .It Cm RFC-854 .Tn TELNET PROTOCOL SPECIFICATION .It Cm RFC-855 TELNET OPTION SPECIFICATIONS .It Cm RFC-856 TELNET BINARY TRANSMISSION .It Cm RFC-857 TELNET ECHO OPTION .It Cm RFC-858 TELNET SUPPRESS GO AHEAD OPTION .It Cm RFC-859 TELNET STATUS OPTION .It Cm RFC-860 TELNET TIMING MARK OPTION .It Cm RFC-861 TELNET EXTENDED OPTIONS - LIST OPTION .It Cm RFC-885 TELNET END OF RECORD OPTION .It Cm RFC-1073 Telnet Window Size Option .It Cm RFC-1079 Telnet Terminal Speed Option .It Cm RFC-1091 Telnet Terminal-Type Option .It Cm RFC-1096 Telnet X Display Location Option .It Cm RFC-1123 Requirements for Internet Hosts -- Application and Support .It Cm RFC-1184 Telnet Linemode Option .It Cm RFC-1372 Telnet Remote Flow Control Option .It Cm RFC-1416 Telnet Authentication Option .It Cm RFC-1411 Telnet Authentication: Kerberos Version 4 .It Cm RFC-1412 Telnet Authentication: SPX .It Cm RFC-1571 Telnet Environment Option Interoperability Issues .It Cm RFC-1572 Telnet Environment Option .Sh BUGS Some .Tn TELNET commands are only partially implemented. .Pp Because of bugs in the original 4.2 BSD .Xr telnet 1 , .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 . .Pp Binary mode has no common interpretation except between similar operating systems (Unix in this case). .Pp The terminal type name received from the remote client is converted to lower case. .Pp .Nm Telnetd never sends .Tn TELNET .Dv IAC GA (go ahead) commands. diff --git a/contrib/telnet/telnetd/telnetd.c b/contrib/telnet/telnetd/telnetd.c index 70c0fc03589c..6e09ab46ca7f 100644 --- a/contrib/telnet/telnetd/telnetd.c +++ b/contrib/telnet/telnetd/telnetd.c @@ -1,1608 +1,1611 @@ /* * 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. */ #ifndef lint -static char copyright[] = +static const char copyright[] = "@(#) Copyright (c) 1989, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)telnetd.c 8.4 (Berkeley) 5/30/95"; +static const char sccsid[] = "@(#)telnetd.c 8.4 (Berkeley) 5/30/95"; #endif /* not lint */ #include "telnetd.h" #include "pathnames.h" #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 #if defined(_SC_CRAY_SECURE_SYS) #include #include # ifdef SO_SEC_MULTI /* 8.0 code */ #include #include # 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 int auth_level = 0; #endif +#if defined(ENCRYPTION) +#include +#endif +#include #if defined(SecurID) int require_SecurID = 0; #endif extern int utmp_len; int registerd_host_only = 0; #ifdef STREAMSPTY # include # include /* make sure we don't get the bsd version */ # include "/usr/include/sys/tty.h" # include /* * Because of the way ptyibuf is used with streams messages, we need * ptyibuf+1 to be on a full-word boundary. The following wierdness * is simply to make that happen. */ long ptyibufbuf[BUFSIZ/sizeof(long)+1]; char *ptyibuf = ((char *)&ptyibufbuf[1])-1; char *ptyip = ((char *)&ptyibufbuf[1])-1; char ptyibuf2[BUFSIZ]; unsigned char ctlbuf[BUFSIZ]; struct strbuf strbufc, strbufd; -int readstream(); - #else /* ! STREAMPTY */ /* * I/O data buffers, * pointers, and counters. */ char ptyibuf[BUFSIZ], *ptyip = ptyibuf; char ptyibuf2[BUFSIZ]; +# include + +int readstream(int p, char *ibuf, int bufsize); +void doit(struct sockaddr_in *who); +int terminaltypeok(char *s); +void startslave(char *host, int autologin, char *autoname); + #endif /* ! STREAMPTY */ int hostinfo = 1; /* do we print login banner? */ #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 *progname; +char *altlogin; extern void usage P((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', ':', 'h', 'k', 'n', 'S', ':', 'u', ':', 'U', + 'd', ':', 'h', 'k', 'n', 'p', ':', 'S', ':', 'u', ':', 'U', #ifdef AUTHENTICATION 'a', ':', 'X', ':', #endif #ifdef BFTPDAEMON 'B', #endif #ifdef DIAGNOSTICS 'D', ':', #endif #ifdef ENCRYPTION 'e', ':', #endif #if defined(CRAY) && defined(NEWINIT) 'I', ':', #endif #ifdef LINEMODE 'l', #endif #ifdef CRAY 'r', ':', #endif #ifdef SecurID 's', #endif '\0' }; main(argc, argv) char *argv[]; { struct sockaddr_in from; int on = 1, fromlen; register int ch; extern char *optarg; extern int optind; #if defined(IPPROTO_IP) && defined(IP_TOS) int tos = -1; #endif pfrontp = pbackp = ptyobuf; netip = netibuf; nfrontp = nbackp = netobuf; #ifdef ENCRYPTION nclearto = 0; #endif /* ENCRYPTION */ progname = *argv; #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)) != EOF) { switch(ch) { #ifdef AUTHENTICATION case 'a': /* * Check for required authentication level */ if (strcmp(optarg, "debug") == 0) { extern int auth_debug_mode; 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; #endif /* AUTHENTICATION */ #ifdef BFTPDAEMON case 'B': bftpd++; break; #endif /* BFTPDAEMON */ 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; #endif /* DIAGNOSTICS */ #ifdef ENCRYPTION case 'e': if (strcmp(optarg, "debug") == 0) { extern int encrypt_debug_mode; encrypt_debug_mode = 1; break; } usage(); /* NOTREACHED */ break; #endif /* ENCRYPTION */ 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) */ #ifdef LINEMODE case 'l': alwayslinemode = 1; break; #endif /* LINEMODE */ 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; + case 'p': + altlogin = optarg; + break; + #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; } #endif /* CRAY */ #ifdef SecurID case 's': /* SecurID required */ require_SecurID = 1; break; #endif /* SecurID */ 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"); #else fprintf(stderr, "%s%s\n", "TOS option unavailable; ", "-S flag not supported\n"); #endif break; case 'u': utmp_len = atoi(optarg); break; case 'U': registerd_host_only = 1; break; #ifdef AUTHENTICATION case 'X': /* * Check for invalid authentication types */ auth_disable_name(optarg); break; #endif /* AUTHENTICATION */ default: fprintf(stderr, "telnetd: %c: unknown option\n", ch); /* FALLTHROUGH */ case '?': usage(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (debug) { int s, ns, foo; struct servent *sp; static struct sockaddr_in sin = { AF_INET }; if (argc > 1) { usage(); /* NOT REACHED */ } else if (argc == 1) { - if (sp = getservbyname(*argv, "tcp")) { + if ((sp = getservbyname(*argv, "tcp"))) { sin.sin_port = sp->s_port; } else { sin.sin_port = atoi(*argv); if ((int)sin.sin_port <= 0) { fprintf(stderr, "telnetd: %s: bad port #\n", *argv); usage(); /* NOT REACHED */ } sin.sin_port = htons((u_short)sin.sin_port); } } else { sp = getservbyname("telnet", "tcp"); if (sp == 0) { fprintf(stderr, "telnetd: tcp/telnet: unknown service\n"); exit(1); } sin.sin_port = sp->s_port; } s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) { perror("telnetd: socket");; exit(1); } (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)); if (bind(s, (struct sockaddr *)&sin, sizeof sin) < 0) { perror("bind"); exit(1); } if (listen(s, 1) < 0) { perror("listen"); exit(1); } foo = sizeof sin; ns = accept(s, (struct sockaddr *)&sin, &foo); if (ns < 0) { perror("accept"); exit(1); } (void) dup2(ns, 0); (void) close(ns); (void) close(s); #ifdef convex } else if (argc == 1) { ; /* VOID*/ /* Just ignore the host/port name */ #endif } else if (argc > 0) { usage(); /* NOT REACHED */ } #if defined(_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 */ memset((char *)&dv, 0, sizeof(dv)); if (getsysv(&sysv, sizeof(struct sysv)) != 0) { perror("getsysv"); exit(1); } /* * 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; } #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 */ } #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"); } #if defined(IPPROTO_IP) && defined(IP_TOS) { # if defined(HAS_GETTOS) 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"); } #endif /* defined(IPPROTO_IP) && defined(IP_TOS) */ net = 0; doit(&from); /* NOTREACHED */ } /* end of main */ void usage() { fprintf(stderr, "Usage: telnetd"); #ifdef AUTHENTICATION fprintf(stderr, " [-a (debug|other|user|valid|off|none)]\n\t"); #endif #ifdef BFTPDAEMON fprintf(stderr, " [-B]"); #endif fprintf(stderr, " [-debug]"); #ifdef DIAGNOSTICS fprintf(stderr, " [-D (options|report|exercise|netdata|ptydata)]\n\t"); #endif #ifdef AUTHENTICATION fprintf(stderr, " [-edebug]"); #endif fprintf(stderr, " [-h]"); #if defined(CRAY) && defined(NEWINIT) fprintf(stderr, " [-Iinitid]"); #endif #if defined(LINEMODE) && defined(KLUDGELINEMODE) fprintf(stderr, " [-k]"); #endif #ifdef LINEMODE fprintf(stderr, " [-l]"); #endif fprintf(stderr, " [-n]"); #ifdef CRAY fprintf(stderr, " [-r[lowpty]-[highpty]]"); #endif fprintf(stderr, "\n\t"); #ifdef SecurID fprintf(stderr, " [-s]"); #endif #ifdef HAS_GETTOS fprintf(stderr, " [-S tos]"); #endif #ifdef AUTHENTICATION fprintf(stderr, " [-X auth-type]"); #endif fprintf(stderr, " [-u utmp_hostname_length] [-U]"); fprintf(stderr, " [port]\n"); exit(1); } /* * getterminaltype * * Ask the other end to send along its terminal type and speed. * Output is the variable terminaltype filled in. */ static unsigned char ttytype_sbbuf[] = { IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE }; int getterminaltype(name) char *name; { int retval = -1; void _gettermname(); settimer(baseline); #if defined(AUTHENTICATION) /* * Handle the Authentication option before we do anything else. */ send_do(TELOPT_AUTHENTICATION, 1); while (his_will_wont_is_changing(TELOPT_AUTHENTICATION)) ttloop(); if (his_state_is_will(TELOPT_AUTHENTICATION)) { retval = auth_wait(name); } #endif #ifdef ENCRYPTION send_will(TELOPT_ENCRYPT, 1); #endif /* ENCRYPTION */ send_do(TELOPT_TTYPE, 1); send_do(TELOPT_TSPEED, 1); send_do(TELOPT_XDISPLOC, 1); send_do(TELOPT_NEW_ENVIRON, 1); send_do(TELOPT_OLD_ENVIRON, 1); while ( #ifdef ENCRYPTION his_do_dont_is_changing(TELOPT_ENCRYPT) || #endif /* ENCRYPTION */ his_will_wont_is_changing(TELOPT_TTYPE) || his_will_wont_is_changing(TELOPT_TSPEED) || his_will_wont_is_changing(TELOPT_XDISPLOC) || his_will_wont_is_changing(TELOPT_NEW_ENVIRON) || his_will_wont_is_changing(TELOPT_OLD_ENVIRON)) { ttloop(); } #ifdef ENCRYPTION /* * Wait for the negotiation of what type of encryption we can * send with. If autoencrypt is not set, this will just return. */ if (his_state_is_will(TELOPT_ENCRYPT)) { encrypt_wait(); } #endif /* ENCRYPTION */ if (his_state_is_will(TELOPT_TSPEED)) { static unsigned char sb[] = { IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE }; memmove(nfrontp, sb, sizeof sb); nfrontp += 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 }; memmove(nfrontp, sb, sizeof sb); nfrontp += 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 }; memmove(nfrontp, sb, sizeof sb); nfrontp += 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 }; memmove(nfrontp, sb, sizeof sb); nfrontp += sizeof sb; DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2);); } if (his_state_is_will(TELOPT_TTYPE)) { memmove(nfrontp, ttytype_sbbuf, sizeof ttytype_sbbuf); nfrontp += sizeof ttytype_sbbuf; DIAG(TD_OPTIONS, printsub('>', ttytype_sbbuf + 2, sizeof ttytype_sbbuf - 2);); } if (his_state_is_will(TELOPT_TSPEED)) { while (sequenceIs(tspeedsubopt, baseline)) ttloop(); } if (his_state_is_will(TELOPT_XDISPLOC)) { while (sequenceIs(xdisplocsubopt, baseline)) ttloop(); } if (his_state_is_will(TELOPT_NEW_ENVIRON)) { while (sequenceIs(environsubopt, baseline)) ttloop(); } if (his_state_is_will(TELOPT_OLD_ENVIRON)) { while (sequenceIs(oenvironsubopt, baseline)) ttloop(); } if (his_state_is_will(TELOPT_TTYPE)) { char first[256], last[256]; while (sequenceIs(ttypesubopt, baseline)) ttloop(); /* * If the other side has already disabled the option, then * we have to just go with what we (might) have already gotten. */ if (his_state_is_will(TELOPT_TTYPE) && !terminaltypeok(terminaltype)) { - (void) strncpy(first, terminaltype, sizeof(first)); + (void) strncpy(first, terminaltype, sizeof(first)-1); + first[sizeof(first)-1] = '\0'; for(;;) { /* * Save the unknown name, and request the next name. */ - (void) strncpy(last, terminaltype, sizeof(last)); + (void) strncpy(last, terminaltype, sizeof(last)-1); + last[sizeof(last)-1] = '\0'; _gettermname(); if (terminaltypeok(terminaltype)) break; if ((strncmp(last, terminaltype, sizeof(last)) == 0) || his_state_is_wont(TELOPT_TTYPE)) { /* * We've hit the end. If this is the same as * the first name, just go with it. */ if (strncmp(first, terminaltype, sizeof(first)) == 0) break; /* * Get the terminal name one more time, so that * RFC1091 compliant telnets will cycle back to * the start of the list. */ _gettermname(); - if (strncmp(first, terminaltype, sizeof(first)) != 0) - (void) strncpy(terminaltype, first, sizeof(first)); + if (strncmp(first, terminaltype, sizeof(first)) != 0) { + (void) strncpy(terminaltype, first, sizeof(terminaltype)-1); + terminaltype[sizeof(terminaltype)-1] = '\0'; + } break; } } } } return(retval); } /* end of getterminaltype */ void _gettermname() { /* * If the client turned off the option, * we can't send another request, so we * just return. */ if (his_state_is_wont(TELOPT_TTYPE)) return; settimer(baseline); memmove(nfrontp, ttytype_sbbuf, sizeof ttytype_sbbuf); nfrontp += sizeof ttytype_sbbuf; DIAG(TD_OPTIONS, printsub('>', ttytype_sbbuf + 2, sizeof ttytype_sbbuf - 2);); while (sequenceIs(ttypesubopt, baseline)) ttloop(); } int terminaltypeok(s) char *s; { char buf[1024]; if (terminaltype == NULL) return(1); /* * tgetent() will return 1 if the type is known, and * 0 if it is not known. If it returns -1, it couldn't * open the database. But if we can't open the database, * it won't help to say we failed, because we won't be * able to verify anything else. So, we treat -1 like 1. */ if (tgetent(buf, s) == 0) return(0); 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 +int level; +char user_name[256]; /* * Get a pty, scan input lines. */ +void doit(who) struct sockaddr_in *who; { char *host, *inet_ntoa(); - int t; struct hostent *hp; - int level; int ptynum; - char user_name[256]; /* * Find an available pty to use. */ #ifndef convex pty = getpty(&ptynum); if (pty < 0) fatal(net, "All network ports in use"); #else for (;;) { char *lp; extern char *line, *getpty(); if ((lp = getpty()) == NULL) fatal(net, "Out of ptys"); if ((pty = open(lp, 2)) >= 0) { strcpy(line,lp); line[5] = 't'; break; } } #endif #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"); } #endif /* _SC_CRAY_SECURE_SYS */ /* get name of connected client */ hp = gethostbyaddr((char *)&who->sin_addr, sizeof (struct in_addr), who->sin_family); 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) <= (unsigned int)((utmp_len < 0) ? -utmp_len : utmp_len))) { host = hp->h_name; } else { host = inet_ntoa(who->sin_addr); } /* * We must make a copy because Kerberos is probably going * to also do a gethost* and overwrite the static data... */ strncpy(remote_host_name, host, sizeof(remote_host_name)-1); remote_host_name[sizeof(remote_host_name)-1] = 0; host = remote_host_name; (void) gethostname(host_name, sizeof (host_name)); hostname = host_name; #if defined(AUTHENTICATION) || defined(ENCRYPTION) auth_encrypt_init(hostname, host, "TELNETD", 1); #endif init_env(); /* * get terminal type. */ *user_name = 0; level = getterminaltype(user_name); setenv("TERM", terminaltype ? terminaltype : "network", 1); - /* - * 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()"); } #endif /* _SC_CRAY_SECURE_SYS */ - telnet(net, pty); /* begin server processing */ -#else - telnet(net, pty, host); -#endif + telnet(net, pty, host); /* begin server process */ + /*NOTREACHED*/ } /* end of doit */ #if defined(CRAY2) && defined(UNICOS5) && defined(UNICOS50) int Xterm_output(ibufp, obuf, icountp, ocount) char **ibufp, *obuf; int *icountp, ocount; { int ret; ret = term_output(*ibufp, obuf, *icountp, ocount); *ibufp += *icountp; *icountp = 0; return(ret); } #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 { 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(); /* * 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); #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 */ /* * 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(); /* * 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); } /* * 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); #ifndef STREAMSPTY /* * Turn on packet mode */ (void) 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(); (void) ioctl(f, FIONBIO, (char *)&on); (void) ioctl(p, FIONBIO, (char *)&on); #if defined(CRAY2) && defined(UNICOS5) init_termdriver(f, p, interrupt, sendbrk); #endif #if defined(SO_OOBINLINE) (void) setsockopt(net, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof on); #endif /* defined(SO_OOBINLINE) */ #ifdef SIGTSTP (void) 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); #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 #ifdef TIOCNOTTY { register int t; t = open(_PATH_TTY, O_RDWR); if (t >= 0) { (void) ioctl(t, TIOCNOTTY, (char *)0); (void) close(t); } } #endif #if defined(CRAY) && defined(NEWINIT) && defined(TIOCSCTTY) (void) setsid(); ioctl(p, TIOCSCTTY, 0); #endif /* * 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 !defined(CRAY) || !defined(NEWINIT) if (getenv("USER")) hostinfo = 0; #endif if (getent(defent, "default") == 1) { char *getstr(); char *cp=defstrs; HE = getstr("he", &cp); HN = getstr("hn", &cp); IM = getstr("im", &cp); if (HN && *HN) (void) strcpy(host_name, HN); 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, {sprintf(nfrontp, "td: Entering processing loop\r\n"); nfrontp += strlen(nfrontp);}); -#ifdef convex - startslave(host); -#endif + /* + * Startup the login process on the slave side of the terminal + * now. We delay this until here to insure option negotiation + * is complete. + */ + startslave(host, level, user_name); nfd = ((f > p) ? f : p) + 1; for (;;) { fd_set ibits, obits, xbits; register int c; 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; } /* * Any urgent data? */ if (FD_ISSET(net, &xbits)) { SYNCHing = 1; } /* * 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 { 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)); } /* * Something to read from the pty... */ if (FD_ISSET(p, &ibits)) { #ifndef STREAMSPTY pcc = read(p, ptyibuf, BUFSIZ); #else pcc = readstream(p, ptyibuf, BUFSIZ); #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 || #ifdef 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 */ #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)); #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) */ } } 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'; } } #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; } #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(); } cleanup(0); } /* end of telnet */ #ifndef TCSIG # ifdef TIOCSIG # define TCSIG TIOCSIG # endif #endif #ifdef STREAMSPTY int flowison = -1; /* current state of flow: -1 is unknown */ int readstream(p, ibuf, bufsize) 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); } } /* * 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); } 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 */ /* * Send interrupt to process on other side of pty. * If it is in raw mode, just write NULL; * otherwise, write intr char. */ void interrupt() { ptyflush(); /* half-hearted */ #if defined(STREAMSPTY) && defined(TIOCSIGNAL) /* Streams PTY style ioctl to post a signal */ { int sig = SIGINT; (void) ioctl(pty, TIOCSIGNAL, &sig); (void) ioctl(pty, I_FLUSH, FLUSHR); } #else #ifdef TCSIG (void) ioctl(pty, TCSIG, (char *)SIGINT); #else /* TCSIG */ init_termbuf(); *pfrontp++ = slctab[SLC_IP].sptr ? (unsigned char)*slctab[SLC_IP].sptr : '\177'; #endif /* TCSIG */ #endif } /* * Send quit to process on other side of pty. * If it is in raw mode, just write NULL; * otherwise, write quit char. */ void sendbrk() { ptyflush(); /* half-hearted */ #ifdef TCSIG (void) ioctl(pty, TCSIG, (char *)SIGQUIT); #else /* TCSIG */ init_termbuf(); *pfrontp++ = slctab[SLC_ABORT].sptr ? (unsigned char)*slctab[SLC_ABORT].sptr : '\034'; #endif /* TCSIG */ } void sendsusp() { #ifdef SIGTSTP ptyflush(); /* half-hearted */ # ifdef TCSIG (void) ioctl(pty, TCSIG, (char *)SIGTSTP); # else /* TCSIG */ *pfrontp++ = slctab[SLC_SUSP].sptr ? (unsigned char)*slctab[SLC_SUSP].sptr : '\032'; # endif /* TCSIG */ #endif /* SIGTSTP */ } /* * When we get an AYT, if ^T is enabled, use that. Otherwise, * just send back "[Yes]". */ 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; } #endif (void) strcpy(nfrontp, "\r\n[Yes]\r\n"); nfrontp += 9; } void doeof() { 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'; } diff --git a/contrib/telnet/telnetd/termstat.c b/contrib/telnet/telnetd/termstat.c index ebc843a13663..be1372a1491c 100644 --- a/contrib/telnet/telnetd/termstat.c +++ b/contrib/telnet/telnetd/termstat.c @@ -1,660 +1,673 @@ /* * 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. */ #ifndef lint -static char sccsid[] = "@(#)termstat.c 8.2 (Berkeley) 5/30/95"; +static const char sccsid[] = "@(#)termstat.c 8.2 (Berkeley) 5/30/95"; #endif /* not lint */ #include "telnetd.h" +#if defined(ENCRYPTION) +#include +#endif + /* * local variables */ 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 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); + } + + if (uselinemode) { + /* * Check for state of BINARY options. + * + * We only need to do the binary dance if we are actually going + * to use linemode. As this confuses some telnet clients + * that don't support linemode, and doesn't gain us + * anything, we don't do it unless we're doing linemode. + * -Crh (henrich@msu.edu) */ + 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); } #ifdef ENCRYPTION /* * If the terminal is not echoing, but editing is enabled, * something like password input is going to happen, so * if we the other side is not currently sending encrypted * data, ask the other side to start encrypting. */ if (his_state_is_will(TELOPT_ENCRYPT)) { static int enc_passwd = 0; if (uselinemode && !tty_isecho() && tty_isediting() && (enc_passwd == 0) && !decrypt_input) { encrypt_send_request_start(); enc_passwd = 1; } else if (enc_passwd) { encrypt_send_request_end(); enc_passwd = 0; } } #endif /* ENCRYPTION */ /* * 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 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; } } } /* * clientstat * * Process linemode related requests from the client. * Client can request a change to only one of linemode, editmode or slc's * 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 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)) { + 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: #ifdef TIOCSWINSZ { 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 */ /* * Change window size as requested by client. */ ws.ws_col = parm1; ws.ws_row = parm2; (void) ioctl(pty, TIOCSWINSZ, (char *)&ws); } #endif /* TIOCSWINSZ */ 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 seperate receive and transmit speeds, the transmit * speed will take precedence. */ tty_rspeed(parm2); tty_tspeed(parm1); set_termbuf(); break; } /* end of case TELOPT_TSPEED */ 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(); } /* 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((char *)&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/contrib/telnet/telnetd/utility.c b/contrib/telnet/telnetd/utility.c index 9553d58b9193..eac3b6905246 100644 --- a/contrib/telnet/telnetd/utility.c +++ b/contrib/telnet/telnetd/utility.c @@ -1,1192 +1,1209 @@ /* * 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. */ #ifndef lint -static char sccsid[] = "@(#)utility.c 8.4 (Berkeley) 5/30/95"; +static const char sccsid[] = "@(#)utility.c 8.4 (Berkeley) 5/30/95"; #endif /* not lint */ +#ifdef __FreeBSD__ +#include +#endif #define PRINTOPTIONS #include "telnetd.h" +#if defined(AUTHENTICATION) +#include +#endif +#if defined(ENCRYPTION) +#include +#endif + /* * utility functions performing io related tasks */ /* * 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. */ void ttloop() { void netflush(); DIAG(TD_REPORT, {sprintf(nfrontp, "td: ttloop\r\n"); nfrontp += strlen(nfrontp);}); if (nfrontp-nbackp) { netflush(); } ncc = read(net, netibuf, sizeof netibuf); if (ncc < 0) { syslog(LOG_INFO, "ttloop: read: %m\n"); exit(1); } else if (ncc == 0) { syslog(LOG_INFO, "ttloop: peer died: %m\n"); exit(1); } DIAG(TD_REPORT, {sprintf(nfrontp, "td: ttloop read %d chars\r\n", ncc); nfrontp += strlen(nfrontp);}); netip = netibuf; telrcv(); /* state machine */ if (ncc > 0) { pfrontp = pbackp = ptyobuf; telrcv(); } } /* end of ttloop */ /* * Check a descriptor to see if out of band data exists on it. */ int stilloob(s) int s; /* socket number */ { static struct timeval timeout = { 0 }; fd_set excepts; int value; do { FD_ZERO(&excepts); FD_SET(s, &excepts); + memset((char *)&timeout, 0, sizeof timeout); value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout); } while ((value == -1) && (errno == EINTR)); if (value < 0) { fatalperror(pty, "select"); } if (FD_ISSET(s, &excepts)) { return 1; } else { return 0; } } void ptyflush() { 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; } /* * nextitem() * * Return the address of the next "item" in the TELNET data * stream. This will be the address of the next character if * the current address is a user data character, or it will * be the address of the character following the TELNET command * if the current address is a TELNET IAC ("I Am a Command") * character. */ char * nextitem(current) char *current; { if ((*current&0xff) != IAC) { return current+1; } switch (*(current+1)&0xff) { case DO: case DONT: case WILL: case WONT: return current+3; case SB: /* loop forever looking for the SE */ { register char *look = current+2; for (;;) { if ((*look++&0xff) == IAC) { if ((*look++&0xff) == SE) { return look; } } } } default: return current+2; } } /* end of nextitem */ /* * netclear() * * We are about to do a TELNET SYNCH operation. Clear * the path to the network. * * Things are a bit tricky since we may have sent the first * byte or so of a previous TELNET command into the network. * So, we have to scan the network buffer from the beginning * until we are up to where we want to be. * * A side effect of what we do, just to keep things * simple, is to clear the urgent data pointer. The principal * caller should be setting the urgent data pointer AFTER calling * us in any case. */ void netclear() { register char *thisitem, *next; char *good; #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) #ifdef ENCRYPTION thisitem = nclearto > netobuf ? nclearto : netobuf; #else /* ENCRYPTION */ thisitem = netobuf; #endif /* ENCRYPTION */ while ((next = nextitem(thisitem)) <= nbackp) { thisitem = next; } /* Now, thisitem is first before/at boundary. */ #ifdef ENCRYPTION good = nclearto > netobuf ? nclearto : netobuf; #else /* ENCRYPTION */ good = netobuf; /* where the good bytes go */ #endif /* ENCRYPTION */ 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; } /* end of netclear */ /* * netflush * Send as much data as possible to the network, * handling requests for urgent data. */ void netflush() { 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 */ }); #ifdef ENCRYPTION if (encrypt_output) { char *s = nclearto ? nclearto : nbackp; if (nfrontp - s > 0) { (*encrypt_output)((unsigned char *)s, nfrontp-s); nclearto = nfrontp; } } #endif /* ENCRYPTION */ /* * if no urgent data, or if the other side appears to be an * old 4.2 client (and thus unable to survive TCP urgent data), * write the entire buffer in non-OOB mode. */ if ((neturg == 0) || (not42 == 0)) { n = write(net, nbackp, n); /* normal write */ } else { n = neturg - nbackp; /* * In 4.2 (and 4.3) systems, there is some question about * what byte in a sendOOB operation is the "OOB" data. * To make ourselves compatible, we only send ONE byte * out of band, the one WE THINK should be OOB (though * we really have more the TCP philosophy of urgent data * rather than the Unix philosophy of OOB data). */ if (n > 1) { n = send(net, nbackp, n-1, 0); /* send URGENT all by itself */ } else { n = send(net, nbackp, n, MSG_OOB); /* URGENT data */ } } } if (n < 0) { if (errno == EWOULDBLOCK || errno == EINTR) return; cleanup(0); } nbackp += n; #ifdef ENCRYPTION if (nbackp > nclearto) nclearto = 0; #endif /* ENCRYPTION */ if (nbackp >= neturg) { neturg = 0; } if (nbackp == nfrontp) { nbackp = nfrontp = netobuf; #ifdef ENCRYPTION nclearto = 0; #endif /* ENCRYPTION */ } return; } /* end of netflush */ /* * writenet * * Just a handy little function to write a bit of raw data to the net. * It will force a transmit of the buffer if necessary * * arguments * ptr - A pointer to a character string to write * len - How many bytes to write */ void writenet(ptr, len) register unsigned char *ptr; register 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(nfrontp, ptr, len); nfrontp += len; } /* end of writenet */ /* * miscellaneous functions doing a variety of little jobs follow ... */ void fatal(f, msg) int f; char *msg; { char buf[BUFSIZ]; (void) sprintf(buf, "telnetd: %s.\r\n", msg); #ifdef ENCRYPTION if (encrypt_output) { /* * Better turn off encryption first.... * Hope it flushes... */ encrypt_send_end(); netflush(); } #endif /* ENCRYPTION */ (void) write(f, buf, (int)strlen(buf)); sleep(1); /*XXX*/ exit(1); } void fatalperror(f, msg) int f; char *msg; { char buf[BUFSIZ], *strerror(); (void) sprintf(buf, "%s: %s", msg, strerror(errno)); fatal(f, buf); } char editedhost[32]; void edithost(pat, host) register char *pat; register char *host; { register char *res = editedhost; char *strncpy(); if (!pat) pat = ""; while (*pat) { switch (*pat) { case '#': if (*host) host++; break; case '@': if (*host) *res++ = *host++; break; default: *res++ = *pat; break; } if (res == &editedhost[sizeof editedhost - 1]) { *res = '\0'; return; } pat++; } if (*host) (void) strncpy(res, host, sizeof editedhost - (res - editedhost) -1); else *res = '\0'; editedhost[sizeof editedhost - 1] = '\0'; } static char *putlocation; void putstr(s) register char *s; { while (*s) putchr(*s++); } void putchr(cc) int cc; { *putlocation++ = cc; } +#ifdef __FreeBSD__ +static char fmtstr[] = { "%+" }; +#else /* * 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" }; +#endif void putf(cp, where) register char *cp; char *where; { char *slash; time_t t; char db[100]; #ifdef STREAMSPTY extern char *strchr(); #else extern char *strrchr(); #endif putlocation = where; while (*cp) { if (*cp != '%') { putchr(*cp++); continue; } switch (*++cp) { case 't': #ifdef STREAMSPTY /* names are like /dev/pts/2 -- we want pts/2 */ slash = strchr(line+1, '/'); #else slash = strrchr(line, '/'); #endif if (slash == (char *) 0) putstr(line); else putstr(&slash[1]); break; case 'h': putstr(editedhost); break; case 'd': +#ifdef __FreeBSD__ + setlocale(LC_TIME, ""); +#endif (void)time(&t); (void)strftime(db, sizeof(db), fmtstr, localtime(&t)); putstr(db); break; 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; { 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; } void printsub(direction, pointer, length) char direction; /* '<' or '>' */ unsigned char *pointer; /* where suboption data sits */ int length; /* length of suboption data */ { register int i; 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); } } length -= 2; } if (length < 1) { sprintf(nfrontp, "(Empty suboption??\?)"); nfrontp += strlen(nfrontp); return; } 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]); } 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; } switch (pointer[1]) { case TELQUAL_IS: sprintf(nfrontp, " IS %.*s", length-2, (char *)pointer+2); nfrontp += strlen(nfrontp); 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); } 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]); } nfrontp += strlen(nfrontp); for (i = 2; i < length; i++) { sprintf(nfrontp, " ?%d?", pointer[i]); nfrontp += strlen(nfrontp); } break; case TELOPT_NAWS: sprintf(nfrontp, "NAWS"); nfrontp += strlen(nfrontp); if (length < 2) { sprintf(nfrontp, " (empty suboption??\?)"); nfrontp += strlen(nfrontp); break; } if (length == 2) { sprintf(nfrontp, " ?%d?", pointer[1]); nfrontp += strlen(nfrontp); break; } 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; } 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); } break; case TELOPT_LINEMODE: sprintf(nfrontp, "LINEMODE "); nfrontp += strlen(nfrontp); if (length < 2) { sprintf(nfrontp, " (empty suboption??\?)"); nfrontp += strlen(nfrontp); break; } 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; 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 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); } } break; 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"); else sprintf(nfrontp, " %d (unknown)", pointer[1]); nfrontp += strlen(nfrontp); for (i = 2; i < length; i++) { sprintf(nfrontp, " ?%d?", pointer[i]); nfrontp += strlen(nfrontp); } 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++]; } printsub(0, &pointer[i], k - i); if (i < length) { sprintf(nfrontp, " SE"); nfrontp += strlen(nfrontp); i = j; } else i = j - 1; sprintf(nfrontp, "\r\n"); nfrontp += strlen(nfrontp); break; default: sprintf(nfrontp, " %d", pointer[i]); nfrontp += strlen(nfrontp); 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_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: sprintf(nfrontp, "\" VALUE " + noquote); nfrontp += strlen(nfrontp); noquote = 2; break; case ENV_ESC: sprintf(nfrontp, "\" ESC " + noquote); nfrontp += strlen(nfrontp); noquote = 2; break; case ENV_USERVAR: sprintf(nfrontp, "\" USERVAR " + noquote); nfrontp += strlen(nfrontp); noquote = 2; break; default: - def_case: 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; } break; } } if (!noquote) *nfrontp++ = '"'; break; } } break; #if defined(AUTHENTICATION) case TELOPT_AUTHENTICATION: sprintf(nfrontp, "AUTHENTICATION"); nfrontp += strlen(nfrontp); if (length < 2) { sprintf(nfrontp, " (empty suboption??\?)"); nfrontp += strlen(nfrontp); 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", ((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; 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; } break; case TELQUAL_NAME: i = 2; sprintf(nfrontp, " NAME \""); nfrontp += strlen(nfrontp); while (i < length) *nfrontp += pointer[i++]; *nfrontp += '"'; break; default: for (i = 2; i < length; i++) { sprintf(nfrontp, " ?%d?", pointer[i]); nfrontp += strlen(nfrontp); } break; } break; #endif #ifdef ENCRYPTION case TELOPT_ENCRYPT: sprintf(nfrontp, "ENCRYPT"); nfrontp += strlen(nfrontp); if (length < 2) { sprintf(nfrontp, " (empty suboption??\?)"); nfrontp += strlen(nfrontp); break; } switch (pointer[1]) { case ENCRYPT_START: sprintf(nfrontp, " START"); nfrontp += strlen(nfrontp); break; case ENCRYPT_END: sprintf(nfrontp, " END"); nfrontp += strlen(nfrontp); break; case ENCRYPT_REQSTART: sprintf(nfrontp, " REQUEST-START"); nfrontp += strlen(nfrontp); break; case ENCRYPT_REQEND: sprintf(nfrontp, " REQUEST-END"); nfrontp += strlen(nfrontp); break; case ENCRYPT_IS: case ENCRYPT_REPLY: sprintf(nfrontp, " %s ", (pointer[1] == ENCRYPT_IS) ? "IS" : "REPLY"); nfrontp += strlen(nfrontp); if (length < 3) { sprintf(nfrontp, " (partial suboption??\?)"); nfrontp += strlen(nfrontp); break; } if (ENCTYPE_NAME_OK(pointer[2])) sprintf(nfrontp, "%s ", ENCTYPE_NAME(pointer[2])); else sprintf(nfrontp, " %d (unknown)", pointer[2]); nfrontp += strlen(nfrontp); encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf)); sprintf(nfrontp, "%s", buf); nfrontp += strlen(nfrontp); break; case ENCRYPT_SUPPORT: i = 2; sprintf(nfrontp, " SUPPORT "); nfrontp += strlen(nfrontp); while (i < length) { if (ENCTYPE_NAME_OK(pointer[i])) sprintf(nfrontp, "%s ", ENCTYPE_NAME(pointer[i])); else sprintf(nfrontp, "%d ", pointer[i]); nfrontp += strlen(nfrontp); i++; } break; case ENCRYPT_ENC_KEYID: - sprintf(nfrontp, " ENC_KEYID", pointer[1]); + sprintf(nfrontp, " ENC_KEYID"); nfrontp += strlen(nfrontp); goto encommon; case ENCRYPT_DEC_KEYID: - sprintf(nfrontp, " DEC_KEYID", pointer[1]); + sprintf(nfrontp, " DEC_KEYID"); nfrontp += strlen(nfrontp); goto encommon; default: sprintf(nfrontp, " %d (unknown)", pointer[1]); nfrontp += strlen(nfrontp); encommon: for (i = 2; i < length; i++) { sprintf(nfrontp, " %d", pointer[i]); nfrontp += strlen(nfrontp); } break; } break; #endif /* ENCRYPTION */ 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); } break; } sprintf(nfrontp, "\r\n"); nfrontp += strlen(nfrontp); } /* * 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; { register int i; char xbuf[30]; while (cnt) { /* flush net output buffer if no room for new data) */ if ((&netobuf[BUFSIZ] - nfrontp) < 80) { netflush(); } /* add a line of output */ 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); } } #endif /* DIAGNOSTICS */ diff --git a/crypto/telnet/arpa/telnet.h b/crypto/telnet/arpa/telnet.h index 10155a84a87c..01601f16b24e 100644 --- a/crypto/telnet/arpa/telnet.h +++ b/crypto/telnet/arpa/telnet.h @@ -1,320 +1,340 @@ /* * Copyright (c) 1983, 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. * * @(#)telnet.h 8.2 (Berkeley) 12/15/93 */ -#ifndef _TELNET_H_ -#define _TELNET_H_ +#ifndef _ARPA_TELNET_H_ +#define _ARPA_TELNET_H_ /* * Definitions for the TELNET protocol. */ #define IAC 255 /* interpret as command: */ #define DONT 254 /* you are not to use option */ #define DO 253 /* please, you use option */ #define WONT 252 /* I won't use option */ #define WILL 251 /* I will use option */ #define SB 250 /* interpret as subnegotiation */ #define GA 249 /* you may reverse the line */ #define EL 248 /* erase the current line */ #define EC 247 /* erase the current character */ #define AYT 246 /* are you there */ #define AO 245 /* abort output--but let prog finish */ #define IP 244 /* interrupt process--permanently */ #define BREAK 243 /* break */ #define DM 242 /* data mark--for connect. cleaning */ #define NOP 241 /* nop */ #define SE 240 /* end sub negotiation */ #define EOR 239 /* end of record (transparent mode) */ #define ABORT 238 /* Abort process */ #define SUSP 237 /* Suspend process */ #define xEOF 236 /* End of file: EOF is already used... */ #define SYNCH 242 /* for telfunc calls */ #ifdef TELCMDS char *telcmds[] = { "EOF", "SUSP", "ABORT", "EOR", "SE", "NOP", "DMARK", "BRK", "IP", "AO", "AYT", "EC", - "EL", "GA", "SB", "WILL", "WONT", "DO", "DONT", "IAC", 0, + "EL", "GA", "SB", "WILL", "WONT", "DO", "DONT", "IAC", + 0 }; #else extern char *telcmds[]; #endif #define TELCMD_FIRST xEOF #define TELCMD_LAST IAC #define TELCMD_OK(x) ((unsigned int)(x) <= TELCMD_LAST && \ (unsigned int)(x) >= TELCMD_FIRST) #define TELCMD(x) telcmds[(x)-TELCMD_FIRST] /* telnet options */ #define TELOPT_BINARY 0 /* 8-bit data path */ #define TELOPT_ECHO 1 /* echo */ #define TELOPT_RCP 2 /* prepare to reconnect */ #define TELOPT_SGA 3 /* suppress go ahead */ #define TELOPT_NAMS 4 /* approximate message size */ #define TELOPT_STATUS 5 /* give status */ #define TELOPT_TM 6 /* timing mark */ #define TELOPT_RCTE 7 /* remote controlled transmission and echo */ #define TELOPT_NAOL 8 /* negotiate about output line width */ #define TELOPT_NAOP 9 /* negotiate about output page size */ #define TELOPT_NAOCRD 10 /* negotiate about CR disposition */ #define TELOPT_NAOHTS 11 /* negotiate about horizontal tabstops */ #define TELOPT_NAOHTD 12 /* negotiate about horizontal tab disposition */ #define TELOPT_NAOFFD 13 /* negotiate about formfeed disposition */ #define TELOPT_NAOVTS 14 /* negotiate about vertical tab stops */ #define TELOPT_NAOVTD 15 /* negotiate about vertical tab disposition */ #define TELOPT_NAOLFD 16 /* negotiate about output LF disposition */ #define TELOPT_XASCII 17 /* extended ascic character set */ #define TELOPT_LOGOUT 18 /* force logout */ #define TELOPT_BM 19 /* byte macro */ #define TELOPT_DET 20 /* data entry terminal */ #define TELOPT_SUPDUP 21 /* supdup protocol */ #define TELOPT_SUPDUPOUTPUT 22 /* supdup output */ #define TELOPT_SNDLOC 23 /* send location */ #define TELOPT_TTYPE 24 /* terminal type */ #define TELOPT_EOR 25 /* end or record */ #define TELOPT_TUID 26 /* TACACS user identification */ #define TELOPT_OUTMRK 27 /* output marking */ #define TELOPT_TTYLOC 28 /* terminal location number */ #define TELOPT_3270REGIME 29 /* 3270 regime */ #define TELOPT_X3PAD 30 /* X.3 PAD */ #define TELOPT_NAWS 31 /* window size */ #define TELOPT_TSPEED 32 /* terminal speed */ #define TELOPT_LFLOW 33 /* remote flow control */ #define TELOPT_LINEMODE 34 /* Linemode option */ #define TELOPT_XDISPLOC 35 /* X Display Location */ #define TELOPT_OLD_ENVIRON 36 /* Old - Environment variables */ #define TELOPT_AUTHENTICATION 37/* Authenticate */ #define TELOPT_ENCRYPT 38 /* Encryption option */ #define TELOPT_NEW_ENVIRON 39 /* New - Environment variables */ #define TELOPT_EXOPL 255 /* extended-options-list */ #define NTELOPTS (1+TELOPT_NEW_ENVIRON) #ifdef TELOPTS char *telopts[NTELOPTS+1] = { "BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD", "NAME", "STATUS", "TIMING MARK", "RCTE", "NAOL", "NAOP", "NAOCRD", "NAOHTS", "NAOHTD", "NAOFFD", "NAOVTS", "NAOVTD", "NAOLFD", "EXTEND ASCII", "LOGOUT", "BYTE MACRO", "DATA ENTRY TERMINAL", "SUPDUP", "SUPDUP OUTPUT", "SEND LOCATION", "TERMINAL TYPE", "END OF RECORD", "TACACS UID", "OUTPUT MARKING", "TTYLOC", "3270 REGIME", "X.3 PAD", "NAWS", "TSPEED", "LFLOW", "LINEMODE", "XDISPLOC", "OLD-ENVIRON", "AUTHENTICATION", "ENCRYPT", "NEW-ENVIRON", - 0, + 0 }; #define TELOPT_FIRST TELOPT_BINARY #define TELOPT_LAST TELOPT_NEW_ENVIRON #define TELOPT_OK(x) ((unsigned int)(x) <= TELOPT_LAST) #define TELOPT(x) telopts[(x)-TELOPT_FIRST] #endif /* sub-option qualifiers */ #define TELQUAL_IS 0 /* option is... */ #define TELQUAL_SEND 1 /* send option */ #define TELQUAL_INFO 2 /* ENVIRON: informational version of IS */ #define TELQUAL_REPLY 2 /* AUTHENTICATION: client version of IS */ #define TELQUAL_NAME 3 /* AUTHENTICATION: client version of IS */ #define LFLOW_OFF 0 /* Disable remote flow control */ #define LFLOW_ON 1 /* Enable remote flow control */ #define LFLOW_RESTART_ANY 2 /* Restart output on any char */ #define LFLOW_RESTART_XON 3 /* Restart output only on XON */ /* * LINEMODE suboptions */ #define LM_MODE 1 #define LM_FORWARDMASK 2 #define LM_SLC 3 #define MODE_EDIT 0x01 #define MODE_TRAPSIG 0x02 #define MODE_ACK 0x04 #define MODE_SOFT_TAB 0x08 #define MODE_LIT_ECHO 0x10 #define MODE_MASK 0x1f /* Not part of protocol, but needed to simplify things... */ #define MODE_FLOW 0x0100 #define MODE_ECHO 0x0200 #define MODE_INBIN 0x0400 #define MODE_OUTBIN 0x0800 #define MODE_FORCE 0x1000 #define SLC_SYNCH 1 #define SLC_BRK 2 #define SLC_IP 3 #define SLC_AO 4 #define SLC_AYT 5 #define SLC_EOR 6 #define SLC_ABORT 7 #define SLC_EOF 8 #define SLC_SUSP 9 #define SLC_EC 10 #define SLC_EL 11 #define SLC_EW 12 #define SLC_RP 13 #define SLC_LNEXT 14 #define SLC_XON 15 #define SLC_XOFF 16 #define SLC_FORW1 17 #define SLC_FORW2 18 - -#define NSLC 18 +#define SLC_MCL 19 +#define SLC_MCR 20 +#define SLC_MCWL 21 +#define SLC_MCWR 22 +#define SLC_MCBOL 23 +#define SLC_MCEOL 24 +#define SLC_INSRT 25 +#define SLC_OVER 26 +#define SLC_ECR 27 +#define SLC_EWR 28 +#define SLC_EBOL 29 +#define SLC_EEOL 30 + +#define NSLC 30 /* * For backwards compatability, we define SLC_NAMES to be the * list of names if SLC_NAMES is not defined. */ #define SLC_NAMELIST "0", "SYNCH", "BRK", "IP", "AO", "AYT", "EOR", \ "ABORT", "EOF", "SUSP", "EC", "EL", "EW", "RP", \ - "LNEXT", "XON", "XOFF", "FORW1", "FORW2", 0, + "LNEXT", "XON", "XOFF", "FORW1", "FORW2", \ + "MCL", "MCR", "MCWL", "MCWR", "MCBOL", \ + "MCEOL", "INSRT", "OVER", "ECR", "EWR", \ + "EBOL", "EEOL", \ + 0 + #ifdef SLC_NAMES char *slc_names[] = { SLC_NAMELIST }; #else extern char *slc_names[]; #define SLC_NAMES SLC_NAMELIST #endif #define SLC_NAME_OK(x) ((unsigned int)(x) <= NSLC) #define SLC_NAME(x) slc_names[x] #define SLC_NOSUPPORT 0 #define SLC_CANTCHANGE 1 #define SLC_VARIABLE 2 #define SLC_DEFAULT 3 #define SLC_LEVELBITS 0x03 #define SLC_FUNC 0 #define SLC_FLAGS 1 #define SLC_VALUE 2 #define SLC_ACK 0x80 #define SLC_FLUSHIN 0x40 #define SLC_FLUSHOUT 0x20 #define OLD_ENV_VAR 1 #define OLD_ENV_VALUE 0 #define NEW_ENV_VAR 0 #define NEW_ENV_VALUE 1 #define ENV_ESC 2 #define ENV_USERVAR 3 /* * AUTHENTICATION suboptions */ /* * Who is authenticating who ... */ #define AUTH_WHO_CLIENT 0 /* Client authenticating server */ #define AUTH_WHO_SERVER 1 /* Server authenticating client */ #define AUTH_WHO_MASK 1 /* * amount of authentication done */ #define AUTH_HOW_ONE_WAY 0 #define AUTH_HOW_MUTUAL 2 #define AUTH_HOW_MASK 2 #define AUTHTYPE_NULL 0 #define AUTHTYPE_KERBEROS_V4 1 #define AUTHTYPE_KERBEROS_V5 2 #define AUTHTYPE_SPX 3 #define AUTHTYPE_MINK 4 #define AUTHTYPE_CNT 5 #define AUTHTYPE_TEST 99 #ifdef AUTH_NAMES char *authtype_names[] = { - "NULL", "KERBEROS_V4", "KERBEROS_V5", "SPX", "MINK", 0, + "NULL", "KERBEROS_V4", "KERBEROS_V5", "SPX", "MINK", + 0 }; #else extern char *authtype_names[]; #endif #define AUTHTYPE_NAME_OK(x) ((unsigned int)(x) < AUTHTYPE_CNT) #define AUTHTYPE_NAME(x) authtype_names[x] /* * ENCRYPTion suboptions */ #define ENCRYPT_IS 0 /* I pick encryption type ... */ #define ENCRYPT_SUPPORT 1 /* I support encryption types ... */ #define ENCRYPT_REPLY 2 /* Initial setup response */ #define ENCRYPT_START 3 /* Am starting to send encrypted */ #define ENCRYPT_END 4 /* Am ending encrypted */ #define ENCRYPT_REQSTART 5 /* Request you start encrypting */ -#define ENCRYPT_REQEND 6 /* Request you send encrypting */ +#define ENCRYPT_REQEND 6 /* Request you end encrypting */ #define ENCRYPT_ENC_KEYID 7 #define ENCRYPT_DEC_KEYID 8 #define ENCRYPT_CNT 9 #define ENCTYPE_ANY 0 #define ENCTYPE_DES_CFB64 1 #define ENCTYPE_DES_OFB64 2 #define ENCTYPE_CNT 3 #ifdef ENCRYPT_NAMES char *encrypt_names[] = { "IS", "SUPPORT", "REPLY", "START", "END", "REQUEST-START", "REQUEST-END", "ENC-KEYID", "DEC-KEYID", - 0, + 0 }; char *enctype_names[] = { - "ANY", "DES_CFB64", "DES_OFB64", 0, + "ANY", "DES_CFB64", "DES_OFB64", + 0 }; #else extern char *encrypt_names[]; extern char *enctype_names[]; #endif #define ENCRYPT_NAME_OK(x) ((unsigned int)(x) < ENCRYPT_CNT) #define ENCRYPT_NAME(x) encrypt_names[x] #define ENCTYPE_NAME_OK(x) ((unsigned int)(x) < ENCTYPE_CNT) #define ENCTYPE_NAME(x) enctype_names[x] #endif /* !_TELNET_H_ */ diff --git a/crypto/telnet/libtelnet/auth-proto.h b/crypto/telnet/libtelnet/auth-proto.h index 06bba2b55c1d..a1e9aa410ff6 100644 --- a/crypto/telnet/libtelnet/auth-proto.h +++ b/crypto/telnet/libtelnet/auth-proto.h @@ -1,96 +1,100 @@ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. * * @(#)auth-proto.h 8.1 (Berkeley) 6/4/93 */ /* * Copyright (C) 1990 by the Massachusetts Institute of Technology * * Export of this software from the United States of America is assumed * to require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. */ #if !defined(P) #ifdef __STDC__ #define P(x) x #else #define P(x) () #endif #endif #if defined(AUTHENTICATION) Authenticator *findauthenticator P((int, int)); void auth_init P((char *, int)); int auth_cmd P((int, char **)); void auth_request P((void)); void auth_send P((unsigned char *, int)); void auth_send_retry P((void)); void auth_is P((unsigned char *, int)); void auth_reply P((unsigned char *, int)); void auth_finished P((Authenticator *, int)); int auth_wait P((char *)); void auth_disable_name P((char *)); void auth_gen_printsub P((unsigned char *, int, unsigned char *, int)); +void auth_name P((unsigned char *, int)); +void auth_printsub P((unsigned char *, int, unsigned char *, int)); +int auth_sendname P((unsigned char *, int)); +void auth_encrypt_user P((char *)); #ifdef KRB4 int kerberos4_init P((Authenticator *, int)); int kerberos4_send P((Authenticator *)); void kerberos4_is P((Authenticator *, unsigned char *, int)); void kerberos4_reply P((Authenticator *, unsigned char *, int)); int kerberos4_status P((Authenticator *, char *, int)); void kerberos4_printsub P((unsigned char *, int, unsigned char *, int)); #endif #ifdef KRB5 int kerberos5_init P((Authenticator *, int)); int kerberos5_send P((Authenticator *)); void kerberos5_is P((Authenticator *, unsigned char *, int)); void kerberos5_reply P((Authenticator *, unsigned char *, int)); int kerberos5_status P((Authenticator *, char *, int)); void kerberos5_printsub P((unsigned char *, int, unsigned char *, int)); #endif #endif diff --git a/crypto/telnet/libtelnet/auth.c b/crypto/telnet/libtelnet/auth.c index a8b287c0e5f7..4262b55a100a 100644 --- a/crypto/telnet/libtelnet/auth.c +++ b/crypto/telnet/libtelnet/auth.c @@ -1,671 +1,674 @@ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. */ #ifndef lint -static char sccsid[] = "@(#)auth.c 8.3 (Berkeley) 5/30/95"; +static const char sccsid[] = "@(#)auth.c 8.3 (Berkeley) 5/30/95"; #endif /* not lint */ /* * Copyright (C) 1990 by the Massachusetts Institute of Technology * * Export of this software from the United States of America is assumed * to require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. */ #if defined(AUTHENTICATION) #include #include #include #define AUTH_NAMES #include #ifdef __STDC__ #include +#include #endif #ifdef NO_STRING_H #include #else #include #endif #include "encrypt.h" #include "auth.h" #include "misc-proto.h" #include "auth-proto.h" #define typemask(x) (1<<((x)-1)) #ifdef KRB4_ENCPWD extern krb4encpwd_init(); extern krb4encpwd_send(); extern krb4encpwd_is(); extern krb4encpwd_reply(); extern krb4encpwd_status(); extern krb4encpwd_printsub(); #endif #ifdef RSA_ENCPWD extern rsaencpwd_init(); extern rsaencpwd_send(); extern rsaencpwd_is(); extern rsaencpwd_reply(); extern rsaencpwd_status(); extern rsaencpwd_printsub(); #endif int auth_debug_mode = 0; static char *Name = "Noname"; static int Server = 0; static Authenticator *authenticated = 0; static int authenticating = 0; static int validuser = 0; static unsigned char _auth_send_data[256]; static unsigned char *auth_send_data; static int auth_send_cnt = 0; +int auth_onoff(char *type, int on); +void auth_encrypt_user(char *name); + /* * Authentication types supported. Plese note that these are stored * in priority order, i.e. try the first one first. */ Authenticator authenticators[] = { #ifdef SPX { AUTHTYPE_SPX, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL, spx_init, spx_send, spx_is, spx_reply, spx_status, spx_printsub }, { AUTHTYPE_SPX, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY, spx_init, spx_send, spx_is, spx_reply, spx_status, spx_printsub }, #endif #ifdef KRB5 # ifdef ENCRYPTION { AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL, kerberos5_init, kerberos5_send, kerberos5_is, kerberos5_reply, kerberos5_status, kerberos5_printsub }, # endif /* ENCRYPTION */ { AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY, kerberos5_init, kerberos5_send, kerberos5_is, kerberos5_reply, kerberos5_status, kerberos5_printsub }, #endif #ifdef KRB4 # ifdef ENCRYPTION { AUTHTYPE_KERBEROS_V4, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL, kerberos4_init, kerberos4_send, kerberos4_is, kerberos4_reply, kerberos4_status, kerberos4_printsub }, # endif /* ENCRYPTION */ { AUTHTYPE_KERBEROS_V4, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY, kerberos4_init, kerberos4_send, kerberos4_is, kerberos4_reply, kerberos4_status, kerberos4_printsub }, #endif #ifdef KRB4_ENCPWD { AUTHTYPE_KRB4_ENCPWD, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL, krb4encpwd_init, krb4encpwd_send, krb4encpwd_is, krb4encpwd_reply, krb4encpwd_status, krb4encpwd_printsub }, #endif #ifdef RSA_ENCPWD { AUTHTYPE_RSA_ENCPWD, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY, rsaencpwd_init, rsaencpwd_send, rsaencpwd_is, rsaencpwd_reply, rsaencpwd_status, rsaencpwd_printsub }, #endif { 0, }, }; static Authenticator NoAuth = { 0 }; static int i_support = 0; static int i_wont_support = 0; Authenticator * findauthenticator(type, way) int type; int way; { Authenticator *ap = authenticators; while (ap->type && (ap->type != type || ap->way != way)) ++ap; return(ap->type ? ap : 0); } void auth_init(name, server) char *name; int server; { Authenticator *ap = authenticators; Server = server; Name = name; i_support = 0; authenticated = 0; authenticating = 0; while (ap->type) { if (!ap->init || (*ap->init)(ap, server)) { i_support |= typemask(ap->type); if (auth_debug_mode) printf(">>>%s: I support auth type %d %d\r\n", Name, ap->type, ap->way); } else if (auth_debug_mode) printf(">>>%s: Init failed: auth type %d %d\r\n", Name, ap->type, ap->way); ++ap; } } void auth_disable_name(name) char *name; { int x; for (x = 0; x < AUTHTYPE_CNT; ++x) { if (!strcasecmp(name, AUTHTYPE_NAME(x))) { i_wont_support |= typemask(x); break; } } } int getauthmask(type, maskp) char *type; int *maskp; { register int x; if (!strcasecmp(type, AUTHTYPE_NAME(0))) { *maskp = -1; return(1); } for (x = 1; x < AUTHTYPE_CNT; ++x) { if (!strcasecmp(type, AUTHTYPE_NAME(x))) { *maskp = typemask(x); return(1); } } return(0); } int auth_enable(type) char *type; { return(auth_onoff(type, 1)); } int auth_disable(type) char *type; { return(auth_onoff(type, 0)); } int auth_onoff(type, on) char *type; int on; { int i, mask = -1; Authenticator *ap; if (!strcasecmp(type, "?") || !strcasecmp(type, "help")) { printf("auth %s 'type'\n", on ? "enable" : "disable"); printf("Where 'type' is one of:\n"); printf("\t%s\n", AUTHTYPE_NAME(0)); mask = 0; for (ap = authenticators; ap->type; ap++) { if ((mask & (i = typemask(ap->type))) != 0) continue; mask |= i; printf("\t%s\n", AUTHTYPE_NAME(ap->type)); } return(0); } if (!getauthmask(type, &mask)) { printf("%s: invalid authentication type\n", type); return(0); } if (on) i_wont_support &= ~mask; else i_wont_support |= mask; return(1); } int auth_togdebug(on) int on; { if (on < 0) auth_debug_mode ^= 1; else auth_debug_mode = on; printf("auth debugging %s\n", auth_debug_mode ? "enabled" : "disabled"); return(1); } int auth_status() { Authenticator *ap; int i, mask; if (i_wont_support == -1) printf("Authentication disabled\n"); else printf("Authentication enabled\n"); mask = 0; for (ap = authenticators; ap->type; ap++) { if ((mask & (i = typemask(ap->type))) != 0) continue; mask |= i; printf("%s: %s\n", AUTHTYPE_NAME(ap->type), (i_wont_support & typemask(ap->type)) ? "disabled" : "enabled"); } return(1); } /* * This routine is called by the server to start authentication * negotiation. */ void auth_request() { static unsigned char str_request[64] = { IAC, SB, TELOPT_AUTHENTICATION, TELQUAL_SEND, }; Authenticator *ap = authenticators; unsigned char *e = str_request + 4; if (!authenticating) { authenticating = 1; while (ap->type) { if (i_support & ~i_wont_support & typemask(ap->type)) { if (auth_debug_mode) { printf(">>>%s: Sending type %d %d\r\n", Name, ap->type, ap->way); } *e++ = ap->type; *e++ = ap->way; } ++ap; } *e++ = IAC; *e++ = SE; net_write(str_request, e - str_request); printsub('>', &str_request[2], e - str_request - 2); } } /* * This is called when an AUTH SEND is received. * It should never arrive on the server side (as only the server can * send an AUTH SEND). * You should probably respond to it if you can... * * If you want to respond to the types out of order (i.e. even * if he sends LOGIN KERBEROS and you support both, you respond * with KERBEROS instead of LOGIN (which is against what the * protocol says)) you will have to hack this code... */ void auth_send(data, cnt) unsigned char *data; int cnt; { Authenticator *ap; static unsigned char str_none[] = { IAC, SB, TELOPT_AUTHENTICATION, TELQUAL_IS, AUTHTYPE_NULL, 0, IAC, SE }; if (Server) { if (auth_debug_mode) { printf(">>>%s: auth_send called!\r\n", Name); } return; } if (auth_debug_mode) { printf(">>>%s: auth_send got:", Name); printd(data, cnt); printf("\r\n"); } /* * Save the data, if it is new, so that we can continue looking * at it if the authorization we try doesn't work */ if (data < _auth_send_data || data > _auth_send_data + sizeof(_auth_send_data)) { auth_send_cnt = cnt > sizeof(_auth_send_data) ? sizeof(_auth_send_data) : cnt; memmove((void *)_auth_send_data, (void *)data, auth_send_cnt); auth_send_data = _auth_send_data; } else { /* * This is probably a no-op, but we just make sure */ auth_send_data = data; auth_send_cnt = cnt; } while ((auth_send_cnt -= 2) >= 0) { if (auth_debug_mode) printf(">>>%s: He supports %d\r\n", Name, *auth_send_data); if ((i_support & ~i_wont_support) & typemask(*auth_send_data)) { ap = findauthenticator(auth_send_data[0], auth_send_data[1]); if (ap && ap->send) { if (auth_debug_mode) printf(">>>%s: Trying %d %d\r\n", Name, auth_send_data[0], auth_send_data[1]); if ((*ap->send)(ap)) { /* * Okay, we found one we like * and did it. * we can go home now. */ if (auth_debug_mode) printf(">>>%s: Using type %d\r\n", Name, *auth_send_data); auth_send_data += 2; return; } } /* else * just continue on and look for the * next one if we didn't do anything. */ } auth_send_data += 2; } net_write(str_none, sizeof(str_none)); printsub('>', &str_none[2], sizeof(str_none) - 2); if (auth_debug_mode) printf(">>>%s: Sent failure message\r\n", Name); auth_finished(0, AUTH_REJECT); #ifdef KANNAN /* * We requested strong authentication, however no mechanisms worked. * Therefore, exit on client end. */ printf("Unable to securely authenticate user ... exit\n"); exit(0); #endif /* KANNAN */ } void auth_send_retry() { /* * if auth_send_cnt <= 0 then auth_send will end up rejecting * the authentication and informing the other side of this. */ auth_send(auth_send_data, auth_send_cnt); } void auth_is(data, cnt) unsigned char *data; int cnt; { Authenticator *ap; if (cnt < 2) return; if (data[0] == AUTHTYPE_NULL) { auth_finished(0, AUTH_REJECT); return; } - if (ap = findauthenticator(data[0], data[1])) { + if ((ap = findauthenticator(data[0], data[1]))) { if (ap->is) (*ap->is)(ap, data+2, cnt-2); } else if (auth_debug_mode) printf(">>>%s: Invalid authentication in IS: %d\r\n", Name, *data); } void auth_reply(data, cnt) unsigned char *data; int cnt; { Authenticator *ap; if (cnt < 2) return; - if (ap = findauthenticator(data[0], data[1])) { + if ((ap = findauthenticator(data[0], data[1]))) { if (ap->reply) (*ap->reply)(ap, data+2, cnt-2); } else if (auth_debug_mode) printf(">>>%s: Invalid authentication in SEND: %d\r\n", Name, *data); } void auth_name(data, cnt) unsigned char *data; int cnt; { - Authenticator *ap; unsigned char savename[256]; if (cnt < 1) { if (auth_debug_mode) printf(">>>%s: Empty name in NAME\r\n", Name); return; } if (cnt > sizeof(savename) - 1) { if (auth_debug_mode) printf(">>>%s: Name in NAME (%d) exceeds %d length\r\n", Name, cnt, sizeof(savename)-1); return; } memmove((void *)savename, (void *)data, cnt); savename[cnt] = '\0'; /* Null terminate */ if (auth_debug_mode) printf(">>>%s: Got NAME [%s]\r\n", Name, savename); auth_encrypt_user(savename); } int auth_sendname(cp, len) unsigned char *cp; int len; { static unsigned char str_request[256+6] = { IAC, SB, TELOPT_AUTHENTICATION, TELQUAL_NAME, }; register unsigned char *e = str_request + 4; register unsigned char *ee = &str_request[sizeof(str_request)-2]; while (--len >= 0) { if ((*e++ = *cp++) == IAC) *e++ = IAC; if (e >= ee) return(0); } *e++ = IAC; *e++ = SE; net_write(str_request, e - str_request); printsub('>', &str_request[2], e - &str_request[2]); return(1); } void auth_finished(ap, result) Authenticator *ap; int result; { if (!(authenticated = ap)) authenticated = &NoAuth; validuser = result; } /* ARGSUSED */ static void auth_intr(sig) int sig; { auth_finished(0, AUTH_REJECT); } int auth_wait(name) char *name; { if (auth_debug_mode) printf(">>>%s: in auth_wait.\r\n", Name); if (Server && !authenticating) return(0); (void) signal(SIGALRM, auth_intr); alarm(30); while (!authenticated) if (telnet_spin()) break; alarm(0); (void) signal(SIGALRM, SIG_DFL); /* * Now check to see if the user is valid or not */ if (!authenticated || authenticated == &NoAuth) return(AUTH_REJECT); if (validuser == AUTH_VALID) validuser = AUTH_USER; if (authenticated->status) validuser = (*authenticated->status)(authenticated, name, validuser); return(validuser); } void auth_debug(mode) int mode; { auth_debug_mode = mode; } void auth_printsub(data, cnt, buf, buflen) unsigned char *data, *buf; int cnt, buflen; { Authenticator *ap; if ((ap = findauthenticator(data[1], data[2])) && ap->printsub) (*ap->printsub)(data, cnt, buf, buflen); else auth_gen_printsub(data, cnt, buf, buflen); } void auth_gen_printsub(data, cnt, buf, buflen) unsigned char *data, *buf; int cnt, buflen; { register unsigned char *cp; unsigned char tbuf[16]; cnt -= 3; data += 3; buf[buflen-1] = '\0'; buf[buflen-2] = '*'; buflen -= 2; for (; cnt > 0; cnt--, data++) { sprintf((char *)tbuf, " %d", *data); for (cp = tbuf; *cp && buflen > 0; --buflen) *buf++ = *cp++; if (buflen <= 0) return; } *buf = '\0'; } #endif diff --git a/crypto/telnet/libtelnet/enc-proto.h b/crypto/telnet/libtelnet/enc-proto.h index 2e30908f292d..8e15ffdab8d1 100644 --- a/crypto/telnet/libtelnet/enc-proto.h +++ b/crypto/telnet/libtelnet/enc-proto.h @@ -1,125 +1,126 @@ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. * * @(#)enc-proto.h 8.1 (Berkeley) 6/4/93 */ /* * Copyright (C) 1990 by the Massachusetts Institute of Technology * * Export of this software from the United States of America is assumed * to require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. */ #if !defined(P) #ifdef __STDC__ #define P(x) x #else #define P(x) () #endif #endif #ifdef ENCRYPTION void encrypt_init P((char *, int)); Encryptions *findencryption P((int)); void encrypt_send_supprt P((void)); void encrypt_auto P((int)); void decrypt_auto P((int)); void encrypt_is P((unsigned char *, int)); void encrypt_reply P((unsigned char *, int)); void encrypt_start_input P((int)); void encrypt_session_key P((Session_Key *, int)); void encrypt_end_input P((void)); void encrypt_start_output P((int)); void encrypt_end_output P((void)); void encrypt_send_request_start P((void)); void encrypt_send_request_end P((void)); void encrypt_send_end P((void)); void encrypt_wait P((void)); void encrypt_send_support P((void)); void encrypt_send_keyid P((int, unsigned char *, int, int)); +void encrypt_start P((unsigned char *, int)); +void encrypt_end P((void)); +void encrypt_support P((unsigned char *, int)); +void encrypt_request_start P((unsigned char *, int)); +void encrypt_request_end P((void)); +void encrypt_enc_keyid P((unsigned char *, int)); +void encrypt_dec_keyid P((unsigned char *, int)); +void encrypt_printsub P((unsigned char *, int, unsigned char *, int)); int net_write P((unsigned char *, int)); -#ifdef TELENTD -void encrypt_wait P((void)); -#else +#ifndef TELENTD int encrypt_cmd P((int, char **)); void encrypt_display P((void)); #endif void krbdes_encrypt P((unsigned char *, int)); int krbdes_decrypt P((int)); int krbdes_is P((unsigned char *, int)); int krbdes_reply P((unsigned char *, int)); void krbdes_init P((int)); int krbdes_start P((int, int)); void krbdes_session P((Session_Key *, int)); void krbdes_printsub P((unsigned char *, int, unsigned char *, int)); void cfb64_encrypt P((unsigned char *, int)); int cfb64_decrypt P((int)); void cfb64_init P((int)); int cfb64_start P((int, int)); int cfb64_is P((unsigned char *, int)); int cfb64_reply P((unsigned char *, int)); void cfb64_session P((Session_Key *, int)); int cfb64_keyid P((int, unsigned char *, int *)); void cfb64_printsub P((unsigned char *, int, unsigned char *, int)); void ofb64_encrypt P((unsigned char *, int)); int ofb64_decrypt P((int)); void ofb64_init P((int)); int ofb64_start P((int, int)); int ofb64_is P((unsigned char *, int)); int ofb64_reply P((unsigned char *, int)); void ofb64_session P((Session_Key *, int)); int ofb64_keyid P((int, unsigned char *, int *)); void ofb64_printsub P((unsigned char *, int, unsigned char *, int)); -int des_new_random_key P((Block)); -void des_set_random_generator_seed P((Block)); -void des_key_sched P((Block, Schedule)); -void des_ecb_encrypt P((Block, Block, Schedule, int)); -int des_string_to_key P((char *, Block)); #endif /* ENCRYPTION */ diff --git a/crypto/telnet/libtelnet/enc_des.c b/crypto/telnet/libtelnet/enc_des.c index d6886fd717d4..8e4b9a7f4b78 100644 --- a/crypto/telnet/libtelnet/enc_des.c +++ b/crypto/telnet/libtelnet/enc_des.c @@ -1,724 +1,720 @@ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. */ #ifndef lint -static char sccsid[] = "@(#)enc_des.c 8.3 (Berkeley) 5/30/95"; +static const char sccsid[] = "@(#)enc_des.c 8.3 (Berkeley) 5/30/95"; #endif /* not lint */ #ifdef ENCRYPTION # ifdef AUTHENTICATION # ifdef DES_ENCRYPTION #include #include #ifdef __STDC__ #include #endif +#include +#include #include "encrypt.h" #include "key-proto.h" #include "misc-proto.h" extern encrypt_debug_mode; #define CFB 0 #define OFB 1 #define NO_SEND_IV 1 #define NO_RECV_IV 2 #define NO_KEYID 4 #define IN_PROGRESS (NO_SEND_IV|NO_RECV_IV|NO_KEYID) #define SUCCESS 0 #define FAILED -1 struct fb { Block krbdes_key; Schedule krbdes_sched; Block temp_feed; unsigned char fb_feed[64]; int need_start; int state[2]; int keyid[2]; int once; struct stinfo { Block str_output; Block str_feed; Block str_iv; Block str_ikey; Schedule str_sched; int str_index; int str_flagshift; } streams[2]; }; static struct fb fb[2]; struct keyidlist { char *keyid; int keyidlen; char *key; int keylen; int flags; } keyidlist [] = { { "\0", 1, 0, 0, 0 }, /* default key of zero */ { 0, 0, 0, 0, 0 } }; #define KEYFLAG_MASK 03 #define KEYFLAG_NOINIT 00 #define KEYFLAG_INIT 01 #define KEYFLAG_OK 02 #define KEYFLAG_BAD 03 #define KEYFLAG_SHIFT 2 #define SHIFT_VAL(a,b) (KEYFLAG_SHIFT*((a)+((b)*2))) #define FB64_IV 1 #define FB64_IV_OK 2 #define FB64_IV_BAD 3 void fb64_stream_iv P((Block, struct stinfo *)); void fb64_init P((struct fb *)); static int fb64_start P((struct fb *, int, int)); int fb64_is P((unsigned char *, int, struct fb *)); int fb64_reply P((unsigned char *, int, struct fb *)); static void fb64_session P((Session_Key *, int, struct fb *)); void fb64_stream_key P((Block, struct stinfo *)); int fb64_keyid P((int, unsigned char *, int *, struct fb *)); void cfb64_init(server) int server; { fb64_init(&fb[CFB]); fb[CFB].fb_feed[4] = ENCTYPE_DES_CFB64; fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, CFB); fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, CFB); } void ofb64_init(server) int server; { fb64_init(&fb[OFB]); fb[OFB].fb_feed[4] = ENCTYPE_DES_OFB64; fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, OFB); fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, OFB); } void fb64_init(fbp) register struct fb *fbp; { memset((void *)fbp, 0, sizeof(*fbp)); fbp->state[0] = fbp->state[1] = FAILED; fbp->fb_feed[0] = IAC; fbp->fb_feed[1] = SB; fbp->fb_feed[2] = TELOPT_ENCRYPT; fbp->fb_feed[3] = ENCRYPT_IS; } /* * Returns: * -1: some error. Negotiation is done, encryption not ready. * 0: Successful, initial negotiation all done. * 1: successful, negotiation not done yet. * 2: Not yet. Other things (like getting the key from * Kerberos) have to happen before we can continue. */ int cfb64_start(dir, server) int dir; int server; { return(fb64_start(&fb[CFB], dir, server)); } int ofb64_start(dir, server) int dir; int server; { return(fb64_start(&fb[OFB], dir, server)); } static int fb64_start(fbp, dir, server) struct fb *fbp; int dir; int server; { - Block b; int x; unsigned char *p; register int state; switch (dir) { case DIR_DECRYPT: /* * This is simply a request to have the other side * start output (our input). He will negotiate an * IV so we need not look for it. */ state = fbp->state[dir-1]; if (state == FAILED) state = IN_PROGRESS; break; case DIR_ENCRYPT: state = fbp->state[dir-1]; if (state == FAILED) state = IN_PROGRESS; else if ((state & NO_SEND_IV) == 0) break; if (!VALIDKEY(fbp->krbdes_key)) { fbp->need_start = 1; break; } state &= ~NO_SEND_IV; state |= NO_RECV_IV; if (encrypt_debug_mode) printf("Creating new feed\r\n"); /* * Create a random feed and send it over. */ - des_new_random_key(fbp->temp_feed); - des_ecb_encrypt(fbp->temp_feed, fbp->temp_feed, + des_new_random_key((Block *)fbp->temp_feed); + des_ecb_encrypt((Block *)fbp->temp_feed, (Block *)fbp->temp_feed, fbp->krbdes_sched, 1); p = fbp->fb_feed + 3; *p++ = ENCRYPT_IS; p++; *p++ = FB64_IV; for (x = 0; x < sizeof(Block); ++x) { if ((*p++ = fbp->temp_feed[x]) == IAC) *p++ = IAC; } *p++ = IAC; *p++ = SE; printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]); net_write(fbp->fb_feed, p - fbp->fb_feed); break; default: return(FAILED); } return(fbp->state[dir-1] = state); } /* * Returns: * -1: some error. Negotiation is done, encryption not ready. * 0: Successful, initial negotiation all done. * 1: successful, negotiation not done yet. */ int cfb64_is(data, cnt) unsigned char *data; int cnt; { return(fb64_is(data, cnt, &fb[CFB])); } int ofb64_is(data, cnt) unsigned char *data; int cnt; { return(fb64_is(data, cnt, &fb[OFB])); } int fb64_is(data, cnt, fbp) unsigned char *data; int cnt; struct fb *fbp; { - int x; unsigned char *p; - Block b; register int state = fbp->state[DIR_DECRYPT-1]; if (cnt-- < 1) goto failure; switch (*data++) { case FB64_IV: if (cnt != sizeof(Block)) { if (encrypt_debug_mode) printf("CFB64: initial vector failed on size\r\n"); state = FAILED; goto failure; } if (encrypt_debug_mode) printf("CFB64: initial vector received\r\n"); if (encrypt_debug_mode) printf("Initializing Decrypt stream\r\n"); fb64_stream_iv((void *)data, &fbp->streams[DIR_DECRYPT-1]); p = fbp->fb_feed + 3; *p++ = ENCRYPT_REPLY; p++; *p++ = FB64_IV_OK; *p++ = IAC; *p++ = SE; printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]); net_write(fbp->fb_feed, p - fbp->fb_feed); state = fbp->state[DIR_DECRYPT-1] = IN_PROGRESS; break; default: if (encrypt_debug_mode) { printf("Unknown option type: %d\r\n", *(data-1)); printd(data, cnt); printf("\r\n"); } /* FALL THROUGH */ failure: /* * We failed. Send an FB64_IV_BAD option * to the other side so it will know that * things failed. */ p = fbp->fb_feed + 3; *p++ = ENCRYPT_REPLY; p++; *p++ = FB64_IV_BAD; *p++ = IAC; *p++ = SE; printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]); net_write(fbp->fb_feed, p - fbp->fb_feed); break; } return(fbp->state[DIR_DECRYPT-1] = state); } /* * Returns: * -1: some error. Negotiation is done, encryption not ready. * 0: Successful, initial negotiation all done. * 1: successful, negotiation not done yet. */ int cfb64_reply(data, cnt) unsigned char *data; int cnt; { return(fb64_reply(data, cnt, &fb[CFB])); } int ofb64_reply(data, cnt) unsigned char *data; int cnt; { return(fb64_reply(data, cnt, &fb[OFB])); } int fb64_reply(data, cnt, fbp) unsigned char *data; int cnt; struct fb *fbp; { - int x; - unsigned char *p; - Block b; register int state = fbp->state[DIR_ENCRYPT-1]; if (cnt-- < 1) goto failure; switch (*data++) { case FB64_IV_OK: fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]); if (state == FAILED) state = IN_PROGRESS; state &= ~NO_RECV_IV; encrypt_send_keyid(DIR_ENCRYPT, (unsigned char *)"\0", 1, 1); break; case FB64_IV_BAD: memset(fbp->temp_feed, 0, sizeof(Block)); fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]); state = FAILED; break; default: if (encrypt_debug_mode) { printf("Unknown option type: %d\r\n", data[-1]); printd(data, cnt); printf("\r\n"); } /* FALL THROUGH */ failure: state = FAILED; break; } return(fbp->state[DIR_ENCRYPT-1] = state); } void cfb64_session(key, server) Session_Key *key; int server; { fb64_session(key, server, &fb[CFB]); } void ofb64_session(key, server) Session_Key *key; int server; { fb64_session(key, server, &fb[OFB]); } static void fb64_session(key, server, fbp) Session_Key *key; int server; struct fb *fbp; { if (!key || key->type != SK_DES) { if (encrypt_debug_mode) printf("Can't set krbdes's session key (%d != %d)\r\n", key ? key->type : -1, SK_DES); return; } memmove((void *)fbp->krbdes_key, (void *)key->data, sizeof(Block)); fb64_stream_key(fbp->krbdes_key, &fbp->streams[DIR_ENCRYPT-1]); fb64_stream_key(fbp->krbdes_key, &fbp->streams[DIR_DECRYPT-1]); if (fbp->once == 0) { - des_set_random_generator_seed(fbp->krbdes_key); + des_set_random_generator_seed((Block *)fbp->krbdes_key); fbp->once = 1; } - des_key_sched(fbp->krbdes_key, fbp->krbdes_sched); + des_key_sched((Block *)fbp->krbdes_key, fbp->krbdes_sched); /* * Now look to see if krbdes_start() was was waiting for * the key to show up. If so, go ahead an call it now * that we have the key. */ if (fbp->need_start) { fbp->need_start = 0; fb64_start(fbp, DIR_ENCRYPT, server); } } /* * We only accept a keyid of 0. If we get a keyid of * 0, then mark the state as SUCCESS. */ int cfb64_keyid(dir, kp, lenp) int dir, *lenp; unsigned char *kp; { return(fb64_keyid(dir, kp, lenp, &fb[CFB])); } int ofb64_keyid(dir, kp, lenp) int dir, *lenp; unsigned char *kp; { return(fb64_keyid(dir, kp, lenp, &fb[OFB])); } int fb64_keyid(dir, kp, lenp, fbp) int dir, *lenp; unsigned char *kp; struct fb *fbp; { register int state = fbp->state[dir-1]; if (*lenp != 1 || (*kp != '\0')) { *lenp = 0; return(state); } if (state == FAILED) state = IN_PROGRESS; state &= ~NO_KEYID; return(fbp->state[dir-1] = state); } void fb64_printsub(data, cnt, buf, buflen, type) unsigned char *data, *buf, *type; int cnt, buflen; { char lbuf[32]; register int i; char *cp; buf[buflen-1] = '\0'; /* make sure it's NULL terminated */ buflen -= 1; switch(data[2]) { case FB64_IV: sprintf(lbuf, "%s_IV", type); cp = lbuf; goto common; case FB64_IV_OK: sprintf(lbuf, "%s_IV_OK", type); cp = lbuf; goto common; case FB64_IV_BAD: sprintf(lbuf, "%s_IV_BAD", type); cp = lbuf; goto common; default: sprintf(lbuf, " %d (unknown)", data[2]); cp = lbuf; common: for (; (buflen > 0) && (*buf = *cp++); buf++) buflen--; for (i = 3; i < cnt; i++) { sprintf(lbuf, " %d", data[i]); for (cp = lbuf; (buflen > 0) && (*buf = *cp++); buf++) buflen--; } break; } } void cfb64_printsub(data, cnt, buf, buflen) unsigned char *data, *buf; int cnt, buflen; { fb64_printsub(data, cnt, buf, buflen, "CFB64"); } void ofb64_printsub(data, cnt, buf, buflen) unsigned char *data, *buf; int cnt, buflen; { fb64_printsub(data, cnt, buf, buflen, "OFB64"); } void fb64_stream_iv(seed, stp) Block seed; register struct stinfo *stp; { memmove((void *)stp->str_iv, (void *)seed, sizeof(Block)); memmove((void *)stp->str_output, (void *)seed, sizeof(Block)); - des_key_sched(stp->str_ikey, stp->str_sched); + des_key_sched((Block *)stp->str_ikey, stp->str_sched); stp->str_index = sizeof(Block); } void fb64_stream_key(key, stp) Block key; register struct stinfo *stp; { memmove((void *)stp->str_ikey, (void *)key, sizeof(Block)); - des_key_sched(key, stp->str_sched); + des_key_sched((Block *)key, stp->str_sched); memmove((void *)stp->str_output, (void *)stp->str_iv, sizeof(Block)); stp->str_index = sizeof(Block); } /* * DES 64 bit Cipher Feedback * * key --->+-----+ * +->| DES |--+ * | +-----+ | * | v * INPUT --(--------->(+)+---> DATA * | | * +-------------+ * * * Given: * iV: Initial vector, 64 bits (8 bytes) long. * Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt). * On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output. * * V0 = DES(iV, key) * On = Dn ^ Vn * V(n+1) = DES(On, key) */ void cfb64_encrypt(s, c) register unsigned char *s; int c; { register struct stinfo *stp = &fb[CFB].streams[DIR_ENCRYPT-1]; register int index; index = stp->str_index; while (c-- > 0) { if (index == sizeof(Block)) { Block b; - des_ecb_encrypt(stp->str_output, b, stp->str_sched, 1); + des_ecb_encrypt((Block *)stp->str_output, (Block *)b, stp->str_sched, 1); memmove((void *)stp->str_feed, (void *)b, sizeof(Block)); index = 0; } /* On encryption, we store (feed ^ data) which is cypher */ *s = stp->str_output[index] = (stp->str_feed[index] ^ *s); s++; index++; } stp->str_index = index; } int cfb64_decrypt(data) int data; { register struct stinfo *stp = &fb[CFB].streams[DIR_DECRYPT-1]; int index; if (data == -1) { /* * Back up one byte. It is assumed that we will * never back up more than one byte. If we do, this * may or may not work. */ if (stp->str_index) --stp->str_index; return(0); } index = stp->str_index++; if (index == sizeof(Block)) { Block b; - des_ecb_encrypt(stp->str_output, b, stp->str_sched, 1); + des_ecb_encrypt((Block *)stp->str_output, (Block *)b, stp->str_sched, 1); memmove((void *)stp->str_feed, (void *)b, sizeof(Block)); stp->str_index = 1; /* Next time will be 1 */ index = 0; /* But now use 0 */ } /* On decryption we store (data) which is cypher. */ stp->str_output[index] = data; return(data ^ stp->str_feed[index]); } /* * DES 64 bit Output Feedback * * key --->+-----+ * +->| DES |--+ * | +-----+ | * +-----------+ * v * INPUT -------->(+) ----> DATA * * Given: * iV: Initial vector, 64 bits (8 bytes) long. * Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt). * On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output. * * V0 = DES(iV, key) * V(n+1) = DES(Vn, key) * On = Dn ^ Vn */ void ofb64_encrypt(s, c) register unsigned char *s; int c; { register struct stinfo *stp = &fb[OFB].streams[DIR_ENCRYPT-1]; register int index; index = stp->str_index; while (c-- > 0) { if (index == sizeof(Block)) { Block b; - des_ecb_encrypt(stp->str_feed, b, stp->str_sched, 1); + des_ecb_encrypt((Block *)stp->str_feed, (Block *)b, stp->str_sched, 1); memmove((void *)stp->str_feed, (void *)b, sizeof(Block)); index = 0; } *s++ ^= stp->str_feed[index]; index++; } stp->str_index = index; } int ofb64_decrypt(data) int data; { register struct stinfo *stp = &fb[OFB].streams[DIR_DECRYPT-1]; int index; if (data == -1) { /* * Back up one byte. It is assumed that we will * never back up more than one byte. If we do, this * may or may not work. */ if (stp->str_index) --stp->str_index; return(0); } index = stp->str_index++; if (index == sizeof(Block)) { Block b; - des_ecb_encrypt(stp->str_feed, b, stp->str_sched, 1); + des_ecb_encrypt((Block *)stp->str_feed, (Block *)b, stp->str_sched, 1); memmove((void *)stp->str_feed, (void *)b, sizeof(Block)); stp->str_index = 1; /* Next time will be 1 */ index = 0; /* But now use 0 */ } return(data ^ stp->str_feed[index]); } # endif /* DES_ENCRYPTION */ # endif /* AUTHENTICATION */ #endif /* ENCRYPTION */ diff --git a/crypto/telnet/libtelnet/encrypt.c b/crypto/telnet/libtelnet/encrypt.c index 432df0cbb333..41dd5cc71044 100644 --- a/crypto/telnet/libtelnet/encrypt.c +++ b/crypto/telnet/libtelnet/encrypt.c @@ -1,1000 +1,1016 @@ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. */ #ifndef lint -static char sccsid[] = "@(#)encrypt.c 8.2 (Berkeley) 5/30/95"; +static const char sccsid[] = "@(#)encrypt.c 8.2 (Berkeley) 5/30/95"; #endif /* not lint */ /* * Copyright (C) 1990 by the Massachusetts Institute of Technology * * Export of this software from the United States of America is assumed * to require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. */ #ifdef ENCRYPTION #define ENCRYPT_NAMES +#include #include #include "encrypt.h" #include "misc.h" #ifdef __STDC__ #include #endif #ifdef NO_STRING_H #include #else #include #endif /* * These functions pointers point to the current routines * for encrypting and decrypting data. */ void (*encrypt_output) P((unsigned char *, int)); int (*decrypt_input) P((int)); +int EncryptType(char *type, char *mode); +int EncryptStart(char *mode); +int EncryptStop(char *mode); +int EncryptStartInput(void); +int EncryptStartOutput(void); +int EncryptStopInput(void); +int EncryptStopOutput(void); + +int Ambiguous(char **s); +int isprefix(char *s1, char *s2); +char **genget(char *name, char **table, int stlen); + int encrypt_debug_mode = 0; static int decrypt_mode = 0; static int encrypt_mode = 0; static int encrypt_verbose = 0; static int autoencrypt = 0; static int autodecrypt = 0; static int havesessionkey = 0; static int Server = 0; static char *Name = "Noname"; #define typemask(x) ((x) > 0 ? 1 << ((x)-1) : 0) static long i_support_encrypt = typemask(ENCTYPE_DES_CFB64) | typemask(ENCTYPE_DES_OFB64); static long i_support_decrypt = typemask(ENCTYPE_DES_CFB64) | typemask(ENCTYPE_DES_OFB64); static long i_wont_support_encrypt = 0; static long i_wont_support_decrypt = 0; #define I_SUPPORT_ENCRYPT (i_support_encrypt & ~i_wont_support_encrypt) #define I_SUPPORT_DECRYPT (i_support_decrypt & ~i_wont_support_decrypt) static long remote_supports_encrypt = 0; static long remote_supports_decrypt = 0; static Encryptions encryptions[] = { #ifdef DES_ENCRYPTION { "DES_CFB64", ENCTYPE_DES_CFB64, cfb64_encrypt, cfb64_decrypt, cfb64_init, cfb64_start, cfb64_is, cfb64_reply, cfb64_session, cfb64_keyid, cfb64_printsub }, { "DES_OFB64", ENCTYPE_DES_OFB64, ofb64_encrypt, ofb64_decrypt, ofb64_init, ofb64_start, ofb64_is, ofb64_reply, ofb64_session, ofb64_keyid, ofb64_printsub }, #endif /* DES_ENCRYPTION */ { 0, }, }; static unsigned char str_send[64] = { IAC, SB, TELOPT_ENCRYPT, ENCRYPT_SUPPORT }; static unsigned char str_suplen = 0; static unsigned char str_start[72] = { IAC, SB, TELOPT_ENCRYPT }; static unsigned char str_end[] = { IAC, SB, TELOPT_ENCRYPT, 0, IAC, SE }; Encryptions * findencryption(type) int type; { Encryptions *ep = encryptions; if (!(I_SUPPORT_ENCRYPT & remote_supports_decrypt & typemask(type))) return(0); while (ep->type && ep->type != type) ++ep; return(ep->type ? ep : 0); } Encryptions * finddecryption(type) int type; { Encryptions *ep = encryptions; if (!(I_SUPPORT_DECRYPT & remote_supports_encrypt & typemask(type))) return(0); while (ep->type && ep->type != type) ++ep; return(ep->type ? ep : 0); } #define MAXKEYLEN 64 static struct key_info { unsigned char keyid[MAXKEYLEN]; int keylen; int dir; int *modep; Encryptions *(*getcrypt)(); } ki[2] = { { { 0 }, 0, DIR_ENCRYPT, &encrypt_mode, findencryption }, { { 0 }, 0, DIR_DECRYPT, &decrypt_mode, finddecryption }, }; +static void encrypt_keyid(struct key_info *kp, unsigned char *keyid, int len); + void encrypt_init(name, server) char *name; int server; { Encryptions *ep = encryptions; Name = name; Server = server; i_support_encrypt = i_support_decrypt = 0; remote_supports_encrypt = remote_supports_decrypt = 0; encrypt_mode = 0; decrypt_mode = 0; encrypt_output = 0; decrypt_input = 0; #ifdef notdef encrypt_verbose = !server; #endif str_suplen = 4; while (ep->type) { if (encrypt_debug_mode) printf(">>>%s: I will support %s\r\n", Name, ENCTYPE_NAME(ep->type)); i_support_encrypt |= typemask(ep->type); i_support_decrypt |= typemask(ep->type); if ((i_wont_support_decrypt & typemask(ep->type)) == 0) if ((str_send[str_suplen++] = ep->type) == IAC) str_send[str_suplen++] = IAC; if (ep->init) (*ep->init)(Server); ++ep; } str_send[str_suplen++] = IAC; str_send[str_suplen++] = SE; } void encrypt_list_types() { Encryptions *ep = encryptions; printf("Valid encryption types:\n"); while (ep->type) { printf("\t%s (%d)\r\n", ENCTYPE_NAME(ep->type), ep->type); ++ep; } } int EncryptEnable(type, mode) char *type, *mode; { if (isprefix(type, "help") || isprefix(type, "?")) { printf("Usage: encrypt enable [input|output]\n"); encrypt_list_types(); return(0); } if (EncryptType(type, mode)) return(EncryptStart(mode)); return(0); } int EncryptDisable(type, mode) char *type, *mode; { register Encryptions *ep; int ret = 0; if (isprefix(type, "help") || isprefix(type, "?")) { printf("Usage: encrypt disable [input|output]\n"); encrypt_list_types(); - } else if ((ep = (Encryptions *)genget(type, encryptions, + } else if ((ep = (Encryptions *)genget(type, (char **)encryptions, sizeof(Encryptions))) == 0) { printf("%s: invalid encryption type\n", type); - } else if (Ambiguous(ep)) { + } else if (Ambiguous((char **)ep)) { printf("Ambiguous type '%s'\n", type); } else { if ((mode == 0) || (isprefix(mode, "input") ? 1 : 0)) { if (decrypt_mode == ep->type) EncryptStopInput(); i_wont_support_decrypt |= typemask(ep->type); ret = 1; } if ((mode == 0) || (isprefix(mode, "output"))) { if (encrypt_mode == ep->type) EncryptStopOutput(); i_wont_support_encrypt |= typemask(ep->type); ret = 1; } if (ret == 0) printf("%s: invalid encryption mode\n", mode); } return(ret); } int EncryptType(type, mode) char *type; char *mode; { register Encryptions *ep; int ret = 0; if (isprefix(type, "help") || isprefix(type, "?")) { printf("Usage: encrypt type [input|output]\n"); encrypt_list_types(); - } else if ((ep = (Encryptions *)genget(type, encryptions, + } else if ((ep = (Encryptions *)genget(type, (char **)encryptions, sizeof(Encryptions))) == 0) { printf("%s: invalid encryption type\n", type); - } else if (Ambiguous(ep)) { + } else if (Ambiguous((char **)ep)) { printf("Ambiguous type '%s'\n", type); } else { if ((mode == 0) || isprefix(mode, "input")) { decrypt_mode = ep->type; i_wont_support_decrypt &= ~typemask(ep->type); ret = 1; } if ((mode == 0) || isprefix(mode, "output")) { encrypt_mode = ep->type; i_wont_support_encrypt &= ~typemask(ep->type); ret = 1; } if (ret == 0) printf("%s: invalid encryption mode\n", mode); } return(ret); } int EncryptStart(mode) char *mode; { register int ret = 0; if (mode) { if (isprefix(mode, "input")) return(EncryptStartInput()); if (isprefix(mode, "output")) return(EncryptStartOutput()); if (isprefix(mode, "help") || isprefix(mode, "?")) { printf("Usage: encrypt start [input|output]\n"); return(0); } printf("%s: invalid encryption mode 'encrypt start ?' for help\n", mode); return(0); } ret += EncryptStartInput(); ret += EncryptStartOutput(); return(ret); } int EncryptStartInput() { if (decrypt_mode) { encrypt_send_request_start(); return(1); } printf("No previous decryption mode, decryption not enabled\r\n"); return(0); } int EncryptStartOutput() { if (encrypt_mode) { encrypt_start_output(encrypt_mode); return(1); } printf("No previous encryption mode, encryption not enabled\r\n"); return(0); } int EncryptStop(mode) char *mode; { int ret = 0; if (mode) { if (isprefix(mode, "input")) return(EncryptStopInput()); if (isprefix(mode, "output")) return(EncryptStopOutput()); if (isprefix(mode, "help") || isprefix(mode, "?")) { printf("Usage: encrypt stop [input|output]\n"); return(0); } printf("%s: invalid encryption mode 'encrypt stop ?' for help\n", mode); return(0); } ret += EncryptStopInput(); ret += EncryptStopOutput(); return(ret); } int EncryptStopInput() { encrypt_send_request_end(); return(1); } int EncryptStopOutput() { encrypt_send_end(); return(1); } void encrypt_display() { if (encrypt_output) printf("Currently encrypting output with %s\r\n", ENCTYPE_NAME(encrypt_mode)); if (decrypt_input) printf("Currently decrypting input with %s\r\n", ENCTYPE_NAME(decrypt_mode)); } int EncryptStatus() { if (encrypt_output) printf("Currently encrypting output with %s\r\n", ENCTYPE_NAME(encrypt_mode)); else if (encrypt_mode) { printf("Currently output is clear text.\r\n"); printf("Last encryption mode was %s\r\n", ENCTYPE_NAME(encrypt_mode)); } if (decrypt_input) { printf("Currently decrypting input with %s\r\n", ENCTYPE_NAME(decrypt_mode)); } else if (decrypt_mode) { printf("Currently input is clear text.\r\n"); printf("Last decryption mode was %s\r\n", ENCTYPE_NAME(decrypt_mode)); } return 1; } void encrypt_send_support() { if (str_suplen) { /* * If the user has requested that decryption start * immediatly, then send a "REQUEST START" before * we negotiate the type. */ if (!Server && autodecrypt) encrypt_send_request_start(); net_write(str_send, str_suplen); printsub('>', &str_send[2], str_suplen - 2); str_suplen = 0; } } int EncryptDebug(on) int on; { if (on < 0) encrypt_debug_mode ^= 1; else encrypt_debug_mode = on; printf("Encryption debugging %s\r\n", encrypt_debug_mode ? "enabled" : "disabled"); return(1); } int EncryptVerbose(on) int on; { if (on < 0) encrypt_verbose ^= 1; else encrypt_verbose = on; printf("Encryption %s verbose\r\n", encrypt_verbose ? "is" : "is not"); return(1); } int EncryptAutoEnc(on) int on; { encrypt_auto(on); printf("Automatic encryption of output is %s\r\n", autoencrypt ? "enabled" : "disabled"); return(1); } int EncryptAutoDec(on) int on; { decrypt_auto(on); printf("Automatic decryption of input is %s\r\n", autodecrypt ? "enabled" : "disabled"); return(1); } /* * Called when ENCRYPT SUPPORT is received. */ void encrypt_support(typelist, cnt) unsigned char *typelist; int cnt; { register int type, use_type = 0; Encryptions *ep; /* * Forget anything the other side has previously told us. */ remote_supports_decrypt = 0; while (cnt-- > 0) { type = *typelist++; if (encrypt_debug_mode) printf(">>>%s: He is supporting %s (%d)\r\n", Name, ENCTYPE_NAME(type), type); if ((type < ENCTYPE_CNT) && (I_SUPPORT_ENCRYPT & typemask(type))) { remote_supports_decrypt |= typemask(type); if (use_type == 0) use_type = type; } } if (use_type) { ep = findencryption(use_type); if (!ep) return; type = ep->start ? (*ep->start)(DIR_ENCRYPT, Server) : 0; if (encrypt_debug_mode) printf(">>>%s: (*ep->start)() returned %d\r\n", Name, type); if (type < 0) return; encrypt_mode = use_type; if (type == 0) encrypt_start_output(use_type); } } void encrypt_is(data, cnt) unsigned char *data; int cnt; { Encryptions *ep; register int type, ret; if (--cnt < 0) return; type = *data++; if (type < ENCTYPE_CNT) remote_supports_encrypt |= typemask(type); if (!(ep = finddecryption(type))) { if (encrypt_debug_mode) printf(">>>%s: Can't find type %s (%d) for initial negotiation\r\n", Name, ENCTYPE_NAME_OK(type) ? ENCTYPE_NAME(type) : "(unknown)", type); return; } if (!ep->is) { if (encrypt_debug_mode) printf(">>>%s: No initial negotiation needed for type %s (%d)\r\n", Name, ENCTYPE_NAME_OK(type) ? ENCTYPE_NAME(type) : "(unknown)", type); ret = 0; } else { ret = (*ep->is)(data, cnt); if (encrypt_debug_mode) - printf("(*ep->is)(%x, %d) returned %s(%d)\n", data, cnt, + printf("(*ep->is)(%p, %d) returned %s(%d)\n", data, cnt, (ret < 0) ? "FAIL " : (ret == 0) ? "SUCCESS " : "MORE_TO_DO ", ret); } if (ret < 0) { autodecrypt = 0; } else { decrypt_mode = type; if (ret == 0 && autodecrypt) encrypt_send_request_start(); } } void encrypt_reply(data, cnt) unsigned char *data; int cnt; { Encryptions *ep; register int ret, type; if (--cnt < 0) return; type = *data++; if (!(ep = findencryption(type))) { if (encrypt_debug_mode) printf(">>>%s: Can't find type %s (%d) for initial negotiation\r\n", Name, ENCTYPE_NAME_OK(type) ? ENCTYPE_NAME(type) : "(unknown)", type); return; } if (!ep->reply) { if (encrypt_debug_mode) printf(">>>%s: No initial negotiation needed for type %s (%d)\r\n", Name, ENCTYPE_NAME_OK(type) ? ENCTYPE_NAME(type) : "(unknown)", type); ret = 0; } else { ret = (*ep->reply)(data, cnt); if (encrypt_debug_mode) - printf("(*ep->reply)(%x, %d) returned %s(%d)\n", + printf("(*ep->reply)(%p, %d) returned %s(%d)\n", data, cnt, (ret < 0) ? "FAIL " : (ret == 0) ? "SUCCESS " : "MORE_TO_DO ", ret); } if (encrypt_debug_mode) printf(">>>%s: encrypt_reply returned %d\n", Name, ret); if (ret < 0) { autoencrypt = 0; } else { encrypt_mode = type; if (ret == 0 && autoencrypt) encrypt_start_output(type); } } /* * Called when a ENCRYPT START command is received. */ void encrypt_start(data, cnt) unsigned char *data; int cnt; { Encryptions *ep; if (!decrypt_mode) { /* * Something is wrong. We should not get a START * command without having already picked our * decryption scheme. Send a REQUEST-END to * attempt to clear the channel... */ printf("%s: Warning, Cannot decrypt input stream!!!\r\n", Name); encrypt_send_request_end(); return; } - if (ep = finddecryption(decrypt_mode)) { + if ((ep = finddecryption(decrypt_mode))) { decrypt_input = ep->input; if (encrypt_verbose) printf("[ Input is now decrypted with type %s ]\r\n", ENCTYPE_NAME(decrypt_mode)); if (encrypt_debug_mode) printf(">>>%s: Start to decrypt input with type %s\r\n", Name, ENCTYPE_NAME(decrypt_mode)); } else { printf("%s: Warning, Cannot decrypt type %s (%d)!!!\r\n", Name, ENCTYPE_NAME_OK(decrypt_mode) ? ENCTYPE_NAME(decrypt_mode) : "(unknown)", decrypt_mode); encrypt_send_request_end(); } } void encrypt_session_key(key, server) Session_Key *key; int server; { Encryptions *ep = encryptions; havesessionkey = 1; while (ep->type) { if (ep->session) (*ep->session)(key, server); #ifdef notdef if (!encrypt_output && autoencrypt && !server) encrypt_start_output(ep->type); if (!decrypt_input && autodecrypt && !server) encrypt_send_request_start(); #endif ++ep; } } /* * Called when ENCRYPT END is received. */ void encrypt_end() { decrypt_input = 0; if (encrypt_debug_mode) printf(">>>%s: Input is back to clear text\r\n", Name); if (encrypt_verbose) printf("[ Input is now clear text ]\r\n"); } /* * Called when ENCRYPT REQUEST-END is received. */ void encrypt_request_end() { encrypt_send_end(); } /* * Called when ENCRYPT REQUEST-START is received. If we receive * this before a type is picked, then that indicates that the * other side wants us to start encrypting data as soon as we * can. */ void encrypt_request_start(data, cnt) unsigned char *data; int cnt; { if (encrypt_mode == 0) { if (Server) autoencrypt = 1; return; } encrypt_start_output(encrypt_mode); } static unsigned char str_keyid[(MAXKEYLEN*2)+5] = { IAC, SB, TELOPT_ENCRYPT }; + void encrypt_enc_keyid(keyid, len) unsigned char *keyid; int len; { encrypt_keyid(&ki[1], keyid, len); } + void encrypt_dec_keyid(keyid, len) unsigned char *keyid; int len; { encrypt_keyid(&ki[0], keyid, len); } + void encrypt_keyid(kp, keyid, len) struct key_info *kp; unsigned char *keyid; int len; { Encryptions *ep; - unsigned char *strp, *cp; int dir = kp->dir; register int ret = 0; if (!(ep = (*kp->getcrypt)(*kp->modep))) { if (len == 0) return; kp->keylen = 0; } else if (len == 0) { /* * Empty option, indicates a failure. */ if (kp->keylen == 0) return; kp->keylen = 0; if (ep->keyid) (void)(*ep->keyid)(dir, kp->keyid, &kp->keylen); } else if ((len != kp->keylen) || (memcmp(keyid, kp->keyid, len) != 0)) { /* * Length or contents are different */ kp->keylen = len; memmove(kp->keyid, keyid, len); if (ep->keyid) (void)(*ep->keyid)(dir, kp->keyid, &kp->keylen); } else { if (ep->keyid) ret = (*ep->keyid)(dir, kp->keyid, &kp->keylen); if ((ret == 0) && (dir == DIR_ENCRYPT) && autoencrypt) encrypt_start_output(*kp->modep); return; } encrypt_send_keyid(dir, kp->keyid, kp->keylen, 0); } void encrypt_send_keyid(dir, keyid, keylen, saveit) int dir; unsigned char *keyid; int keylen; int saveit; { unsigned char *strp; str_keyid[3] = (dir == DIR_ENCRYPT) ? ENCRYPT_ENC_KEYID : ENCRYPT_DEC_KEYID; if (saveit) { struct key_info *kp = &ki[(dir == DIR_ENCRYPT) ? 0 : 1]; memmove(kp->keyid, keyid, keylen); kp->keylen = keylen; } for (strp = &str_keyid[4]; keylen > 0; --keylen) { if ((*strp++ = *keyid++) == IAC) *strp++ = IAC; } *strp++ = IAC; *strp++ = SE; net_write(str_keyid, strp - str_keyid); printsub('>', &str_keyid[2], strp - str_keyid - 2); } void encrypt_auto(on) int on; { if (on < 0) autoencrypt ^= 1; else autoencrypt = on ? 1 : 0; } void decrypt_auto(on) int on; { if (on < 0) autodecrypt ^= 1; else autodecrypt = on ? 1 : 0; } void encrypt_start_output(type) int type; { Encryptions *ep; register unsigned char *p; register int i; if (!(ep = findencryption(type))) { if (encrypt_debug_mode) { printf(">>>%s: Can't encrypt with type %s (%d)\r\n", Name, ENCTYPE_NAME_OK(type) ? ENCTYPE_NAME(type) : "(unknown)", type); } return; } if (ep->start) { i = (*ep->start)(DIR_ENCRYPT, Server); if (encrypt_debug_mode) { printf(">>>%s: Encrypt start: %s (%d) %s\r\n", Name, (i < 0) ? "failed" : "initial negotiation in progress", i, ENCTYPE_NAME(type)); } if (i) return; } p = str_start + 3; *p++ = ENCRYPT_START; for (i = 0; i < ki[0].keylen; ++i) { if ((*p++ = ki[0].keyid[i]) == IAC) *p++ = IAC; } *p++ = IAC; *p++ = SE; net_write(str_start, p - str_start); net_encrypt(); printsub('>', &str_start[2], p - &str_start[2]); /* * If we are already encrypting in some mode, then * encrypt the ring (which includes our request) in * the old mode, mark it all as "clear text" and then * switch to the new mode. */ encrypt_output = ep->output; encrypt_mode = type; if (encrypt_debug_mode) printf(">>>%s: Started to encrypt output with type %s\r\n", Name, ENCTYPE_NAME(type)); if (encrypt_verbose) printf("[ Output is now encrypted with type %s ]\r\n", ENCTYPE_NAME(type)); } void encrypt_send_end() { if (!encrypt_output) return; str_end[3] = ENCRYPT_END; net_write(str_end, sizeof(str_end)); net_encrypt(); printsub('>', &str_end[2], sizeof(str_end) - 2); /* * Encrypt the output buffer now because it will not be done by * netflush... */ encrypt_output = 0; if (encrypt_debug_mode) printf(">>>%s: Output is back to clear text\r\n", Name); if (encrypt_verbose) printf("[ Output is now clear text ]\r\n"); } void encrypt_send_request_start() { register unsigned char *p; register int i; p = &str_start[3]; *p++ = ENCRYPT_REQSTART; for (i = 0; i < ki[1].keylen; ++i) { if ((*p++ = ki[1].keyid[i]) == IAC) *p++ = IAC; } *p++ = IAC; *p++ = SE; net_write(str_start, p - str_start); printsub('>', &str_start[2], p - &str_start[2]); if (encrypt_debug_mode) printf(">>>%s: Request input to be encrypted\r\n", Name); } void encrypt_send_request_end() { str_end[3] = ENCRYPT_REQEND; net_write(str_end, sizeof(str_end)); printsub('>', &str_end[2], sizeof(str_end) - 2); if (encrypt_debug_mode) printf(">>>%s: Request input to be clear text\r\n", Name); } void encrypt_wait() { - register int encrypt, decrypt; if (encrypt_debug_mode) printf(">>>%s: in encrypt_wait\r\n", Name); if (!havesessionkey || !(I_SUPPORT_ENCRYPT & remote_supports_decrypt)) return; while (autoencrypt && !encrypt_output) if (telnet_spin()) return; } void encrypt_debug(mode) int mode; { encrypt_debug_mode = mode; } void encrypt_gen_printsub(data, cnt, buf, buflen) unsigned char *data, *buf; int cnt, buflen; { char tbuf[16], *cp; cnt -= 2; data += 2; buf[buflen-1] = '\0'; buf[buflen-2] = '*'; buflen -= 2;; for (; cnt > 0; cnt--, data++) { sprintf(tbuf, " %d", *data); for (cp = tbuf; *cp && buflen > 0; --buflen) *buf++ = *cp++; if (buflen <= 0) return; } *buf = '\0'; } void encrypt_printsub(data, cnt, buf, buflen) unsigned char *data, *buf; int cnt, buflen; { Encryptions *ep; register int type = data[1]; for (ep = encryptions; ep->type && ep->type != type; ep++) ; if (ep->printsub) (*ep->printsub)(data, cnt, buf, buflen); else encrypt_gen_printsub(data, cnt, buf, buflen); } #endif /* ENCRYPTION */ diff --git a/crypto/telnet/libtelnet/encrypt.h b/crypto/telnet/libtelnet/encrypt.h index e0ae385f13f3..1c942dc6e7e8 100644 --- a/crypto/telnet/libtelnet/encrypt.h +++ b/crypto/telnet/libtelnet/encrypt.h @@ -1,108 +1,108 @@ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. * * @(#)encrypt.h 8.1 (Berkeley) 6/4/93 */ /* * Copyright (C) 1990 by the Massachusetts Institute of Technology * * Export of this software from the United States of America is assumed * to require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. */ #ifdef ENCRYPTION # ifndef __ENCRYPTION__ # define __ENCRYPTION__ #define DIR_DECRYPT 1 #define DIR_ENCRYPT 2 typedef unsigned char Block[8]; typedef unsigned char *BlockT; -typedef struct { Block _; } Schedule[16]; +typedef struct { Block __; } Schedule[16]; #define VALIDKEY(key) ( key[0] | key[1] | key[2] | key[3] | \ key[4] | key[5] | key[6] | key[7]) #define SAMEKEY(k1, k2) (!bcmp((void *)k1, (void *)k2, sizeof(Block))) typedef struct { short type; int length; unsigned char *data; } Session_Key; # if !defined(P) # ifdef __STDC__ # define P(x) x # else # define P(x) () # endif # endif typedef struct { char *name; int type; void (*output) P((unsigned char *, int)); int (*input) P((int)); void (*init) P((int)); int (*start) P((int, int)); int (*is) P((unsigned char *, int)); int (*reply) P((unsigned char *, int)); void (*session) P((Session_Key *, int)); int (*keyid) P((int, unsigned char *, int *)); void (*printsub) P((unsigned char *, int, unsigned char *, int)); } Encryptions; #define SK_DES 1 /* Matched Kerberos v5 KEYTYPE_DES */ #include "enc-proto.h" extern int encrypt_debug_mode; extern int (*decrypt_input) P((int)); extern void (*encrypt_output) P((unsigned char *, int)); # endif /* __ENCRYPTION__ */ #endif /* ENCRYPTION */ diff --git a/crypto/telnet/libtelnet/genget.c b/crypto/telnet/libtelnet/genget.c index 7be384647e3f..8668db47a700 100644 --- a/crypto/telnet/libtelnet/genget.c +++ b/crypto/telnet/libtelnet/genget.c @@ -1,105 +1,104 @@ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. */ #ifndef lint -static char sccsid[] = "@(#)genget.c 8.2 (Berkeley) 5/30/95"; +static const char sccsid[] = "@(#)genget.c 8.2 (Berkeley) 5/30/95"; #endif /* not lint */ #include #define LOWER(x) (isupper(x) ? tolower(x) : (x)) /* * The prefix function returns 0 if *s1 is not a prefix * of *s2. If *s1 exactly matches *s2, the negative of * the length is returned. If *s1 is a prefix of *s2, * the length of *s1 is returned. */ int isprefix(s1, s2) register char *s1, *s2; { - register int n = 0; char *os1; register char c1, c2; if (*s1 == '\0') return(-1); os1 = s1; c1 = *s1; c2 = *s2; while (LOWER(c1) == LOWER(c2)) { if (c1 == '\0') break; c1 = *++s1; c2 = *++s2; } return(*s1 ? 0 : (*s2 ? (s1 - os1) : (os1 - s1))); } static char *ambiguous; /* special return value for command routines */ char ** genget(name, table, stlen) char *name; /* name to match */ char **table; /* name entry in table */ int stlen; { register char **c, **found; register int n; if (name == 0) return 0; found = 0; for (c = table; *c != 0; c = (char **)((char *)c + stlen)) { if ((n = isprefix(name, *c)) == 0) continue; if (n < 0) /* exact match */ return(c); if (found) return(&ambiguous); found = c; } return(found); } /* * Function call version of Ambiguous() */ int Ambiguous(s) - char *s; + char **s; { - return((char **)s == &ambiguous); + return(s == &ambiguous); } diff --git a/crypto/telnet/libtelnet/kerberos.c b/crypto/telnet/libtelnet/kerberos.c index dbf495684ab8..738a57f35ce6 100644 --- a/crypto/telnet/libtelnet/kerberos.c +++ b/crypto/telnet/libtelnet/kerberos.c @@ -1,560 +1,550 @@ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. */ #ifndef lint -static char sccsid[] = "@(#)kerberos.c 8.3 (Berkeley) 5/30/95"; +static const char sccsid[] = "@(#)kerberos.c 8.3 (Berkeley) 5/30/95"; #endif /* not lint */ /* * Copyright (C) 1990 by the Massachusetts Institute of Technology * * Export of this software from the United States of America is assumed * to require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. */ #ifdef KRB4 #include #include #include #include /* BSD wont include this in krb.h, so we do it here */ #include #ifdef __STDC__ #include #endif #ifdef NO_STRING_H #include #else #include #endif #include "encrypt.h" #include "auth.h" #include "misc.h" int kerberos4_cksum P((unsigned char *, int)); -int krb_mk_req P((KTEXT, char *, char *, char *, u_long)); -int krb_rd_req P((KTEXT, char *, char *, u_long, AUTH_DAT *, char *)); -int krb_kntoln P((AUTH_DAT *, char *)); -int krb_get_cred P((char *, char *, char *, CREDENTIALS *)); -int krb_get_lrealm P((char *, int)); int kuserok P((AUTH_DAT *, char *)); extern auth_debug_mode; static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0, AUTHTYPE_KERBEROS_V4, }; -static unsigned char str_name[1024] = { IAC, SB, TELOPT_AUTHENTICATION, - TELQUAL_NAME, }; #define KRB_AUTH 0 /* Authentication data follows */ #define KRB_REJECT 1 /* Rejected (reason might follow) */ #define KRB_ACCEPT 2 /* Accepted */ #define KRB_CHALLENGE 3 /* Challenge for mutual auth. */ #define KRB_RESPONSE 4 /* Response for mutual auth. */ #define KRB_SERVICE_NAME "rcmd" static KTEXT_ST auth; static char name[ANAME_SZ]; static AUTH_DAT adat = { 0 }; #ifdef ENCRYPTION static Block session_key = { 0 }; -static Schedule sched; +static des_key_schedule sched; static Block challenge = { 0 }; #endif /* ENCRYPTION */ static int Data(ap, type, d, c) Authenticator *ap; int type; void *d; int c; { unsigned char *p = str_data + 4; unsigned char *cd = (unsigned char *)d; if (c == -1) c = strlen((char *)cd); if (auth_debug_mode) { printf("%s:%d: [%d] (%d)", str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY", str_data[3], type, c); printd(d, c); printf("\r\n"); } *p++ = ap->type; *p++ = ap->way; *p++ = type; while (c-- > 0) { if ((*p++ = *cd++) == IAC) *p++ = IAC; } *p++ = IAC; *p++ = SE; if (str_data[3] == TELQUAL_IS) printsub('>', &str_data[2], p - (&str_data[2])); return(net_write(str_data, p - str_data)); } int kerberos4_init(ap, server) Authenticator *ap; int server; { FILE *fp; if (server) { str_data[3] = TELQUAL_REPLY; if ((fp = fopen(KEYFILE, "r")) == NULL) return(0); fclose(fp); } else { str_data[3] = TELQUAL_IS; } return(1); } char dst_realm_buf[REALM_SZ], *dest_realm = NULL; int dst_realm_sz = REALM_SZ; int kerberos4_send(ap) Authenticator *ap; { KTEXT_ST auth; -#ifdef ENCRYPTION - Block enckey; -#endif /* ENCRYPTION */ char instance[INST_SZ]; char *realm; char *krb_realmofhost(); char *krb_get_phost(); CREDENTIALS cred; int r; printf("[ Trying KERBEROS4 ... ]\n"); if (!UserNameRequested) { if (auth_debug_mode) { printf("Kerberos V4: no user name supplied\r\n"); } return(0); } memset(instance, 0, sizeof(instance)); - if (realm = krb_get_phost(RemoteHostName)) + if ((realm = krb_get_phost(RemoteHostName))) strncpy(instance, realm, sizeof(instance)); instance[sizeof(instance)-1] = '\0'; realm = dest_realm ? dest_realm : krb_realmofhost(RemoteHostName); if (!realm) { printf("Kerberos V4: no realm for %s\r\n", RemoteHostName); return(0); } - if (r = krb_mk_req(&auth, KRB_SERVICE_NAME, instance, realm, 0L)) { + if ((r = krb_mk_req(&auth, KRB_SERVICE_NAME, instance, realm, 0L))) { printf("mk_req failed: %s\r\n", krb_err_txt[r]); return(0); } - if (r = krb_get_cred(KRB_SERVICE_NAME, instance, realm, &cred)) { + if ((r = krb_get_cred(KRB_SERVICE_NAME, instance, realm, &cred))) { printf("get_cred failed: %s\r\n", krb_err_txt[r]); return(0); } if (!auth_sendname(UserNameRequested, strlen(UserNameRequested))) { if (auth_debug_mode) printf("Not enough room for user name\r\n"); return(0); } if (auth_debug_mode) printf("Sent %d bytes of authentication data\r\n", auth.length); if (!Data(ap, KRB_AUTH, (void *)auth.dat, auth.length)) { if (auth_debug_mode) printf("Not enough room for authentication data\r\n"); return(0); } #ifdef ENCRYPTION /* * If we are doing mutual authentication, get set up to send * the challenge, and verify it when the response comes back. */ if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { register int i; - des_key_sched(cred.session, sched); - des_init_random_number_generator(cred.session); - des_new_random_key(session_key); - des_ecb_encrypt(session_key, session_key, sched, 0); - des_ecb_encrypt(session_key, challenge, sched, 0); + des_key_sched(&cred.session, sched); + des_init_random_number_generator(&cred.session); + des_new_random_key(&session_key); + des_ecb_encrypt(&session_key, &session_key, sched, 0); + des_ecb_encrypt(&session_key, &challenge, sched, 0); /* * Increment the challenge by 1, and encrypt it for * later comparison. */ for (i = 7; i >= 0; --i) { register int x; x = (unsigned int)challenge[i] + 1; challenge[i] = x; /* ignore overflow */ if (x < 256) /* if no overflow, all done */ break; } - des_ecb_encrypt(challenge, challenge, sched, 1); + des_ecb_encrypt(&challenge, &challenge, sched, 1); } #endif /* ENCRYPTION */ if (auth_debug_mode) { printf("CK: %d:", kerberos4_cksum(auth.dat, auth.length)); printd(auth.dat, auth.length); printf("\r\n"); printf("Sent Kerberos V4 credentials to server\r\n"); } return(1); } void kerberos4_is(ap, data, cnt) Authenticator *ap; unsigned char *data; int cnt; { #ifdef ENCRYPTION Session_Key skey; Block datablock; #endif /* ENCRYPTION */ char realm[REALM_SZ]; char instance[INST_SZ]; int r; if (cnt-- < 1) return; switch (*data++) { case KRB_AUTH: if (krb_get_lrealm(realm, 1) != KSUCCESS) { Data(ap, KRB_REJECT, (void *)"No local V4 Realm.", -1); auth_finished(ap, AUTH_REJECT); if (auth_debug_mode) printf("No local realm\r\n"); return; } memmove((void *)auth.dat, (void *)data, auth.length = cnt); if (auth_debug_mode) { printf("Got %d bytes of authentication data\r\n", cnt); printf("CK: %d:", kerberos4_cksum(auth.dat, auth.length)); printd(auth.dat, auth.length); printf("\r\n"); } instance[0] = '*'; instance[1] = 0; - if (r = krb_rd_req(&auth, KRB_SERVICE_NAME, - instance, 0, &adat, "")) { + if ((r = krb_rd_req(&auth, KRB_SERVICE_NAME, + instance, 0, &adat, ""))) { if (auth_debug_mode) printf("Kerberos failed him as %s\r\n", name); Data(ap, KRB_REJECT, (void *)krb_err_txt[r], -1); auth_finished(ap, AUTH_REJECT); return; } #ifdef ENCRYPTION memmove((void *)session_key, (void *)adat.session, sizeof(Block)); #endif /* ENCRYPTION */ krb_kntoln(&adat, name); if (UserNameRequested && !kuserok(&adat, UserNameRequested)) Data(ap, KRB_ACCEPT, (void *)0, 0); else Data(ap, KRB_REJECT, (void *)"user is not authorized", -1); auth_finished(ap, AUTH_USER); break; case KRB_CHALLENGE: #ifndef ENCRYPTION Data(ap, KRB_RESPONSE, (void *)0, 0); #else /* ENCRYPTION */ if (!VALIDKEY(session_key)) { /* * We don't have a valid session key, so just * send back a response with an empty session * key. */ Data(ap, KRB_RESPONSE, (void *)0, 0); break; } /* * Initialize the random number generator since it's * used later on by the encryption routine. */ - des_init_random_number_generator(session_key); - des_key_sched(session_key, sched); + des_init_random_number_generator(&session_key); + des_key_sched(&session_key, sched); memmove((void *)datablock, (void *)data, sizeof(Block)); /* * Take the received encrypted challenge, and encrypt * it again to get a unique session_key for the * ENCRYPT option. */ - des_ecb_encrypt(datablock, session_key, sched, 1); + des_ecb_encrypt(&datablock, &session_key, sched, 1); skey.type = SK_DES; skey.length = 8; skey.data = session_key; encrypt_session_key(&skey, 1); /* * Now decrypt the received encrypted challenge, * increment by one, re-encrypt it and send it back. */ - des_ecb_encrypt(datablock, challenge, sched, 0); + des_ecb_encrypt(&datablock, &challenge, sched, 0); for (r = 7; r >= 0; r--) { register int t; t = (unsigned int)challenge[r] + 1; challenge[r] = t; /* ignore overflow */ if (t < 256) /* if no overflow, all done */ break; } - des_ecb_encrypt(challenge, challenge, sched, 1); + des_ecb_encrypt(&challenge, &challenge, sched, 1); Data(ap, KRB_RESPONSE, (void *)challenge, sizeof(challenge)); #endif /* ENCRYPTION */ break; default: if (auth_debug_mode) printf("Unknown Kerberos option %d\r\n", data[-1]); Data(ap, KRB_REJECT, 0, 0); break; } } void kerberos4_reply(ap, data, cnt) Authenticator *ap; unsigned char *data; int cnt; { #ifdef ENCRYPTION Session_Key skey; #endif /* ENCRYPTION */ if (cnt-- < 1) return; switch (*data++) { case KRB_REJECT: if (cnt > 0) { printf("[ Kerberos V4 refuses authentication because %.*s ]\r\n", cnt, data); } else printf("[ Kerberos V4 refuses authentication ]\r\n"); auth_send_retry(); return; case KRB_ACCEPT: printf("[ Kerberos V4 accepts you ]\n"); if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { /* * Send over the encrypted challenge. */ #ifndef ENCRYPTION Data(ap, KRB_CHALLENGE, (void *)0, 0); #else /* ENCRYPTION */ Data(ap, KRB_CHALLENGE, (void *)session_key, sizeof(session_key)); - des_ecb_encrypt(session_key, session_key, sched, 1); + des_ecb_encrypt(&session_key, &session_key, sched, 1); skey.type = SK_DES; skey.length = 8; skey.data = session_key; encrypt_session_key(&skey, 0); #endif /* ENCRYPTION */ return; } auth_finished(ap, AUTH_USER); return; case KRB_RESPONSE: #ifdef ENCRYPTION /* * Verify that the response to the challenge is correct. */ if ((cnt != sizeof(Block)) || (0 != memcmp((void *)data, (void *)challenge, sizeof(challenge)))) { #endif /* ENCRYPTION */ printf("[ Kerberos V4 challenge failed!!! ]\r\n"); auth_send_retry(); return; #ifdef ENCRYPTION } printf("[ Kerberos V4 challenge successful ]\r\n"); auth_finished(ap, AUTH_USER); #endif /* ENCRYPTION */ break; default: if (auth_debug_mode) printf("Unknown Kerberos option %d\r\n", data[-1]); return; } } int kerberos4_status(ap, name, level) Authenticator *ap; char *name; int level; { if (level < AUTH_USER) return(level); if (UserNameRequested && !kuserok(&adat, UserNameRequested)) { strcpy(name, UserNameRequested); return(AUTH_VALID); } else return(AUTH_USER); } #define BUMP(buf, len) while (*(buf)) {++(buf), --(len);} #define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len);} void kerberos4_printsub(data, cnt, buf, buflen) unsigned char *data, *buf; int cnt, buflen; { char lbuf[32]; register int i; buf[buflen-1] = '\0'; /* make sure its NULL terminated */ buflen -= 1; switch(data[3]) { case KRB_REJECT: /* Rejected (reason might follow) */ strncpy((char *)buf, " REJECT ", buflen); goto common; case KRB_ACCEPT: /* Accepted (name might follow) */ strncpy((char *)buf, " ACCEPT ", buflen); common: BUMP(buf, buflen); if (cnt <= 4) break; ADDC(buf, buflen, '"'); for (i = 4; i < cnt; i++) ADDC(buf, buflen, data[i]); ADDC(buf, buflen, '"'); ADDC(buf, buflen, '\0'); break; case KRB_AUTH: /* Authentication data follows */ strncpy((char *)buf, " AUTH", buflen); goto common2; case KRB_CHALLENGE: strncpy((char *)buf, " CHALLENGE", buflen); goto common2; case KRB_RESPONSE: strncpy((char *)buf, " RESPONSE", buflen); goto common2; default: sprintf(lbuf, " %d (unknown)", data[3]); strncpy((char *)buf, lbuf, buflen); common2: BUMP(buf, buflen); for (i = 4; i < cnt; i++) { sprintf(lbuf, " %d", data[i]); strncpy((char *)buf, lbuf, buflen); BUMP(buf, buflen); } break; } } int kerberos4_cksum(d, n) unsigned char *d; int n; { int ck = 0; /* * A comment is probably needed here for those not * well versed in the "C" language. Yes, this is * supposed to be a "switch" with the body of the * "switch" being a "while" statement. The whole * purpose of the switch is to allow us to jump into * the middle of the while() loop, and then not have * to do any more switch()s. * * Some compilers will spit out a warning message * about the loop not being entered at the top. */ switch (n&03) while (n > 0) { case 0: ck ^= (int)*d++ << 24; --n; case 3: ck ^= (int)*d++ << 16; --n; case 2: ck ^= (int)*d++ << 8; --n; case 1: ck ^= (int)*d++; --n; } return(ck); } #endif #ifdef notdef prkey(msg, key) char *msg; unsigned char *key; { register int i; printf("%s:", msg); for (i = 0; i < 8; i++) printf(" %3d", key[i]); printf("\r\n"); } #endif diff --git a/crypto/telnet/libtelnet/krb4encpwd.c b/crypto/telnet/libtelnet/krb4encpwd.c index 6148190dd4f5..cb9523c99205 100644 --- a/crypto/telnet/libtelnet/krb4encpwd.c +++ b/crypto/telnet/libtelnet/krb4encpwd.c @@ -1,446 +1,445 @@ /*- * Copyright (c) 1992, 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. */ #ifndef lint static char sccsid[] = "@(#)krb4encpwd.c 8.3 (Berkeley) 5/30/95"; #endif /* not lint */ #ifdef KRB4_ENCPWD /* * COPYRIGHT (C) 1990 DIGITAL EQUIPMENT CORPORATION * ALL RIGHTS RESERVED * * "Digital Equipment Corporation authorizes the reproduction, * distribution and modification of this software subject to the following * restrictions: * * 1. Any partial or whole copy of this software, or any modification * thereof, must include this copyright notice in its entirety. * * 2. This software is supplied "as is" with no warranty of any kind, * expressed or implied, for any purpose, including any warranty of fitness * or merchantibility. DIGITAL assumes no responsibility for the use or * reliability of this software, nor promises to provide any form of * support for it on any basis. * * 3. Distribution of this software is authorized only if no profit or * remuneration of any kind is received in exchange for such distribution. * * 4. This software produces public key authentication certificates * bearing an expiration date established by DIGITAL and RSA Data * Security, Inc. It may cease to generate certificates after the expiration * date. Any modification of this software that changes or defeats * the expiration date or its effect is unauthorized. * * 5. Software that will renew or extend the expiration date of * authentication certificates produced by this software may be obtained * from RSA Data Security, Inc., 10 Twin Dolphin Drive, Redwood City, CA * 94065, (415)595-8782, or from DIGITAL" * */ #include #include #include #include #include #include #ifdef __STDC__ #include #endif #ifdef NO_STRING_H #include #else #include #endif #include "encrypt.h" #include "auth.h" #include "misc.h" int krb_mk_encpwd_req P((KTEXT, char *, char *, char *, char *, char *, char *)); int krb_rd_encpwd_req P((KTEXT, char *, char *, u_long, AUTH_DAT *, char *, char *, char *, char *)); extern auth_debug_mode; static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0, AUTHTYPE_KRB4_ENCPWD, }; static unsigned char str_name[1024] = { IAC, SB, TELOPT_AUTHENTICATION, TELQUAL_NAME, }; #define KRB4_ENCPWD_AUTH 0 /* Authentication data follows */ #define KRB4_ENCPWD_REJECT 1 /* Rejected (reason might follow) */ #define KRB4_ENCPWD_ACCEPT 2 /* Accepted */ #define KRB4_ENCPWD_CHALLENGE 3 /* Challenge for mutual auth. */ #define KRB4_ENCPWD_ACK 4 /* Acknowledge */ #define KRB_SERVICE_NAME "rcmd" static KTEXT_ST auth; static char name[ANAME_SZ]; static char user_passwd[ANAME_SZ]; static AUTH_DAT adat = { 0 }; #ifdef ENCRYPTION static Block session_key = { 0 }; #endif /* ENCRYPTION */ -static Schedule sched; static char challenge[REALM_SZ]; static int Data(ap, type, d, c) Authenticator *ap; int type; void *d; int c; { unsigned char *p = str_data + 4; unsigned char *cd = (unsigned char *)d; if (c == -1) c = strlen((char *)cd); if (0) { printf("%s:%d: [%d] (%d)", str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY", str_data[3], type, c); printd(d, c); printf("\r\n"); } *p++ = ap->type; *p++ = ap->way; *p++ = type; while (c-- > 0) { if ((*p++ = *cd++) == IAC) *p++ = IAC; } *p++ = IAC; *p++ = SE; if (str_data[3] == TELQUAL_IS) printsub('>', &str_data[2], p - (&str_data[2])); return(net_write(str_data, p - str_data)); } int krb4encpwd_init(ap, server) Authenticator *ap; int server; { char hostname[80], *cp, *realm; C_Block skey; if (server) { str_data[3] = TELQUAL_REPLY; } else { str_data[3] = TELQUAL_IS; gethostname(hostname, sizeof(hostname)); realm = krb_realmofhost(hostname); cp = strchr(hostname, '.'); if (*cp != NULL) *cp = NULL; if (read_service_key(KRB_SERVICE_NAME, hostname, realm, 0, KEYFILE, (char *)skey)) { return(0); } } return(1); } int krb4encpwd_send(ap) Authenticator *ap; { printf("[ Trying KRB4ENCPWD ... ]\n"); if (!UserNameRequested) { return(0); } if (!auth_sendname(UserNameRequested, strlen(UserNameRequested))) { return(0); } if (!Data(ap, KRB4_ENCPWD_ACK, (void *)NULL, 0)) { return(0); } return(1); } void krb4encpwd_is(ap, data, cnt) Authenticator *ap; unsigned char *data; int cnt; { Session_Key skey; Block datablock; char r_passwd[ANAME_SZ], r_user[ANAME_SZ]; char lhostname[ANAME_SZ], *cp; int r; time_t now; if (cnt-- < 1) return; switch (*data++) { case KRB4_ENCPWD_AUTH: memmove((void *)auth.dat, (void *)data, auth.length = cnt); gethostname(lhostname, sizeof(lhostname)); if ((cp = strchr(lhostname, '.')) != 0) *cp = '\0'; if (r = krb_rd_encpwd_req(&auth, KRB_SERVICE_NAME, lhostname, 0, &adat, NULL, challenge, r_user, r_passwd)) { Data(ap, KRB4_ENCPWD_REJECT, (void *)"Auth failed", -1); auth_finished(ap, AUTH_REJECT); return; } auth_encrypt_userpwd(r_passwd); if (passwdok(UserNameRequested, UserPassword) == 0) { /* * illegal username and password */ Data(ap, KRB4_ENCPWD_REJECT, (void *)"Illegal password", -1); auth_finished(ap, AUTH_REJECT); return; } memmove((void *)session_key, (void *)adat.session, sizeof(Block)); Data(ap, KRB4_ENCPWD_ACCEPT, (void *)0, 0); auth_finished(ap, AUTH_USER); break; case KRB4_ENCPWD_CHALLENGE: /* * Take the received random challenge text and save * for future authentication. */ memmove((void *)challenge, (void *)data, sizeof(Block)); break; case KRB4_ENCPWD_ACK: /* * Receive ack, if mutual then send random challenge */ /* * If we are doing mutual authentication, get set up to send * the challenge, and verify it when the response comes back. */ if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { register int i; time(&now); sprintf(challenge, "%x", now); Data(ap, KRB4_ENCPWD_CHALLENGE, (void *)challenge, strlen(challenge)); } break; default: Data(ap, KRB4_ENCPWD_REJECT, 0, 0); break; } } void krb4encpwd_reply(ap, data, cnt) Authenticator *ap; unsigned char *data; int cnt; { Session_Key skey; KTEXT_ST krb_token; Block enckey; CREDENTIALS cred; int r; char randchal[REALM_SZ], instance[ANAME_SZ], *cp; char hostname[80], *realm; if (cnt-- < 1) return; switch (*data++) { case KRB4_ENCPWD_REJECT: if (cnt > 0) { printf("[ KRB4_ENCPWD refuses authentication because %.*s ]\r\n", cnt, data); } else printf("[ KRB4_ENCPWD refuses authentication ]\r\n"); auth_send_retry(); return; case KRB4_ENCPWD_ACCEPT: printf("[ KRB4_ENCPWD accepts you ]\n"); auth_finished(ap, AUTH_USER); return; case KRB4_ENCPWD_CHALLENGE: /* * Verify that the response to the challenge is correct. */ gethostname(hostname, sizeof(hostname)); realm = krb_realmofhost(hostname); memmove((void *)challenge, (void *)data, cnt); memset(user_passwd, 0, sizeof(user_passwd)); local_des_read_pw_string(user_passwd, sizeof(user_passwd)-1, "Password: ", 0); UserPassword = user_passwd; Challenge = challenge; strcpy(instance, RemoteHostName); if ((cp = strchr(instance, '.')) != 0) *cp = '\0'; if (r = krb_mk_encpwd_req(&krb_token, KRB_SERVICE_NAME, instance, realm, Challenge, UserNameRequested, user_passwd)) { krb_token.length = 0; } if (!Data(ap, KRB4_ENCPWD_AUTH, (void *)krb_token.dat, krb_token.length)) { return; } break; default: return; } } int krb4encpwd_status(ap, name, level) Authenticator *ap; char *name; int level; { if (level < AUTH_USER) return(level); if (UserNameRequested && passwdok(UserNameRequested, UserPassword)) { strcpy(name, UserNameRequested); return(AUTH_VALID); } else { return(AUTH_USER); } } #define BUMP(buf, len) while (*(buf)) {++(buf), --(len);} #define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len);} void krb4encpwd_printsub(data, cnt, buf, buflen) unsigned char *data, *buf; int cnt, buflen; { char lbuf[32]; register int i; buf[buflen-1] = '\0'; /* make sure its NULL terminated */ buflen -= 1; switch(data[3]) { case KRB4_ENCPWD_REJECT: /* Rejected (reason might follow) */ strncpy((char *)buf, " REJECT ", buflen); goto common; case KRB4_ENCPWD_ACCEPT: /* Accepted (name might follow) */ strncpy((char *)buf, " ACCEPT ", buflen); common: BUMP(buf, buflen); if (cnt <= 4) break; ADDC(buf, buflen, '"'); for (i = 4; i < cnt; i++) ADDC(buf, buflen, data[i]); ADDC(buf, buflen, '"'); ADDC(buf, buflen, '\0'); break; case KRB4_ENCPWD_AUTH: /* Authentication data follows */ strncpy((char *)buf, " AUTH", buflen); goto common2; case KRB4_ENCPWD_CHALLENGE: strncpy((char *)buf, " CHALLENGE", buflen); goto common2; case KRB4_ENCPWD_ACK: strncpy((char *)buf, " ACK", buflen); goto common2; default: sprintf(lbuf, " %d (unknown)", data[3]); strncpy((char *)buf, lbuf, buflen); common2: BUMP(buf, buflen); for (i = 4; i < cnt; i++) { sprintf(lbuf, " %d", data[i]); strncpy((char *)buf, lbuf, buflen); BUMP(buf, buflen); } break; } } int passwdok(name, passwd) char *name, *passwd; { char *crypt(); char *salt, *p; struct passwd *pwd; int passwdok_status = 0; if (pwd = getpwnam(name)) salt = pwd->pw_passwd; else salt = "xx"; p = crypt(passwd, salt); if (pwd && !strcmp(p, pwd->pw_passwd)) { passwdok_status = 1; } else passwdok_status = 0; return(passwdok_status); } #endif #ifdef notdef prkey(msg, key) char *msg; unsigned char *key; { register int i; printf("%s:", msg); for (i = 0; i < 8; i++) printf(" %3d", key[i]); printf("\r\n"); } #endif diff --git a/crypto/telnet/libtelnet/misc.c b/crypto/telnet/libtelnet/misc.c index 9565900a391e..4f8f8d53644b 100644 --- a/crypto/telnet/libtelnet/misc.c +++ b/crypto/telnet/libtelnet/misc.c @@ -1,94 +1,98 @@ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. */ #ifndef lint -static char sccsid[] = "@(#)misc.c 8.1 (Berkeley) 6/4/93"; +static const char sccsid[] = "@(#)misc.c 8.1 (Berkeley) 6/4/93"; #endif /* not lint */ +#include +#include #include "misc.h" +#include "auth.h" +#include "encrypt.h" char *RemoteHostName; char *LocalHostName; char *UserNameRequested = 0; int ConnectedCount = 0; void auth_encrypt_init(local, remote, name, server) char *local; char *remote; char *name; int server; { RemoteHostName = remote; LocalHostName = local; #if defined(AUTHENTICATION) auth_init(name, server); #endif #ifdef ENCRYPTION encrypt_init(name, server); #endif /* ENCRYPTION */ if (UserNameRequested) { free(UserNameRequested); UserNameRequested = 0; } } void auth_encrypt_user(name) char *name; { extern char *strdup(); if (UserNameRequested) free(UserNameRequested); UserNameRequested = name ? strdup(name) : 0; } void auth_encrypt_connect(cnt) int cnt; { } void printd(data, cnt) unsigned char *data; int cnt; { if (cnt > 16) cnt = 16; while (cnt-- > 0) { printf(" %02x", *data); ++data; } } diff --git a/crypto/telnet/libtelnet/spx.c b/crypto/telnet/libtelnet/spx.c index 86c619787c9b..90c37a47ebd6 100644 --- a/crypto/telnet/libtelnet/spx.c +++ b/crypto/telnet/libtelnet/spx.c @@ -1,588 +1,587 @@ /*- * Copyright (c) 1992, 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. */ #ifndef lint static char sccsid[] = "@(#)spx.c 8.2 (Berkeley) 5/30/95"; #endif /* not lint */ #ifdef SPX /* * COPYRIGHT (C) 1990 DIGITAL EQUIPMENT CORPORATION * ALL RIGHTS RESERVED * * "Digital Equipment Corporation authorizes the reproduction, * distribution and modification of this software subject to the following * restrictions: * * 1. Any partial or whole copy of this software, or any modification * thereof, must include this copyright notice in its entirety. * * 2. This software is supplied "as is" with no warranty of any kind, * expressed or implied, for any purpose, including any warranty of fitness * or merchantibility. DIGITAL assumes no responsibility for the use or * reliability of this software, nor promises to provide any form of * support for it on any basis. * * 3. Distribution of this software is authorized only if no profit or * remuneration of any kind is received in exchange for such distribution. * * 4. This software produces public key authentication certificates * bearing an expiration date established by DIGITAL and RSA Data * Security, Inc. It may cease to generate certificates after the expiration * date. Any modification of this software that changes or defeats * the expiration date or its effect is unauthorized. * * 5. Software that will renew or extend the expiration date of * authentication certificates produced by this software may be obtained * from RSA Data Security, Inc., 10 Twin Dolphin Drive, Redwood City, CA * 94065, (415)595-8782, or from DIGITAL" * */ #include #include #include #include "gssapi_defs.h" #ifdef __STDC__ #include #endif #ifdef NO_STRING_H #include #else #include #endif #include #include "encrypt.h" #include "auth.h" #include "misc.h" extern auth_debug_mode; static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0, AUTHTYPE_SPX, }; static unsigned char str_name[1024] = { IAC, SB, TELOPT_AUTHENTICATION, TELQUAL_NAME, }; #define SPX_AUTH 0 /* Authentication data follows */ #define SPX_REJECT 1 /* Rejected (reason might follow) */ #define SPX_ACCEPT 2 /* Accepted */ #ifdef ENCRYPTION static Block session_key = { 0 }; #endif /* ENCRYPTION */ -static Schedule sched; static Block challenge = { 0 }; /*******************************************************************/ gss_OID_set actual_mechs; gss_OID actual_mech_type, output_name_type; int major_status, status, msg_ctx = 0, new_status; int req_flags = 0, ret_flags, lifetime_rec; gss_cred_id_t gss_cred_handle; gss_ctx_id_t actual_ctxhandle, context_handle; gss_buffer_desc output_token, input_token, input_name_buffer; gss_buffer_desc status_string; gss_name_t desired_targname, src_name; gss_channel_bindings input_chan_bindings; char lhostname[GSS_C_MAX_PRINTABLE_NAME]; char targ_printable[GSS_C_MAX_PRINTABLE_NAME]; int to_addr=0, from_addr=0; char *address; gss_buffer_desc fullname_buffer; gss_OID fullname_type; gss_cred_id_t gss_delegated_cred_handle; /*******************************************************************/ static int Data(ap, type, d, c) Authenticator *ap; int type; void *d; int c; { unsigned char *p = str_data + 4; unsigned char *cd = (unsigned char *)d; if (c == -1) c = strlen((char *)cd); if (0) { printf("%s:%d: [%d] (%d)", str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY", str_data[3], type, c); printd(d, c); printf("\r\n"); } *p++ = ap->type; *p++ = ap->way; *p++ = type; while (c-- > 0) { if ((*p++ = *cd++) == IAC) *p++ = IAC; } *p++ = IAC; *p++ = SE; if (str_data[3] == TELQUAL_IS) printsub('>', &str_data[2], p - (&str_data[2])); return(net_write(str_data, p - str_data)); } int spx_init(ap, server) Authenticator *ap; int server; { gss_cred_id_t tmp_cred_handle; if (server) { str_data[3] = TELQUAL_REPLY; gethostname(lhostname, sizeof(lhostname)); strcpy(targ_printable, "SERVICE:rcmd@"); strcat(targ_printable, lhostname); input_name_buffer.length = strlen(targ_printable); input_name_buffer.value = targ_printable; major_status = gss_import_name(&status, &input_name_buffer, GSS_C_NULL_OID, &desired_targname); major_status = gss_acquire_cred(&status, desired_targname, 0, GSS_C_NULL_OID_SET, GSS_C_ACCEPT, &tmp_cred_handle, &actual_mechs, &lifetime_rec); if (major_status != GSS_S_COMPLETE) return(0); } else { str_data[3] = TELQUAL_IS; } return(1); } int spx_send(ap) Authenticator *ap; { Block enckey; int r; gss_OID actual_mech_type, output_name_type; int msg_ctx = 0, new_status, status; int req_flags = 0, ret_flags, lifetime_rec, major_status; gss_buffer_desc output_token, input_token, input_name_buffer; gss_buffer_desc output_name_buffer, status_string; gss_name_t desired_targname; gss_channel_bindings input_chan_bindings; char targ_printable[GSS_C_MAX_PRINTABLE_NAME]; int from_addr=0, to_addr=0, myhostlen, j; int deleg_flag=1, mutual_flag=0, replay_flag=0, seq_flag=0; char *address; printf("[ Trying SPX ... ]\n"); strcpy(targ_printable, "SERVICE:rcmd@"); strcat(targ_printable, RemoteHostName); input_name_buffer.length = strlen(targ_printable); input_name_buffer.value = targ_printable; if (!UserNameRequested) { return(0); } major_status = gss_import_name(&status, &input_name_buffer, GSS_C_NULL_OID, &desired_targname); major_status = gss_display_name(&status, desired_targname, &output_name_buffer, &output_name_type); printf("target is '%s'\n", output_name_buffer.value); fflush(stdout); major_status = gss_release_buffer(&status, &output_name_buffer); input_chan_bindings = (gss_channel_bindings) malloc(sizeof(gss_channel_bindings_desc)); input_chan_bindings->initiator_addrtype = GSS_C_AF_INET; input_chan_bindings->initiator_address.length = 4; address = (char *) malloc(4); input_chan_bindings->initiator_address.value = (char *) address; address[0] = ((from_addr & 0xff000000) >> 24); address[1] = ((from_addr & 0xff0000) >> 16); address[2] = ((from_addr & 0xff00) >> 8); address[3] = (from_addr & 0xff); input_chan_bindings->acceptor_addrtype = GSS_C_AF_INET; input_chan_bindings->acceptor_address.length = 4; address = (char *) malloc(4); input_chan_bindings->acceptor_address.value = (char *) address; address[0] = ((to_addr & 0xff000000) >> 24); address[1] = ((to_addr & 0xff0000) >> 16); address[2] = ((to_addr & 0xff00) >> 8); address[3] = (to_addr & 0xff); input_chan_bindings->application_data.length = 0; req_flags = 0; if (deleg_flag) req_flags = req_flags | 1; if (mutual_flag) req_flags = req_flags | 2; if (replay_flag) req_flags = req_flags | 4; if (seq_flag) req_flags = req_flags | 8; major_status = gss_init_sec_context(&status, /* minor status */ GSS_C_NO_CREDENTIAL, /* cred handle */ &actual_ctxhandle, /* ctx handle */ desired_targname, /* target name */ GSS_C_NULL_OID, /* mech type */ req_flags, /* req flags */ 0, /* time req */ input_chan_bindings, /* chan binding */ GSS_C_NO_BUFFER, /* input token */ &actual_mech_type, /* actual mech */ &output_token, /* output token */ &ret_flags, /* ret flags */ &lifetime_rec); /* time rec */ if ((major_status != GSS_S_COMPLETE) && (major_status != GSS_S_CONTINUE_NEEDED)) { gss_display_status(&new_status, status, GSS_C_MECH_CODE, GSS_C_NULL_OID, &msg_ctx, &status_string); printf("%s\n", status_string.value); return(0); } if (!auth_sendname(UserNameRequested, strlen(UserNameRequested))) { return(0); } if (!Data(ap, SPX_AUTH, (void *)output_token.value, output_token.length)) { return(0); } return(1); } void spx_is(ap, data, cnt) Authenticator *ap; unsigned char *data; int cnt; { Session_Key skey; Block datablock; int r; if (cnt-- < 1) return; switch (*data++) { case SPX_AUTH: input_token.length = cnt; input_token.value = (char *) data; gethostname(lhostname, sizeof(lhostname)); strcpy(targ_printable, "SERVICE:rcmd@"); strcat(targ_printable, lhostname); input_name_buffer.length = strlen(targ_printable); input_name_buffer.value = targ_printable; major_status = gss_import_name(&status, &input_name_buffer, GSS_C_NULL_OID, &desired_targname); major_status = gss_acquire_cred(&status, desired_targname, 0, GSS_C_NULL_OID_SET, GSS_C_ACCEPT, &gss_cred_handle, &actual_mechs, &lifetime_rec); major_status = gss_release_name(&status, desired_targname); input_chan_bindings = (gss_channel_bindings) malloc(sizeof(gss_channel_bindings_desc)); input_chan_bindings->initiator_addrtype = GSS_C_AF_INET; input_chan_bindings->initiator_address.length = 4; address = (char *) malloc(4); input_chan_bindings->initiator_address.value = (char *) address; address[0] = ((from_addr & 0xff000000) >> 24); address[1] = ((from_addr & 0xff0000) >> 16); address[2] = ((from_addr & 0xff00) >> 8); address[3] = (from_addr & 0xff); input_chan_bindings->acceptor_addrtype = GSS_C_AF_INET; input_chan_bindings->acceptor_address.length = 4; address = (char *) malloc(4); input_chan_bindings->acceptor_address.value = (char *) address; address[0] = ((to_addr & 0xff000000) >> 24); address[1] = ((to_addr & 0xff0000) >> 16); address[2] = ((to_addr & 0xff00) >> 8); address[3] = (to_addr & 0xff); input_chan_bindings->application_data.length = 0; major_status = gss_accept_sec_context(&status, &context_handle, gss_cred_handle, &input_token, input_chan_bindings, &src_name, &actual_mech_type, &output_token, &ret_flags, &lifetime_rec, &gss_delegated_cred_handle); if (major_status != GSS_S_COMPLETE) { major_status = gss_display_name(&status, src_name, &fullname_buffer, &fullname_type); Data(ap, SPX_REJECT, (void *)"auth failed", -1); auth_finished(ap, AUTH_REJECT); return; } major_status = gss_display_name(&status, src_name, &fullname_buffer, &fullname_type); Data(ap, SPX_ACCEPT, (void *)output_token.value, output_token.length); auth_finished(ap, AUTH_USER); break; default: Data(ap, SPX_REJECT, 0, 0); break; } } void spx_reply(ap, data, cnt) Authenticator *ap; unsigned char *data; int cnt; { Session_Key skey; if (cnt-- < 1) return; switch (*data++) { case SPX_REJECT: if (cnt > 0) { printf("[ SPX refuses authentication because %.*s ]\r\n", cnt, data); } else printf("[ SPX refuses authentication ]\r\n"); auth_send_retry(); return; case SPX_ACCEPT: printf("[ SPX accepts you ]\n"); if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { /* * Send over the encrypted challenge. */ input_token.value = (char *) data; input_token.length = cnt; major_status = gss_init_sec_context(&status, /* minor stat */ GSS_C_NO_CREDENTIAL, /* cred handle */ &actual_ctxhandle, /* ctx handle */ desired_targname, /* target name */ GSS_C_NULL_OID, /* mech type */ req_flags, /* req flags */ 0, /* time req */ input_chan_bindings, /* chan binding */ &input_token, /* input token */ &actual_mech_type, /* actual mech */ &output_token, /* output token */ &ret_flags, /* ret flags */ &lifetime_rec); /* time rec */ if (major_status != GSS_S_COMPLETE) { gss_display_status(&new_status, status, GSS_C_MECH_CODE, GSS_C_NULL_OID, &msg_ctx, &status_string); printf("[ SPX mutual response fails ... '%s' ]\r\n", status_string.value); auth_send_retry(); return; } } auth_finished(ap, AUTH_USER); return; default: return; } } int spx_status(ap, name, level) Authenticator *ap; char *name; int level; { gss_buffer_desc fullname_buffer, acl_file_buffer; gss_OID fullname_type; char acl_file[160], fullname[160]; int major_status, status = 0; struct passwd *pwd; /* * hard code fullname to * "SPX:/C=US/O=Digital/OU=LKG/OU=Sphinx/OU=Users/CN=Kannan Alagappan" * and acl_file to "~kannan/.sphinx" */ pwd = getpwnam(UserNameRequested); if (pwd == NULL) { return(AUTH_USER); /* not authenticated */ } strcpy(acl_file, pwd->pw_dir); strcat(acl_file, "/.sphinx"); acl_file_buffer.value = acl_file; acl_file_buffer.length = strlen(acl_file); major_status = gss_display_name(&status, src_name, &fullname_buffer, &fullname_type); if (level < AUTH_USER) return(level); major_status = gss__check_acl(&status, &fullname_buffer, &acl_file_buffer); if (major_status == GSS_S_COMPLETE) { strcpy(name, UserNameRequested); return(AUTH_VALID); } else { return(AUTH_USER); } } #define BUMP(buf, len) while (*(buf)) {++(buf), --(len);} #define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len);} void spx_printsub(data, cnt, buf, buflen) unsigned char *data, *buf; int cnt, buflen; { char lbuf[32]; register int i; buf[buflen-1] = '\0'; /* make sure its NULL terminated */ buflen -= 1; switch(data[3]) { case SPX_REJECT: /* Rejected (reason might follow) */ strncpy((char *)buf, " REJECT ", buflen); goto common; case SPX_ACCEPT: /* Accepted (name might follow) */ strncpy((char *)buf, " ACCEPT ", buflen); common: BUMP(buf, buflen); if (cnt <= 4) break; ADDC(buf, buflen, '"'); for (i = 4; i < cnt; i++) ADDC(buf, buflen, data[i]); ADDC(buf, buflen, '"'); ADDC(buf, buflen, '\0'); break; case SPX_AUTH: /* Authentication data follows */ strncpy((char *)buf, " AUTH", buflen); goto common2; default: sprintf(lbuf, " %d (unknown)", data[3]); strncpy((char *)buf, lbuf, buflen); common2: BUMP(buf, buflen); for (i = 4; i < cnt; i++) { sprintf(lbuf, " %d", data[i]); strncpy((char *)buf, lbuf, buflen); BUMP(buf, buflen); } break; } } #endif #ifdef notdef prkey(msg, key) char *msg; unsigned char *key; { register int i; printf("%s:", msg); for (i = 0; i < 8; i++) printf(" %3d", key[i]); printf("\r\n"); } #endif diff --git a/crypto/telnet/telnet/authenc.c b/crypto/telnet/telnet/authenc.c index 545df780051d..f829b1a741a9 100644 --- a/crypto/telnet/telnet/authenc.c +++ b/crypto/telnet/telnet/authenc.c @@ -1,111 +1,111 @@ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. */ #ifndef lint -static char sccsid[] = "@(#)authenc.c 8.1 (Berkeley) 6/6/93"; +static const char sccsid[] = "@(#)authenc.c 8.1 (Berkeley) 6/6/93"; #endif /* not lint */ #if defined(AUTHENTICATION) || defined(ENCRYPTION) #include #include #include #include #include "general.h" #include "ring.h" #include "externs.h" #include "defines.h" #include "types.h" int net_write(str, len) unsigned char *str; int len; { if (NETROOM() > len) { ring_supply_data(&netoring, str, len); if (str[0] == IAC && str[1] == SE) printsub('>', &str[2], len-2); return(len); } return(0); } void net_encrypt() { #ifdef ENCRYPTION if (encrypt_output) ring_encrypt(&netoring, encrypt_output); else ring_clearto(&netoring); #endif /* ENCRYPTION */ } int telnet_spin() { return(-1); } char * telnet_getenv(val) char *val; { return((char *)env_getvalue((unsigned char *)val)); } char * telnet_gets(prompt, result, length, echo) char *prompt; char *result; int length; int echo; { extern char *getpass(); extern int globalmode; int om = globalmode; char *res; TerminalNewMode(-1); if (echo) { printf("%s", prompt); res = fgets(result, length, stdin); - } else if (res = getpass(prompt)) { + } else if ((res = getpass(prompt))) { strncpy(result, res, length); res = result; } TerminalNewMode(om); return(res); } #endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */ diff --git a/crypto/telnet/telnet/commands.c b/crypto/telnet/telnet/commands.c index 41ef5cdad438..8073fb50f120 100644 --- a/crypto/telnet/telnet/commands.c +++ b/crypto/telnet/telnet/commands.c @@ -1,2945 +1,3002 @@ /* * Copyright (c) 1988, 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. */ #ifndef lint -static char sccsid[] = "@(#)commands.c 8.4 (Berkeley) 5/30/95"; +static const char sccsid[] = "@(#)commands.c 8.4 (Berkeley) 5/30/95"; #endif /* not lint */ #if defined(unix) #include #if defined(CRAY) || defined(sysV88) #include #endif #include #else #include #endif /* defined(unix) */ #include #include #ifdef CRAY #include #endif /* CRAY */ #include #include #include #include #include #include +#include +#include #include #include "general.h" #include "ring.h" #include "externs.h" #include "defines.h" #include "types.h" +#if defined(AUTHENTICATION) +#include +#endif +#if defined(ENCRYPTION) +#include +#endif + #if !defined(CRAY) && !defined(sysV88) #include # if (defined(vax) || defined(tahoe) || defined(hp300)) && !defined(ultrix) # include # endif /* vax */ #endif /* !defined(CRAY) && !defined(sysV88) */ #include #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 64 #endif MAXHOSTNAMELEN #if defined(IPPROTO_IP) && defined(IP_TOS) int tos = -1; #endif /* defined(IPPROTO_IP) && defined(IP_TOS) */ char *hostname; static char _hostname[MAXHOSTNAMELEN]; extern char *getenv(); extern int isprefix(); extern char **genget(); extern int Ambiguous(); -static call(); +static int help(int argc, char *argv[]); +static int call(); +static void cmdrc(char *m1, char *m2); + +int quit(void); typedef struct { char *name; /* command name */ char *help; /* help string (NULL for no help) */ int (*handler)(); /* routine which executes command */ int needconnect; /* Do we need to be connected to execute? */ } Command; static char line[256]; static char saveline[256]; static int margc; static char *margv[20]; +#if defined(SKEY) +#include +#define PATH_SKEY "/usr/bin/key" + int +skey_calc(argc, argv) + int argc; + char **argv; +{ + int status; + + if(argc != 3) { + printf("%s sequence challenge\n", argv[0]); + return; + } + + switch(fork()) { + case 0: + execv(PATH_SKEY, argv); + exit (1); + case -1: + perror("fork"); + break; + default: + (void) wait(&status); + if (WIFEXITED(status)) + return (WEXITSTATUS(status)); + return (0); + } +} +#endif + static void makeargv() { register char *cp, *cp2, c; register char **argp = margv; margc = 0; cp = line; if (*cp == '!') { /* Special case shell escape */ strcpy(saveline, line); /* save for shell command */ *argp++ = "!"; /* No room in string to get this */ margc++; cp++; } - while (c = *cp) { + while ((c = *cp)) { register int inquote = 0; while (isspace(c)) c = *++cp; if (c == '\0') break; *argp++ = cp; margc += 1; for (cp2 = cp; c != '\0'; c = *++cp) { if (inquote) { if (c == inquote) { inquote = 0; continue; } } else { if (c == '\\') { if ((c = *++cp) == '\0') break; } else if (c == '"') { inquote = '"'; continue; } else if (c == '\'') { inquote = '\''; continue; } else if (isspace(c)) break; } *cp2++ = c; } *cp2 = '\0'; if (c == '\0') break; cp++; } *argp++ = 0; } /* * Make a character string into a number. * * Todo: 1. Could take random integers (12, 0x12, 012, 0b1). */ - static + static int special(s) register char *s; { register char c; char b; switch (*s) { case '^': b = *++s; if (b == '?') { c = b | 0x40; /* DEL */ } else { c = b & 0x1f; } break; default: c = *s; break; } return c; } /* * Construct a control character sequence * for a special character. */ static char * control(c) register cc_t c; { static char buf[5]; /* * The only way I could get the Sun 3.5 compiler * to shut up about * if ((unsigned int)c >= 0x80) * was to assign "c" to an unsigned int variable... * Arggg.... */ register unsigned int uic = (unsigned int)c; if (uic == 0x7f) return ("^?"); if (c == (cc_t)_POSIX_VDISABLE) { return "off"; } if (uic >= 0x80) { buf[0] = '\\'; buf[1] = ((c>>6)&07) + '0'; buf[2] = ((c>>3)&07) + '0'; buf[3] = (c&07) + '0'; buf[4] = 0; } else if (uic >= 0x20) { buf[0] = c; buf[1] = 0; } else { buf[0] = '^'; buf[1] = '@'+c; buf[2] = 0; } return (buf); } /* * The following are data structures and routines for * the "send" command. * */ struct sendlist { char *name; /* How user refers to it (case independent) */ char *help; /* Help information (0 ==> no help) */ int needconnect; /* Need to be connected */ int narg; /* Number of arguments */ int (*handler)(); /* Routine to perform (for special ops) */ int nbyte; /* Number of bytes to send this command */ int what; /* Character to be sent (<0 ==> special) */ }; static int send_esc P((void)), send_help P((void)), send_docmd P((char *)), send_dontcmd P((char *)), send_willcmd P((char *)), send_wontcmd P((char *)); static struct sendlist Sendlist[] = { { "ao", "Send Telnet Abort output", 1, 0, 0, 2, AO }, { "ayt", "Send Telnet 'Are You There'", 1, 0, 0, 2, AYT }, { "brk", "Send Telnet Break", 1, 0, 0, 2, BREAK }, { "break", 0, 1, 0, 0, 2, BREAK }, { "ec", "Send Telnet Erase Character", 1, 0, 0, 2, EC }, { "el", "Send Telnet Erase Line", 1, 0, 0, 2, EL }, { "escape", "Send current escape character", 1, 0, send_esc, 1, 0 }, { "ga", "Send Telnet 'Go Ahead' sequence", 1, 0, 0, 2, GA }, { "ip", "Send Telnet Interrupt Process", 1, 0, 0, 2, IP }, { "intp", 0, 1, 0, 0, 2, IP }, { "interrupt", 0, 1, 0, 0, 2, IP }, { "intr", 0, 1, 0, 0, 2, IP }, { "nop", "Send Telnet 'No operation'", 1, 0, 0, 2, NOP }, { "eor", "Send Telnet 'End of Record'", 1, 0, 0, 2, EOR }, { "abort", "Send Telnet 'Abort Process'", 1, 0, 0, 2, ABORT }, { "susp", "Send Telnet 'Suspend Process'", 1, 0, 0, 2, SUSP }, { "eof", "Send Telnet End of File Character", 1, 0, 0, 2, xEOF }, { "synch", "Perform Telnet 'Synch operation'", 1, 0, dosynch, 2, 0 }, { "getstatus", "Send request for STATUS", 1, 0, get_status, 6, 0 }, { "?", "Display send options", 0, 0, send_help, 0, 0 }, { "help", 0, 0, 0, send_help, 0, 0 }, { "do", 0, 0, 1, send_docmd, 3, 0 }, { "dont", 0, 0, 1, send_dontcmd, 3, 0 }, { "will", 0, 0, 1, send_willcmd, 3, 0 }, { "wont", 0, 0, 1, send_wontcmd, 3, 0 }, { 0 } }; #define GETSEND(name) ((struct sendlist *) genget(name, (char **) Sendlist, \ sizeof(struct sendlist))) static int sendcmd(argc, argv) int argc; char **argv; { int count; /* how many bytes we are going to need to send */ int i; - int question = 0; /* was at least one argument a question */ struct sendlist *s; /* pointer to current command */ int success = 0; int needconnect = 0; if (argc < 2) { printf("need at least one argument for 'send' command\n"); printf("'send ?' for help\n"); return 0; } /* * First, validate all the send arguments. * In addition, we see how much space we are going to need, and * whether or not we will be doing a "SYNCH" operation (which * flushes the network queue). */ count = 0; for (i = 1; i < argc; i++) { s = GETSEND(argv[i]); if (s == 0) { printf("Unknown send argument '%s'\n'send ?' for help.\n", argv[i]); return 0; } else if (Ambiguous(s)) { printf("Ambiguous send argument '%s'\n'send ?' for help.\n", argv[i]); return 0; } if (i + s->narg >= argc) { fprintf(stderr, "Need %d argument%s to 'send %s' command. 'send %s ?' for help.\n", s->narg, s->narg == 1 ? "" : "s", s->name, s->name); return 0; } count += s->nbyte; if (s->handler == send_help) { send_help(); return 0; } i += s->narg; needconnect += s->needconnect; } if (!connected && needconnect) { printf("?Need to be connected first.\n"); printf("'send ?' for help\n"); return 0; } /* Now, do we have enough room? */ if (NETROOM() < count) { printf("There is not enough room in the buffer TO the network\n"); printf("to process your request. Nothing will be done.\n"); printf("('send synch' will throw away most data in the network\n"); printf("buffer, if this might help.)\n"); return 0; } /* OK, they are all OK, now go through again and actually send */ count = 0; for (i = 1; i < argc; i++) { if ((s = GETSEND(argv[i])) == 0) { fprintf(stderr, "Telnet 'send' error - argument disappeared!\n"); (void) quit(); /*NOTREACHED*/ } if (s->handler) { count++; success += (*s->handler)((s->narg > 0) ? argv[i+1] : 0, (s->narg > 1) ? argv[i+2] : 0); i += s->narg; } else { NET2ADD(IAC, s->what); printoption("SENT", IAC, s->what); } } return (count == success); } static int send_esc() { NETADD(escape); return 1; } static int send_docmd(name) char *name; { return(send_tncmd(send_do, "do", name)); } static int send_dontcmd(name) char *name; { return(send_tncmd(send_dont, "dont", name)); } static int send_willcmd(name) char *name; { return(send_tncmd(send_will, "will", name)); } static int send_wontcmd(name) char *name; { return(send_tncmd(send_wont, "wont", name)); } int send_tncmd(func, cmd, name) void (*func)(); char *cmd, *name; { char **cpp; extern char *telopts[]; register int val = 0; if (isprefix(name, "help") || isprefix(name, "?")) { register int col, len; printf("Usage: send %s \n", cmd); printf("\"value\" must be from 0 to 255\n"); printf("Valid options are:\n\t"); col = 8; for (cpp = telopts; *cpp; cpp++) { len = strlen(*cpp) + 3; if (col + len > 65) { printf("\n\t"); col = 8; } printf(" \"%s\"", *cpp); col += len; } printf("\n"); return 0; } cpp = (char **)genget(name, telopts, sizeof(char *)); if (Ambiguous(cpp)) { fprintf(stderr,"'%s': ambiguous argument ('send %s ?' for help).\n", name, cmd); return 0; } if (cpp) { val = cpp - telopts; } else { register char *cp = name; while (*cp >= '0' && *cp <= '9') { val *= 10; val += *cp - '0'; cp++; } if (*cp != 0) { fprintf(stderr, "'%s': unknown argument ('send %s ?' for help).\n", name, cmd); return 0; } else if (val < 0 || val > 255) { fprintf(stderr, "'%s': bad value ('send %s ?' for help).\n", name, cmd); return 0; } } if (!connected) { printf("?Need to be connected first.\n"); return 0; } (*func)(val, 1); return 1; } static int send_help() { struct sendlist *s; /* pointer to current command */ for (s = Sendlist; s->name; s++) { if (s->help) printf("%-15s %s\n", s->name, s->help); } return(0); } /* * The following are the routines and data structures referred * to by the arguments to the "toggle" command. */ static int lclchars() { donelclchars = 1; return 1; } static int togdebug() { #ifndef NOT43 if (net > 0 && (SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) { perror("setsockopt (SO_DEBUG)"); } #else /* NOT43 */ if (debug) { - if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) + if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) perror("setsockopt (SO_DEBUG)"); } else printf("Cannot turn off socket debugging\n"); #endif /* NOT43 */ return 1; } static int togcrlf() { if (crlf) { printf("Will send carriage returns as telnet .\n"); } else { printf("Will send carriage returns as telnet .\n"); } return 1; } int binmode; static int togbinary(val) int val; { donebinarytoggle = 1; if (val >= 0) { binmode = val; } else { if (my_want_state_is_will(TELOPT_BINARY) && my_want_state_is_do(TELOPT_BINARY)) { binmode = 1; } else if (my_want_state_is_wont(TELOPT_BINARY) && my_want_state_is_dont(TELOPT_BINARY)) { binmode = 0; } val = binmode ? 0 : 1; } if (val == 1) { if (my_want_state_is_will(TELOPT_BINARY) && my_want_state_is_do(TELOPT_BINARY)) { printf("Already operating in binary mode with remote host.\n"); } else { printf("Negotiating binary mode with remote host.\n"); tel_enter_binary(3); } } else { if (my_want_state_is_wont(TELOPT_BINARY) && my_want_state_is_dont(TELOPT_BINARY)) { printf("Already in network ascii mode with remote host.\n"); } else { printf("Negotiating network ascii mode with remote host.\n"); tel_leave_binary(3); } } return 1; } static int togrbinary(val) int val; { donebinarytoggle = 1; if (val == -1) val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1; if (val == 1) { if (my_want_state_is_do(TELOPT_BINARY)) { printf("Already receiving in binary mode.\n"); } else { printf("Negotiating binary mode on input.\n"); tel_enter_binary(1); } } else { if (my_want_state_is_dont(TELOPT_BINARY)) { printf("Already receiving in network ascii mode.\n"); } else { printf("Negotiating network ascii mode on input.\n"); tel_leave_binary(1); } } return 1; } static int togxbinary(val) int val; { donebinarytoggle = 1; if (val == -1) val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1; if (val == 1) { if (my_want_state_is_will(TELOPT_BINARY)) { printf("Already transmitting in binary mode.\n"); } else { printf("Negotiating binary mode on output.\n"); tel_enter_binary(2); } } else { if (my_want_state_is_wont(TELOPT_BINARY)) { printf("Already transmitting in network ascii mode.\n"); } else { printf("Negotiating network ascii mode on output.\n"); tel_leave_binary(2); } } return 1; } static int togglehelp P((void)); #if defined(AUTHENTICATION) extern int auth_togdebug P((int)); #endif #ifdef ENCRYPTION extern int EncryptAutoEnc P((int)); extern int EncryptAutoDec P((int)); extern int EncryptDebug P((int)); extern int EncryptVerbose P((int)); #endif /* ENCRYPTION */ struct togglelist { char *name; /* name of toggle */ char *help; /* help message */ int (*handler)(); /* routine to do actual setting */ int *variable; char *actionexplanation; }; static struct togglelist Togglelist[] = { { "autoflush", "flushing of output when sending interrupt characters", 0, &autoflush, "flush output when sending interrupt characters" }, { "autosynch", "automatic sending of interrupt characters in urgent mode", 0, &autosynch, "send interrupt characters in urgent mode" }, #if defined(AUTHENTICATION) { "autologin", "automatic sending of login and/or authentication info", 0, &autologin, "send login name and/or authentication information" }, { "authdebug", "Toggle authentication debugging", auth_togdebug, 0, "print authentication debugging information" }, #endif #ifdef ENCRYPTION { "autoencrypt", "automatic encryption of data stream", EncryptAutoEnc, 0, "automatically encrypt output" }, { "autodecrypt", "automatic decryption of data stream", EncryptAutoDec, 0, "automatically decrypt input" }, { "verbose_encrypt", "Toggle verbose encryption output", EncryptVerbose, 0, "print verbose encryption output" }, { "encdebug", "Toggle encryption debugging", EncryptDebug, 0, "print encryption debugging information" }, #endif /* ENCRYPTION */ { "skiprc", "don't read ~/.telnetrc file", 0, &skiprc, "skip reading of ~/.telnetrc file" }, { "binary", "sending and receiving of binary data", togbinary, 0, 0 }, { "inbinary", "receiving of binary data", togrbinary, 0, 0 }, { "outbinary", "sending of binary data", togxbinary, 0, 0 }, { "crlf", "sending carriage returns as telnet ", togcrlf, &crlf, 0 }, { "crmod", "mapping of received carriage returns", 0, &crmod, "map carriage return on output" }, { "localchars", "local recognition of certain control characters", lclchars, &localchars, "recognize certain control characters" }, { " ", "", 0 }, /* empty line */ #if defined(unix) && defined(TN3270) { "apitrace", "(debugging) toggle tracing of API transactions", 0, &apitrace, "trace API transactions" }, { "cursesdata", "(debugging) toggle printing of hexadecimal curses data", 0, &cursesdata, "print hexadecimal representation of curses data" }, #endif /* defined(unix) && defined(TN3270) */ { "debug", "debugging", togdebug, &debug, "turn on socket level debugging" }, { "netdata", "printing of hexadecimal network data (debugging)", 0, &netdata, "print hexadecimal representation of network traffic" }, { "prettydump", "output of \"netdata\" to user readable format (debugging)", 0, &prettydump, "print user readable output for \"netdata\"" }, { "options", "viewing of options processing (debugging)", 0, &showoptions, "show option processing" }, #if defined(unix) { "termdata", "(debugging) toggle printing of hexadecimal terminal data", 0, &termdata, "print hexadecimal representation of terminal traffic" }, #endif /* defined(unix) */ { "?", 0, togglehelp }, { "help", 0, togglehelp }, { 0 } }; static int togglehelp() { struct togglelist *c; for (c = Togglelist; c->name; c++) { if (c->help) { if (*c->help) printf("%-15s toggle %s\n", c->name, c->help); else printf("\n"); } } printf("\n"); printf("%-15s %s\n", "?", "display help information"); return 0; } static void settogglehelp(set) int set; { struct togglelist *c; for (c = Togglelist; c->name; c++) { if (c->help) { if (*c->help) printf("%-15s %s %s\n", c->name, set ? "enable" : "disable", c->help); else printf("\n"); } } } #define GETTOGGLE(name) (struct togglelist *) \ genget(name, (char **) Togglelist, sizeof(struct togglelist)) static int toggle(argc, argv) int argc; char *argv[]; { int retval = 1; char *name; struct togglelist *c; if (argc < 2) { fprintf(stderr, "Need an argument to 'toggle' command. 'toggle ?' for help.\n"); return 0; } argc--; argv++; while (argc--) { name = *argv++; c = GETTOGGLE(name); if (Ambiguous(c)) { fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n", name); return 0; } else if (c == 0) { fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n", name); return 0; } else { if (c->variable) { *c->variable = !*c->variable; /* invert it */ if (c->actionexplanation) { printf("%s %s.\n", *c->variable? "Will" : "Won't", c->actionexplanation); } } if (c->handler) { retval &= (*c->handler)(-1); } } } return retval; } /* * The following perform the "set" command. */ #ifdef USE_TERMIO struct termio new_tc = { 0 }; #endif struct setlist { char *name; /* name */ char *help; /* help information */ void (*handler)(); cc_t *charp; /* where it is located at */ }; static struct setlist Setlist[] = { #ifdef KLUDGELINEMODE { "echo", "character to toggle local echoing on/off", 0, &echoc }, #endif { "escape", "character to escape back to telnet command mode", 0, &escape }, { "rlogin", "rlogin escape character", 0, &rlogin }, { "tracefile", "file to write trace information to", SetNetTrace, (cc_t *)NetTraceFile}, { " ", "" }, { " ", "The following need 'localchars' to be toggled true", 0, 0 }, { "flushoutput", "character to cause an Abort Output", 0, termFlushCharp }, { "interrupt", "character to cause an Interrupt Process", 0, termIntCharp }, { "quit", "character to cause an Abort process", 0, termQuitCharp }, { "eof", "character to cause an EOF ", 0, termEofCharp }, { " ", "" }, { " ", "The following are for local editing in linemode", 0, 0 }, { "erase", "character to use to erase a character", 0, termEraseCharp }, { "kill", "character to use to erase a line", 0, termKillCharp }, { "lnext", "character to use for literal next", 0, termLiteralNextCharp }, { "susp", "character to cause a Suspend Process", 0, termSuspCharp }, { "reprint", "character to use for line reprint", 0, termRprntCharp }, { "worderase", "character to use to erase a word", 0, termWerasCharp }, { "start", "character to use for XON", 0, termStartCharp }, { "stop", "character to use for XOFF", 0, termStopCharp }, { "forw1", "alternate end of line character", 0, termForw1Charp }, { "forw2", "alternate end of line character", 0, termForw2Charp }, { "ayt", "alternate AYT character", 0, termAytCharp }, { 0 } }; #if defined(CRAY) && !defined(__STDC__) /* Work around compiler bug in pcc 4.1.5 */ void _setlist_init() { #ifndef KLUDGELINEMODE #define N 5 #else #define N 6 #endif Setlist[N+0].charp = &termFlushChar; Setlist[N+1].charp = &termIntChar; Setlist[N+2].charp = &termQuitChar; Setlist[N+3].charp = &termEofChar; Setlist[N+6].charp = &termEraseChar; Setlist[N+7].charp = &termKillChar; Setlist[N+8].charp = &termLiteralNextChar; Setlist[N+9].charp = &termSuspChar; Setlist[N+10].charp = &termRprntChar; Setlist[N+11].charp = &termWerasChar; Setlist[N+12].charp = &termStartChar; Setlist[N+13].charp = &termStopChar; Setlist[N+14].charp = &termForw1Char; Setlist[N+15].charp = &termForw2Char; Setlist[N+16].charp = &termAytChar; #undef N } #endif /* defined(CRAY) && !defined(__STDC__) */ static struct setlist * getset(name) char *name; { return (struct setlist *) genget(name, (char **) Setlist, sizeof(struct setlist)); } void set_escape_char(s) char *s; { if (rlogin != _POSIX_VDISABLE) { rlogin = (s && *s) ? special(s) : _POSIX_VDISABLE; printf("Telnet rlogin escape character is '%s'.\n", control(rlogin)); } else { escape = (s && *s) ? special(s) : _POSIX_VDISABLE; printf("Telnet escape character is '%s'.\n", control(escape)); } } static int setcmd(argc, argv) int argc; char *argv[]; { int value; struct setlist *ct; struct togglelist *c; if (argc < 2 || argc > 3) { printf("Format is 'set Name Value'\n'set ?' for help.\n"); return 0; } if ((argc == 2) && (isprefix(argv[1], "?") || isprefix(argv[1], "help"))) { for (ct = Setlist; ct->name; ct++) printf("%-15s %s\n", ct->name, ct->help); printf("\n"); settogglehelp(1); printf("%-15s %s\n", "?", "display help information"); return 0; } ct = getset(argv[1]); if (ct == 0) { c = GETTOGGLE(argv[1]); if (c == 0) { fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n", argv[1]); return 0; } else if (Ambiguous(c)) { fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n", argv[1]); return 0; } if (c->variable) { if ((argc == 2) || (strcmp("on", argv[2]) == 0)) *c->variable = 1; else if (strcmp("off", argv[2]) == 0) *c->variable = 0; else { printf("Format is 'set togglename [on|off]'\n'set ?' for help.\n"); return 0; } if (c->actionexplanation) { printf("%s %s.\n", *c->variable? "Will" : "Won't", c->actionexplanation); } } if (c->handler) (*c->handler)(1); } else if (argc != 3) { printf("Format is 'set Name Value'\n'set ?' for help.\n"); return 0; } else if (Ambiguous(ct)) { fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n", argv[1]); return 0; } else if (ct->handler) { (*ct->handler)(argv[2]); printf("%s set to \"%s\".\n", ct->name, (char *)ct->charp); } else { if (strcmp("off", argv[2])) { value = special(argv[2]); } else { value = _POSIX_VDISABLE; } *(ct->charp) = (cc_t)value; printf("%s character is '%s'.\n", ct->name, control(*(ct->charp))); } slc_check(); return 1; } static int unsetcmd(argc, argv) int argc; char *argv[]; { struct setlist *ct; struct togglelist *c; register char *name; if (argc < 2) { fprintf(stderr, "Need an argument to 'unset' command. 'unset ?' for help.\n"); return 0; } if (isprefix(argv[1], "?") || isprefix(argv[1], "help")) { for (ct = Setlist; ct->name; ct++) printf("%-15s %s\n", ct->name, ct->help); printf("\n"); settogglehelp(0); printf("%-15s %s\n", "?", "display help information"); return 0; } argc--; argv++; while (argc--) { name = *argv++; ct = getset(name); if (ct == 0) { c = GETTOGGLE(name); if (c == 0) { fprintf(stderr, "'%s': unknown argument ('unset ?' for help).\n", name); return 0; } else if (Ambiguous(c)) { fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n", name); return 0; } if (c->variable) { *c->variable = 0; if (c->actionexplanation) { printf("%s %s.\n", *c->variable? "Will" : "Won't", c->actionexplanation); } } if (c->handler) (*c->handler)(0); } else if (Ambiguous(ct)) { fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n", name); return 0; } else if (ct->handler) { (*ct->handler)(0); printf("%s reset to \"%s\".\n", ct->name, (char *)ct->charp); } else { *(ct->charp) = _POSIX_VDISABLE; printf("%s character is '%s'.\n", ct->name, control(*(ct->charp))); } } return 1; } /* * The following are the data structures and routines for the * 'mode' command. */ #ifdef KLUDGELINEMODE extern int kludgelinemode; - static int + static void dokludgemode() { kludgelinemode = 1; send_wont(TELOPT_LINEMODE, 1); send_dont(TELOPT_SGA, 1); send_dont(TELOPT_ECHO, 1); } #endif static int dolinemode() { #ifdef KLUDGELINEMODE if (kludgelinemode) send_dont(TELOPT_SGA, 1); #endif send_will(TELOPT_LINEMODE, 1); send_dont(TELOPT_ECHO, 1); return 1; } static int docharmode() { #ifdef KLUDGELINEMODE if (kludgelinemode) send_do(TELOPT_SGA, 1); else #endif send_wont(TELOPT_LINEMODE, 1); send_do(TELOPT_ECHO, 1); return 1; } static int dolmmode(bit, on) int bit, on; { unsigned char c; extern int linemode; if (my_want_state_is_wont(TELOPT_LINEMODE)) { printf("?Need to have LINEMODE option enabled first.\n"); printf("'mode ?' for help.\n"); return 0; } if (on) c = (linemode | bit); else c = (linemode & ~bit); lm_mode(&c, 1, 1); return 1; } int -setmode(bit) +setmod(bit) { return dolmmode(bit, 1); } int clearmode(bit) { return dolmmode(bit, 0); } struct modelist { char *name; /* command name */ char *help; /* help string */ int (*handler)(); /* routine which executes command */ int needconnect; /* Do we need to be connected to execute? */ int arg1; }; extern int modehelp(); static struct modelist ModeList[] = { { "character", "Disable LINEMODE option", docharmode, 1 }, #ifdef KLUDGELINEMODE { "", "(or disable obsolete line-by-line mode)", 0 }, #endif { "line", "Enable LINEMODE option", dolinemode, 1 }, #ifdef KLUDGELINEMODE { "", "(or enable obsolete line-by-line mode)", 0 }, #endif { "", "", 0 }, { "", "These require the LINEMODE option to be enabled", 0 }, - { "isig", "Enable signal trapping", setmode, 1, MODE_TRAPSIG }, - { "+isig", 0, setmode, 1, MODE_TRAPSIG }, + { "isig", "Enable signal trapping", setmod, 1, MODE_TRAPSIG }, + { "+isig", 0, setmod, 1, MODE_TRAPSIG }, { "-isig", "Disable signal trapping", clearmode, 1, MODE_TRAPSIG }, - { "edit", "Enable character editing", setmode, 1, MODE_EDIT }, - { "+edit", 0, setmode, 1, MODE_EDIT }, + { "edit", "Enable character editing", setmod, 1, MODE_EDIT }, + { "+edit", 0, setmod, 1, MODE_EDIT }, { "-edit", "Disable character editing", clearmode, 1, MODE_EDIT }, - { "softtabs", "Enable tab expansion", setmode, 1, MODE_SOFT_TAB }, - { "+softtabs", 0, setmode, 1, MODE_SOFT_TAB }, + { "softtabs", "Enable tab expansion", setmod, 1, MODE_SOFT_TAB }, + { "+softtabs", 0, setmod, 1, MODE_SOFT_TAB }, { "-softtabs", "Disable character editing", clearmode, 1, MODE_SOFT_TAB }, - { "litecho", "Enable literal character echo", setmode, 1, MODE_LIT_ECHO }, - { "+litecho", 0, setmode, 1, MODE_LIT_ECHO }, + { "litecho", "Enable literal character echo", setmod, 1, MODE_LIT_ECHO }, + { "+litecho", 0, setmod, 1, MODE_LIT_ECHO }, { "-litecho", "Disable literal character echo", clearmode, 1, MODE_LIT_ECHO }, { "help", 0, modehelp, 0 }, #ifdef KLUDGELINEMODE { "kludgeline", 0, dokludgemode, 1 }, #endif { "", "", 0 }, { "?", "Print help information", modehelp, 0 }, { 0 }, }; int modehelp() { struct modelist *mt; printf("format is: 'mode Mode', where 'Mode' is one of:\n\n"); for (mt = ModeList; mt->name; mt++) { if (mt->help) { if (*mt->help) printf("%-15s %s\n", mt->name, mt->help); else printf("\n"); } } return 0; } #define GETMODECMD(name) (struct modelist *) \ genget(name, (char **) ModeList, sizeof(struct modelist)) static int modecmd(argc, argv) int argc; char *argv[]; { struct modelist *mt; if (argc != 2) { printf("'mode' command requires an argument\n"); printf("'mode ?' for help.\n"); } else if ((mt = GETMODECMD(argv[1])) == 0) { fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]); } else if (Ambiguous(mt)) { fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]); } else if (mt->needconnect && !connected) { printf("?Need to be connected first.\n"); printf("'mode ?' for help.\n"); } else if (mt->handler) { return (*mt->handler)(mt->arg1); } return 0; } /* * The following data structures and routines implement the * "display" command. */ static int display(argc, argv) int argc; char *argv[]; { struct togglelist *tl; struct setlist *sl; #define dotog(tl) if (tl->variable && tl->actionexplanation) { \ if (*tl->variable) { \ printf("will"); \ } else { \ printf("won't"); \ } \ printf(" %s.\n", tl->actionexplanation); \ } #define doset(sl) if (sl->name && *sl->name != ' ') { \ if (sl->handler == 0) \ printf("%-15s [%s]\n", sl->name, control(*sl->charp)); \ else \ printf("%-15s \"%s\"\n", sl->name, (char *)sl->charp); \ } if (argc == 1) { for (tl = Togglelist; tl->name; tl++) { dotog(tl); } printf("\n"); for (sl = Setlist; sl->name; sl++) { doset(sl); } } else { int i; for (i = 1; i < argc; i++) { sl = getset(argv[i]); tl = GETTOGGLE(argv[i]); if (Ambiguous(sl) || Ambiguous(tl)) { printf("?Ambiguous argument '%s'.\n", argv[i]); return 0; } else if (!sl && !tl) { printf("?Unknown argument '%s'.\n", argv[i]); return 0; } else { if (tl) { dotog(tl); } if (sl) { doset(sl); } } } } /*@*/optionstatus(); #ifdef ENCRYPTION EncryptStatus(); #endif /* ENCRYPTION */ return 1; #undef doset #undef dotog } /* * The following are the data structures, and many of the routines, * relating to command processing. */ /* * Set the escape character. */ static int setescape(argc, argv) int argc; char *argv[]; { register char *arg; char buf[50]; printf( "Deprecated usage - please use 'set escape%s%s' in the future.\n", (argc > 2)? " ":"", (argc > 2)? argv[1]: ""); if (argc > 2) arg = argv[1]; else { printf("new escape character: "); (void) fgets(buf, sizeof(buf), stdin); arg = buf; } if (arg[0] != '\0') escape = arg[0]; if (!In3270) { printf("Escape character is '%s'.\n", control(escape)); } (void) fflush(stdout); return 1; } /*VARARGS*/ static int togcrmod() { crmod = !crmod; printf("Deprecated usage - please use 'toggle crmod' in the future.\n"); printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't"); (void) fflush(stdout); return 1; } /*VARARGS*/ int suspend() { #ifdef SIGTSTP setcommandmode(); { long oldrows, oldcols, newrows, newcols, err; err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0; (void) kill(0, SIGTSTP); /* * If we didn't get the window size before the SUSPEND, but we * can get them now (?), then send the NAWS to make sure that * we are set up for the right window size. */ if (TerminalWindowSize(&newrows, &newcols) && connected && (err || ((oldrows != newrows) || (oldcols != newcols)))) { sendnaws(); } } /* reget parameters in case they were changed */ TerminalSaveState(); setconnmode(0); #else printf("Suspend is not supported. Try the '!' command instead\n"); #endif return 1; } #if !defined(TN3270) /*ARGSUSED*/ int shell(argc, argv) int argc; char *argv[]; { long oldrows, oldcols, newrows, newcols, err; setcommandmode(); err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0; switch(vfork()) { case -1: perror("Fork failed\n"); break; case 0: { /* * Fire up the shell in the child. */ register char *shellp, *shellname; extern char *strrchr(); shellp = getenv("SHELL"); if (shellp == NULL) shellp = "/bin/sh"; if ((shellname = strrchr(shellp, '/')) == 0) shellname = shellp; else shellname++; if (argc > 1) execl(shellp, shellname, "-c", &saveline[1], 0); else execl(shellp, shellname, 0); perror("Execl"); _exit(1); } default: (void)wait((int *)0); /* Wait for the shell to complete */ if (TerminalWindowSize(&newrows, &newcols) && connected && (err || ((oldrows != newrows) || (oldcols != newcols)))) { sendnaws(); } break; } return 1; } #else /* !defined(TN3270) */ extern int shell(); #endif /* !defined(TN3270) */ /*VARARGS*/ - static + static int bye(argc, argv) int argc; /* Number of arguments */ char *argv[]; /* arguments */ { extern int resettermname; if (connected) { (void) shutdown(net, 2); printf("Connection closed.\n"); (void) NetClose(net); connected = 0; resettermname = 1; #if defined(AUTHENTICATION) || defined(ENCRYPTION) auth_encrypt_connect(connected); #endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */ /* reset options */ tninit(); #if defined(TN3270) SetIn3270(); /* Get out of 3270 mode */ #endif /* defined(TN3270) */ } if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) { longjmp(toplevel, 1); /* NOTREACHED */ } return 1; /* Keep lint, etc., happy */ } /*VARARGS*/ + int quit() { (void) call(bye, "bye", "fromquit", 0); Exit(0); /*NOTREACHED*/ } /*VARARGS*/ int logout() { send_do(TELOPT_LOGOUT, 1); (void) netflush(); return 1; } /* * The SLC command. */ struct slclist { char *name; char *help; void (*handler)(); int arg; }; static void slc_help(); struct slclist SlcList[] = { { "export", "Use local special character definitions", slc_mode_export, 0 }, { "import", "Use remote special character definitions", slc_mode_import, 1 }, { "check", "Verify remote special character definitions", slc_mode_import, 0 }, { "help", 0, slc_help, 0 }, { "?", "Print help information", slc_help, 0 }, { 0 }, }; static void slc_help() { struct slclist *c; for (c = SlcList; c->name; c++) { if (c->help) { if (*c->help) printf("%-15s %s\n", c->name, c->help); else printf("\n"); } } } static struct slclist * getslc(name) char *name; { return (struct slclist *) genget(name, (char **) SlcList, sizeof(struct slclist)); } - static + static int slccmd(argc, argv) int argc; char *argv[]; { struct slclist *c; if (argc != 2) { fprintf(stderr, "Need an argument to 'slc' command. 'slc ?' for help.\n"); return 0; } c = getslc(argv[1]); if (c == 0) { fprintf(stderr, "'%s': unknown argument ('slc ?' for help).\n", argv[1]); return 0; } if (Ambiguous(c)) { fprintf(stderr, "'%s': ambiguous argument ('slc ?' for help).\n", argv[1]); return 0; } (*c->handler)(c->arg); slcstate(); return 1; } /* * The ENVIRON command. */ struct envlist { char *name; char *help; void (*handler)(); int narg; }; extern struct env_lst * env_define P((unsigned char *, unsigned char *)); extern void env_undefine P((unsigned char *)), env_export P((unsigned char *)), env_unexport P((unsigned char *)), env_send P((unsigned char *)), #if defined(OLD_ENVIRON) && defined(ENV_HACK) env_varval P((unsigned char *)), #endif env_list P((void)); static void env_help P((void)); struct envlist EnvList[] = { { "define", "Define an environment variable", (void (*)())env_define, 2 }, { "undefine", "Undefine an environment variable", env_undefine, 1 }, { "export", "Mark an environment variable for automatic export", env_export, 1 }, { "unexport", "Don't mark an environment variable for automatic export", env_unexport, 1 }, { "send", "Send an environment variable", env_send, 1 }, { "list", "List the current environment variables", env_list, 0 }, #if defined(OLD_ENVIRON) && defined(ENV_HACK) { "varval", "Reverse VAR and VALUE (auto, right, wrong, status)", env_varval, 1 }, #endif { "help", 0, env_help, 0 }, { "?", "Print help information", env_help, 0 }, { 0 }, }; static void env_help() { struct envlist *c; for (c = EnvList; c->name; c++) { if (c->help) { if (*c->help) printf("%-15s %s\n", c->name, c->help); else printf("\n"); } } } static struct envlist * getenvcmd(name) char *name; { return (struct envlist *) genget(name, (char **) EnvList, sizeof(struct envlist)); } + int env_cmd(argc, argv) int argc; char *argv[]; { struct envlist *c; if (argc < 2) { fprintf(stderr, "Need an argument to 'environ' command. 'environ ?' for help.\n"); return 0; } c = getenvcmd(argv[1]); if (c == 0) { fprintf(stderr, "'%s': unknown argument ('environ ?' for help).\n", argv[1]); return 0; } if (Ambiguous(c)) { fprintf(stderr, "'%s': ambiguous argument ('environ ?' for help).\n", argv[1]); return 0; } if (c->narg + 2 != argc) { fprintf(stderr, "Need %s%d argument%s to 'environ %s' command. 'environ ?' for help.\n", c->narg < argc + 2 ? "only " : "", c->narg, c->narg == 1 ? "" : "s", c->name); return 0; } (*c->handler)(argv[2], argv[3]); return 1; } struct env_lst { struct env_lst *next; /* pointer to next structure */ struct env_lst *prev; /* pointer to previous structure */ unsigned char *var; /* pointer to variable name */ unsigned char *value; /* pointer to variable value */ int export; /* 1 -> export with default list of variables */ int welldefined; /* A well defined variable */ }; struct env_lst envlisthead; struct env_lst * env_find(var) unsigned char *var; { register struct env_lst *ep; for (ep = envlisthead.next; ep; ep = ep->next) { if (strcmp((char *)ep->var, (char *)var) == 0) return(ep); } return(NULL); } void env_init() { extern char **environ; register char **epp, *cp; register struct env_lst *ep; extern char *strchr(); for (epp = environ; *epp; epp++) { - if (cp = strchr(*epp, '=')) { + if ((cp = strchr(*epp, '='))) { *cp = '\0'; ep = env_define((unsigned char *)*epp, (unsigned char *)cp+1); ep->export = 0; *cp = '='; } } /* * Special case for DISPLAY variable. If it is ":0.0" or * "unix:0.0", we have to get rid of "unix" and insert our * hostname. */ if ((ep = env_find("DISPLAY")) && ((*ep->value == ':') || (strncmp((char *)ep->value, "unix:", 5) == 0))) { char hbuf[256+1]; char *cp2 = strchr((char *)ep->value, ':'); gethostname(hbuf, 256); hbuf[256] = '\0'; cp = (char *)malloc(strlen(hbuf) + strlen(cp2) + 1); sprintf((char *)cp, "%s%s", hbuf, cp2); free(ep->value); ep->value = (unsigned char *)cp; } /* * If USER is not defined, but LOGNAME is, then add * USER with the value from LOGNAME. By default, we * don't export the USER variable. */ if ((env_find("USER") == NULL) && (ep = env_find("LOGNAME"))) { env_define((unsigned char *)"USER", ep->value); env_unexport((unsigned char *)"USER"); } env_export((unsigned char *)"DISPLAY"); env_export((unsigned char *)"PRINTER"); } struct env_lst * env_define(var, value) unsigned char *var, *value; { register struct env_lst *ep; - if (ep = env_find(var)) { + if ((ep = env_find(var))) { if (ep->var) free(ep->var); if (ep->value) free(ep->value); } else { ep = (struct env_lst *)malloc(sizeof(struct env_lst)); ep->next = envlisthead.next; envlisthead.next = ep; ep->prev = &envlisthead; if (ep->next) ep->next->prev = ep; } ep->welldefined = opt_welldefined(var); ep->export = 1; ep->var = (unsigned char *)strdup((char *)var); ep->value = (unsigned char *)strdup((char *)value); return(ep); } void env_undefine(var) unsigned char *var; { register struct env_lst *ep; - if (ep = env_find(var)) { + if ((ep = env_find(var))) { ep->prev->next = ep->next; if (ep->next) ep->next->prev = ep->prev; if (ep->var) free(ep->var); if (ep->value) free(ep->value); free(ep); } } void env_export(var) unsigned char *var; { register struct env_lst *ep; - if (ep = env_find(var)) + if ((ep = env_find(var))) ep->export = 1; } void env_unexport(var) unsigned char *var; { register struct env_lst *ep; - if (ep = env_find(var)) + if ((ep = env_find(var))) ep->export = 0; } void env_send(var) unsigned char *var; { register struct env_lst *ep; if (my_state_is_wont(TELOPT_NEW_ENVIRON) #ifdef OLD_ENVIRON && my_state_is_wont(TELOPT_OLD_ENVIRON) #endif ) { fprintf(stderr, "Cannot send '%s': Telnet ENVIRON option not enabled\n", var); return; } ep = env_find(var); if (ep == 0) { fprintf(stderr, "Cannot send '%s': variable not defined\n", var); return; } env_opt_start_info(); env_opt_add(ep->var); env_opt_end(0); } void env_list() { register struct env_lst *ep; for (ep = envlisthead.next; ep; ep = ep->next) { printf("%c %-20s %s\n", ep->export ? '*' : ' ', ep->var, ep->value); } } unsigned char * env_default(init, welldefined) int init; { static struct env_lst *nep = NULL; if (init) { nep = &envlisthead; - return; + return(NULL); } if (nep) { - while (nep = nep->next) { + while ((nep = nep->next)) { if (nep->export && (nep->welldefined == welldefined)) return(nep->var); } } return(NULL); } unsigned char * env_getvalue(var) unsigned char *var; { register struct env_lst *ep; - if (ep = env_find(var)) + if ((ep = env_find(var))) return(ep->value); return(NULL); } #if defined(OLD_ENVIRON) && defined(ENV_HACK) void env_varval(what) unsigned char *what; { extern int old_env_var, old_env_value, env_auto; int len = strlen((char *)what); if (len == 0) goto unknown; if (strncasecmp((char *)what, "status", len) == 0) { if (env_auto) printf("%s%s", "VAR and VALUE are/will be ", "determined automatically\n"); if (old_env_var == OLD_ENV_VAR) printf("VAR and VALUE set to correct definitions\n"); else printf("VAR and VALUE definitions are reversed\n"); } else if (strncasecmp((char *)what, "auto", len) == 0) { env_auto = 1; old_env_var = OLD_ENV_VALUE; old_env_value = OLD_ENV_VAR; } else if (strncasecmp((char *)what, "right", len) == 0) { env_auto = 0; old_env_var = OLD_ENV_VAR; old_env_value = OLD_ENV_VALUE; } else if (strncasecmp((char *)what, "wrong", len) == 0) { env_auto = 0; old_env_var = OLD_ENV_VALUE; old_env_value = OLD_ENV_VAR; } else { unknown: printf("Unknown \"varval\" command. (\"auto\", \"right\", \"wrong\", \"status\")\n"); } } #endif #if defined(AUTHENTICATION) /* * The AUTHENTICATE command. */ struct authlist { char *name; char *help; int (*handler)(); int narg; }; extern int auth_enable P((char *)), auth_disable P((char *)), auth_status P((void)); static int auth_help P((void)); struct authlist AuthList[] = { { "status", "Display current status of authentication information", auth_status, 0 }, { "disable", "Disable an authentication type ('auth disable ?' for more)", auth_disable, 1 }, { "enable", "Enable an authentication type ('auth enable ?' for more)", auth_enable, 1 }, { "help", 0, auth_help, 0 }, { "?", "Print help information", auth_help, 0 }, { 0 }, }; static int auth_help() { struct authlist *c; for (c = AuthList; c->name; c++) { if (c->help) { if (*c->help) printf("%-15s %s\n", c->name, c->help); else printf("\n"); } } return 0; } + int auth_cmd(argc, argv) int argc; char *argv[]; { struct authlist *c; if (argc < 2) { fprintf(stderr, "Need an argument to 'auth' command. 'auth ?' for help.\n"); return 0; } c = (struct authlist *) genget(argv[1], (char **) AuthList, sizeof(struct authlist)); if (c == 0) { fprintf(stderr, "'%s': unknown argument ('auth ?' for help).\n", argv[1]); return 0; } if (Ambiguous(c)) { fprintf(stderr, "'%s': ambiguous argument ('auth ?' for help).\n", argv[1]); return 0; } if (c->narg + 2 != argc) { fprintf(stderr, "Need %s%d argument%s to 'auth %s' command. 'auth ?' for help.\n", c->narg < argc + 2 ? "only " : "", c->narg, c->narg == 1 ? "" : "s", c->name); return 0; } return((*c->handler)(argv[2], argv[3])); } #endif #ifdef ENCRYPTION /* * The ENCRYPT command. */ struct encryptlist { char *name; char *help; int (*handler)(); int needconnect; int minarg; int maxarg; }; extern int EncryptEnable P((char *, char *)), EncryptDisable P((char *, char *)), EncryptType P((char *, char *)), EncryptStart P((char *)), EncryptStartInput P((void)), EncryptStartOutput P((void)), EncryptStop P((char *)), EncryptStopInput P((void)), EncryptStopOutput P((void)), EncryptStatus P((void)); static int EncryptHelp P((void)); struct encryptlist EncryptList[] = { { "enable", "Enable encryption. ('encrypt enable ?' for more)", EncryptEnable, 1, 1, 2 }, { "disable", "Disable encryption. ('encrypt enable ?' for more)", EncryptDisable, 0, 1, 2 }, { "type", "Set encryption type. ('encrypt type ?' for more)", EncryptType, 0, 1, 1 }, { "start", "Start encryption. ('encrypt start ?' for more)", EncryptStart, 1, 0, 1 }, { "stop", "Stop encryption. ('encrypt stop ?' for more)", EncryptStop, 1, 0, 1 }, { "input", "Start encrypting the input stream", EncryptStartInput, 1, 0, 0 }, { "-input", "Stop encrypting the input stream", EncryptStopInput, 1, 0, 0 }, { "output", "Start encrypting the output stream", EncryptStartOutput, 1, 0, 0 }, { "-output", "Stop encrypting the output stream", EncryptStopOutput, 1, 0, 0 }, { "status", "Display current status of authentication information", EncryptStatus, 0, 0, 0 }, { "help", 0, EncryptHelp, 0, 0, 0 }, { "?", "Print help information", EncryptHelp, 0, 0, 0 }, { 0 }, }; static int EncryptHelp() { struct encryptlist *c; for (c = EncryptList; c->name; c++) { if (c->help) { if (*c->help) printf("%-15s %s\n", c->name, c->help); else printf("\n"); } } return 0; } + int encrypt_cmd(argc, argv) int argc; char *argv[]; { struct encryptlist *c; if (argc < 2) { fprintf(stderr, "Need an argument to 'encrypt' command. 'encrypt ?' for help.\n"); return 0; } c = (struct encryptlist *) genget(argv[1], (char **) EncryptList, sizeof(struct encryptlist)); if (c == 0) { fprintf(stderr, "'%s': unknown argument ('encrypt ?' for help).\n", argv[1]); return 0; } if (Ambiguous(c)) { fprintf(stderr, "'%s': ambiguous argument ('encrypt ?' for help).\n", argv[1]); return 0; } argc -= 2; if (argc < c->minarg || argc > c->maxarg) { if (c->minarg == c->maxarg) { fprintf(stderr, "Need %s%d argument%s ", c->minarg < argc ? "only " : "", c->minarg, c->minarg == 1 ? "" : "s"); } else { fprintf(stderr, "Need %s%d-%d arguments ", c->maxarg < argc ? "only " : "", c->minarg, c->maxarg); } fprintf(stderr, "to 'encrypt %s' command. 'encrypt ?' for help.\n", c->name); return 0; } if (c->needconnect && !connected) { if (!(argc && (isprefix(argv[2], "help") || isprefix(argv[2], "?")))) { printf("?Need to be connected first.\n"); return 0; } } return ((*c->handler)(argc > 0 ? argv[2] : 0, argc > 1 ? argv[3] : 0, argc > 2 ? argv[4] : 0)); } #endif /* ENCRYPTION */ #if defined(unix) && defined(TN3270) static void filestuff(fd) int fd; { int res; #ifdef F_GETOWN setconnmode(0); res = fcntl(fd, F_GETOWN, 0); setcommandmode(); if (res == -1) { perror("fcntl"); return; } printf("\tOwner is %d.\n", res); #endif setconnmode(0); res = fcntl(fd, F_GETFL, 0); setcommandmode(); if (res == -1) { perror("fcntl"); return; } #ifdef notdef printf("\tFlags are 0x%x: %s\n", res, decodeflags(res)); #endif } #endif /* defined(unix) && defined(TN3270) */ /* * Print status about the connection. */ /*ARGSUSED*/ - static + static int status(argc, argv) int argc; char *argv[]; { if (connected) { printf("Connected to %s.\n", hostname); if ((argc < 2) || strcmp(argv[1], "notmuch")) { int mode = getconnmode(); if (my_want_state_is_will(TELOPT_LINEMODE)) { printf("Operating with LINEMODE option\n"); printf("%s line editing\n", (mode&MODE_EDIT) ? "Local" : "No"); printf("%s catching of signals\n", (mode&MODE_TRAPSIG) ? "Local" : "No"); slcstate(); #ifdef KLUDGELINEMODE } else if (kludgelinemode && my_want_state_is_dont(TELOPT_SGA)) { printf("Operating in obsolete linemode\n"); #endif } else { printf("Operating in single character mode\n"); if (localchars) printf("Catching signals locally\n"); } printf("%s character echo\n", (mode&MODE_ECHO) ? "Local" : "Remote"); if (my_want_state_is_will(TELOPT_LFLOW)) printf("%s flow control\n", (mode&MODE_FLOW) ? "Local" : "No"); #ifdef ENCRYPTION encrypt_display(); #endif /* ENCRYPTION */ } } else { printf("No connection.\n"); } # if !defined(TN3270) printf("Escape character is '%s'.\n", control(escape)); (void) fflush(stdout); # else /* !defined(TN3270) */ if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) { printf("Escape character is '%s'.\n", control(escape)); } # if defined(unix) if ((argc >= 2) && !strcmp(argv[1], "everything")) { printf("SIGIO received %d time%s.\n", sigiocount, (sigiocount == 1)? "":"s"); if (In3270) { printf("Process ID %d, process group %d.\n", getpid(), getpgrp(getpid())); printf("Terminal input:\n"); filestuff(tin); printf("Terminal output:\n"); filestuff(tout); printf("Network socket:\n"); filestuff(net); } } if (In3270 && transcom) { printf("Transparent mode command is '%s'.\n", transcom); } # endif /* defined(unix) */ (void) fflush(stdout); if (In3270) { return 0; } # endif /* defined(TN3270) */ return 1; } #ifdef SIGINFO /* * Function that gets called when SIGINFO is received. */ + void ayt_status() { (void) call(status, "status", "notmuch", 0); } #endif unsigned long inet_addr(); int tn(argc, argv) int argc; char *argv[]; { register struct hostent *host = 0; struct sockaddr_in sin; struct servent *sp = 0; unsigned long temp; extern char *inet_ntoa(); #if defined(IP_OPTIONS) && defined(IPPROTO_IP) char *srp = 0, *strrchr(); unsigned long sourceroute(), srlen; #endif char *cmd, *hostp = 0, *portp = 0, *user = 0; /* clear the socket address prior to use */ memset((char *)&sin, 0, sizeof(sin)); if (connected) { printf("?Already connected to %s\n", hostname); setuid(getuid()); return 0; } if (argc < 2) { (void) strcpy(line, "open "); printf("(to) "); (void) fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin); makeargv(); argc = margc; argv = margv; } cmd = *argv; --argc; ++argv; while (argc) { if (strcmp(*argv, "help") == 0 || isprefix(*argv, "?")) goto usage; if (strcmp(*argv, "-l") == 0) { --argc; ++argv; if (argc == 0) goto usage; user = *argv++; --argc; continue; } if (strcmp(*argv, "-a") == 0) { --argc; ++argv; autologin = 1; continue; } if (hostp == 0) { hostp = *argv++; --argc; continue; } if (portp == 0) { portp = *argv++; --argc; continue; } usage: printf("usage: %s [-l user] [-a] host-name [port]\n", cmd); setuid(getuid()); return 0; } if (hostp == 0) goto usage; #if defined(IP_OPTIONS) && defined(IPPROTO_IP) if (hostp[0] == '@' || hostp[0] == '!') { if ((hostname = strrchr(hostp, ':')) == NULL) hostname = strrchr(hostp, '@'); hostname++; srp = 0; temp = sourceroute(hostp, &srp, &srlen); if (temp == 0) { herror(srp); setuid(getuid()); return 0; } else if (temp == -1) { printf("Bad source route option: %s\n", hostp); setuid(getuid()); return 0; } else { sin.sin_addr.s_addr = temp; sin.sin_family = AF_INET; } } else { #endif temp = inet_addr(hostp); - if (temp != (unsigned long) -1) { + if (temp != INADDR_NONE) { sin.sin_addr.s_addr = temp; sin.sin_family = AF_INET; - (void) strcpy(_hostname, hostp); + host = gethostbyaddr((char *)&temp, sizeof(temp), AF_INET); + if (host) + (void) strncpy(_hostname, host->h_name, sizeof(_hostname)); + else + (void) strncpy(_hostname, hostp, sizeof(_hostname)); + _hostname[sizeof(_hostname)-1] = '\0'; hostname = _hostname; } else { host = gethostbyname(hostp); if (host) { sin.sin_family = host->h_addrtype; #if defined(h_addr) /* In 4.3, this is a #define */ memmove((caddr_t)&sin.sin_addr, host->h_addr_list[0], host->h_length); #else /* defined(h_addr) */ memmove((caddr_t)&sin.sin_addr, host->h_addr, host->h_length); #endif /* defined(h_addr) */ strncpy(_hostname, host->h_name, sizeof(_hostname)); _hostname[sizeof(_hostname)-1] = '\0'; hostname = _hostname; } else { herror(hostp); setuid(getuid()); return 0; } } #if defined(IP_OPTIONS) && defined(IPPROTO_IP) } #endif if (portp) { if (*portp == '-') { portp++; telnetport = 1; } else telnetport = 0; sin.sin_port = atoi(portp); if (sin.sin_port == 0) { sp = getservbyname(portp, "tcp"); if (sp) sin.sin_port = sp->s_port; else { printf("%s: bad port number\n", portp); setuid(getuid()); return 0; } } else { #if !defined(htons) u_short htons P((unsigned short)); #endif /* !defined(htons) */ sin.sin_port = htons(sin.sin_port); } } else { if (sp == 0) { sp = getservbyname("telnet", "tcp"); if (sp == 0) { fprintf(stderr, "telnet: tcp/telnet: unknown service\n"); setuid(getuid()); return 0; } sin.sin_port = sp->s_port; } telnetport = 1; } printf("Trying %s...\n", inet_ntoa(sin.sin_addr)); do { net = socket(AF_INET, SOCK_STREAM, 0); setuid(getuid()); if (net < 0) { perror("telnet: socket"); return 0; } #if defined(IP_OPTIONS) && defined(IPPROTO_IP) if (srp && setsockopt(net, IPPROTO_IP, IP_OPTIONS, (char *)srp, srlen) < 0) perror("setsockopt (IP_OPTIONS)"); #endif #if defined(IPPROTO_IP) && defined(IP_TOS) { # if defined(HAS_GETTOS) 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(net, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0) && (errno != ENOPROTOOPT)) perror("telnet: setsockopt (IP_TOS) (ignored)"); } #endif /* defined(IPPROTO_IP) && defined(IP_TOS) */ if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) { perror("setsockopt (SO_DEBUG)"); } if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) { #if defined(h_addr) /* In 4.3, this is a #define */ if (host && host->h_addr_list[1]) { int oerrno = errno; fprintf(stderr, "telnet: connect to address %s: ", inet_ntoa(sin.sin_addr)); errno = oerrno; perror((char *)0); host->h_addr_list++; memmove((caddr_t)&sin.sin_addr, host->h_addr_list[0], host->h_length); (void) NetClose(net); continue; } #endif /* defined(h_addr) */ perror("telnet: Unable to connect to remote host"); return 0; } connected++; #if defined(AUTHENTICATION) || defined(ENCRYPTION) auth_encrypt_connect(connected); #endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */ } while (connected == 0); cmdrc(hostp, hostname); if (autologin && user == NULL) { struct passwd *pw; user = getenv("USER"); if (user == NULL || - (pw = getpwnam(user)) && pw->pw_uid != getuid()) { - if (pw = getpwuid(getuid())) + ((pw = getpwnam(user)) && pw->pw_uid != getuid())) { + if ((pw = getpwuid(getuid()))) user = pw->pw_name; else user = NULL; } } if (user) { env_define((unsigned char *)"USER", (unsigned char *)user); env_export((unsigned char *)"USER"); } (void) call(status, "status", "notmuch", 0); if (setjmp(peerdied) == 0) telnet(user); (void) NetClose(net); ExitString("Connection closed by foreign host.\n",1); /*NOTREACHED*/ } #define HELPINDENT (sizeof ("connect")) static char openhelp[] = "connect to a site", closehelp[] = "close current connection", logouthelp[] = "forcibly logout remote user and close the connection", quithelp[] = "exit telnet", statushelp[] = "print status information", helphelp[] = "print help information", sendhelp[] = "transmit special characters ('send ?' for more)", sethelp[] = "set operating parameters ('set ?' for more)", unsethelp[] = "unset operating parameters ('unset ?' for more)", togglestring[] ="toggle operating parameters ('toggle ?' for more)", slchelp[] = "change state of special charaters ('slc ?' for more)", displayhelp[] = "display operating parameters", #if defined(TN3270) && defined(unix) transcomhelp[] = "specify Unix command for transparent mode pipe", #endif /* defined(TN3270) && defined(unix) */ #if defined(AUTHENTICATION) authhelp[] = "turn on (off) authentication ('auth ?' for more)", #endif #ifdef ENCRYPTION encrypthelp[] = "turn on (off) encryption ('encrypt ?' for more)", #endif /* ENCRYPTION */ #if defined(unix) zhelp[] = "suspend telnet", #endif /* defined(unix) */ +#if defined(SKEY) + skeyhelp[] = "compute response to s/key challenge", +#endif shellhelp[] = "invoke a subshell", envhelp[] = "change environment variables ('environ ?' for more)", modestring[] = "try to enter line or character mode ('mode ?' for more)"; -static int help(); - static Command cmdtab[] = { { "close", closehelp, bye, 1 }, { "logout", logouthelp, logout, 1 }, { "display", displayhelp, display, 0 }, { "mode", modestring, modecmd, 0 }, { "open", openhelp, tn, 0 }, { "quit", quithelp, quit, 0 }, { "send", sendhelp, sendcmd, 0 }, { "set", sethelp, setcmd, 0 }, { "unset", unsethelp, unsetcmd, 0 }, { "status", statushelp, status, 0 }, { "toggle", togglestring, toggle, 0 }, { "slc", slchelp, slccmd, 0 }, #if defined(TN3270) && defined(unix) { "transcom", transcomhelp, settranscom, 0 }, #endif /* defined(TN3270) && defined(unix) */ #if defined(AUTHENTICATION) { "auth", authhelp, auth_cmd, 0 }, #endif #ifdef ENCRYPTION { "encrypt", encrypthelp, encrypt_cmd, 0 }, #endif /* ENCRYPTION */ #if defined(unix) { "z", zhelp, suspend, 0 }, #endif /* defined(unix) */ #if defined(TN3270) { "!", shellhelp, shell, 1 }, #else { "!", shellhelp, shell, 0 }, #endif { "environ", envhelp, env_cmd, 0 }, { "?", helphelp, help, 0 }, - 0 +#if defined(SKEY) + { "skey", skeyhelp, skey_calc, 0 }, +#endif + { 0, 0, 0, 0 } }; static char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead"; static char escapehelp[] = "deprecated command -- use 'set escape' instead"; static Command cmdtab2[] = { { "help", 0, help, 0 }, { "escape", escapehelp, setescape, 0 }, { "crmod", crmodhelp, togcrmod, 0 }, - 0 + { 0, 0, 0, 0 } }; /* * Call routine with argc, argv set from args (terminated by 0). */ /*VARARGS1*/ - static + static int call(va_alist) va_dcl { va_list ap; typedef int (*intrtn_t)(); intrtn_t routine; char *args[100]; int argno = 0; va_start(ap); routine = (va_arg(ap, intrtn_t)); while ((args[argno++] = va_arg(ap, char *)) != 0) { ; } va_end(ap); return (*routine)(argno-1, args); } static Command * getcmd(name) char *name; { Command *cm; - if (cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command))) + if ((cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command)))) return cm; return (Command *) genget(name, (char **) cmdtab2, sizeof(Command)); } void command(top, tbuf, cnt) int top; char *tbuf; int cnt; { register Command *c; setcommandmode(); if (!top) { putchar('\n'); #if defined(unix) } else { (void) signal(SIGINT, SIG_DFL); (void) signal(SIGQUIT, SIG_DFL); #endif /* defined(unix) */ } for (;;) { if (rlogin == _POSIX_VDISABLE) printf("%s> ", prompt); if (tbuf) { register char *cp; cp = line; while (cnt > 0 && (*cp++ = *tbuf++) != '\n') cnt--; tbuf = 0; if (cp == line || *--cp != '\n' || cp == line) goto getline; *cp = '\0'; if (rlogin == _POSIX_VDISABLE) printf("%s\n", line); } else { getline: if (rlogin != _POSIX_VDISABLE) printf("%s> ", prompt); if (fgets(line, sizeof(line), stdin) == NULL) { if (feof(stdin) || ferror(stdin)) { (void) quit(); /*NOTREACHED*/ } break; } } if (line[0] == 0) break; makeargv(); if (margv[0] == 0) { break; } c = getcmd(margv[0]); if (Ambiguous(c)) { printf("?Ambiguous command\n"); continue; } if (c == 0) { printf("?Invalid command\n"); continue; } if (c->needconnect && !connected) { printf("?Need to be connected first.\n"); continue; } if ((*c->handler)(margc, margv)) { break; } } if (!top) { if (!connected) { longjmp(toplevel, 1); /*NOTREACHED*/ } #if defined(TN3270) if (shell_active == 0) { setconnmode(0); } #else /* defined(TN3270) */ setconnmode(0); #endif /* defined(TN3270) */ } } /* * Help command. */ - static + static int help(argc, argv) int argc; char *argv[]; { register Command *c; if (argc == 1) { printf("Commands may be abbreviated. Commands are:\n\n"); for (c = cmdtab; c->name; c++) if (c->help) { printf("%-*s\t%s\n", HELPINDENT, c->name, c->help); } - return 0; } - while (--argc > 0) { + else while (--argc > 0) { register char *arg; arg = *++argv; c = getcmd(arg); if (Ambiguous(c)) printf("?Ambiguous help command %s\n", arg); else if (c == (Command *)0) printf("?Invalid help command %s\n", arg); else printf("%s\n", c->help); } - return 0; + return(0); } static char *rcname = 0; static char rcbuf[128]; + void cmdrc(m1, m2) char *m1, *m2; { register Command *c; FILE *rcfile; int gotmachine = 0; int l1 = strlen(m1); int l2 = strlen(m2); char m1save[64]; if (skiprc) return; strcpy(m1save, m1); m1 = m1save; if (rcname == 0) { rcname = getenv("HOME"); - if (rcname) + if (rcname && (strlen(rcname) + 10) < sizeof(rcbuf)) strcpy(rcbuf, rcname); else rcbuf[0] = '\0'; strcat(rcbuf, "/.telnetrc"); rcname = rcbuf; } if ((rcfile = fopen(rcname, "r")) == 0) { return; } for (;;) { if (fgets(line, sizeof(line), rcfile) == NULL) break; if (line[0] == 0) break; if (line[0] == '#') continue; if (gotmachine) { if (!isspace(line[0])) gotmachine = 0; } if (gotmachine == 0) { if (isspace(line[0])) continue; if (strncasecmp(line, m1, l1) == 0) strncpy(line, &line[l1], sizeof(line) - l1); else if (strncasecmp(line, m2, l2) == 0) strncpy(line, &line[l2], sizeof(line) - l2); else if (strncasecmp(line, "DEFAULT", 7) == 0) strncpy(line, &line[7], sizeof(line) - 7); else continue; if (line[0] != ' ' && line[0] != '\t' && line[0] != '\n') continue; gotmachine = 1; } makeargv(); if (margv[0] == 0) continue; c = getcmd(margv[0]); if (Ambiguous(c)) { printf("?Ambiguous command: %s\n", margv[0]); continue; } if (c == 0) { printf("?Invalid command: %s\n", margv[0]); continue; } /* * This should never happen... */ if (c->needconnect && !connected) { printf("?Need to be connected first for %s.\n", margv[0]); continue; } (*c->handler)(margc, margv); } fclose(rcfile); } #if defined(IP_OPTIONS) && defined(IPPROTO_IP) /* * Source route is handed in as * [!]@hop1@hop2...[@|:]dst * If the leading ! is present, it is a * strict source route, otherwise it is * assmed to be a loose source route. * * We fill in the source route option as * hop1,hop2,hop3...dest * and return a pointer to hop1, which will * be the address to connect() to. * * Arguments: * arg: pointer to route list to decipher * * cpp: If *cpp is not equal to NULL, this is a * pointer to a pointer to a character array * that should be filled in with the option. * * lenp: pointer to an integer that contains the * length of *cpp if *cpp != NULL. * * Return values: * * Returns the address of the host to connect to. If the * return value is -1, there was a syntax error in the * option, either unknown characters, or too many hosts. * If the return value is 0, one of the hostnames in the * path is unknown, and *cpp is set to point to the bad * hostname. * * *cpp: If *cpp was equal to NULL, it will be filled * in with a pointer to our static area that has * the option filled in. This will be 32bit aligned. * * *lenp: This will be filled in with how long the option * pointed to by *cpp is. * */ unsigned long sourceroute(arg, cpp, lenp) char *arg; char **cpp; int *lenp; { static char lsr[44]; #ifdef sysV88 static IOPTN ipopt; #endif char *cp, *cp2, *lsrp, *lsrep; register int tmp; struct in_addr sin_addr; register struct hostent *host = 0; register char c; /* * Verify the arguments, and make sure we have * at least 7 bytes for the option. */ if (cpp == NULL || lenp == NULL) return((unsigned long)-1); if (*cpp != NULL && *lenp < 7) return((unsigned long)-1); /* * Decide whether we have a buffer passed to us, * or if we need to use our own static buffer. */ if (*cpp) { lsrp = *cpp; lsrep = lsrp + *lenp; } else { *cpp = lsrp = lsr; lsrep = lsrp + 44; } cp = arg; /* * Next, decide whether we have a loose source * route or a strict source route, and fill in * the begining of the option. */ #ifndef sysV88 if (*cp == '!') { cp++; *lsrp++ = IPOPT_SSRR; } else *lsrp++ = IPOPT_LSRR; #else if (*cp == '!') { cp++; ipopt.io_type = IPOPT_SSRR; } else ipopt.io_type = IPOPT_LSRR; #endif if (*cp != '@') return((unsigned long)-1); #ifndef sysV88 lsrp++; /* skip over length, we'll fill it in later */ *lsrp++ = 4; #endif cp++; sin_addr.s_addr = 0; for (c = 0;;) { if (c == ':') cp2 = 0; - else for (cp2 = cp; c = *cp2; cp2++) { + else for (cp2 = cp; (c = *cp2); cp2++) { if (c == ',') { *cp2++ = '\0'; if (*cp2 == '@') cp2++; } else if (c == '@') { *cp2++ = '\0'; } else if (c == ':') { *cp2++ = '\0'; } else continue; break; } if (!c) cp2 = 0; if ((tmp = inet_addr(cp)) != -1) { sin_addr.s_addr = tmp; - } else if (host = gethostbyname(cp)) { + } else if ((host = gethostbyname(cp))) { #if defined(h_addr) memmove((caddr_t)&sin_addr, host->h_addr_list[0], host->h_length); #else memmove((caddr_t)&sin_addr, host->h_addr, host->h_length); #endif } else { *cpp = cp; return(0); } memmove(lsrp, (char *)&sin_addr, 4); lsrp += 4; if (cp2) cp = cp2; else break; /* * Check to make sure there is space for next address */ if (lsrp + 4 > lsrep) return((unsigned long)-1); } #ifndef sysV88 if ((*(*cpp+IPOPT_OLEN) = lsrp - *cpp) <= 7) { *cpp = 0; *lenp = 0; return((unsigned long)-1); } *lsrp++ = IPOPT_NOP; /* 32 bit word align it */ *lenp = lsrp - *cpp; #else ipopt.io_len = lsrp - *cpp; if (ipopt.io_len <= 5) { /* Is 3 better ? */ *cpp = 0; *lenp = 0; return((unsigned long)-1); } *lenp = sizeof(ipopt); *cpp = (char *) &ipopt; #endif return(sin_addr.s_addr); } #endif diff --git a/crypto/telnet/telnet/externs.h b/crypto/telnet/telnet/externs.h index 83ba07b2d486..a834c61c39df 100644 --- a/crypto/telnet/telnet/externs.h +++ b/crypto/telnet/telnet/externs.h @@ -1,482 +1,491 @@ /* * Copyright (c) 1988, 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. * * @(#)externs.h 8.3 (Berkeley) 5/30/95 */ #ifndef BSD # define BSD 43 #endif /* * ucb stdio.h defines BSD as something wierd */ #if defined(sun) && defined(__svr4__) #define BSD 43 #endif #ifndef USE_TERMIO # if BSD > 43 || defined(SYSV_TERMIO) # define USE_TERMIO # endif #endif #include #include #if defined(CRAY) && !defined(NO_BSD_SETJMP) #include #endif #ifndef FILIO_H #include #else #include #endif #ifdef CRAY # include #endif /* CRAY */ #ifdef USE_TERMIO # ifndef VINTR # ifdef SYSV_TERMIO # include # else # include # define termio termios # endif # endif #endif #if defined(NO_CC_T) || !defined(USE_TERMIO) # if !defined(USE_TERMIO) typedef char cc_t; # else typedef unsigned char cc_t; # endif #endif #ifndef NO_STRING_H #include #else #include #endif #ifndef _POSIX_VDISABLE # ifdef sun # include /* pick up VDISABLE definition, mayby */ # endif # ifdef VDISABLE # define _POSIX_VDISABLE VDISABLE # else # define _POSIX_VDISABLE ((cc_t)'\377') # endif #endif #define SUBBUFSIZE 256 #ifndef CRAY extern int errno; /* outside this world */ #endif /* !CRAY */ #if !defined(P) # ifdef __STDC__ # define P(x) x # else # define P(x) () # endif #endif extern int autologin, /* Autologin enabled */ skiprc, /* Don't process the ~/.telnetrc file */ eight, /* use eight bit mode (binary in and/or out */ flushout, /* flush output */ connected, /* Are we connected to the other side? */ globalmode, /* Mode tty should be in */ In3270, /* Are we in 3270 mode? */ telnetport, /* Are we connected to the telnet port? */ localflow, /* Flow control handled locally */ restartany, /* If flow control, restart output on any character */ localchars, /* we recognize interrupt/quit */ donelclchars, /* the user has set "localchars" */ showoptions, net, /* Network file descriptor */ tin, /* Terminal input file descriptor */ tout, /* Terminal output file descriptor */ crlf, /* Should '\r' be mapped to (or )? */ autoflush, /* flush output when interrupting? */ autosynch, /* send interrupt characters with SYNCH? */ SYNCHing, /* Is the stream in telnet SYNCH mode? */ donebinarytoggle, /* the user has put us in binary */ dontlecho, /* do we suppress local echoing right now? */ crmod, netdata, /* Print out network data flow */ prettydump, /* Print "netdata" output in user readable format */ #if defined(unix) #if defined(TN3270) cursesdata, /* Print out curses data flow */ apitrace, /* Trace API transactions */ #endif /* defined(TN3270) */ termdata, /* Print out terminal data flow */ #endif /* defined(unix) */ - debug; /* Debug level */ + debug, /* Debug level */ + clienteof; /* Client received EOF */ extern cc_t escape; /* Escape to command mode */ extern cc_t rlogin; /* Rlogin mode escape character */ #ifdef KLUDGELINEMODE extern cc_t echoc; /* Toggle local echoing */ #endif extern char *prompt; /* Prompt for command. */ extern char doopt[], dont[], will[], wont[], options[], /* All the little options */ *hostname; /* Who are we connected to? */ #ifdef ENCRYPTION extern void (*encrypt_output) P((unsigned char *, int)); extern int (*decrypt_input) P((int)); #endif /* ENCRYPTION */ /* * We keep track of each side of the option negotiation. */ #define MY_STATE_WILL 0x01 #define MY_WANT_STATE_WILL 0x02 #define MY_STATE_DO 0x04 #define MY_WANT_STATE_DO 0x08 /* * Macros to check the current state of things */ #define my_state_is_do(opt) (options[opt]&MY_STATE_DO) #define my_state_is_will(opt) (options[opt]&MY_STATE_WILL) #define my_want_state_is_do(opt) (options[opt]&MY_WANT_STATE_DO) #define my_want_state_is_will(opt) (options[opt]&MY_WANT_STATE_WILL) #define my_state_is_dont(opt) (!my_state_is_do(opt)) #define my_state_is_wont(opt) (!my_state_is_will(opt)) #define my_want_state_is_dont(opt) (!my_want_state_is_do(opt)) #define my_want_state_is_wont(opt) (!my_want_state_is_will(opt)) #define set_my_state_do(opt) {options[opt] |= MY_STATE_DO;} #define set_my_state_will(opt) {options[opt] |= MY_STATE_WILL;} #define set_my_want_state_do(opt) {options[opt] |= MY_WANT_STATE_DO;} #define set_my_want_state_will(opt) {options[opt] |= MY_WANT_STATE_WILL;} #define set_my_state_dont(opt) {options[opt] &= ~MY_STATE_DO;} #define set_my_state_wont(opt) {options[opt] &= ~MY_STATE_WILL;} #define set_my_want_state_dont(opt) {options[opt] &= ~MY_WANT_STATE_DO;} #define set_my_want_state_wont(opt) {options[opt] &= ~MY_WANT_STATE_WILL;} /* * Make everything symetrical */ #define HIS_STATE_WILL MY_STATE_DO #define HIS_WANT_STATE_WILL MY_WANT_STATE_DO #define HIS_STATE_DO MY_STATE_WILL #define HIS_WANT_STATE_DO MY_WANT_STATE_WILL #define his_state_is_do my_state_is_will #define his_state_is_will my_state_is_do #define his_want_state_is_do my_want_state_is_will #define his_want_state_is_will my_want_state_is_do #define his_state_is_dont my_state_is_wont #define his_state_is_wont my_state_is_dont #define his_want_state_is_dont my_want_state_is_wont #define his_want_state_is_wont my_want_state_is_dont #define set_his_state_do set_my_state_will #define set_his_state_will set_my_state_do #define set_his_want_state_do set_my_want_state_will #define set_his_want_state_will set_my_want_state_do #define set_his_state_dont set_my_state_wont #define set_his_state_wont set_my_state_dont #define set_his_want_state_dont set_my_want_state_wont #define set_his_want_state_wont set_my_want_state_dont extern FILE *NetTrace; /* Where debugging output goes */ extern unsigned char NetTraceFile[]; /* Name of file where debugging output goes */ extern void SetNetTrace P((char *)); /* Function to change where debugging goes */ extern jmp_buf peerdied, toplevel; /* For error conditions. */ extern void command P((int, char *, int)), Dump P((int, unsigned char *, int)), + ExitString P((char *, int)), init_3270 P((void)), printoption P((char *, int, int)), printsub P((int, unsigned char *, int)), sendnaws P((void)), setconnmode P((int)), setcommandmode P((void)), setneturg P((void)), sys_telnet_init P((void)), telnet P((char *)), tel_enter_binary P((int)), TerminalFlushOutput P((void)), TerminalNewMode P((int)), TerminalRestoreState P((void)), TerminalSaveState P((void)), tninit P((void)), upcase P((char *)), willoption P((int)), wontoption P((int)); extern void send_do P((int, int)), send_dont P((int, int)), send_will P((int, int)), send_wont P((int, int)); extern void lm_will P((unsigned char *, int)), lm_wont P((unsigned char *, int)), lm_do P((unsigned char *, int)), lm_dont P((unsigned char *, int)), lm_mode P((unsigned char *, int, int)); extern void slc_init P((void)), slcstate P((void)), slc_mode_export P((void)), slc_mode_import P((int)), slc_import P((int)), slc_export P((void)), slc P((unsigned char *, int)), slc_check P((void)), slc_start_reply P((void)), slc_add_reply P((int, int, int)), slc_end_reply P((void)); extern int - slc_update P((void)); + NetClose P((int)), + netflush P((void)), + SetSockOpt P((int, int, int, int)), + slc_update P((void)), + telrcv P((void)), + TerminalWrite P((char *, int)), + TerminalAutoFlush P((void)), + ttyflush P((int)); extern void env_opt P((unsigned char *, int)), env_opt_start P((void)), env_opt_start_info P((void)), env_opt_add P((unsigned char *)), env_opt_end P((int)); extern unsigned char *env_default P((int, int)), *env_getvalue P((unsigned char *)); extern int get_status P((void)), dosynch P((void)); extern cc_t *tcval P((int)); #ifndef USE_TERMIO extern struct tchars ntc; extern struct ltchars nltc; extern struct sgttyb nttyb; # define termEofChar ntc.t_eofc # define termEraseChar nttyb.sg_erase # define termFlushChar nltc.t_flushc # define termIntChar ntc.t_intrc # define termKillChar nttyb.sg_kill # define termLiteralNextChar nltc.t_lnextc # define termQuitChar ntc.t_quitc # define termSuspChar nltc.t_suspc # define termRprntChar nltc.t_rprntc # define termWerasChar nltc.t_werasc # define termStartChar ntc.t_startc # define termStopChar ntc.t_stopc # define termForw1Char ntc.t_brkc extern cc_t termForw2Char; extern cc_t termAytChar; # define termEofCharp (cc_t *)&ntc.t_eofc # define termEraseCharp (cc_t *)&nttyb.sg_erase # define termFlushCharp (cc_t *)&nltc.t_flushc # define termIntCharp (cc_t *)&ntc.t_intrc # define termKillCharp (cc_t *)&nttyb.sg_kill # define termLiteralNextCharp (cc_t *)&nltc.t_lnextc # define termQuitCharp (cc_t *)&ntc.t_quitc # define termSuspCharp (cc_t *)&nltc.t_suspc # define termRprntCharp (cc_t *)&nltc.t_rprntc # define termWerasCharp (cc_t *)&nltc.t_werasc # define termStartCharp (cc_t *)&ntc.t_startc # define termStopCharp (cc_t *)&ntc.t_stopc # define termForw1Charp (cc_t *)&ntc.t_brkc # define termForw2Charp (cc_t *)&termForw2Char # define termAytCharp (cc_t *)&termAytChar # else extern struct termio new_tc; # define termEofChar new_tc.c_cc[VEOF] # define termEraseChar new_tc.c_cc[VERASE] # define termIntChar new_tc.c_cc[VINTR] # define termKillChar new_tc.c_cc[VKILL] # define termQuitChar new_tc.c_cc[VQUIT] # ifndef VSUSP extern cc_t termSuspChar; # else # define termSuspChar new_tc.c_cc[VSUSP] # endif # if defined(VFLUSHO) && !defined(VDISCARD) # define VDISCARD VFLUSHO # endif # ifndef VDISCARD extern cc_t termFlushChar; # else # define termFlushChar new_tc.c_cc[VDISCARD] # endif # ifndef VWERASE extern cc_t termWerasChar; # else # define termWerasChar new_tc.c_cc[VWERASE] # endif # ifndef VREPRINT extern cc_t termRprntChar; # else # define termRprntChar new_tc.c_cc[VREPRINT] # endif # ifndef VLNEXT extern cc_t termLiteralNextChar; # else # define termLiteralNextChar new_tc.c_cc[VLNEXT] # endif # ifndef VSTART extern cc_t termStartChar; # else # define termStartChar new_tc.c_cc[VSTART] # endif # ifndef VSTOP extern cc_t termStopChar; # else # define termStopChar new_tc.c_cc[VSTOP] # endif # ifndef VEOL extern cc_t termForw1Char; # else # define termForw1Char new_tc.c_cc[VEOL] # endif # ifndef VEOL2 extern cc_t termForw2Char; # else # define termForw2Char new_tc.c_cc[VEOL] # endif # ifndef VSTATUS extern cc_t termAytChar; #else # define termAytChar new_tc.c_cc[VSTATUS] #endif # if !defined(CRAY) || defined(__STDC__) # define termEofCharp &termEofChar # define termEraseCharp &termEraseChar # define termIntCharp &termIntChar # define termKillCharp &termKillChar # define termQuitCharp &termQuitChar # define termSuspCharp &termSuspChar # define termFlushCharp &termFlushChar # define termWerasCharp &termWerasChar # define termRprntCharp &termRprntChar # define termLiteralNextCharp &termLiteralNextChar # define termStartCharp &termStartChar # define termStopCharp &termStopChar # define termForw1Charp &termForw1Char # define termForw2Charp &termForw2Char # define termAytCharp &termAytChar # else /* Work around a compiler bug */ # define termEofCharp 0 # define termEraseCharp 0 # define termIntCharp 0 # define termKillCharp 0 # define termQuitCharp 0 # define termSuspCharp 0 # define termFlushCharp 0 # define termWerasCharp 0 # define termRprntCharp 0 # define termLiteralNextCharp 0 # define termStartCharp 0 # define termStopCharp 0 # define termForw1Charp 0 # define termForw2Charp 0 # define termAytCharp 0 # endif #endif /* Ring buffer structures which are shared */ extern Ring netoring, netiring, ttyoring, ttyiring; /* Tn3270 section */ #if defined(TN3270) extern int HaveInput, /* Whether an asynchronous I/O indication came in */ noasynchtty, /* Don't do signals on I/O (SIGURG, SIGIO) */ noasynchnet, /* Don't do signals on I/O (SIGURG, SIGIO) */ sigiocount, /* Count of SIGIO receptions */ shell_active; /* Subshell is active */ extern char *Ibackp, /* Oldest byte of 3270 data */ Ibuf[], /* 3270 buffer */ *Ifrontp, /* Where next 3270 byte goes */ tline[], *transcom; /* Transparent command */ extern int settranscom P((int, char**)); extern void inputAvailable P((int)); #endif /* defined(TN3270) */ diff --git a/crypto/telnet/telnet/main.c b/crypto/telnet/telnet/main.c index 6073dbf8ec4a..9049385e200f 100644 --- a/crypto/telnet/telnet/main.c +++ b/crypto/telnet/telnet/main.c @@ -1,322 +1,337 @@ /* * Copyright (c) 1988, 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. */ #ifndef lint -static char copyright[] = +static const char copyright[] = "@(#) Copyright (c) 1988, 1990, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)main.c 8.3 (Berkeley) 5/30/95"; +static const char sccsid[] = "@(#)main.c 8.3 (Berkeley) 5/30/95"; #endif /* not lint */ #include +#include #include "ring.h" #include "externs.h" #include "defines.h" +#if defined(AUTHENTICATION) +#include +#endif +#if defined(ENCRYPTION) +#include +#endif + /* These values need to be the same as defined in libtelnet/kerberos5.c */ /* Either define them in both places, or put in some common header file. */ #define OPTS_FORWARD_CREDS 0x00000002 #define OPTS_FORWARDABLE_CREDS 0x00000001 #if 0 #define FORWARD #endif +void init_terminal(void); +void init_network(void); +void init_telnet(void); +void init_sys(void); +void init_3270(void); + /* * Initialize variables. */ void tninit() { init_terminal(); init_network(); init_telnet(); init_sys(); #if defined(TN3270) init_3270(); #endif } void usage() { fprintf(stderr, "Usage: %s %s%s%s%s\n", prompt, #ifdef AUTHENTICATION "[-8] [-E] [-K] [-L] [-S tos] [-X atype] [-a] [-c] [-d] [-e char]", "\n\t[-k realm] [-l user] [-f/-F] [-n tracefile] ", #else "[-8] [-E] [-L] [-S tos] [-a] [-c] [-d] [-e char] [-l user]", "\n\t[-n tracefile]", #endif #if defined(TN3270) && defined(unix) # ifdef AUTHENTICATION "[-noasynch] [-noasynctty]\n\t[-noasyncnet] [-r] [-t transcom] ", # else "[-noasynch] [-noasynctty] [-noasyncnet] [-r]\n\t[-t transcom]", # endif #else "[-r] ", #endif #ifdef ENCRYPTION "[-x] [host-name [port]]" #else /* ENCRYPTION */ "[host-name [port]]" #endif /* ENCRYPTION */ ); exit(1); } /* * main. Parse arguments, invoke the protocol or command parser. */ - + int main(argc, argv) int argc; char *argv[]; { extern char *optarg; extern int optind; int ch; char *user, *strrchr(); #ifdef FORWARD extern int forward_flags; #endif /* FORWARD */ tninit(); /* Clear out things */ #if defined(CRAY) && !defined(__STDC__) _setlist_init(); /* Work around compiler bug */ #endif TerminalSaveState(); - if (prompt = strrchr(argv[0], '/')) + if ((prompt = strrchr(argv[0], '/'))) ++prompt; else prompt = argv[0]; user = NULL; rlogin = (strncmp(prompt, "rlog", 4) == 0) ? '~' : _POSIX_VDISABLE; autologin = -1; while ((ch = getopt(argc, argv, "8EKLS:X:acde:fFk:l:n:rt:x")) != EOF) { switch(ch) { case '8': eight = 3; /* binary output and input */ break; case 'E': rlogin = escape = _POSIX_VDISABLE; break; case 'K': #ifdef AUTHENTICATION autologin = 0; #endif break; case 'L': eight |= 2; /* binary output only */ break; case 'S': { #ifdef HAS_GETTOS extern int tos; if ((tos = parsetos(optarg, "tcp")) < 0) fprintf(stderr, "%s%s%s%s\n", prompt, ": Bad TOS argument '", optarg, "; will try to use default TOS"); #else fprintf(stderr, "%s: Warning: -S ignored, no parsetos() support.\n", prompt); #endif } break; case 'X': #ifdef AUTHENTICATION auth_disable_name(optarg); #endif break; case 'a': autologin = 1; break; case 'c': skiprc = 1; break; case 'd': debug = 1; break; case 'e': set_escape_char(optarg); break; case 'f': #if defined(AUTHENTICATION) && defined(KRB5) && defined(FORWARD) if (forward_flags & OPTS_FORWARD_CREDS) { fprintf(stderr, "%s: Only one of -f and -F allowed.\n", prompt); usage(); } forward_flags |= OPTS_FORWARD_CREDS; #else fprintf(stderr, "%s: Warning: -f ignored, no Kerberos V5 support.\n", prompt); #endif break; case 'F': #if defined(AUTHENTICATION) && defined(KRB5) && defined(FORWARD) if (forward_flags & OPTS_FORWARD_CREDS) { fprintf(stderr, "%s: Only one of -f and -F allowed.\n", prompt); usage(); } forward_flags |= OPTS_FORWARD_CREDS; forward_flags |= OPTS_FORWARDABLE_CREDS; #else fprintf(stderr, "%s: Warning: -F ignored, no Kerberos V5 support.\n", prompt); #endif break; case 'k': #if defined(AUTHENTICATION) && defined(KRB4) { extern char *dest_realm, dst_realm_buf[], dst_realm_sz; dest_realm = dst_realm_buf; (void)strncpy(dest_realm, optarg, dst_realm_sz); } #else fprintf(stderr, "%s: Warning: -k ignored, no Kerberos V4 support.\n", prompt); #endif break; case 'l': autologin = 1; user = optarg; break; case 'n': #if defined(TN3270) && defined(unix) /* distinguish between "-n oasynch" and "-noasynch" */ if (argv[optind - 1][0] == '-' && argv[optind - 1][1] == 'n' && argv[optind - 1][2] == 'o') { if (!strcmp(optarg, "oasynch")) { noasynchtty = 1; noasynchnet = 1; } else if (!strcmp(optarg, "oasynchtty")) noasynchtty = 1; else if (!strcmp(optarg, "oasynchnet")) noasynchnet = 1; } else #endif /* defined(TN3270) && defined(unix) */ SetNetTrace(optarg); break; case 'r': rlogin = '~'; break; case 't': #if defined(TN3270) && defined(unix) transcom = tline; (void)strcpy(transcom, optarg); #else fprintf(stderr, "%s: Warning: -t ignored, no TN3270 support.\n", prompt); #endif break; case 'x': #ifdef ENCRYPTION encrypt_auto(1); decrypt_auto(1); #else /* ENCRYPTION */ fprintf(stderr, "%s: Warning: -x ignored, no ENCRYPT support.\n", prompt); #endif /* ENCRYPTION */ break; case '?': default: usage(); /* NOTREACHED */ } } if (autologin == -1) autologin = (rlogin == _POSIX_VDISABLE) ? 0 : 1; argc -= optind; argv += optind; if (argc) { char *args[7], **argp = args; if (argc > 2) usage(); *argp++ = prompt; if (user) { *argp++ = "-l"; *argp++ = user; } *argp++ = argv[0]; /* host */ if (argc > 1) *argp++ = argv[1]; /* port */ *argp = 0; if (setjmp(toplevel) != 0) Exit(0); if (tn(argp - args, args) == 1) return (0); else return (1); } (void)setjmp(toplevel); for (;;) { #ifdef TN3270 if (shell_active) shell_continue(); else #endif command(1, 0, 0); } + return 0; } diff --git a/crypto/telnet/telnet/network.c b/crypto/telnet/telnet/network.c index 0fe5cee0be4c..9964bc205cef 100644 --- a/crypto/telnet/telnet/network.c +++ b/crypto/telnet/telnet/network.c @@ -1,177 +1,178 @@ /* * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. */ #ifndef lint -static char sccsid[] = "@(#)network.c 8.2 (Berkeley) 12/15/93"; +static const char sccsid[] = "@(#)network.c 8.2 (Berkeley) 12/15/93"; #endif /* not lint */ #include #include #include #include #include +#include #include "ring.h" #include "defines.h" #include "externs.h" #include "fdset.h" Ring netoring, netiring; unsigned char netobuf[2*BUFSIZ], netibuf[BUFSIZ]; /* * Initialize internal network data structures. */ void init_network() { if (ring_init(&netoring, netobuf, sizeof netobuf) != 1) { exit(1); } if (ring_init(&netiring, netibuf, sizeof netibuf) != 1) { exit(1); } NetTrace = stdout; } /* * Check to see if any out-of-band data exists on a socket (for * Telnet "synch" processing). */ int stilloob() { static struct timeval timeout = { 0 }; fd_set excepts; int value; do { FD_ZERO(&excepts); FD_SET(net, &excepts); value = select(net+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout); } while ((value == -1) && (errno == EINTR)); if (value < 0) { perror("select"); (void) quit(); /* NOTREACHED */ } if (FD_ISSET(net, &excepts)) { return 1; } else { return 0; } } /* * setneturg() * * Sets "neturg" to the current location. */ void setneturg() { ring_mark(&netoring); } /* * netflush * Send as much data as possible to the network, * handling requests for urgent data. * * The return value indicates whether we did any * useful work. */ int netflush() { register int n, n1; #ifdef ENCRYPTION if (encrypt_output) ring_encrypt(&netoring, encrypt_output); #endif /* ENCRYPTION */ if ((n1 = n = ring_full_consecutive(&netoring)) > 0) { if (!ring_at_mark(&netoring)) { n = send(net, (char *)netoring.consume, n, 0); /* normal write */ } else { /* * In 4.2 (and 4.3) systems, there is some question about * what byte in a sendOOB operation is the "OOB" data. * To make ourselves compatible, we only send ONE byte * out of band, the one WE THINK should be OOB (though * we really have more the TCP philosophy of urgent data * rather than the Unix philosophy of OOB data). */ n = send(net, (char *)netoring.consume, 1, MSG_OOB);/* URGENT data */ } } if (n < 0) { if (errno != ENOBUFS && errno != EWOULDBLOCK) { setcommandmode(); perror(hostname); (void)NetClose(net); ring_clear_mark(&netoring); longjmp(peerdied, -1); /*NOTREACHED*/ } n = 0; } if (netdata && n) { Dump('>', netoring.consume, n); } if (n) { ring_consumed(&netoring, n); /* * If we sent all, and more to send, then recurse to pick * up the other half. */ if ((n1 == n) && ring_full_consecutive(&netoring)) { (void) netflush(); } return 1; } else { return 0; } } diff --git a/crypto/telnet/telnet/ring.c b/crypto/telnet/telnet/ring.c index 37dfda8bc499..13fe6c2b79cb 100644 --- a/crypto/telnet/telnet/ring.c +++ b/crypto/telnet/telnet/ring.c @@ -1,362 +1,364 @@ /* * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. */ #ifndef lint -static char sccsid[] = "@(#)ring.c 8.2 (Berkeley) 5/30/95"; +static const char sccsid[] = "@(#)ring.c 8.2 (Berkeley) 5/30/95"; #endif /* not lint */ /* * This defines a structure for a ring buffer. * * The circular buffer has two parts: *((( * full: [consume, supply) * empty: [supply, consume) *]]] * */ #include #include +#include #ifdef size_t #undef size_t #endif #include #ifndef FILIO_H #include #endif #include #include "ring.h" #include "general.h" /* Internal macros */ #if !defined(MIN) #define MIN(a,b) (((a)<(b))? (a):(b)) #endif /* !defined(MIN) */ #define ring_subtract(d,a,b) (((a)-(b) >= 0)? \ (a)-(b): (((a)-(b))+(d)->size)) #define ring_increment(d,a,c) (((a)+(c) < (d)->top)? \ (a)+(c) : (((a)+(c))-(d)->size)) #define ring_decrement(d,a,c) (((a)-(c) >= (d)->bottom)? \ (a)-(c) : (((a)-(c))-(d)->size)) /* * The following is a clock, used to determine full, empty, etc. * * There is some trickiness here. Since the ring buffers are initialized * to ZERO on allocation, we need to make sure, when interpreting the * clock, that when the times are EQUAL, then the buffer is FULL. */ static u_long ring_clock = 0; #define ring_empty(d) (((d)->consume == (d)->supply) && \ ((d)->consumetime >= (d)->supplytime)) #define ring_full(d) (((d)->supply == (d)->consume) && \ ((d)->supplytime > (d)->consumetime)) /* Buffer state transition routines */ + int ring_init(ring, buffer, count) Ring *ring; unsigned char *buffer; int count; { memset((char *)ring, 0, sizeof *ring); ring->size = count; ring->supply = ring->consume = ring->bottom = buffer; ring->top = ring->bottom+ring->size; #ifdef ENCRYPTION ring->clearto = 0; #endif /* ENCRYPTION */ return 1; } /* Mark routines */ /* * Mark the most recently supplied byte. */ void ring_mark(ring) Ring *ring; { ring->mark = ring_decrement(ring, ring->supply, 1); } /* * Is the ring pointing to the mark? */ int ring_at_mark(ring) Ring *ring; { if (ring->mark == ring->consume) { return 1; } else { return 0; } } /* * Clear any mark set on the ring. */ void ring_clear_mark(ring) Ring *ring; { ring->mark = 0; } /* * Add characters from current segment to ring buffer. */ void ring_supplied(ring, count) Ring *ring; int count; { ring->supply = ring_increment(ring, ring->supply, count); ring->supplytime = ++ring_clock; } /* * We have just consumed "c" bytes. */ void ring_consumed(ring, count) Ring *ring; int count; { if (count == 0) /* don't update anything */ return; if (ring->mark && (ring_subtract(ring, ring->mark, ring->consume) < count)) { ring->mark = 0; } #ifdef ENCRYPTION if (ring->consume < ring->clearto && ring->clearto <= ring->consume + count) ring->clearto = 0; else if (ring->consume + count > ring->top && ring->bottom <= ring->clearto && ring->bottom + ((ring->consume + count) - ring->top)) ring->clearto = 0; #endif /* ENCRYPTION */ ring->consume = ring_increment(ring, ring->consume, count); ring->consumetime = ++ring_clock; /* * Try to encourage "ring_empty_consecutive()" to be large. */ if (ring_empty(ring)) { ring->consume = ring->supply = ring->bottom; } } /* Buffer state query routines */ /* Number of bytes that may be supplied */ int ring_empty_count(ring) Ring *ring; { if (ring_empty(ring)) { /* if empty */ return ring->size; } else { return ring_subtract(ring, ring->consume, ring->supply); } } /* number of CONSECUTIVE bytes that may be supplied */ int ring_empty_consecutive(ring) Ring *ring; { if ((ring->consume < ring->supply) || ring_empty(ring)) { /* * if consume is "below" supply, or empty, then * return distance to the top */ return ring_subtract(ring, ring->top, ring->supply); } else { /* * else, return what we may. */ return ring_subtract(ring, ring->consume, ring->supply); } } /* Return the number of bytes that are available for consuming * (but don't give more than enough to get to cross over set mark) */ int ring_full_count(ring) Ring *ring; { if ((ring->mark == 0) || (ring->mark == ring->consume)) { if (ring_full(ring)) { return ring->size; /* nothing consumed, but full */ } else { return ring_subtract(ring, ring->supply, ring->consume); } } else { return ring_subtract(ring, ring->mark, ring->consume); } } /* * Return the number of CONSECUTIVE bytes available for consuming. * However, don't return more than enough to cross over set mark. */ int ring_full_consecutive(ring) Ring *ring; { if ((ring->mark == 0) || (ring->mark == ring->consume)) { if ((ring->supply < ring->consume) || ring_full(ring)) { return ring_subtract(ring, ring->top, ring->consume); } else { return ring_subtract(ring, ring->supply, ring->consume); } } else { if (ring->mark < ring->consume) { return ring_subtract(ring, ring->top, ring->consume); } else { /* Else, distance to mark */ return ring_subtract(ring, ring->mark, ring->consume); } } } /* * Move data into the "supply" portion of of the ring buffer. */ void ring_supply_data(ring, buffer, count) Ring *ring; unsigned char *buffer; int count; { int i; while (count) { i = MIN(count, ring_empty_consecutive(ring)); memmove(ring->supply, buffer, i); ring_supplied(ring, i); count -= i; buffer += i; } } #ifdef notdef /* * Move data from the "consume" portion of the ring buffer */ void ring_consume_data(ring, buffer, count) Ring *ring; unsigned char *buffer; int count; { int i; while (count) { i = MIN(count, ring_full_consecutive(ring)); memmove(buffer, ring->consume, i); ring_consumed(ring, i); count -= i; buffer += i; } } #endif #ifdef ENCRYPTION void ring_encrypt(ring, encryptor) Ring *ring; void (*encryptor)(); { unsigned char *s, *c; if (ring_empty(ring) || ring->clearto == ring->supply) return; if (!(c = ring->clearto)) c = ring->consume; s = ring->supply; if (s <= c) { (*encryptor)(c, ring->top - c); (*encryptor)(ring->bottom, s - ring->bottom); } else (*encryptor)(c, s - c); ring->clearto = ring->supply; } void ring_clearto(ring) Ring *ring; { if (!ring_empty(ring)) ring->clearto = ring->supply; else ring->clearto = 0; } #endif /* ENCRYPTION */ diff --git a/crypto/telnet/telnet/sys_bsd.c b/crypto/telnet/telnet/sys_bsd.c index f2769acbade7..ed5f459e957c 100644 --- a/crypto/telnet/telnet/sys_bsd.c +++ b/crypto/telnet/telnet/sys_bsd.c @@ -1,1220 +1,1221 @@ /* * Copyright (c) 1988, 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. */ #ifndef lint -static char sccsid[] = "@(#)sys_bsd.c 8.4 (Berkeley) 5/30/95"; +static const char sccsid[] = "@(#)sys_bsd.c 8.4 (Berkeley) 5/30/95"; #endif /* not lint */ /* * The following routines try to encapsulate what is system dependent * (at least between 4.x and dos) which is used in telnet.c. */ #include #include #include #include #include #include #include +#include #include "ring.h" #include "fdset.h" #include "defines.h" #include "externs.h" #include "types.h" #if defined(CRAY) || (defined(USE_TERMIO) && !defined(SYSV_TERMIO)) #define SIG_FUNC_RET void #else #define SIG_FUNC_RET int #endif #ifdef SIGINFO extern SIG_FUNC_RET ayt_status(); #endif int tout, /* Output file descriptor */ tin, /* Input file descriptor */ net; #ifndef USE_TERMIO struct tchars otc = { 0 }, ntc = { 0 }; struct ltchars oltc = { 0 }, nltc = { 0 }; struct sgttyb ottyb = { 0 }, nttyb = { 0 }; int olmode = 0; # define cfgetispeed(ptr) (ptr)->sg_ispeed # define cfgetospeed(ptr) (ptr)->sg_ospeed # define old_tc ottyb #else /* USE_TERMIO */ struct termio old_tc = { 0 }; extern struct termio new_tc; # ifndef TCSANOW # ifdef TCSETS # define TCSANOW TCSETS # define TCSADRAIN TCSETSW # define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t) # else # ifdef TCSETA # define TCSANOW TCSETA # define TCSADRAIN TCSETAW # define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t) # else # define TCSANOW TIOCSETA # define TCSADRAIN TIOCSETAW # define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t) # endif # endif # define tcsetattr(f, a, t) ioctl(f, a, (char *)t) # define cfgetospeed(ptr) ((ptr)->c_cflag&CBAUD) # ifdef CIBAUD # define cfgetispeed(ptr) (((ptr)->c_cflag&CIBAUD) >> IBSHIFT) # else # define cfgetispeed(ptr) cfgetospeed(ptr) # endif # endif /* TCSANOW */ # ifdef sysV88 # define TIOCFLUSH TC_PX_DRAIN # endif #endif /* USE_TERMIO */ static fd_set ibits, obits, xbits; void init_sys() { tout = fileno(stdout); tin = fileno(stdin); FD_ZERO(&ibits); FD_ZERO(&obits); FD_ZERO(&xbits); errno = 0; } int TerminalWrite(buf, n) char *buf; int n; { return write(tout, buf, n); } int TerminalRead(buf, n) - unsigned char *buf; + char *buf; int n; { return read(tin, buf, n); } /* * */ int TerminalAutoFlush() { #if defined(LNOFLSH) int flush; ioctl(0, TIOCLGET, (char *)&flush); return !(flush&LNOFLSH); /* if LNOFLSH, no autoflush */ #else /* LNOFLSH */ return 1; #endif /* LNOFLSH */ } #ifdef KLUDGELINEMODE extern int kludgelinemode; #endif /* * TerminalSpecialChars() * * Look at an input character to see if it is a special character * and decide what to do. * * Output: * * 0 Don't add this character. * 1 Do add this character */ extern void xmitAO(), xmitEL(), xmitEC(), intp(), sendbrk(); int TerminalSpecialChars(c) int c; { if (c == termIntChar) { intp(); return 0; } else if (c == termQuitChar) { #ifdef KLUDGELINEMODE if (kludgelinemode) sendbrk(); else #endif sendabort(); return 0; } else if (c == termEofChar) { if (my_want_state_is_will(TELOPT_LINEMODE)) { sendeof(); return 0; } return 1; } else if (c == termSuspChar) { sendsusp(); return(0); } else if (c == termFlushChar) { xmitAO(); /* Transmit Abort Output */ return 0; } else if (!MODE_LOCAL_CHARS(globalmode)) { if (c == termKillChar) { xmitEL(); return 0; } else if (c == termEraseChar) { xmitEC(); /* Transmit Erase Character */ return 0; } } return 1; } /* * Flush output to the terminal */ void TerminalFlushOutput() { #ifdef TIOCFLUSH (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0); #else (void) ioctl(fileno(stdout), TCFLSH, (char *) 0); #endif } void TerminalSaveState() { #ifndef USE_TERMIO ioctl(0, TIOCGETP, (char *)&ottyb); ioctl(0, TIOCGETC, (char *)&otc); ioctl(0, TIOCGLTC, (char *)&oltc); ioctl(0, TIOCLGET, (char *)&olmode); ntc = otc; nltc = oltc; nttyb = ottyb; #else /* USE_TERMIO */ tcgetattr(0, &old_tc); new_tc = old_tc; #ifndef VDISCARD termFlushChar = CONTROL('O'); #endif #ifndef VWERASE termWerasChar = CONTROL('W'); #endif #ifndef VREPRINT termRprntChar = CONTROL('R'); #endif #ifndef VLNEXT termLiteralNextChar = CONTROL('V'); #endif #ifndef VSTART termStartChar = CONTROL('Q'); #endif #ifndef VSTOP termStopChar = CONTROL('S'); #endif #ifndef VSTATUS termAytChar = CONTROL('T'); #endif #endif /* USE_TERMIO */ } cc_t * tcval(func) register int func; { switch(func) { case SLC_IP: return(&termIntChar); case SLC_ABORT: return(&termQuitChar); case SLC_EOF: return(&termEofChar); case SLC_EC: return(&termEraseChar); case SLC_EL: return(&termKillChar); case SLC_XON: return(&termStartChar); case SLC_XOFF: return(&termStopChar); case SLC_FORW1: return(&termForw1Char); #ifdef USE_TERMIO case SLC_FORW2: return(&termForw2Char); # ifdef VDISCARD case SLC_AO: return(&termFlushChar); # endif # ifdef VSUSP case SLC_SUSP: return(&termSuspChar); # endif # ifdef VWERASE case SLC_EW: return(&termWerasChar); # endif # ifdef VREPRINT case SLC_RP: return(&termRprntChar); # endif # ifdef VLNEXT case SLC_LNEXT: return(&termLiteralNextChar); # endif # ifdef VSTATUS case SLC_AYT: return(&termAytChar); # endif #endif case SLC_SYNCH: case SLC_BRK: case SLC_EOR: default: return((cc_t *)0); } } void TerminalDefaultChars() { #ifndef USE_TERMIO ntc = otc; nltc = oltc; nttyb.sg_kill = ottyb.sg_kill; nttyb.sg_erase = ottyb.sg_erase; #else /* USE_TERMIO */ memmove(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc)); # ifndef VDISCARD termFlushChar = CONTROL('O'); # endif # ifndef VWERASE termWerasChar = CONTROL('W'); # endif # ifndef VREPRINT termRprntChar = CONTROL('R'); # endif # ifndef VLNEXT termLiteralNextChar = CONTROL('V'); # endif # ifndef VSTART termStartChar = CONTROL('Q'); # endif # ifndef VSTOP termStopChar = CONTROL('S'); # endif # ifndef VSTATUS termAytChar = CONTROL('T'); # endif #endif /* USE_TERMIO */ } #ifdef notdef void TerminalRestoreState() { } #endif /* * TerminalNewMode - set up terminal to a specific mode. * MODE_ECHO: do local terminal echo * MODE_FLOW: do local flow control * MODE_TRAPSIG: do local mapping to TELNET IAC sequences * MODE_EDIT: do local line editing * * Command mode: * MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG * local echo * local editing * local xon/xoff * local signal mapping * * Linemode: * local/no editing * Both Linemode and Single Character mode: * local/remote echo * local/no xon/xoff * local/no signal mapping */ void TerminalNewMode(f) register int f; { static int prevmode = 0; #ifndef USE_TERMIO struct tchars tc; struct ltchars ltc; struct sgttyb sb; int lmode; #else /* USE_TERMIO */ struct termio tmp_tc; #endif /* USE_TERMIO */ int onoff; int old; cc_t esc; globalmode = f&~MODE_FORCE; if (prevmode == f) return; /* * Write any outstanding data before switching modes * ttyflush() returns 0 only when there is no more data * left to write out, it returns -1 if it couldn't do * anything at all, otherwise it returns 1 + the number * of characters left to write. #ifndef USE_TERMIO * We would really like ask the kernel to wait for the output * to drain, like we can do with the TCSADRAIN, but we don't have * that option. The only ioctl that waits for the output to * drain, TIOCSETP, also flushes the input queue, which is NOT * what we want (TIOCSETP is like TCSADFLUSH). #endif */ old = ttyflush(SYNCHing|flushout); if (old < 0 || old > 1) { #ifdef USE_TERMIO tcgetattr(tin, &tmp_tc); #endif /* USE_TERMIO */ do { /* * Wait for data to drain, then flush again. */ #ifdef USE_TERMIO tcsetattr(tin, TCSADRAIN, &tmp_tc); #endif /* USE_TERMIO */ old = ttyflush(SYNCHing|flushout); } while (old < 0 || old > 1); } old = prevmode; prevmode = f&~MODE_FORCE; #ifndef USE_TERMIO sb = nttyb; tc = ntc; ltc = nltc; lmode = olmode; #else tmp_tc = new_tc; #endif if (f&MODE_ECHO) { #ifndef USE_TERMIO sb.sg_flags |= ECHO; #else tmp_tc.c_lflag |= ECHO; tmp_tc.c_oflag |= ONLCR; if (crlf) tmp_tc.c_iflag |= ICRNL; #endif } else { #ifndef USE_TERMIO sb.sg_flags &= ~ECHO; #else tmp_tc.c_lflag &= ~ECHO; tmp_tc.c_oflag &= ~ONLCR; # ifdef notdef if (crlf) tmp_tc.c_iflag &= ~ICRNL; # endif #endif } if ((f&MODE_FLOW) == 0) { #ifndef USE_TERMIO tc.t_startc = _POSIX_VDISABLE; tc.t_stopc = _POSIX_VDISABLE; #else tmp_tc.c_iflag &= ~(IXOFF|IXON); /* Leave the IXANY bit alone */ } else { if (restartany < 0) { tmp_tc.c_iflag |= IXOFF|IXON; /* Leave the IXANY bit alone */ } else if (restartany > 0) { tmp_tc.c_iflag |= IXOFF|IXON|IXANY; } else { tmp_tc.c_iflag |= IXOFF|IXON; tmp_tc.c_iflag &= ~IXANY; } #endif } if ((f&MODE_TRAPSIG) == 0) { #ifndef USE_TERMIO tc.t_intrc = _POSIX_VDISABLE; tc.t_quitc = _POSIX_VDISABLE; tc.t_eofc = _POSIX_VDISABLE; ltc.t_suspc = _POSIX_VDISABLE; ltc.t_dsuspc = _POSIX_VDISABLE; #else tmp_tc.c_lflag &= ~ISIG; #endif localchars = 0; } else { #ifdef USE_TERMIO tmp_tc.c_lflag |= ISIG; #endif localchars = 1; } if (f&MODE_EDIT) { #ifndef USE_TERMIO sb.sg_flags &= ~CBREAK; sb.sg_flags |= CRMOD; #else tmp_tc.c_lflag |= ICANON; #endif } else { #ifndef USE_TERMIO sb.sg_flags |= CBREAK; if (f&MODE_ECHO) sb.sg_flags |= CRMOD; else sb.sg_flags &= ~CRMOD; #else tmp_tc.c_lflag &= ~ICANON; tmp_tc.c_iflag &= ~ICRNL; tmp_tc.c_cc[VMIN] = 1; tmp_tc.c_cc[VTIME] = 0; #endif } if ((f&(MODE_EDIT|MODE_TRAPSIG)) == 0) { #ifndef USE_TERMIO ltc.t_lnextc = _POSIX_VDISABLE; #else # ifdef VLNEXT tmp_tc.c_cc[VLNEXT] = (cc_t)(_POSIX_VDISABLE); # endif #endif } if (f&MODE_SOFT_TAB) { #ifndef USE_TERMIO sb.sg_flags |= XTABS; #else # ifdef OXTABS tmp_tc.c_oflag |= OXTABS; # endif # ifdef TABDLY tmp_tc.c_oflag &= ~TABDLY; tmp_tc.c_oflag |= TAB3; # endif #endif } else { #ifndef USE_TERMIO sb.sg_flags &= ~XTABS; #else # ifdef OXTABS tmp_tc.c_oflag &= ~OXTABS; # endif # ifdef TABDLY tmp_tc.c_oflag &= ~TABDLY; # endif #endif } if (f&MODE_LIT_ECHO) { #ifndef USE_TERMIO lmode &= ~LCTLECH; #else # ifdef ECHOCTL tmp_tc.c_lflag &= ~ECHOCTL; # endif #endif } else { #ifndef USE_TERMIO lmode |= LCTLECH; #else # ifdef ECHOCTL tmp_tc.c_lflag |= ECHOCTL; # endif #endif } if (f == -1) { onoff = 0; } else { #ifndef USE_TERMIO if (f & MODE_OUTBIN) lmode |= LLITOUT; else lmode &= ~LLITOUT; if (f & MODE_INBIN) lmode |= LPASS8; else lmode &= ~LPASS8; #else if (f & MODE_INBIN) tmp_tc.c_iflag &= ~ISTRIP; else tmp_tc.c_iflag |= ISTRIP; if (f & MODE_OUTBIN) { tmp_tc.c_cflag &= ~(CSIZE|PARENB); tmp_tc.c_cflag |= CS8; tmp_tc.c_oflag &= ~OPOST; } else { tmp_tc.c_cflag &= ~(CSIZE|PARENB); tmp_tc.c_cflag |= old_tc.c_cflag & (CSIZE|PARENB); tmp_tc.c_oflag |= OPOST; } #endif onoff = 1; } if (f != -1) { #ifdef SIGTSTP SIG_FUNC_RET susp(); #endif /* SIGTSTP */ #ifdef SIGINFO SIG_FUNC_RET ayt(); #endif #ifdef SIGTSTP (void) signal(SIGTSTP, susp); #endif /* SIGTSTP */ #ifdef SIGINFO (void) signal(SIGINFO, ayt); #endif #if defined(USE_TERMIO) && defined(NOKERNINFO) tmp_tc.c_lflag |= NOKERNINFO; #endif /* * We don't want to process ^Y here. It's just another * character that we'll pass on to the back end. It has * to process it because it will be processed when the * user attempts to read it, not when we send it. */ #ifndef USE_TERMIO ltc.t_dsuspc = _POSIX_VDISABLE; #else # ifdef VDSUSP tmp_tc.c_cc[VDSUSP] = (cc_t)(_POSIX_VDISABLE); # endif #endif #ifdef USE_TERMIO /* * If the VEOL character is already set, then use VEOL2, * otherwise use VEOL. */ esc = (rlogin != _POSIX_VDISABLE) ? rlogin : escape; if ((tmp_tc.c_cc[VEOL] != esc) # ifdef VEOL2 && (tmp_tc.c_cc[VEOL2] != esc) # endif ) { if (tmp_tc.c_cc[VEOL] == (cc_t)(_POSIX_VDISABLE)) tmp_tc.c_cc[VEOL] = esc; # ifdef VEOL2 else if (tmp_tc.c_cc[VEOL2] == (cc_t)(_POSIX_VDISABLE)) tmp_tc.c_cc[VEOL2] = esc; # endif } #else if (tc.t_brkc == (cc_t)(_POSIX_VDISABLE)) tc.t_brkc = esc; #endif } else { #ifdef SIGINFO SIG_FUNC_RET ayt_status(); (void) signal(SIGINFO, ayt_status); #endif #ifdef SIGTSTP (void) signal(SIGTSTP, SIG_DFL); # ifndef SOLARIS (void) sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1))); # else SOLARIS (void) sigrelse(SIGTSTP); # endif SOLARIS #endif /* SIGTSTP */ #ifndef USE_TERMIO ltc = oltc; tc = otc; sb = ottyb; lmode = olmode; #else tmp_tc = old_tc; #endif } #ifndef USE_TERMIO ioctl(tin, TIOCLSET, (char *)&lmode); ioctl(tin, TIOCSLTC, (char *)<c); ioctl(tin, TIOCSETC, (char *)&tc); ioctl(tin, TIOCSETN, (char *)&sb); #else if (tcsetattr(tin, TCSADRAIN, &tmp_tc) < 0) tcsetattr(tin, TCSANOW, &tmp_tc); #endif #if (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) # if !defined(sysV88) ioctl(tin, FIONBIO, (char *)&onoff); ioctl(tout, FIONBIO, (char *)&onoff); # endif #endif /* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */ #if defined(TN3270) if (noasynchtty == 0) { ioctl(tin, FIOASYNC, (char *)&onoff); } #endif /* defined(TN3270) */ } /* * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD). */ #if B4800 != 4800 #define DECODE_BAUD #endif #ifdef DECODE_BAUD #ifndef B7200 #define B7200 B4800 #endif #ifndef B14400 #define B14400 B9600 #endif #ifndef B19200 # define B19200 B14400 #endif #ifndef B28800 #define B28800 B19200 #endif #ifndef B38400 # define B38400 B28800 #endif #ifndef B57600 #define B57600 B38400 #endif #ifndef B76800 #define B76800 B57600 #endif #ifndef B115200 #define B115200 B76800 #endif #ifndef B230400 #define B230400 B115200 #endif /* * This code assumes that the values B0, B50, B75... * are in ascending order. They do not have to be * contiguous. */ struct termspeeds { long speed; long 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 }, { 7200, B7200 }, { 9600, B9600 }, { 14400, B14400 }, { 19200, B19200 }, { 28800, B28800 }, { 38400, B38400 }, { 57600, B57600 }, { 115200, B115200 }, { 230400, B230400 }, { -1, B230400 } }; #endif /* DECODE_BAUD */ void TerminalSpeeds(ispeed, ospeed) long *ispeed; long *ospeed; { #ifdef DECODE_BAUD register struct termspeeds *tp; #endif /* DECODE_BAUD */ register long in, out; out = cfgetospeed(&old_tc); in = cfgetispeed(&old_tc); if (in == 0) in = out; #ifdef DECODE_BAUD tp = termspeeds; while ((tp->speed != -1) && (tp->value < in)) tp++; *ispeed = tp->speed; tp = termspeeds; while ((tp->speed != -1) && (tp->value < out)) tp++; *ospeed = tp->speed; #else /* DECODE_BAUD */ *ispeed = in; *ospeed = out; #endif /* DECODE_BAUD */ } int TerminalWindowSize(rows, cols) long *rows, *cols; { #ifdef TIOCGWINSZ struct winsize ws; if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) >= 0) { *rows = ws.ws_row; *cols = ws.ws_col; return 1; } #endif /* TIOCGWINSZ */ return 0; } int NetClose(fd) int fd; { return close(fd); } void NetNonblockingIO(fd, onoff) int fd; int onoff; { ioctl(fd, FIONBIO, (char *)&onoff); } #if defined(TN3270) void NetSigIO(fd, onoff) int fd; int onoff; { ioctl(fd, FIOASYNC, (char *)&onoff); /* hear about input */ } void NetSetPgrp(fd) int fd; { int myPid; myPid = getpid(); fcntl(fd, F_SETOWN, myPid); } #endif /*defined(TN3270)*/ /* * Various signal handling routines. */ /* ARGSUSED */ SIG_FUNC_RET deadpeer(sig) int sig; { setcommandmode(); longjmp(peerdied, -1); } /* ARGSUSED */ SIG_FUNC_RET intr(sig) int sig; { if (localchars) { intp(); return; } setcommandmode(); longjmp(toplevel, -1); } /* ARGSUSED */ SIG_FUNC_RET intr2(sig) int sig; { if (localchars) { #ifdef KLUDGELINEMODE if (kludgelinemode) sendbrk(); else #endif sendabort(); return; } } #ifdef SIGTSTP /* ARGSUSED */ SIG_FUNC_RET susp(sig) int sig; { if ((rlogin != _POSIX_VDISABLE) && rlogin_susp()) return; if (localchars) sendsusp(); } #endif #ifdef SIGWINCH /* ARGSUSED */ SIG_FUNC_RET sendwin(sig) int sig; { if (connected) { sendnaws(); } } #endif #ifdef SIGINFO /* ARGSUSED */ SIG_FUNC_RET ayt(sig) int sig; { if (connected) sendayt(); else ayt_status(); } #endif void sys_telnet_init() { (void) signal(SIGINT, intr); (void) signal(SIGQUIT, intr2); (void) signal(SIGPIPE, deadpeer); #ifdef SIGWINCH (void) signal(SIGWINCH, sendwin); #endif #ifdef SIGTSTP (void) signal(SIGTSTP, susp); #endif #ifdef SIGINFO (void) signal(SIGINFO, ayt); #endif setconnmode(0); NetNonblockingIO(net, 1); #if defined(TN3270) if (noasynchnet == 0) { /* DBX can't handle! */ NetSigIO(net, 1); NetSetPgrp(net); } #endif /* defined(TN3270) */ #if defined(SO_OOBINLINE) if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) { perror("SetSockOpt"); } #endif /* defined(SO_OOBINLINE) */ } /* * Process rings - * * This routine tries to fill up/empty our various rings. * * The parameter specifies whether this is a poll operation, * or a block-until-something-happens operation. * * The return value is 1 if something happened, 0 if not. */ int process_rings(netin, netout, netex, ttyin, ttyout, poll) int poll; /* If 0, then block until something to do */ { register int c; /* One wants to be a bit careful about setting returnValue * to one, since a one implies we did some useful work, * and therefore probably won't be called to block next * time (TN3270 mode only). */ int returnValue = 0; static struct timeval TimeValue = { 0 }; if (netout) { FD_SET(net, &obits); } if (ttyout) { FD_SET(tout, &obits); } #if defined(TN3270) if (ttyin) { FD_SET(tin, &ibits); } #else /* defined(TN3270) */ if (ttyin) { FD_SET(tin, &ibits); } #endif /* defined(TN3270) */ #if defined(TN3270) if (netin) { FD_SET(net, &ibits); } # else /* !defined(TN3270) */ if (netin) { FD_SET(net, &ibits); } # endif /* !defined(TN3270) */ if (netex) { FD_SET(net, &xbits); } if ((c = select(16, &ibits, &obits, &xbits, (poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) { if (c == -1) { /* * we can get EINTR if we are in line mode, * and the user does an escape (TSTP), or * some other signal generator. */ if (errno == EINTR) { return 0; } # if defined(TN3270) /* * we can get EBADF if we were in transparent * mode, and the transcom process died. */ if (errno == EBADF) { /* * zero the bits (even though kernel does it) * to make sure we are selecting on the right * ones. */ FD_ZERO(&ibits); FD_ZERO(&obits); FD_ZERO(&xbits); return 0; } # endif /* defined(TN3270) */ /* I don't like this, does it ever happen? */ - printf("sleep(5) from telnet, after select\r\n"); + printf("sleep(5) from telnet, after select: %s\r\n", strerror(errno)); sleep(5); } return 0; } /* * Any urgent data? */ if (FD_ISSET(net, &xbits)) { FD_CLR(net, &xbits); SYNCHing = 1; (void) ttyflush(1); /* flush already enqueued data */ } /* * Something to read from the network... */ if (FD_ISSET(net, &ibits)) { int canread; FD_CLR(net, &ibits); canread = ring_empty_consecutive(&netiring); #if !defined(SO_OOBINLINE) /* * In 4.2 (and some early 4.3) 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; static int bogus_oob = 0, first = 1; ioctl(net, SIOCATMARK, (char *)&atmark); if (atmark) { c = recv(net, netiring.supply, canread, MSG_OOB); if ((c == -1) && (errno == EINVAL)) { c = recv(net, netiring.supply, canread, 0); if (clocks.didnetreceive < clocks.gotDM) { SYNCHing = stilloob(net); } } else if (first && c > 0) { /* * Bogosity check. Systems based on 4.2BSD * do not return an error if you do a second * recv(MSG_OOB). So, we do one. If it * succeeds and returns exactly the same * data, then assume that we are running * on a broken system and set the bogus_oob * flag. (If the data was different, then * we probably got some valid new data, so * increment the count...) */ int i; i = recv(net, netiring.supply + c, canread - c, MSG_OOB); if (i == c && memcmp(netiring.supply, netiring.supply + c, i) == 0) { bogus_oob = 1; first = 0; } else if (i < 0) { bogus_oob = 0; first = 0; } else c += i; } if (bogus_oob && c > 0) { int i; /* * Bogosity. We have to do the read * to clear the atmark to get out of * an infinate loop. */ i = read(net, netiring.supply + c, canread - c); if (i > 0) c += i; } } else { c = recv(net, netiring.supply, canread, 0); } } else { c = recv(net, netiring.supply, canread, 0); } settimer(didnetreceive); #else /* !defined(SO_OOBINLINE) */ c = recv(net, (char *)netiring.supply, canread, 0); #endif /* !defined(SO_OOBINLINE) */ if (c < 0 && errno == EWOULDBLOCK) { c = 0; } else if (c <= 0) { return -1; } if (netdata) { Dump('<', netiring.supply, c); } if (c) ring_supplied(&netiring, c); returnValue = 1; } /* * Something to read from the tty... */ if (FD_ISSET(tin, &ibits)) { FD_CLR(tin, &ibits); c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring)); if (c < 0 && errno == EIO) c = 0; if (c < 0 && errno == EWOULDBLOCK) { c = 0; } else { /* EOF detection for line mode!!!! */ if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) { /* must be an EOF... */ *ttyiring.supply = termEofChar; c = 1; } if (c <= 0) { return -1; } if (termdata) { Dump('<', ttyiring.supply, c); } ring_supplied(&ttyiring, c); } returnValue = 1; /* did something useful */ } if (FD_ISSET(net, &obits)) { FD_CLR(net, &obits); returnValue |= netflush(); } if (FD_ISSET(tout, &obits)) { FD_CLR(tout, &obits); returnValue |= (ttyflush(SYNCHing|flushout) > 0); } return returnValue; } diff --git a/crypto/telnet/telnet/telnet.c b/crypto/telnet/telnet/telnet.c index e7922624e6e6..1c1ee333fa72 100644 --- a/crypto/telnet/telnet/telnet.c +++ b/crypto/telnet/telnet/telnet.c @@ -1,2650 +1,2662 @@ /* * Copyright (c) 1988, 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. */ #ifndef lint -static char sccsid[] = "@(#)telnet.c 8.4 (Berkeley) 5/30/95"; +static const char sccsid[] = "@(#)telnet.c 8.4 (Berkeley) 5/30/95"; #endif /* not lint */ #include #if defined(unix) #include /* By the way, we need to include curses.h before telnet.h since, * among other things, telnet.h #defines 'DO', which is a variable * declared in curses.h. */ #endif /* defined(unix) */ #include #include +#include +#include +#include + #include "ring.h" #include "defines.h" #include "externs.h" #include "types.h" #include "general.h" +#if defined(AUTHENTICATION) +#include +#endif +#if defined(ENCRYPTION) +#include +#endif +#include #define strip(x) ((my_want_state_is_wont(TELOPT_BINARY)) ? ((x)&0x7f) : (x)) static unsigned char subbuffer[SUBBUFSIZE], *subpointer, *subend; /* buffer for sub-options */ #define SB_CLEAR() subpointer = subbuffer; #define SB_TERM() { subend = subpointer; SB_CLEAR(); } #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ *subpointer++ = (c); \ } #define SB_GET() ((*subpointer++)&0xff) #define SB_PEEK() ((*subpointer)&0xff) #define SB_EOF() (subpointer >= subend) #define SB_LEN() (subend - subpointer) char options[256]; /* The combined options */ char do_dont_resp[256]; char will_wont_resp[256]; int eight = 0, autologin = 0, /* Autologin anyone? */ skiprc = 0, connected, showoptions, In3270, /* Are we in 3270 mode? */ ISend, /* trying to send network data in */ debug = 0, crmod, netdata, /* Print out network data flow */ crlf, /* Should '\r' be mapped to (or )? */ #if defined(TN3270) noasynchtty = 0,/* User specified "-noasynch" on command line */ noasynchnet = 0,/* User specified "-noasynch" on command line */ askedSGA = 0, /* We have talked about suppress go ahead */ #endif /* defined(TN3270) */ telnetport, SYNCHing, /* we are in TELNET SYNCH mode */ flushout, /* flush output */ autoflush = 0, /* flush output when interrupting? */ autosynch, /* send interrupt characters with SYNCH? */ localflow, /* we handle flow control locally */ restartany, /* if flow control enabled, restart on any character */ localchars, /* we recognize interrupt/quit */ donelclchars, /* the user has set "localchars" */ donebinarytoggle, /* the user has put us in binary */ dontlecho, /* do we suppress local echoing right now? */ - globalmode; + globalmode, + clienteof = 0; char *prompt = 0; cc_t escape; cc_t rlogin; #ifdef KLUDGELINEMODE cc_t echoc; #endif /* * Telnet receiver states for fsm */ #define TS_DATA 0 #define TS_IAC 1 #define TS_WILL 2 #define TS_WONT 3 #define TS_DO 4 #define TS_DONT 5 #define TS_CR 6 #define TS_SB 7 /* sub-option collection */ #define TS_SE 8 /* looking for sub-option end */ static int telrcv_state; #ifdef OLD_ENVIRON unsigned char telopt_environ = TELOPT_NEW_ENVIRON; #else # define telopt_environ TELOPT_NEW_ENVIRON #endif jmp_buf toplevel = { 0 }; jmp_buf peerdied; int flushline; int linemode; #ifdef KLUDGELINEMODE int kludgelinemode = 1; #endif /* * The following are some clocks used to decide how to interpret * the relationship between various variables. */ Clocks clocks; #ifdef notdef Modelist modelist[] = { { "telnet command mode", COMMAND_LINE }, { "character-at-a-time mode", 0 }, { "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS }, { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS }, { "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS }, { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS }, { "3270 mode", 0 }, }; #endif /* * Initialize telnet environment. */ void init_telnet() { env_init(); SB_CLEAR(); ClearArray(options); connected = In3270 = ISend = localflow = donebinarytoggle = 0; #if defined(AUTHENTICATION) || defined(ENCRYPTION) auth_encrypt_connect(connected); #endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */ restartany = -1; SYNCHing = 0; /* Don't change NetTrace */ escape = CONTROL(']'); rlogin = _POSIX_VDISABLE; #ifdef KLUDGELINEMODE echoc = CONTROL('E'); #endif flushline = 1; telrcv_state = TS_DATA; } #ifdef notdef #include /*VARARGS*/ static void printring(va_alist) va_dcl { va_list ap; char buffer[100]; /* where things go */ char *ptr; char *format; char *string; Ring *ring; int i; va_start(ap); ring = va_arg(ap, Ring *); format = va_arg(ap, char *); ptr = buffer; while ((i = *format++) != 0) { if (i == '%') { i = *format++; switch (i) { case 'c': *ptr++ = va_arg(ap, int); break; case 's': string = va_arg(ap, char *); ring_supply_data(ring, buffer, ptr-buffer); ring_supply_data(ring, string, strlen(string)); ptr = buffer; break; case 0: ExitString("printring: trailing %%.\n", 1); /*NOTREACHED*/ default: ExitString("printring: unknown format character.\n", 1); /*NOTREACHED*/ } } else { *ptr++ = i; } } ring_supply_data(ring, buffer, ptr-buffer); } #endif /* * These routines are in charge of sending option negotiations * to the other side. * * The basic idea is that we send the negotiation if either side * is in disagreement as to what the current state should be. */ void send_do(c, init) register int c, init; { if (init) { if (((do_dont_resp[c] == 0) && my_state_is_do(c)) || my_want_state_is_do(c)) return; set_my_want_state_do(c); do_dont_resp[c]++; } NET2ADD(IAC, DO); NETADD(c); printoption("SENT", DO, c); } void send_dont(c, init) register int c, init; { if (init) { if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) || my_want_state_is_dont(c)) return; set_my_want_state_dont(c); do_dont_resp[c]++; } NET2ADD(IAC, DONT); NETADD(c); printoption("SENT", DONT, c); } void send_will(c, init) register int c, init; { if (init) { if (((will_wont_resp[c] == 0) && my_state_is_will(c)) || my_want_state_is_will(c)) return; set_my_want_state_will(c); will_wont_resp[c]++; } NET2ADD(IAC, WILL); NETADD(c); printoption("SENT", WILL, c); } void send_wont(c, init) register int c, init; { if (init) { if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) || my_want_state_is_wont(c)) return; set_my_want_state_wont(c); will_wont_resp[c]++; } NET2ADD(IAC, WONT); NETADD(c); printoption("SENT", WONT, c); } void willoption(option) int option; { int new_state_ok = 0; if (do_dont_resp[option]) { --do_dont_resp[option]; if (do_dont_resp[option] && my_state_is_do(option)) --do_dont_resp[option]; } if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) { switch (option) { case TELOPT_ECHO: # if defined(TN3270) /* * The following is a pain in the rear-end. * Various IBM servers (some versions of Wiscnet, * possibly Fibronics/Spartacus, and who knows who * else) will NOT allow us to send "DO SGA" too early * in the setup proceedings. On the other hand, * 4.2 servers (telnetd) won't set SGA correctly. * So, we are stuck. Empirically (but, based on * a VERY small sample), the IBM servers don't send * out anything about ECHO, so we postpone our sending * "DO SGA" until we see "WILL ECHO" (which 4.2 servers * DO send). */ { if (askedSGA == 0) { askedSGA = 1; if (my_want_state_is_dont(TELOPT_SGA)) send_do(TELOPT_SGA, 1); } } /* Fall through */ case TELOPT_EOR: #endif /* defined(TN3270) */ case TELOPT_BINARY: case TELOPT_SGA: settimer(modenegotiated); /* FALL THROUGH */ case TELOPT_STATUS: #if defined(AUTHENTICATION) case TELOPT_AUTHENTICATION: #endif #ifdef ENCRYPTION case TELOPT_ENCRYPT: #endif /* ENCRYPTION */ new_state_ok = 1; break; case TELOPT_TM: if (flushout) flushout = 0; /* * Special case for TM. If we get back a WILL, * pretend we got back a WONT. */ set_my_want_state_dont(option); set_my_state_dont(option); return; /* Never reply to TM will's/wont's */ case TELOPT_LINEMODE: default: break; } if (new_state_ok) { set_my_want_state_do(option); send_do(option, 0); setconnmode(0); /* possibly set new tty mode */ } else { do_dont_resp[option]++; send_dont(option, 0); } } set_my_state_do(option); #ifdef ENCRYPTION if (option == TELOPT_ENCRYPT) encrypt_send_support(); #endif /* ENCRYPTION */ } void wontoption(option) int option; { if (do_dont_resp[option]) { --do_dont_resp[option]; if (do_dont_resp[option] && my_state_is_dont(option)) --do_dont_resp[option]; } if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) { switch (option) { #ifdef KLUDGELINEMODE case TELOPT_SGA: if (!kludgelinemode) break; /* FALL THROUGH */ #endif case TELOPT_ECHO: settimer(modenegotiated); break; case TELOPT_TM: if (flushout) flushout = 0; set_my_want_state_dont(option); set_my_state_dont(option); return; /* Never reply to TM will's/wont's */ default: break; } set_my_want_state_dont(option); if (my_state_is_do(option)) send_dont(option, 0); setconnmode(0); /* Set new tty mode */ } else if (option == TELOPT_TM) { /* * Special case for TM. */ if (flushout) flushout = 0; set_my_want_state_dont(option); } set_my_state_dont(option); } static void dooption(option) int option; { int new_state_ok = 0; 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) { if (my_want_state_is_wont(option)) { switch (option) { case TELOPT_TM: /* * Special case for TM. We send a WILL, but pretend * we sent WONT. */ send_will(option, 0); set_my_want_state_wont(TELOPT_TM); set_my_state_wont(TELOPT_TM); return; # if defined(TN3270) case TELOPT_EOR: /* end of record */ # endif /* defined(TN3270) */ case TELOPT_BINARY: /* binary mode */ case TELOPT_NAWS: /* window size */ case TELOPT_TSPEED: /* terminal speed */ case TELOPT_LFLOW: /* local flow control */ case TELOPT_TTYPE: /* terminal type option */ case TELOPT_SGA: /* no big deal */ #ifdef ENCRYPTION case TELOPT_ENCRYPT: /* encryption variable option */ #endif /* ENCRYPTION */ new_state_ok = 1; break; case TELOPT_NEW_ENVIRON: /* New environment variable option */ #ifdef OLD_ENVIRON if (my_state_is_will(TELOPT_OLD_ENVIRON)) send_wont(TELOPT_OLD_ENVIRON, 1); /* turn off the old */ goto env_common; case TELOPT_OLD_ENVIRON: /* Old environment variable option */ if (my_state_is_will(TELOPT_NEW_ENVIRON)) break; /* Don't enable if new one is in use! */ env_common: telopt_environ = option; #endif new_state_ok = 1; break; #if defined(AUTHENTICATION) case TELOPT_AUTHENTICATION: if (autologin) new_state_ok = 1; break; #endif case TELOPT_XDISPLOC: /* X Display location */ if (env_getvalue((unsigned char *)"DISPLAY")) new_state_ok = 1; break; case TELOPT_LINEMODE: #ifdef KLUDGELINEMODE kludgelinemode = 0; send_do(TELOPT_SGA, 1); #endif set_my_want_state_will(TELOPT_LINEMODE); send_will(option, 0); set_my_state_will(TELOPT_LINEMODE); slc_init(); return; case TELOPT_ECHO: /* We're never going to echo... */ default: break; } if (new_state_ok) { set_my_want_state_will(option); send_will(option, 0); setconnmode(0); /* Set new tty mode */ } else { will_wont_resp[option]++; send_wont(option, 0); } } else { /* * Handle options that need more things done after the * other side has acknowledged the option. */ switch (option) { case TELOPT_LINEMODE: #ifdef KLUDGELINEMODE kludgelinemode = 0; send_do(TELOPT_SGA, 1); #endif set_my_state_will(option); slc_init(); send_do(TELOPT_SGA, 0); return; } } } set_my_state_will(option); } static void dontoption(option) int 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_LINEMODE: linemode = 0; /* put us back to the default state */ break; #ifdef OLD_ENVIRON case TELOPT_NEW_ENVIRON: /* * The new environ option wasn't recognized, try * the old one. */ send_will(TELOPT_OLD_ENVIRON, 1); telopt_environ = TELOPT_OLD_ENVIRON; break; #endif } /* we always accept a DONT */ set_my_want_state_wont(option); if (my_state_is_will(option)) send_wont(option, 0); setconnmode(0); /* Set new tty mode */ } set_my_state_wont(option); } /* * Given a buffer returned by tgetent(), this routine will turn * the pipe seperated list of names in the buffer into an array * of pointers to null terminated names. We toss out any bad, * duplicate, or verbose names (names with spaces). */ static char *name_unknown = "UNKNOWN"; static char *unknown[] = { 0, 0 }; char ** mklist(buf, name) char *buf, *name; { register int n; register char c, *cp, **argvp, *cp2, **argv, **avt; if (name) { if ((int)strlen(name) > 40) { name = 0; unknown[0] = name_unknown; } else { unknown[0] = name; upcase(name); } } else unknown[0] = name_unknown; /* * Count up the number of names. */ for (n = 1, cp = buf; *cp && *cp != ':'; cp++) { if (*cp == '|') n++; } /* * Allocate an array to put the name pointers into */ argv = (char **)malloc((n+3)*sizeof(char *)); if (argv == 0) return(unknown); /* * Fill up the array of pointers to names. */ *argv = 0; argvp = argv+1; n = 0; for (cp = cp2 = buf; (c = *cp); cp++) { if (c == '|' || c == ':') { *cp++ = '\0'; /* * Skip entries that have spaces or are over 40 * characters long. If this is our environment * name, then put it up front. Otherwise, as * long as this is not a duplicate name (case * insensitive) add it to the list. */ if (n || (cp - cp2 > 41)) ; else if (name && (strncasecmp(name, cp2, cp-cp2) == 0)) *argv = cp2; else if (is_unique(cp2, argv+1, argvp)) *argvp++ = cp2; if (c == ':') break; /* * Skip multiple delimiters. Reset cp2 to * the beginning of the next name. Reset n, * the flag for names with spaces. */ while ((c = *cp) == '|') cp++; cp2 = cp; n = 0; } /* * Skip entries with spaces or non-ascii values. * Convert lower case letters to upper case. */ if ((c == ' ') || !isascii(c)) n = 1; else if (islower(c)) *cp = toupper(c); } /* * Check for an old V6 2 character name. If the second * name points to the beginning of the buffer, and is * only 2 characters long, move it to the end of the array. */ if ((argv[1] == buf) && (strlen(argv[1]) == 2)) { --argvp; for (avt = &argv[1]; avt < argvp; avt++) *avt = *(avt+1); *argvp++ = buf; } /* * Duplicate last name, for TTYPE option, and null * terminate the array. If we didn't find a match on * our terminal name, put that name at the beginning. */ cp = *(argvp-1); *argvp++ = cp; *argvp = 0; if (*argv == 0) { if (name) *argv = name; else { --argvp; for (avt = argv; avt < argvp; avt++) *avt = *(avt+1); } } if (*argv) return(argv); else return(unknown); } int is_unique(name, as, ae) register char *name, **as, **ae; { register char **ap; register int n; n = strlen(name) + 1; for (ap = as; ap < ae; ap++) if (strncasecmp(*ap, name, n) == 0) return(0); return (1); } #ifdef TERMCAP char termbuf[1024]; /*ARGSUSED*/ int setupterm(tname, fd, errp) char *tname; int fd, *errp; { if (tgetent(termbuf, tname) == 1) { termbuf[1023] = '\0'; if (errp) *errp = 1; return(0); } if (errp) *errp = 0; return(-1); } #else #define termbuf ttytype extern char ttytype[]; #endif int resettermname = 1; char * gettermname() { char *tname; static char **tnamep = 0; static char **next; int err; if (resettermname) { resettermname = 0; if (tnamep && tnamep != unknown) free(tnamep); if ((tname = (char *)env_getvalue((unsigned char *)"TERM")) && (setupterm(tname, 1, &err) == 0)) { tnamep = mklist(termbuf, tname); } else { if (tname && ((int)strlen(tname) <= 40)) { unknown[0] = tname; upcase(tname); } else unknown[0] = name_unknown; tnamep = unknown; } next = tnamep; } if (*next == 0) next = tnamep; return(*next++); } /* * suboption() * * Look at the sub-option buffer, and try to be helpful to the other * side. * * Currently we recognize: * * Terminal type, send request. * Terminal speed (send request). * Local flow control (is request). * Linemode */ static void suboption() { unsigned char subchar; printsub('<', subbuffer, SB_LEN()+2); switch (subchar = SB_GET()) { case TELOPT_TTYPE: if (my_want_state_is_wont(TELOPT_TTYPE)) return; if (SB_EOF() || SB_GET() != TELQUAL_SEND) { return; } else { char *name; unsigned char temp[50]; int len; #if defined(TN3270) if (tn3270_ttype()) { return; } #endif /* defined(TN3270) */ name = gettermname(); len = strlen(name) + 4 + 2; if (len < NETROOM()) { sprintf((char *)temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, TELQUAL_IS, name, IAC, SE); ring_supply_data(&netoring, temp, len); printsub('>', &temp[2], len-2); } else { ExitString("No room in buffer for terminal type.\n", 1); /*NOTREACHED*/ } } break; case TELOPT_TSPEED: if (my_want_state_is_wont(TELOPT_TSPEED)) return; if (SB_EOF()) return; if (SB_GET() == TELQUAL_SEND) { long ospeed, ispeed; unsigned char temp[50]; int len; TerminalSpeeds(&ispeed, &ospeed); - sprintf((char *)temp, "%c%c%c%c%d,%d%c%c", IAC, SB, TELOPT_TSPEED, + sprintf((char *)temp, "%c%c%c%c%ld,%ld%c%c", IAC, SB, TELOPT_TSPEED, TELQUAL_IS, ospeed, ispeed, IAC, SE); len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */ if (len < NETROOM()) { ring_supply_data(&netoring, temp, len); printsub('>', temp+2, len - 2); } /*@*/ else printf("lm_will: not enough room in buffer\n"); } break; case TELOPT_LFLOW: if (my_want_state_is_wont(TELOPT_LFLOW)) return; if (SB_EOF()) return; switch(SB_GET()) { case LFLOW_RESTART_ANY: restartany = 1; break; case LFLOW_RESTART_XON: restartany = 0; break; case LFLOW_ON: localflow = 1; break; case LFLOW_OFF: localflow = 0; break; default: return; } setcommandmode(); setconnmode(0); break; case TELOPT_LINEMODE: if (my_want_state_is_wont(TELOPT_LINEMODE)) return; if (SB_EOF()) return; switch (SB_GET()) { case WILL: lm_will(subpointer, SB_LEN()); break; case WONT: lm_wont(subpointer, SB_LEN()); break; case DO: lm_do(subpointer, SB_LEN()); break; case DONT: lm_dont(subpointer, SB_LEN()); break; case LM_SLC: slc(subpointer, SB_LEN()); break; case LM_MODE: lm_mode(subpointer, SB_LEN(), 0); break; default: break; } break; #ifdef OLD_ENVIRON case TELOPT_OLD_ENVIRON: #endif case TELOPT_NEW_ENVIRON: if (SB_EOF()) return; switch(SB_PEEK()) { case TELQUAL_IS: case TELQUAL_INFO: if (my_want_state_is_dont(subchar)) return; break; case TELQUAL_SEND: if (my_want_state_is_wont(subchar)) { return; } break; default: return; } env_opt(subpointer, SB_LEN()); break; case TELOPT_XDISPLOC: if (my_want_state_is_wont(TELOPT_XDISPLOC)) return; if (SB_EOF()) return; if (SB_GET() == TELQUAL_SEND) { unsigned char temp[50], *dp; int len; if ((dp = env_getvalue((unsigned char *)"DISPLAY")) == NULL) { /* * Something happened, we no longer have a DISPLAY * variable. So, turn off the option. */ send_wont(TELOPT_XDISPLOC, 1); break; } sprintf((char *)temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC, TELQUAL_IS, dp, IAC, SE); len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */ if (len < NETROOM()) { ring_supply_data(&netoring, temp, len); printsub('>', temp+2, len - 2); } /*@*/ else printf("lm_will: not enough room in buffer\n"); } break; #if defined(AUTHENTICATION) case TELOPT_AUTHENTICATION: { if (!autologin) break; if (SB_EOF()) return; switch(SB_GET()) { case TELQUAL_IS: if (my_want_state_is_dont(TELOPT_AUTHENTICATION)) return; auth_is(subpointer, SB_LEN()); break; case TELQUAL_SEND: if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) return; auth_send(subpointer, SB_LEN()); break; case TELQUAL_REPLY: if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) return; auth_reply(subpointer, SB_LEN()); break; case TELQUAL_NAME: if (my_want_state_is_dont(TELOPT_AUTHENTICATION)) return; auth_name(subpointer, SB_LEN()); break; } } break; #endif #ifdef ENCRYPTION case TELOPT_ENCRYPT: if (SB_EOF()) return; switch(SB_GET()) { case ENCRYPT_START: if (my_want_state_is_dont(TELOPT_ENCRYPT)) return; encrypt_start(subpointer, SB_LEN()); break; case ENCRYPT_END: if (my_want_state_is_dont(TELOPT_ENCRYPT)) return; encrypt_end(); break; case ENCRYPT_SUPPORT: if (my_want_state_is_wont(TELOPT_ENCRYPT)) return; encrypt_support(subpointer, SB_LEN()); break; case ENCRYPT_REQSTART: if (my_want_state_is_wont(TELOPT_ENCRYPT)) return; encrypt_request_start(subpointer, SB_LEN()); break; case ENCRYPT_REQEND: if (my_want_state_is_wont(TELOPT_ENCRYPT)) return; /* * 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_IS: if (my_want_state_is_dont(TELOPT_ENCRYPT)) return; encrypt_is(subpointer, SB_LEN()); break; case ENCRYPT_REPLY: if (my_want_state_is_wont(TELOPT_ENCRYPT)) return; encrypt_reply(subpointer, SB_LEN()); break; case ENCRYPT_ENC_KEYID: if (my_want_state_is_dont(TELOPT_ENCRYPT)) return; encrypt_enc_keyid(subpointer, SB_LEN()); break; case ENCRYPT_DEC_KEYID: if (my_want_state_is_wont(TELOPT_ENCRYPT)) return; encrypt_dec_keyid(subpointer, SB_LEN()); break; default: break; } break; #endif /* ENCRYPTION */ default: break; } } static unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE }; void lm_will(cmd, len) unsigned char *cmd; int len; { if (len < 1) { /*@*/ printf("lm_will: no command!!!\n"); /* Should not happen... */ return; } switch(cmd[0]) { case LM_FORWARDMASK: /* We shouldn't ever get this... */ default: str_lm[3] = DONT; str_lm[4] = cmd[0]; if (NETROOM() > sizeof(str_lm)) { ring_supply_data(&netoring, str_lm, sizeof(str_lm)); printsub('>', &str_lm[2], sizeof(str_lm)-2); } /*@*/ else printf("lm_will: not enough room in buffer\n"); break; } } void lm_wont(cmd, len) unsigned char *cmd; int len; { if (len < 1) { /*@*/ printf("lm_wont: no command!!!\n"); /* Should not happen... */ return; } switch(cmd[0]) { case LM_FORWARDMASK: /* We shouldn't ever get this... */ default: /* We are always DONT, so don't respond */ return; } } void lm_do(cmd, len) unsigned char *cmd; int len; { if (len < 1) { /*@*/ printf("lm_do: no command!!!\n"); /* Should not happen... */ return; } switch(cmd[0]) { case LM_FORWARDMASK: default: str_lm[3] = WONT; str_lm[4] = cmd[0]; if (NETROOM() > sizeof(str_lm)) { ring_supply_data(&netoring, str_lm, sizeof(str_lm)); printsub('>', &str_lm[2], sizeof(str_lm)-2); } /*@*/ else printf("lm_do: not enough room in buffer\n"); break; } } void lm_dont(cmd, len) unsigned char *cmd; int len; { if (len < 1) { /*@*/ printf("lm_dont: no command!!!\n"); /* Should not happen... */ return; } switch(cmd[0]) { case LM_FORWARDMASK: default: /* we are always WONT, so don't respond */ break; } } static unsigned char str_lm_mode[] = { IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE }; void lm_mode(cmd, len, init) unsigned char *cmd; int len, init; { if (len != 1) return; if ((linemode&MODE_MASK&~MODE_ACK) == *cmd) return; if (*cmd&MODE_ACK) return; linemode = *cmd&(MODE_MASK&~MODE_ACK); str_lm_mode[4] = linemode; if (!init) str_lm_mode[4] |= MODE_ACK; if (NETROOM() > sizeof(str_lm_mode)) { ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode)); printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2); } /*@*/ else printf("lm_mode: not enough room in buffer\n"); setconnmode(0); /* set changed mode */ } /* * slc() * Handle special character suboption of LINEMODE. */ struct spc { cc_t val; cc_t *valp; char flags; /* Current flags & level */ char mylevel; /* Maximum level & flags */ } spc_data[NSLC+1]; #define SLC_IMPORT 0 #define SLC_EXPORT 1 #define SLC_RVALUE 2 static int slc_mode = SLC_EXPORT; void slc_init() { register struct spc *spcp; localchars = 1; for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) { spcp->val = 0; spcp->valp = 0; spcp->flags = spcp->mylevel = SLC_NOSUPPORT; } #define initfunc(func, flags) { \ spcp = &spc_data[func]; \ - if (spcp->valp = tcval(func)) { \ + if ((spcp->valp = tcval(func))) { \ spcp->val = *spcp->valp; \ spcp->mylevel = SLC_VARIABLE|flags; \ } else { \ spcp->val = 0; \ spcp->mylevel = SLC_DEFAULT; \ } \ } initfunc(SLC_SYNCH, 0); /* No BRK */ initfunc(SLC_AO, 0); initfunc(SLC_AYT, 0); /* No EOR */ initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT); initfunc(SLC_EOF, 0); #ifndef SYSV_TERMIO initfunc(SLC_SUSP, SLC_FLUSHIN); #endif initfunc(SLC_EC, 0); initfunc(SLC_EL, 0); #ifndef SYSV_TERMIO initfunc(SLC_EW, 0); initfunc(SLC_RP, 0); initfunc(SLC_LNEXT, 0); #endif initfunc(SLC_XON, 0); initfunc(SLC_XOFF, 0); #ifdef SYSV_TERMIO spc_data[SLC_XON].mylevel = SLC_CANTCHANGE; spc_data[SLC_XOFF].mylevel = SLC_CANTCHANGE; #endif initfunc(SLC_FORW1, 0); #ifdef USE_TERMIO initfunc(SLC_FORW2, 0); /* No FORW2 */ #endif initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT); #undef initfunc if (slc_mode == SLC_EXPORT) slc_export(); else slc_import(1); } void slcstate() { printf("Special characters are %s values\n", slc_mode == SLC_IMPORT ? "remote default" : slc_mode == SLC_EXPORT ? "local" : "remote"); } void slc_mode_export() { slc_mode = SLC_EXPORT; if (my_state_is_will(TELOPT_LINEMODE)) slc_export(); } void slc_mode_import(def) int def; { slc_mode = def ? SLC_IMPORT : SLC_RVALUE; if (my_state_is_will(TELOPT_LINEMODE)) slc_import(def); } unsigned char slc_import_val[] = { IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE }; unsigned char slc_import_def[] = { IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE }; void slc_import(def) int def; { if (NETROOM() > sizeof(slc_import_val)) { if (def) { ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def)); printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2); } else { ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val)); printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2); } } /*@*/ else printf("slc_import: not enough room\n"); } void slc_export() { register struct spc *spcp; TerminalDefaultChars(); slc_start_reply(); for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { if (spcp->mylevel != SLC_NOSUPPORT) { if (spcp->val == (cc_t)(_POSIX_VDISABLE)) spcp->flags = SLC_NOSUPPORT; else spcp->flags = spcp->mylevel; if (spcp->valp) spcp->val = *spcp->valp; slc_add_reply(spcp - spc_data, spcp->flags, spcp->val); } } slc_end_reply(); (void)slc_update(); setconnmode(1); /* Make sure the character values are set */ } void slc(cp, len) register unsigned char *cp; int len; { register struct spc *spcp; register int func,level; slc_start_reply(); for (; len >= 3; len -=3, cp +=3) { func = cp[SLC_FUNC]; if (func == 0) { /* * Client side: always ignore 0 function. */ continue; } if (func > NSLC) { if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT) slc_add_reply(func, SLC_NOSUPPORT, 0); continue; } spcp = &spc_data[func]; level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK); if ((cp[SLC_VALUE] == (unsigned char)spcp->val) && ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) { continue; } if (level == (SLC_DEFAULT|SLC_ACK)) { /* * This is an error condition, the SLC_ACK * bit should never be set for the SLC_DEFAULT * level. Our best guess to recover is to * ignore the SLC_ACK bit. */ cp[SLC_FLAGS] &= ~SLC_ACK; } if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) { spcp->val = (cc_t)cp[SLC_VALUE]; spcp->flags = cp[SLC_FLAGS]; /* include SLC_ACK */ continue; } level &= ~SLC_ACK; if (level <= (spcp->mylevel&SLC_LEVELBITS)) { spcp->flags = cp[SLC_FLAGS]|SLC_ACK; spcp->val = (cc_t)cp[SLC_VALUE]; } if (level == SLC_DEFAULT) { if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT) spcp->flags = spcp->mylevel; else spcp->flags = SLC_NOSUPPORT; } slc_add_reply(func, spcp->flags, spcp->val); } slc_end_reply(); if (slc_update()) setconnmode(1); /* set the new character values */ } void slc_check() { register struct spc *spcp; slc_start_reply(); for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { if (spcp->valp && spcp->val != *spcp->valp) { spcp->val = *spcp->valp; if (spcp->val == (cc_t)(_POSIX_VDISABLE)) spcp->flags = SLC_NOSUPPORT; else spcp->flags = spcp->mylevel; slc_add_reply(spcp - spc_data, spcp->flags, spcp->val); } } slc_end_reply(); setconnmode(1); } unsigned char slc_reply[128]; unsigned char *slc_replyp; void slc_start_reply() { slc_replyp = slc_reply; *slc_replyp++ = IAC; *slc_replyp++ = SB; *slc_replyp++ = TELOPT_LINEMODE; *slc_replyp++ = LM_SLC; } void slc_add_reply(func, flags, value) unsigned char func; unsigned char flags; cc_t value; { if ((*slc_replyp++ = func) == IAC) *slc_replyp++ = IAC; if ((*slc_replyp++ = flags) == IAC) *slc_replyp++ = IAC; if ((*slc_replyp++ = (unsigned char)value) == IAC) *slc_replyp++ = IAC; } void slc_end_reply() { register int len; *slc_replyp++ = IAC; *slc_replyp++ = SE; len = slc_replyp - slc_reply; if (len <= 6) return; if (NETROOM() > len) { ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply); printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2); } /*@*/else printf("slc_end_reply: not enough room\n"); } int slc_update() { register struct spc *spcp; int need_update = 0; for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { if (!(spcp->flags&SLC_ACK)) continue; spcp->flags &= ~SLC_ACK; if (spcp->valp && (*spcp->valp != spcp->val)) { *spcp->valp = spcp->val; need_update = 1; } } return(need_update); } #ifdef OLD_ENVIRON # ifdef ENV_HACK /* * Earlier version of telnet/telnetd from the BSD code had * the definitions of VALUE and VAR reversed. To ensure * maximum interoperability, we assume that the server is * an older BSD server, until proven otherwise. The newer * BSD servers should be able to handle either definition, * so it is better to use the wrong values if we don't * know what type of server it is. */ int env_auto = 1; int old_env_var = OLD_ENV_VAR; int old_env_value = OLD_ENV_VALUE; # else # define old_env_var OLD_ENV_VAR # define old_env_value OLD_ENV_VALUE # endif #endif void env_opt(buf, len) register unsigned char *buf; register int len; { register unsigned char *ep = 0, *epc = 0; register int i; switch(buf[0]&0xff) { case TELQUAL_SEND: env_opt_start(); if (len == 1) { env_opt_add(NULL); } else for (i = 1; i < len; i++) { switch (buf[i]&0xff) { #ifdef OLD_ENVIRON case OLD_ENV_VAR: # ifdef ENV_HACK if (telopt_environ == TELOPT_OLD_ENVIRON && env_auto) { /* Server has the same definitions */ old_env_var = OLD_ENV_VAR; old_env_value = OLD_ENV_VALUE; } /* FALL THROUGH */ # endif case OLD_ENV_VALUE: /* * Although OLD_ENV_VALUE is not legal, we will * still recognize it, just in case it is an * old server that has VAR & VALUE mixed up... */ /* FALL THROUGH */ #else case NEW_ENV_VAR: #endif case ENV_USERVAR: if (ep) { *epc = 0; env_opt_add(ep); } ep = epc = &buf[i+1]; break; case ENV_ESC: i++; /*FALL THROUGH*/ default: if (epc) *epc++ = buf[i]; break; } } if (ep) { *epc = 0; env_opt_add(ep); } env_opt_end(1); break; case TELQUAL_IS: case TELQUAL_INFO: /* Ignore for now. We shouldn't get it anyway. */ break; default: break; } } #define OPT_REPLY_SIZE 256 unsigned char *opt_reply; unsigned char *opt_replyp; unsigned char *opt_replyend; void env_opt_start() { if (opt_reply) opt_reply = (unsigned char *)realloc(opt_reply, OPT_REPLY_SIZE); else opt_reply = (unsigned char *)malloc(OPT_REPLY_SIZE); if (opt_reply == NULL) { /*@*/ printf("env_opt_start: malloc()/realloc() failed!!!\n"); opt_reply = opt_replyp = opt_replyend = NULL; return; } opt_replyp = opt_reply; opt_replyend = opt_reply + OPT_REPLY_SIZE; *opt_replyp++ = IAC; *opt_replyp++ = SB; *opt_replyp++ = telopt_environ; *opt_replyp++ = TELQUAL_IS; } void env_opt_start_info() { env_opt_start(); if (opt_replyp) opt_replyp[-1] = TELQUAL_INFO; } void env_opt_add(ep) register unsigned char *ep; { register unsigned char *vp, c; if (opt_reply == NULL) /*XXX*/ return; /*XXX*/ if (ep == NULL || *ep == '\0') { /* Send user defined variables first. */ env_default(1, 0); - while (ep = env_default(0, 0)) + while ((ep = env_default(0, 0))) env_opt_add(ep); /* Now add the list of well know variables. */ env_default(1, 1); - while (ep = env_default(0, 1)) + while ((ep = env_default(0, 1))) env_opt_add(ep); return; } vp = env_getvalue(ep); if (opt_replyp + (vp ? strlen((char *)vp) : 0) + strlen((char *)ep) + 6 > opt_replyend) { register int len; opt_replyend += OPT_REPLY_SIZE; len = opt_replyend - opt_reply; opt_reply = (unsigned char *)realloc(opt_reply, len); if (opt_reply == NULL) { /*@*/ printf("env_opt_add: realloc() failed!!!\n"); opt_reply = opt_replyp = opt_replyend = NULL; return; } opt_replyp = opt_reply + len - (opt_replyend - opt_replyp); opt_replyend = opt_reply + len; } if (opt_welldefined(ep)) #ifdef OLD_ENVIRON if (telopt_environ == TELOPT_OLD_ENVIRON) *opt_replyp++ = old_env_var; else #endif *opt_replyp++ = NEW_ENV_VAR; else *opt_replyp++ = ENV_USERVAR; for (;;) { - while (c = *ep++) { + while ((c = *ep++)) { switch(c&0xff) { case IAC: *opt_replyp++ = IAC; break; case NEW_ENV_VAR: case NEW_ENV_VALUE: case ENV_ESC: case ENV_USERVAR: *opt_replyp++ = ENV_ESC; break; } *opt_replyp++ = c; } - if (ep = vp) { + if ((ep = vp)) { #ifdef OLD_ENVIRON if (telopt_environ == TELOPT_OLD_ENVIRON) *opt_replyp++ = old_env_value; else #endif *opt_replyp++ = NEW_ENV_VALUE; vp = NULL; } else break; } } int opt_welldefined(ep) char *ep; { if ((strcmp(ep, "USER") == 0) || (strcmp(ep, "DISPLAY") == 0) || (strcmp(ep, "PRINTER") == 0) || (strcmp(ep, "SYSTEMTYPE") == 0) || (strcmp(ep, "JOB") == 0) || (strcmp(ep, "ACCT") == 0)) return(1); return(0); } void env_opt_end(emptyok) register int emptyok; { register int len; len = opt_replyp - opt_reply + 2; if (emptyok || len > 6) { *opt_replyp++ = IAC; *opt_replyp++ = SE; if (NETROOM() > len) { ring_supply_data(&netoring, opt_reply, len); printsub('>', &opt_reply[2], len - 2); } /*@*/ else printf("slc_end_reply: not enough room\n"); } if (opt_reply) { free(opt_reply); opt_reply = opt_replyp = opt_replyend = NULL; } } int telrcv() { register int c; register int scc; register unsigned char *sbp; int count; int returnValue = 0; scc = 0; count = 0; while (TTYROOM() > 2) { if (scc == 0) { if (count) { ring_consumed(&netiring, count); returnValue = 1; count = 0; } sbp = netiring.consume; scc = ring_full_consecutive(&netiring); if (scc == 0) { /* No more data coming in */ break; } } c = *sbp++ & 0xff, scc--; count++; #ifdef ENCRYPTION if (decrypt_input) c = (*decrypt_input)(c); #endif /* ENCRYPTION */ switch (telrcv_state) { case TS_CR: telrcv_state = TS_DATA; if (c == '\0') { break; /* Ignore \0 after CR */ } else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) { TTYADD(c); break; } /* Else, fall through */ case TS_DATA: if (c == IAC) { telrcv_state = TS_IAC; break; } # if defined(TN3270) if (In3270) { *Ifrontp++ = c; while (scc > 0) { c = *sbp++ & 0377, scc--; count++; #ifdef ENCRYPTION if (decrypt_input) c = (*decrypt_input)(c); #endif /* ENCRYPTION */ if (c == IAC) { telrcv_state = TS_IAC; break; } *Ifrontp++ = c; } } else # endif /* defined(TN3270) */ /* * The 'crmod' hack (see following) is needed * since we can't * set CRMOD on output only. * Machines like MULTICS like to send \r without * \n; since we must turn off CRMOD to get proper * input, the mapping is done here (sigh). */ if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) { if (scc > 0) { c = *sbp&0xff; #ifdef ENCRYPTION if (decrypt_input) c = (*decrypt_input)(c); #endif /* ENCRYPTION */ if (c == 0) { sbp++, scc--; count++; /* a "true" CR */ TTYADD('\r'); } else if (my_want_state_is_dont(TELOPT_ECHO) && (c == '\n')) { sbp++, scc--; count++; TTYADD('\n'); } else { #ifdef ENCRYPTION if (decrypt_input) (*decrypt_input)(-1); #endif /* ENCRYPTION */ TTYADD('\r'); if (crmod) { TTYADD('\n'); } } } else { telrcv_state = TS_CR; TTYADD('\r'); if (crmod) { TTYADD('\n'); } } } else { TTYADD(c); } continue; case TS_IAC: process_iac: switch (c) { case WILL: telrcv_state = TS_WILL; continue; case WONT: telrcv_state = TS_WONT; continue; case DO: telrcv_state = TS_DO; continue; case DONT: telrcv_state = TS_DONT; continue; case DM: /* * We may have missed an urgent notification, * so make sure we flush whatever is in the * buffer currently. */ printoption("RCVD", IAC, DM); SYNCHing = 1; (void) ttyflush(1); SYNCHing = stilloob(); settimer(gotDM); break; case SB: SB_CLEAR(); telrcv_state = TS_SB; continue; # if defined(TN3270) case EOR: if (In3270) { if (Ibackp == Ifrontp) { Ibackp = Ifrontp = Ibuf; ISend = 0; /* should have been! */ } else { Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1); ISend = 1; } } printoption("RCVD", IAC, EOR); break; # endif /* defined(TN3270) */ case IAC: # if !defined(TN3270) TTYADD(IAC); # else /* !defined(TN3270) */ if (In3270) { *Ifrontp++ = IAC; } else { TTYADD(IAC); } # endif /* !defined(TN3270) */ break; case NOP: case GA: default: printoption("RCVD", IAC, c); break; } telrcv_state = TS_DATA; continue; case TS_WILL: printoption("RCVD", WILL, c); willoption(c); SetIn3270(); telrcv_state = TS_DATA; continue; case TS_WONT: printoption("RCVD", WONT, c); wontoption(c); SetIn3270(); telrcv_state = TS_DATA; continue; case TS_DO: printoption("RCVD", DO, c); dooption(c); SetIn3270(); if (c == TELOPT_NAWS) { sendnaws(); } else if (c == TELOPT_LFLOW) { localflow = 1; setcommandmode(); setconnmode(0); } telrcv_state = TS_DATA; continue; case TS_DONT: printoption("RCVD", DONT, c); dontoption(c); flushline = 1; setconnmode(0); /* set new tty mode (maybe) */ SetIn3270(); telrcv_state = TS_DATA; continue; case TS_SB: if (c == IAC) { telrcv_state = TS_SE; } else { SB_ACCUM(c); } continue; case TS_SE: if (c != SE) { if (c != IAC) { /* * This is an error. We only expect to get * "IAC IAC" or "IAC SE". Several things may * have happend. An IAC was not doubled, the * IAC SE was left off, or another option got * inserted into the suboption are all possibilities. * If we assume that the IAC was not doubled, * and really the IAC SE was left off, we could * get into an infinate loop here. So, instead, * we terminate the suboption, and process the * partial suboption if we can. */ SB_ACCUM(IAC); SB_ACCUM(c); subpointer -= 2; SB_TERM(); printoption("In SUBOPTION processing, RCVD", IAC, c); suboption(); /* handle sub-option */ SetIn3270(); telrcv_state = TS_IAC; goto process_iac; } SB_ACCUM(c); telrcv_state = TS_SB; } else { SB_ACCUM(IAC); SB_ACCUM(SE); subpointer -= 2; SB_TERM(); suboption(); /* handle sub-option */ SetIn3270(); telrcv_state = TS_DATA; } } } if (count) ring_consumed(&netiring, count); return returnValue||count; } static int bol = 1, local = 0; int rlogin_susp() { if (local) { local = 0; bol = 1; command(0, "z\n", 2); return(1); } return(0); } static int telsnd() { int tcc; int count; int returnValue = 0; unsigned char *tbp; tcc = 0; count = 0; while (NETROOM() > 2) { register int sc; register int c; if (tcc == 0) { if (count) { ring_consumed(&ttyiring, count); returnValue = 1; count = 0; } tbp = ttyiring.consume; tcc = ring_full_consecutive(&ttyiring); if (tcc == 0) { break; } } c = *tbp++ & 0xff, sc = strip(c), tcc--; count++; if (rlogin != _POSIX_VDISABLE) { if (bol) { bol = 0; if (sc == rlogin) { local = 1; continue; } } else if (local) { local = 0; if (sc == '.' || c == termEofChar) { bol = 1; command(0, "close\n", 6); continue; } if (sc == termSuspChar) { bol = 1; command(0, "z\n", 2); continue; } if (sc == escape) { command(0, (char *)tbp, tcc); bol = 1; count += tcc; tcc = 0; flushline = 1; break; } if (sc != rlogin) { ++tcc; --tbp; --count; c = sc = rlogin; } } if ((sc == '\n') || (sc == '\r')) bol = 1; } else if (sc == escape) { /* * Double escape is a pass through of a single escape character. */ if (tcc && strip(*tbp) == escape) { tbp++; tcc--; count++; bol = 0; } else { command(0, (char *)tbp, tcc); bol = 1; count += tcc; tcc = 0; flushline = 1; break; } } else bol = 0; #ifdef KLUDGELINEMODE if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) { if (tcc > 0 && strip(*tbp) == echoc) { tcc--; tbp++; count++; } else { dontlecho = !dontlecho; settimer(echotoggle); setconnmode(0); flushline = 1; break; } } #endif if (MODE_LOCAL_CHARS(globalmode)) { if (TerminalSpecialChars(sc) == 0) { bol = 1; break; } } if (my_want_state_is_wont(TELOPT_BINARY)) { switch (c) { case '\n': /* * If we are in CRMOD mode (\r ==> \n) * on our local machine, then probably * a newline (unix) is CRLF (TELNET). */ if (MODE_LOCAL_CHARS(globalmode)) { NETADD('\r'); } NETADD('\n'); bol = flushline = 1; break; case '\r': if (!crlf) { NET2ADD('\r', '\0'); } else { NET2ADD('\r', '\n'); } bol = flushline = 1; break; case IAC: NET2ADD(IAC, IAC); break; default: NETADD(c); break; } } else if (c == IAC) { NET2ADD(IAC, IAC); } else { NETADD(c); } } if (count) ring_consumed(&ttyiring, count); return returnValue||count; /* Non-zero if we did anything */ } /* * Scheduler() * * Try to do something. * * If we do something useful, return 1; else return 0. * */ int Scheduler(block) int block; /* should we block in the select ? */ { /* One wants to be a bit careful about setting returnValue * to one, since a one implies we did some useful work, * and therefore probably won't be called to block next * time (TN3270 mode only). */ int returnValue; int netin, netout, netex, ttyin, ttyout; /* Decide which rings should be processed */ netout = ring_full_count(&netoring) && (flushline || (my_want_state_is_wont(TELOPT_LINEMODE) #ifdef KLUDGELINEMODE && (!kludgelinemode || my_want_state_is_do(TELOPT_SGA)) #endif ) || my_want_state_is_will(TELOPT_BINARY)); ttyout = ring_full_count(&ttyoring); #if defined(TN3270) - ttyin = ring_empty_count(&ttyiring) && (shell_active == 0); + ttyin = ring_empty_count(&ttyiring) && (clienteof == 0) && (shell_active == 0); #else /* defined(TN3270) */ - ttyin = ring_empty_count(&ttyiring); + ttyin = ring_empty_count(&ttyiring) && (clienteof == 0); #endif /* defined(TN3270) */ #if defined(TN3270) netin = ring_empty_count(&netiring); # else /* !defined(TN3270) */ netin = !ISend && ring_empty_count(&netiring); # endif /* !defined(TN3270) */ netex = !SYNCHing; /* If we have seen a signal recently, reset things */ # if defined(TN3270) && defined(unix) if (HaveInput) { HaveInput = 0; (void) signal(SIGIO, inputAvailable); } #endif /* defined(TN3270) && defined(unix) */ /* Call to system code to process rings */ returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block); /* Now, look at the input rings, looking for work to do. */ if (ring_full_count(&ttyiring)) { # if defined(TN3270) if (In3270) { int c; c = DataFromTerminal(ttyiring.consume, ring_full_consecutive(&ttyiring)); if (c) { returnValue = 1; ring_consumed(&ttyiring, c); } } else { # endif /* defined(TN3270) */ returnValue |= telsnd(); # if defined(TN3270) } # endif /* defined(TN3270) */ } if (ring_full_count(&netiring)) { # if !defined(TN3270) returnValue |= telrcv(); # else /* !defined(TN3270) */ returnValue = Push3270(); # endif /* !defined(TN3270) */ } return returnValue; } /* * Select from tty and network... */ void telnet(user) char *user; { sys_telnet_init(); #if defined(AUTHENTICATION) || defined(ENCRYPTION) { static char local_host[256] = { 0 }; if (!local_host[0]) { gethostname(local_host, sizeof(local_host)); local_host[sizeof(local_host)-1] = 0; } auth_encrypt_init(local_host, hostname, "TELNET", 0); auth_encrypt_user(user); } #endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */ # if !defined(TN3270) if (telnetport) { #if defined(AUTHENTICATION) if (autologin) send_will(TELOPT_AUTHENTICATION, 1); #endif #ifdef ENCRYPTION send_do(TELOPT_ENCRYPT, 1); send_will(TELOPT_ENCRYPT, 1); #endif /* ENCRYPTION */ send_do(TELOPT_SGA, 1); send_will(TELOPT_TTYPE, 1); send_will(TELOPT_NAWS, 1); send_will(TELOPT_TSPEED, 1); send_will(TELOPT_LFLOW, 1); send_will(TELOPT_LINEMODE, 1); send_will(TELOPT_NEW_ENVIRON, 1); send_do(TELOPT_STATUS, 1); if (env_getvalue((unsigned char *)"DISPLAY")) send_will(TELOPT_XDISPLOC, 1); if (eight) tel_enter_binary(eight); } # endif /* !defined(TN3270) */ # if !defined(TN3270) for (;;) { int schedValue; while ((schedValue = Scheduler(0)) != 0) { if (schedValue == -1) { setcommandmode(); return; } } if (Scheduler(1) == -1) { setcommandmode(); return; } } # else /* !defined(TN3270) */ for (;;) { int schedValue; while (!In3270 && !shell_active) { if (Scheduler(1) == -1) { setcommandmode(); return; } } while ((schedValue = Scheduler(0)) != 0) { if (schedValue == -1) { setcommandmode(); return; } } /* If there is data waiting to go out to terminal, don't * schedule any more data for the terminal. */ if (ring_full_count(&ttyoring)) { schedValue = 1; } else { if (shell_active) { if (shell_continue() == 0) { ConnectScreen(); } } else if (In3270) { schedValue = DoTerminalOutput(); } } if (schedValue && (shell_active == 0)) { if (Scheduler(1) == -1) { setcommandmode(); return; } } } # endif /* !defined(TN3270) */ } #if 0 /* XXX - this not being in is a bug */ /* * nextitem() * * Return the address of the next "item" in the TELNET data * stream. This will be the address of the next character if * the current address is a user data character, or it will * be the address of the character following the TELNET command * if the current address is a TELNET IAC ("I Am a Command") * character. */ static char * nextitem(current) char *current; { if ((*current&0xff) != IAC) { return current+1; } switch (*(current+1)&0xff) { case DO: case DONT: case WILL: case WONT: return current+3; case SB: /* loop forever looking for the SE */ { register char *look = current+2; for (;;) { if ((*look++&0xff) == IAC) { if ((*look++&0xff) == SE) { return look; } } } } default: return current+2; } } #endif /* 0 */ /* * netclear() * * We are about to do a TELNET SYNCH operation. Clear * the path to the network. * * Things are a bit tricky since we may have sent the first * byte or so of a previous TELNET command into the network. * So, we have to scan the network buffer from the beginning * until we are up to where we want to be. * * A side effect of what we do, just to keep things * simple, is to clear the urgent data pointer. The principal * caller should be setting the urgent data pointer AFTER calling * us in any case. */ static void netclear() { #if 0 /* XXX */ register char *thisitem, *next; char *good; #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) thisitem = netobuf; while ((next = nextitem(thisitem)) <= netobuf.send) { thisitem = next; } /* Now, thisitem is first before/at boundary. */ good = netobuf; /* where the good bytes go */ while (netoring.add > 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); } } #endif /* 0 */ } /* * These routines add various telnet commands to the data stream. */ static void doflush() { NET2ADD(IAC, DO); NETADD(TELOPT_TM); flushline = 1; flushout = 1; (void) ttyflush(1); /* Flush/drop output */ /* do printoption AFTER flush, otherwise the output gets tossed... */ printoption("SENT", DO, TELOPT_TM); } void xmitAO() { NET2ADD(IAC, AO); printoption("SENT", IAC, AO); if (autoflush) { doflush(); } } void xmitEL() { NET2ADD(IAC, EL); printoption("SENT", IAC, EL); } void xmitEC() { NET2ADD(IAC, EC); printoption("SENT", IAC, EC); } int dosynch() { netclear(); /* clear the path to the network */ NETADD(IAC); setneturg(); NETADD(DM); printoption("SENT", IAC, DM); return 1; } int want_status_response = 0; int get_status() { unsigned char tmp[16]; register unsigned char *cp; if (my_want_state_is_dont(TELOPT_STATUS)) { printf("Remote side does not support STATUS option\n"); return 0; } cp = tmp; *cp++ = IAC; *cp++ = SB; *cp++ = TELOPT_STATUS; *cp++ = TELQUAL_SEND; *cp++ = IAC; *cp++ = SE; if (NETROOM() >= cp - tmp) { ring_supply_data(&netoring, tmp, cp-tmp); printsub('>', tmp+2, cp - tmp - 2); } ++want_status_response; return 1; } void intp() { NET2ADD(IAC, IP); printoption("SENT", IAC, IP); flushline = 1; if (autoflush) { doflush(); } if (autosynch) { dosynch(); } } void sendbrk() { NET2ADD(IAC, BREAK); printoption("SENT", IAC, BREAK); flushline = 1; if (autoflush) { doflush(); } if (autosynch) { dosynch(); } } void sendabort() { NET2ADD(IAC, ABORT); printoption("SENT", IAC, ABORT); flushline = 1; if (autoflush) { doflush(); } if (autosynch) { dosynch(); } } void sendsusp() { NET2ADD(IAC, SUSP); printoption("SENT", IAC, SUSP); flushline = 1; if (autoflush) { doflush(); } if (autosynch) { dosynch(); } } void sendeof() { NET2ADD(IAC, xEOF); printoption("SENT", IAC, xEOF); } void sendayt() { NET2ADD(IAC, AYT); printoption("SENT", IAC, AYT); } /* * Send a window size update to the remote system. */ void sendnaws() { long rows, cols; unsigned char tmp[16]; register unsigned char *cp; if (my_state_is_wont(TELOPT_NAWS)) return; #define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \ if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; } if (TerminalWindowSize(&rows, &cols) == 0) { /* Failed */ return; } cp = tmp; *cp++ = IAC; *cp++ = SB; *cp++ = TELOPT_NAWS; PUTSHORT(cp, cols); PUTSHORT(cp, rows); *cp++ = IAC; *cp++ = SE; if (NETROOM() >= cp - tmp) { ring_supply_data(&netoring, tmp, cp-tmp); printsub('>', tmp+2, cp - tmp - 2); } } void tel_enter_binary(rw) int rw; { if (rw&1) send_do(TELOPT_BINARY, 1); if (rw&2) send_will(TELOPT_BINARY, 1); } void tel_leave_binary(rw) int rw; { if (rw&1) send_dont(TELOPT_BINARY, 1); if (rw&2) send_wont(TELOPT_BINARY, 1); } diff --git a/crypto/telnet/telnet/terminal.c b/crypto/telnet/telnet/terminal.c index b5ceeda2b525..a2383d9e6696 100644 --- a/crypto/telnet/telnet/terminal.c +++ b/crypto/telnet/telnet/terminal.c @@ -1,240 +1,244 @@ /* * Copyright (c) 1988, 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. */ #ifndef lint -static char sccsid[] = "@(#)terminal.c 8.2 (Berkeley) 2/16/95"; +static const char sccsid[] = "@(#)terminal.c 8.2 (Berkeley) 2/16/95"; #endif /* not lint */ #include #include #include "ring.h" #include "externs.h" #include "types.h" +#if defined(ENCRYPTION) +#include +#endif + Ring ttyoring, ttyiring; unsigned char ttyobuf[2*BUFSIZ], ttyibuf[BUFSIZ]; int termdata; /* Debugging flag */ #ifdef USE_TERMIO # ifndef VDISCARD cc_t termFlushChar; # endif # ifndef VLNEXT cc_t termLiteralNextChar; # endif # ifndef VSUSP cc_t termSuspChar; # endif # ifndef VWERASE cc_t termWerasChar; # endif # ifndef VREPRINT cc_t termRprntChar; # endif # ifndef VSTART cc_t termStartChar; # endif # ifndef VSTOP cc_t termStopChar; # endif # ifndef VEOL cc_t termForw1Char; # endif # ifndef VEOL2 cc_t termForw2Char; # endif # ifndef VSTATUS cc_t termAytChar; # endif #else cc_t termForw2Char; cc_t termAytChar; #endif /* * initialize the terminal data structures. */ void init_terminal() { if (ring_init(&ttyoring, ttyobuf, sizeof ttyobuf) != 1) { exit(1); } if (ring_init(&ttyiring, ttyibuf, sizeof ttyibuf) != 1) { exit(1); } autoflush = TerminalAutoFlush(); } /* * Send as much data as possible to the terminal. * * Return value: * -1: No useful work done, data waiting to go out. * 0: No data was waiting, so nothing was done. * 1: All waiting data was written out. * n: All data - n was written out. */ int ttyflush(drop) int drop; { register int n, n0, n1; n0 = ring_full_count(&ttyoring); if ((n1 = n = ring_full_consecutive(&ttyoring)) > 0) { if (drop) { TerminalFlushOutput(); /* we leave 'n' alone! */ } else { n = TerminalWrite(ttyoring.consume, n); } } if (n > 0) { if (termdata && n) { Dump('>', ttyoring.consume, n); } /* * If we wrote everything, and the full count is * larger than what we wrote, then write the * rest of the buffer. */ if (n1 == n && n0 > n) { n1 = n0 - n; if (!drop) n1 = TerminalWrite(ttyoring.bottom, n1); if (n1 > 0) n += n1; } ring_consumed(&ttyoring, n); } if (n < 0) return -1; if (n == n0) { if (n0) return -1; return 0; } return n0 - n + 1; } /* * These routines decides on what the mode should be (based on the values * of various global variables). */ int getconnmode() { extern int linemode; int mode = 0; #ifdef KLUDGELINEMODE extern int kludgelinemode; #endif if (In3270) return(MODE_FLOW); if (my_want_state_is_dont(TELOPT_ECHO)) mode |= MODE_ECHO; if (localflow) mode |= MODE_FLOW; if (my_want_state_is_will(TELOPT_BINARY)) mode |= MODE_INBIN; if (his_want_state_is_will(TELOPT_BINARY)) mode |= MODE_OUTBIN; #ifdef KLUDGELINEMODE if (kludgelinemode) { if (my_want_state_is_dont(TELOPT_SGA)) { mode |= (MODE_TRAPSIG|MODE_EDIT); if (dontlecho && (clocks.echotoggle > clocks.modenegotiated)) { mode &= ~MODE_ECHO; } } return(mode); } #endif if (my_want_state_is_will(TELOPT_LINEMODE)) mode |= linemode; return(mode); } void setconnmode(force) int force; { #ifdef ENCRYPTION static int enc_passwd = 0; #endif /* ENCRYPTION */ register int newmode; newmode = getconnmode()|(force?MODE_FORCE:0); TerminalNewMode(newmode); #ifdef ENCRYPTION if ((newmode & (MODE_ECHO|MODE_EDIT)) == MODE_EDIT) { if (my_want_state_is_will(TELOPT_ENCRYPT) && (enc_passwd == 0) && !encrypt_output) { encrypt_request_start(0, 0); enc_passwd = 1; } } else { if (enc_passwd) { encrypt_request_end(); enc_passwd = 0; } } #endif /* ENCRYPTION */ } void setcommandmode() { TerminalNewMode(-1); } diff --git a/crypto/telnet/telnet/tn3270.c b/crypto/telnet/telnet/tn3270.c index a75cd1ecb5a9..5a453d98cc5b 100644 --- a/crypto/telnet/telnet/tn3270.c +++ b/crypto/telnet/telnet/tn3270.c @@ -1,411 +1,411 @@ /* * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. */ #ifndef lint -static char sccsid[] = "@(#)tn3270.c 8.2 (Berkeley) 5/30/95"; +static const char sccsid[] = "@(#)tn3270.c 8.2 (Berkeley) 5/30/95"; #endif /* not lint */ #include #include #include "general.h" #include "defines.h" #include "ring.h" #include "externs.h" #include "fdset.h" #if defined(TN3270) #include "../ctlr/screen.h" #include "../general/globals.h" #include "../sys_curses/telextrn.h" #include "../ctlr/externs.h" #if defined(unix) int HaveInput, /* There is input available to scan */ cursesdata, /* Do we dump curses data? */ sigiocount; /* Number of times we got a SIGIO */ char tline[200]; char *transcom = 0; /* transparent mode command (default: none) */ #endif /* defined(unix) */ char Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp; static char sb_terminal[] = { IAC, SB, TELOPT_TTYPE, TELQUAL_IS, 'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2', IAC, SE }; #define SBTERMMODEL 13 static int Sent3270TerminalType; /* Have we said we are a 3270? */ #endif /* defined(TN3270) */ void init_3270() { #if defined(TN3270) #if defined(unix) HaveInput = 0; sigiocount = 0; #endif /* defined(unix) */ Sent3270TerminalType = 0; Ifrontp = Ibackp = Ibuf; init_ctlr(); /* Initialize some things */ init_keyboard(); init_screen(); init_system(); #endif /* defined(TN3270) */ } #if defined(TN3270) /* * DataToNetwork - queue up some data to go to network. If "done" is set, * then when last byte is queued, we add on an IAC EOR sequence (so, * don't call us with "done" until you want that done...) * * We actually do send all the data to the network buffer, since our * only client needs for us to do that. */ int DataToNetwork(buffer, count, done) register char *buffer; /* where the data is */ register int count; /* how much to send */ int done; /* is this the last of a logical block */ { register int loop, c; int origCount; origCount = count; while (count) { /* If not enough room for EORs, IACs, etc., wait */ if (NETROOM() < 6) { fd_set o; FD_ZERO(&o); netflush(); while (NETROOM() < 6) { FD_SET(net, &o); (void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0, (struct timeval *) 0); netflush(); } } c = ring_empty_count(&netoring); if (c > count) { c = count; } loop = c; while (loop) { if (((unsigned char)*buffer) == IAC) { break; } buffer++; loop--; } if ((c = c-loop)) { ring_supply_data(&netoring, buffer-c, c); count -= c; } if (loop) { NET2ADD(IAC, IAC); count--; buffer++; } } if (done) { NET2ADD(IAC, EOR); netflush(); /* try to move along as quickly as ... */ } return(origCount - count); } #if defined(unix) void inputAvailable(signo) int signo; { HaveInput = 1; sigiocount++; } #endif /* defined(unix) */ void outputPurge() { (void) ttyflush(1); } /* * The following routines are places where the various tn3270 * routines make calls into telnet.c. */ /* * DataToTerminal - queue up some data to go to terminal. * * Note: there are people who call us and depend on our processing * *all* the data at one time (thus the select). */ int DataToTerminal(buffer, count) register char *buffer; /* where the data is */ register int count; /* how much to send */ { register int c; int origCount; origCount = count; while (count) { if (TTYROOM() == 0) { #if defined(unix) fd_set o; FD_ZERO(&o); #endif /* defined(unix) */ (void) ttyflush(0); while (TTYROOM() == 0) { #if defined(unix) FD_SET(tout, &o); (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0, (struct timeval *) 0); #endif /* defined(unix) */ (void) ttyflush(0); } } c = TTYROOM(); if (c > count) { c = count; } ring_supply_data(&ttyoring, buffer, c); count -= c; buffer += c; } return(origCount); } /* * Push3270 - Try to send data along the 3270 output (to screen) direction. */ int Push3270() { int save = ring_full_count(&netiring); if (save) { if (Ifrontp+save > Ibuf+sizeof Ibuf) { if (Ibackp != Ibuf) { memmove(Ibuf, Ibackp, Ifrontp-Ibackp); Ifrontp -= (Ibackp-Ibuf); Ibackp = Ibuf; } } if (Ifrontp+save < Ibuf+sizeof Ibuf) { (void)telrcv(); } } return save != ring_full_count(&netiring); } /* * Finish3270 - get the last dregs of 3270 data out to the terminal * before quitting. */ void Finish3270() { while (Push3270() || !DoTerminalOutput()) { #if defined(unix) HaveInput = 0; #endif /* defined(unix) */ ; } } /* StringToTerminal - output a null terminated string to the terminal */ void StringToTerminal(s) char *s; { int count; count = strlen(s); if (count) { (void) DataToTerminal(s, count); /* we know it always goes... */ } } #if ((!defined(NOT43)) || defined(PUTCHAR)) /* _putchar - output a single character to the terminal. This name is so that * curses(3x) can call us to send out data. */ void _putchar(c) char c; { #if defined(sun) /* SunOS 4.0 bug */ c &= 0x7f; #endif /* defined(sun) */ if (cursesdata) { Dump('>', &c, 1); } if (!TTYROOM()) { (void) DataToTerminal(&c, 1); } else { TTYADD(c); } } #endif /* ((!defined(NOT43)) || defined(PUTCHAR)) */ void SetIn3270() { if (Sent3270TerminalType && my_want_state_is_will(TELOPT_BINARY) && my_want_state_is_do(TELOPT_BINARY) && !donebinarytoggle) { if (!In3270) { In3270 = 1; Init3270(); /* Initialize 3270 functions */ /* initialize terminal key mapping */ InitTerminal(); /* Start terminal going */ setconnmode(0); } } else { if (In3270) { StopScreen(1); In3270 = 0; Stop3270(); /* Tell 3270 we aren't here anymore */ setconnmode(0); } } } /* * tn3270_ttype() * * Send a response to a terminal type negotiation. * * Return '0' if no more responses to send; '1' if a response sent. */ int tn3270_ttype() { /* * Try to send a 3270 type terminal name. Decide which one based * on the format of our screen, and (in the future) color * capaiblities. */ InitTerminal(); /* Sets MaxNumberColumns, MaxNumberLines */ if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) { Sent3270TerminalType = 1; if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) { MaxNumberLines = 27; MaxNumberColumns = 132; sb_terminal[SBTERMMODEL] = '5'; } else if (MaxNumberLines >= 43) { MaxNumberLines = 43; MaxNumberColumns = 80; sb_terminal[SBTERMMODEL] = '4'; } else if (MaxNumberLines >= 32) { MaxNumberLines = 32; MaxNumberColumns = 80; sb_terminal[SBTERMMODEL] = '3'; } else { MaxNumberLines = 24; MaxNumberColumns = 80; sb_terminal[SBTERMMODEL] = '2'; } NumberLines = 24; /* before we start out... */ NumberColumns = 80; ScreenSize = NumberLines*NumberColumns; if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) { ExitString("Programming error: MAXSCREENSIZE too small.\n", 1); /*NOTREACHED*/ } printsub('>', sb_terminal+2, sizeof sb_terminal-2); ring_supply_data(&netoring, sb_terminal, sizeof sb_terminal); return 1; } else { return 0; } } #if defined(unix) int settranscom(argc, argv) int argc; char *argv[]; { int i; if (argc == 1 && transcom) { transcom = 0; } if (argc == 1) { return 1; } transcom = tline; (void) strcpy(transcom, argv[1]); for (i = 2; i < argc; ++i) { (void) strcat(transcom, " "); (void) strcat(transcom, argv[i]); } return 1; } #endif /* defined(unix) */ #endif /* defined(TN3270) */ diff --git a/crypto/telnet/telnet/utilities.c b/crypto/telnet/telnet/utilities.c index 06d08a45120c..0ee882ebd87c 100644 --- a/crypto/telnet/telnet/utilities.c +++ b/crypto/telnet/telnet/utilities.c @@ -1,939 +1,946 @@ /* * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. */ #ifndef lint -static char sccsid[] = "@(#)utilities.c 8.3 (Berkeley) 5/30/95"; +static const char sccsid[] = "@(#)utilities.c 8.3 (Berkeley) 5/30/95"; #endif /* not lint */ #define TELOPTS #define TELCMDS #define SLC_NAMES #include #include +#include #include +#include #include #include "general.h" #include "fdset.h" #include "ring.h" #include "defines.h" #include "externs.h" +#if defined(AUTHENTICATION) +#include +#endif +#if defined(ENCRYPTION) +#include +#endif + FILE *NetTrace = 0; /* Not in bss, since needs to stay */ int prettydump; /* * upcase() * * Upcase (in place) the argument. */ void upcase(argument) register char *argument; { register int c; while ((c = *argument) != 0) { if (islower(c)) { *argument = toupper(c); } argument++; } } /* * SetSockOpt() * * Compensate for differences in 4.2 and 4.3 systems. */ int SetSockOpt(fd, level, option, yesno) int fd, level, option, yesno; { #ifndef NOT43 return setsockopt(fd, level, option, (char *)&yesno, sizeof yesno); #else /* NOT43 */ if (yesno == 0) { /* Can't do that in 4.2! */ fprintf(stderr, "Error: attempt to turn off an option 0x%x.\n", option); return -1; } return setsockopt(fd, level, option, 0, 0); #endif /* NOT43 */ } /* * The following are routines used to print out debugging information. */ unsigned char NetTraceFile[256] = "(standard output)"; void SetNetTrace(file) register char *file; { if (NetTrace && NetTrace != stdout) fclose(NetTrace); if (file && (strcmp(file, "-") != 0)) { NetTrace = fopen(file, "w"); if (NetTrace) { strcpy((char *)NetTraceFile, file); return; } fprintf(stderr, "Cannot open %s.\n", file); } NetTrace = stdout; strcpy((char *)NetTraceFile, "(standard output)"); } void Dump(direction, buffer, length) char direction; unsigned char *buffer; int length; { # define BYTES_PER_LINE 32 # define min(x,y) ((x' */ unsigned char *pointer; /* where suboption data sits */ int length; /* length of suboption data */ { register int i; char buf[512]; extern int want_status_response; if (showoptions || direction == 0 || (want_status_response && (pointer[0] == TELOPT_STATUS))) { if (direction) { fprintf(NetTrace, "%s IAC SB ", (direction == '<')? "RCVD":"SENT"); if (length >= 3) { register int j; i = pointer[length-2]; j = pointer[length-1]; if (i != IAC || j != SE) { fprintf(NetTrace, "(terminated by "); if (TELOPT_OK(i)) fprintf(NetTrace, "%s ", TELOPT(i)); else if (TELCMD_OK(i)) fprintf(NetTrace, "%s ", TELCMD(i)); else fprintf(NetTrace, "%d ", i); if (TELOPT_OK(j)) fprintf(NetTrace, "%s", TELOPT(j)); else if (TELCMD_OK(j)) fprintf(NetTrace, "%s", TELCMD(j)); else fprintf(NetTrace, "%d", j); fprintf(NetTrace, ", not IAC SE!) "); } } length -= 2; } if (length < 1) { fprintf(NetTrace, "(Empty suboption??\?)"); if (NetTrace == stdout) fflush(NetTrace); return; } switch (pointer[0]) { case TELOPT_TTYPE: fprintf(NetTrace, "TERMINAL-TYPE "); switch (pointer[1]) { case TELQUAL_IS: fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2); break; case TELQUAL_SEND: fprintf(NetTrace, "SEND"); break; default: fprintf(NetTrace, "- unknown qualifier %d (0x%x).", pointer[1], pointer[1]); } break; case TELOPT_TSPEED: fprintf(NetTrace, "TERMINAL-SPEED"); if (length < 2) { fprintf(NetTrace, " (empty suboption??\?)"); break; } switch (pointer[1]) { case TELQUAL_IS: fprintf(NetTrace, " IS "); fprintf(NetTrace, "%.*s", length-2, (char *)pointer+2); break; default: if (pointer[1] == 1) fprintf(NetTrace, " SEND"); else fprintf(NetTrace, " %d (unknown)", pointer[1]); for (i = 2; i < length; i++) fprintf(NetTrace, " ?%d?", pointer[i]); break; } break; case TELOPT_LFLOW: fprintf(NetTrace, "TOGGLE-FLOW-CONTROL"); if (length < 2) { fprintf(NetTrace, " (empty suboption??\?)"); break; } switch (pointer[1]) { case LFLOW_OFF: fprintf(NetTrace, " OFF"); break; case LFLOW_ON: fprintf(NetTrace, " ON"); break; case LFLOW_RESTART_ANY: fprintf(NetTrace, " RESTART-ANY"); break; case LFLOW_RESTART_XON: fprintf(NetTrace, " RESTART-XON"); break; default: fprintf(NetTrace, " %d (unknown)", pointer[1]); } for (i = 2; i < length; i++) fprintf(NetTrace, " ?%d?", pointer[i]); break; case TELOPT_NAWS: fprintf(NetTrace, "NAWS"); if (length < 2) { fprintf(NetTrace, " (empty suboption??\?)"); break; } if (length == 2) { fprintf(NetTrace, " ?%d?", pointer[1]); break; } fprintf(NetTrace, " %d %d (%d)", pointer[1], pointer[2], (int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2]))); if (length == 4) { fprintf(NetTrace, " ?%d?", pointer[3]); break; } fprintf(NetTrace, " %d %d (%d)", pointer[3], pointer[4], (int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4]))); for (i = 5; i < length; i++) fprintf(NetTrace, " ?%d?", pointer[i]); break; #if defined(AUTHENTICATION) case TELOPT_AUTHENTICATION: fprintf(NetTrace, "AUTHENTICATION"); if (length < 2) { fprintf(NetTrace, " (empty suboption??\?)"); break; } switch (pointer[1]) { case TELQUAL_REPLY: case TELQUAL_IS: fprintf(NetTrace, " %s ", (pointer[1] == TELQUAL_IS) ? "IS" : "REPLY"); if (AUTHTYPE_NAME_OK(pointer[2])) fprintf(NetTrace, "%s ", AUTHTYPE_NAME(pointer[2])); else fprintf(NetTrace, "%d ", pointer[2]); if (length < 3) { fprintf(NetTrace, "(partial suboption??\?)"); break; } fprintf(NetTrace, "%s|%s", ((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? "CLIENT" : "SERVER", ((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? "MUTUAL" : "ONE-WAY"); auth_printsub(&pointer[1], length - 1, buf, sizeof(buf)); fprintf(NetTrace, "%s", buf); break; case TELQUAL_SEND: i = 2; fprintf(NetTrace, " SEND "); while (i < length) { if (AUTHTYPE_NAME_OK(pointer[i])) fprintf(NetTrace, "%s ", AUTHTYPE_NAME(pointer[i])); else fprintf(NetTrace, "%d ", pointer[i]); if (++i >= length) { fprintf(NetTrace, "(partial suboption??\?)"); break; } fprintf(NetTrace, "%s|%s ", ((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? "CLIENT" : "SERVER", ((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? "MUTUAL" : "ONE-WAY"); ++i; } break; case TELQUAL_NAME: i = 2; fprintf(NetTrace, " NAME \""); while (i < length) putc(pointer[i++], NetTrace); putc('"', NetTrace); break; default: for (i = 2; i < length; i++) fprintf(NetTrace, " ?%d?", pointer[i]); break; } break; #endif #ifdef ENCRYPTION case TELOPT_ENCRYPT: fprintf(NetTrace, "ENCRYPT"); if (length < 2) { fprintf(NetTrace, " (empty suboption??\?)"); break; } switch (pointer[1]) { case ENCRYPT_START: fprintf(NetTrace, " START"); break; case ENCRYPT_END: fprintf(NetTrace, " END"); break; case ENCRYPT_REQSTART: fprintf(NetTrace, " REQUEST-START"); break; case ENCRYPT_REQEND: fprintf(NetTrace, " REQUEST-END"); break; case ENCRYPT_IS: case ENCRYPT_REPLY: fprintf(NetTrace, " %s ", (pointer[1] == ENCRYPT_IS) ? "IS" : "REPLY"); if (length < 3) { fprintf(NetTrace, " (partial suboption??\?)"); break; } if (ENCTYPE_NAME_OK(pointer[2])) fprintf(NetTrace, "%s ", ENCTYPE_NAME(pointer[2])); else fprintf(NetTrace, " %d (unknown)", pointer[2]); encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf)); fprintf(NetTrace, "%s", buf); break; case ENCRYPT_SUPPORT: i = 2; fprintf(NetTrace, " SUPPORT "); while (i < length) { if (ENCTYPE_NAME_OK(pointer[i])) fprintf(NetTrace, "%s ", ENCTYPE_NAME(pointer[i])); else fprintf(NetTrace, "%d ", pointer[i]); i++; } break; case ENCRYPT_ENC_KEYID: fprintf(NetTrace, " ENC_KEYID "); goto encommon; case ENCRYPT_DEC_KEYID: fprintf(NetTrace, " DEC_KEYID "); goto encommon; default: fprintf(NetTrace, " %d (unknown)", pointer[1]); encommon: for (i = 2; i < length; i++) fprintf(NetTrace, " %d", pointer[i]); break; } break; #endif /* ENCRYPTION */ case TELOPT_LINEMODE: fprintf(NetTrace, "LINEMODE "); if (length < 2) { fprintf(NetTrace, " (empty suboption??\?)"); break; } switch (pointer[1]) { case WILL: fprintf(NetTrace, "WILL "); goto common; case WONT: fprintf(NetTrace, "WONT "); goto common; case DO: fprintf(NetTrace, "DO "); goto common; case DONT: fprintf(NetTrace, "DONT "); common: if (length < 3) { fprintf(NetTrace, "(no option??\?)"); break; } switch (pointer[2]) { case LM_FORWARDMASK: fprintf(NetTrace, "Forward Mask"); for (i = 3; i < length; i++) fprintf(NetTrace, " %x", pointer[i]); break; default: fprintf(NetTrace, "%d (unknown)", pointer[2]); for (i = 3; i < length; i++) fprintf(NetTrace, " %d", pointer[i]); break; } break; case LM_SLC: fprintf(NetTrace, "SLC"); for (i = 2; i < length - 2; i += 3) { if (SLC_NAME_OK(pointer[i+SLC_FUNC])) fprintf(NetTrace, " %s", SLC_NAME(pointer[i+SLC_FUNC])); else fprintf(NetTrace, " %d", pointer[i+SLC_FUNC]); switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) { case SLC_NOSUPPORT: fprintf(NetTrace, " NOSUPPORT"); break; case SLC_CANTCHANGE: fprintf(NetTrace, " CANTCHANGE"); break; case SLC_VARIABLE: fprintf(NetTrace, " VARIABLE"); break; case SLC_DEFAULT: fprintf(NetTrace, " DEFAULT"); break; } fprintf(NetTrace, "%s%s%s", pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "", pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "", pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : ""); if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN| SLC_FLUSHOUT| SLC_LEVELBITS)) fprintf(NetTrace, "(0x%x)", pointer[i+SLC_FLAGS]); fprintf(NetTrace, " %d;", pointer[i+SLC_VALUE]); if ((pointer[i+SLC_VALUE] == IAC) && (pointer[i+SLC_VALUE+1] == IAC)) i++; } for (; i < length; i++) fprintf(NetTrace, " ?%d?", pointer[i]); break; case LM_MODE: fprintf(NetTrace, "MODE "); if (length < 3) { fprintf(NetTrace, "(no mode??\?)"); break; } { char tbuf[64]; sprintf(tbuf, "%s%s%s%s%s", pointer[2]&MODE_EDIT ? "|EDIT" : "", pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "", pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "", pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "", pointer[2]&MODE_ACK ? "|ACK" : ""); fprintf(NetTrace, "%s", tbuf[1] ? &tbuf[1] : "0"); } if (pointer[2]&~(MODE_MASK)) fprintf(NetTrace, " (0x%x)", pointer[2]); for (i = 3; i < length; i++) fprintf(NetTrace, " ?0x%x?", pointer[i]); break; default: fprintf(NetTrace, "%d (unknown)", pointer[1]); for (i = 2; i < length; i++) fprintf(NetTrace, " %d", pointer[i]); } break; case TELOPT_STATUS: { register char *cp; register int j, k; fprintf(NetTrace, "STATUS"); switch (pointer[1]) { default: if (pointer[1] == TELQUAL_SEND) fprintf(NetTrace, " SEND"); else fprintf(NetTrace, " %d (unknown)", pointer[1]); for (i = 2; i < length; i++) fprintf(NetTrace, " ?%d?", pointer[i]); break; case TELQUAL_IS: if (--want_status_response < 0) want_status_response = 0; if (NetTrace == stdout) fprintf(NetTrace, " IS\r\n"); else fprintf(NetTrace, " IS\n"); for (i = 2; i < length; i++) { switch(pointer[i]) { case DO: cp = "DO"; goto common2; case DONT: cp = "DONT"; goto common2; case WILL: cp = "WILL"; goto common2; case WONT: cp = "WONT"; goto common2; common2: i++; if (TELOPT_OK((int)pointer[i])) fprintf(NetTrace, " %s %s", cp, TELOPT(pointer[i])); else fprintf(NetTrace, " %s %d", cp, pointer[i]); if (NetTrace == stdout) fprintf(NetTrace, "\r\n"); else fprintf(NetTrace, "\n"); break; case SB: fprintf(NetTrace, " SB "); i++; j = k = i; while (j < length) { if (pointer[j] == SE) { if (j+1 == length) break; if (pointer[j+1] == SE) j++; else break; } pointer[k++] = pointer[j++]; } printsub(0, &pointer[i], k - i); if (i < length) { fprintf(NetTrace, " SE"); i = j; } else i = j - 1; if (NetTrace == stdout) fprintf(NetTrace, "\r\n"); else fprintf(NetTrace, "\n"); break; default: fprintf(NetTrace, " %d", pointer[i]); break; } } break; } break; } case TELOPT_XDISPLOC: fprintf(NetTrace, "X-DISPLAY-LOCATION "); switch (pointer[1]) { case TELQUAL_IS: fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2); break; case TELQUAL_SEND: fprintf(NetTrace, "SEND"); break; default: fprintf(NetTrace, "- unknown qualifier %d (0x%x).", pointer[1], pointer[1]); } break; case TELOPT_NEW_ENVIRON: fprintf(NetTrace, "NEW-ENVIRON "); #ifdef OLD_ENVIRON goto env_common1; case TELOPT_OLD_ENVIRON: fprintf(NetTrace, "OLD-ENVIRON"); env_common1: #endif switch (pointer[1]) { case TELQUAL_IS: fprintf(NetTrace, "IS "); goto env_common; case TELQUAL_SEND: fprintf(NetTrace, "SEND "); goto env_common; case TELQUAL_INFO: fprintf(NetTrace, "INFO "); env_common: { register int noquote = 2; #if defined(ENV_HACK) && defined(OLD_ENVIRON) extern int old_env_var, old_env_value; #endif for (i = 2; i < length; i++ ) { switch (pointer[i]) { case NEW_ENV_VALUE: #ifdef OLD_ENVIRON /* case NEW_ENV_OVAR: */ if (pointer[0] == TELOPT_OLD_ENVIRON) { # ifdef ENV_HACK if (old_env_var == OLD_ENV_VALUE) fprintf(NetTrace, "\" (VALUE) " + noquote); else # endif fprintf(NetTrace, "\" VAR " + noquote); } else #endif /* OLD_ENVIRON */ fprintf(NetTrace, "\" VALUE " + noquote); noquote = 2; break; case NEW_ENV_VAR: #ifdef OLD_ENVIRON /* case OLD_ENV_VALUE: */ if (pointer[0] == TELOPT_OLD_ENVIRON) { # ifdef ENV_HACK if (old_env_value == OLD_ENV_VAR) fprintf(NetTrace, "\" (VAR) " + noquote); else # endif fprintf(NetTrace, "\" VALUE " + noquote); } else #endif /* OLD_ENVIRON */ fprintf(NetTrace, "\" VAR " + noquote); noquote = 2; break; case ENV_ESC: fprintf(NetTrace, "\" ESC " + noquote); noquote = 2; break; case ENV_USERVAR: fprintf(NetTrace, "\" USERVAR " + noquote); noquote = 2; break; default: - def_case: if (isprint(pointer[i]) && pointer[i] != '"') { if (noquote) { putc('"', NetTrace); noquote = 0; } putc(pointer[i], NetTrace); } else { fprintf(NetTrace, "\" %03o " + noquote, pointer[i]); noquote = 2; } break; } } if (!noquote) putc('"', NetTrace); break; } } break; default: if (TELOPT_OK(pointer[0])) fprintf(NetTrace, "%s (unknown)", TELOPT(pointer[0])); else fprintf(NetTrace, "%d (unknown)", pointer[0]); for (i = 1; i < length; i++) fprintf(NetTrace, " %d", pointer[i]); break; } if (direction) { if (NetTrace == stdout) fprintf(NetTrace, "\r\n"); else fprintf(NetTrace, "\n"); } if (NetTrace == stdout) fflush(NetTrace); } } /* EmptyTerminal - called to make sure that the terminal buffer is empty. * Note that we consider the buffer to run all the * way to the kernel (thus the select). */ void EmptyTerminal() { #if defined(unix) fd_set o; FD_ZERO(&o); #endif /* defined(unix) */ if (TTYBYTES() == 0) { #if defined(unix) FD_SET(tout, &o); (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0, (struct timeval *) 0); /* wait for TTLOWAT */ #endif /* defined(unix) */ } else { while (TTYBYTES()) { (void) ttyflush(0); #if defined(unix) FD_SET(tout, &o); (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0, (struct timeval *) 0); /* wait for TTLOWAT */ #endif /* defined(unix) */ } } } void SetForExit() { setconnmode(0); #if defined(TN3270) if (In3270) { Finish3270(); } #else /* defined(TN3270) */ do { (void)telrcv(); /* Process any incoming data */ EmptyTerminal(); } while (ring_full_count(&netiring)); /* While there is any */ #endif /* defined(TN3270) */ setcommandmode(); fflush(stdout); fflush(stderr); #if defined(TN3270) if (In3270) { StopScreen(1); } #endif /* defined(TN3270) */ setconnmode(0); EmptyTerminal(); /* Flush the path to the tty */ setcommandmode(); } void Exit(returnCode) int returnCode; { SetForExit(); exit(returnCode); } void ExitString(string, returnCode) char *string; int returnCode; { SetForExit(); fwrite(string, 1, strlen(string), stderr); exit(returnCode); } diff --git a/crypto/telnet/telnetd/authenc.c b/crypto/telnet/telnetd/authenc.c index ccb463c94d1e..bff80a2b5879 100644 --- a/crypto/telnet/telnetd/authenc.c +++ b/crypto/telnet/telnetd/authenc.c @@ -1,91 +1,91 @@ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. 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. */ #ifndef lint -static char sccsid[] = "@(#)authenc.c 8.2 (Berkeley) 5/30/95"; +static const char sccsid[] = "@(#)authenc.c 8.2 (Berkeley) 5/30/95"; #endif /* not lint */ #if defined(AUTHENTICATION) || defined(ENCRYPTION) #include "telnetd.h" #include int net_write(str, len) unsigned char *str; int len; { if (nfrontp + len < netobuf + BUFSIZ) { memmove((void *)nfrontp, (void *)str, len); nfrontp += len; return(len); } return(0); } void net_encrypt() { #ifdef ENCRYPTION char *s = (nclearto > nbackp) ? nclearto : nbackp; if (s < nfrontp && encrypt_output) { (*encrypt_output)((unsigned char *)s, nfrontp - s); } nclearto = nfrontp; #endif /* ENCRYPTION */ } int telnet_spin() { ttloop(); return(0); } char * telnet_getenv(val) char *val; { extern char *getenv(); return(getenv(val)); } char * telnet_gets(prompt, result, length, echo) char *prompt; char *result; int length; int echo; { return((char *)0); } #endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */ diff --git a/crypto/telnet/telnetd/ext.h b/crypto/telnet/telnetd/ext.h index 19bc0d638296..f60139e078ac 100644 --- a/crypto/telnet/telnetd/ext.h +++ b/crypto/telnet/telnetd/ext.h @@ -1,240 +1,242 @@ /* * 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. * * @(#)ext.h 8.2 (Berkeley) 12/15/93 */ /* * 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(SecurID) extern int require_SecurID; #endif #if defined(AUTHENTICATION) extern int auth_level; #endif extern slcfun slctab[NSLC + 1]; /* slc mapping table */ char *terminaltype; /* * I/O data buffers, pointers, and counters. */ 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 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; extern int SYNCHing; /* we are in TELNET SYNCH mode */ #ifndef P # ifdef __STDC__ # define P(x) x # else # define P(x) () # endif #endif 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 int end_slc P((unsigned char **)), getnpty P((void)), #ifndef convex getpty P((int *)), #endif login_tty P((int)), 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)); #ifdef ENCRYPTION extern void (*encrypt_output) P((unsigned char *, int)); extern int (*decrypt_input) P((int)); extern char *nclearto; #endif /* ENCRYPTION */ /* * The following are some clocks used to decide how to interpret * the relationship between various variables. */ extern struct { int system, /* what the current time is */ echotoggle, /* last time user entered echo character */ modenegotiated, /* last time operating mode negotiated */ didnetreceive, /* last time we read data from network */ ttypesubopt, /* ttype subopt is received */ tspeedsubopt, /* tspeed subopt is received */ environsubopt, /* environ subopt is received */ oenvironsubopt, /* old environ subopt is received */ xdisplocsubopt, /* xdisploc subopt is received */ baseline, /* time started to do timed action */ gotDM; /* when did we last see a data mark */ } clocks; #if defined(CRAY2) && defined(UNICOS5) extern int needtermstat; #endif #ifndef DEFAULT_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 +# ifdef __FreeBSD__ +# define DEFAULT_IM "\r\n\r\nFreeBSD (%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 # endif # endif #endif diff --git a/crypto/telnet/telnetd/global.c b/crypto/telnet/telnetd/global.c index af21acc69fb1..0699d005d48b 100644 --- a/crypto/telnet/telnetd/global.c +++ b/crypto/telnet/telnetd/global.c @@ -1,48 +1,48 @@ /* * 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. */ #ifndef lint -static char sccsid[] = "@(#)global.c 8.1 (Berkeley) 6/4/93"; +static const char sccsid[] = "@(#)global.c 8.1 (Berkeley) 6/4/93"; #endif /* not lint */ /* * 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. */ #include "defs.h" #define extern #include "ext.h" diff --git a/crypto/telnet/telnetd/slc.c b/crypto/telnet/telnetd/slc.c index 6cbb7ababa1b..9579d0df32ff 100644 --- a/crypto/telnet/telnetd/slc.c +++ b/crypto/telnet/telnetd/slc.c @@ -1,491 +1,491 @@ /* * 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. */ #ifndef lint -static char sccsid[] = "@(#)slc.c 8.2 (Berkeley) 5/30/95"; +static const char sccsid[] = "@(#)slc.c 8.2 (Berkeley) 5/30/95"; #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 */ /* * 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 char func, flag; register cc_t val; { register int hislevel, mylevel; hislevel = flag & SLC_LEVELBITS; - mylevel = slctab[func].defset.flag & SLC_LEVELBITS; + mylevel = slctab[(int)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; + slctab[(int)func].current.flag = flag; + slctab[(int)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; + slctab[(int)func].current.flag = SLC_NOSUPPORT; } else { - slctab[func].current.flag = slctab[func].defset.flag; + slctab[(int)func].current.flag = slctab[(int)func].defset.flag; } - slctab[func].current.val = slctab[func].defset.val; - add_slc(func, slctab[func].current.flag, - slctab[func].current.val); + slctab[(int)func].current.val = slctab[(int)func].defset.val; + add_slc(func, slctab[(int)func].current.flag, + slctab[(int)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) { + if (slctab[(int)func].sptr) { /* * We can change this one. */ - slctab[func].current.val = val; - *(slctab[func].sptr) = val; - slctab[func].current.flag = flag; + slctab[(int)func].current.val = val; + *(slctab[(int)func].sptr) = val; + slctab[(int)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; + slctab[(int)func].current.flag = flag; + slctab[(int)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; + slctab[(int)func].current.flag = flag; } else { flag &= ~SLC_LEVELBITS; flag |= mylevel; - slctab[func].current.flag = flag; + slctab[(int)func].current.flag = flag; if (mylevel == SLC_CANTCHANGE) { - slctab[func].current.val = - slctab[func].defset.val; - val = slctab[func].current.val; + slctab[(int)func].current.val = + slctab[(int)func].defset.val; + val = slctab[(int)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 */ memmove(def_slcbuf, ptr, 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 */ diff --git a/crypto/telnet/telnetd/state.c b/crypto/telnet/telnetd/state.c index 4ee8bea66f97..faf4088b537f 100644 --- a/crypto/telnet/telnetd/state.c +++ b/crypto/telnet/telnetd/state.c @@ -1,1612 +1,1615 @@ /* * 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. */ #ifndef lint -static char sccsid[] = "@(#)state.c 8.5 (Berkeley) 5/30/95"; +static const char sccsid[] = "@(#)state.c 8.5 (Berkeley) 5/30/95"; #endif /* not lint */ #include "telnetd.h" #if defined(AUTHENTICATION) #include #endif +#if defined(ENCRYPTION) +#include +#endif unsigned char doopt[] = { IAC, DO, '%', 'c', 0 }; unsigned char dont[] = { IAC, DONT, '%', 'c', 0 }; unsigned char will[] = { IAC, WILL, '%', 'c', 0 }; unsigned char wont[] = { IAC, WONT, '%', 'c', 0 }; int not42 = 1; /* * Buffer for sub-options, and macros * for suboptions buffer manipulations */ unsigned char subbuffer[512], *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); \ } #define SB_GET() ((*subpointer++)&0xff) #define SB_EOF() (subpointer >= subend) #define SB_LEN() (subend - subpointer) #ifdef ENV_HACK unsigned char *subsave; #define SB_SAVE() subsave = subpointer; #define SB_RESTORE() subpointer = subsave; #endif /* * State for recv fsm */ #define TS_DATA 0 /* base state */ #define TS_IAC 1 /* look for double IAC's */ #define TS_CR 2 /* CR-LF ->'s CR */ #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 " */ void telrcv() { register int c; static int state = TS_DATA; #if defined(CRAY2) && defined(UNICOS5) char *opfrontp = pfrontp; #endif while (ncc > 0) { if ((&ptyobuf[BUFSIZ] - pfrontp) < 2) break; c = *netip++ & 0377, ncc--; #ifdef ENCRYPTION if (decrypt_input) c = (*decrypt_input)(c); #endif /* ENCRYPTION */ 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_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 /* ENCRYPTION */ #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 #endif { #ifdef ENCRYPTION if (decrypt_input) (void)(*decrypt_input)(-1); #endif /* ENCRYPTION */ 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; } /* * 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); 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); } } #if defined(CRAY2) && defined(UNICOS5) if (!linemode) { char xptyobuf[BUFSIZ+NETSLOP]; char xbuf2[BUFSIZ]; register char *cp; int n = pfrontp - opfrontp, oc; memmove(xptyobuf, opfrontp, n); pfrontp = opfrontp; pfrontp += term_input(xptyobuf, pfrontp, n, BUFSIZ+NETSLOP, xbuf2, &oc, BUFSIZ); for (cp = xbuf2; oc > 0; --oc) if ((*nfrontp++ = *cp++) == IAC) *nfrontp++ = IAC; } #endif /* defined(CRAY2) && defined(UNICOS5) */ } /* end of telrcv */ /* * The will/wont/do/dont state machines are based on Dave Borman's * Telnet option processing state machine. * * These correspond to the following states: * my_state = the last negotiated state * want_state = what I want the state to go to * want_resp = how many requests I have sent * All state defaults are negative, and resp defaults to 0. * * When initiating a request to change state to new_state: * * if ((want_resp == 0 && new_state == my_state) || want_state == new_state) { * do nothing; * } else { * want_state = new_state; * send new_state; * want_resp++; * } * * When receiving new_state: * * if (want_resp) { * want_resp--; * if (want_resp && (new_state == my_state)) * want_resp--; * } * if ((want_resp == 0) && (new_state != want_state)) { * if (ok_to_switch_to new_state) * want_state = new_state; * else * want_resp++; * send want_state; * } * my_state = new_state; * * Note that new_state is implied in these functions by the function itself. * will and do imply positive new_state, wont and dont imply negative. * * Finally, there is one catch. If we send a negative response to a * positive request, my_state will be the positive while want_state will * remain negative. my_state will revert to negative when the negative * acknowlegment arrives from the peer. Thus, my_state generally tells * us not only the last negotiated state, but also tells us what the peer * wants to be doing as well. It is important to understand this difference * as we may wish to be processing data streams based on our desired state * (want_state) or based on what the peer thinks the state is (my_state). * * This all works fine because if the peer sends a positive request, the data * that we receive prior to negative acknowlegment will probably be affected * by the positive state, and we can process it as such (if we can; if we * can't then it really doesn't matter). If it is that important, then the * peer probably should be buffering until this option state negotiation * is complete. * */ void send_do(option, init) int option, 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)); } #ifdef AUTHENTICATION extern void auth_request(); #endif #ifdef LINEMODE extern void doclientstat(); #endif #ifdef ENCRYPTION extern void encrypt_send_support(); #endif /* ENCRYPTION */ void willoption(option) int 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; case TELOPT_ECHO: /* * See comments below for more info. */ not42 = 0; /* looks like a 4.2 system */ break; 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; #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; #endif #ifdef ENCRYPTION case TELOPT_ENCRYPT: func = encrypt_send_support; changeok++; break; #endif /* ENCRYPTION */ 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 */ /* * 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 */ #ifdef AUTHENTICATION case TELOPT_AUTHENTICATION: func = auth_request; break; #endif #ifdef ENCRYPTION case TELOPT_ENCRYPT: func = encrypt_send_support; break; #endif /* ENCRYPTION */ case TELOPT_LFLOW: func = flowstat; break; } } } set_his_state_will(option); if (func) (*func)(); } /* end of willoption */ void send_dont(option, init) int option, 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)); } void wontoption(option) int option; { /* * Process client input. */ 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; case TELOPT_BINARY: init_termbuf(); tty_binaryin(0); set_termbuf(); break; #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; #if defined(AUTHENTICATION) case TELOPT_AUTHENTICATION: auth_finished(0, AUTH_REJECT); break; #endif /* * For options that we might spin waiting for * sub-negotiation, if the client turns off the * option rather than responding to the request, * we have to treat it here as if we got a response * 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_TSPEED: settimer(tspeedsubopt); break; case TELOPT_XDISPLOC: settimer(xdisplocsubopt); break; case TELOPT_OLD_ENVIRON: settimer(oenvironsubopt); 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; #if defined(AUTHENTICATION) case TELOPT_AUTHENTICATION: auth_finished(0, AUTH_REJECT); break; #endif default: break; } } } set_his_state_wont(option); } /* end of wontoption */ void send_will(option, init) int option, 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 !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 * leave it at that. This is so that when we talk to * clients that understand KLUDGELINEMODE but not LINEMODE, * we'll keep them in char-at-a-time mode. */ int turn_on_sga = 0; #endif void dooption(option) int option; { 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: #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_BINARY: init_termbuf(); tty_binaryout(1); set_termbuf(); 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_STATUS: 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_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; #endif /* ENCRYPTION */ 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: #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); } } set_my_state_will(option); } /* end of dooption */ void send_wont(option, init) int option, 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)); } void dontoption(option) int option; { /* * Process client input. */ 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; 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_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; } set_my_want_state_wont(option); if (my_state_is_will(option)) send_wont(option, 0); } set_my_state_wont(option); } /* end of dontoption */ #ifdef ENV_HACK int env_ovar = -1; int env_ovalue = -1; #else /* ENV_HACK */ # define env_ovar OLD_ENV_VAR # define env_ovalue OLD_ENV_VALUE #endif /* ENV_HACK */ /* * suboption() * * Look at the sub-option buffer, and try to be helpful to the other * side. * * Currently we recognize: * * Terminal type is * Linemode * Window size * Terminal speed */ void suboption() { register int subchar; DIAG(TD_OPTIONS, {netflush(); printsub('<', subpointer, SB_LEN()+2);}); subchar = SB_GET(); switch (subchar) { case TELOPT_TSPEED: { register int xspeed, rspeed; if (his_state_is_wont(TELOPT_TSPEED)) /* Ignore if option disabled */ break; settimer(tspeedsubopt); if (SB_EOF() || SB_GET() != TELQUAL_IS) return; xspeed = atoi((char *)subpointer); while (SB_GET() != ',' && !SB_EOF()); if (SB_EOF()) return; rspeed = atoi((char *)subpointer); clientstat(TELOPT_TSPEED, xspeed, rspeed); break; } /* end of case TELOPT_TSPEED */ case TELOPT_TTYPE: { /* Yaaaay! */ static char terminalname[41]; if (his_state_is_wont(TELOPT_TTYPE)) /* Ignore if option disabled */ break; settimer(ttypesubopt); if (SB_EOF() || SB_GET() != TELQUAL_IS) { return; /* ??? XXX but, this is the most robust */ } terminaltype = terminalname; while ((terminaltype < (terminalname + sizeof terminalname-1)) && !SB_EOF()) { register int c; c = SB_GET(); if (isupper(c)) { c = tolower(c); } *terminaltype++ = c; /* accumulate name */ } *terminaltype = 0; terminaltype = terminalname; break; } /* end of case TELOPT_TTYPE */ case TELOPT_NAWS: { register int xwinsize, ywinsize; if (his_state_is_wont(TELOPT_NAWS)) /* Ignore if option disabled */ break; if (SB_EOF()) return; xwinsize = SB_GET() << 8; if (SB_EOF()) return; xwinsize |= SB_GET(); if (SB_EOF()) return; ywinsize = SB_GET() << 8; if (SB_EOF()) return; ywinsize |= SB_GET(); clientstat(TELOPT_NAWS, xwinsize, ywinsize); break; } /* 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; if (SB_EOF()) break; mode = SB_GET(); switch (mode) { case TELQUAL_SEND: if (my_state_is_will(TELOPT_STATUS)) send_status(); break; case TELQUAL_IS: break; default: break; } break; } /* end of case TELOPT_STATUS */ case TELOPT_XDISPLOC: { if (SB_EOF() || SB_GET() != TELQUAL_IS) return; settimer(xdisplocsubopt); subpointer[SB_LEN()] = '\0'; (void)setenv("DISPLAY", (char *)subpointer, 1); break; } /* end of case TELOPT_XDISPLOC */ #ifdef TELOPT_NEW_ENVIRON case TELOPT_NEW_ENVIRON: #endif case TELOPT_OLD_ENVIRON: { register int c; register char *cp, *varp, *valp; if (SB_EOF()) return; c = SB_GET(); if (c == TELQUAL_IS) { if (subchar == TELOPT_OLD_ENVIRON) settimer(oenvironsubopt); else settimer(environsubopt); } else if (c != TELQUAL_INFO) { return; } #ifdef TELOPT_NEW_ENVIRON if (subchar == TELOPT_NEW_ENVIRON) { while (!SB_EOF()) { c = SB_GET(); if ((c == NEW_ENV_VAR) || (c == ENV_USERVAR)) 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. */ 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; 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; 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; case ENV_ESC: if (!SB_EOF()) c = SB_GET(); /* FALL THROUGH */ default: empty = 0; continue; } empty = 1; } if (empty) { if (last == OLD_ENV_VALUE) 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: env_ovar = OLD_ENV_VAR; env_ovalue = OLD_ENV_VALUE; } 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);}); } } SB_RESTORE(); #endif while (!SB_EOF()) { c = SB_GET(); if ((c == env_ovar) || (c == ENV_USERVAR)) break; } } if (SB_EOF()) 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; case NEW_ENV_VAR: case ENV_USERVAR: *cp = '\0'; if (valp) (void)setenv(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 (valp) (void)setenv(varp, valp, 1); else unsetenv(varp); break; } /* end of case TELOPT_NEW_ENVIRON */ #if defined(AUTHENTICATION) case TELOPT_AUTHENTICATION: if (SB_EOF()) break; switch(SB_GET()) { case TELQUAL_SEND: case TELQUAL_REPLY: /* * These are sent by us and cannot be sent by * the client. */ break; case TELQUAL_IS: auth_is(subpointer, SB_LEN()); break; case TELQUAL_NAME: auth_name(subpointer, SB_LEN()); break; } break; #endif #ifdef ENCRYPTION case TELOPT_ENCRYPT: if (SB_EOF()) break; switch(SB_GET()) { case ENCRYPT_SUPPORT: encrypt_support(subpointer, SB_LEN()); break; case ENCRYPT_IS: encrypt_is(subpointer, SB_LEN()); break; case ENCRYPT_REPLY: encrypt_reply(subpointer, SB_LEN()); break; case ENCRYPT_START: encrypt_start(subpointer, SB_LEN()); break; case ENCRYPT_END: encrypt_end(); break; case ENCRYPT_REQSTART: 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; case ENCRYPT_ENC_KEYID: encrypt_enc_keyid(subpointer, SB_LEN()); break; case ENCRYPT_DEC_KEYID: encrypt_dec_keyid(subpointer, SB_LEN()); break; default: break; } break; #endif /* ENCRYPTION */ default: break; } /* end of switch */ } /* end of suboption */ void doclientstat() { 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 */ 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); } } 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); } } #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); writenet(statusbuf, ncp - statusbuf); netflush(); /* Send it on its way */ DIAG(TD_OPTIONS, {printsub('>', statusbuf, ncp - statusbuf); netflush();}); } diff --git a/crypto/telnet/telnetd/sys_term.c b/crypto/telnet/telnetd/sys_term.c index 67a2f942d347..fe9509e9e508 100644 --- a/crypto/telnet/telnetd/sys_term.c +++ b/crypto/telnet/telnetd/sys_term.c @@ -1,2303 +1,2325 @@ /* * 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. */ #ifndef lint -static char sccsid[] = "@(#)sys_term.c 8.4+1 (Berkeley) 5/30/95"; +static const char sccsid[] = "@(#)sys_term.c 8.4+1 (Berkeley) 5/30/95"; #endif /* not lint */ #include "telnetd.h" #include "pathnames.h" #if defined(AUTHENTICATION) #include #endif +extern char *altlogin; +int cleanopen(char *line); +void scrub_env(void); + #if defined(CRAY) || defined(__hpux) # define PARENT_DOES_UTMP #endif +int utmp_len = MAXHOSTNAMELEN; #ifdef NEWINIT #include -int utmp_len = MAXHOSTNAMELEN; /* sizeof(init_request.host) */ #else /* NEWINIT*/ # ifdef UTMPX # include struct utmpx wtmp; # else # include struct utmp wtmp; # endif /* UTMPX */ -int utmp_len = sizeof(wtmp.ut_host); # ifndef PARENT_DOES_UTMP +#ifdef _PATH_WTMP +char wtmpf[] = _PATH_WTMP; +#else char wtmpf[] = "/usr/adm/wtmp"; +#endif +#ifdef _PATH_UTMP +char utmpf[] = _PATH_UTMP; +#else char utmpf[] = "/etc/utmp"; +#endif # else /* PARENT_DOES_UTMP */ char wtmpf[] = "/etc/wtmp"; # endif /* PARENT_DOES_UTMP */ +#include + # ifdef CRAY #include #include # if (UNICOS_LVL == '7.0') || (UNICOS_LVL == '7.1') # define UNICOS7x # endif # ifdef UNICOS7x #include #include extern int secflag; extern struct sysv sysv; # endif /* UNICOS7x */ # endif /* CRAY */ #endif /* NEWINIT */ #ifdef STREAMSPTY #include #include #endif #define SCPYN(a, b) (void) strncpy(a, b, sizeof(a)) #define SCMPN(a, b) strncmp(a, b, sizeof(a)) #ifdef STREAMS #include #endif #ifdef __hpux #include #include #endif #include #ifdef t_erase #undef t_erase #undef t_kill #undef t_intrc #undef t_quitc #undef t_startc #undef t_stopc #undef t_eofc #undef t_brkc #undef t_suspc #undef t_dsuspc #undef t_rprntc #undef t_flushc #undef t_werasc #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 # ifndef TCSANOW # ifdef TCSETS # define TCSANOW TCSETS # define TCSADRAIN TCSETSW # define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t) # else # ifdef TCSETA # define TCSANOW TCSETA # define TCSADRAIN TCSETAW # define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t) # else # define TCSANOW TIOCSETA # define TCSADRAIN TIOCSETAW # define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t) # endif # endif # define tcsetattr(f, a, t) ioctl(f, a, t) # define cfsetospeed(tp, val) (tp)->c_cflag &= ~CBAUD; \ (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)<c_cflag & CIBAUD)>>IBSHIFT) # else # define cfsetispeed(tp, val) (tp)->c_cflag &= ~CBAUD; \ (tp)->c_cflag |= (val) # define cfgetispeed(tp) ((tp)->c_cflag & CBAUD) # endif # endif /* TCSANOW */ struct termios termbuf, termbuf2; /* pty control structure */ # ifdef STREAMSPTY int ttyfd = -1; # endif #endif /* USE_TERMIO */ /* * init_termbuf() * copy_termbuf(cp) * set_termbuf() * * These three routines are used to get and set the "termbuf" structure * to and from the kernel. init_termbuf() gets the current settings. * copy_termbuf() hands in a new "termbuf" to write to the kernel, and * set_termbuf() writes the structure into the kernel. */ void init_termbuf() { #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); # 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((char *)&termbuf, cp, len); termbuf2 = termbuf; } #endif /* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */ void set_termbuf() { /* * Only make the necessary changes. */ #ifndef USE_TERMIO if (memcmp((char *)&termbuf.sg, (char *)&termbuf2.sg, sizeof(termbuf.sg))) (void) ioctl(pty, TIOCSETN, (char *)&termbuf.sg); if (memcmp((char *)&termbuf.tc, (char *)&termbuf2.tc, sizeof(termbuf.tc))) (void) ioctl(pty, TIOCSETC, (char *)&termbuf.tc); if (memcmp((char *)&termbuf.ltc, (char *)&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((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf))) # ifdef STREAMSPTY (void) tcsetattr(ttyfd, TCSANOW, &termbuf); # else (void) tcsetattr(pty, TCSANOW, &termbuf); # endif # if defined(CRAY2) && defined(UNICOS5) needtermstat = 1; # endif #endif /* USE_TERMIO */ } /* * spcset(func, valp, valpp) * * This function takes various special characters (func), and * sets *valp to the current value of that character, and * *valpp to point to where in the "termbuf" structure that * value is kept. * * 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; { #define setval(a, b) *valp = termbuf.c_cc[a]; \ *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: #ifdef VSTART setval(VSTART, SLC_VARIABLE); #else defval(0x13); #endif case SLC_XOFF: #ifdef VSTOP setval(VSTOP, SLC_VARIABLE); #else defval(0x11); #endif case SLC_EW: #ifdef VWERASE setval(VWERASE, SLC_VARIABLE); #else defval(0); #endif case SLC_RP: #ifdef VREPRINT setval(VREPRINT, SLC_VARIABLE); #else defval(0); #endif case SLC_LNEXT: #ifdef VLNEXT setval(VLNEXT, SLC_VARIABLE); #else defval(0); #endif case SLC_AO: #if !defined(VDISCARD) && defined(VFLUSHO) # define VDISCARD VFLUSHO #endif #ifdef VDISCARD setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT); #else defval(0); #endif case SLC_SUSP: #ifdef VSUSP setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN); #else defval(0); #endif #ifdef VEOL case SLC_FORW1: setval(VEOL, SLC_VARIABLE); #endif #ifdef VEOL2 case SLC_FORW2: setval(VEOL2, SLC_VARIABLE); #endif case SLC_AYT: #ifdef VSTATUS setval(VSTATUS, SLC_VARIABLE); #else defval(0); #endif case SLC_BRK: case SLC_SYNCH: case SLC_EOR: defval(0); default: *valp = 0; *valpp = 0; return(SLC_NOSUPPORT); } } #endif /* USE_TERMIO */ #ifdef CRAY /* * getnpty() * * Return the number of pty's configured into the system. */ int getnpty() { #ifdef _SC_CRAY_NPTY int numptys; if ((numptys = sysconf(_SC_CRAY_NPTY)) != -1) return numptys; else #endif /* _SC_CRAY_NPTY */ return 128; } #endif /* CRAY */ #ifndef convex /* * getpty() * * Allocate a pty. As a side effect, the external character * array "line" contains the name of the slave side. * * Returns the file descriptor of the opened pty. */ #ifndef __GNUC__ char *line = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; #else static char Xline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; char *line = Xline; #endif #ifdef CRAY char *myline = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; #endif /* CRAY */ int getpty(ptynum) int *ptynum; { register int p; #ifdef STREAMSPTY int t; char *ptsname(); p = open("/dev/ptmx", 2); if (p > 0) { grantpt(p); unlockpt(p); strcpy(line, ptsname(p)); return(p); } #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++) { + for (cp = "pqrsPQRS"; *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]; + for (i = 0; i < 32; i++) { + *p2 = "0123456789abcdefghijklmnopqrstuv"[i]; p = open(line, 2); 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, 2); 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, 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 */ (void) close(p); } } #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() { #ifndef convex #ifndef USE_TERMIO return(termbuf.state & TS_EXTPROC); #else return(termbuf.c_lflag & EXTPROC); #endif #else return(linestate); #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() { #ifndef USE_TERMIO return(((termbuf.tc.t_startc) > 0 && (termbuf.tc.t_stopc) > 0) ? 1 : 0); #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 #else return((termbuf.c_iflag & IXANY) ? 1 : 0); #endif } void tty_setecho(on) int on; { #ifndef USE_TERMIO if (on) termbuf.sg.sg_flags |= ECHO|CRMOD; else termbuf.sg.sg_flags &= ~(ECHO|CRMOD); #else if (on) termbuf.c_lflag |= ECHO; else termbuf.c_lflag &= ~ECHO; #endif } int tty_israw() { #ifndef USE_TERMIO return(termbuf.sg.sg_flags & RAW); #else return(!(termbuf.c_lflag & ICANON)); #endif } #if defined (AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R) int tty_setraw(on) { # 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 } #endif void tty_binaryin(on) int on; { #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 } void tty_binaryout(on) int on; { #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 } int tty_isbinaryin() { #ifndef USE_TERMIO return(termbuf.lflags & LPASS8); #else return(!(termbuf.c_iflag & ISTRIP)); #endif } int tty_isbinaryout() { #ifndef USE_TERMIO return(termbuf.lflags & LLITOUT); #else return(!(termbuf.c_oflag&OPOST)); #endif } #ifdef LINEMODE int tty_isediting() { #ifndef USE_TERMIO return(!(termbuf.sg.sg_flags & (CBREAK|RAW))); #else return(termbuf.c_lflag & ICANON); #endif } int tty_istrapsig() { #ifndef USE_TERMIO return(!(termbuf.sg.sg_flags&RAW)); #else return(termbuf.c_lflag & ISIG); #endif } void tty_setedit(on) int on; { #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 } void tty_setsig(on) int on; { #ifndef USE_TERMIO if (on) ; #else if (on) termbuf.c_lflag |= ISIG; else termbuf.c_lflag &= ~ISIG; #endif } #endif /* LINEMODE */ int tty_issofttab() { #ifndef USE_TERMIO return (termbuf.sg.sg_flags & XTABS); #else # ifdef OXTABS return (termbuf.c_oflag & OXTABS); # endif # ifdef TABDLY return ((termbuf.c_oflag & TABDLY) == TAB3); # endif #endif } void tty_setsofttab(on) int on; { #ifndef USE_TERMIO if (on) termbuf.sg.sg_flags |= XTABS; else termbuf.sg.sg_flags &= ~XTABS; #else if (on) { # ifdef OXTABS termbuf.c_oflag |= OXTABS; # endif # ifdef TABDLY termbuf.c_oflag &= ~TABDLY; termbuf.c_oflag |= TAB3; # endif } else { # ifdef OXTABS termbuf.c_oflag &= ~OXTABS; # endif # ifdef TABDLY termbuf.c_oflag &= ~TABDLY; termbuf.c_oflag |= TAB0; # endif } #endif } int tty_islitecho() { #ifndef USE_TERMIO return (!(termbuf.lflags & LCTLECH)); #else # ifdef ECHOCTL return (!(termbuf.c_lflag & ECHOCTL)); # endif # ifdef TCTLECH return (!(termbuf.c_lflag & TCTLECH)); # endif # if !defined(ECHOCTL) && !defined(TCTLECH) return (0); /* assumes ctl chars are echoed '^x' */ # endif #endif } void tty_setlitecho(on) 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; # endif # ifdef TCTLECH if (on) termbuf.c_lflag &= ~TCTLECH; else termbuf.c_lflag |= TCTLECH; # endif #endif } int tty_iscrnl() { #ifndef USE_TERMIO return (termbuf.sg.sg_flags & CRMOD); #else return (termbuf.c_iflag & ICRNL); #endif } /* * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD). */ #if B4800 != 4800 #define DECODE_BAUD #endif #ifdef DECODE_BAUD /* * A table of available terminal speeds */ struct termspeeds { 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 }, #ifdef B7200 { 7200, B7200 }, #endif { 9600, B9600 }, #ifdef B14400 { 14400, B14400 }, #endif #ifdef B19200 { 19200, B19200 }, #endif #ifdef B28800 { 28800, B28800 }, #endif #ifdef B38400 { 38400, B38400 }, #endif #ifdef B57600 { 57600, B57600 }, #endif #ifdef B115200 { 115200, B115200 }, #endif #ifdef B230400 { 230400, B230400 }, #endif { -1, 0 } }; #endif /* DECODE_BUAD */ void tty_tspeed(val) int val; { #ifdef DECODE_BAUD register 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); #else /* DECODE_BUAD */ cfsetospeed(&termbuf, val); #endif /* DECODE_BUAD */ } void tty_rspeed(val) int val; { #ifdef DECODE_BAUD register 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); #else /* DECODE_BAUD */ 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; { gotalarm++; } # 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 */ #endif /* * getptyslave() * * Open the slave side of the pty, and do any initialization * that is necessary. The return value is a file descriptor * for the slave side. */ - int + void getptyslave() { register int t = -1; + char erase; #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 + * erase character * so that we can re-set them if we need to. */ # ifdef LINEMODE waslm = tty_linemode(); # endif - + erase = termbuf.c_cc[VERASE]; /* * Make sure that we don't have a controlling tty, and * that we are the session (process group) leader. */ # ifdef TIOCNOTTY t = open(_PATH_TTY, O_RDWR); if (t >= 0) { (void) ioctl(t, TIOCNOTTY, (char *)0); (void) close(t); } # endif # ifdef PARENT_DOES_UTMP /* * 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); #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 /* * set up the tty modes as we like them to be. */ init_termbuf(); # ifdef TIOCGWINSZ if (def_row || def_col) { memset((char *)&ws, 0, sizeof(ws)); ws.ws_col = def_col; ws.ws_row = def_row; (void)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; # 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) # 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); + if (erase) + termbuf.c_cc[VERASE] = erase; # 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 } #if !defined(CRAY) || !defined(NEWINIT) #ifndef O_NOCTTY #define O_NOCTTY 0 #endif /* * Open the specified slave side of the pty, * making sure that we have a clean tty. */ int cleanopen(line) char *line; { register int t; #ifdef UNICOS7x struct secstat secbuf; #endif /* UNICOS7x */ #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); #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); } #endif /* UNICOS7x */ t = open(line, O_RDWR|O_NOCTTY); #ifdef UNICOS7x if (secflag) { if (setulvl(sysv.sy_minlvl) < 0) return(-1); if (setucmp(0) < 0) return(-1); } #endif /* UNICOS7x */ 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); # 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; } # endif /* defined(CRAY) && defined(TCVHUP) */ return(t); } #endif /* !defined(CRAY) || !defined(NEWINIT) */ #if BSD <= 43 int login_tty(t) 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)"); # 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)); # 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); } #endif /* BSD <= 43 */ #ifdef NEWINIT char *gen_id = "fe"; #endif /* * startslave(host) * * Given a hostname, do whatever * is necessary to startup the login process on the slave side of the pty. */ /* ARGSUSED */ void startslave(host, autologin, autoname) char *host; int autologin; char *autoname; { register int i; long time(); - char name[256]; #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 #ifndef NEWINIT # ifdef PARENT_DOES_UTMP utmp_sig_init(); # endif /* PARENT_DOES_UTMP */ 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. */ if ((i = open(INIT_FIFO, O_WRONLY)) < 0) { char tbuf[128]; (void) sprintf(tbuf, "Can't open %s\n", INIT_FIFO); fatalperror(net, tbuf); } memset((char *)&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 /* * Are we working as the bftp daemon? */ if (bftpd) { SCPYN(request.exec_name, BFTPPATH); } #endif /* BFTPDAEMON */ if (write(i, (char *)&request, sizeof(request)) < 0) { char tbuf[128]; (void) sprintf(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; sprintf(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 */ } char *envinit[3]; extern char **environ; void init_env() { extern char *getenv(); char **envp; envp = envinit; - if (*envp = getenv("TZ")) + if ((*envp = getenv("TZ"))) *envp++ -= 3; #if defined(CRAY) || defined(__hpux) else *envp++ = "TZ=GMT0"; #endif *envp = 0; environ = envinit; } #ifndef NEWINIT /* * start_login(host) * * Assuming that we are now running as a child processes, this * function will turn us into the login process. */ void start_login(host, autologin, name) char *host; int autologin; char *name; { - register char *cp; register char **argv; - char **addarg(); + char **addarg(), *user; extern char *getenv(); #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 */ memset(&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"); #if !defined(NO_LOGIN_H) # 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 } #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); # ifdef KLUDGELINEMODE else if (lmodetype == KLUDGE_LINEMODE || lmodetype == KLUDGE_OK) setenv("LINEMODE", "kludge", 1); # 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 (SecurID) /* * don't worry about the -f that might get sent. * A -s is supposed to override it anyhow. */ if (require_SecurID) argv = addarg(argv, "-s"); #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); sprintf(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; 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); #endif 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(_PATH_LOGIN, argv); - syslog(LOG_ERR, "%s: %m\n", _PATH_LOGIN); - fatalperror(net, _PATH_LOGIN); + if (altlogin == NULL) { + altlogin = _PATH_LOGIN; + } + execv(altlogin, argv); + + syslog(LOG_ERR, "%s: %m\n", altlogin); + fatalperror(net, altlogin); /*NOTREACHED*/ } char ** addarg(argv, val) register char **argv; register 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[(int)argv[-1]]) { --argv; *argv = (char *)((int)(*argv) + 10); argv = (char **)realloc(argv, sizeof(*argv)*((int)(*argv) + 2)); if (argv == NULL) return(NULL); argv++; cpp = &argv[(int)argv[-1] - 10]; } *cpp++ = val; *cpp = 0; return(argv); } #endif /* NEWINIT */ /* * scrub_env() * * Remove a few things from the environment that * don't need to be there. */ + void scrub_env() { register char **cpp, **cpp2; for (cpp2 = cpp = environ; *cpp; cpp++) { +#ifdef __FreeBSD__ + if (strncmp(*cpp, "LD_LIBRARY_PATH=", 16) && + strncmp(*cpp, "LD_PRELOAD=", 11) && +#else if (strncmp(*cpp, "LD_", 3) && strncmp(*cpp, "_RLD_", 5) && strncmp(*cpp, "LIBPATH=", 8) && +#endif strncmp(*cpp, "IFS=", 4)) *cpp2++ = *cpp; } *cpp2 = 0; } /* * cleanup() * * 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; /* * 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 (WIFSTOPPED(child_status)) { return; } } t = sigblock(sigmask(SIGCHLD)); if (incleanup) { sigsetmask(t); return; } incleanup = 1; 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 */ } #if defined(PARENT_DOES_UTMP) && !defined(NEWINIT) /* * _utmp_sig_rcv * utmp_sig_init * utmp_sig_wait * These three functions are used to coordinate the handling of * the utmp file between the server and the soon-to-be-login shell. * The server actually creates the utmp structure, the child calls * utmp_sig_wait(), until the server calls utmp_sig_notify() and * signals the future-login shell to proceed. */ static int caught=0; /* NZ when signal intercepted */ static void (*func)(); /* address of previous handler */ void _utmp_sig_rcv(sig) int sig; { caught = 1; (void) signal(SIGUSR1, func); } void utmp_sig_init() { /* * register signal handler for UTMP creation */ if ((int)(func = signal(SIGUSR1, _utmp_sig_rcv)) == -1) fatalperror(net, "telnetd/signal"); } void utmp_sig_reset() { (void) signal(SIGUSR1, func); /* reset handler to default */ } # ifdef __hpux # define sigoff() /* do nothing */ # define sigon() /* do nothing */ # endif void utmp_sig_wait() { /* * 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 */ } void utmp_sig_notify(pid) { kill(pid, SIGUSR1); } # ifdef CRAY static int gotsigjob = 0; /*ARGSUSED*/ void sigjob(sig) int sig; { register int jid; register struct jobtemp *jp; while ((jid = waitjob(NULL)) != -1) { if (jid == 0) { return; } gotsigjob++; jobend(jid, NULL, NULL); } } /* * jid_getutid: * called by jobend() before calling cleantmp() * to find the correct $TMPDIR to cleanup. */ struct utmp * jid_getutid(jid) int jid; { struct utmp *cur = NULL; setutent(); /* just to make sure */ while (cur = getutent()) { if ( (cur->ut_type != NULL) && (jid == cur->ut_jid) ) { return(cur); } } return(0); } /* * Clean up the TMPDIR that login created. * The first time this is called we pick up the info * from the utmp. If the job has already gone away, * then we'll clean up and be done. If not, then * when this is called the second time it will wait * for the signal that the job is done. */ int cleantmp(wtp) register struct utmp *wtp; { struct utmp *utp; static int first = 1; register int mask, omask, ret; extern struct utmp *getutid P((const struct utmp *_Id)); mask = sigmask(WJSIGNAL); 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); /* * 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 jobend(jid, path, user) register int jid; register char *path; register 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) { 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(); utp = jid_getutid(pty_saved_jid); if (utp == 0) { syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR"); return(-1); } 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; { 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: /* * 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; /* * This updates the utmpx and utmp entries and make a wtmp/x entry */ 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, ((long)u)-((long)utmp), L_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((long *) 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); } #endif diff --git a/crypto/telnet/telnetd/telnetd.8 b/crypto/telnet/telnetd/telnetd.8 index f618385ed09b..e77443e6e010 100644 --- a/crypto/telnet/telnetd/telnetd.8 +++ b/crypto/telnet/telnetd/telnetd.8 @@ -1,607 +1,613 @@ .\" Copyright (c) 1983, 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. .\" .\" @(#)telnetd.8 8.4 (Berkeley) 6/1/94 .\" .Dd June 1, 1994 .Dt TELNETD 8 .Os BSD 4.2 .Sh NAME .Nm telnetd .Nd DARPA .Tn TELNET protocol server .Sh SYNOPSIS .Nm /usr/libexec/telnetd .Op Fl BUhlkns .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 edebug +.Op Fl P Ar loginprog .Op Fl r Ns Ar lowpty-highpty .Op Fl u Ar len .Op Fl debug Op Ar port .Sh DESCRIPTION The .Nm telnetd command is a server which supports the .Tn DARPA standard .Tn TELNET virtual terminal protocol. .Nm Telnetd is normally invoked by the internet server (see .Xr inetd 8 ) for requests to connect to the .Tn TELNET port as indicated by the .Pa /etc/services file (see .Xr services 5 ) . The .Fl debug option may be used to start up .Nm telnetd manually, instead of through .Xr inetd 8 . If started up this way, .Ar port may be specified to run .Nm telnetd on an alternate .Tn TCP port number. .Pp The .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 telnetd has been compiled with support for the .Dv AUTHENTICATION option. There are several valid values for .Ar authmode: .Bl -tag -width debug .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. .It valid 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. .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 .Fl a .Cm valid . .It none This is the default state. Authentication information is not required. If no or insufficient authentication information is provided, then the .Xr login 1 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 Specifies bftp server mode. In this mode, .Nm telnetd causes login to start a .Xr bftp 1 session rather than the user's normal shell. In bftp daemon mode normal logins are not supported, and it must be used on a port other than the normal .Tn TELNET port. .It Fl D Ar debugmode This option may be used for debugging purposes. This allows .Nm telnetd to print out debugging information to the connection, allowing the user to see what .Nm telnetd is doing. There are several possible values for .Ar debugmode: .Bl -tag -width exercise .It Cm options Prints information about the negotiation of .Tn TELNET options. .It Cm report Prints the .Cm options information, plus some additional information about what processing is going on. .It Cm netdata Displays the data stream received by .Nm telnetd. .It Cm ptydata 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 telnetd (see .Dv SO_DEBUG in .Xr socket 2 ) . .It Fl edebug If .Nm telnetd has been compiled with support for data encryption, then the .Fl edebug option may be used to enable encryption debugging code. +.It Fl P Ar loginprog +Specifies an alternate +.Xr login 1 +command to run to complete the login. The alternate command must +understand the same command arguments as the standard login. .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 .Dv ID from .Pa /etc/inittab to use when init starts login sessions. The default .Dv ID is .Dv fe. .It Fl k This option is only useful if .Nm telnetd 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 .Dv LINEMODE option, then .Nm telnetd 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 by the client sending .Dv DONT SUPPRESS-GO-AHEAD and .Dv 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 .Dv WILL TIMING-MARK in response to a .Dv 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 .Dv LINEMODE option is not supported, it will go into kludge linemode. .It Fl n Disable .Dv TCP keep-alives. Normally .Nm telnetd enables the .Tn TCP keep-alive mechanism to probe connections that have been idle for some period of time to determine if the client is still there, so that idle connections 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 telnetd is compiled for .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 .Ar lowpty or .Ar highpty 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 telnetd can differentiate .Ar highpty from .Ar lowpty . .It Fl s This option is only enabled if .Nm telnetd is compiled with support for .Tn SecurID cards. It causes the .Fl s option to be passed on to .Xr login 1 , and thus is only useful if .Xr login 1 supports the .Fl s flag to indicate that only .Tn SecurID validated logins are allowed, and is usually useful for controlling remote logins from outside of a firewall. .It Fl S Ar tos .It Fl u Ar len 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 , the dotted decimal value will be used instead. This allows hosts with very long host names that overflow this field to still be uniquely identified. Specifying .Fl u0 indicates that only dotted decimal addresses should be put into the .Pa utmp file. .ne 1i .It Fl U This option causes .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 telnetd has been built with support for the authentication option. It disables the use of .Ar authtype authentication, and can be used to temporarily disable a specific authentication type without having to recompile .Nm telnetd . .El .Pp .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 .Dv stdin , .Dv stdout and .Dv stderr . .Nm Telnetd manipulates the master side of the pseudo-terminal, implementing the .Tn TELNET protocol and passing characters between the remote client and the login process. .Pp When a .Tn TELNET session is started up, .Nm telnetd sends .Tn TELNET options to the client side indicating a willingness to do the following .Tn TELNET options, which are described in more detail below: .Bd -literal -offset indent DO AUTHENTICATION WILL ENCRYPT DO TERMINAL TYPE DO TSPEED DO XDISPLOC DO NEW-ENVIRON DO ENVIRON WILL SUPPRESS GO AHEAD DO ECHO DO LINEMODE DO NAWS WILL STATUS DO LFLOW DO TIMING-MARK .Ed .Pp The pseudo-terminal allocated to the client is configured to operate in \*(lqcooked\*(rq mode, and with .Dv XTABS and .Dv CRMOD enabled (see .Xr tty 4 ) . .Pp .Nm Telnetd has support for enabling locally the following .Tn TELNET options: .Bl -tag -width "DO AUTHENTICATION" .It "WILL ECHO" When the .Dv LINEMODE option is enabled, a .Dv WILL ECHO or .Dv WONT ECHO will be sent to the client to indicate the current state of terminal echoing. When terminal echo is not desired, a .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 .Dv WONT ECHO is sent to indicate that .Tn telnetd will not be doing any terminal echoing, so the client should do any terminal echoing that is needed. .It "WILL BINARY" Indicates that the client is willing to send a 8 bits of data, rather than the normal 7 bits of the Network Virtual Terminal. .It "WILL SGA" Indicates that it will not be sending .Dv IAC GA, go ahead, commands. .It "WILL STATUS" Indicates a willingness to send the client, upon request, of the current status of all .Tn TELNET options. .It "WILL TIMING-MARK" Whenever a .Dv DO TIMING-MARK command is received, it is always responded to with a .Dv WILL TIMING-MARK .ne 1i .It "WILL LOGOUT" When a .Dv DO LOGOUT is received, a .Dv WILL LOGOUT is sent in response, and the .Tn TELNET session is shut down. .It "WILL ENCRYPT" Only sent if .Nm telnetd is compiled with support for data encryption, and indicates a willingness to decrypt the data stream. .El .Pp .Nm Telnetd has support for enabling remotely the following .Tn TELNET options: .Bl -tag -width "DO AUTHENTICATION" .It "DO BINARY" Sent to indicate that .Tn telnetd is willing to receive an 8 bit data stream. .It "DO LFLOW" Requests that the client handle flow control characters remotely. .It "DO ECHO" This is not really supported, but is sent to identify a 4.2BSD .Xr telnet 1 client, which will improperly respond with .Dv WILL ECHO. If a .Dv WILL ECHO is received, a .Dv DONT ECHO will be sent in response. .It "DO TERMINAL-TYPE" Indicates a desire to be able to request the 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 .Dv IAC GA, the go ahead command. .It "DO NAWS" Requests that the client inform the server when the window (display) size changes. .It "DO TERMINAL-SPEED" Indicates a desire to be able to request information about the speed of the serial line to which the client is attached. .It "DO XDISPLOC" Indicates a desire to be able to request the name of the X windows display that is associated with the telnet client. .It "DO NEW-ENVIRON" Indicates a desire to be able to request environment variable information, as described in RFC 1572. .It "DO ENVIRON" Indicates a desire to be able to request environment variable information, as described in RFC 1408. .It "DO LINEMODE" Only sent if .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 telnetd is compiled with support for both linemode and kludge linemode, and the client responded with .Dv WONT LINEMODE. If the client responds with .Dv WILL TM, the it is assumed that the client supports kludge linemode. Note that the .Op Fl k option can be used to disable this. .It "DO AUTHENTICATION" Only sent if .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 telnetd is compiled with support for data encryption, and indicates a willingness to decrypt the data stream. .Sh ENVIRONMENT .Sh FILES .Pa /etc/services .br .Pa /etc/inittab (UNICOS systems only) .br .Pa /etc/iptos (if supported) .br .Pa /usr/ucb/bftp (if supported) .Sh "SEE ALSO" -.Xr telnet 1 , +.Xr bftp 1 , .Xr login 1 , -.Xr bftp 1 +.Xr telnet 1 (if supported) .Sh STANDARDS .Bl -tag -compact -width RFC-1572 .It Cm RFC-854 .Tn TELNET PROTOCOL SPECIFICATION .It Cm RFC-855 TELNET OPTION SPECIFICATIONS .It Cm RFC-856 TELNET BINARY TRANSMISSION .It Cm RFC-857 TELNET ECHO OPTION .It Cm RFC-858 TELNET SUPPRESS GO AHEAD OPTION .It Cm RFC-859 TELNET STATUS OPTION .It Cm RFC-860 TELNET TIMING MARK OPTION .It Cm RFC-861 TELNET EXTENDED OPTIONS - LIST OPTION .It Cm RFC-885 TELNET END OF RECORD OPTION .It Cm RFC-1073 Telnet Window Size Option .It Cm RFC-1079 Telnet Terminal Speed Option .It Cm RFC-1091 Telnet Terminal-Type Option .It Cm RFC-1096 Telnet X Display Location Option .It Cm RFC-1123 Requirements for Internet Hosts -- Application and Support .It Cm RFC-1184 Telnet Linemode Option .It Cm RFC-1372 Telnet Remote Flow Control Option .It Cm RFC-1416 Telnet Authentication Option .It Cm RFC-1411 Telnet Authentication: Kerberos Version 4 .It Cm RFC-1412 Telnet Authentication: SPX .It Cm RFC-1571 Telnet Environment Option Interoperability Issues .It Cm RFC-1572 Telnet Environment Option .Sh BUGS Some .Tn TELNET commands are only partially implemented. .Pp Because of bugs in the original 4.2 BSD .Xr telnet 1 , .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 . .Pp Binary mode has no common interpretation except between similar operating systems (Unix in this case). .Pp The terminal type name received from the remote client is converted to lower case. .Pp .Nm Telnetd never sends .Tn TELNET .Dv IAC GA (go ahead) commands. diff --git a/crypto/telnet/telnetd/telnetd.c b/crypto/telnet/telnetd/telnetd.c index 70c0fc03589c..6e09ab46ca7f 100644 --- a/crypto/telnet/telnetd/telnetd.c +++ b/crypto/telnet/telnetd/telnetd.c @@ -1,1608 +1,1611 @@ /* * 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. */ #ifndef lint -static char copyright[] = +static const char copyright[] = "@(#) Copyright (c) 1989, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)telnetd.c 8.4 (Berkeley) 5/30/95"; +static const char sccsid[] = "@(#)telnetd.c 8.4 (Berkeley) 5/30/95"; #endif /* not lint */ #include "telnetd.h" #include "pathnames.h" #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 #if defined(_SC_CRAY_SECURE_SYS) #include #include # ifdef SO_SEC_MULTI /* 8.0 code */ #include #include # 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 int auth_level = 0; #endif +#if defined(ENCRYPTION) +#include +#endif +#include #if defined(SecurID) int require_SecurID = 0; #endif extern int utmp_len; int registerd_host_only = 0; #ifdef STREAMSPTY # include # include /* make sure we don't get the bsd version */ # include "/usr/include/sys/tty.h" # include /* * Because of the way ptyibuf is used with streams messages, we need * ptyibuf+1 to be on a full-word boundary. The following wierdness * is simply to make that happen. */ long ptyibufbuf[BUFSIZ/sizeof(long)+1]; char *ptyibuf = ((char *)&ptyibufbuf[1])-1; char *ptyip = ((char *)&ptyibufbuf[1])-1; char ptyibuf2[BUFSIZ]; unsigned char ctlbuf[BUFSIZ]; struct strbuf strbufc, strbufd; -int readstream(); - #else /* ! STREAMPTY */ /* * I/O data buffers, * pointers, and counters. */ char ptyibuf[BUFSIZ], *ptyip = ptyibuf; char ptyibuf2[BUFSIZ]; +# include + +int readstream(int p, char *ibuf, int bufsize); +void doit(struct sockaddr_in *who); +int terminaltypeok(char *s); +void startslave(char *host, int autologin, char *autoname); + #endif /* ! STREAMPTY */ int hostinfo = 1; /* do we print login banner? */ #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 *progname; +char *altlogin; extern void usage P((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', ':', 'h', 'k', 'n', 'S', ':', 'u', ':', 'U', + 'd', ':', 'h', 'k', 'n', 'p', ':', 'S', ':', 'u', ':', 'U', #ifdef AUTHENTICATION 'a', ':', 'X', ':', #endif #ifdef BFTPDAEMON 'B', #endif #ifdef DIAGNOSTICS 'D', ':', #endif #ifdef ENCRYPTION 'e', ':', #endif #if defined(CRAY) && defined(NEWINIT) 'I', ':', #endif #ifdef LINEMODE 'l', #endif #ifdef CRAY 'r', ':', #endif #ifdef SecurID 's', #endif '\0' }; main(argc, argv) char *argv[]; { struct sockaddr_in from; int on = 1, fromlen; register int ch; extern char *optarg; extern int optind; #if defined(IPPROTO_IP) && defined(IP_TOS) int tos = -1; #endif pfrontp = pbackp = ptyobuf; netip = netibuf; nfrontp = nbackp = netobuf; #ifdef ENCRYPTION nclearto = 0; #endif /* ENCRYPTION */ progname = *argv; #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)) != EOF) { switch(ch) { #ifdef AUTHENTICATION case 'a': /* * Check for required authentication level */ if (strcmp(optarg, "debug") == 0) { extern int auth_debug_mode; 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; #endif /* AUTHENTICATION */ #ifdef BFTPDAEMON case 'B': bftpd++; break; #endif /* BFTPDAEMON */ 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; #endif /* DIAGNOSTICS */ #ifdef ENCRYPTION case 'e': if (strcmp(optarg, "debug") == 0) { extern int encrypt_debug_mode; encrypt_debug_mode = 1; break; } usage(); /* NOTREACHED */ break; #endif /* ENCRYPTION */ 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) */ #ifdef LINEMODE case 'l': alwayslinemode = 1; break; #endif /* LINEMODE */ 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; + case 'p': + altlogin = optarg; + break; + #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; } #endif /* CRAY */ #ifdef SecurID case 's': /* SecurID required */ require_SecurID = 1; break; #endif /* SecurID */ 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"); #else fprintf(stderr, "%s%s\n", "TOS option unavailable; ", "-S flag not supported\n"); #endif break; case 'u': utmp_len = atoi(optarg); break; case 'U': registerd_host_only = 1; break; #ifdef AUTHENTICATION case 'X': /* * Check for invalid authentication types */ auth_disable_name(optarg); break; #endif /* AUTHENTICATION */ default: fprintf(stderr, "telnetd: %c: unknown option\n", ch); /* FALLTHROUGH */ case '?': usage(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (debug) { int s, ns, foo; struct servent *sp; static struct sockaddr_in sin = { AF_INET }; if (argc > 1) { usage(); /* NOT REACHED */ } else if (argc == 1) { - if (sp = getservbyname(*argv, "tcp")) { + if ((sp = getservbyname(*argv, "tcp"))) { sin.sin_port = sp->s_port; } else { sin.sin_port = atoi(*argv); if ((int)sin.sin_port <= 0) { fprintf(stderr, "telnetd: %s: bad port #\n", *argv); usage(); /* NOT REACHED */ } sin.sin_port = htons((u_short)sin.sin_port); } } else { sp = getservbyname("telnet", "tcp"); if (sp == 0) { fprintf(stderr, "telnetd: tcp/telnet: unknown service\n"); exit(1); } sin.sin_port = sp->s_port; } s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) { perror("telnetd: socket");; exit(1); } (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)); if (bind(s, (struct sockaddr *)&sin, sizeof sin) < 0) { perror("bind"); exit(1); } if (listen(s, 1) < 0) { perror("listen"); exit(1); } foo = sizeof sin; ns = accept(s, (struct sockaddr *)&sin, &foo); if (ns < 0) { perror("accept"); exit(1); } (void) dup2(ns, 0); (void) close(ns); (void) close(s); #ifdef convex } else if (argc == 1) { ; /* VOID*/ /* Just ignore the host/port name */ #endif } else if (argc > 0) { usage(); /* NOT REACHED */ } #if defined(_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 */ memset((char *)&dv, 0, sizeof(dv)); if (getsysv(&sysv, sizeof(struct sysv)) != 0) { perror("getsysv"); exit(1); } /* * 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; } #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 */ } #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"); } #if defined(IPPROTO_IP) && defined(IP_TOS) { # if defined(HAS_GETTOS) 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"); } #endif /* defined(IPPROTO_IP) && defined(IP_TOS) */ net = 0; doit(&from); /* NOTREACHED */ } /* end of main */ void usage() { fprintf(stderr, "Usage: telnetd"); #ifdef AUTHENTICATION fprintf(stderr, " [-a (debug|other|user|valid|off|none)]\n\t"); #endif #ifdef BFTPDAEMON fprintf(stderr, " [-B]"); #endif fprintf(stderr, " [-debug]"); #ifdef DIAGNOSTICS fprintf(stderr, " [-D (options|report|exercise|netdata|ptydata)]\n\t"); #endif #ifdef AUTHENTICATION fprintf(stderr, " [-edebug]"); #endif fprintf(stderr, " [-h]"); #if defined(CRAY) && defined(NEWINIT) fprintf(stderr, " [-Iinitid]"); #endif #if defined(LINEMODE) && defined(KLUDGELINEMODE) fprintf(stderr, " [-k]"); #endif #ifdef LINEMODE fprintf(stderr, " [-l]"); #endif fprintf(stderr, " [-n]"); #ifdef CRAY fprintf(stderr, " [-r[lowpty]-[highpty]]"); #endif fprintf(stderr, "\n\t"); #ifdef SecurID fprintf(stderr, " [-s]"); #endif #ifdef HAS_GETTOS fprintf(stderr, " [-S tos]"); #endif #ifdef AUTHENTICATION fprintf(stderr, " [-X auth-type]"); #endif fprintf(stderr, " [-u utmp_hostname_length] [-U]"); fprintf(stderr, " [port]\n"); exit(1); } /* * getterminaltype * * Ask the other end to send along its terminal type and speed. * Output is the variable terminaltype filled in. */ static unsigned char ttytype_sbbuf[] = { IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE }; int getterminaltype(name) char *name; { int retval = -1; void _gettermname(); settimer(baseline); #if defined(AUTHENTICATION) /* * Handle the Authentication option before we do anything else. */ send_do(TELOPT_AUTHENTICATION, 1); while (his_will_wont_is_changing(TELOPT_AUTHENTICATION)) ttloop(); if (his_state_is_will(TELOPT_AUTHENTICATION)) { retval = auth_wait(name); } #endif #ifdef ENCRYPTION send_will(TELOPT_ENCRYPT, 1); #endif /* ENCRYPTION */ send_do(TELOPT_TTYPE, 1); send_do(TELOPT_TSPEED, 1); send_do(TELOPT_XDISPLOC, 1); send_do(TELOPT_NEW_ENVIRON, 1); send_do(TELOPT_OLD_ENVIRON, 1); while ( #ifdef ENCRYPTION his_do_dont_is_changing(TELOPT_ENCRYPT) || #endif /* ENCRYPTION */ his_will_wont_is_changing(TELOPT_TTYPE) || his_will_wont_is_changing(TELOPT_TSPEED) || his_will_wont_is_changing(TELOPT_XDISPLOC) || his_will_wont_is_changing(TELOPT_NEW_ENVIRON) || his_will_wont_is_changing(TELOPT_OLD_ENVIRON)) { ttloop(); } #ifdef ENCRYPTION /* * Wait for the negotiation of what type of encryption we can * send with. If autoencrypt is not set, this will just return. */ if (his_state_is_will(TELOPT_ENCRYPT)) { encrypt_wait(); } #endif /* ENCRYPTION */ if (his_state_is_will(TELOPT_TSPEED)) { static unsigned char sb[] = { IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE }; memmove(nfrontp, sb, sizeof sb); nfrontp += 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 }; memmove(nfrontp, sb, sizeof sb); nfrontp += 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 }; memmove(nfrontp, sb, sizeof sb); nfrontp += 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 }; memmove(nfrontp, sb, sizeof sb); nfrontp += sizeof sb; DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2);); } if (his_state_is_will(TELOPT_TTYPE)) { memmove(nfrontp, ttytype_sbbuf, sizeof ttytype_sbbuf); nfrontp += sizeof ttytype_sbbuf; DIAG(TD_OPTIONS, printsub('>', ttytype_sbbuf + 2, sizeof ttytype_sbbuf - 2);); } if (his_state_is_will(TELOPT_TSPEED)) { while (sequenceIs(tspeedsubopt, baseline)) ttloop(); } if (his_state_is_will(TELOPT_XDISPLOC)) { while (sequenceIs(xdisplocsubopt, baseline)) ttloop(); } if (his_state_is_will(TELOPT_NEW_ENVIRON)) { while (sequenceIs(environsubopt, baseline)) ttloop(); } if (his_state_is_will(TELOPT_OLD_ENVIRON)) { while (sequenceIs(oenvironsubopt, baseline)) ttloop(); } if (his_state_is_will(TELOPT_TTYPE)) { char first[256], last[256]; while (sequenceIs(ttypesubopt, baseline)) ttloop(); /* * If the other side has already disabled the option, then * we have to just go with what we (might) have already gotten. */ if (his_state_is_will(TELOPT_TTYPE) && !terminaltypeok(terminaltype)) { - (void) strncpy(first, terminaltype, sizeof(first)); + (void) strncpy(first, terminaltype, sizeof(first)-1); + first[sizeof(first)-1] = '\0'; for(;;) { /* * Save the unknown name, and request the next name. */ - (void) strncpy(last, terminaltype, sizeof(last)); + (void) strncpy(last, terminaltype, sizeof(last)-1); + last[sizeof(last)-1] = '\0'; _gettermname(); if (terminaltypeok(terminaltype)) break; if ((strncmp(last, terminaltype, sizeof(last)) == 0) || his_state_is_wont(TELOPT_TTYPE)) { /* * We've hit the end. If this is the same as * the first name, just go with it. */ if (strncmp(first, terminaltype, sizeof(first)) == 0) break; /* * Get the terminal name one more time, so that * RFC1091 compliant telnets will cycle back to * the start of the list. */ _gettermname(); - if (strncmp(first, terminaltype, sizeof(first)) != 0) - (void) strncpy(terminaltype, first, sizeof(first)); + if (strncmp(first, terminaltype, sizeof(first)) != 0) { + (void) strncpy(terminaltype, first, sizeof(terminaltype)-1); + terminaltype[sizeof(terminaltype)-1] = '\0'; + } break; } } } } return(retval); } /* end of getterminaltype */ void _gettermname() { /* * If the client turned off the option, * we can't send another request, so we * just return. */ if (his_state_is_wont(TELOPT_TTYPE)) return; settimer(baseline); memmove(nfrontp, ttytype_sbbuf, sizeof ttytype_sbbuf); nfrontp += sizeof ttytype_sbbuf; DIAG(TD_OPTIONS, printsub('>', ttytype_sbbuf + 2, sizeof ttytype_sbbuf - 2);); while (sequenceIs(ttypesubopt, baseline)) ttloop(); } int terminaltypeok(s) char *s; { char buf[1024]; if (terminaltype == NULL) return(1); /* * tgetent() will return 1 if the type is known, and * 0 if it is not known. If it returns -1, it couldn't * open the database. But if we can't open the database, * it won't help to say we failed, because we won't be * able to verify anything else. So, we treat -1 like 1. */ if (tgetent(buf, s) == 0) return(0); 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 +int level; +char user_name[256]; /* * Get a pty, scan input lines. */ +void doit(who) struct sockaddr_in *who; { char *host, *inet_ntoa(); - int t; struct hostent *hp; - int level; int ptynum; - char user_name[256]; /* * Find an available pty to use. */ #ifndef convex pty = getpty(&ptynum); if (pty < 0) fatal(net, "All network ports in use"); #else for (;;) { char *lp; extern char *line, *getpty(); if ((lp = getpty()) == NULL) fatal(net, "Out of ptys"); if ((pty = open(lp, 2)) >= 0) { strcpy(line,lp); line[5] = 't'; break; } } #endif #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"); } #endif /* _SC_CRAY_SECURE_SYS */ /* get name of connected client */ hp = gethostbyaddr((char *)&who->sin_addr, sizeof (struct in_addr), who->sin_family); 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) <= (unsigned int)((utmp_len < 0) ? -utmp_len : utmp_len))) { host = hp->h_name; } else { host = inet_ntoa(who->sin_addr); } /* * We must make a copy because Kerberos is probably going * to also do a gethost* and overwrite the static data... */ strncpy(remote_host_name, host, sizeof(remote_host_name)-1); remote_host_name[sizeof(remote_host_name)-1] = 0; host = remote_host_name; (void) gethostname(host_name, sizeof (host_name)); hostname = host_name; #if defined(AUTHENTICATION) || defined(ENCRYPTION) auth_encrypt_init(hostname, host, "TELNETD", 1); #endif init_env(); /* * get terminal type. */ *user_name = 0; level = getterminaltype(user_name); setenv("TERM", terminaltype ? terminaltype : "network", 1); - /* - * 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()"); } #endif /* _SC_CRAY_SECURE_SYS */ - telnet(net, pty); /* begin server processing */ -#else - telnet(net, pty, host); -#endif + telnet(net, pty, host); /* begin server process */ + /*NOTREACHED*/ } /* end of doit */ #if defined(CRAY2) && defined(UNICOS5) && defined(UNICOS50) int Xterm_output(ibufp, obuf, icountp, ocount) char **ibufp, *obuf; int *icountp, ocount; { int ret; ret = term_output(*ibufp, obuf, *icountp, ocount); *ibufp += *icountp; *icountp = 0; return(ret); } #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 { 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(); /* * 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); #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 */ /* * 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(); /* * 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); } /* * 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); #ifndef STREAMSPTY /* * Turn on packet mode */ (void) 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(); (void) ioctl(f, FIONBIO, (char *)&on); (void) ioctl(p, FIONBIO, (char *)&on); #if defined(CRAY2) && defined(UNICOS5) init_termdriver(f, p, interrupt, sendbrk); #endif #if defined(SO_OOBINLINE) (void) setsockopt(net, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof on); #endif /* defined(SO_OOBINLINE) */ #ifdef SIGTSTP (void) 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); #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 #ifdef TIOCNOTTY { register int t; t = open(_PATH_TTY, O_RDWR); if (t >= 0) { (void) ioctl(t, TIOCNOTTY, (char *)0); (void) close(t); } } #endif #if defined(CRAY) && defined(NEWINIT) && defined(TIOCSCTTY) (void) setsid(); ioctl(p, TIOCSCTTY, 0); #endif /* * 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 !defined(CRAY) || !defined(NEWINIT) if (getenv("USER")) hostinfo = 0; #endif if (getent(defent, "default") == 1) { char *getstr(); char *cp=defstrs; HE = getstr("he", &cp); HN = getstr("hn", &cp); IM = getstr("im", &cp); if (HN && *HN) (void) strcpy(host_name, HN); 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, {sprintf(nfrontp, "td: Entering processing loop\r\n"); nfrontp += strlen(nfrontp);}); -#ifdef convex - startslave(host); -#endif + /* + * Startup the login process on the slave side of the terminal + * now. We delay this until here to insure option negotiation + * is complete. + */ + startslave(host, level, user_name); nfd = ((f > p) ? f : p) + 1; for (;;) { fd_set ibits, obits, xbits; register int c; 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; } /* * Any urgent data? */ if (FD_ISSET(net, &xbits)) { SYNCHing = 1; } /* * 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 { 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)); } /* * Something to read from the pty... */ if (FD_ISSET(p, &ibits)) { #ifndef STREAMSPTY pcc = read(p, ptyibuf, BUFSIZ); #else pcc = readstream(p, ptyibuf, BUFSIZ); #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 || #ifdef 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 */ #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)); #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) */ } } 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'; } } #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; } #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(); } cleanup(0); } /* end of telnet */ #ifndef TCSIG # ifdef TIOCSIG # define TCSIG TIOCSIG # endif #endif #ifdef STREAMSPTY int flowison = -1; /* current state of flow: -1 is unknown */ int readstream(p, ibuf, bufsize) 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); } } /* * 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); } 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 */ /* * Send interrupt to process on other side of pty. * If it is in raw mode, just write NULL; * otherwise, write intr char. */ void interrupt() { ptyflush(); /* half-hearted */ #if defined(STREAMSPTY) && defined(TIOCSIGNAL) /* Streams PTY style ioctl to post a signal */ { int sig = SIGINT; (void) ioctl(pty, TIOCSIGNAL, &sig); (void) ioctl(pty, I_FLUSH, FLUSHR); } #else #ifdef TCSIG (void) ioctl(pty, TCSIG, (char *)SIGINT); #else /* TCSIG */ init_termbuf(); *pfrontp++ = slctab[SLC_IP].sptr ? (unsigned char)*slctab[SLC_IP].sptr : '\177'; #endif /* TCSIG */ #endif } /* * Send quit to process on other side of pty. * If it is in raw mode, just write NULL; * otherwise, write quit char. */ void sendbrk() { ptyflush(); /* half-hearted */ #ifdef TCSIG (void) ioctl(pty, TCSIG, (char *)SIGQUIT); #else /* TCSIG */ init_termbuf(); *pfrontp++ = slctab[SLC_ABORT].sptr ? (unsigned char)*slctab[SLC_ABORT].sptr : '\034'; #endif /* TCSIG */ } void sendsusp() { #ifdef SIGTSTP ptyflush(); /* half-hearted */ # ifdef TCSIG (void) ioctl(pty, TCSIG, (char *)SIGTSTP); # else /* TCSIG */ *pfrontp++ = slctab[SLC_SUSP].sptr ? (unsigned char)*slctab[SLC_SUSP].sptr : '\032'; # endif /* TCSIG */ #endif /* SIGTSTP */ } /* * When we get an AYT, if ^T is enabled, use that. Otherwise, * just send back "[Yes]". */ 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; } #endif (void) strcpy(nfrontp, "\r\n[Yes]\r\n"); nfrontp += 9; } void doeof() { 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'; } diff --git a/crypto/telnet/telnetd/termstat.c b/crypto/telnet/telnetd/termstat.c index ebc843a13663..be1372a1491c 100644 --- a/crypto/telnet/telnetd/termstat.c +++ b/crypto/telnet/telnetd/termstat.c @@ -1,660 +1,673 @@ /* * 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. */ #ifndef lint -static char sccsid[] = "@(#)termstat.c 8.2 (Berkeley) 5/30/95"; +static const char sccsid[] = "@(#)termstat.c 8.2 (Berkeley) 5/30/95"; #endif /* not lint */ #include "telnetd.h" +#if defined(ENCRYPTION) +#include +#endif + /* * local variables */ 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 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); + } + + if (uselinemode) { + /* * Check for state of BINARY options. + * + * We only need to do the binary dance if we are actually going + * to use linemode. As this confuses some telnet clients + * that don't support linemode, and doesn't gain us + * anything, we don't do it unless we're doing linemode. + * -Crh (henrich@msu.edu) */ + 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); } #ifdef ENCRYPTION /* * If the terminal is not echoing, but editing is enabled, * something like password input is going to happen, so * if we the other side is not currently sending encrypted * data, ask the other side to start encrypting. */ if (his_state_is_will(TELOPT_ENCRYPT)) { static int enc_passwd = 0; if (uselinemode && !tty_isecho() && tty_isediting() && (enc_passwd == 0) && !decrypt_input) { encrypt_send_request_start(); enc_passwd = 1; } else if (enc_passwd) { encrypt_send_request_end(); enc_passwd = 0; } } #endif /* ENCRYPTION */ /* * 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 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; } } } /* * clientstat * * Process linemode related requests from the client. * Client can request a change to only one of linemode, editmode or slc's * 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 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)) { + 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: #ifdef TIOCSWINSZ { 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 */ /* * Change window size as requested by client. */ ws.ws_col = parm1; ws.ws_row = parm2; (void) ioctl(pty, TIOCSWINSZ, (char *)&ws); } #endif /* TIOCSWINSZ */ 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 seperate receive and transmit speeds, the transmit * speed will take precedence. */ tty_rspeed(parm2); tty_tspeed(parm1); set_termbuf(); break; } /* end of case TELOPT_TSPEED */ 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(); } /* 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((char *)&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/crypto/telnet/telnetd/utility.c b/crypto/telnet/telnetd/utility.c index 9553d58b9193..eac3b6905246 100644 --- a/crypto/telnet/telnetd/utility.c +++ b/crypto/telnet/telnetd/utility.c @@ -1,1192 +1,1209 @@ /* * 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. */ #ifndef lint -static char sccsid[] = "@(#)utility.c 8.4 (Berkeley) 5/30/95"; +static const char sccsid[] = "@(#)utility.c 8.4 (Berkeley) 5/30/95"; #endif /* not lint */ +#ifdef __FreeBSD__ +#include +#endif #define PRINTOPTIONS #include "telnetd.h" +#if defined(AUTHENTICATION) +#include +#endif +#if defined(ENCRYPTION) +#include +#endif + /* * utility functions performing io related tasks */ /* * 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. */ void ttloop() { void netflush(); DIAG(TD_REPORT, {sprintf(nfrontp, "td: ttloop\r\n"); nfrontp += strlen(nfrontp);}); if (nfrontp-nbackp) { netflush(); } ncc = read(net, netibuf, sizeof netibuf); if (ncc < 0) { syslog(LOG_INFO, "ttloop: read: %m\n"); exit(1); } else if (ncc == 0) { syslog(LOG_INFO, "ttloop: peer died: %m\n"); exit(1); } DIAG(TD_REPORT, {sprintf(nfrontp, "td: ttloop read %d chars\r\n", ncc); nfrontp += strlen(nfrontp);}); netip = netibuf; telrcv(); /* state machine */ if (ncc > 0) { pfrontp = pbackp = ptyobuf; telrcv(); } } /* end of ttloop */ /* * Check a descriptor to see if out of band data exists on it. */ int stilloob(s) int s; /* socket number */ { static struct timeval timeout = { 0 }; fd_set excepts; int value; do { FD_ZERO(&excepts); FD_SET(s, &excepts); + memset((char *)&timeout, 0, sizeof timeout); value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout); } while ((value == -1) && (errno == EINTR)); if (value < 0) { fatalperror(pty, "select"); } if (FD_ISSET(s, &excepts)) { return 1; } else { return 0; } } void ptyflush() { 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; } /* * nextitem() * * Return the address of the next "item" in the TELNET data * stream. This will be the address of the next character if * the current address is a user data character, or it will * be the address of the character following the TELNET command * if the current address is a TELNET IAC ("I Am a Command") * character. */ char * nextitem(current) char *current; { if ((*current&0xff) != IAC) { return current+1; } switch (*(current+1)&0xff) { case DO: case DONT: case WILL: case WONT: return current+3; case SB: /* loop forever looking for the SE */ { register char *look = current+2; for (;;) { if ((*look++&0xff) == IAC) { if ((*look++&0xff) == SE) { return look; } } } } default: return current+2; } } /* end of nextitem */ /* * netclear() * * We are about to do a TELNET SYNCH operation. Clear * the path to the network. * * Things are a bit tricky since we may have sent the first * byte or so of a previous TELNET command into the network. * So, we have to scan the network buffer from the beginning * until we are up to where we want to be. * * A side effect of what we do, just to keep things * simple, is to clear the urgent data pointer. The principal * caller should be setting the urgent data pointer AFTER calling * us in any case. */ void netclear() { register char *thisitem, *next; char *good; #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) #ifdef ENCRYPTION thisitem = nclearto > netobuf ? nclearto : netobuf; #else /* ENCRYPTION */ thisitem = netobuf; #endif /* ENCRYPTION */ while ((next = nextitem(thisitem)) <= nbackp) { thisitem = next; } /* Now, thisitem is first before/at boundary. */ #ifdef ENCRYPTION good = nclearto > netobuf ? nclearto : netobuf; #else /* ENCRYPTION */ good = netobuf; /* where the good bytes go */ #endif /* ENCRYPTION */ 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; } /* end of netclear */ /* * netflush * Send as much data as possible to the network, * handling requests for urgent data. */ void netflush() { 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 */ }); #ifdef ENCRYPTION if (encrypt_output) { char *s = nclearto ? nclearto : nbackp; if (nfrontp - s > 0) { (*encrypt_output)((unsigned char *)s, nfrontp-s); nclearto = nfrontp; } } #endif /* ENCRYPTION */ /* * if no urgent data, or if the other side appears to be an * old 4.2 client (and thus unable to survive TCP urgent data), * write the entire buffer in non-OOB mode. */ if ((neturg == 0) || (not42 == 0)) { n = write(net, nbackp, n); /* normal write */ } else { n = neturg - nbackp; /* * In 4.2 (and 4.3) systems, there is some question about * what byte in a sendOOB operation is the "OOB" data. * To make ourselves compatible, we only send ONE byte * out of band, the one WE THINK should be OOB (though * we really have more the TCP philosophy of urgent data * rather than the Unix philosophy of OOB data). */ if (n > 1) { n = send(net, nbackp, n-1, 0); /* send URGENT all by itself */ } else { n = send(net, nbackp, n, MSG_OOB); /* URGENT data */ } } } if (n < 0) { if (errno == EWOULDBLOCK || errno == EINTR) return; cleanup(0); } nbackp += n; #ifdef ENCRYPTION if (nbackp > nclearto) nclearto = 0; #endif /* ENCRYPTION */ if (nbackp >= neturg) { neturg = 0; } if (nbackp == nfrontp) { nbackp = nfrontp = netobuf; #ifdef ENCRYPTION nclearto = 0; #endif /* ENCRYPTION */ } return; } /* end of netflush */ /* * writenet * * Just a handy little function to write a bit of raw data to the net. * It will force a transmit of the buffer if necessary * * arguments * ptr - A pointer to a character string to write * len - How many bytes to write */ void writenet(ptr, len) register unsigned char *ptr; register 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(nfrontp, ptr, len); nfrontp += len; } /* end of writenet */ /* * miscellaneous functions doing a variety of little jobs follow ... */ void fatal(f, msg) int f; char *msg; { char buf[BUFSIZ]; (void) sprintf(buf, "telnetd: %s.\r\n", msg); #ifdef ENCRYPTION if (encrypt_output) { /* * Better turn off encryption first.... * Hope it flushes... */ encrypt_send_end(); netflush(); } #endif /* ENCRYPTION */ (void) write(f, buf, (int)strlen(buf)); sleep(1); /*XXX*/ exit(1); } void fatalperror(f, msg) int f; char *msg; { char buf[BUFSIZ], *strerror(); (void) sprintf(buf, "%s: %s", msg, strerror(errno)); fatal(f, buf); } char editedhost[32]; void edithost(pat, host) register char *pat; register char *host; { register char *res = editedhost; char *strncpy(); if (!pat) pat = ""; while (*pat) { switch (*pat) { case '#': if (*host) host++; break; case '@': if (*host) *res++ = *host++; break; default: *res++ = *pat; break; } if (res == &editedhost[sizeof editedhost - 1]) { *res = '\0'; return; } pat++; } if (*host) (void) strncpy(res, host, sizeof editedhost - (res - editedhost) -1); else *res = '\0'; editedhost[sizeof editedhost - 1] = '\0'; } static char *putlocation; void putstr(s) register char *s; { while (*s) putchr(*s++); } void putchr(cc) int cc; { *putlocation++ = cc; } +#ifdef __FreeBSD__ +static char fmtstr[] = { "%+" }; +#else /* * 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" }; +#endif void putf(cp, where) register char *cp; char *where; { char *slash; time_t t; char db[100]; #ifdef STREAMSPTY extern char *strchr(); #else extern char *strrchr(); #endif putlocation = where; while (*cp) { if (*cp != '%') { putchr(*cp++); continue; } switch (*++cp) { case 't': #ifdef STREAMSPTY /* names are like /dev/pts/2 -- we want pts/2 */ slash = strchr(line+1, '/'); #else slash = strrchr(line, '/'); #endif if (slash == (char *) 0) putstr(line); else putstr(&slash[1]); break; case 'h': putstr(editedhost); break; case 'd': +#ifdef __FreeBSD__ + setlocale(LC_TIME, ""); +#endif (void)time(&t); (void)strftime(db, sizeof(db), fmtstr, localtime(&t)); putstr(db); break; 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; { 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; } void printsub(direction, pointer, length) char direction; /* '<' or '>' */ unsigned char *pointer; /* where suboption data sits */ int length; /* length of suboption data */ { register int i; 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); } } length -= 2; } if (length < 1) { sprintf(nfrontp, "(Empty suboption??\?)"); nfrontp += strlen(nfrontp); return; } 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]); } 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; } switch (pointer[1]) { case TELQUAL_IS: sprintf(nfrontp, " IS %.*s", length-2, (char *)pointer+2); nfrontp += strlen(nfrontp); 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); } 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]); } nfrontp += strlen(nfrontp); for (i = 2; i < length; i++) { sprintf(nfrontp, " ?%d?", pointer[i]); nfrontp += strlen(nfrontp); } break; case TELOPT_NAWS: sprintf(nfrontp, "NAWS"); nfrontp += strlen(nfrontp); if (length < 2) { sprintf(nfrontp, " (empty suboption??\?)"); nfrontp += strlen(nfrontp); break; } if (length == 2) { sprintf(nfrontp, " ?%d?", pointer[1]); nfrontp += strlen(nfrontp); break; } 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; } 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); } break; case TELOPT_LINEMODE: sprintf(nfrontp, "LINEMODE "); nfrontp += strlen(nfrontp); if (length < 2) { sprintf(nfrontp, " (empty suboption??\?)"); nfrontp += strlen(nfrontp); break; } 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; 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 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); } } break; 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"); else sprintf(nfrontp, " %d (unknown)", pointer[1]); nfrontp += strlen(nfrontp); for (i = 2; i < length; i++) { sprintf(nfrontp, " ?%d?", pointer[i]); nfrontp += strlen(nfrontp); } 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++]; } printsub(0, &pointer[i], k - i); if (i < length) { sprintf(nfrontp, " SE"); nfrontp += strlen(nfrontp); i = j; } else i = j - 1; sprintf(nfrontp, "\r\n"); nfrontp += strlen(nfrontp); break; default: sprintf(nfrontp, " %d", pointer[i]); nfrontp += strlen(nfrontp); 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_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: sprintf(nfrontp, "\" VALUE " + noquote); nfrontp += strlen(nfrontp); noquote = 2; break; case ENV_ESC: sprintf(nfrontp, "\" ESC " + noquote); nfrontp += strlen(nfrontp); noquote = 2; break; case ENV_USERVAR: sprintf(nfrontp, "\" USERVAR " + noquote); nfrontp += strlen(nfrontp); noquote = 2; break; default: - def_case: 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; } break; } } if (!noquote) *nfrontp++ = '"'; break; } } break; #if defined(AUTHENTICATION) case TELOPT_AUTHENTICATION: sprintf(nfrontp, "AUTHENTICATION"); nfrontp += strlen(nfrontp); if (length < 2) { sprintf(nfrontp, " (empty suboption??\?)"); nfrontp += strlen(nfrontp); 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", ((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; 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; } break; case TELQUAL_NAME: i = 2; sprintf(nfrontp, " NAME \""); nfrontp += strlen(nfrontp); while (i < length) *nfrontp += pointer[i++]; *nfrontp += '"'; break; default: for (i = 2; i < length; i++) { sprintf(nfrontp, " ?%d?", pointer[i]); nfrontp += strlen(nfrontp); } break; } break; #endif #ifdef ENCRYPTION case TELOPT_ENCRYPT: sprintf(nfrontp, "ENCRYPT"); nfrontp += strlen(nfrontp); if (length < 2) { sprintf(nfrontp, " (empty suboption??\?)"); nfrontp += strlen(nfrontp); break; } switch (pointer[1]) { case ENCRYPT_START: sprintf(nfrontp, " START"); nfrontp += strlen(nfrontp); break; case ENCRYPT_END: sprintf(nfrontp, " END"); nfrontp += strlen(nfrontp); break; case ENCRYPT_REQSTART: sprintf(nfrontp, " REQUEST-START"); nfrontp += strlen(nfrontp); break; case ENCRYPT_REQEND: sprintf(nfrontp, " REQUEST-END"); nfrontp += strlen(nfrontp); break; case ENCRYPT_IS: case ENCRYPT_REPLY: sprintf(nfrontp, " %s ", (pointer[1] == ENCRYPT_IS) ? "IS" : "REPLY"); nfrontp += strlen(nfrontp); if (length < 3) { sprintf(nfrontp, " (partial suboption??\?)"); nfrontp += strlen(nfrontp); break; } if (ENCTYPE_NAME_OK(pointer[2])) sprintf(nfrontp, "%s ", ENCTYPE_NAME(pointer[2])); else sprintf(nfrontp, " %d (unknown)", pointer[2]); nfrontp += strlen(nfrontp); encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf)); sprintf(nfrontp, "%s", buf); nfrontp += strlen(nfrontp); break; case ENCRYPT_SUPPORT: i = 2; sprintf(nfrontp, " SUPPORT "); nfrontp += strlen(nfrontp); while (i < length) { if (ENCTYPE_NAME_OK(pointer[i])) sprintf(nfrontp, "%s ", ENCTYPE_NAME(pointer[i])); else sprintf(nfrontp, "%d ", pointer[i]); nfrontp += strlen(nfrontp); i++; } break; case ENCRYPT_ENC_KEYID: - sprintf(nfrontp, " ENC_KEYID", pointer[1]); + sprintf(nfrontp, " ENC_KEYID"); nfrontp += strlen(nfrontp); goto encommon; case ENCRYPT_DEC_KEYID: - sprintf(nfrontp, " DEC_KEYID", pointer[1]); + sprintf(nfrontp, " DEC_KEYID"); nfrontp += strlen(nfrontp); goto encommon; default: sprintf(nfrontp, " %d (unknown)", pointer[1]); nfrontp += strlen(nfrontp); encommon: for (i = 2; i < length; i++) { sprintf(nfrontp, " %d", pointer[i]); nfrontp += strlen(nfrontp); } break; } break; #endif /* ENCRYPTION */ 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); } break; } sprintf(nfrontp, "\r\n"); nfrontp += strlen(nfrontp); } /* * 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; { register int i; char xbuf[30]; while (cnt) { /* flush net output buffer if no room for new data) */ if ((&netobuf[BUFSIZ] - nfrontp) < 80) { netflush(); } /* add a line of output */ 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); } } #endif /* DIAGNOSTICS */