| 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","",timo); |
| #else |
| debug(F101,"tcpsrv_open not BSDSELECT","",timo); |
| #endif /* BSDSELECT */ |
| |
| if (timo) { |
| while (!ready_to_accept) { |
| #ifdef BSDSELECT |
| FD_ZERO(&rfds); |
| FD_SET(tcpsrfd, &rfds); |
| ready_to_accept = |
| ((select(FD_SETSIZE, |
| #ifdef HPUX |
| #ifdef HPUX1010 |
| (fd_set *) |
| #else |
| |
| (int *) |
| #endif /* HPUX1010 */ |
| #else |
| #ifdef __DECC |
| (fd_set *) |
| #endif /* __DECC */ |
| #endif /* HPUX */ |
| &rfds, NULL, NULL, &tv) > 0) && |
| FD_ISSET(tcpsrfd, &rfds)); |
| #else /* BSDSELECT */ |
| #ifdef IBMSELECT |
| #define ck_sleepint 250 |
| ready_to_accept = |
| (select(&tcpsrfd, 1, 0, 0, |
| timo < 0 ? -timo : |
| (timo > 0 ? timo * 1000L : ck_sleepint)) == 1 |
| ); |
| #else |
| #ifdef BELLSELECT |
| FD_ZERO(rfds); |
| FD_SET(tcpsrfd, rfds); |
| ready_to_accept = |
| ((select(128, rfds, NULL, NULL, timo < 0 ? -timo : |
| (timo > 0 ? timo * 1000L)) > 0) && |
| FD_ISSET(tcpsrfd, rfds)); |
| #else |
| /* Try this - what's the worst that can happen... */ |
| |
| FD_ZERO(&rfds); |
| FD_SET(tcpsrfd, &rfds); |
| ready_to_accept = |
| ((select(FD_SETSIZE, |
| (fd_set *) &rfds, NULL, NULL, &tv) > 0) && |
| FD_ISSET(tcpsrfd, &rfds)); |
| |
| #endif /* BELLSELECT */ |
| #endif /* IBMSELECT */ |
| #endif /* BSDSELECT */ |
| } |
| } |
| if (ready_to_accept || timo == 0) { |
| if ((ttyfd = accept(tcpsrfd, |
| (struct sockaddr *)&saddr,&saddrlen)) < 0) { |
| i = errno; /* save error code */ |
| #ifdef TCPIPLIB |
| socket_close(tcpsrfd); |
| #else /* TCPIPLIB */ |
| close(tcpsrfd); |
| #endif /* TCPIPLIB */ |
| ttyfd = -1; |
| wasclosed = 1; |
| tcpsrfd = -1; |
| tcpsrv_port = 0; |
| errno = i; /* and report this error */ |
| debug(F101,"tcpsrv_open accept errno","",errno); |
| return(-1); |
| } |
| setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on); |
| |
| #ifndef NOTCPOPTS |
| #ifndef datageneral |
| #ifdef SOL_SOCKET |
| #ifdef TCP_NODELAY |
| no_delay(ttyfd,tcp_nodelay); |
| debug(F101,"tcpsrv_open no_delay","",tcp_nodelay); |
| #endif /* TCP_NODELAY */ |
| #ifdef SO_KEEPALIVE |
| keepalive(ttyfd,tcp_keepalive); |
| debug(F101,"tcpsrv_open keepalive","",tcp_keepalive); |
| #endif /* SO_KEEPALIVE */ |
| #ifdef SO_LINGER |
| ck_linger(ttyfd,tcp_linger, tcp_linger_tmo); |
| debug(F101,"tcpsrv_open 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 /* SOL_SOCKET */ |
| #endif /* datageneral */ |
| #endif /* NOTCPOPTS */ |
| |
| ttnet = nett; /* TCP/IP (sockets) network */ |
| tcp_incoming = 1; /* This is an incoming connection */ |
| sstelnet = 1; /* Do server-side Telnet protocol */ |
| |
| /* See if the service is TELNET. */ |
| x = (unsigned short)service->s_port; |
| service2 = getservbyname("telnet", "tcp"); |
| if (service2 && x == service2->s_port) { |
| if (ttnproto != NP_TCPRAW) /* Yes and if raw port not requested */ |
| ttnproto = NP_TELNET; /* Set protocol to TELNET. */ |
| } |
| |
| ckstrncpy(ipaddr,(char *)inet_ntoa(saddr.sin_addr),20); |
| if (tcp_rdns) { |
| if (!quiet) { |
| printf(" Reverse DNS Lookup... "); |
| fflush(stdout); |
| } |
| if (host = gethostbyaddr((char *)&saddr.sin_addr,4,PF_INET)) { |
| host = ck_copyhostent(host); |
| debug(F100,"tcpsrv_open gethostbyaddr != NULL","",0); |
| if (!quiet) { |
| printf("(OK)\n"); |
| fflush(stdout); |
| } |
| name[0] = '*'; |
| ckstrncpy(&name[1],host->h_name,78); |
| strncat(name,":",80-strlen(name)); |
| strncat(name,p,80-strlen(name)); |
| if (!quiet |
| #ifndef NOICP |
| && !doconx |
| #endif /* NOICP */ |
| ) |
| printf("%s connected on port %s\n",host->h_name,p); |
| } else { |
| if (!quiet) printf("Failed.\n"); |
| } |
| } else if (!quiet) printf("(OK)\n"); |
| |
| if (!tcp_rdns || !host) { |
| ckstrncpy(name,ipaddr,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",ipaddr,ntohs(saddr.sin_port)); |
| } |
| if (!quiet) fflush(stdout); |
| |
| #ifdef CK_SECURITY |
| /* Before Initialization Telnet/Rlogin Negotiations Init Kerberos */ |
| ck_auth_init((tcp_rdns && host && host->h_name && host->h_name[0]) ? |
| (char *)host->h_name : ipaddr, |
| ipaddr, |
| uidbuf, |
| ttyfd |
| ); |
| #endif /* CK_SECURITY */ |
| |
| #ifdef CK_SSL |
| if (ck_ssleay_is_installed() && !ssl_failed) { |
| if (ck_ssl_incoming(ttyfd) < 0) { |
| #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); |
| } |
| } |
| #endif /* CK_SSL */ |
| |
| #ifndef datageneral |
| /* Find out our own IP address. */ |
| l_slen = sizeof(l_addr); |
| bzero((char *)&l_addr, l_slen); |
| #ifndef EXCELAN |
| if (!getsockname(ttyfd, (struct sockaddr *)&l_addr, &l_slen)) { |
| char * s = (char *)inet_ntoa(l_addr.sin_addr); |
| ckstrncpy(myipaddr, s,20); |
| debug(F110,"getsockname",myipaddr,0); |
| } |
| #endif /* EXCELAN */ |
| #endif /* datageneral */ |
| |
| if (tn_ini() < 0) /* Start TELNET negotiations. */ |
| if (ttchk() < 0) { /* Disconnected? */ |
| i = errno; /* save error code */ |
| #ifdef TCPIPLIB |
| socket_close(tcpsrfd); |
| #else /* TCPIPLIB */ |
| close(tcpsrfd); |
| #endif /* TCPIPLIB */ |
| ttyfd = -1; |
| wasclosed = 1; |
| tcpsrfd = -1; |
| tcpsrv_port = 0; |
| errno = i; /* and report this error */ |
| debug(F101,"tcpsrv_open accept errno","",errno); |
| return(-1); |
| } |
| debug(F101,"tcpsrv_open service","",x); |
| if (*lcl < 0) /* Set local mode. */ |
| *lcl = 1; |
| |
| #ifdef CK_KERBEROS |
| #ifdef KRB5_U2U |
| if ( ttnproto == NP_K5U2U ) { |
| if (k5_user_to_user_server_auth() != 0) { |
| i = errno; /* save error code */ |
| #ifdef TCPIPLIB |
| socket_close(tcpsrfd); |
| #else /* TCPIPLIB */ |
| close(tcpsrfd); |
| #endif /* TCPIPLIB */ |
| ttyfd = -1; |
| wasclosed = 1; |
| tcpsrfd = -1; |
| tcpsrv_port = 0; |
| errno = i; /* and report this error */ |
| debug(F101,"tcpsrv_open accept errno","",errno); |
| return(-1); |
| } |
| } |
| #endif /* KRB5_U2U */ |
| #endif /* CK_KERBEROS */ |
| return(0); /* Done. */ |
| } else { |
| i = errno; /* save error code */ |
| #ifdef TCPIPLIB |
| socket_close(tcpsrfd); |
| #else /* TCPIPLIB */ |
| close(tcpsrfd); |
| #endif /* TCPIPLIB */ |
| ttyfd = -1; |
| wasclosed = 1; |
| tcpsrfd = -1; |
| tcpsrv_port = 0; |
| errno = i; /* and report this error */ |
| debug(F101,"tcpsrv_open accept errno","",errno); |
| return(-1); |
| } |
| } |
| #endif /* NOLISTEN */ |
| #endif /* OS2 */ |
| #endif /* TCPSOCKET */ |
| #endif /* NONET */ |
| |
| #ifdef TCPSOCKET |
| char * |
| ckname2addr(name) char * name; |
| { |
| #ifdef HPUX5 |
| return(""); |
| #else |
| struct hostent *host; |
| |
| if (name == NULL || *name == '\0') |
| return(""); |
| |
| host = gethostbyname(name); |
| if ( host ) { |
| host = ck_copyhostent(host); |
| return(inet_ntoa(*((struct in_addr *) host->h_addr))); |
| } |
| return(""); |
| #endif /* HPUX5 */ |
| } |
| |
| char * |
| ckaddr2name(addr) char * addr; |
| { |
| #ifdef HPUX5 |
| return(""); |
| #else |
| struct hostent *host; |
| struct in_addr sin_addr; |
| |
| if (addr == NULL || *addr == '\0') |
| return(""); |
| |
| sin_addr.s_addr = inet_addr(addr); |
| host = gethostbyaddr((char *)&sin_addr,4,AF_INET); |
| if (host) { |
| host = ck_copyhostent(host); |
| return((char *)host->h_name); |
| } |
| return(""); |
| #endif /* HPUX5 */ |
| } |
| #endif /* TCPSOCKET */ |
| |
|