blob: 3bae53ec642b8e4dfeb9b3c16ab5c1b4821553f0 [file] [log] [blame]
char *cknetv = "Network support, 8.0.283, 7 Feb 2004";
/* C K C N E T -- Network support */
/*
Copyright (C) 1985, 2004,
Trustees of Columbia University in the City of New York.
All rights reserved. See the C-Kermit COPYING.TXT file or the
copyright text in the ckcmai.c module for disclaimer and permissions.
*/
/*
REMINDER: Any changes made to this file that other modules depend must
also be made to cklnet.c (for VOS) until such time as cklnet.c and this
module are merged back together.
NOTE TO CONTRIBUTORS: This file, and all the other shared (ckc and cku)
C-Kermit source files, must be compatible with C preprocessors that support
only #ifdef, #else, #endif, #define, and #undef. Please do not use #if,
logical operators, or other preprocessor features in this module. Also,
don't use any ANSI C constructs except within #ifdef CK_ANSIC..#endif.
Authors:
Frank da Cruz (fdc@columbia.edu),
Columbia University Academic Information Systems, New York City.
Jeffrey E Altman (jaltman@secure-endpoints.com) -- Primary
maintainer/developer since about 1996.
netopen() routine for TCP/IP originally by Ken Yap, Rochester University
(ken@cs.rochester.edu) (no longer at that address).
Missing pieces for Excelan sockets library from William Bader.
Telnet protocol by Frank da Cruz and Jeffrey Altman.
Rlogin protocol by Jeffrey E Altman.
SSL support adapted by Jeffrey E Altman from work done by
Tim Hudson <tjh@cryptosoft.com> +61 7 32781581
TLS support by Jeffrey E Altman.
HTTP support by Jeffrey E Altman.
TGV MultiNet code by Frank da Cruz.
MultiNet code adapted to WIN/TCP by Ray Hunter of TWG.
MultiNet code adapted to DEC TCP/IP by Lee Tibbert of DEC and Frank da Cruz.
TCP/IP support adapted to IBM TCP/IP 1.2.1,2.0 for OS/2 by Kai Uwe Rommel.
CMU-OpenVMS/IP modifications by Mike O'Malley, Digital (DEC).
X.25 support by Marcello Frutig, Catholic University,
Rio de Janeiro, Brazil (frutig@rnp.impa.br) with fixes from
Stefaan Eeckels, Eurokom, Luxembourg.
David Lane added support for Stratus VOS X.25 1996.
Stephen Riehm added support for IBM AIX X.25 in April 1998.
Other contributions as indicated in the code.
*/
#define CKCNET_C
#include "ckcsym.h"
#include "ckcdeb.h"
#include "ckcker.h"
#include "ckcasc.h"
#ifdef I386IX /* Has to come before ckcnet.h in */
#include <errno.h> /* this version, but after in others */
#endif /* I386IX */
#include "ckcnet.h" /* which includes ckctel.h */
#ifdef CK_SSL
#include "ck_ssl.h"
#endif /* CK_SSL */
#ifdef CK_DNS_SRV
#ifdef OS2
#ifdef NT
#include <wshelper.h>
#else /* NT */
/* !Error OS/2 does not support DNS Service Records. */
#endif /* NT */
#else /* OS2 */
#include <arpa/inet.h>
#ifdef USE_NAMESER_COMPAT
#include <arpa/nameser_compat.h>
#endif /* USE_NAMESER_COMPAT */
#include <arpa/nameser.h>
#include <resolv.h>
#ifndef PS2AIX10
#ifndef BSD4
#ifndef I386IX
#ifndef RTAIX
#include <netdb.h>
#endif /* RTAIX */
#endif /* I386IX */
#endif /* BSD4 */
#endif /* PS2AIX10 */
#endif /* OS2 */
#ifndef T_SRV
#define T_SRV 33
#endif /* T_SRV */
#ifndef T_TXT
#define T_TXT 16
#endif /* T_TXT */
/* for old Unixes and friends ... */
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 64
#endif /* MAXHOSTNAMELEN */
#define MAX_DNS_NAMELEN (15*(MAXHOSTNAMELEN + 1)+1)
#endif /* CK_DNS_SRV */
#ifdef NONET
#ifdef TCPIPLIB
#undef TCPIPLIB
#endif /* TCPIPLIB */
#endif /* NONET */
#ifndef NOMHHOST
#ifdef datageneral
#define NOMHHOST
#else
#ifdef HPUX5WINTCP
#define NOMHHOST
#endif /* HPUX5WINTCP */
#endif /* datageneral */
#endif /* NOMHHOST */
#ifdef INADDRX
struct in_addr inaddrx;
#endif /* INADDRX */
int ttnet = NET_NONE; /* Network type */
int ttnproto = NP_DEFAULT; /* Network virtual terminal protocol */
/* 0 = don't lowercase username for Rlogin/Telnet protocol */
/* nonzero = do lowercase it. Add a SET command if necessary... */
#ifdef VMS
int ck_lcname = 1;
#else
int ck_lcname = 0;
#endif /* VMS */
extern int /* External variables */
duplex, debses, seslog, sessft, wasclosed,
ttyfd, quiet, msgflg, what, nettype, ttmdm;
#ifdef IKSD
extern int inserver;
#endif /* IKSD */
char myipaddr[20] = { '\0' }; /* Global copy of my IP address */
#ifdef NETCONN
/* Don't need any of this if there is no network support. */
/*
NETLEBUF is (must be) defined for those platforms that call this
module to do network i/o (e.g. netinc(), nettchk(), etc) rather
than doing it themselves (ttinc(), ttchk(), etc). In this case
the Telnet local-echo buffers and routines are defined and referenced
here, rather than in the ck?tio.c module.
*/
#ifdef NETLEBUF
#define LEBUFSIZ 4096
int ttpush = -1, le_data = 0; /* These are seen from outside */
static CHAR le_buf[LEBUFSIZ]; /* These are used internally */
static int le_start = 0, le_end = 0;
int tt_push_inited = 0;
#endif /* NETLEBUF */
#ifdef CK_SOCKS /* SOCKS Internet relay package */
#ifdef CK_SOCKS5 /* SOCKS 5 */
#define accept SOCKSaccept
#define bind SOCKSbind
#define connect SOCKSconnect
#define getsockname SOCKSgetsockname
#define listen SOCKSlisten
#else /* Not SOCKS 5 */
#define accept Raccept
#define bind Rbind
#define connect Rconnect
#define getsockname Rgetsockname
#define listen Rlisten
#endif /* CK_SOCKS5 */
#endif /* CK_SOCKS */
#ifdef DEC_TCPIP
#include <time.h>
#include <inet.h>
#endif /* DEC_TCPIP */
/* Also see ckcnet.h -- hmmm, why don't we always include inet.h? */
#ifdef HPUX
#ifndef HPUX7 /* HPUX 7.00 doesn't have it */
#include <arpa/inet.h> /* For inet_ntoa() prototype */
#endif /* HPUX7 */
#endif /* HPUX */
#ifdef CMU_TCPIP
#include <time.h>
#endif /* CMU_TCPIP */
#ifndef NODCLTIMEVAL
#ifdef DCLTIMEVAL /* UnixWare 7 */
struct timeval { /* And define these ourselves. */
long tv_sec; /* (see comments in ckutio.c) */
long tv_usec;
};
struct timezone {
int tz_minuteswest;
int tz_dsttime;
};
#endif /* DCLTIMEVAL */
#endif /* NODCLTIMEVAL */
#ifdef WINTCP
#include <setjmp.h>
#include <signal.h>
#include <sys/time.h>
/*
The WIN/TCP code path is the same as that for MultiNet.
Only the routine names have changed ...
*/
#define socket_read netread
#define socket_ioctl ioctl
#define socket_write netwrite
#define socket_close netclose
#ifdef OLD_TWG /* some routines have evolved */
extern int vmserrno, uerrno;
#define socket_errno uerrno
#define socket_perror perror /* which uses errno, not uerrno! */
#else
#define socket_errno errno
#define socket_perror win$perror
#endif /* OLD_TWG */
#else /* Not WINTCP */
#ifdef OSF13
#ifdef CK_ANSIC
#ifdef _NO_PROTO
#undef _NO_PROTO
#endif /* _NO_PROTO */
#endif /* CK_ANSIC */
#endif /* OSF13 */
#ifndef I386IX
#include <errno.h> /* Already included above */
#endif /* I386IX */
#include <signal.h> /* Everybody needs this */
#ifdef ZILOG /* Zilog has different name for this */
#include <setret.h>
#else
#include <setjmp.h>
#endif /* ZILOG */
#endif /* WINTCP */
#ifdef datageneral /* Data General AOS/VS */
#include <:usr:include:vs_tcp_errno.h>
#include <:usr:include:sys:vs_tcp_types.h>
#ifdef SELECT
/*
NOTE: This can be compiled and linked OK with SELECT defined
but it doesn't work at all. Anybody who cares and knows how
to fix it, feel free.
*/
#include <:usr:include:sys:vs_tcp_time.h>
#endif /* SELECT */
#include <:usr:include:sys:socket.h>
#include <:usr:include:netinet:in.h>
#include <:usr:include:netdb.h>
#endif /* datageneral */
#ifndef socket_errno
#define socket_errno errno
#endif /* socket_errno */
#ifdef TNCODE
extern int tn_deb;
#endif /* TNCODE */
int tcp_rdns = /* Reverse DNS lookup */
#ifdef DEC_TCPIP_OLD
SET_OFF /* Doesn't seem to work in UCX */
#else
SET_AUTO
#endif /* DEC_TCPIP */
;
#ifdef CK_DNS_SRV
int tcp_dns_srv = SET_OFF;
#endif /* CK_DNS_SRV */
_PROTOTYP( char * cmcvtdate, (char *, int) );
#ifdef RLOGCODE
_PROTOTYP( int rlog_ctrl, (CHAR *, int) );
_PROTOTYP( static int rlog_oob, (CHAR *, int) );
#ifndef TCPIPLIB
_PROTOTYP( static SIGTYP rlogoobh, ( int ) );
#endif /* TCPIPLIB */
_PROTOTYP( static int rlog_ini, (CHAR *, int,
struct sockaddr_in *,
struct sockaddr_in *) );
int rlog_mode = RL_COOKED;
int rlog_stopped = 0;
int rlog_inband = 0;
#endif /* RLOGCODE */
#ifndef NOICP
extern int doconx; /* CONNECT-class command active */
#endif /* NOICP */
#ifdef IBMX25
/* This variable should probably be generalised for true client/server
* support - ie: the fd of the listening server, accepted calls should
* be forked or at least handled via a second fd (for IBM's X.25 -
* ttyfd always holds the active fd - ie the server becomes inactive
* as long as a client is connected, and becomes active again when the
* connection is closed)
*/
int x25serverfd = 0; /* extern in ckcnet.h */
int x25seqno = 0; /* Connection sequence number */
int x25lastmsg = -1; /* A cheapskate's state table */
#define X25_CLOSED 0 /* Default state: no connection, no STREAM */
#define X25_SETUP 1 /* X.25 has been set up (no connection) */
#define X25_CONNECTED 2 /* X.25 connection has been established */
int x25_state = X25_CLOSED; /* Default state */
#endif /* IBMX25 */
#ifndef DEBUG
#define deblog 0
#endif /* DEBUG */
#ifdef CK_NAWS /* Negotiate About Window Size */
#ifdef RLOGCODE
_PROTOTYP( int rlog_naws, (void) );
#endif /* RLOGCODE */
#endif /* CK_NAWS */
#ifdef OS2 /* For terminal type name string */
#include "ckuusr.h"
#ifndef NT
#include <os2.h>
#undef COMMENT
#endif /* NT */
#include "ckocon.h"
extern int tt_type, max_tt;
extern struct tt_info_rec tt_info[];
extern char ttname[];
#else
#ifdef CK_AUTHENTICATION
#include "ckuusr.h"
#endif /* CK_AUTHENTICATION */
#endif /* OS2 */
#ifdef NT
extern int winsock_version;
#endif /* NT */
#ifdef CK_AUTHENTICATION
#include "ckuath.h"
#endif /* CK_AUTHENTICATION */
#include "ckcsig.h"
#ifndef OS2 /* For timeout longjumps */
static ckjmpbuf njbuf;
#endif /* OS2 */
#define NAMECPYL 1024 /* Local copy of hostname */
char namecopy[NAMECPYL]; /* Referenced by ckctel.c */
char namecopy2[NAMECPYL]; /* Referenced by ckctel.c */
#ifndef NOHTTP
char http_host_port[NAMECPYL]; /* orig host/port necessary for http */
char http_ip[20] = { '\0' }; /* ip address of host */
char http_port = 0;
int http_ssl = 0;
char * http_agent = 0;
int httpfd = -1; /* socket for http connections */
int http_code = 0;
#define HTTPBUFLEN 1024
char http_reply_str[HTTPBUFLEN] = "";
#endif /* NOHTTP */
char ipaddr[20] = { '\0' }; /* Global copy of IP address */
unsigned long myxipaddr = 0L; /* Ditto as a number */
#endif /* NETCONN */
char *tcp_address = NULL; /* Preferred IP Address */
extern char uidbuf[]; /* User ID buffer */
extern char pwbuf[]; /* Password buffer */
#ifndef NOHTTP
char * tcp_http_proxy = NULL; /* Name[:port] of http proxy server */
int tcp_http_proxy_errno = 0;
char * tcp_http_proxy_user = NULL;
char * tcp_http_proxy_pwd = NULL;
char * tcp_http_proxy_agent = NULL;
#define HTTPCPYL 1024
static char proxycopy[HTTPCPYL];
#endif /* NOHTTP */
#ifdef OS2
extern int tt_rows[], tt_cols[];
extern int tt_status[VNUM];
#else /* OS2 */
extern int tt_rows, tt_cols; /* Everybody has this */
#endif /* OS2 */
extern int cmd_cols, cmd_rows;
#ifdef STREAMING /* Use blocking writes for streaming */
extern int streaming;
#endif /* STREAMING */
#ifdef NT
extern int WSASafeToCancel;
int win95selectbug = 0; /* For TCP/IP stacks whose select() */
/* always fails on write requests such as Cisco and Quarterdeck */
#define stricmp _stricmp
#endif /* NT */
#ifndef NOTCPOPTS
/* Skip all this if NOTCPOPTS specified. */
#ifdef SOL_SOCKET
#ifdef TCP_NODELAY
int tcp_nodelay = 0; /* Nagle algorithm TCP_NODELAY */
#endif /* TCP_NODELAY */
#ifdef SO_DONTROUTE
int tcp_dontroute = 0;
#endif /* SO_DONTROUTE */
#ifdef SO_LINGER
int tcp_linger = 0; /* SO_LINGER */
int tcp_linger_tmo = 0; /* SO_LINGER timeout */
#endif /* SO_LINGER */
#ifdef HPUX /* But the data structures */
#ifndef HPUX8 /* needed for linger are not */
#ifndef HPUX9 /* defined in HP-UX versions */
#ifndef HPUX10 /* prior to 8.00. */
#ifdef SO_LINGER
#undef SO_LINGER
#endif /* SO_LINGER */
#endif /* HPUX10 */
#endif /* HPUX9 */
#endif /* HPUX8 */
#endif /* HPUX */
#ifndef SO_OOBINLINE /* Hopefully only HP-UX 7.0 */
#define SO_OOBINLINE 0x0100
#endif /* SO_OOBINLINE */
#ifndef TCPSNDBUFSIZ
#ifdef VMS
#ifdef __alpha
#define TCPSNDBUFSIZ 16384
#endif /* __alpha */
#endif /* VMS */
#endif /* TCPSNDBUFSIZ */
#ifndef TCPSNDBUFSIZ
#define TCPSNDBUFSIZ -1
#endif /* TCPSNDBUFSIZ */
#ifdef SO_SNDBUF
int tcp_sendbuf = TCPSNDBUFSIZ;
#endif /* SO_SNDBUF */
#ifdef SO_RCVBUF
int tcp_recvbuf = -1;
#endif /* SO_RCVBUF */
#ifdef SO_KEEPALIVE
int tcp_keepalive = 1;
#endif /* SO_KEEPALIVE */
#endif /* SOL_SOCKET */
#endif /* NOTCPOPTS */
#ifndef NETCONN
/*
Network support not defined.
Dummy functions here in case #ifdef's forgotten elsewhere.
*/
int /* Open network connection */
netopen(name, lcl, nett) char *name; int *lcl, nett; {
return(-1);
}
int /* Close network connection */
netclos() {
return(-1);
}
int /* Check network input buffer */
nettchk() {
return(-1);
}
int /* Flush network input buffer */
netflui() {
return(-1);
}
int /* Send network BREAK */
netbreak() {
return(-1);
}
int /* Input character from network */
netinc(timo) int timo; {
return(-1);
}
int /* Output character to network */
#ifdef CK_ANSIC
nettoc(CHAR c)
#else
nettoc(c) CHAR c;
#endif /* CK_ANSIC */
/* nettoc */ {
return(-1);
}
int
nettol(s,n) CHAR *s; int n; {
return(-1);
}
#else /* NETCONN is defined (much of this module...) */
#ifdef NETLEBUF
VOID
le_init() { /* LocalEchoInit() */
int i;
for (i = 0; i < LEBUFSIZ; i++)
le_buf[i] = '\0';
le_start = 0;
le_end = 0;
le_data = 0;
tt_push_inited = 1;
}
VOID
le_clean() { /* LocalEchoCleanup() */
le_init();
return;
}
int
le_inbuf() {
int rc = 0;
if (le_start != le_end) {
rc = (le_end -
le_start +
LEBUFSIZ) % LEBUFSIZ;
}
return(rc);
}
int
#ifdef CK_ANSIC
le_putchar(CHAR ch)
#else
le_putchar(ch) CHAR ch;
#endif /* CK_ANSIC */
/* le_putchar */ {
if ((le_start - le_end + LEBUFSIZ)%LEBUFSIZ == 1) {
debug(F110,"le_putchar","buffer is full",0);
return(-1);
}
le_buf[le_end++] = ch;
if (le_end == LEBUFSIZ)
le_end = 0;
le_data = 1;
return(0);
}
int
#ifdef CK_ANSIC
le_puts(CHAR * s, int n)
#else
le_puts(s,n) CHAR * s; int n;
#endif /* CK_ANSIC */
/* le_puts */ {
int rc = 0;
int i = 0;
CHAR * p = (CHAR *)"le_puts";
hexdump(p,s,n);
for (i = 0; i < n; i++)
rc = le_putchar((char)s[i]);
debug(F101,"le_puts","",rc);
return(rc);
}
int
#ifdef CK_ANSIC
le_putstr(CHAR * s)
#else
le_putstr(s) CHAR * s;
#endif /* CK_ANSIC */
/* le_puts */ {
CHAR * p;
int rc = 0;
p = (CHAR *)"le_putstr";
hexdump(p,s,(int)strlen((char *)s));
for (p = s; *p && !rc; p++)
rc = le_putchar(*p);
return(rc);
}
int
#ifdef CK_ANSIC
le_getchar(CHAR * pch)
#else /* CK_ANSIC */
le_getchar(pch) CHAR * pch;
#endif /* CK_ANSIC */
/* le_gatchar */ {
int rc = 0;
if (le_start != le_end) {
*pch = le_buf[le_start];
le_buf[le_start] = 0;
le_start++;
if (le_start == LEBUFSIZ)
le_start = 0;
if (le_start == le_end) {
le_data = 0;
}
rc++;
} else {
*pch = 0;
}
return(rc);
}
#endif /* NETLEBUF */
#ifdef VMS
/*
In edit 190, we moved tn_ini() to be called from within netopen().
But tn_ini() calls ttol(), and ttol() checks to see if it's a net
connection, but the flag for that isn't set until after netopen()
is finished. Since, in this module, we are always doing network
output anyway, we just call nettol() directly, instead of going thru
ttol(). Only needed for VMS, since UNIX, AOS/VS, and VOS can handle
net connections just like regular connections in ttol(), and OS/2
has a special routine for this.
*/
#define ttol nettol
#endif /* VMS */
int tcpsrfd = -1;
#ifdef CK_KERBEROS
char * krb5_d_principal = NULL; /* Default principal */
char * krb5_d_instance = NULL; /* Default instance */
char * krb5_d_realm = NULL; /* Default realm */
char * krb5_d_cc = NULL; /* Default credentials cache */
char * krb5_d_srv = NULL; /* Default Service */
int krb5_d_lifetime = 600; /* Default lifetime (10 hours) */
int krb5_d_forwardable = 0; /* creds not forwardable */
int krb5_d_proxiable = 0; /* creds not proxiable */
int krb5_d_renewable = 0; /* creds not renewable (0 min) */
int krb5_autoget = 1; /* Autoget TGTs */
int krb5_autodel = 0; /* Auto delete TGTs */
int krb5_d_getk4 = 0; /* K5 Kinit gets K4 TGTs */
int krb5_checkaddrs = 1; /* Check TGT Addrs */
int krb5_d_no_addresses = 0; /* Do not include IP Addresses */
char * krb5_d_addrs[KRB5_NUM_OF_ADDRS+1]={NULL,NULL}; /* Addrs to include */
int krb5_errno = 0; /* Last K5 errno */
char * krb5_errmsg = NULL; /* Last K5 errmsg */
char * k5_keytab = NULL;
char * krb4_d_principal = NULL; /* Default principal */
char * krb4_d_realm = NULL; /* Default realm */
char * krb4_d_srv = NULL; /* Default Service */
int krb4_d_lifetime = 600; /* Default lifetime (10 hours) */
int krb4_d_preauth = 1; /* Use preauth requests */
char * krb4_d_instance = NULL; /* Default instance */
int krb4_autoget = 1; /* Autoget TGTs */
int krb4_autodel = 0; /* Auto delete TGTs */
int krb4_checkaddrs = 1; /* Check TGT Addrs */
char * k4_keytab = NULL;
int krb4_errno = 0; /* Last K4 errno */
char * krb4_errmsg = NULL; /* Last K4 errmsg */
struct krb_op_data krb_op = { /* Operational data structure */
0, NULL /* (version, cachefile) */
};
struct krb4_init_data krb4_init = { /* Kerberos 4 INIT data structure */
0, NULL, NULL, NULL, NULL
};
struct krb5_init_data krb5_init = { /* Kerberos 5 INIT data structure */
0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0,
{ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
0
};
struct krb5_list_cred_data krb5_lc = { /* List Credentials data structure */
0, 0, 0
};
int krb_action = -1; /* Kerberos action to perform */
#ifndef CK_AUTHENTICATION
char *
ck_krb4_getrealm() {
return("");
}
char *
ck_krb5_getrealm(cc) char * cc; {
return("");
}
char *
ck_krb4_getprincipal() {
return("");
}
char *
ck_krb5_getprincipal(cc) char * cc; {
return("");
}
#endif /* CK_AUTHENTICATION */
/* I N I _ K E R B -- Initialize Kerberos data */
VOID
ini_kerb() {
int i;
krb_action = -1; /* No action specified */
krb_op.version = 0; /* Kerberos version (none) */
krb_op.cache = NULL; /* Cache file (none) */
/* Kerberos 5 */
krb5_init.forwardable = krb5_d_forwardable; /* Init switch values... */
krb5_init.proxiable = krb5_d_proxiable;
krb5_init.lifetime = krb5_d_lifetime;
krb5_init.renew = 0;
krb5_init.renewable = krb5_d_renewable;
krb5_init.validate = 0;
krb5_init.no_addresses = krb5_d_no_addresses;
krb5_init.getk4 = krb5_d_getk4;
if (krb5_init.postdate) {
free(krb5_init.postdate);
krb5_init.postdate = NULL;
}
if (krb5_init.service) {
free(krb5_init.service);
krb5_init.service = NULL;
}
if (!krb5_d_cc || !krb5_d_cc[0]) { /* Set default cache */
char * p;
p = ck_krb5_get_cc_name();
makestr(&krb5_d_cc,(p && p[0]) ? p : NULL);
}
if (!krb5_d_realm || !krb5_d_realm[0]) { /* Set default realm */
char * p;
p = ck_krb5_getrealm(krb5_d_cc);
makestr(&krb5_d_realm,(p && p[0]) ? p : NULL);
}
makestr(&krb5_init.instance,krb5_d_instance);
makestr(&krb5_init.realm,krb5_d_realm); /* Set realm from default */
if (krb5_init.password) {
memset(krb5_init.password,0xFF,strlen(krb5_init.password));
free(krb5_init.password);
krb5_init.password = NULL;
}
if (!krb5_d_principal) { /* Default principal */
/* a Null principal indicates the user should be prompted */
char * p = ck_krb5_getprincipal(krb5_d_cc);
if (!p || !(*p))
p = (char *)uidbuf; /* Principal = user */
makestr(&krb5_d_principal,(p && p[0]) ? p : NULL);
}
makestr(&krb5_init.principal,krb5_d_principal);
for (i = 0; i <= KRB5_NUM_OF_ADDRS; i++) {
if (krb5_init.addrs[i])
free(krb5_init.addrs[i]);
krb5_init.addrs[i] = NULL;
}
for (i = 0; i <= KRB5_NUM_OF_ADDRS && krb5_d_addrs[i]; i++) {
makestr(&krb5_init.addrs[i],krb5_d_addrs[i]);
}
/* Kerberos 4 */
krb4_init.lifetime = krb4_d_lifetime;
krb4_init.preauth = krb4_d_preauth;
makestr(&krb4_init.instance,krb4_d_instance);
if (!krb4_d_realm || !krb4_d_realm[0]) {/* Set default realm */
char * p;
p = ck_krb4_getrealm();
makestr(&krb4_d_realm,(p && p[0]) ? p : NULL);
}
makestr(&krb4_init.realm,krb4_d_realm);
if (krb4_init.password) {
memset(krb4_init.password,0xFF,strlen(krb4_init.password));
free(krb4_init.password);
krb4_init.password = NULL;
}
if (!krb4_d_principal) { /* Default principal */
/* a Null principal indicates the user should be prompted */
char * p = ck_krb4_getprincipal();
if (!p || !(*p))
p = (char *)uidbuf; /* Principal = user */
makestr(&(krb4_d_principal),(p && p[0]) ? p : NULL);
}
makestr(&(krb4_init.principal),krb4_d_principal);
}
/* D O A U T H -- AUTHENTICATE action routine */
int
doauth(cx) int cx; { /* AUTHENTICATE action routine */
int rc = 0; /* Return code */
#ifdef CK_AUTHENTICATION
#ifdef OS2
if (!ck_security_loaddll()) /* Load various DLLs */
return(rc);
#endif /* OS2 */
if (krb_op.version == 4) { /* Version = 4 */
#ifdef COMMENT
sho_auth(AUTHTYPE_KERBEROS_V4);
#endif /* COMMENT */
if (!ck_krb4_is_installed()) {
printf("?Kerberos 4 is not installed\n");
return(0);
}
switch (krb_action) { /* Perform V4 functions */
case KRB_A_IN: /* INIT */
rc |= !(ck_krb4_initTGT(&krb_op,&krb4_init) < 0);
break;
case KRB_A_DE: /* DESTROY */
rc |= !(ck_krb4_destroy(&krb_op) < 0);
break;
case KRB_A_LC: /* LIST-CREDENTIALS */
rc |= !(ck_krb4_list_creds(&krb_op) < 0);
break;
}
}
if (krb_op.version == 5) { /* V5 functions */
#ifdef COMMENT
sho_auth(AUTHTYPE_KERBEROS_V5);
#endif /* COMMENT */
if (!ck_krb5_is_installed()) {
printf("?Kerberos 5 is not installed\n");
return(0);
}
switch (krb_action) {
case KRB_A_IN: /* INIT */
rc |= !(ck_krb5_initTGT(&krb_op,&krb5_init,
krb5_init.getk4 ? &krb4_init : 0) < 0);
break;
case KRB_A_DE: /* DESTROY */
rc |= !(ck_krb5_destroy(&krb_op) < 0);
break;
case KRB_A_LC: /* LIST-CREDENTIALS */
if (krb_op.version == 0)
printf("\n");
rc |= !(ck_krb5_list_creds(&krb_op,&krb5_lc) < 0);
break;
}
}
#else
#ifndef NOICP
#ifndef NOSHOW
rc = sho_auth(0); /* Show all */
#endif /* NOSHOW */
#endif /* NOICP */
#endif /* CK_AUTHENTICATION */
return(rc);
}
#endif /* CK_KERBEROS */
#ifdef TCPSOCKET
#ifndef OS2
#ifndef NOLISTEN /* For incoming connections */
#ifndef INADDR_ANY
#define INADDR_ANY 0
#endif /* INADDR_ANY */
_PROTOTYP( int ttbufr, ( VOID ) );
_PROTOTYP( int tcpsrv_open, (char *, int *, int, int ) );
static unsigned short tcpsrv_port = 0;
#endif /* NOLISTEN */
#endif /* OS2 */
static char svcbuf[80]; /* TCP service string */
static int svcnum = 0; /* TCP port number */
#endif /* TCPSOCKET */
/*
TCPIPLIB means use separate socket calls for i/o, while on UNIX the
normal file system calls are used for TCP/IP sockets too.
Means "DEC_TCPIP or MULTINET or WINTCP or OS2 or BEBOX" (see ckcnet.h),
*/
#ifdef TCPIPLIB
/* For buffered network reads... */
/*
If the buffering code is written right, it shouldn't matter
how long this buffer is.
*/
#ifdef OS2
#ifdef NT
#define TTIBUFL 64240 /* 44 * 1460 (MSS) */
#else
#define TTIBUFL 32120 /* 22 * 1460 (MSS) */
#endif /* NT */
#else /* OS2 */
#define TTIBUFL 8191 /* Let's use 8K. */
#endif /* OS2 */
CHAR ttibuf[TTIBUFL+1];
/*
select() is used in preference to alarm()/signal(), but different systems
use different forms of select()...
*/
#ifndef NOSELECT /* Option to override BSDSELECT */
#ifdef BELLV10
/*
Note: Although BELLV10 does have TCP/IP support, and does use the unique
form of select() that is evident in this module (and in ckutio.c), it does
not have a sockets library and so we can't build Kermit TCP/IP support for
it. For this, somebody would have to write TCP/IP streams code.
*/
#define BELLSELECT
#ifndef FD_SETSIZE
#define FD_SETSIZE 128
#endif /* FD_SETSIZE */
#else
#ifdef WINTCP /* VMS with Wollongong WIN/TCP */
#ifndef OLD_TWG /* TWG 3.2 has only select(read) */
#define BSDSELECT
#endif /* OLD_TWG */
#else
#ifdef CMU_TCPIP /* LIBCMU can do select */
#define BSDSELECT
#else
#ifdef DEC_TCPIP
#define BSDSELECT
#else
#ifdef OS2 /* OS/2 with TCP/IP */
#ifdef NT
#define BSDSELECT
#else /* NT */
#define IBMSELECT
#endif /* NT */
#endif /* OS2 */
#endif /* DEC_TCPIP */
#endif /* CMU_TCPIP */
#endif /* WINTCP */
#endif /* BELLV10 */
#endif /* NOSELECT */
/*
Others (TGV, TCPware, ...) use alarm()/signal(). The BSDSELECT case does not
compile at all; the IBMSELECT case compiles and links but crashes at runtime.
NOTE: If any of these can be converted to select(), they should be for two
reasons: (1) It's a lot faster; (2) certain sockets libraries do not like
their socket_read() calls to be interrupted; subsequent socket_read()'s tend
to fail with EBUSY. This happened in the UCX case before it was converted
to use select().
*/
#ifndef OS2
#ifndef VMS
static /* These are used in CKVTIO.C */
#endif /* VMS */ /* And in CKONET.C */
#endif /* OS2 */
int
ttibp = 0,
ttibn = 0;
/*
Read bytes from network into internal buffer ttibuf[].
To be called when input buffer is empty, i.e. when ttibn == 0.
Other network reading routines, like ttinc, ttinl, ttxin, should check the
internal buffer first, and call this routine for a refill if necessary.
Returns -1 on error, 0 if nothing happens. When data is read successfully,
returns number of bytes read, and sets global ttibn to that number and
ttibp (the buffer pointer) to zero.
*/
_PROTOTYP( int ttbufr, ( VOID ) );
int
ttbufr() { /* TT Buffer Read */
int count;
if (ttnet != NET_TCPB) /* First make sure current net is */
return(-1); /* TCP/IP; if not, do nothing. */
#ifdef OS2
RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
#endif /* OS2 */
if (ttibn > 0) { /* Our internal buffer is not empty, */
#ifdef OS2
ReleaseTCPIPMutex();
#endif /* OS2 */
return(ttibn); /* so keep using it. */
}
if (ttyfd == -1) { /* No connection, error */
#ifdef OS2
ReleaseTCPIPMutex();
#endif /* OS2 */
return(-2);
}
ttibp = 0; /* Else reset pointer to beginning */
#ifdef WINTCP
count = 512; /* This works for WIN/TCP */
#else
#ifdef DEC_TCPIP
count = 512; /* UCX */
#else
#ifdef OS2
count = TTIBUFL;
#else /* Multinet, etc. */
count = ttchk(); /* Check network input buffer, */
if (ttibn > 0) { /* which can put a char there! */
debug(F111,"ttbufr","ttchk() returns",count);
#ifdef OS2
ReleaseTCPIPMutex();
#endif /* OS2 */
return(ttibn);
}
if (count < 0) { /* Read error - connection closed */
#ifdef OS2
ReleaseTCPIPMutex();
#endif /* OS2 */
return(-2);
}
else if (count > TTIBUFL) /* Too many to read */
count = TTIBUFL;
else if (count == 0) /* None, so force blocking read */
count = 1;
#endif /* OS2 */
#endif /* DEC_TCPIP */
#endif /* WINTCP */
debug(F101,"ttbufr count 1","",count);
#ifdef CK_SSL
if (ssl_active_flag || tls_active_flag) {
int error;
ssl_read:
if (ssl_active_flag)
count = SSL_read(ssl_con, ttibuf, count);
else
count = SSL_read(tls_con, ttibuf, count);
error = SSL_get_error(ssl_active_flag?ssl_con:tls_con,count);
switch (error) {
case SSL_ERROR_NONE:
debug(F111,"ttbufr SSL_ERROR_NONE","count",count);
if (count > 0) {
ttibp = 0; /* Reset buffer pointer. */
ttibn = count;
#ifdef OS2
ReleaseTCPIPMutex();
#endif /* OS2 */
return(ttibn); /* Return buffer count. */
} else if (count < 0) {
#ifdef OS2
ReleaseTCPIPMutex();
#endif /* OS2 */
return(-1);
} else {
netclos();
#ifdef OS2
ReleaseTCPIPMutex();
#endif /* OS2 */
return(-2);
}
case SSL_ERROR_WANT_WRITE:
debug(F100,"ttbufr SSL_ERROR_WANT_WRITE","",0);
#ifdef OS2
ReleaseTCPIPMutex();
#endif /* OS2 */
return(-1);
case SSL_ERROR_WANT_READ:
debug(F100,"ttbufr SSL_ERROR_WANT_READ","",0);
#ifdef OS2
ReleaseTCPIPMutex();
#endif /* OS2 */
return(-1);
case SSL_ERROR_SYSCALL:
if ( count == 0 ) { /* EOF */
netclos();
#ifdef OS2
ReleaseTCPIPMutex();
#endif /* OS2 */
return(-2);
} else {
int rc = -1;
#ifdef NT
int gle = GetLastError();
debug(F111,"ttbufr SSL_ERROR_SYSCALL",
"GetLastError()",gle);
rc = os2socketerror(gle);
if (rc == -1)
rc = -2;
else if ( rc == -2 )
rc = -1;
#endif /* NT */
#ifdef OS2
ReleaseTCPIPMutex();
#endif /* OS2 */
return(rc);
}
case SSL_ERROR_WANT_X509_LOOKUP:
debug(F100,"ttbufr SSL_ERROR_WANT_X509_LOOKUP","",0);
netclos();
#ifdef OS2
ReleaseTCPIPMutex();
#endif /* OS2 */
return(-2);
case SSL_ERROR_SSL:
if (bio_err!=NULL) {
int len;
extern char ssl_err[];
BIO_printf(bio_err,"ttbufr SSL_ERROR_SSL\n");
ERR_print_errors(bio_err);
len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
debug(F110,"ttbufr SSL_ERROR_SSL",ssl_err,0);
if (ssl_debug_flag)
printf(ssl_err);
} else if (ssl_debug_flag) {
debug(F100,"ttbufr SSL_ERROR_SSL","",0);
fflush(stderr);
fprintf(stderr,"ttbufr SSL_ERROR_SSL\n");
ERR_print_errors_fp(stderr);
}
#ifdef COMMENT
netclos();
#endif /* COMMENT */
#ifdef OS2
ReleaseTCPIPMutex();
#endif /* OS2 */
return(-2);
case SSL_ERROR_ZERO_RETURN:
debug(F100,"ttbufr SSL_ERROR_ZERO_RETURN","",0);
netclos();
#ifdef OS2
ReleaseTCPIPMutex();
#endif /* OS2 */
return(-2);
default:
debug(F100,"ttbufr SSL_ERROR_?????","",0);
netclos();
#ifdef OS2
ReleaseTCPIPMutex();
#endif /* OS2 */
return(-2);
}
}
#endif /* CK_SSL */
#ifdef COMMENT
/*
This is for nonblocking reads, which we don't do any more. This code didn't
work anyway, in the sense that a broken connection was never sensed.
*/
if ((count = socket_read(ttyfd,&ttibuf[ttibp+ttibn],count)) < 1) {
if (count == -1 && socket_errno == EWOULDBLOCK) {
debug(F100,"ttbufr finds nothing","",0);
#ifdef OS2
ReleaseTCPIPMutex();
#endif /* OS2 */
return(0);
} else {
debug(F101,"ttbufr socket_read error","",socket_errno);
#ifdef OS2
ReleaseTCPIPMutex();
#endif /* OS2 */
return(-1);
}
} else if (count == 0) {
debug(F100,"ttbufr socket eof","",0);
#ifdef OS2
ReleaseTCPIPMutex();
#endif /* OS2 */
return(-1);
}
#else /* COMMENT */
/* This is for blocking reads */
#ifndef VMS
#ifdef SO_OOBINLINE
{
int outofband = 0;
#ifdef BELLSELECT
if (select(128, NULL, NULL, efds, 0) > 0 && FD_ISSET(ttyfd, efds))
outofband = 1;
#else
#ifdef BSDSELECT
fd_set efds;
struct timeval tv;
FD_ZERO(&efds);
FD_SET(ttyfd, &efds);
tv.tv_sec = tv.tv_usec = 0L;
debug(F100,"Out-of-Band BSDSELECT","",0);
#ifdef NT
WSASafeToCancel = 1;
#endif /* NT */
if (select(FD_SETSIZE, NULL, NULL, &efds, &tv) > 0 &&
FD_ISSET(ttyfd, &efds))
outofband = 1;
#ifdef NT
WSASafeToCancel = 0;
#endif /* NT */
#else /* !BSDSELECT */
#ifdef IBMSELECT
/* Is used by OS/2 ... */
/* ... and it came in handy! For our TCP/IP layer, it avoids all the fd_set */
/* and timeval stuff since this is the only place where it is used. */
int socket = ttyfd;
debug(F100,"Out-of-Band IBMSELECT","",0);
if ((select(&socket, 0, 0, 1, 0L) == 1) && (socket == ttyfd))
outofband = 1;
#else /* !IBMSELECT */
/*
If we can't use select(), then we use the regular alarm()/signal()
timeout mechanism.
*/
debug(F101,"Out-of-Band data not supported","",0);
outofband = 0;
#endif /* IBMSELECT */
#endif /* BSDSELECT */
#endif /* BELLSELECT */
if (outofband) {
/* Get the Urgent Data */
/* if OOBINLINE is disabled this should be only a single byte */
/* MS Winsock has a bug in Windows 95. Extra bytes are delivered */
/* That were never sent. */
#ifdef OS2
RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
#endif /* OS2 */
count = socket_recv(ttyfd,&ttibuf[ttibp+ttibn],count,MSG_OOB);
#ifdef OS2
ReleaseTCPIPMutex();
#endif /* OS2 */
if (count <= 0) {
int s_errno = socket_errno;
debug(F101, "ttbufr socket_recv MSG_OOB","",count);
debug(F101, "ttbufr socket_errno","",s_errno);
#ifdef OS2ONLY
if (count < 0 && (s_errno == 0 || s_errno == 23)) {
/* These appear in OS/2 - don't know why */
/* ignore it and read as normal data */
/* and break, then we will attempt to read */
/* the port using normal read() techniques */
debug(F100,"ttbufr handing as in-band data","",0);
count = 1;
} else {
netclos(); /* *** *** */
#ifdef OS2
ReleaseTCPIPMutex();
#endif /* OS2 */
return(-2);
}
#else /* OS2ONLY */
netclos(); /* *** *** */
#ifdef OS2
ReleaseTCPIPMutex();
#endif /* OS2 */
return(-2);
#endif /* OS2ONLY */
} else { /* we got out-of-band data */
hexdump("ttbufr out-of-band chars",&ttibuf[ttibp+ttibn],count);
#ifdef BETADEBUG
bleep(BP_NOTE);
#endif /* BETADEBUG */
#ifdef RLOGCODE /* blah */
if (ttnproto == NP_RLOGIN ||
ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN ||
((ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN) &&
!rlog_inband)
)
{
/*
When urgent data is read with MSG_OOB and not OOBINLINE
then urgent data and normal data are not mixed. So
treat the entire buffer as urgent data.
*/
rlog_oob(&ttibuf[ttibp+ttibn], count);
#ifdef OS2
ReleaseTCPIPMutex();
#endif /* OS2 */
return ttbufr();
} else
#endif /* RLOGCODE */ /* blah */
#ifdef COMMENT
/*
I haven't written this yet, nor do I know what it should do
*/
if (ttnproto == NP_TELNET) {
tn_oob();
#ifdef OS2
ReleaseTCPIPMutex();
#endif /* OS2 */
return 0;
} else
#endif /* COMMENT */
{
/* For any protocols we don't have a special out-of-band */
/* handler for, just put the bytes in the normal buffer */
/* and return */
ttibp += 0; /* Reset buffer pointer. */
ttibn += count;
#ifdef DEBUG
/* Got some bytes. */
debug(F101,"ttbufr count 2","",count);
if (count > 0)
ttibuf[ttibp+ttibn] = '\0';
debug(F111,"ttbufr ttibuf",ttibuf,ttibp);
#endif /* DEBUG */
#ifdef OS2
ReleaseTCPIPMutex();
#endif /* OS2 */
return(ttibn); /* Return buffer count. */
}
}
}
}
#endif /* SO_OOBINLINE */
#endif /* VMS */
count = socket_read(ttyfd,&ttibuf[ttibp+ttibn],count);
if (count <= 0) {
int s_errno = socket_errno;
debug(F101,"ttbufr socket_read","",count);
debug(F101,"ttbufr socket_errno","",s_errno);
#ifdef OS2
if (count == 0 || os2socketerror(s_errno) < 0) {
netclos();
ReleaseTCPIPMutex();
return(-2);
}
ReleaseTCPIPMutex();
return(-1);
#else /* OS2 */
netclos(); /* *** *** */
return(-2);
#endif /* OS2 */
}
#endif /* COMMENT */ /* (blocking vs nonblock reads...) */
else {
ttibp = 0; /* Reset buffer pointer. */
ttibn += count;
#ifdef DEBUG
debug(F101,"ttbufr count 2","",count); /* Got some bytes. */
if (count > 0)
ttibuf[ttibp+ttibn] = '\0';
debug(F111,"ttbufr ttibuf",&ttibuf[ttibp],ttibn);
#endif /* DEBUG */
#ifdef OS2
ReleaseTCPIPMutex();
#endif /* OS2 */
return(ttibn); /* Return buffer count. */
}
}
#endif /* TCPIPLIB */
#ifndef IBMSELECT
#ifndef BELLSELECT
#ifndef BSDSELECT /* Non-TCPIPLIB case */
#ifdef SELECT
#define BSDSELECT
#endif /* SELECT */
#endif /* BSDSELECT */
#endif /* BELLSELECT */
#endif /* IBMSELECT */
#define TELNET_PORT 23 /* Should do lookup, but it won't change */
#define RLOGIN_PORT 513
#define KERMIT_PORT 1649
#define KLOGIN_PORT 543
#define EKLOGIN_PORT 2105
#ifndef NONET
/*
C-Kermit network open/close functions for BSD-sockets.
Much of this code shared by SunLink X.25, which also uses the socket library.
*/
/* N E T O P N -- Open a network connection. */
/*
Call with:
name of host (or host:service),
lcl - local-mode flag to be set if this function succeeds,
network type - value defined in ckunet.h.
*/
#ifdef TCPSOCKET
struct hostent *
#ifdef CK_ANSIC
ck_copyhostent(struct hostent * h)
#else /* CK_ANSIC */
ck_copyhostent(h) struct hostent * h;
#endif /* CK_ANSIC */
{
/*
* The hostent structure is dynamic in nature.
* struct hostent {
* char * h_name;
* char * * h_aliases;
* short h_addrtype;
* short h_length;
* char * * h_addr_list;
* #define h_addr h_addr_list[0]
*/
#define HOSTENTCNT 5
static struct hostent hosts[HOSTENTCNT] = {{NULL,NULL,0,0,NULL},
{NULL,NULL,0,0,NULL},
{NULL,NULL,0,0,NULL},
{NULL,NULL,0,0,NULL},
{NULL,NULL,0,0,NULL}};
static int next = 0;
int i,cnt;
char ** pp;
if ( h == NULL )
return(NULL);
if (next == HOSTENTCNT)
next = 0;
if ( hosts[next].h_name ) {
free(hosts[next].h_name);
hosts[next].h_name = NULL;
}
if ( hosts[next].h_aliases ) {
pp = hosts[next].h_aliases;
while ( *pp ) {
free(*pp);
pp++;
}
free(hosts[next].h_aliases);
}
#ifdef HADDRLIST
if ( hosts[next].h_addr_list ) {
pp = hosts[next].h_addr_list;
while ( *pp ) {
free(*pp);
pp++;
}
free(hosts[next].h_addr_list);
}
#endif /* HADDRLIST */
makestr(&hosts[next].h_name,h->h_name);
if (h->h_aliases) {
for ( cnt=0,pp=h->h_aliases; pp && *pp; pp++,cnt++) ;
/* The following can give warnings in non-ANSI builds */
hosts[next].h_aliases = (char **) malloc(sizeof(char *) * (cnt+1));
for ( i=0; i<cnt; i++) {
hosts[next].h_aliases[i] = NULL;
makestr(&hosts[next].h_aliases[i],h->h_aliases[i]);
}
hosts[next].h_aliases[i] = NULL;
} else
hosts[next].h_aliases = NULL;
hosts[next].h_addrtype = h->h_addrtype;
hosts[next].h_length = h->h_length;
#ifdef HADDRLIST
#ifdef h_addr
if (h->h_addr_list) {
for ( cnt=0,pp=h->h_addr_list; pp && *pp; pp++,cnt++) ;
/* The following can give warnings non-ANSI builds */
hosts[next].h_addr_list = (char **) malloc(sizeof(char *) * (cnt+1));
for ( i=0; i<cnt; i++) {
hosts[next].h_addr_list[i] = malloc(h->h_length);
bcopy(h->h_addr_list[i],hosts[next].h_addr_list[i],h->h_length);
}
hosts[next].h_addr_list[i] = NULL;
} else
hosts[next].h_addr_list = NULL;
#else
bcopy(h->h_addr, &hosts[next].h_addr, h->h_length);
#endif /* h_addr */
#else /* HADDRLIST */
bcopy(h->h_addr, &hosts[next].h_addr, h->h_length);
#endif /* HADDRLIST */
return(&hosts[next++]);
}
#ifdef EXCELAN
/*
Most other BSD sockets implementations define these in header files
and libraries.
*/
struct servent {
unsigned short s_port;
};
struct hostent {
short h_addrtype;
struct in_addr h_addr;
int h_length;
};
struct servent *
getservbyname(service, connection) char *service,*connection; {
static struct servent servrec;
int port;
port = 0;
if (strcmp(service, "telnet") == 0) port = 23;
else if (strcmp(service, "smtp") == 0) port = 25;
else port = atoi(service);
debug(F101,"getservbyname return port ","",port);
if (port > 0) {
servrec.s_port = htons(port);
return(&servrec);
}
return((struct servent *) NULL);
}
struct hostent *
gethostbyname(hostname) char *hostname; {
return((struct hostent *) NULL);
}
unsigned long
inet_addr(name) char *name; {
unsigned long addr;
addr = rhost(&name);
debug(F111,"inet_addr ",name,(int)addr);
return(addr);
}
char *
inet_ntoa(in) struct in_addr in; {
static char name[80];
ckmakxmsg(name, ckuitoa(in.s_net),".",ckuitoa(in.s_host),".",
ckuitoa(in.s_lh),".", ckuitoa(in.s_impno));
return(name);
}
#else
#ifdef DEC_TCPIP /* UCX */
int ucx_port_bug = 0; /* Explained below */
#ifndef __DECC /* VAXC or GCC */
#define getservbyname my_getservbyname
#ifdef CK_ANSIC
globalref int (*C$$GA_UCX_GETSERVBYNAME)();
extern void C$$TRANSLATE();
extern void C$$SOCK_TRANSLATE();
#else
globalref int (*C$$GA_UCX_GETSERVBYNAME)();
extern VOID C$$TRANSLATE();
extern VOID C$$SOCK_TRANSLATE();
#endif /* CK_ANSIC */
struct servent *
my_getservbyname (service, proto) char *service, *proto; {
static struct servent sent;
struct iosb {
union {
unsigned long status;
unsigned short st[2];
} sb;
unsigned long spare;
} s;
struct {
struct iosb *s;
char *serv;
char *prot;
} par;
unsigned long e;
char sbuf[30], pbuf[30];
char *p;
debug(F111,"UCX getservbyname",service,(int)C$$GA_UCX_GETSERVBYNAME);
p = sbuf;
ckstrncpy(p, service, 29);
while (*p = toupper(*p), *p++) {}
p = pbuf;
ckstrncpy(p, proto, 29);
while (*p = toupper(*p), *p++) {}
par.s = &s;
par.serv = "";
par.prot = "";
/* reset file pointer or something like that!?!? */
e = (*C$$GA_UCX_GETSERVBYNAME)(&par, &sent, par.s);
par.serv = sbuf;
par.prot = pbuf; /* that is don't care */
e = (*C$$GA_UCX_GETSERVBYNAME)(&par, &sent, par.s);
if ((long)e == -1L)
return NULL;
if ((e & 1) == 0L) {
C$$TRANSLATE(e);
return NULL;
}
if ((s.sb.st[0] & 1) == 0) {
C$$SOCK_TRANSLATE(&s.sb.st[0]);
return NULL;
}
/*
sent.s_port is supposed to be returned by UCX in network byte order.
However, UCX 2.0 through 2.0C did not do this; 2.0D and later do it.
But there is no way of knowing which UCX version, so we have a user-settable
runtime variable. Note: UCX 2.0 was only for the VAX.
*/
debug(F101,"UCX getservbyname port","",sent.s_port);
debug(F101,"UCX getservbyname ntohs(port)","",ntohs(sent.s_port));
if (ucx_port_bug) {
sent.s_port = htons(sent.s_port);
debug(F100,"UCX-PORT-BUG ON: swapping bytes","",0);
debug(F101,"UCX swapped port","",sent.s_port);
debug(F101,"UCX swapped ntohs(port)","",ntohs(sent.s_port));
}
return &sent;
}
#endif /* __DECC */
#endif /* DEC_TCPIP */
#endif /* EXCELAN */
#endif /* TCPSOCKET */
#ifndef NOTCPOPTS
#ifndef datageneral
int
ck_linger(sock, onoff, timo) int sock; int onoff; int timo; {
/*
The following, from William Bader, turns off the socket linger parameter,
which makes a close() block until all data is sent. "I don't think that
disabling linger can ever cause kermit to lose data, but you telnet to a
flaky server (or to our modem server when the modem is in use), disabling
linger prevents kermit from hanging on the close if you try to exit."
Modified by Jeff Altman to be generally useful.
*/
#ifdef SOL_SOCKET
#ifdef SO_LINGER
struct linger set_linger_opt;
struct linger get_linger_opt;
SOCKOPT_T x;
#ifdef IKSD
if (!inserver)
#endif /* IKSD */
if (sock == -1 ||
nettype != NET_TCPA && nettype != NET_TCPB &&
nettype != NET_SSH || ttmdm >= 0) {
tcp_linger = onoff;
tcp_linger_tmo = timo;
return(1);
}
x = sizeof(get_linger_opt);
if (getsockopt(sock, SOL_SOCKET, SO_LINGER,
(char *)&get_linger_opt, &x)) {
debug(F111,"TCP ck_linger can't get SO_LINGER",ck_errstr(),errno);
} else if (x != sizeof(get_linger_opt)) {
#ifdef OS2
struct _linger16 {
short s_linger;
short s_onoff;
} get_linger_opt16, set_linger_opt16;
if ( x == sizeof(get_linger_opt16) ) {
debug(F111,"TCP setlinger warning: SO_LINGER","len is 16-bit",x);
if (getsockopt(sock,
SOL_SOCKET, SO_LINGER,
(char *)&get_linger_opt16, &x)
) {
debug(F111,
"TCP ck_linger can't get SO_LINGER",ck_errstr(),errno);
} else if (get_linger_opt16.s_onoff != onoff ||
get_linger_opt16.s_linger != timo)
{
set_linger_opt16.s_onoff = onoff;
set_linger_opt16.s_linger = timo;
if (setsockopt(sock,
SOL_SOCKET,
SO_LINGER,
(char *)&set_linger_opt16,
sizeof(set_linger_opt16))
) {
debug(F111,
"TCP ck_linger can't set SO_LINGER",
ck_errstr(),
errno
);
tcp_linger = get_linger_opt16.s_onoff;
tcp_linger_tmo = get_linger_opt16.s_linger;
} else {
debug(F101,
"TCP ck_linger new SO_LINGER","",
set_linger_opt16.s_onoff);
tcp_linger = set_linger_opt16.s_onoff;
tcp_linger_tmo = set_linger_opt16.s_linger;
return 1;
}
} else {
debug(F101,"TCP ck_linger SO_LINGER unchanged","",
get_linger_opt16.s_onoff);
tcp_linger = get_linger_opt16.s_onoff;
tcp_linger_tmo = get_linger_opt16.s_linger;
return 1;
}
return(0);
}
#endif /* OS2 */
debug(F111,"TCP ck_linger error: SO_LINGER","len",x);
debug(F111,"TCP ck_linger SO_LINGER",
"expected len",sizeof(get_linger_opt));
debug(F111,"TCP ck_linger SO_LINGER","linger_opt.l_onoff",
get_linger_opt.l_onoff);
debug(F111,"TCP linger SO_LINGER","linger_opt.l_linger",
get_linger_opt.l_linger);
} else if (get_linger_opt.l_onoff != onoff ||
get_linger_opt.l_linger != timo) {
set_linger_opt.l_onoff = onoff;
set_linger_opt.l_linger = timo;
if (setsockopt(sock,
SOL_SOCKET,
SO_LINGER,
(char *)&set_linger_opt,
sizeof(set_linger_opt))) {
debug(F111,"TCP ck_linger can't set SO_LINGER",ck_errstr(),errno);
tcp_linger = get_linger_opt.l_onoff;
tcp_linger_tmo = get_linger_opt.l_linger;
} else {
debug(F101,
"TCP ck_linger new SO_LINGER",
"",
set_linger_opt.l_onoff
);
tcp_linger = set_linger_opt.l_onoff;
tcp_linger_tmo = set_linger_opt.l_linger;
return 1;
}
} else {
debug(F101,"TCP ck_linger SO_LINGER unchanged","",
get_linger_opt.l_onoff);
tcp_linger = get_linger_opt.l_onoff;
tcp_linger_tmo = get_linger_opt.l_linger;
return 1;
}
#else
debug(F100,"TCP ck_linger SO_LINGER not defined","",0);
#endif /* SO_LINGER */
#else
debug(F100,"TCP ck_linger SO_SOCKET not defined","",0);
#endif /* SOL_SOCKET */
return(0);
}
int
sendbuf(sock,size) int sock; int size; {
/*
The following, from William Bader, allows changing of socket buffer sizes,
in case that might affect performance.
Modified by Jeff Altman to be generally useful.
*/
#ifdef SOL_SOCKET
#ifdef SO_SNDBUF
int i, j;
SOCKOPT_T x;
#ifdef IKSD
if (!inserver)
#endif /* IKSD */
if (sock == -1 ||
nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH
|| ttmdm >= 0) {
tcp_sendbuf = size;
return 1;
}
x = sizeof(i);
if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&i, &x)) {
debug(F111,"TCP sendbuf can't get SO_SNDBUF",ck_errstr(),errno);
} else if (x != sizeof(i)) {
#ifdef OS2
short i16,j16;
if (x == sizeof(i16)) {
debug(F111,"TCP sendbuf warning: SO_SNDBUF","len is 16-bit",x);
if (getsockopt(sock,
SOL_SOCKET, SO_SNDBUF,
(char *)&i16, &x)
) {
debug(F111,"TCP sendbuf can't get SO_SNDBUF",
ck_errstr(),errno);
} else if (size <= 0) {
tcp_sendbuf = i16;
debug(F101,"TCP sendbuf SO_SNDBUF retrieved","",i16);
return 1;
} else if (i16 != size) {
j16 = size;
if (setsockopt(sock,
SOL_SOCKET,
SO_SNDBUF,
(char *)&j16,
sizeof(j16))
) {
debug(F111,"TCP sendbuf can't set SO_SNDBUF",
ck_errstr(),errno);
} else {
debug(F101,"TCP sendbuf old SO_SNDBUF","",i16);
debug(F101,"TCP sendbuf new SO_SNDBUF","",j16);
tcp_sendbuf = size;
return 1;
}
} else {
debug(F101,"TCP sendbuf SO_SNDBUF unchanged","",i16);
tcp_sendbuf = size;
return 1;
}
return(0);
}
#endif /* OS2 */
debug(F111,"TCP sendbuf error: SO_SNDBUF","len",x);
debug(F111,"TCP sendbuf SO_SNDBUF","expected len",sizeof(i));
debug(F111,"TCP sendbuf SO_SNDBUF","i",i);
} else if (size <= 0) {
tcp_sendbuf = i;
debug(F101,"TCP sendbuf SO_SNDBUF retrieved","",i);
return 1;
} else if (i != size) {
j = size;
if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&j, sizeof(j))) {
debug(F111,"TCP sendbuf can't set SO_SNDBUF",ck_errstr(),errno);
tcp_sendbuf = i;
} else {
debug(F101,"TCP sendbuf old SO_SNDBUF","",i);
debug(F101,"TCP sendbuf new SO_SNDBUF","",j);
tcp_sendbuf = size;
return 1;
}
} else {
debug(F101,"TCP sendbuf SO_SNDBUF unchanged","",i);
tcp_sendbuf = size;
return 1;
}
#else
debug(F100,"TCP sendbuf SO_SNDBUF not defined","",0);
#endif /* SO_SNDBUF */
#else
debug(F100,"TCP sendbuf SO_SOCKET not defined","",0);
#endif /* SOL_SOCKET */
return(0);
}
int
recvbuf(sock,size) int sock; int size; {
/*
The following, from William Bader, allows changing of socket buffer sizes,
in case that might affect performance.
Modified by Jeff Altman to be generally useful.
*/
#ifdef SOL_SOCKET
#ifdef SO_RCVBUF
int i, j;
SOCKOPT_T x;
#ifdef IKSD
if (!inserver)
#endif /* IKSD */
if (sock == -1 ||
nettype != NET_TCPA && nettype != NET_TCPB &&
nettype != NET_SSH || ttmdm >= 0) {
tcp_recvbuf = size;
return(1);
}
x = sizeof(i);
if (getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&i, &x)) {
debug(F111,"TCP recvbuf can't get SO_RCVBUF",ck_errstr(),errno);
} else if (x != sizeof(i)) {
#ifdef OS2
short i16,j16;
if ( x == sizeof(i16) ) {
debug(F111,"TCP recvbuf warning: SO_RCVBUF","len is 16-bit",x);
if (getsockopt(sock,
SOL_SOCKET, SO_RCVBUF,
(char *)&i16, &x)
) {
debug(F111,"TCP recvbuf can't get SO_RCVBUF",
ck_errstr(),errno);
} else if (size <= 0) {
tcp_recvbuf = i16;
debug(F101,"TCP recvbuf SO_RCVBUF retrieved","",i16);
return 1;
} else if (i16 != size) {
j16 = size;
if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&j16,
sizeof(j16))) {
debug(F111,"TCP recvbuf can' set SO_RCVBUF",
ck_errstr(),errno);
} else {
debug(F101,"TCP recvbuf old SO_RCVBUF","",i16);
debug(F101,"TCP recvbuf new SO_RCVBUF","",j16);
tcp_recvbuf = size;
return 1;
}
} else {
debug(F101,"TCP recvbuf SO_RCVBUF unchanged","",i16);
tcp_recvbuf = size;
return 1;
}
return(0);
}
#endif /* OS2 */
debug(F111,"TCP recvbuf error: SO_RCVBUF","len",x);
debug(F111,"TCP recvbuf SO_RCVBUF","expected len",sizeof(i));
debug(F111,"TCP recvbuf SO_RCVBUF","i",i);
} else if (size <= 0) {
tcp_recvbuf = i;
debug(F101,"TCP recvbuf SO_RCVBUF retrieved","",i);
return 1;
} else if (i != size) {
j = size;
if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&j, sizeof(j))) {
debug(F111,"TCP recvbuf can't set SO_RCVBUF",ck_errstr(),errno);
tcp_recvbuf = i;
} else {
debug(F101,"TCP recvbuf old SO_RCVBUF","",i);
debug(F101,"TCP recvbuf new SO_RCVBUF","",j);
tcp_recvbuf = size;
return 1;
}
} else {
debug(F101,"TCP recvbuf SO_RCVBUF unchanged","",i);
tcp_recvbuf = size;
return 1;
}
#else
debug(F100,"TCP recvbuf SO_RCVBUF not defined","",0);
#endif /* SO_RCVBUF */
#else
debug(F100,"TCP recvbuf SO_SOCKET not defined","",0);
#endif /* SOL_SOCKET */
return 0;
}
int
keepalive(sock,onoff) int sock; int onoff; {
#ifdef SOL_SOCKET
#ifdef SO_KEEPALIVE
int get_keepalive_opt;
int set_keepalive_opt;
SOCKOPT_T x;
debug(F111,"TCP keepalive","sock",sock);
debug(F111,"TCP keepalive","nettype",nettype);
debug(F111,"TCP keepalive","ttmdm",ttmdm);
#ifdef IKSD
if (!inserver)
#endif /* IKSD */
if (sock == -1 ||
nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH
|| ttmdm >= 0) {
tcp_keepalive = onoff;
return 1;
}
x = sizeof(get_keepalive_opt);
if (getsockopt(sock,
SOL_SOCKET, SO_KEEPALIVE, (char *)&get_keepalive_opt, &x)) {
debug(F111,"TCP keepalive can't get SO_KEEPALIVE",ck_errstr(),errno);
} else if (x != sizeof(get_keepalive_opt)) {
#ifdef OS2
short get_keepalive_opt16;
short set_keepalive_opt16;
if (x == sizeof(get_keepalive_opt16)) {
debug(F111,"TCP keepalive warning: SO_KEEPALIVE",
"len is 16-bit",x);
if (getsockopt(sock,
SOL_SOCKET, SO_KEEPALIVE,
(char *)&get_keepalive_opt16, &x)
) {
debug(F111,
"TCP keepalive can't get SO_KEEPALIVE",
ck_errstr(),
errno
);
} else if (get_keepalive_opt16 != onoff) {
set_keepalive_opt16 = onoff;
if (setsockopt(sock,
SOL_SOCKET,
SO_KEEPALIVE,
(char *)&set_keepalive_opt16,
sizeof(set_keepalive_opt16))
) {
debug(F111,
"TCP keepalive can't clear SO_KEEPALIVE",
ck_errstr(),
errno
);
tcp_keepalive = get_keepalive_opt16;
} else {
debug(F101,
"TCP keepalive new SO_KEEPALIVE","",
set_keepalive_opt16);
tcp_keepalive = set_keepalive_opt16;
return 1;
}
} else {
debug(F101,"TCP keepalive SO_KEEPALIVE unchanged","",
get_keepalive_opt16);
tcp_keepalive = onoff;
return 1;
}
return(0);
}
#endif /* OS2 */
debug(F111,"TCP keepalive error: SO_KEEPALIVE","len",x);
debug(F111,
"TCP keepalive SO_KEEPALIVE",
"expected len",
sizeof(get_keepalive_opt)
);
debug(F111,
"TCP keepalive SO_KEEPALIVE",
"keepalive_opt",
get_keepalive_opt
);
} else if (get_keepalive_opt != onoff) {
set_keepalive_opt = onoff;
if (setsockopt(sock,
SOL_SOCKET,
SO_KEEPALIVE,
(char *)&set_keepalive_opt,
sizeof(set_keepalive_opt))
) {
debug(F111,
"TCP keepalive can't clear SO_KEEPALIVE",
ck_errstr(),
errno
);
tcp_keepalive = get_keepalive_opt;
} else {
debug(F101,
"TCP keepalive new SO_KEEPALIVE",
"",
set_keepalive_opt
);
tcp_keepalive = onoff;
return 1;
}
} else {
debug(F101,"TCP keepalive SO_KEEPALIVE unchanged",
"",
get_keepalive_opt
);
tcp_keepalive = onoff;
return 1;
}
#else
debug(F100,"TCP keepalive SO_KEEPALIVE not defined","",0);
#endif /* SO_KEEPALIVE */
#else
debug(F100,"TCP keepalive SO_SOCKET not defined","",0);
#endif /* SOL_SOCKET */
return(0);
}
int
dontroute(sock,onoff) int sock; int onoff; {
#ifdef SOL_SOCKET
#ifdef SO_DONTROUTE
int get_dontroute_opt;
int set_dontroute_opt;
SOCKOPT_T x;
#ifdef IKSD
if (!inserver)
#endif /* IKSD */
if (sock == -1 ||
nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH
|| ttmdm >= 0) {
tcp_dontroute = onoff;
return 1;
}
x = sizeof(get_dontroute_opt);
if (getsockopt(sock,
SOL_SOCKET, SO_DONTROUTE, (char *)&get_dontroute_opt, &x)) {
debug(F111,"TCP dontroute can't get SO_DONTROUTE",ck_errstr(),errno);
} else if (x != sizeof(get_dontroute_opt)) {
#ifdef OS2
short get_dontroute_opt16;
short set_dontroute_opt16;
if (x == sizeof(get_dontroute_opt16)) {
debug(F111,"TCP dontroute warning: SO_DONTROUTE",
"len is 16-bit",x);
if (getsockopt(sock,
SOL_SOCKET, SO_DONTROUTE,
(char *)&get_dontroute_opt16, &x)
) {
debug(F111,
"TCP dontroute can't get SO_DONTROUTE",
ck_errstr(),
errno
);
} else if (get_dontroute_opt16 != onoff) {
set_dontroute_opt16 = onoff;
if (setsockopt(sock,
SOL_SOCKET,
SO_DONTROUTE,
(char *)&set_dontroute_opt16,
sizeof(set_dontroute_opt16))
) {
debug(F111,
"TCP dontroute can't clear SO_DONTROUTE",
ck_errstr(),
errno
);
tcp_dontroute = get_dontroute_opt16;
} else {
debug(F101,
"TCP dontroute new SO_DONTROUTE","",
set_dontroute_opt16);
tcp_dontroute = set_dontroute_opt16;
return 1;
}
} else {
debug(F101,"TCP dontroute SO_DONTROUTE unchanged","",
get_dontroute_opt16);
tcp_dontroute = onoff;
return 1;
}
return(0);
}
#endif /* OS2 */
debug(F111,"TCP dontroute error: SO_DONTROUTE","len",x);
debug(F111,
"TCP dontroute SO_DONTROUTE",
"expected len",
sizeof(get_dontroute_opt)
);
debug(F111,
"TCP dontroute SO_DONTROUTE",
"dontroute_opt",
get_dontroute_opt
);
} else if (get_dontroute_opt != onoff) {
set_dontroute_opt = onoff;
if (setsockopt(sock,
SOL_SOCKET,
SO_DONTROUTE,
(char *)&set_dontroute_opt,
sizeof(set_dontroute_opt))
) {
debug(F111,
"TCP dontroute can't clear SO_DONTROUTE",
ck_errstr(),
errno
);
tcp_dontroute = get_dontroute_opt;
} else {
debug(F101,
"TCP dontroute new SO_DONTROUTE",
"",
set_dontroute_opt
);
tcp_dontroute = onoff;
return 1;
}
} else {
debug(F101,"TCP dontroute SO_DONTROUTE unchanged",
"",
get_dontroute_opt
);
tcp_dontroute = onoff;
return 1;
}
#else
debug(F100,"TCP dontroute SO_DONTROUTE not defined","",0);
#endif /* SO_DONTROUTE */
#else
debug(F100,"TCP dontroute SO_SOCKET not defined","",0);
#endif /* SOL_SOCKET */
return(0);
}
int
no_delay(sock,onoff) int sock; int onoff; {
#ifdef SOL_SOCKET
#ifdef TCP_NODELAY
int get_nodelay_opt;
int set_nodelay_opt;
SOCKOPT_T x;
#ifdef IKSD
if (!inserver)
#endif /* IKSD */
if (sock == -1 ||
nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH
|| ttmdm >= 0) {
tcp_nodelay = onoff;
return(1);
}
x = sizeof(get_nodelay_opt);
if (getsockopt(sock,IPPROTO_TCP,TCP_NODELAY,
(char *)&get_nodelay_opt,&x)) {
debug(F111,
"TCP no_delay can't get TCP_NODELAY",
ck_errstr(),
errno);
} else if (x != sizeof(get_nodelay_opt)) {
#ifdef OS2
short get_nodelay_opt16;
short set_nodelay_opt16;
if (x == sizeof(get_nodelay_opt16)) {
debug(F111,"TCP no_delay warning: TCP_NODELAY","len is 16-bit",x);
if (getsockopt(sock,
IPPROTO_TCP, TCP_NODELAY,
(char *)&get_nodelay_opt16, &x)
) {
debug(F111,
"TCP no_delay can't get TCP_NODELAY",
ck_errstr(),
errno);
} else if (get_nodelay_opt16 != onoff) {
set_nodelay_opt16 = onoff;
if (setsockopt(sock,
IPPROTO_TCP,
TCP_NODELAY,
(char *)&set_nodelay_opt16,
sizeof(set_nodelay_opt16))
) {
debug(F111,
"TCP no_delay can't clear TCP_NODELAY",
ck_errstr(),
errno);
tcp_nodelay = get_nodelay_opt16;
} else {
debug(F101,
"TCP no_delay new TCP_NODELAY",
"",
set_nodelay_opt16);
tcp_nodelay = onoff;
return 1;
}
} else {
debug(F101,"TCP no_delay TCP_NODELAY unchanged","",
get_nodelay_opt16);
tcp_nodelay = onoff;
return 1;
}
return(0);
}
#endif /* OS2 */
debug(F111,"TCP no_delay error: TCP_NODELAY","len",x);
debug(F111,"TCP no_delay TCP_NODELAY","expected len",
sizeof(get_nodelay_opt));
debug(F111,"TCP no_delay TCP_NODELAY","nodelay_opt",get_nodelay_opt);
} else if (get_nodelay_opt != onoff) {
set_nodelay_opt = onoff;
if (setsockopt(sock,
IPPROTO_TCP,
TCP_NODELAY,
(char *)&set_nodelay_opt,
sizeof(set_nodelay_opt))) {
debug(F111,
"TCP no_delay can't clear TCP_NODELAY",
ck_errstr(),
errno
);
tcp_nodelay = get_nodelay_opt;
} else {
debug(F101,"TCP no_delay new TCP_NODELAY","",set_nodelay_opt);
tcp_nodelay = onoff;
return 1;
}
} else {
debug(F101,"TCP no_delay TCP_NODELAY unchanged","",get_nodelay_opt);
tcp_nodelay = onoff;
return(1);
}
#else
debug(F100,"TCP no_delay TCP_NODELAY not defined","",0);
#endif /* TCP_NODELAY */
#else
debug(F100,"TCP no_delay SO_SOCKET not defined","",0);
#endif /* SOL_SOCKET */
return 0;
}
#endif /* datageneral */
#endif /* NOTCPOPTS */
#ifdef SUNX25
#ifndef X25_WR_FACILITY
/* For Solaris 2.3 / SunLink 8.x - see comments in ckcnet.h */
void
bzero(s,n) char *s; int n; {
memset(s,0,n);
}
#endif /* X25_WR_FACILITY */
#endif /* SUNX25 */
#ifdef TCPSOCKET
#ifndef OS2
#ifndef NOLISTEN
#ifdef BSDSELECT
#ifndef VMS
#ifndef BELLV10
#ifndef datageneral
#ifdef hp9000s500 /* HP-9000/500 HP-U 5.21 */
#include <time.h>
#else
/****** THIS SECTION ADDED BY STEVE RANCE - OS9 NETWORK SERVER
* ------------------------------------------------------
*
* Due to OS9's Lack of a select() call, the following seems to be
* enough to fool the rest of the code into compiling. The only
* effect that I can see is using control L to refresh the status
* display gets qued up until some network packets arrive.
*
* This solution is by no means elegant but works enough to be
* a (the) solution.
*
* Also with the defines I had specified in my makefile I had to
* have an #endif right at the end of the file when compiling.
* I did not bother speding time to find out why.
*
* COPTS = -to=osk -d=OSK -d=TCPSOCKET -d=SELECT -d=VOID=void -d=SIG_V \
* -d=DYNAMIC -d=PARSENSE -d=KANJI -d=MYCURSES -d=ZFCDAT \
* -d=CK_APC -d=CK_REDIR -d=RENAME -d=CK_TTYFD -d=NOOLDMODEMS \
* -d=CK_ANSIC -d=CK_XYZ -tp=68040d -l=netdb.l -l=socklib.l \
* -l=termlib.l -l=math.l -l=sys_clib.l
*
* stever@ozemail.com.au
*/
#ifdef OSK
#define BSDSELECT /* switch on BSD select code */
#define FD_SETSIZE 32 /* Max # of paths in OS9 */
#define FD_ZERO(p) ((*p)=0)
#define FD_SET(n,b) ((*b)|=(1<<(n)))
#define FD_ISSET(n,b) 1 /* always say data is ready */
#define select(a,b,c,d,e) 1 /* always say 1 path has data */
typedef int fd_set; /* keep BSD Code Happy */
struct timeval {int tv_sec,tv_usec;}; /* keep BSD Code Happy */
/****** END OF OS9 MODS FROM STEVE RANCE **************************/
#endif /* OSK */
#include <sys/time.h>
#endif /* hp9000s500 */
#endif /* datageneral */
#endif /* BELLV10 */
#endif /* VMS */
#ifdef SELECT_H
#include <sys/select.h>
#endif /* SELECT_H */
#endif /* BSDSELECT */
#ifdef SELECT
#ifdef CK_SCOV5
#include <sys/select.h>
#endif /* CK_SCOV5 */
#endif /* SELECT */
#ifdef NOTUSED
/* T C P S O C K E T _ O P E N -- Open a preexisting socket number */
int
tcpsocket_open(name,lcl,nett,timo) char * name; int * lcl; int nett; int timo {
int on = 1;
static struct servent *service, servrec;
static struct hostent *host;
static struct sockaddr_in saddr;
static
#ifdef UCX50
unsigned
#endif /* UCX50 */
int saddrlen;
#ifdef BSDSELECT
fd_set rfds;
struct timeval tv;
#else
#ifdef BELLSELECT
fd_set rfds;
#else
fd_set rfds;
fd_set rfds;
struct timeval {
long tv_sec;
long tv_usec;
} tv;
#endif /* BELLSELECT */
#endif /* BSDSELECT */
debug(F101,"tcpsocket_open nett","",nett);
*ipaddr = '\0';
if (nett != NET_TCPB)
return(-1); /* BSD socket support */
netclos(); /* Close any previous connection. */
ckstrncpy(namecopy, name, NAMECPYL); /* Copy the hostname. */
if (ttnproto != NP_TCPRAW)
ttnproto = NP_NONE; /* No protocol selected yet. */
debug(F110,"tcpsocket_open namecopy",namecopy,0);
/* Assign the socket number to ttyfd and then fill in tcp structures */
ttyfd = atoi(&name[1]);
debug(F111,"tcpsocket_open","ttyfd",ttyfd);
#ifndef NOTCPOPTS
#ifdef SOL_SOCKET
setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
#ifndef datageneral
#ifdef TCP_NODELAY
no_delay(ttyfd,tcp_nodelay);
#endif /* TCP_NODELAY */
#ifdef SO_KEEPALIVE
keepalive(ttyfd,tcp_keepalive);
#endif /* SO_KEEPALIVE */
#ifdef SO_LINGER
ck_linger(ttyfd,tcp_linger, tcp_linger_tmo);
#endif /* SO_LINGER */
#ifdef SO_SNDBUF
sendbuf(ttyfd,tcp_sendbuf);
#endif /* SO_SNDBUF */
#ifdef SO_RCVBUF
recvbuf(ttyfd,tcp_recvbuf);
#endif /* SO_RCVBUF */
#endif /* datageneral */
#endif /* SOL_SOCKET */
#endif /* NOTCPOPTS */
#ifdef NT_TCP_OVERLAPPED
OverlappedWriteInit();
OverlappedReadInit();
#endif /* NT_TCP_OVERLAPPED */
/* Get the name of the host we are connected to */
saddrlen = sizeof(saddr);
getpeername(ttyfd,(struct sockaddr *)&saddr,&saddrlen);
ckstrncpy(ipaddr,(char *)inet_ntoa(saddr.sin_addr),20);
if (tcp_rdns == SET_ON
#ifdef CK_KERBEROS
|| tcp_rdns == SET_AUTO &&
(ck_krb5_is_installed() || ck_krb4_is_installed())
#endif /* CK_KERBEROS */
#ifndef NOHTTP
&& (tcp_http_proxy == NULL)
#endif /* NOHTTP */
#ifdef CK_SSL
&& !(ssl_only_flag || tls_only_flag)
#endif /* CK_SSL */
) { /* Reverse DNS */
if (!quiet) {
printf(" Reverse DNS Lookup... ");
fflush(stdout);
}
host = gethostbyaddr((char *)&saddr.sin_addr,4,PF_INET);
debug(F110,"tcpsocket_open gethostbyaddr",host ? "OK" : "FAILED",0);
if (host) {
host = ck_copyhostent(host);
debug(F100,"tcpsocket_open gethostbyaddr != NULL","",0);
if (!quiet) {
printf("(OK)\n");
fflush(stdout);
}
ckstrncpy(name, host->h_name, 80);
ckstrncat(name, ":", 80);
ckstrncat(name,ckuitoa(ntohs(saddr.sin_port)), 80);
if (!quiet
#ifndef NOICP
&& !doconx
#endif /* NOICP */
)
printf("%s connected on port %d\n",
host->h_name,
ntohs(saddr.sin_port)
);
} else if (!quiet)
printf("Failed\n");
} else if (!quiet)
printf("(OK)\n");
if (tcp_rdns != SET_ON || !host) {
ckstrncpy(name,ipaddr,80);
ckstrncat(name,":",80);
ckstrncat(name,ckuitoa(ntohs(saddr.sin_port)),80);
if (!quiet
#ifdef NOICP
&& !doconx
#endif /* NOICP */
)
printf("%s connected on port %d\n",ipaddr,ntohs(saddr.sin_port));
}
if (!quiet) fflush(stdout);
ttnet = nett; /* TCP/IP (sockets) network */
#ifdef RLOGCODE
if (ntohs(saddr.sin_port) == 513)
ttnproto = NP_LOGIN;
else
#endif /* RLOGCODE */
/* Assume the service is TELNET. */
if (ttnproto != NP_TCPRAW)
ttnproto = NP_TELNET; /* Yes, set global flag. */
#ifdef CK_SECURITY
/* Before Initialization Telnet/Rlogin Negotiations Init Kerberos */
ck_auth_init((tcp_rdns && host && host->h_name && host->h_name[0]) ?
host->h_name : ipaddr,
ipaddr,
uidbuf,
ttyfd
);
#endif /* CK_SECURITY */
if (tn_ini() < 0) /* Start/Reset TELNET negotiations */
if (ttchk() < 0) /* Did it fail due to connect loss? */
return(-1);
if (*lcl < 0) *lcl = 1; /* Local mode. */
return(0); /* Done. */
}
#endif /* NOTUSED */
/* T C P S R V _ O P E N -- Open a TCP/IP Server connection */
/*
Calling conventions same as ttopen(), except third argument is network
type rather than modem type.
*/
int
tcpsrv_open(name,lcl,nett,timo) char * name; int * lcl; int nett; int timo; {
char *p;
int i, x;
SOCKOPT_T on = 1;
int ready_to_accept = 0;
static struct servent *service, *service2, servrec;
static struct hostent *host;
static struct sockaddr_in saddr;
struct sockaddr_in l_addr;
GSOCKNAME_T l_slen;
#ifdef UCX50
static u_int saddrlen;
#else
static SOCKOPT_T saddrlen;
#endif /* UCX50 */
#ifdef BSDSELECT
fd_set rfds;
struct timeval tv;
#else
#ifdef BELLSELCT
fd_set rfds;
#else
fd_set rfds;
struct timeval {
long tv_sec;
long tv_usec;
} tv;
#endif /* BELLSELECT */
#endif /* BSDSELECT */
#ifdef CK_SSL
int ssl_failed = 0;
#endif /* CK_SSL */
debug(F101,"tcpsrv_open nett","",nett);
*ipaddr = '\0';
if (nett != NET_TCPB)
return(-1); /* BSD socket support */
netclos(); /* Close any previous connection. */
ckstrncpy(namecopy, name, NAMECPYL); /* Copy the hostname. */
#ifdef COMMENT
/* Don't do this. */
if (ttnproto != NP_TCPRAW)
ttnproto = NP_NONE; /* No protocol selected yet. */
#endif /* COMMENT */
debug(F110,"tcpsrv_open namecopy",namecopy,0);
p = namecopy; /* Was a service requested? */
while (*p != '\0' && *p != ':')
p++; /* Look for colon */
if (*p == ':') { /* Have a colon */
*p++ = '\0'; /* Get service name or number */
} else { /* Otherwise use kermit */
p = "kermit";
}
debug(F110,"tcpsrv_open service requested",p,0);
if (isdigit(*p)) { /* Use socket number without lookup */
service = &servrec;
service->s_port = htons((unsigned short)atoi(p));
} else { /* Otherwise lookup the service name */
service = getservbyname(p, "tcp");
}
if (!service && !strcmp("kermit",p)) { /* Use Kermit service port */
service = &servrec;
service->s_port = htons(1649);
}
#ifdef RLOGCODE
if (service && !strcmp("login",p) && service->s_port != htons(513)) {
fprintf(stderr,
" Warning: login service on port %d instead of port 513\n",
ntohs(service->s_port));
fprintf(stderr, " Edit SERVICES file if RLOGIN fails to connect.\n");
debug(F101,"tcpsrv_open login on port","",ntohs(service->s_port));
}
#endif /* RLOGCODE */
if (!service) {
fprintf(stderr, "Cannot find port for service: %s\n", p);
debug(F111,"tcpsrv_open can't get service",p,errno);
errno = 0; /* rather than mislead */
return(-1);
}
/* If we currently have a listen active but port has changed then close */
debug(F101,"tcpsrv_open checking previous connection","",tcpsrfd);
debug(F101,"tcpsrv_open previous tcpsrv_port","",tcpsrv_port);
if (tcpsrfd != -1 &&
tcpsrv_port != ntohs((unsigned short)service->s_port)) {
debug(F100,"tcpsrv_open closing previous connection","",0);
#ifdef TCPIPLIB
socket_close(tcpsrfd);
#else
close(tcpsrfd);
#endif /* TCPIPLIB */
tcpsrfd = -1;
}
debug(F100,"tcpsrv_open tcpsrfd","",tcpsrfd);
if (tcpsrfd == -1) {
/* Set up socket structure and get host address */
bzero((char *)&saddr, sizeof(saddr));
debug(F100,"tcpsrv_open bzero ok","",0);
saddr.sin_family = AF_INET;
if (tcp_address) {
#ifdef INADDRX
inaddrx = inet_addr(tcp_address);
saddr.sin_addr.s_addr = *(unsigned long *)&inaddrx;
#else
saddr.sin_addr.s_addr = inet_addr(tcp_address);
#endif /* INADDRX */
} else
saddr.sin_addr.s_addr = INADDR_ANY;
/* Get a file descriptor for the connection. */
saddr.sin_port = service->s_port;
ipaddr[0] = '\0';
debug(F100,"tcpsrv_open calling socket","",0);
if ((tcpsrfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("TCP socket error");
debug(F101,"tcpsrv_open socket error","",errno);
return (-1);
}
errno = 0;
/* Specify the Port may be reused */
debug(F100,"tcpsrv_open calling setsockopt","",0);
x = setsockopt(tcpsrfd,
SOL_SOCKET,SO_REUSEADDR,(char *)&on,sizeof on);
debug(F101,"tcpsrv_open setsockopt","",x);
/* Now bind to the socket */
printf("\nBinding socket to port %d ...\n",
ntohs((unsigned short)service->s_port));
if (bind(tcpsrfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
i = errno; /* Save error code */
#ifdef TCPIPLIB
socket_close(tcpsrfd);
#else /* TCPIPLIB */
close(tcpsrfd);
#endif /* TCPIPLIB */
tcpsrfd = -1;
tcpsrv_port = 0;
ttyfd = -1;
wasclosed = 1;
errno = i; /* and report this error */
debug(F101,"tcpsrv_open bind errno","",errno);
printf("?Unable to bind to socket (errno = %d)\n",errno);
return(-1);
}
debug(F100,"tcpsrv_open bind OK","",0);
printf("Listening ...\n");
if (listen(tcpsrfd, 15) < 0) {
i = errno; /* Save error code */
#ifdef TCPIPLIB
socket_close(tcpsrfd);
#else /* TCPIPLIB */
close(tcpsrfd);
#endif /* TCPIPLIB */
tcpsrfd = -1;
tcpsrv_port = 0;
ttyfd = -1;
wasclosed = 1;
errno = i; /* And report this error */
debug(F101,"tcpsrv_open listen errno","",errno);
return(-1);
}
debug(F100,"tcpsrv_open listen OK","",0);
tcpsrv_port = ntohs((unsigned short)service->s_port);
}
#ifdef CK_SSL
if (ck_ssleay_is_installed()) {
if (!ssl_tn_init(SSL_SERVER)) {
ssl_failed = 1;
if (bio_err!=NULL) {
BIO_printf(bio_err,"do_ssleay_init() failed\n");
ERR_print_errors(bio_err);
} else {
fflush(stderr);
fprintf(stderr,"do_ssleay_init() failed\n");
ERR_print_errors_fp(stderr);
}
if (tls_only_flag || ssl_only_flag) {
#ifdef TCPIPLIB
socket_close(ttyfd);
socket_close(tcpsrfd);
#else /* TCPIPLIB */
close(ttyfd);
close(tcpsrfd);
#endif /* TCPIPLIB */
ttyfd = -1;
wasclosed = 1;
tcpsrfd = -1;
tcpsrv_port = 0;
return(-1);
}
/* we will continue to accept the connection */
/* without SSL or TLS support unless required. */
if ( TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) != TN_NG_MU )
TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
if ( TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) != TN_NG_MU )
TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
if ( TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) != TN_NG_MU )
TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
if ( TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) != TN_NG_MU )
TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
}
}
#endif /* CK_SSL */
printf("\nWaiting to Accept a TCP/IP connection on port %d ...\n",
ntohs((unsigned short)service->s_port));
saddrlen = sizeof(saddr);
#ifdef BSDSELECT
tv.tv_sec = tv.tv_usec = 0L;
if (timo < 0)
tv.tv_usec = (long) -timo * 10000L;
else
tv.tv_sec = timo;
debug(F101,"tcpsrv_open BSDSELECT"