diff options
| author | Peter Wemm <peter@FreeBSD.org> | 1995-12-26 04:54:48 +0000 |
|---|---|---|
| committer | Peter Wemm <peter@FreeBSD.org> | 1995-12-26 04:54:48 +0000 |
| commit | d14071a4b3f94fc0205683a8186f924d8afa6357 (patch) | |
| tree | 2df06c65b06de43fedf640ab5766a1459303b33b /usr.sbin/sup/lib/scm.c | |
| parent | 98542945540416173425248242bf3f110f59e694 (diff) | |
Notes
Diffstat (limited to 'usr.sbin/sup/lib/scm.c')
| -rw-r--r-- | usr.sbin/sup/lib/scm.c | 596 |
1 files changed, 596 insertions, 0 deletions
diff --git a/usr.sbin/sup/lib/scm.c b/usr.sbin/sup/lib/scm.c new file mode 100644 index 000000000000..5d71bccc8ae4 --- /dev/null +++ b/usr.sbin/sup/lib/scm.c @@ -0,0 +1,596 @@ +/* + * Copyright (c) 1992 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * SUP Communication Module for 4.3 BSD + * + * SUP COMMUNICATION MODULE SPECIFICATIONS: + * + * IN THIS MODULE: + * + * CONNECTION ROUTINES + * + * FOR SERVER + * servicesetup (port) establish TCP port connection + * char *port; name of service + * service () accept TCP port connection + * servicekill () close TCP port in use by another process + * serviceprep () close temp ports used to make connection + * serviceend () close TCP port + * + * FOR CLIENT + * request (port,hostname,retry) establish TCP port connection + * char *port,*hostname; name of service and host + * int retry; true if retries should be used + * requestend () close TCP port + * + * HOST NAME CHECKING + * p = remotehost () remote host name (if known) + * char *p; + * i = samehost () whether remote host is also this host + * int i; + * i = matchhost (name) whether remote host is same as name + * int i; + * char *name; + * + * RETURN CODES + * All procedures return values as indicated above. Other routines + * normally return SCMOK on success, SCMERR on error. + * + * COMMUNICATION PROTOCOL + * + * Described in scmio.c. + * + ********************************************************************** + * HISTORY + * 2-Oct-92 Mary Thompson (mrt) at Carnegie-Mellon University + * Added conditional declarations of INADDR_NONE and INADDR_LOOPBACK + * since Tahoe version of <netinet/in.h> does not define them. + * + * $Log: scm.c,v $ + * Revision 1.2 1994/06/20 06:04:04 rgrimes + * Humm.. they did a lot of #if __STDC__ but failed to properly prototype + * the code. Also fixed one bad argument to a wait3 call. + * + * It won't compile -Wall, but atleast it compiles standard without warnings + * now. + * + * Revision 1.1.1.1 1993/08/21 00:46:33 jkh + * Current sup with compression support. + * + * Revision 1.1.1.1 1993/05/21 14:52:17 cgd + * initial import of CMU's SUP to NetBSD + * + * Revision 1.13 92/08/11 12:05:35 mrt + * Added changes from stump: + * Allow for multiple interfaces, and for numeric addresses. + * Changed to use builtin port for the "supfiledbg" + * service when getservbyname() cannot find it. + * Added forward static declatations, delinted. + * Updated variable argument usage. + * [92/08/08 mrt] + * + * Revision 1.12 92/02/08 19:01:11 mja + * Add (struct sockaddr *) casts for HC 2.1. + * [92/02/08 18:59:09 mja] + * + * Revision 1.11 89/08/03 19:49:03 mja + * Updated to use v*printf() in place of _doprnt(). + * [89/04/19 mja] + * + * 11-Feb-88 Glenn Marcy (gm0w) at Carnegie-Mellon University + * Moved sleep into computeBackoff, renamed to dobackoff. + * + * 10-Feb-88 Glenn Marcy (gm0w) at Carnegie-Mellon University + * Added timeout to backoff. + * + * 27-Dec-87 Glenn Marcy (gm0w) at Carnegie-Mellon University + * Removed nameserver support. + * + * 09-Sep-87 Glenn Marcy (gm0w) at Carnegie-Mellon University + * Fixed to depend less upon having name of remote host. + * + * 25-May-87 Doug Philips (dwp) at Carnegie-Mellon Universtiy + * Extracted backoff/sleeptime computation from "request" and + * created "computeBackoff" so that I could use it in sup.c when + * trying to get to nameservers as a group. + * + * 21-May-87 Chriss Stephens (chriss) at Carnegie Mellon University + * Merged divergent CS and EE versions. + * + * 02-May-87 Glenn Marcy (gm0w) at Carnegie-Mellon University + * Added some bullet-proofing code around hostname calls. + * + * 31-Mar-87 Dan Nydick (dan) at Carnegie-Mellon University + * Fixed for 4.3. + * + * 30-May-86 Glenn Marcy (gm0w) at Carnegie-Mellon University + * Added code to use known values for well-known ports if they are + * not found in the host table. + * + * 19-Feb-86 Glenn Marcy (gm0w) at Carnegie-Mellon University + * Changed setsockopt SO_REUSEADDR to be non-fatal. Added fourth + * parameter as described in 4.3 manual entry. + * + * 15-Feb-86 Glenn Marcy (gm0w) at Carnegie-Mellon University + * Added call of readflush() to requestend() routine. + * + * 29-Dec-85 Glenn Marcy (gm0w) at Carnegie-Mellon University + * Major rewrite for protocol version 4. All read/write and crypt + * routines are now in scmio.c. + * + * 14-Dec-85 Glenn Marcy (gm0w) at Carnegie-Mellon University + * Added setsockopt SO_REUSEADDR call. + * + * 01-Dec-85 Glenn Marcy (gm0w) at Carnegie-Mellon University + * Removed code to "gracefully" handle unexpected messages. This + * seems reasonable since it didn't work anyway, and should be + * handled at a higher level anyway by adhering to protocol version + * number conventions. + * + * 26-Nov-85 Glenn Marcy (gm0w) at Carnegie-Mellon University + * Fixed scm.c to free space for remote host name when connection + * is closed. + * + * 07-Nov-85 Glenn Marcy (gm0w) at Carnegie-Mellon University + * Fixed 4.2 retry code to reload sin values before retry. + * + * 22-Oct-85 Glenn Marcy (gm0w) at Carnegie-Mellon University + * Added code to retry initial connection open request. + * + * 22-Sep-85 Glenn Marcy (gm0w) at Carnegie-Mellon University + * Merged 4.1 and 4.2 versions together. + * + * 21-Sep-85 Glenn Marcy (gm0w) at Carnegie-Mellon University + * Add close() calls after pipe() call. + * + * 12-Jun-85 Steven Shafer (sas) at Carnegie-Mellon University + * Converted for 4.2 sockets; added serviceprep() routine. + * + * 04-Jun-85 Steven Shafer (sas) at Carnegie-Mellon University + * Created for 4.2 BSD. + * + ********************************************************************** + */ + +#include <libc.h> +#include <errno.h> +#include <sys/param.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <net/if.h> +#include <netdb.h> +#if __STDC__ +#include <stdarg.h> +#else +#include <varargs.h> +#endif +#include "sup.h" + +#ifndef INADDR_NONE +#define INADDR_NONE 0xffffffff /* -1 return */ +#endif +#ifndef INADDR_LOOPBACK +#define INADDR_LOOPBACK (u_long)0x7f000001 /* 127.0.0.1 */ +#endif + +extern int errno; +static char *myhost (); + +char scmversion[] = "4.3 BSD"; + +/* + * PROTOTYPES + */ +#if __STDC__ +int scmerr __P((int, char *,...)); +#endif +/************************* + *** M A C R O S *** + *************************/ + +/* networking parameters */ +#define NCONNECTS 5 + +/********************************************* + *** G L O B A L V A R I A B L E S *** + *********************************************/ + +extern char program[]; /* name of program we are running */ +extern int progpid; /* process id to display */ + +int netfile = -1; /* network file descriptor */ + +static int sock = -1; /* socket used to make connection */ +static struct in_addr remoteaddr; /* remote host address */ +static char *remotename = NULL; /* remote host name */ +static int swapmode; /* byte-swapping needed on server? */ + +/*************************************************** + *** C O N N E C T I O N R O U T I N E S *** + *** F O R S E R V E R *** + ***************************************************/ + +servicesetup (server) /* listen for clients */ +char *server; +{ + struct sockaddr_in sin; + struct servent *sp; + short port; + int one = 1; + + if (myhost () == NULL) + return (scmerr (-1,"Local hostname not known")); + if ((sp = getservbyname(server,"tcp")) == 0) { + if (strcmp(server, FILEPORT) == 0) + port = htons((u_short)FILEPORTNUM); + else if (strcmp(server, DEBUGFPORT) == 0) + port = htons((u_short)DEBUGFPORTNUM); + else + return (scmerr (-1,"Can't find %s server description",server)); + (void) scmerr (-1,"%s/tcp: unknown service: using port %d", + server,port); + } else + port = sp->s_port; + endservent (); + sock = socket (AF_INET,SOCK_STREAM,0); + if (sock < 0) + return (scmerr (errno,"Can't create socket for connections")); + if (setsockopt (sock,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(int)) < 0) + (void) scmerr (errno,"Can't set SO_REUSEADDR socket option"); + (void) bzero ((char *)&sin,sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = port; + if (bind (sock,(struct sockaddr *)&sin,sizeof(sin)) < 0) + return (scmerr (errno,"Can't bind socket for connections")); + if (listen (sock,NCONNECTS) < 0) + return (scmerr (errno,"Can't listen on socket")); + return (SCMOK); +} + +service () +{ + struct sockaddr_in from; + int x,len; + + remotename = NULL; + len = sizeof (from); + do { + netfile = accept (sock,(struct sockaddr *)&from,&len); + } while (netfile < 0 && errno == EINTR); + if (netfile < 0) + return (scmerr (errno,"Can't accept connections")); + remoteaddr = from.sin_addr; + if (read(netfile,(char *)&x,sizeof(int)) != sizeof(int)) + return (scmerr (errno,"Can't transmit data on connection")); + if (x == 0x01020304) + swapmode = 0; + else if (x == 0x04030201) + swapmode = 1; + else + return (scmerr (-1,"Unexpected byteswap mode %x",x)); + return (SCMOK); +} + +serviceprep () /* kill temp socket in daemon */ +{ + if (sock >= 0) { + (void) close (sock); + sock = -1; + } + return (SCMOK); +} + +servicekill () /* kill net file in daemon's parent */ +{ + if (netfile >= 0) { + (void) close (netfile); + netfile = -1; + } + if (remotename) { + free (remotename); + remotename = NULL; + } + return (SCMOK); +} + +serviceend () /* kill net file after use in daemon */ +{ + if (netfile >= 0) { + (void) close (netfile); + netfile = -1; + } + if (remotename) { + free (remotename); + remotename = NULL; + } + return (SCMOK); +} + +/*************************************************** + *** C O N N E C T I O N R O U T I N E S *** + *** F O R C L I E N T *** + ***************************************************/ + +dobackoff (t,b) +int *t,*b; +{ + struct timeval tt; + unsigned s; + + if (*t == 0) + return (0); + s = *b * 30; + if (gettimeofday (&tt,(struct timezone *)NULL) >= 0) + s += (tt.tv_usec >> 8) % s; + if (*b < 32) *b <<= 1; + if (*t != -1) { + if (s > *t) + s = *t; + *t -= s; + } + (void) scmerr (-1,"Will retry in %d seconds",s); + sleep (s); + return (1); +} + +request (server,hostname,retry) /* connect to server */ +char *server; +char *hostname; +int *retry; +{ + int x, backoff; + struct hostent *h; + struct servent *sp; + struct sockaddr_in sin, tin; + short port; + + if ((sp = getservbyname(server,"tcp")) == 0) { + if (strcmp(server, FILEPORT) == 0) + port = htons((u_short)FILEPORTNUM); + else if (strcmp(server, DEBUGFPORT) == 0) + port = htons((u_short)DEBUGFPORTNUM); + else + return (scmerr (-1,"Can't find %s server description", + server)); + (void) scmerr (-1,"%s/tcp: unknown service: using port %d", + server,port); + } else + port = sp->s_port; + (void) bzero ((char *)&sin,sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = inet_addr (hostname); + if (sin.sin_addr.s_addr == (u_long) INADDR_NONE) { + if ((h = gethostbyname (hostname)) == NULL) + return (scmerr (-1,"Can't find host entry for %s", + hostname)); + hostname = h->h_name; + (void) bcopy (h->h_addr,(char *)&sin.sin_addr,h->h_length); + } + sin.sin_port = port; + backoff = 1; + for (;;) { + netfile = socket (AF_INET,SOCK_STREAM,0); + if (netfile < 0) + return (scmerr (errno,"Can't create socket")); + tin = sin; + if (connect(netfile,(struct sockaddr *)&tin,sizeof(tin)) >= 0) + break; + (void) scmerr (errno,"Can't connect to server for %s",server); + (void) close(netfile); + if (!dobackoff (retry,&backoff)) + return (SCMERR); + } + remoteaddr = sin.sin_addr; + remotename = salloc(hostname); + x = 0x01020304; + (void) write (netfile,(char *)&x,sizeof(int)); + swapmode = 0; /* swap only on server, not client */ + return (SCMOK); +} + +requestend () /* end connection to server */ +{ + (void) readflush (); + if (netfile >= 0) { + (void) close (netfile); + netfile = -1; + } + if (remotename) { + free (remotename); + remotename = NULL; + } + return (SCMOK); +} + +/************************************************* + *** H O S T N A M E C H E C K I N G *** + *************************************************/ + +static +char *myhost () /* find my host name */ +{ + struct hostent *h; + static char name[MAXHOSTNAMELEN]; + + + if (name[0] == '\0') { + if (gethostname (name,MAXHOSTNAMELEN) < 0) + return (NULL); + if ((h = gethostbyname (name)) == NULL) + return (NULL); + (void) strcpy (name,h->h_name); + } + return (name); +} + +char *remotehost () /* remote host name (if known) */ +{ + register struct hostent *h; + + if (remotename == NULL) { + h = gethostbyaddr ((char *)&remoteaddr,sizeof(remoteaddr), + AF_INET); + remotename = salloc (h ? h->h_name : inet_ntoa(remoteaddr)); + if (remotename == NULL) + return("UNKNOWN"); + } + return (remotename); +} + +int thishost (host) +register char *host; +{ + register struct hostent *h; + char *name; + + if ((name = myhost ()) == NULL) + logquit (1,"Can't find my host entry"); + h = gethostbyname (host); + if (h == NULL) return (0); + return (strcasecmp (name,h->h_name) == 0); +} + +int samehost () /* is remote host same as local host? */ +{ + static struct in_addr *intp; + static int nint = 0; + struct in_addr *ifp; + int n; + + if (nint <= 0) { + int s; + char buf[BUFSIZ]; + struct ifconf ifc; + struct ifreq *ifr; + struct sockaddr_in sin; + + if ((s = socket (AF_INET,SOCK_DGRAM,0)) < 0) + logquit (1,"Can't create socket for SIOCGIFCONF"); + ifc.ifc_len = sizeof(buf); + ifc.ifc_buf = buf; + if (ioctl (s,SIOCGIFCONF,(char *)&ifc) < 0) + logquit (1,"SIOCGIFCONF failed"); + (void) close(s); + if ((nint = ifc.ifc_len/sizeof(struct ifreq)) <= 0) + return (0); + intp = (struct in_addr *) + malloc ((unsigned) nint*sizeof(struct in_addr)); + if ((ifp = intp) == 0) + logquit (1,"no space for interfaces"); + for (ifr = ifc.ifc_req, n = nint; n > 0; --n, ifr++) { + (void) bcopy ((char *)&ifr->ifr_addr,(char *)&sin,sizeof(sin)); + *ifp++ = sin.sin_addr; + } + } + if (remoteaddr.s_addr == htonl(INADDR_LOOPBACK)) + return (1); + for (ifp = intp, n = nint; n > 0; --n, ifp++) + if (remoteaddr.s_addr == ifp->s_addr) + return (1); + return (0); +} + +int matchhost (name) /* is this name of remote host? */ +char *name; +{ + struct hostent *h; + struct in_addr addr; + char **ap; + if ((addr.s_addr = inet_addr(name)) != (u_long) INADDR_NONE) + return (addr.s_addr == remoteaddr.s_addr); + if ((h = gethostbyname (name)) == 0) + return (0); + if (h->h_addrtype != AF_INET || h->h_length != sizeof(struct in_addr)) + return (0); + for (ap = h->h_addr_list; *ap; ap++) + if (bcmp ((char *)&remoteaddr,*ap,h->h_length) == 0) + return (1); + return (0); +} + +#if __STDC__ +int scmerr (int errno,char *fmt,...) +#else +/*VARARGS*//*ARGSUSED*/ +int scmerr (va_alist) +va_dcl +#endif +{ +#if !__STDC__ + int errno; + char *fmt; +#endif + va_list ap; + + (void) fflush (stdout); + if (progpid > 0) + fprintf (stderr,"%s %d: ",program,progpid); + else + fprintf (stderr,"%s: ",program); +#if __STDC__ + va_start(ap,fmt); +#else + va_start(ap); + errno = va_arg(ap,int); + fmt = va_arg(ap,char *); +#endif + vfprintf(stderr, fmt, ap); + va_end(ap); + if (errno >= 0) + fprintf (stderr,": %s\n",errmsg(errno)); + else + fprintf (stderr,"\n"); + (void) fflush (stderr); + return (SCMERR); +} + +/******************************************************* + *** I N T E G E R B Y T E - S W A P P I N G *** + *******************************************************/ + +union intchar { + int ui; + char uc[sizeof(int)]; +}; + +int byteswap (in) +int in; +{ + union intchar x,y; + register int ix,iy; + + if (swapmode == 0) return (in); + x.ui = in; + iy = sizeof(int); + for (ix=0; ix<sizeof(int); ix++) { + --iy; + y.uc[iy] = x.uc[ix]; + } + return (y.ui); +} |
