File: [local] / src / usr.bin / sup / src / Attic / scm.c (download)
Revision 1.15, Tue Feb 19 19:39:39 2002 UTC (22 years, 3 months ago) by millert
Branch: MAIN
CVS Tags: OPENBSD_3_1_BASE, OPENBSD_3_1 Changes since 1.14: +2 -21 lines
We live in an ANSI C world. Remove lots of gratuitous #ifdef __STDC__ cruft.
|
/* $OpenBSD: scm.c,v 1.15 2002/02/19 19:39:39 millert Exp $ */
/*
* 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.
*
* 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>
#ifndef SIOCGIFCONF
#include <sys/sockio.h>
#endif
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <netdb.h>
#include <syslog.h>
#include <stdarg.h>
#include "supcdefs.h"
#include "supextern.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
char scmversion[] = "4.3 BSD";
extern int silent;
/*************************
*** 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? */
static char *myhost(void);
/***************************************************
*** 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 ***
***************************************************/
/*
* Mark that we are servicing a connection from host at ia. We do
* this by getting an exclusive lock on a file that is "ia" in
* dotted decimal, in directory "lockdir". For convienence's sake we
* write our process ID in there. Should be called from servicing
* child, so lock goes away on exit. Must be called after service()
* sets global remoteaddr (above).
*
* Returns fd for file on success, -1 on failure.
*/
int
lock_host_file(lockdir)
char *lockdir;
{
char *dd, *lpath;
int i, fd;
FILE *f;
dd = strdup(inet_ntoa(remoteaddr));
if (dd == NULL) {
syslog(LOG_ERR, "Malloc failed in lock_host_file()");
return(-1);
}
i = strlen(lockdir) + strlen(dd) + 2; /* NUL and maybe a / */
lpath = (char *)malloc(i);
if (lpath == NULL) {
syslog(LOG_ERR, "Malloc failed in lock_host_file()");
free(dd);
return(-1);
}
(void) strlcpy(lpath, lockdir, i);
if (lpath[strlen(lpath) - 1] != '/') {
lpath[strlen(lpath)] = '/';
lpath[strlen(lpath) + 1] = '\0';
}
if (strlcat(lpath, dd, i) >= i) {
syslog(LOG_CRIT, "Buffer overrun in lock_host_file(). SHOULD NOT HAPPEN!");
abort();
}
free(dd);
if ((fd = open(lpath, O_CREAT | O_WRONLY, 0600)) < 0) {
syslog(LOG_ERR, "Couldn't open/create lock file %s (%m)", lpath);
free(lpath);
return(-1);
}
#ifdef USE_LOCKF
if (lockf(fd, F_TLOCK, 0) != 0)
#else
if (flock(fd, LOCK_EX | LOCK_NB ) != 0)
#endif
{
syslog(LOG_DEBUG, "Can't get lock on %s.", lpath);
free(lpath);
close(fd);
return(-1);
}
if (ftruncate(fd, 0) < 0) {
syslog(LOG_ERR,
"Couldn't ftruncate fd %d for lock file %s (%m)",
fd, lpath);
free(lpath);
close(fd);
return(-1);
}
f = fdopen(fd, "w");
if (f == NULL) {
syslog(LOG_ERR, "Couldn't fopen fd %d for lock file %s (%m)",
fd, lpath);
free(lpath);
close(fd);
return(-1);
}
(void)fprintf(f, "%d\n", (int) getpid());
fflush(f);
free(lpath);
return(fd);
}
int
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) memset(&sin, 0, 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);
}
int
service()
{
struct sockaddr_in from;
int x, len;
again:
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"));
/* protection against ftp bounce attack */
if (from.sin_port == htons(20)) {
close(netfile);
goto again;
}
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);
}
int
serviceprep() /* kill temp socket in daemon */
{
if (sock >= 0) {
(void) close (sock);
sock = -1;
}
return (SCMOK);
}
int
servicekill() /* kill net file in daemon's parent */
{
if (netfile >= 0) {
(void) close(netfile);
netfile = -1;
}
if (remotename) {
free(remotename);
remotename = NULL;
}
return (SCMOK);
}
int
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 ***
***************************************************/
int dobackoff(t, b)
int *t, *b;
{
struct timeval tt;
unsigned s;
if (*t == 0)
return (0);
s = *b * 30;
if (gettimeofday(&tt, NULL) >= 0)
s += (tt.tv_usec >> 8) % s;
if (*b < 32)
*b <<= 1;
if (*t != -1) {
if (s > *t)
s = *t;
*t -= s;
}
if (!silent)
(void) scmerr(-1, "Will retry in %d seconds", s);
sleep(s);
return (1);
}
int
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));
if (!silent)
(void) scmerr (-1, "%s/tcp: unknown service: using port %d",
server, port);
} else
port = sp->s_port;
(void) memset(&sin, 0, 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) memcpy(&sin.sin_addr, h->h_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 = strdup(hostname);
x = 0x01020304;
(void) write (netfile, (char *)&x, sizeof(int));
swapmode = 0; /* swap only on server, not client */
return (SCMOK);
}
int
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,sizeof name) < 0)
return (NULL);
if ((h = gethostbyname(name)) == NULL)
return (NULL);
(void) strlcpy(name, h->h_name, sizeof name);
}
return (name);
}
char *
remotehost() /* remote host name (if known) */
{
struct hostent *h;
if (remotename == NULL) {
h = gethostbyaddr((char *)&remoteaddr, sizeof(remoteaddr),
AF_INET);
remotename = strdup(h ? h->h_name : inet_ntoa(remoteaddr));
if (remotename == NULL)
return("UNKNOWN");
}
return (remotename);
}
int
thishost(host)
char *host;
{
struct hostent *h;
char *name;
if ((name = myhost()) == NULL)
logquit (1, "Can't find my host entry '%s'", myhost());
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 (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) memcpy(&sin, &ifr->ifr_addr, 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 (memcmp(&remoteaddr, *ap, h->h_length) == 0)
return (1);
return (0);
}
int scmerr(int error,char *fmt,...)
{
va_list ap;
va_start(ap,fmt);
(void) fflush(stdout);
if (progpid > 0)
fprintf(stderr, "%s %d: ", program, progpid);
else
fprintf(stderr,"%s: ", program);
vfprintf(stderr, fmt, ap);
va_end(ap);
if (error >= 0)
fprintf(stderr, ": %s\n", errmsg(error));
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;
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);
}