#include "ckcsym.h" char *cknetv = "Stratus VOS Network Support, 7.0.010, 18 Oct 1999"; /* C K L N E T -- Network support */ /* Authors: Frank da Cruz (fdc@columbia.edu, FDCCU@CUVMA.BITNET), Columbia University Center for Computing Activities. 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, Moravian College . TELNET protocol by Frank da Cruz. 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. SunLink X.25 support by Marcello Frutig, Catholic University, Rio de Janeiro, Brazil (frutig@rnp.impa.br) with fixes from Stefaan Eeckels, Eurokom, Luxembourg. Most non-BSD sockets code removed, converted for Stratus VOS, renamed to cklnet.c by David R. Lane, SoftCom Systems, Inc. Other contributions as indicated below. Copyright (C) 1985, 2000, 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. */ #include "ckcdeb.h" #include "ckcker.h" #include "ckcnet.h" #ifdef NETCONN /* Don't need these if there is no network support. */ #include #include #include #include /* only need these includes if using OS TCP/IP */ #ifdef TCPSOCKET #include #include #ifdef CK_SOCKS /* SOCKS Internet relay package */ #define accept Raccept #define bind Rbind #define connect Rconnect #define getsockname Rgetsockname #define listen Rlisten #endif /* CK_SOCKS */ #endif /* TCPSOCKET */ /* only need these for X.25 support */ #ifdef STRATUSX25 _PROTOTYP( extern VOID s$read_event, (long *event_id, long *event_count, short *event_status, short *status) ); _PROTOTYP( extern VOID s$vc_call_full, (CV(32) *gateway, CV(15) *address, CV(63) *facilities, CV(128) *call_data, void *opts, long *timeout, short *vcid, long *event_id, short *status) ); _PROTOTYP( extern VOID s$vc_call_full_sts, (CV(66) *destination, short *extension, CV(63) *facilities, CV(128) *call_data, void *opts, long *timeout, short *vcid, long *event_id, short *status) ); _PROTOTYP( extern VOID s$vc_clear, (short *vcid, short *diag, short *status) ); _PROTOTYP( extern VOID s$vc_recv_packet, (short *vcid, short *buff_len, void *buff, short *packet_size, short *level, short *more, short *status) ); _PROTOTYP( extern VOID s$vc_recv_interrupt, (short *vcid, char *data, short *status) ); _PROTOTYP( extern VOID s$vc_reset, (short *vcid, short *diag, short *status) ); _PROTOTYP( extern VOID s$vc_send_interrupt, (short *vcid, char *data, short *status) ); _PROTOTYP( extern VOID s$vc_send_packet, (short *vcid, short *buff_len, void *buff, short *level, short *more, short *status) ); _PROTOTYP( extern VOID s$vc_set_no_wait_mode, (void) ); _PROTOTYP( extern VOID s$vc_set_wait_mode, (void) ); _PROTOTYP( extern VOID s$vc_status, (short *vcid, short *diag_code, short *status) ); extern int linkid, lcn, x25ver; extern int revcall, closgr, cudata; extern CHAR udata[MAXCUDATA]; extern CHAR padparms[MAXPADPARMS+1]; static long vcid_event; /* have to save this from open */ static short x25qbit; /* qbit out flag */ #endif /* STRATUSX25 */ static int netnowait; extern SIGTYP (*saval)(); /* For saving alarm handler */ _PROTOTYP( VOID bgchk, (void) ); int tcp_rdns = SET_OFF; /* Not working yet for VOS */ /* These only go with TCP/IP */ #ifdef TCPSOCKET #ifdef RLOGCODE #ifdef TCPIPLIB _PROTOTYP( static VOID rlog_oob, (CHAR *, int) ); #else /* TCPIPLIB */ _PROTOTYP( static SIGTYP rlogoobh, ( int ) ); #endif /* TCPIPLIB */ _PROTOTYP( static int rlog_ini, (VOID) ); int rlog_mode = RL_COOKED; int rlog_stopped = 0; #endif /* RLOGCODE */ #endif /* TCPSOCKET */ _PROTOTYP( long congspd, (void) ); /* returns speed of console device */ extern int /* External variables */ duplex, debses, seslog, sessft, wasclosed, ttyfd, quiet, msgflg, what, nettype, ttmdm; #define NAMECPYL 100 /* Local copy of hostname */ char namecopy[NAMECPYL]; /* Referenced by ckctel.c */ char ipaddr[20] = { '\0' }; /* Global copy of IP address */ char myipaddr[20] = { '\0' }; /* Global copy of my IP address */ #endif /* NETCONN */ int ttnet = NET_NONE; /* Network type */ int ttnproto = NP_NONE; /* Network virtual terminal protocol */ /* 0 = don't lowercase username for Rlogin/Telnet protocol */ /* nonzero = do lowercase it. Add a SET command if necessary... */ int ck_lcname = 0; int tcp_incoming = 0; /* Incoming connection? */ extern int sstelnet; /* Server side telnet? */ #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 SO_SNDBUF int tcp_sendbuf = -1; #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 (rest of this module...) */ #ifdef TCPSOCKET int tcpsrfd = -1; #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 */ static char svcbuf[80]; /* TCP service string */ static int svcnum = 0; /* TCP port number */ #endif /* TCPSOCKET */ /* For buffered network reads... */ #define TTXBUFL 1024 /* Maybe 8K?... */ extern CHAR ttxbuf[TTXBUFL+1]; extern int ttxbp, ttxbn = 0; /* Read bytes from network into internal buffer ttxbuf[], the same buffer that is used by ttbufr routine in ASYNC terminal io. To be called when input buffer is empty, i.e. when ttxbn == 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 ttxbn to that number and ttxbp (the buffer pointer) to zero. */ int netbufr(int timo) { /* TT Buffer Read */ int count; short status; if (ttnet != NET_TCPB && /* First make sure current net is */ ttnet != NET_VX25) { /* supported (VOS X.25 & OS TCP/IP) */ return(-1); /* if not, do nothing. */ } if (ttxbn > 0) /* Out internal buffer is not empty, */ return(ttxbn); /* so keep using it. */ count = nettchk(); /* Check network input buffer, */ if (ttxbn > 0) return(ttxbn); /* which can put a char there! */ if (count < 0) /* Read error */ return(-1); else if (count > TTXBUFL) /* Too many to read */ count = TTXBUFL; else if (count == 0) /* None, so read */ count = 1; debug(F101,"netbufr count 1","",count); #ifdef TCPSOCKET if (ttnet == NET_TCPB) { /* This is for nonblocking reads */ if ((count = net_read(ttyfd,ttxbuf,count,0)) < 1) { if (count == -1 && errno == e$caller_must_wait) { debug(F100,"netbufr finds nothing","",0); return(0); } else if (count == 0) { debug(F100,"netbufr socket eof","",0); return(-2); /* this is really a disconnect */ } else { debug(F101,"netbufr net_read error","",errno); return(-2); /* say it's disconnected */ } } } #endif /* TCPSOCKET */ #ifdef STRATUSX25 if (ttnet == NET_VX25) { count = x25xin(sizeof(ttxbuf), ttxbuf); if (count <= 0) return count; } #endif /* STRATUSX25 */ ttxbp = 0; /* Reset buffer pointer. */ ttxbn = count; #ifdef DEBUG debug(F101,"netbufr count 2","",count); /* Got some bytes. */ if (count > 0) ttxbuf[count] = '\0'; debug(F111,"netbufr ttxbuf",ttxbuf,ttxbp); #endif /* DEBUG */ return(ttxbn); /* Return buffer count. */ } /* C-Kermit network open/close functions for OS TCP/IP & X.25/X.29 Networking. */ /* N E T O P E N -- Open a network connection. */ /* Returns 0 on success, -1 on failure. */ #ifdef TCPSOCKET #define TELNET_PORT 23 /* Should do lookup, but it won't change */ #define RLOGIN_PORT 513 #define KERMIT_PORT 1649 #endif /* TCPSOCKET */ #ifndef NOTCPOPTS int ck_linger(onoff, timo) 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 debug(F100,"TCP ck_linger dummy version", "", 0); #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(size) 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 #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(size) 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 debug(F100,"TCP recvbuf dummy version","",0); #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(onoff) int onoff; { #ifdef SOL_SOCKET #ifdef SO_KEEPALIVE debug(F100,"TCP keepalive dummy version","",0); #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(onoff) int onoff; { #ifdef SOL_SOCKET #ifdef SO_DONTROUTE debug(F100,"TCP dontroute dummy version","",0); #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(onoff) int onoff; { #ifdef SOL_SOCKET #ifdef TCP_NODELAY debug(F100,"TCP no_delay dummy version","",0); #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 /* NOTCPOPTS */ char * ckgetpeer() { #ifdef TCPSOCKET static struct hostent *host; static struct sockaddr_in saddr; #ifdef PTX static size_t saddrlen; #else #ifdef AIX42 /* It's size_t in 4.2 but int in 4.1 and earlier. */ /* Note: the 4.2 man page lies; believe socket.h. */ static size_t saddrlen; #else #ifdef UNIXWARE static size_t saddrlen; #else /* UNIXWARE */ #ifdef VMS static unsigned int saddrlen; #else static int saddrlen; #endif /* VMS */ #endif /* UNIXWARE */ #endif /* AIX42 */ #endif /* PTX */ saddrlen = sizeof(saddr); if (getpeername(ttyfd,(struct sockaddr *)&saddr,&saddrlen) < 0) return(NULL); host = gethostbyaddr((char *)&saddr.sin_addr,4,AF_INET); return((char *)host->h_name); #else return(NULL); #endif /* TCPSOCKET */ } /* N E T O P E N -- Open a network connection */ /* Calling conventions same as ttopen(), except third argument is network type rather than modem type. Designed to be called from within ttopen. */ int netopen(name, lcl, nett) char *name; int *lcl, nett; { char *p = NULL; #ifdef SO_OOBINLINE int on = 1; #endif /* SO_OOBINLINE */ int i=0, x=0, dns=0;; #ifdef TCPSOCKET struct servent *service=NULL, servrec; struct hostent *host=NULL; struct sockaddr_in saddr; extern CHAR uidbuf[]; #endif /* TCPSOCKET */ #ifdef STRATUSX25 CV(66) destination; CV(15) address; CV(63) facilities; CV(128) call_data; long x25_timeout; short vcid; short status; struct { short version; short max_delay; short send_size; short recv_size; } x25_options; short sts_extension; #endif /* STRATUSX25 */ debug(F101,"netopen nett","",nett); *ipaddr = '\0'; /* Initialize IP address string */ #ifdef STRATUSX25 if (nett == NET_VX25) { /* If network type is X.25 */ netclos(); /* Close any previous net connection */ ttnproto = NP_NONE; /* No protocol selected yet */ sts_extension = -1; strncpy (namecopy, name, NAMECPYL); p = strchr (namecopy, ':'); if (NULL == p) { /* no address given */ strcpy (&destination, namecopy); strcpy (&address, ""); } else { /* address in part of name */ *p++ = '\0'; strcpy (&destination, namecopy); strcpy (&address, p); } if (namecopy[0] == '%') { /* STS with %system#module */ /* remove % from destination if no module name given */ if (NULL == strchr (namecopy, '#')) /* no module name */ strcpy (&destination, &namecopy[1]); sts_extension = (*p) ? atoi (p) : 255; strcpy (&call_data, ""); /* STS includes protocol ID */ } else memcpy (&call_data, "\x00\x04\x01\x00\x00\x00", 6); /* KLUDGE! */ /* Set call user data if specified */ if (cudata) strcat(&call_data,udata); strcpy (&facilities, ""); /* Set reverse charge call and closed user group if requested */ if (revcall) { /* reverse charge requested */ strcat (&facilities, "\x01\x01"); } /* closed user group not supported */ if (closgr > -1) { debug(F101,"x25 closed user group not supported","",closgr); } x25_options.version = 1; x25_options.max_delay = 0; x25_options.send_size = 1024; x25_options.recv_size = 1024; x25_timeout = 30 * 1024; /* lost timeout coming to netopen() */ /* Open X.25 virtual circuit */ if (sts_extension > -1) { s$vc_call_full_sts (&destination, &sts_extension, &facilities, &call_data, &x25_options, &x25_timeout, &vcid, &vcid_event, &status); debug(F101,"netopen s$vc_call_full_sts status","",status); } else { s$vc_call_full ((CV(32) *)&destination, &address, &facilities, &call_data, &x25_options, &x25_timeout, &vcid, &vcid_event, &status); debug(F101,"netopen s$vc_call_full status","",status); } if (status) { return (-1); } lcn = vcid; ttyfd = vcid; linkid = sts_extension; ttnet = nett; /* Stratus X.25 network */ ttnproto = NP_X3; /* PAD X.3, X.28, X.29 protocol */ if (*lcl < 0) *lcl = 1; /* Local mode */ return(0); } #endif /* STRATUSX25 */ #ifdef TCPSOCKET if (nett == NET_TCPB) { netclos(); /* Close any previous connection. */ strncpy(namecopy, name, NAMECPYL); /* Copy the hostname. */ ttnproto = NP_NONE; /* No protocol selected yet. */ debug(F110,"netopen namecopy",namecopy,0); #ifndef NOLISTEN if (name[0] == '*') return(tcpsrv_open(name, lcl, nett, 0)); #endif /* NOLISTEN */ p = namecopy; /* Was a service requested? */ while (*p != '\0' && *p != ':') p++; /* Look for colon */ if (*p == ':') { /* Have a colon */ debug(F110,"netopen name has colon",namecopy,0); *p++ = '\0'; /* Get service name or number */ #ifdef CK_URL /* Here we have to check for various popular syntaxes: host:port (our original syntax) URL such as telnet:host or telnet://host/ Or even telnet://user:password@host:port/ Or a malformed URL such as generated by Netscape 4.0 like: telnet:telnet or telnet::host. */ if (*p == ':') /* a second colon */ *p++ = '\0'; /* get rid of that one too */ while (*p == '/') *p++ = '\0'; /* and slashes */ x = strlen(p); /* Length of remainder */ if (p[x-1] == '/') /* If there is a trailing slash */ p[x-1] = '\0'; /* remove it. */ debug(F110,"netopen namecopy after stripping",namecopy,0); debug(F110,"netopen p after stripping",p,0); service = getservbyname(namecopy,"tcp"); if (service || !xxstrcmp("rlogin",namecopy,NAMECPYL)) { char temphost[80], tempservice[80]; char * q = p, *r = p, *w = p; /* Check for userid and possibly password */ while (*p != '\0' && *p != '@') p++; /* look for @ */ if (*p == '@') { /* found username and perhaps password */ debug(F110,"netopen namecopy found @","",0); *p = '\0'; p++; while (*w != '\0' && *w != ':') w++; if (*w == ':') *w++ = '\0'; /* r now points to username, save it and discard password */ debug(F110,"netopen namecopy username",r,0); debug(F110,"netopen namecopy password",w,0); strncpy(uidbuf,r,64); q = p; /* Host after user and pwd */ } else { p = q; /* No username or password */ } /* Now we must look for the optional port. */ debug(F110,"netopen x p",p,0); debug(F110,"netopen x q",q,0); while (*p != '\0' && *p != ':') /* Look for another colon */ p++; if (*p == ':') { debug(F110,"netopen found port",q,0); *p++ = '\0'; /* Found a port name or number */ debug(F110,"netopen port",p,0); if (ttnproto == NP_NONE) { /* namecopy[] identifies a protocol, so use it */ if (!xxstrcmp("telnet",namecopy,NAMECPYL)) ttnproto = NP_TELNET; #ifdef RLOGCODE else if (!xxstrcmp("login",namecopy,NAMECPYL) || !xxstrcmp("rlogin",namecopy,NAMECPYL)) { ttnproto = NP_RLOGIN; } #endif /* RLOGCODE */ } strncpy(tempservice,p,79); strncpy(temphost,q,79); strncpy(namecopy,temphost,NAMECPYL); debug(F110,"netopen tempservice",tempservice,0); debug(F110,"netopen temphost",temphost,0); x = strlen(namecopy); p = namecopy + x + 1; strncpy(p, tempservice, NAMECPYL - x - 1); } else { /* We didn't find another port, but if q is a service */ /* then assume that namecopy is actually a host. */ if (getservbyname(q,"tcp")) { p = q; } else { #ifdef RLOGCODE /* rlogin is not a valid service */ if (!xxstrcmp("rlogin",namecopy,6)) { strncpy(namecopy,"login",NAMECPYL); } #endif /* RLOGCODE */ /* Reconstruct namecopy */ strncpy(tempservice,namecopy,79); strncpy(temphost,q,79); strncpy(namecopy,temphost,NAMECPYL); debug(F110,"netopen tempservice",tempservice,0); debug(F110,"netopen temphost",temphost,0); x = strlen(namecopy); p = namecopy + x + 1; strncpy(p, tempservice, NAMECPYL - x - 1); } } debug(F110,"netopen URL result",namecopy,0); } #endif /* CK_URL */ } else { /* Otherwise use telnet */ #ifdef COMMENT p = "telnet"; #else p = "23"; #endif /* COMMENT */ } /* By the time we get here, namecopy[] should hold the null-terminated hostname or address, and p should point to the service name or number. */ debug(F110,"netopen host",namecopy,0); debug(F110,"netopen 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) { fprintf(stderr, "Cannot find port for service %s\n", p); #ifdef TGVORWIN debug(F101,"netopen can't get service","",socket_errno); #else debug(F101,"netopen can't get service","",errno); #endif /* TGVORWIN */ errno = 0; /* rather than mislead */ return(-1); } strncpy(svcbuf,p,79); svcbuf[79] = '\0'; debug(F110,"netopen service ok",svcbuf,0); #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 */ /* Set up socket structure and get host address */ memset((char *)&saddr, 0, sizeof(saddr)); if ((host = gethostbyname(namecopy)) != NULL) { dns = 1; saddr.sin_family = host->h_addrtype; memcpy((caddr_t)&saddr.sin_addr, host->h_addr, host->h_length); } else { #ifdef INADDRX /* inet_addr() is of type struct in_addr */ struct in_addr ina; unsigned long uu; ina = inet_addr(namecopy); uu = *(unsigned long *)&ina; #else /* Not INADDRX */ /* inet_addr() is unsigned long */ unsigned long uu; uu = inet_addr(namecopy); #endif /* INADDRX */ if ((saddr.sin_addr.s_addr = uu) != ((unsigned long)-1)) saddr.sin_family = AF_INET; else { fprintf(stderr, "Can't get address for %s\n", namecopy); debug(F101,"netopen can't get address","",errno); errno = 0; /* rather than mislead */ return(-1); } } /* Get a file descriptor for the connection. */ saddr.sin_port = service->s_port; sprintf(ipaddr,"%s", inet_ntoa(saddr.sin_addr)); if (!quiet && *ipaddr) printf(" Trying %s...\n", ipaddr); if ((ttyfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("TCP socket error"); debug(F101,"netopen socket error","",errno); return (-1); } errno = 0; #ifdef RLOGCODE /* Not part of the RLOGIN RFC, but the BSD implementation */ /* requires that the client port be a priviliged port (<1024) */ /* on a Unix system this would require SuperUser permissions */ /* thereby saying that the root of the Unix system has given */ /* permission for this connection to be created */ if (service->s_port == htons((unsigned short)RLOGIN_PORT)) { struct sockaddr_in sin; static unsigned short lport = 1024; /* max reserved port */ int s_errno; lport--; /* Make sure we do not reuse a port */ if (lport == 512) lport = 1023; sin.sin_family = AF_INET; sin.sin_addr.s_addr = INADDR_ANY; while (1) { sin.sin_port = htons(lport); if (bind(ttyfd, (struct sockaddr *)&sin, sizeof(sin)) >= 0) break; if (errno != EADDRINUSE) { printf("\nBind failed with errno %d for port %d.\n", errno, lport); debug(F101,"rlogin bind failed","",errno); perror("rlogin bind"); netclos(); return -1; } lport--; if (lport == 512 /* lowest reserved port to use */ ) { printf("\nNo reserved ports available.\n"); netclos(); return -1; } } debug(F101,"rlogin lport","",lport); ttnproto = NP_RLOGIN; } #endif /* RLOGCODE */ /* Now connect to the socket on the other end. */ if (connect(ttyfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) { i = errno; /* save error code */ #ifdef RLOGCODE if (errno == EADDRINUSE && ttnproto == NP_RLOGIN) { #ifdef TCPIPLIB socket_close(ttyfd); /* Close it. */ #else close(ttyfd); #endif /* TCPIPLIB */ continue; /* Try a different lport */ } #endif /* RLOGCODE */ close(ttyfd); ttyfd = -1; wasclosed = 1; errno = i; /* and report this error */ debug(F101,"netopen connect errno","",errno); return(-1); } #ifdef SO_OOBINLINE /* The symbol SO_OOBINLINE is not known to Ultrix 2.0. It means "leave out of band data inline". The normal value is 0x0100, but don't try this on systems where the symbol is undefined. */ setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on); #endif /* SO_OOBINLINE */ /* See if the service is TELNET. */ if ((x = ntohs((unsigned short)service->s_port)) == TELNET_PORT) ttnproto = NP_TELNET; /* Yes, set global flag. */ debug(F101,"netopen service","",x); ttnet = nett; /* TCP/IP (sockets) network */ if (*lcl < 0) *lcl = 1; /* Local mode. */ return(0); /* Done. */ } #ifndef NOTCPOPTS #ifdef SOL_SOCKET #ifdef TCP_NODELAY no_delay(tcp_nodelay); #endif /* TCP_NODELAY */ #ifdef SO_KEEPALIVE keepalive(tcp_keepalive); #endif /* SO_KEEPALIVE */ #ifdef SO_LINGER ck_linger(tcp_linger, tcp_linger_tmo); #endif /* SO_LINGER */ #ifdef SO_SNDBUF sendbuf(tcp_sendbuf); #endif /* SO_SNDBUF */ #ifdef SO_RCVBUF recvbuf(tcp_recvbuf); #endif /* SO_RCVBUF */ #endif /* SOL_SOCKET */ #endif /* NOTCPOPTS */ ttnet = nett; /* TCP/IP (sockets) network */ x = ntohs((unsigned short)service->s_port); svcnum = x; /* See if the service is TELNET. */ if (x == TELNET_PORT) { if (ttnproto != NP_TCPRAW) /* Yes, so if raw port not requested */ ttnproto = NP_TELNET; /* select TELNET protocol. */ } #ifdef RLOGCODE else if (x == RLOGIN_PORT) { ttnproto = NP_RLOGIN; } #endif /* RLOGCODE */ #ifdef COMMENT /* not yet */ else if (x == KERMIT_PORT) { ttnproto = NP_KERMIT; } #endif /* COMMENT */ #ifndef datageneral /* Find out our own IP address */ { struct sockaddr_in sa; #ifndef GSOCKNAME_T #define GSOCKNAME_T int #ifdef UNIXWARE #undef GSOCKNAME_T #define GSOCKNAME_T size_t #else #ifdef VMS #ifdef DEC_TCPIP #ifdef __DECC_VER #undef GSOCKNAME_T #define GSOCKNAME_T size_t #endif /* __DECC_VER */ #endif /* DEC_TCPIP */ #endif /* VMS */ #endif /* UNIXWARE */ #endif /* GSOCKNAME_T */ GSOCKNAME_T slen; slen = sizeof(sa); /* memset is not portable, but it exists on VOS */ memset(&sa, 0, slen); #ifndef EXCELAN if (!getsockname(ttyfd, (struct sockaddr *)&sa, &slen) ) { sprintf(myipaddr,"%s", (char *)inet_ntoa(sa.sin_addr)); debug(F110,"getsockname",myipaddr,0); } #endif /* EXCELAN */ } #endif /* datageneral */ if (tcp_rdns && dns || tcp_rdns == SET_ON) { if (!quiet) { printf(" Reverse DNS Lookup... "); fflush(stdout); } if (host = gethostbyaddr((char *)&saddr.sin_addr,4,PF_INET)) { debug(F100,"netopen gethostbyname != NULL","",0); if (!quiet) { printf("(OK)\n"); fflush(stdout); } strncpy(name,host->h_name,79); strncat(name,":",80-strlen(name)); strncat(name,p,80-strlen(name)); if (!quiet) { printf(" %s connected on port %s\n",host->h_name,p); } } else { if (!quiet) printf("Failed.\n"); } } else if (!quiet) printf("(OK)\n"); if (!quiet) fflush(stdout); /* This should already have been done but just in case */ sprintf(ipaddr,"%s", (char *)inet_ntoa(saddr.sin_addr)); #ifdef CK_AUTHENTICATION /* Before Initialization Telnet/Rlogin Negotiations Init Kerberos */ ck_auth_init( namecopy, uidbuf, ttyfd ); #endif /* CK_AUTHENTICATION */ tn_ini(); /* Reset/Start Telnet negotiations */ if (ttchk() < 0) return(-1); #ifdef RLOGCODE if (ttnproto == NP_RLOGIN) { if (rlog_ini() < 0) { debug(F100,"rlogin initialization failed","",0); netclos(); return -1; } } #endif /* RLOGCODE */ debug(F101,"netopen service","",svcnum); if (*lcl < 0) *lcl = 1; /* Local mode. */ return(0); #endif /* TCPSOCKET */ /* Add support for other networks here. */ return(-1); /* Unsupported Network type */ } /* N E T C L O S -- Close current network connection. */ int netclos() { int x = 0; short vcid; short status; short diag; if (ttyfd < 0) /* Was open? */ return(0); /* Wasn't. */ #ifdef STRATUSX25 if (ttnet == NET_VX25) { if (ttyfd > -1) { vcid = ttyfd; diag = 0; s$vc_clear (&vcid, &diag, &status); debug(F101,"s$vc_clear status","",status); ttyfd = -1; wasclosed = 1; x = (status == 0) ? 0 : -1; } } #endif /* STRATUSX25 */ #ifdef TCPSOCKET if (ttnet == NET_TCPB) { if (ttyfd > -1) /* Was. */ #ifdef TNCODE tn_sopt(DO,TELOPT_LOGOUT); /* Send LOGOUT option before close */ TELOPT_UNANSWERED_DO(TELOPT_LOGOUT) = 1; #endif /* TNCODE */ x = net_close(ttyfd); } tn_init = 0; /* Remember about telnet protocol... */ *ipaddr = '\0'; /* Zero the IP address string */ tcp_incoming = 0; /* No longer incoming */ sstelnet = 0; /* Client-side Telnet */ #endif /* TCPSOCKET */ ttyfd = -1; /* Mark it as closed. */ wasclosed = 1; #ifdef TCPIPLIB /* Empty the internal buffers so they won't be used as invalid input on the next connect attempt (rlogin). */ ttibp = 0; ttibn = 0; #endif /* TCPIPLIB */ return(x); } /* N E T T C H K -- Check if network up, and how many bytes can be read */ /* Returns number of bytes waiting, or -1 if connection has been dropped. */ int /* Check how many bytes are ready */ nettchk() { /* for reading from network */ unsigned int count = 0; int x, y; char c; x = y = 0; #ifdef COMMENT debug(F101,"nettchk entry ttxbn","",ttxbn); debug(F101,"nettchk entry ttxbp","",ttxbp); #endif errno = 0; /* for X.25, just return count of buffered characters */ #ifdef TCPSOCKET if (ttnet == NET_TCPB) { if (net_ioctl(ttyfd,FIONREAD,(char *)&count) < 0) { debug(F101,"nettchk net_ioctl error","",errno); if (ttxbn < 1) return(-1); else return(ttxbn); } debug(F101,"nettchk count","",count); } #endif /* TCPSOCKET */ /* count what's in network and what we have buffered */ debug(F101,"nettchk returns","",count+ttxbn); return(count + ttxbn); } /* N E T I N C -- Input character from network */ int netinc(timo) int timo; { debug(F101,"WARNING: netinc called, timo","",timo); return(-1); } /* N E T T O L -- Output a string of bytes to the network */ /* Call with s = pointer to string, n = length. Returns number of bytes actually written on success, or -1 on i/o error, -2 if called improperly. */ int nettol(s,n) char *s; int n; { int count = 0; short buflen = n; #ifdef TCPSOCKET if (ttnet == NET_TCPB) { if ((count = net_write(ttyfd,s,n,0)) < 1) { debug(F101,"nettol net_write error","",errno); return(-1); } debug(F111,"nettol net_write",s,count); return(count); } #endif /* TCPSOCKET */ #ifdef STRATUSX25 if (ttnet == NET_VX25) { short mbit = 0; short vcid = ttyfd; short status; if (0 == x25qbit && padparms[PAD_DATA_FORWARD_TIMEOUT]) mbit = 2; /* stream data, may combine packets */ if (buflen > 1024) /* only try to send 1K */ buflen = 1024; s$vc_send_packet (&vcid, &buflen, s, &x25qbit, &mbit, &status); s[n] = '\0'; debug(F111,"nettol s$vc_send_packet status",s,status); if (status) return (-1); count = buflen; return (count); } #endif /* STRATUSX25 */ return(-2); } /* N E T T O C -- Output character to network */ /* Call with character to be transmitted. Returns 0 if transmission was successful, or -1 upon i/o error, or -2 if called improperly. */ int #ifdef CK_ANSIC nettoc(char c) #else nettoc(c) char c; #endif /* CK_ANSIC */ /* nettoc */ { unsigned char cc; cc = c; #ifdef TCPSOCKET if (ttnet == NET_TCPB) { debug(F101,"nettoc cc","",cc); if (net_write(ttyfd,&cc,1,0) < 1) { debug(F101,"nettoc net_write error","",errno); return(-1); } debug(F101,"nettoc net_write","", cc); return(0); } #endif /* TCPSOCKET */ #ifdef STRATUSX25 if (ttnet == NET_VX25) { short mbit = 2; /* may be joined with other packets before send */ short vcid = ttyfd; short buflen = 1; short status; s$vc_send_packet (&vcid, &buflen, &cc, &x25qbit, &mbit, &status); if (status) { debug(F101,"nettoc s$vc_send_packet status",0,status); } return (status ? -2 : 0); } #endif /* STRATUSX25 */ return(-2); } /* N E T F L U I -- Flush network input buffer */ int netflui() { int n; CHAR ch; ttxbuf[ttxbp+1] = '\0'; debug(F111,"netflui 1",ttxbuf,ttxbn); #ifdef TNCODE if (ttnproto == NP_TELNET) { /* Netflui must process Telnet negotiations or get out of sync */ if ((n = ttchk()) <= 0) return(0); while (n-- > 0) { ch = ttinc(1); if (ch == IAC) { extern int duplex; /* this really shouldn't be here but ... */ int tx = tn_doop((CHAR)(ch & 0xff),duplex,ttinc); if (tx == 1) duplex = 1; else if (tx == 2) duplex = 0; n = ttchk(); } } return(0); } else #endif /* TNCODE */ ttxbn = ttxbp = 0; /* Flush internal buffer *FIRST* */ if ((n = nettchk()) > 0) { /* Now see what's waiting on the net */ if (n > TTXBUFL) n = TTXBUFL; /* and sponge it up */ debug(F101,"netflui 2","",n); /* ... */ #ifdef TCPSOCKET if (ttnet == NET_TCPB) n = net_read(ttyfd,ttxbuf,n,0) ; /* into our buffer */ else n = 0; #endif /* TCPSOCKET */ #ifdef STRATUSX25 if (ttnet == NET_VX25) n = 0; /* x25 don't read to flush */ #endif /* STRATUSX25 */ if (n >= 0) ttxbuf[n] = '\0'; debug(F111,"netflui 3",ttxbuf,n); ttxbuf[0] = '\0'; } return(0); } /* N E T W A I T -- Set a network connection back and forth between wait mode and nowait mode, used by contti during network connections. Assumes the caller logs the statuses. */ int #ifdef CK_ANSIC netwait(int no_wait, int sd, long *evid, long *evcnt) #else netwait(no_wait, sd, evid, evcnt) int no_wait; int sd; long *evid; long *evcnt; #endif /* netwait(int no_wait, int sd, long *evid, long *evcnt) */ { short status; int y; int x; short event_stat; status = 0; debug(F101,"netwait no_wait","",no_wait); debug(F101," sd","",sd); netnowait = no_wait; #ifdef STRATUSX25 /* X.25 we don't actually change the mode. We stay in wait mode for everything except receiving packets. */ if (ttnet == NET_VX25) { if (no_wait) { /* pass back the saved event information */ *evid = vcid_event; s$read_event (evid, evcnt, &event_stat, &status); } } #endif /* STRATUSX25 */ #ifdef TCPSOCKET if (ttnet == NET_TCPB) { if (no_wait) { if (0 > get_socket_event (sd, evid, evcnt)) { status = errno; return status; } y = 0; /* Turn on nonblocking reads */ x = net_ioctl(ttyfd,FIONBIO,(char*)&y); debug(F101,"netwait FIONBIO","",x); if (x < 0) status = errno; } else { y = 1; /* Turn on blocking reads */ x = net_ioctl(ttyfd,FIONBIO,(char*)&y); debug(F101,"netwait FIONBIO","",x); if (x < 0) status = errno; } } #endif /* TCPSOCKET */ return (status); } /* getlocalipaddr() attempts to resolve an IP Address for the local machine. * If the host is multi-homed it returns only one address. * * Two techniques are used. * (1) get the local host name and perform a reverse DNS lookup, then take * the first entry; * (2) open a UDP socket, use it to connect to a fictitious host (it's OK, * no data is sent), then retrieve the local address from the socket. * Note: the second technique won't work on Microsoft systems. See * Article ID: Q129065 PRB: Getsockname() Returns IP Address 0.0.0.0 for UDP */ int getlocalipaddr() { #ifdef TCPSOCKET #ifndef datageneral struct sockaddr_in l_sa; struct sockaddr_in r_sa; GSOCKNAME_T slen = sizeof(struct sockaddr_in); int sock; int rc; struct in_addr laddr; /* if still not resolved, then try second strategy */ /* This second strategy does not work on Windows */ memset(&l_sa,0,slen); memset(&r_sa,0,slen); /* get a UDP socket */ sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock != -1) { /* connect to arbirary port and address (NOT loopback) */ r_sa.sin_family = AF_INET; r_sa.sin_port = htons(IPPORT_ECHO); /* The following is an "illegal conversion" in AOS/VS */ /* (and who knows where else) */ #ifdef INADDRX inaddrx = inet_addr("128.127.50.1"); r_sa.sin_addr.s_addr = *(unsigned long *)&inaddrx; #else r_sa.sin_addr.s_addr = inet_addr("128.127.50.1"); #endif /* INADDRX */ rc = connect(sock, (struct sockaddr *) &r_sa, sizeof(struct sockaddr)); if (!rc) { /* get local address */ getsockname(sock,(struct sockaddr *)&l_sa,&slen); #ifdef TCPIPLIB socket_close(sock); /* We're done with the socket */ #else close(sock); #endif /* TCPIPLIB */ if (l_sa.sin_addr.s_addr != INADDR_ANY) { sprintf(myipaddr,"%s", (char *)inet_ntoa(l_sa.sin_addr)); debug(F110,"getlocalipaddr setting buf to",myipaddr,0); return(0); } } } return getlocalipaddrs(myipaddr,sizeof(myipaddr),0); #else /* datageneral */ return(-1); #endif /* datageneral */ #else return(-1); #endif /* TCPSOCKET */ } int getlocalipaddrs(buf,bufsz,index) char * buf; int bufsz; int index; /* getlocalipaddrs */ { #ifdef TCPSOCKET #ifndef datageneral char localhost[256]; struct hostent * host=NULL; struct sockaddr_in l_sa; struct sockaddr_in r_sa; GSOCKNAME_T slen = sizeof(struct sockaddr_in); int sock; int rc; char messageBuf[60]; struct in_addr laddr; memset(&l_sa,0,slen); memset(&r_sa,0,slen); /* init local address (to zero) */ l_sa.sin_addr.s_addr = INADDR_ANY; #ifdef CKGHNLHOST rc = gethostname(localhost, 256); debug(F110,"getlocalipaddrs localhost",localhost,0); #else /* This doesn't work on some platforms, e.g. Solaris */ rc = 0; localhost[0] = '\0'; #endif /* CKGHNLHOST */ if (!rc) { /* resolve host name for local address */ host = gethostbyname(localhost); if (host) { #ifdef HADDRLIST if ( index < 0 || index > 63 || !host->h_addr_list[index] ) { buf[0] = '\0'; return(-1); } l_sa.sin_addr.s_addr = *((unsigned long *) (host->h_addr_list[index])); sprintf(buf,"%s", (char *)inet_ntoa(l_sa.sin_addr)); debug(F110,"getlocalipaddrs setting buf to",buf,0); #else /* HADDRLIST */ if (index != 0) { buf[0] = '\0'; return(-1); } l_sa.sin_addr.s_addr = *((unsigned long *) (host->h_addr)); sprintf(buf,"%s", (char *)inet_ntoa(l_sa.sin_addr)); debug(F110,"getlocalipaddrs setting buf to",buf,0); #endif /* HADDRLIST */ return(0); } else debug(F110, "getlocalipaddrs: gethostbyname() failed", localhost, 0 ); } #endif /* datageneral */ #else return(-1); #endif /* TCPSOCKET */ } #ifdef TCPSOCKET #ifdef RLOGCODE /* TCP/IP RLOGIN protocol support code */ static int rlog_naws() { struct rlog_naws { char id[4]; unsigned short rows, cols, ypix, xpix; } nawsbuf; if (ttnet != NET_TCPB) return 0; if (ttnproto != NP_RLOGIN) return 0; if (!nawsflg) return 0; debug(F100,"rlogin Window Size sent","",0); nawsbuf.id[0] = nawsbuf.id[1] = 0xFF; nawsbuf.id[2] = nawsbuf.id[3] = 's'; nawsbuf.rows = htons((unsigned short) tt_rows); nawsbuf.cols = htons((unsigned short) tt_cols); nawsbuf.ypix = htons(0); /* y pixels */ nawsbuf.xpix = htons(0); /* x pixels */ if (ttol((CHAR *) &nawsbuf, 12) < 0) return -1; return 0; } static int rlog_ini() { #ifdef RLOGOUTBUF char outbuf[512]; int outbytes=0; #endif /* RLOGOUTBUF */ int flag = 0; #define TERMLEN 16 extern char uidbuf[]; char localuser[255]; int userlen = 0; char terminal[TERMLEN+1]; #ifdef CONGSPD #define CONSPDLEN 16 char conspeed[CONSPDLEN+1]; long conspd = -1L; #endif /* CONGSPD */ int i, n; int rc = 0; tn_ini(); /* This call will reset all of the Telnet */ /* options and then quit. We need to do */ /* this since we use the Telnet options */ /* to hold various state information */ duplex = 0; /* Rlogin is always remote echo */ #ifdef CK_TTGWSIZ /* But compute the values anyway before the first read since the out- of-band NAWS request would arrive before the first data byte (NULL). */ debug(F101,"rlog_ini tt_rows 1","",tt_rows); debug(F101,"rlog_ini tt_cols 1","",tt_cols); if (tt_rows < 0 || tt_cols < 0) { /* Not known yet */ ttgwsiz(); /* Try to find out */ } debug(F101,"rlog_ini tt_rows 2","",tt_rows); debug(F101,"rlog_ini tt_cols 2","",tt_cols); #endif /* CK_TTGWSIZ */ ttflui(); /* Start by flushing the buffers */ rlog_mode = RL_COOKED; #ifdef RLOGOUTBUF outbuf[outbytes++] = 0; #else ttoc(0); /* Send an initial NUL as wake-up */ #endif /* RLOGOUTBUF */ /* Followed by client username ... */ localuser[0] = '\0'; { char *s; char *p; char * user = getenv("USER"); debug(F110,"rlogin getenv(USER)",user,0); if (!user) user = ""; userlen = strlen(user); s = user; p = (char *)localuser; while (*p++ = *s++) ; if (ck_lcname) { cklower((char *)localuser); debug(F110,"rlog_ini localuser 2",localuser,0); } #ifdef RLOGOUTBUF strcpy(&outbuf[outbytes],localuser); outbytes += userlen+1; #else rc = ttol((CHAR *)localuser,userlen+1); /* strlen + 1 */ #endif /* RLOGOUTBUF */ debug(F111,"rlog_ini","ttol local user",rc); } /* Then the server userid... */ if (uidbuf[0]) { #ifdef RLOGOUTBUF strcpy(&outbuf[outbytes],uidbuf); outbytes += strlen(uidbuf) + 1; #else rc = ttol((CHAR *) uidbuf,strlen(uidbuf)+1); /* strlen + 1 */ #endif /* RLOGOUTBUF */ debug(F111,"rlog_ini","ttol server user",rc); } else if (localuser[0]) { #ifdef RLOGOUTBUF strcpy(&outbuf[outbytes],localuser); outbytes += strlen(localuser) + 1; #else rc = ttol((CHAR *) localuser,userlen+1); #endif /* RLOGOUTBUF */ debug(F111,"rlog_ini","ttol server user",rc); } else { #ifdef RLOGOUTBUF outbuf[outbytes++]=0; #else rc = ttoc(0); #endif /* RLOGOUTBUF */ debug(F111,"rlog_ini","ttoc NUL server user",rc); } /* Finally the terminal type and speed */ terminal[0] = '\0'; if (tn_term) { /* SET TELNET TERMINAL-TYPE value */ if (*tn_term) { /* (if any) takes precedence. */ strncpy(terminal, tn_term, TERMLEN); terminal[TERMLEN] = '\0'; flag = 1; } } else { /* Otherwise the local terminal type */ /* we just look at the TERM environment variable */ /* That's one that we understand in our getenv() replacement */ char *p = getenv("TERM"); if (p) strncpy(terminal,p,TERMLEN); else terminal[0] = '\0'; } n = strlen(terminal); if (n > 0) { /* We have a terminal type */ if (!flag) { /* If not user-specified */ for (i = 0; i < n; i++) /* then lowercase it. */ if (isupper(terminal[i])) terminal[i] = tolower(terminal[i]); } #ifdef RLOGOUTBUF strcpy(&outbuf[outbytes],terminal); outbytes += n; #else rc = ttol((CHAR *)terminal,n); #endif /* RLOGOUTBUF */ debug(F111,"rlog_ini","ttol terminal",rc); #ifdef CONGSPD /* conspd() is not yet defined in all ck*tio.c modules */ /* And it will be defined at some point for us, but not now */ conspd = congspd(); if (conspd > 0L) { sprintf(conspeed,"/%ld",conspd); n = strlen(conspeed); #ifdef RLOGOUTBUF strcpy(&outbuf[outbytes],conspeed); outbytes += n+1; #else rc = ttol((CHAR *)conspeed,n+1); #endif /* RLOGOUTBUF */ } else #endif /* CONGSPD */ { #ifdef RLOGOUTBUF strcpy(&outbuf[outbytes],"/19200"); outbytes += 7; #else rc = ttol((CHAR *)"/19200",7); /* strlen + 1 */ #endif /* RLOGOUTBUF */ } debug(F111,"rlog_ini","ttol speed",rc); } else { #ifdef RLOGOUTBUF outbuf[outbytes++]=0; #else rc = ttoc(0); #endif /* RLOGOUTBUF */ debug(F111,"rlog_ini","ttoc NUL terminal/speed",rc); } #ifdef RLOGOUTBUF ttol(outbuf,outbytes); #endif /* RLOGOUTBUF */ /* Now we are supposed to get back a single zero byte as confirmation */ errno = 0; rc = ttinc(60); debug(F101,"rlogin first ttinc","",rc); if (rc > 0) { debug(F101,"rlogin ttinc 1","",rc); printf("Rlogin protocol error - 0x%x received instead of 0x00\n", rc); return(-1); } else if (rc < 0) { debug(F101,"rlogin ttinc errno","",errno); /* printf("Network error: %d\n", errno); */ return(-1); } return(0); } static VOID rlog_oob(oobdata, count) CHAR * oobdata; int count; { int i; for (i = 0; i 0 && diff < (speed - ccittspeeds[match])) match = i; } padparms[PAD_LINE_SPEED] = match; /* line speed (as good as we can get) */ } /* Set PAD parameters */ VOID setpad(s,n) CHAR *s; int n; { int i; CHAR *ps = s; char buff[30]; if (n) { for (i = 0; i < n; i++) { if(deblog) { sprintf(buff," set pad parm %d=%d",*ps,*(ps+1)); debug(F100,buff,"",0); } /* out of range or read only */ if (*ps > MAXPADPARMS || *ps == PAD_LINE_SPEED) x29err[i+2] = *ps; else padparms[*ps] = *(ps+1); ps += 2; } } else { debug(F100," setpad calling initpad","",0); initpad(); } } /* Read PAD parameters */ VOID readpad(s,n,r) CHAR *s; int n; CHAR *r; { int i; CHAR *ps = s; CHAR *pr = r; char buff[30]; *pr++ = X29_PARAMETER_INDICATION; if (n == 0) { /* All supported parameters */ for (i = 1; i <= MAXPADPARMS; i++, ps++) { *pr++ = i; *pr++ = padparms[i]; if(deblog) { sprintf(buff," read pad parm %d=%d",i,padparms[i]); debug(F100,buff,"",0); } } } else { /* list of specific parameters */ for (i = 0; i < n; i++, ps++) { if(deblog) { sprintf(buff," read pad parm %d=%d", *ps, (*ps <= MAXPADPARMS) ? padparms[i] : -1); debug(F100,buff,"",0); } if (*ps > MAXPADPARMS) { x29err[i+2] = *ps++; } else { *pr++ = *ps; *pr++ = padparms[*ps++]; } } } } int qbitpkt(s,n) CHAR *s; int n; { CHAR *ps = s; int x29cmd = *ps; CHAR *psa = s+1; CHAR x29resp[(MAXPADPARMS*2)+1]; debug (F101,"qbitpkt, len","",n); switch (x29cmd) { case X29_SET_PARMS: debug(F100,"X29 SET PAD","",0); setpad (psa,n/2); if ((int)strlen(x29err) > 2) { ttol (x29err,(int)strlen(x29err)); x29err[2] = '\0'; } break; case X29_READ_PARMS: debug(F100,"X29 READ PAD","",0); readpad (psa,n/2,x29resp); setqbit (); ttol (x29resp, (n > 1) ? n : (MAXPADPARMS * 2 + 1)); if ((int)strlen(x29err) > 2) { ttol (x29err,(int)strlen(x29err)); x29err[2] = '\0'; } resetqbit(); break; case X29_SET_AND_READ_PARMS: debug(F100,"X29 SET AND READ PAD","",0); setpad (psa,n/2); readpad (psa,n/2,x29resp); setqbit(); ttol (x29resp, (n > 1) ? n : (MAXPADPARMS * 2 + 1)); if ((int)strlen(x29err) > 2) { ttol (x29err,(int)strlen(x29err)); x29err [2] = '\0'; } resetqbit(); break; case X29_INVITATION_TO_CLEAR: debug(F100,"X29 INVITATION TO CLEAR","",0); (VOID) x25clear(); return (-2) ; /* hang it up */ case X29_INDICATION_OF_BREAK: debug(F100,"X29 INDICATION OF BREAK","",0); break; } return (0); } /* PAD break action processor */ VOID breakact() { extern char x25obuf[]; extern int obufl; extern int active; extern unsigned char tosend; static CHAR indbrk[3] = { X29_INDICATION_OF_BREAK, PAD_SUPPRESSION_OF_DATA, 1 }; CHAR intudat, cause, diag; if (x25stat() < 0) return; /* Ignore if no virtual call established */ if (padparms[PAD_BREAK_ACTION] != 0) /* Forward condition */ if (ttol(x25obuf,obufl) < 0) { perror ("\r\nCan't send characters"); active = 0; } else { /* bzero (x25obuf,sizeof(x25obuf)); */ /**/ obufl = 0; tosend = 0; }; switch (padparms[PAD_BREAK_ACTION]) { case 0 : break; /* do nothing */ case 1 : /* send interrupt packet with interrupt user data field = 1 */ intudat = 1; x25intr (intudat); break; case 2 : /* send reset packet with cause and diag = 0 */ cause = diag = 0; x25reset (cause,diag); break; case 5 : /* send interrupt packet with interrupt user data field = 0 */ intudat = 0; x25intr (intudat) ; setqbit (); /* send indication of break without a parameter field */ ttoc(X29_INDICATION_OF_BREAK); resetqbit (); break; case 8 : active = 0; /* leave data transfer */ conol ("\r\n"); break; case 21: /* send interrupt packet with interrupt user data field = 0 */ intudat = 0; x25intr (intudat); setpad (indbrk+1,1); /* set pad to discard input */ setqbit (); /* send indication of break with parameter field */ ttol (indbrk,sizeof(indbrk)); resetqbit (); break; } } /* X.25 support functions */ /* Convert a null-terminated string representing an X.121 address to a packed BCD form. */ #ifdef SUNX25 /* not used for Stratus X.25 */ int pkx121(str,bcd) char *str; CHAR *bcd; { int i, j; u_char c; i = j = 0; while (str[i]) { if ( i >= 15 || str [i] < '0' || str [i] > '9' ) return (-1); c = str [i] - '0'; if ( i & 1 ) bcd [j++] |= c; else bcd [j] = c << 4; i++; } return (i); } #endif /* SUNX25 */ /* Reads and prints X.25 diagnostic */ int x25diag () { int i; #ifdef SUNX25 bzero ((char *)&diag,sizeof(diag)); if (ioctl(ttyfd,X25_RD_CAUSE_DIAG,&diag)) { perror ("Reading X.25 diagnostic"); return(-1); } if (diag.datalen > 0) { printf ("X.25 Diagnostic :"); for (i = 0; i < diag.datalen; i++) printf (" %02x",diag.data[i]); printf ("\r\n"); } #endif /* SUNX25 */ return(0); } /* X.25 Out-of-Band Signal Handler */ #ifdef SUNX25 VOID x25oobh() { int oobtype; u_char oobdata; (VOID) signal(SIGURG,x25oobh); do { if (ioctl(ttyfd,X25_OOB_TYPE,&oobtype)) { perror ("Getting signal type"); return; } switch (oobtype) { case INT_DATA: if (recv(ttyfd,oobdata,1,MSG_OOB) < 0) { perror ("Receiving X.25 interrupt data"); return; } printf ("\r\nInterrupt received, data = %d\r\n", oobdata); break; case VC_RESET: printf ("\r\nVirtual circuit reset\r\n"); x25diag (); break; case N_RESETS: printf ("\r\nReset timeout\r\n"); break; case N_CLEARS: printf ("\r\nClear timeout\r\n"); break; case MSG_TOO_LONG: printf ("\r\nMessage discarded, too long\r\n"); break; default: if (oobtype) printf("\r\nUnknown oob type %d\r\n",oobtype); break; } } while (oobtype); } #endif /* SUNX25 */ /* Send a X.25 interrupt packet */ int #ifdef CK_ANSIC x25intr(char intr) #else x25intr(intr) char intr; #endif /* CK_ANSIC */ /* x25intr */ { short vcid = ttyfd; short status; short diag; debug(F101,"X.25 intr, char","",(long) intr); s$vc_send_interrupt (&vcid, &intr, &status); debug(F101,"s$vc_send_interrupt status",0,status); s$vc_status (&vcid, &diag, &status); debug(F101,"s$vc_status status",0,status); return(0); } /* Reset X.25 virtual circuit */ int #ifdef CK_ANSIC x25reset(char cause, char diagn) #else x25reset(cause, diagn) char cause; char diagn; #endif /* CK_ANSIC */ /* x25reset */ { short vcid = ttyfd; short status; short vc_diag; char buff[50]; sprintf (buff, "cause=%d[IGNORED], diag=%d", cause, diagn); vc_diag = (CHAR) diagn; s$vc_reset (&vcid, &vc_diag, &status); debug(F111,"X.25 reset, status",buff,status); return(0); } /* Clear X.25 virtual circuit */ int x25clear() { short vcid = ttyfd; short diag = 0; short status; s$vc_clear (&vcid, &diag, &status); debug(F101,"X.25 clear status","",status); return(ttclos(0)); /* Close socket */ } /* X.25 status */ int x25stat() { if (ttyfd < 0) return (-1); return(0); } /* Set Q_BIT on */ VOID setqbit() { x25qbit = 1; } /* Set Q_BIT off */ VOID resetqbit() { x25qbit = 0; } /* Read n characters from X.25 circuit into buf */ int x25xin(n,buf) int n; CHAR *buf; { register int x, c; int qpkt; short vcid = ttyfd; short buffsize = n; short packsize; short mbit; short qbit; char intchar; short diag; short status; do { if (netnowait) /* do this in no_wait mode */ s$vc_set_no_wait_mode (); s$vc_recv_packet (&vcid, &buffsize, buf, &packsize, &qbit, &mbit, &status); debug(F101,"s$vc_recv_packet status","",status); if (netnowait) /* change it back for everything else */ s$vc_set_wait_mode (); x = (status)? (-1) : packsize; switch (status) { case 0: break; case e$vc_interrupt_pending: s$vc_recv_interrupt (&vcid, &intchar, &status); debug(F101,"s$vc_recv_interrupt status","",status); break; case e$vc_reset_pending: s$vc_reset (&vcid, &diag, &status); debug(F101,"s$vc_reset status","",status); break; case e$caller_must_wait: x = 0; break; default: return (-2); /* I dunno, but it's broke */ } if (x > 0 && qbit) { /* If Q_BIT packet, process it */ if ((c=qbitpkt(buf,x)) < 0) return(c); qpkt = 1; } else qpkt = 0; } while (qpkt); if (x >= 0) buf[x] = '\0'; else x = -1; debug(F101,"x25xin x","",x); return(x); } #endif /* STRATUSX25 */ #endif /* NETCONN */