diff options
author | Steve Price <steve@FreeBSD.org> | 1997-06-29 18:50:34 +0000 |
---|---|---|
committer | Steve Price <steve@FreeBSD.org> | 1997-06-29 18:50:34 +0000 |
commit | 0559b33149171859c5c0a8c618eede70e44da85d (patch) | |
tree | fba3b578a1c82b5af450b261897b86496f5a497c /libexec/rbootd | |
parent | e5d6c2c9e7f35dc0ba43408dcf39ddca2a374e0c (diff) | |
download | src-0559b33149171859c5c0a8c618eede70e44da85d.tar.gz src-0559b33149171859c5c0a8c618eede70e44da85d.zip |
Notes
Diffstat (limited to 'libexec/rbootd')
-rw-r--r-- | libexec/rbootd/Makefile | 8 | ||||
-rw-r--r-- | libexec/rbootd/bpf.c | 420 | ||||
-rw-r--r-- | libexec/rbootd/conf.c | 92 | ||||
-rw-r--r-- | libexec/rbootd/defs.h | 186 | ||||
-rw-r--r-- | libexec/rbootd/parseconf.c | 361 | ||||
-rw-r--r-- | libexec/rbootd/pathnames.h | 53 | ||||
-rw-r--r-- | libexec/rbootd/rbootd.8 | 158 | ||||
-rw-r--r-- | libexec/rbootd/rbootd.c | 449 | ||||
-rw-r--r-- | libexec/rbootd/rmp.h | 97 | ||||
-rw-r--r-- | libexec/rbootd/rmp_var.h | 246 | ||||
-rw-r--r-- | libexec/rbootd/rmpproto.c | 602 | ||||
-rw-r--r-- | libexec/rbootd/utils.c | 557 |
12 files changed, 3229 insertions, 0 deletions
diff --git a/libexec/rbootd/Makefile b/libexec/rbootd/Makefile new file mode 100644 index 000000000000..59d3137bb790 --- /dev/null +++ b/libexec/rbootd/Makefile @@ -0,0 +1,8 @@ +# from: @(#)Makefile 8.1 (Berkeley) 6/4/93 +# $NetBSD: Makefile,v 1.4 1995/08/21 17:05:08 thorpej Exp $ + +PROG= rbootd +SRCS= bpf.c conf.c parseconf.c rbootd.c rmpproto.c utils.c +MAN= rbootd.8 + +.include <bsd.prog.mk> diff --git a/libexec/rbootd/bpf.c b/libexec/rbootd/bpf.c new file mode 100644 index 000000000000..2ccf7da94590 --- /dev/null +++ b/libexec/rbootd/bpf.c @@ -0,0 +1,420 @@ +/* $NetBSD: bpf.c,v 1.7 1997/01/27 22:51:50 thorpej Exp $ */ + +/* + * Copyright (c) 1988, 1992 The University of Utah and the Center + * for Software Science (CSS). + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Center for Software Science of the University of Utah Computer + * Science Department. CSS requests users of this software to return + * to css-dist@cs.utah.edu any improvements that they make and grant + * CSS redistribution rights. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)bpf.c 8.1 (Berkeley) 6/4/93 + * + * From: Utah Hdr: bpf.c 3.1 92/07/06 + * Author: Jeff Forys, University of Utah CSS + */ + +#ifndef lint +/*static char sccsid[] = "@(#)bpf.c 8.1 (Berkeley) 6/4/93";*/ +static char rcsid[] = "$NetBSD: bpf.c,v 1.7 1997/01/27 22:51:50 thorpej Exp $"; +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/ioctl.h> +#include <sys/socket.h> + +#include <net/if.h> +#include <net/bpf.h> + +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <unistd.h> +#include "defs.h" +#include "pathnames.h" + +static int BpfFd = -1; +static unsigned BpfLen = 0; +static u_int8_t *BpfPkt = NULL; + +/* +** BpfOpen -- Open and initialize a BPF device. +** +** Parameters: +** None. +** +** Returns: +** File descriptor of opened BPF device (for select() etc). +** +** Side Effects: +** If an error is encountered, the program terminates here. +*/ +int +BpfOpen() +{ + struct ifreq ifr; + char bpfdev[32]; + int n = 0; + + /* + * Open the first available BPF device. + */ + do { + (void) sprintf(bpfdev, _PATH_BPF, n++); + BpfFd = open(bpfdev, O_RDWR); + } while (BpfFd < 0 && (errno == EBUSY || errno == EPERM)); + + if (BpfFd < 0) { + syslog(LOG_ERR, "bpf: no available devices: %m"); + Exit(0); + } + + /* + * Set interface name for bpf device, get data link layer + * type and make sure it's type Ethernet. + */ + (void) strncpy(ifr.ifr_name, IntfName, sizeof(ifr.ifr_name)); + if (ioctl(BpfFd, BIOCSETIF, (caddr_t)&ifr) < 0) { + syslog(LOG_ERR, "bpf: ioctl(BIOCSETIF,%s): %m", IntfName); + Exit(0); + } + + /* + * Make sure we are dealing with an Ethernet device. + */ + if (ioctl(BpfFd, BIOCGDLT, (caddr_t)&n) < 0) { + syslog(LOG_ERR, "bpf: ioctl(BIOCGDLT): %m"); + Exit(0); + } + if (n != DLT_EN10MB) { + syslog(LOG_ERR,"bpf: %s: data-link type %d unsupported", + IntfName, n); + Exit(0); + } + + /* + * On read(), return packets immediately (do not buffer them). + */ + n = 1; + if (ioctl(BpfFd, BIOCIMMEDIATE, (caddr_t)&n) < 0) { + syslog(LOG_ERR, "bpf: ioctl(BIOCIMMEDIATE): %m"); + Exit(0); + } + + /* + * Try to enable the chip/driver's multicast address filter to + * grab our RMP address. If this fails, try promiscuous mode. + * If this fails, there's no way we are going to get any RMP + * packets so just exit here. + */ +#ifdef MSG_EOR + ifr.ifr_addr.sa_len = RMP_ADDRLEN + 2; +#endif + ifr.ifr_addr.sa_family = AF_UNSPEC; + bcopy(&RmpMcastAddr[0], (char *)&ifr.ifr_addr.sa_data[0], RMP_ADDRLEN); + if (ioctl(BpfFd, BIOCPROMISC, (caddr_t)0) < 0) { + syslog(LOG_ERR, "bpf: can't set promiscuous mode: %m"); + Exit(0); + } + + /* + * Ask BPF how much buffer space it requires and allocate one. + */ + if (ioctl(BpfFd, BIOCGBLEN, (caddr_t)&BpfLen) < 0) { + syslog(LOG_ERR, "bpf: ioctl(BIOCGBLEN): %m"); + Exit(0); + } + if (BpfPkt == NULL) + BpfPkt = (u_int8_t *)malloc(BpfLen); + + if (BpfPkt == NULL) { + syslog(LOG_ERR, "bpf: out of memory (%u bytes for bpfpkt)", + BpfLen); + Exit(0); + } + + /* + * Write a little program to snarf RMP Boot packets and stuff + * it down BPF's throat (i.e. set up the packet filter). + */ + { +#define RMP ((struct rmp_packet *)0) + static struct bpf_insn bpf_insn[] = { + { BPF_LD|BPF_B|BPF_ABS, 0, 0, (long)&RMP->hp_llc.dsap }, + { BPF_JMP|BPF_JEQ|BPF_K, 0, 5, IEEE_DSAP_HP }, + { BPF_LD|BPF_H|BPF_ABS, 0, 0, (long)&RMP->hp_llc.cntrl }, + { BPF_JMP|BPF_JEQ|BPF_K, 0, 3, IEEE_CNTL_HP }, + { BPF_LD|BPF_H|BPF_ABS, 0, 0, (long)&RMP->hp_llc.dxsap }, + { BPF_JMP|BPF_JEQ|BPF_K, 0, 1, HPEXT_DXSAP }, + { BPF_RET|BPF_K, 0, 0, RMP_MAX_PACKET }, + { BPF_RET|BPF_K, 0, 0, 0x0 } + }; +#undef RMP + static struct bpf_program bpf_pgm = { + sizeof(bpf_insn)/sizeof(bpf_insn[0]), bpf_insn + }; + + if (ioctl(BpfFd, BIOCSETF, (caddr_t)&bpf_pgm) < 0) { + syslog(LOG_ERR, "bpf: ioctl(BIOCSETF): %m"); + Exit(0); + } + } + + return(BpfFd); +} + +/* +** BPF GetIntfName -- Return the name of a network interface attached to +** the system, or 0 if none can be found. The interface +** must be configured up; the lowest unit number is +** preferred; loopback is ignored. +** +** Parameters: +** errmsg - if no network interface found, *errmsg explains why. +** +** Returns: +** A (static) pointer to interface name, or NULL on error. +** +** Side Effects: +** None. +*/ +char * +BpfGetIntfName(errmsg) + char **errmsg; +{ + struct ifreq ibuf[8], *ifrp, *ifend, *mp; + struct ifconf ifc; + int fd; + int minunit, n; + char *cp; + static char device[sizeof(ifrp->ifr_name)]; + static char errbuf[128] = "No Error!"; + + if (errmsg != NULL) + *errmsg = errbuf; + + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + (void) strcpy(errbuf, "bpf: socket: %m"); + return(NULL); + } + ifc.ifc_len = sizeof ibuf; + ifc.ifc_buf = (caddr_t)ibuf; + +#ifdef OSIOCGIFCONF + if (ioctl(fd, OSIOCGIFCONF, (char *)&ifc) < 0 || + ifc.ifc_len < sizeof(struct ifreq)) { + (void) strcpy(errbuf, "bpf: ioctl(OSIOCGIFCONF): %m"); + return(NULL); + } +#else + if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 || + ifc.ifc_len < sizeof(struct ifreq)) { + (void) strcpy(errbuf, "bpf: ioctl(SIOCGIFCONF): %m"); + return(NULL); + } +#endif + ifrp = ibuf; + ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len); + + mp = 0; + minunit = 666; + for (; ifrp < ifend; ++ifrp) { + if (ioctl(fd, SIOCGIFFLAGS, (char *)ifrp) < 0) { + (void) strcpy(errbuf, "bpf: ioctl(SIOCGIFFLAGS): %m"); + return(NULL); + } + + /* + * If interface is down or this is the loopback interface, + * ignore it. + */ + if ((ifrp->ifr_flags & IFF_UP) == 0 || +#ifdef IFF_LOOPBACK + (ifrp->ifr_flags & IFF_LOOPBACK)) +#else + (strcmp(ifrp->ifr_name, "lo0") == 0)) +#endif + continue; + + for (cp = ifrp->ifr_name; !isdigit(*cp); ++cp) + ; + n = atoi(cp); + if (n < minunit) { + minunit = n; + mp = ifrp; + } + } + + (void) close(fd); + if (mp == 0) { + (void) strcpy(errbuf, "bpf: no interfaces found"); + return(NULL); + } + + (void) strcpy(device, mp->ifr_name); + return(device); +} + +/* +** BpfRead -- Read packets from a BPF device and fill in `rconn'. +** +** Parameters: +** rconn - filled in with next packet. +** doread - is True if we can issue a read() syscall. +** +** Returns: +** True if `rconn' contains a new packet, False otherwise. +** +** Side Effects: +** None. +*/ +int +BpfRead(rconn, doread) + RMPCONN *rconn; + int doread; +{ + register int datlen, caplen, hdrlen; + static u_int8_t *bp = NULL, *ep = NULL; + int cc; + + /* + * The read() may block, or it may return one or more packets. + * We let the caller decide whether or not we can issue a read(). + */ + if (doread) { + if ((cc = read(BpfFd, (char *)BpfPkt, (int)BpfLen)) < 0) { + syslog(LOG_ERR, "bpf: read: %m"); + return(0); + } else { + bp = BpfPkt; + ep = BpfPkt + cc; + } + } + +#define bhp ((struct bpf_hdr *)bp) + /* + * If there is a new packet in the buffer, stuff it into `rconn' + * and return a success indication. + */ + if (bp < ep) { + datlen = bhp->bh_datalen; + caplen = bhp->bh_caplen; + hdrlen = bhp->bh_hdrlen; + + if (caplen != datlen) + syslog(LOG_ERR, + "bpf: short packet dropped (%d of %d bytes)", + caplen, datlen); + else if (caplen > sizeof(struct rmp_packet)) + syslog(LOG_ERR, "bpf: large packet dropped (%d bytes)", + caplen); + else { + rconn->rmplen = caplen; + bcopy((char *)&bhp->bh_tstamp, (char *)&rconn->tstamp, + sizeof(struct timeval)); + bcopy((char *)bp + hdrlen, (char *)&rconn->rmp, caplen); + } + bp += BPF_WORDALIGN(caplen + hdrlen); + return(1); + } +#undef bhp + + return(0); +} + +/* +** BpfWrite -- Write packet to BPF device. +** +** Parameters: +** rconn - packet to send. +** +** Returns: +** True if write succeeded, False otherwise. +** +** Side Effects: +** None. +*/ +int +BpfWrite(rconn) + RMPCONN *rconn; +{ + if (write(BpfFd, (char *)&rconn->rmp, rconn->rmplen) < 0) { + syslog(LOG_ERR, "write: %s: %m", EnetStr(rconn)); + return(0); + } + + return(1); +} + +/* +** BpfClose -- Close a BPF device. +** +** Parameters: +** None. +** +** Returns: +** Nothing. +** +** Side Effects: +** None. +*/ +void +BpfClose() +{ + struct ifreq ifr; + + if (BpfPkt != NULL) { + free((char *)BpfPkt); + BpfPkt = NULL; + } + + if (BpfFd == -1) + return; + +#ifdef MSG_EOR + ifr.ifr_addr.sa_len = RMP_ADDRLEN + 2; +#endif + ifr.ifr_addr.sa_family = AF_UNSPEC; + bcopy(&RmpMcastAddr[0], (char *)&ifr.ifr_addr.sa_data[0], RMP_ADDRLEN); + if (ioctl(BpfFd, SIOCDELMULTI, (caddr_t)&ifr) < 0) + (void) ioctl(BpfFd, BIOCPROMISC, (caddr_t)0); + + (void) close(BpfFd); + BpfFd = -1; +} diff --git a/libexec/rbootd/conf.c b/libexec/rbootd/conf.c new file mode 100644 index 000000000000..51ad23bac5ca --- /dev/null +++ b/libexec/rbootd/conf.c @@ -0,0 +1,92 @@ +/* $NetBSD: conf.c,v 1.5 1995/10/06 05:12:13 thorpej Exp $ */ + +/* + * Copyright (c) 1988, 1992 The University of Utah and the Center + * for Software Science (CSS). + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Center for Software Science of the University of Utah Computer + * Science Department. CSS requests users of this software to return + * to css-dist@cs.utah.edu any improvements that they make and grant + * CSS redistribution rights. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)conf.c 8.1 (Berkeley) 6/4/93 + * + * From: Utah Hdr: conf.c 3.1 92/07/06 + * Author: Jeff Forys, University of Utah CSS + */ + +#ifndef lint +/*static char sccsid[] = "@(#)conf.c 8.1 (Berkeley) 6/4/93";*/ +static char rcsid[] = "$NetBSD: conf.c,v 1.5 1995/10/06 05:12:13 thorpej Exp $"; +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/time.h> + +#include <stdio.h> +#include "defs.h" +#include "pathnames.h" + +/* +** Define (and possibly initialize) global variables here. +** +** Caveat: +** The maximum number of bootable files (`char *BootFiles[]') is +** limited to C_MAXFILE (i.e. the maximum number of files that +** can be spec'd in the configuration file). This was done to +** simplify the boot file search code. +*/ + +char MyHost[MAXHOSTNAMELEN+1]; /* host name */ +pid_t MyPid; /* process id */ +int DebugFlg = 0; /* set true if debugging */ +int BootAny = 0; /* set true if we boot anyone */ + +char *ConfigFile = NULL; /* configuration file */ +char *DfltConfig = _PATH_RBOOTDCONF; /* default configuration file */ +char *PidFile = _PATH_RBOOTDPID; /* file w/pid of server */ +char *BootDir = _PATH_RBOOTDLIB; /* directory w/boot files */ +char *DbgFile = _PATH_RBOOTDDBG; /* debug output file */ + +FILE *DbgFp = NULL; /* debug file pointer */ +char *IntfName = NULL; /* intf we are attached to */ + +u_int16_t SessionID = 0; /* generated session ID */ + +char *BootFiles[C_MAXFILE]; /* list of boot files */ + +CLIENT *Clients = NULL; /* list of addrs we'll accept */ +RMPCONN *RmpConns = NULL; /* list of active connections */ + +u_int8_t RmpMcastAddr[RMP_ADDRLEN] = RMP_ADDR; /* RMP multicast address */ diff --git a/libexec/rbootd/defs.h b/libexec/rbootd/defs.h new file mode 100644 index 000000000000..9ff814e2c309 --- /dev/null +++ b/libexec/rbootd/defs.h @@ -0,0 +1,186 @@ +/* $NetBSD: defs.h,v 1.5 1995/10/06 05:12:14 thorpej Exp $ */ + +/* + * Copyright (c) 1988, 1992 The University of Utah and the Center + * for Software Science (CSS). + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Center for Software Science of the University of Utah Computer + * Science Department. CSS requests users of this software to return + * to css-dist@cs.utah.edu any improvements that they make and grant + * CSS redistribution rights. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)defs.h 8.1 (Berkeley) 6/4/93 + * + * From: Utah Hdr: defs.h 3.1 92/07/06 + * Author: Jeff Forys, University of Utah CSS + */ + +#include "rmp.h" +#include "rmp_var.h" + +/* +** Common #define's and external variables. All other files should +** include this. +*/ + +/* + * This may be defined in <sys/param.h>, if not, it's defined here. + */ +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 64 +#endif + +/* + * SIGUSR1 and SIGUSR2 are defined in <signal.h> for 4.3BSD systems. + */ +#ifndef SIGUSR1 +#define SIGUSR1 SIGEMT +#endif +#ifndef SIGUSR2 +#define SIGUSR2 SIGFPE +#endif + +/* + * These can be faster & more efficient than strcmp()/strncmp()... + */ +#define STREQN(s1,s2) ((*s1 == *s2) && (strcmp(s1,s2) == 0)) +#define STRNEQN(s1,s2,n) ((*s1 == *s2) && (strncmp(s1,s2,n) == 0)) + +/* + * Configuration file limitations. + */ +#define C_MAXFILE 10 /* max number of boot-able files */ +#define C_LINELEN 1024 /* max length of line */ + +/* + * Direction of packet (used as argument to DispPkt). + */ +#define DIR_RCVD 0 +#define DIR_SENT 1 +#define DIR_NONE 2 + +/* + * These need not be functions, so... + */ +#define FreeStr(str) free(str) +#define FreeClient(cli) free(cli) +#define GenSessID() (++SessionID ? SessionID: ++SessionID) + +/* + * Converting an Ethernet address to a string is done in many routines. + * Using `rmp.hp_hdr.saddr' works because this field is *never* changed; + * it will *always* contain the source address of the packet. + */ +#define EnetStr(rptr) GetEtherAddr(&(rptr)->rmp.hp_hdr.saddr[0]) + +/* + * Every machine we can boot will have one of these allocated for it + * (unless there are no restrictions on who we can boot). + */ +typedef struct client_s { + u_int8_t addr[RMP_ADDRLEN]; /* addr of machine */ + char *files[C_MAXFILE]; /* boot-able files */ + struct client_s *next; /* ptr to next */ +} CLIENT; + +/* + * Every active connection has one of these allocated for it. + */ +typedef struct rmpconn_s { + struct rmp_packet rmp; /* RMP packet */ + int rmplen; /* length of packet */ + struct timeval tstamp; /* last time active */ + int bootfd; /* open boot file */ + struct rmpconn_s *next; /* ptr to next */ +} RMPCONN; + +/* + * All these variables are defined in "conf.c". + */ +extern char MyHost[]; /* this hosts' name */ +extern pid_t MyPid; /* this processes' ID */ +extern int DebugFlg; /* set true if debugging */ +extern int BootAny; /* set true if we can boot anyone */ + +extern char *ConfigFile; /* configuration file */ +extern char *DfltConfig; /* default configuration file */ +extern char *DbgFile; /* debug output file */ +extern char *PidFile; /* file containing pid of server */ +extern char *BootDir; /* directory w/boot files */ + +extern FILE *DbgFp; /* debug file pointer */ +extern char *IntfName; /* interface we are attached to */ + +extern u_int16_t SessionID; /* generated session ID */ + +extern char *BootFiles[]; /* list of boot files */ + +extern CLIENT *Clients; /* list of addrs we'll accept */ +extern RMPCONN *RmpConns; /* list of active connections */ + +extern u_int8_t RmpMcastAddr[]; /* RMP multicast address */ + +void AddConn __P((RMPCONN *)); +int BootDone __P((RMPCONN *)); +void BpfClose __P((void)); +char *BpfGetIntfName __P((char **)); +int BpfOpen __P((void)); +int BpfRead __P((RMPCONN *, int)); +int BpfWrite __P((RMPCONN *)); +void DebugOff __P((int)); +void DebugOn __P((int)); +void DispPkt __P((RMPCONN *, int)); +void DoTimeout __P((void)); +void DspFlnm __P((u_int, char *)); +void Exit __P((int)); +CLIENT *FindClient __P((RMPCONN *)); +RMPCONN *FindConn __P((RMPCONN *)); +void FreeClients __P((void)); +void FreeConn __P((RMPCONN *)); +void FreeConns __P((void)); +int GetBootFiles __P((void)); +char *GetEtherAddr __P((u_int8_t *)); +CLIENT *NewClient __P((u_int8_t *)); +RMPCONN *NewConn __P((RMPCONN *)); +char *NewStr __P((char *)); +u_int8_t *ParseAddr __P((char *)); +int ParseConfig __P((void)); +void ProcessPacket __P((RMPCONN *, CLIENT *)); +void ReConfig __P((int)); +void RemoveConn __P((RMPCONN *)); +int SendBootRepl __P((struct rmp_packet *, RMPCONN *, char *[])); +int SendFileNo __P((struct rmp_packet *, RMPCONN *, char *[])); +int SendPacket __P((RMPCONN *)); +int SendReadRepl __P((RMPCONN *)); +int SendServerID __P((RMPCONN *)); diff --git a/libexec/rbootd/parseconf.c b/libexec/rbootd/parseconf.c new file mode 100644 index 000000000000..e96e9275d737 --- /dev/null +++ b/libexec/rbootd/parseconf.c @@ -0,0 +1,361 @@ +/* $NetBSD: parseconf.c,v 1.4 1995/10/06 05:12:16 thorpej Exp $ */ + +/* + * Copyright (c) 1988, 1992 The University of Utah and the Center + * for Software Science (CSS). + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Center for Software Science of the University of Utah Computer + * Science Department. CSS requests users of this software to return + * to css-dist@cs.utah.edu any improvements that they make and grant + * CSS redistribution rights. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)parseconf.c 8.1 (Berkeley) 6/4/93 + * + * From: Utah Hdr: parseconf.c 3.1 92/07/06 + * Author: Jeff Forys, University of Utah CSS + */ + +#ifndef lint +/*static char sccsid[] = "@(#)parseconf.c 8.1 (Berkeley) 6/4/93";*/ +static char rcsid[] = "$NetBSD: parseconf.c,v 1.4 1995/10/06 05:12:16 thorpej Exp $"; +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/stat.h> + +#include <ctype.h> +#include <dirent.h> +#include <fcntl.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include "defs.h" + +/* +** ParseConfig -- parse the config file into linked list of clients. +** +** Parameters: +** None. +** +** Returns: +** 1 on success, 0 otherwise. +** +** Side Effects: +** - Linked list of clients will be (re)allocated. +** +** Warnings: +** - GetBootFiles() must be called before this routine +** to create a linked list of default boot files. +*/ +int +ParseConfig() +{ + FILE *fp; + CLIENT *client; + u_int8_t *addr; + char line[C_LINELEN]; + register char *cp, *bcp; + register int i, j; + int omask, linecnt = 0; + + if (BootAny) /* ignore config file */ + return(1); + + FreeClients(); /* delete old list of clients */ + + if ((fp = fopen(ConfigFile, "r")) == NULL) { + syslog(LOG_ERR, "ParseConfig: can't open config file (%s)", + ConfigFile); + return(0); + } + + /* + * We've got to block SIGHUP to prevent reconfiguration while + * dealing with the linked list of Clients. This can be done + * when actually linking the new client into the list, but + * this could have unexpected results if the server was HUP'd + * whilst reconfiguring. Hence, it is done here. + */ + omask = sigblock(sigmask(SIGHUP)); + + /* + * GETSTR positions `bcp' at the start of the current token, + * and null terminates it. `cp' is positioned at the start + * of the next token. spaces & commas are separators. + */ +#define GETSTR while (isspace(*cp) || *cp == ',') cp++; \ + bcp = cp; \ + while (*cp && *cp!=',' && !isspace(*cp)) cp++; \ + if (*cp) *cp++ = '\0' + + /* + * For each line, parse it into a new CLIENT struct. + */ + while (fgets(line, C_LINELEN, fp) != NULL) { + linecnt++; /* line counter */ + + if (*line == '\0' || *line == '#') /* ignore comment */ + continue; + + if ((cp = index(line,'#')) != NULL) /* trash comments */ + *cp = '\0'; + + cp = line; /* init `cp' */ + GETSTR; /* get RMP addr */ + if (bcp == cp) /* all delimiters */ + continue; + + /* + * Get an RMP address from a string. Abort on failure. + */ + if ((addr = ParseAddr(bcp)) == NULL) { + syslog(LOG_ERR, + "ParseConfig: line %d: cant parse <%s>", + linecnt, bcp); + continue; + } + + if ((client = NewClient(addr)) == NULL) /* alloc new client */ + continue; + + GETSTR; /* get first file */ + + /* + * If no boot files are spec'd, use the default list. + * Otherwise, validate each file (`bcp') against the + * list of boot-able files. + */ + i = 0; + if (bcp == cp) /* no files spec'd */ + for (; i < C_MAXFILE && BootFiles[i] != NULL; i++) + client->files[i] = BootFiles[i]; + else { + do { + /* + * For each boot file spec'd, make sure it's + * in our list. If so, include a pointer to + * it in the CLIENT's list of boot files. + */ + for (j = 0; ; j++) { + if (j==C_MAXFILE||BootFiles[j]==NULL) { + syslog(LOG_ERR, "ParseConfig: line %d: no boot file (%s)", + linecnt, bcp); + break; + } + if (STREQN(BootFiles[j], bcp)) { + if (i < C_MAXFILE) + client->files[i++] = + BootFiles[j]; + else + syslog(LOG_ERR, "ParseConfig: line %d: too many boot files (%s)", + linecnt, bcp); + break; + } + } + GETSTR; /* get next file */ + } while (bcp != cp); + + /* + * Restricted list of boot files were spec'd, + * however, none of them were found. Since we + * apparently cant let them boot "just anything", + * the entire record is invalidated. + */ + if (i == 0) { + FreeClient(client); + continue; + } + } + + /* + * Link this client into the linked list of clients. + * SIGHUP has already been blocked. + */ + if (Clients) + client->next = Clients; + Clients = client; + } + + (void) fclose(fp); /* close config file */ + + (void) sigsetmask(omask); /* reset signal mask */ + + return(1); /* return success */ +} + +/* +** ParseAddr -- Parse a string containing an RMP address. +** +** This routine is fairly liberal at parsing an RMP address. The +** address must contain 6 octets consisting of between 0 and 2 hex +** chars (upper/lower case) separated by colons. If two colons are +** together (e.g. "::", the octet between them is recorded as being +** zero. Hence, the following addrs are all valid and parse to the +** same thing: +** +** 08:00:09:00:66:ad 8::9:0:66:AD 8::9::66:aD +** +** For clarity, an RMP address is really an Ethernet address, but +** since the HP boot code uses IEEE 802.3, it's really an IEEE +** 802.3 address. Of course, all of these are identical. +** +** Parameters: +** str - string representation of an RMP address. +** +** Returns: +** pointer to a static array of RMP_ADDRLEN bytes. +** +** Side Effects: +** None. +** +** Warnings: +** - The return value points to a static buffer; it must +** be copied if it's to be saved. +*/ +u_int8_t * +ParseAddr(str) + char *str; +{ + static u_int8_t addr[RMP_ADDRLEN]; + register char *cp; + register unsigned i; + register int part, subpart; + + bzero((char *)&addr[0], RMP_ADDRLEN); /* zero static buffer */ + + part = subpart = 0; + for (cp = str; *cp; cp++) { + /* + * A colon (`:') must be used to delimit each octet. + */ + if (*cp == ':') { + if (++part == RMP_ADDRLEN) /* too many parts */ + return(NULL); + subpart = 0; + continue; + } + + /* + * Convert hex character to an integer. + */ + if (isdigit(*cp)) + i = *cp - '0'; + else { + i = (isupper(*cp)? tolower(*cp): *cp) - 'a' + 10; + if (i < 10 || i > 15) /* not a hex char */ + return(NULL); + } + + if (subpart++) { + if (subpart > 2) /* too many hex chars */ + return(NULL); + addr[part] <<= 4; + } + addr[part] |= i; + } + + if (part != (RMP_ADDRLEN-1)) /* too few parts */ + return(NULL); + + return(&addr[0]); +} + +/* +** GetBootFiles -- record list of files in current (boot) directory. +** +** Parameters: +** None. +** +** Returns: +** Number of boot files on success, 0 on failure. +** +** Side Effects: +** Strings in `BootFiles' are freed/allocated. +** +** Warnings: +** - After this routine is called, ParseConfig() must be +** called to re-order it's list of boot file pointers. +*/ +int +GetBootFiles() +{ + DIR *dfd; + struct stat statb; + register struct dirent *dp; + register int i; + + /* + * Free the current list of boot files. + */ + for (i = 0; i < C_MAXFILE && BootFiles[i] != NULL; i++) { + FreeStr(BootFiles[i]); + BootFiles[i] = NULL; + } + + /* + * Open current directory to read boot file names. + */ + if ((dfd = opendir(".")) == NULL) { /* open BootDir */ + syslog(LOG_ERR, "GetBootFiles: can't open directory (%s)\n", + BootDir); + return(0); + } + + /* + * Read each boot file name and allocate space for it in the + * list of boot files (BootFiles). All boot files read after + * C_MAXFILE will be ignored. + */ + i = 0; + for (dp = readdir(dfd); dp != NULL; dp = readdir(dfd)) { + if (stat(dp->d_name, &statb) < 0 || + (statb.st_mode & S_IFMT) != S_IFREG) + continue; + if (i == C_MAXFILE) + syslog(LOG_ERR, + "GetBootFiles: too many boot files (%s ignored)", + dp->d_name); + else if ((BootFiles[i] = NewStr(dp->d_name)) != NULL) + i++; + } + + (void) closedir(dfd); /* close BootDir */ + + if (i == 0) /* cant find any boot files */ + syslog(LOG_ERR, "GetBootFiles: no boot files (%s)\n", BootDir); + + return(i); +} diff --git a/libexec/rbootd/pathnames.h b/libexec/rbootd/pathnames.h new file mode 100644 index 000000000000..381864abc45c --- /dev/null +++ b/libexec/rbootd/pathnames.h @@ -0,0 +1,53 @@ +/* $NetBSD: pathnames.h,v 1.3 1995/08/21 17:05:15 thorpej Exp $ */ + +/* + * Copyright (c) 1988, 1992 The University of Utah and the Center + * for Software Science (CSS). + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Center for Software Science of the University of Utah Computer + * Science Department. CSS requests users of this software to return + * to css-dist@cs.utah.edu any improvements that they make and grant + * CSS redistribution rights. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)pathnames.h 8.1 (Berkeley) 6/4/93 + * + * From: Utah Hdr: pathnames.h 3.1 92/07/06 + * Author: Jeff Forys, University of Utah CSS + */ + +#define _PATH_BPF "/dev/bpf%d" +#define _PATH_RBOOTDCONF "/etc/rbootd.conf" +#define _PATH_RBOOTDDBG "/tmp/rbootd.dbg" +#define _PATH_RBOOTDLIB "/usr/mdec/rbootd" +#define _PATH_RBOOTDPID "/var/run/rbootd.pid" diff --git a/libexec/rbootd/rbootd.8 b/libexec/rbootd/rbootd.8 new file mode 100644 index 000000000000..3b783bb77516 --- /dev/null +++ b/libexec/rbootd/rbootd.8 @@ -0,0 +1,158 @@ +.\" $NetBSD: rbootd.8,v 1.4 1997/05/29 01:48:46 cgd Exp $ +.\" +.\" Copyright (c) 1988, 1992 The University of Utah and the Center +.\" for Software Science (CSS). +.\" Copyright (c) 1992, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the Center for Software Science of the University of Utah Computer +.\" Science Department. CSS requests users of this software to return +.\" to css-dist@cs.utah.edu any improvements that they make and grant +.\" CSS redistribution rights. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" from: @(#)rbootd.8 8.2 (Berkeley) 12/11/93 +.\" +.\" Utah Hdr: rbootd.man 3.1 92/07/06 +.\" Author: Jeff Forys, University of Utah CSS +.\" +.Dd December 11, 1993 +.Dt RBOOTD 8 +.Os +.Sh NAME +.Nm rbootd +.Nd HP remote boot server +.Sh SYNOPSIS +.Nm rbootd +.Op Fl ad +.Op Fl i Ar interface +.Op config_file +.Sh DESCRIPTION +The +.Nm rbootd +utility services boot requests from Hewlett-Packard workstations over a +local area network. +All boot files must reside in the boot file directory; further, if a +client supplies path information in its boot request, it will be silently +stripped away before processing. +By default, +.Nm rbootd +only responds to requests from machines listed in its configuration file. +.Pp +The options are as follows: +.Bl -tag -width Fl +.It Fl a +Respond to boot requests from any machine. +The configuration file is ignored if this option is specified. +.It Fl d +Run +.Nm rbootd +in debug mode. +Packets sent and received are displayed to the terminal. +.It Fl i Ar interface +Service boot requests on specified interface. +If unspecified, +.Nm rbootd +searches the system interface list for the lowest numbered, configured +``up'' interface (excluding loopback). +Ties are broken by choosing the earliest match. +.El +.Pp +Specifying +.Ar config_file +on the command line causes +.Nm rbootd +to use a different configuration file from the default. +.Pp +The configuration file is a text file where each line describes a particular +machine. +A line must start with a machine's Ethernet address followed by an optional +list of boot file names. +An Ethernet address is specified in hexadecimal with each of its six octets +separated by a colon. +The boot file names come from the boot file directory. +The ethernet address and boot file(s) must be separated by white-space +and/or comma characters. +A pound sign causes the remainder of a line to be ignored. +.Pp +Here is a sample configuration file: +.Bl -column 08:00:09:0:66:ad SYSHPBSD,SYSHPUX "# vandy (anything)" +.It # +.It # ethernet addr boot file(s) comments +.It # +.It 08:00:09:0:66:ad SYSHPBSD # snake (4.3BSD) +.It 08:00:09:0:59:5b # vandy (anything) +.It 8::9:1:C6:75 SYSHPBSD,SYSHPUX # jaguar (either) +.El +.Pp +.Nm Rbootd +logs status and error messages via +.Xr syslog 3 . +A startup message is always logged, and in the case of fatal errors (or +deadly signals) a message is logged announcing the server's termination. +In general, a non-fatal error is handled by ignoring the event that caused +it (e.g. an invalid Ethernet address in the config file causes that line +to be invalidated). +.Pp +The following signals have the specified effect when sent to the server +process using the +.Xr kill 1 +command: +.Bl -tag -width SIGUSR1 -offset -compact +.It SIGHUP +Drop all active connections and reconfigure. +.It SIGUSR1 +Turn on debugging, do nothing if already on. +.It SIGUSR2 +Turn off debugging, do nothing if already off. +.El +.Sh "FILES" +.Bl -tag -width /usr/libexec/rbootd -compact +.It /dev/bpf# +packet-filter device +.It /etc/rbootd.conf +configuration file +.It /tmp/rbootd.dbg +debug output +.It /usr/mdec/rbootd +directory containing boot files +.It /var/run/rbootd.pid +process id +.El +.Sh SEE ALSO +.Xr kill 1 , +.Xr socket 2 , +.Xr signal 3 , +.Xr syslog 3 , +.Xr rmp 4 +.Sh BUGS +If multiple servers are started on the same interface, each will receive +and respond to the same boot packets. diff --git a/libexec/rbootd/rbootd.c b/libexec/rbootd/rbootd.c new file mode 100644 index 000000000000..11d5445911ac --- /dev/null +++ b/libexec/rbootd/rbootd.c @@ -0,0 +1,449 @@ +/* $NetBSD: rbootd.c,v 1.5 1995/10/06 05:12:17 thorpej Exp $ */ + +/* + * Copyright (c) 1988, 1992 The University of Utah and the Center + * for Software Science (CSS). + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Center for Software Science of the University of Utah Computer + * Science Department. CSS requests users of this software to return + * to css-dist@cs.utah.edu any improvements that they make and grant + * CSS redistribution rights. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)rbootd.c 8.1 (Berkeley) 6/4/93 + * + * From: Utah Hdr: rbootd.c 3.1 92/07/06 + * Author: Jeff Forys, University of Utah CSS + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1992, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +/*static char sccsid[] = "@(#)rbootd.c 8.1 (Berkeley) 6/4/93";*/ +static char rcsid[] = "$NetBSD: rbootd.c,v 1.5 1995/10/06 05:12:17 thorpej Exp $"; +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/time.h> +#include <ctype.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <unistd.h> +#include "defs.h" + +extern char *__progname; /* from crt0.o */ + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int c, fd, omask, maxfds; + fd_set rset; + + /* + * Close any open file descriptors. + * Temporarily leave stdin & stdout open for `-d', + * and stderr open for any pre-syslog error messages. + */ + { + int i, nfds = getdtablesize(); + + for (i = 0; i < nfds; i++) + if (i != fileno(stdin) && i != fileno(stdout) && + i != fileno(stderr)) + (void) close(i); + } + + /* + * Parse any arguments. + */ + while ((c = getopt(argc, argv, "adi:")) != EOF) + switch(c) { + case 'a': + BootAny++; + break; + case 'd': + DebugFlg++; + break; + case 'i': + IntfName = optarg; + break; + } + for (; optind < argc; optind++) { + if (ConfigFile == NULL) + ConfigFile = argv[optind]; + else { + warnx("too many config files (`%s' ignored)\n", + argv[optind]); + } + } + + if (ConfigFile == NULL) /* use default config file */ + ConfigFile = DfltConfig; + + if (DebugFlg) { + DbgFp = stdout; /* output to stdout */ + + (void) signal(SIGUSR1, SIG_IGN); /* dont muck w/DbgFp */ + (void) signal(SIGUSR2, SIG_IGN); + (void) fclose(stderr); /* finished with it */ + } else { + if (daemon(0, 0)) + err(1, "can't detach from terminal"); + + (void) signal(SIGUSR1, DebugOn); + (void) signal(SIGUSR2, DebugOff); + } + + openlog(__progname, LOG_PID, LOG_DAEMON); + + /* + * If no interface was specified, get one now. + * + * This is convoluted because we want to get the default interface + * name for the syslog("restarted") message. If BpfGetIntfName() + * runs into an error, it will return a syslog-able error message + * (in `errmsg') which will be displayed here. + */ + if (IntfName == NULL) { + char *errmsg; + + if ((IntfName = BpfGetIntfName(&errmsg)) == NULL) { + syslog(LOG_NOTICE, "restarted (??)"); + syslog(LOG_ERR, errmsg); + Exit(0); + } + } + + syslog(LOG_NOTICE, "restarted (%s)", IntfName); + + (void) signal(SIGHUP, ReConfig); + (void) signal(SIGINT, Exit); + (void) signal(SIGTERM, Exit); + + /* + * Grab our host name and pid. + */ + if (gethostname(MyHost, MAXHOSTNAMELEN) < 0) { + syslog(LOG_ERR, "gethostname: %m"); + Exit(0); + } + MyHost[MAXHOSTNAMELEN] = '\0'; + + MyPid = getpid(); + + /* + * Write proc's pid to a file. + */ + { + FILE *fp; + + if ((fp = fopen(PidFile, "w")) != NULL) { + (void) fprintf(fp, "%d\n", (int) MyPid); + (void) fclose(fp); + } else { + syslog(LOG_WARNING, "fopen: failed (%s)", PidFile); + } + } + + /* + * All boot files are relative to the boot directory, we might + * as well chdir() there to make life easier. + */ + if (chdir(BootDir) < 0) { + syslog(LOG_ERR, "chdir: %m (%s)", BootDir); + Exit(0); + } + + /* + * Initial configuration. + */ + omask = sigblock(sigmask(SIGHUP)); /* prevent reconfig's */ + if (GetBootFiles() == 0) /* get list of boot files */ + Exit(0); + if (ParseConfig() == 0) /* parse config file */ + Exit(0); + + /* + * Open and initialize a BPF device for the appropriate interface. + * If an error is encountered, a message is displayed and Exit() + * is called. + */ + fd = BpfOpen(); + + (void) sigsetmask(omask); /* allow reconfig's */ + + /* + * Main loop: receive a packet, determine where it came from, + * and if we service this host, call routine to handle request. + */ + maxfds = fd + 1; + FD_ZERO(&rset); + FD_SET(fd, &rset); + for (;;) { + struct timeval timeout; + fd_set r; + int nsel; + + r = rset; + + if (RmpConns == NULL) { /* timeout isnt necessary */ + nsel = select(maxfds, &r, NULL, NULL, NULL); + } else { + timeout.tv_sec = RMP_TIMEOUT; + timeout.tv_usec = 0; + nsel = select(maxfds, &r, NULL, NULL, &timeout); + } + + if (nsel < 0) { + if (errno == EINTR) + continue; + syslog(LOG_ERR, "select: %m"); + Exit(0); + } else if (nsel == 0) { /* timeout */ + DoTimeout(); /* clear stale conns */ + continue; + } + + if (FD_ISSET(fd, &r)) { + RMPCONN rconn; + CLIENT *client, *FindClient(); + int doread = 1; + + while (BpfRead(&rconn, doread)) { + doread = 0; + + if (DbgFp != NULL) /* display packet */ + DispPkt(&rconn,DIR_RCVD); + + omask = sigblock(sigmask(SIGHUP)); + + /* + * If we do not restrict service, set the + * client to NULL (ProcessPacket() handles + * this). Otherwise, check that we can + * service this host; if not, log a message + * and ignore the packet. + */ + if (BootAny) { + client = NULL; + } else if ((client=FindClient(&rconn))==NULL) { + syslog(LOG_INFO, + "%s: boot packet ignored", + EnetStr(&rconn)); + (void) sigsetmask(omask); + continue; + } + + ProcessPacket(&rconn,client); + + (void) sigsetmask(omask); + } + } + } +} + +/* +** DoTimeout -- Free any connections that have timed out. +** +** Parameters: +** None. +** +** Returns: +** Nothing. +** +** Side Effects: +** - Timed out connections in `RmpConns' will be freed. +*/ +void +DoTimeout() +{ + register RMPCONN *rtmp; + struct timeval now; + + (void) gettimeofday(&now, (struct timezone *)0); + + /* + * For each active connection, if RMP_TIMEOUT seconds have passed + * since the last packet was sent, delete the connection. + */ + for (rtmp = RmpConns; rtmp != NULL; rtmp = rtmp->next) + if ((rtmp->tstamp.tv_sec + RMP_TIMEOUT) < now.tv_sec) { + syslog(LOG_WARNING, "%s: connection timed out (%u)", + EnetStr(rtmp), rtmp->rmp.r_type); + RemoveConn(rtmp); + } +} + +/* +** FindClient -- Find client associated with a packet. +** +** Parameters: +** rconn - the new packet. +** +** Returns: +** Pointer to client info if found, NULL otherwise. +** +** Side Effects: +** None. +** +** Warnings: +** - This routine must be called with SIGHUP blocked since +** a reconfigure can invalidate the information returned. +*/ + +CLIENT * +FindClient(rconn) + register RMPCONN *rconn; +{ + register CLIENT *ctmp; + + for (ctmp = Clients; ctmp != NULL; ctmp = ctmp->next) + if (bcmp((char *)&rconn->rmp.hp_hdr.saddr[0], + (char *)&ctmp->addr[0], RMP_ADDRLEN) == 0) + break; + + return(ctmp); +} + +/* +** Exit -- Log an error message and exit. +** +** Parameters: +** sig - caught signal (or zero if not dying on a signal). +** +** Returns: +** Does not return. +** +** Side Effects: +** - This process ceases to exist. +*/ +void +Exit(sig) + int sig; +{ + if (sig > 0) + syslog(LOG_ERR, "going down on signal %d", sig); + else + syslog(LOG_ERR, "going down with fatal error"); + BpfClose(); + exit(1); +} + +/* +** ReConfig -- Get new list of boot files and reread config files. +** +** Parameters: +** None. +** +** Returns: +** Nothing. +** +** Side Effects: +** - All active connections are dropped. +** - List of boot-able files is changed. +** - List of clients is changed. +** +** Warnings: +** - This routine must be called with SIGHUP blocked. +*/ +void +ReConfig(signo) + int signo; +{ + syslog(LOG_NOTICE, "reconfiguring boot server"); + + FreeConns(); + + if (GetBootFiles() == 0) + Exit(0); + + if (ParseConfig() == 0) + Exit(0); +} + +/* +** DebugOff -- Turn off debugging. +** +** Parameters: +** None. +** +** Returns: +** Nothing. +** +** Side Effects: +** - Debug file is closed. +*/ +void +DebugOff(signo) + int signo; +{ + if (DbgFp != NULL) + (void) fclose(DbgFp); + + DbgFp = NULL; +} + +/* +** DebugOn -- Turn on debugging. +** +** Parameters: +** None. +** +** Returns: +** Nothing. +** +** Side Effects: +** - Debug file is opened/truncated if not already opened, +** otherwise do nothing. +*/ +void +DebugOn(signo) + int signo; +{ + if (DbgFp == NULL) { + if ((DbgFp = fopen(DbgFile, "w")) == NULL) + syslog(LOG_ERR, "can't open debug file (%s)", DbgFile); + } +} diff --git a/libexec/rbootd/rmp.h b/libexec/rbootd/rmp.h new file mode 100644 index 000000000000..4a686ef2b451 --- /dev/null +++ b/libexec/rbootd/rmp.h @@ -0,0 +1,97 @@ +/* $NetBSD: rmp.h,v 1.4 1995/10/06 05:12:18 thorpej Exp $ */ + +/* + * Copyright (c) 1988, 1992 The University of Utah and the Center + * for Software Science (CSS). + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Center for Software Science of the University of Utah Computer + * Science Department. CSS requests users of this software to return + * to css-dist@cs.utah.edu any improvements that they make and grant + * CSS redistribution rights. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)rmp.h 8.1 (Berkeley) 6/4/93 + * + * From: Utah Hdr: rmp.h 3.1 92/07/06 + * Author: Jeff Forys, University of Utah CSS + */ + +/* + * Define MIN/MAX sizes of RMP (ethernet) packet. + * For ease of computation, the 4 octet CRC field is not included. + * + * MCLBYTES is for bpfwrite(); it is adamant about using a cluster. + */ + +#define RMP_MAX_PACKET MIN(1514,MCLBYTES) +#define RMP_MIN_PACKET 60 + +/* + * Define RMP/Ethernet Multicast address (9:0:9:0:0:4) and its length. + */ +#define RMP_ADDR { 0x9, 0x0, 0x9, 0x0, 0x0, 0x4 } +#define RMP_ADDRLEN 6 + +/* + * Define IEEE802.2 (Logical Link Control) information. + */ +#define IEEE_DSAP_HP 0xF8 /* Destination Service Access Point */ +#define IEEE_SSAP_HP 0xF8 /* Source Service Access Point */ +#define IEEE_CNTL_HP 0x0300 /* Type 1 / I format control information */ + +#define HPEXT_DXSAP 0x608 /* HP Destination Service Access Point */ +#define HPEXT_SXSAP 0x609 /* HP Source Service Access Point */ + +/* + * 802.3-style "Ethernet" header. + */ + +struct hp_hdr { + u_int8_t daddr[RMP_ADDRLEN]; + u_int8_t saddr[RMP_ADDRLEN]; + u_int16_t len; +}; + +/* + * HP uses 802.2 LLC with their own local extensions. This struct makes + * sense out of this data (encapsulated in the above 802.3 packet). + */ + +struct hp_llc { + u_int8_t dsap; /* 802.2 DSAP */ + u_int8_t ssap; /* 802.2 SSAP */ + u_int16_t cntrl; /* 802.2 control field */ + u_int16_t filler; /* HP filler (must be zero) */ + u_int16_t dxsap; /* HP extended DSAP */ + u_int16_t sxsap; /* HP extended SSAP */ +}; diff --git a/libexec/rbootd/rmp_var.h b/libexec/rbootd/rmp_var.h new file mode 100644 index 000000000000..c60b6ddf3637 --- /dev/null +++ b/libexec/rbootd/rmp_var.h @@ -0,0 +1,246 @@ +/* $NetBSD: rmp_var.h,v 1.8 1995/11/14 08:41:44 thorpej Exp $ */ + +/* + * Copyright (c) 1988, 1992 The University of Utah and the Center + * for Software Science (CSS). + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Center for Software Science of the University of Utah Computer + * Science Department. CSS requests users of this software to return + * to css-dist@cs.utah.edu any improvements that they make and grant + * CSS redistribution rights. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)rmp_var.h 8.1 (Berkeley) 6/4/93 + * + * from: Utah Hdr: rmp_var.h 3.1 92/07/06 + * Author: Jeff Forys, University of Utah CSS + */ + +/* + * Possible values for "rmp_type" fields. + */ + +#define RMP_BOOT_REQ 1 /* boot request packet */ +#define RMP_BOOT_REPL 129 /* boot reply packet */ +#define RMP_READ_REQ 2 /* read request packet */ +#define RMP_READ_REPL 130 /* read reply packet */ +#define RMP_BOOT_DONE 3 /* boot complete packet */ + +/* + * Useful constants. + */ + +#define RMP_VERSION 2 /* protocol version */ +#define RMP_TIMEOUT 600 /* timeout connection after ten minutes */ +#define RMP_PROBESID 0xffff /* session ID for probes */ +#define RMP_HOSTLEN 13 /* max length of server's name */ +#define RMP_MACHLEN 20 /* length of machine type field */ + +/* + * RMP error codes + */ + +#define RMP_E_OKAY 0 +#define RMP_E_EOF 2 /* read reply: returned end of file */ +#define RMP_E_ABORT 3 /* abort operation */ +#define RMP_E_BUSY 4 /* boot reply: server busy */ +#define RMP_E_TIMEOUT 5 /* lengthen time out (not implemented) */ +#define RMP_E_NOFILE 16 /* boot reply: file does not exist */ +#define RMP_E_OPENFILE 17 /* boot reply: file open failed */ +#define RMP_E_NODFLT 18 /* boot reply: default file does not exist */ +#define RMP_E_OPENDFLT 19 /* boot reply: default file open failed */ +#define RMP_E_BADSID 25 /* read reply: bad session ID */ +#define RMP_E_BADPACKET 27 /* Bad packet detected */ + +/* + * RMPDATALEN is the maximum number of data octets that can be stuffed + * into an RMP packet. This excludes the 802.2 LLC w/HP extensions. + */ +#define RMPDATALEN (RMP_MAX_PACKET - (sizeof(struct hp_hdr) + \ + sizeof(struct hp_llc))) + +/* + * Define sizes of packets we send. Boot and Read replies are variable + * in length depending on the length of `s'. + * + * Also, define how much space `restofpkt' can take up for outgoing + * Boot and Read replies. Boot Request packets are effectively + * limited to 255 bytes due to the preceding 1-byte length field. + */ + +#define RMPBOOTSIZE(s) (sizeof(struct hp_hdr) + sizeof(struct hp_llc) + \ + sizeof(struct rmp_boot_repl) + s - sizeof(restofpkt)) +#define RMPREADSIZE(s) (sizeof(struct hp_hdr) + sizeof(struct hp_llc) + \ + sizeof(struct rmp_read_repl) + s - sizeof(restofpkt) \ + - sizeof(u_int8_t)) +#define RMPDONESIZE (sizeof(struct hp_hdr) + sizeof(struct hp_llc) + \ + sizeof(struct rmp_boot_done)) +#define RMPBOOTDATA 255 +#define RMPREADDATA (RMPDATALEN - \ + (2*sizeof(u_int8_t)+sizeof(u_int16_t)+sizeof(u_word))) + +/* + * This protocol defines some field sizes as "rest of ethernet packet". + * There is no easy way to specify this in C, so we use a one character + * field to denote it, and index past it to the end of the packet. + */ + +typedef char restofpkt; + +/* + * Due to the RMP packet layout, we'll run into alignment problems + * on machines that can't access (or don't, by default, align) words + * on half-word boundaries. If you know that your machine does not suffer + * from this problem, add it to the vax/tahoe/m68k #define below. + * + * The following macros are used to deal with this problem: + * WORDZE(w) Return True if u_word `w' is zero, False otherwise. + * ZEROWORD(w) Set u_word `w' to zero. + * COPYWORD(w1,w2) Copy u_word `w1' to `w2'. + * GETWORD(w,i) Copy u_word `w' into int `i'. + * PUTWORD(i,w) Copy int `i' into u_word `w'. + * + * N.B. Endianness is handled by use of ntohl/htonl + */ +#if defined(__vax__) || defined(__tahoe__) || defined(__m68k__) + +typedef u_int32_t u_word; + +#define WORDZE(w) ((w) == 0) +#define ZEROWORD(w) (w) = 0 +#define COPYWORD(w1,w2) (w2) = (w1) +#define GETWORD(w, i) (i) = ntohl(w) +#define PUTWORD(i, w) (w) = htonl(i) + +#else + +#define _WORD_HIGHPART 0 +#define _WORD_LOWPART 1 + +typedef struct _uword { u_int16_t val[2]; } u_word; + +#define WORDZE(w) \ + ((w.val[_WORD_HIGHPART] == 0) && (w.val[_WORD_LOWPART] == 0)) +#define ZEROWORD(w) \ + (w).val[_WORD_HIGHPART] = (w).val[_WORD_LOWPART] = 0 +#define COPYWORD(w1, w2) \ + { (w2).val[_WORD_HIGHPART] = (w1).val[_WORD_HIGHPART]; \ + (w2).val[_WORD_LOWPART] = (w1).val[_WORD_LOWPART]; \ + } +#define GETWORD(w, i) \ + (i) = (((u_int32_t)ntohs((w).val[_WORD_HIGHPART])) << 16) | ntohs((w).val[_WORD_LOWPART]) +#define PUTWORD(i, w) \ + { (w).val[_WORD_HIGHPART] = htons((u_int16_t) ((i >> 16) & 0xffff)); \ + (w).val[_WORD_LOWPART] = htons((u_int16_t) (i & 0xffff)); \ + } + +#endif + +/* + * Packet structures. + */ + +struct rmp_raw { /* generic RMP packet */ + u_int8_t rmp_type; /* packet type */ + u_int8_t rmp_rawdata[RMPDATALEN-1]; +}; + +struct rmp_boot_req { /* boot request */ + u_int8_t rmp_type; /* packet type (RMP_BOOT_REQ) */ + u_int8_t rmp_retcode; /* return code (0) */ + u_word rmp_seqno; /* sequence number (real time clock) */ + u_int16_t rmp_session; /* session id (normally 0) */ + u_int16_t rmp_version; /* protocol version (RMP_VERSION) */ + char rmp_machtype[RMP_MACHLEN]; /* machine type */ + u_int8_t rmp_flnmsize; /* length of rmp_flnm */ + restofpkt rmp_flnm; /* name of file to be read */ +}; + +struct rmp_boot_repl { /* boot reply */ + u_int8_t rmp_type; /* packet type (RMP_BOOT_REPL) */ + u_int8_t rmp_retcode; /* return code (normally 0) */ + u_word rmp_seqno; /* sequence number (from boot req) */ + u_int16_t rmp_session; /* session id (generated) */ + u_int16_t rmp_version; /* protocol version (RMP_VERSION) */ + u_int8_t rmp_flnmsize; /* length of rmp_flnm */ + restofpkt rmp_flnm; /* name of file (from boot req) */ +}; + +struct rmp_read_req { /* read request */ + u_int8_t rmp_type; /* packet type (RMP_READ_REQ) */ + u_int8_t rmp_retcode; /* return code (0) */ + u_word rmp_offset; /* file relative byte offset */ + u_int16_t rmp_session; /* session id (from boot repl) */ + u_int16_t rmp_size; /* max no of bytes to send */ +}; + +struct rmp_read_repl { /* read reply */ + u_int8_t rmp_type; /* packet type (RMP_READ_REPL) */ + u_int8_t rmp_retcode; /* return code (normally 0) */ + u_word rmp_offset; /* byte offset (from read req) */ + u_int16_t rmp_session; /* session id (from read req) */ + restofpkt rmp_data; /* data (max size from read req) */ + u_int8_t rmp_unused; /* padding to 16-bit boundary */ +}; + +struct rmp_boot_done { /* boot complete */ + u_int8_t rmp_type; /* packet type (RMP_BOOT_DONE) */ + u_int8_t rmp_retcode; /* return code (0) */ + u_word rmp_unused; /* not used (0) */ + u_int16_t rmp_session; /* session id (from read repl) */ +}; + +struct rmp_packet { + struct hp_hdr hp_hdr; + struct hp_llc hp_llc; + union { + struct rmp_boot_req rmp_brq; /* boot request */ + struct rmp_boot_repl rmp_brpl; /* boot reply */ + struct rmp_read_req rmp_rrq; /* read request */ + struct rmp_read_repl rmp_rrpl; /* read reply */ + struct rmp_boot_done rmp_done; /* boot complete */ + struct rmp_raw rmp_raw; /* raw data */ + } rmp_proto; +}; + +/* + * Make life easier... + */ + +#define r_type rmp_proto.rmp_raw.rmp_type +#define r_data rmp_proto.rmp_raw.rmp_rawdata +#define r_brq rmp_proto.rmp_brq +#define r_brpl rmp_proto.rmp_brpl +#define r_rrq rmp_proto.rmp_rrq +#define r_rrpl rmp_proto.rmp_rrpl +#define r_done rmp_proto.rmp_done diff --git a/libexec/rbootd/rmpproto.c b/libexec/rbootd/rmpproto.c new file mode 100644 index 000000000000..12a6f5cb1777 --- /dev/null +++ b/libexec/rbootd/rmpproto.c @@ -0,0 +1,602 @@ +/* $NetBSD: rmpproto.c,v 1.7 1996/02/01 21:27:46 mycroft Exp $ */ + +/* + * Copyright (c) 1988, 1992 The University of Utah and the Center + * for Software Science (CSS). + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Center for Software Science of the University of Utah Computer + * Science Department. CSS requests users of this software to return + * to css-dist@cs.utah.edu any improvements that they make and grant + * CSS redistribution rights. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)rmpproto.c 8.1 (Berkeley) 6/4/93 + * + * From: Utah Hdr: rmpproto.c 3.1 92/07/06 + * Author: Jeff Forys, University of Utah CSS + */ + +#ifndef lint +/*static char sccsid[] = "@(#)rmpproto.c 8.1 (Berkeley) 6/4/93";*/ +static char rcsid[] = "$NetBSD: rmpproto.c,v 1.7 1996/02/01 21:27:46 mycroft Exp $"; +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/time.h> + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <syslog.h> +#include <unistd.h> +#include "defs.h" + +/* +** ProcessPacket -- determine packet type and do what's required. +** +** An RMP BOOT packet has been received. Look at the type field +** and process Boot Requests, Read Requests, and Boot Complete +** packets. Any other type will be dropped with a warning msg. +** +** Parameters: +** rconn - the new connection +** client - list of files available to this host +** +** Returns: +** Nothing. +** +** Side Effects: +** - If this is a valid boot request, it will be added to +** the linked list of outstanding requests (RmpConns). +** - If this is a valid boot complete, its associated +** entry in RmpConns will be deleted. +** - Also, unless we run out of memory, a reply will be +** sent to the host that sent the packet. +*/ +void +ProcessPacket(rconn, client) + RMPCONN *rconn; + CLIENT *client; +{ + struct rmp_packet *rmp; + RMPCONN *rconnout; + + rmp = &rconn->rmp; /* cache pointer to RMP packet */ + + switch(rmp->r_type) { /* do what we came here to do */ + case RMP_BOOT_REQ: /* boot request */ + if ((rconnout = NewConn(rconn)) == NULL) + return; + + /* + * If the Session ID is 0xffff, this is a "probe" + * packet and we do not want to add the connection + * to the linked list of active connections. There + * are two types of probe packets, if the Sequence + * Number is 0 they want to know our host name, o/w + * they want the name of the file associated with + * the number spec'd by the Sequence Number. + * + * If this is an actual boot request, open the file + * and send a reply. If SendBootRepl() does not + * return 0, add the connection to the linked list + * of active connections, otherwise delete it since + * an error was encountered. + */ + if (ntohs(rmp->r_brq.rmp_session) == RMP_PROBESID) { + if (WORDZE(rmp->r_brq.rmp_seqno)) + (void) SendServerID(rconnout); + else + (void) SendFileNo(rmp, rconnout, + client? client->files: + BootFiles); + FreeConn(rconnout); + } else { + if (SendBootRepl(rmp, rconnout, + client? client->files: BootFiles)) + AddConn(rconnout); + else + FreeConn(rconnout); + } + break; + + case RMP_BOOT_REPL: /* boot reply (not valid) */ + syslog(LOG_WARNING, "%s: sent a boot reply", + EnetStr(rconn)); + break; + + case RMP_READ_REQ: /* read request */ + /* + * Send a portion of the boot file. + */ + (void) SendReadRepl(rconn); + break; + + case RMP_READ_REPL: /* read reply (not valid) */ + syslog(LOG_WARNING, "%s: sent a read reply", + EnetStr(rconn)); + break; + + case RMP_BOOT_DONE: /* boot complete */ + /* + * Remove the entry from the linked list of active + * connections. + */ + (void) BootDone(rconn); + break; + + default: /* unknown RMP packet type */ + syslog(LOG_WARNING, "%s: unknown packet type (%u)", + EnetStr(rconn), rmp->r_type); + } +} + +/* +** SendServerID -- send our host name to who ever requested it. +** +** Parameters: +** rconn - the reply packet to be formatted. +** +** Returns: +** 1 on success, 0 on failure. +** +** Side Effects: +** none. +*/ +int +SendServerID(rconn) + RMPCONN *rconn; +{ + register struct rmp_packet *rpl; + register char *src, *dst; + register u_int8_t *size; + + rpl = &rconn->rmp; /* cache ptr to RMP packet */ + + /* + * Set up assorted fields in reply packet. + */ + rpl->r_brpl.rmp_type = RMP_BOOT_REPL; + rpl->r_brpl.rmp_retcode = RMP_E_OKAY; + ZEROWORD(rpl->r_brpl.rmp_seqno); + rpl->r_brpl.rmp_session = 0; + rpl->r_brpl.rmp_version = htons(RMP_VERSION); + + size = &rpl->r_brpl.rmp_flnmsize; /* ptr to length of host name */ + + /* + * Copy our host name into the reply packet incrementing the + * length as we go. Stop at RMP_HOSTLEN or the first dot. + */ + src = MyHost; + dst = (char *) &rpl->r_brpl.rmp_flnm; + for (*size = 0; *size < RMP_HOSTLEN; (*size)++) { + if (*src == '.' || *src == '\0') + break; + *dst++ = *src++; + } + + rconn->rmplen = RMPBOOTSIZE(*size); /* set packet length */ + + return(SendPacket(rconn)); /* send packet */ +} + +/* +** SendFileNo -- send the name of a bootable file to the requester. +** +** Parameters: +** req - RMP BOOT packet containing the request. +** rconn - the reply packet to be formatted. +** filelist - list of files available to the requester. +** +** Returns: +** 1 on success, 0 on failure. +** +** Side Effects: +** none. +*/ +int +SendFileNo(req, rconn, filelist) + struct rmp_packet *req; + RMPCONN *rconn; + char *filelist[]; +{ + register struct rmp_packet *rpl; + register char *src, *dst; + register u_int8_t *size; + register int i; + + GETWORD(req->r_brpl.rmp_seqno, i); /* SeqNo is really FileNo */ + rpl = &rconn->rmp; /* cache ptr to RMP packet */ + + /* + * Set up assorted fields in reply packet. + */ + rpl->r_brpl.rmp_type = RMP_BOOT_REPL; + PUTWORD(i, rpl->r_brpl.rmp_seqno); + i--; + rpl->r_brpl.rmp_session = 0; + rpl->r_brpl.rmp_version = htons(RMP_VERSION); + + size = &rpl->r_brpl.rmp_flnmsize; /* ptr to length of filename */ + *size = 0; /* init length to zero */ + + /* + * Copy the file name into the reply packet incrementing the + * length as we go. Stop at end of string or when RMPBOOTDATA + * characters have been copied. Also, set return code to + * indicate success or "no more files". + */ + if (i < C_MAXFILE && filelist[i] != NULL) { + src = filelist[i]; + dst = (char *)&rpl->r_brpl.rmp_flnm; + for (; *src && *size < RMPBOOTDATA; (*size)++) { + if (*src == '\0') + break; + *dst++ = *src++; + } + rpl->r_brpl.rmp_retcode = RMP_E_OKAY; + } else + rpl->r_brpl.rmp_retcode = RMP_E_NODFLT; + + rconn->rmplen = RMPBOOTSIZE(*size); /* set packet length */ + + return(SendPacket(rconn)); /* send packet */ +} + +/* +** SendBootRepl -- open boot file and respond to boot request. +** +** Parameters: +** req - RMP BOOT packet containing the request. +** rconn - the reply packet to be formatted. +** filelist - list of files available to the requester. +** +** Returns: +** 1 on success, 0 on failure. +** +** Side Effects: +** none. +*/ +int +SendBootRepl(req, rconn, filelist) + struct rmp_packet *req; + RMPCONN *rconn; + char *filelist[]; +{ + int retval; + char *filename, filepath[RMPBOOTDATA+1]; + RMPCONN *oldconn; + register struct rmp_packet *rpl; + register char *src, *dst1, *dst2; + register u_int8_t i; + + /* + * If another connection already exists, delete it since we + * are obviously starting again. + */ + if ((oldconn = FindConn(rconn)) != NULL) { + syslog(LOG_WARNING, "%s: dropping existing connection", + EnetStr(oldconn)); + RemoveConn(oldconn); + } + + rpl = &rconn->rmp; /* cache ptr to RMP packet */ + + /* + * Set up assorted fields in reply packet. + */ + rpl->r_brpl.rmp_type = RMP_BOOT_REPL; + COPYWORD(req->r_brq.rmp_seqno, rpl->r_brpl.rmp_seqno); + rpl->r_brpl.rmp_session = htons(GenSessID()); + rpl->r_brpl.rmp_version = htons(RMP_VERSION); + rpl->r_brpl.rmp_flnmsize = req->r_brq.rmp_flnmsize; + + /* + * Copy file name to `filepath' string, and into reply packet. + */ + src = &req->r_brq.rmp_flnm; + dst1 = filepath; + dst2 = &rpl->r_brpl.rmp_flnm; + for (i = 0; i < req->r_brq.rmp_flnmsize; i++) + *dst1++ = *dst2++ = *src++; + *dst1 = '\0'; + + /* + * If we are booting HP-UX machines, their secondary loader will + * ask for files like "/hp-ux". As a security measure, we do not + * allow boot files to lay outside the boot directory (unless they + * are purposely link'd out. So, make `filename' become the path- + * stripped file name and spoof the client into thinking that it + * really got what it wanted. + */ + filename = (filename = rindex(filepath,'/'))? ++filename: filepath; + + /* + * Check that this is a valid boot file name. + */ + for (i = 0; i < C_MAXFILE && filelist[i] != NULL; i++) + if (STREQN(filename, filelist[i])) + goto match; + + /* + * Invalid boot file name, set error and send reply packet. + */ + rpl->r_brpl.rmp_retcode = RMP_E_NOFILE; + retval = 0; + goto sendpkt; + +match: + /* + * This is a valid boot file. Open the file and save the file + * descriptor associated with this connection and set success + * indication. If the file couldnt be opened, set error: + * "no such file or dir" - RMP_E_NOFILE + * "file table overflow" - RMP_E_BUSY + * "too many open files" - RMP_E_BUSY + * anything else - RMP_E_OPENFILE + */ + if ((rconn->bootfd = open(filename, O_RDONLY, 0600)) < 0) { + rpl->r_brpl.rmp_retcode = (errno == ENOENT)? RMP_E_NOFILE: + (errno == EMFILE || errno == ENFILE)? RMP_E_BUSY: + RMP_E_OPENFILE; + retval = 0; + } else { + rpl->r_brpl.rmp_retcode = RMP_E_OKAY; + retval = 1; + } + +sendpkt: + syslog(LOG_INFO, "%s: request to boot %s (%s)", + EnetStr(rconn), filename, retval? "granted": "denied"); + + rconn->rmplen = RMPBOOTSIZE(rpl->r_brpl.rmp_flnmsize); + + return (retval & SendPacket(rconn)); +} + +/* +** SendReadRepl -- send a portion of the boot file to the requester. +** +** Parameters: +** rconn - the reply packet to be formatted. +** +** Returns: +** 1 on success, 0 on failure. +** +** Side Effects: +** none. +*/ +int +SendReadRepl(rconn) + RMPCONN *rconn; +{ + int retval = 0; + RMPCONN *oldconn; + register struct rmp_packet *rpl, *req; + register int size = 0; + int madeconn = 0; + + /* + * Find the old connection. If one doesnt exist, create one only + * to return the error code. + */ + if ((oldconn = FindConn(rconn)) == NULL) { + if ((oldconn = NewConn(rconn)) == NULL) + return(0); + syslog(LOG_ERR, "SendReadRepl: no active connection (%s)", + EnetStr(rconn)); + madeconn++; + } + + req = &rconn->rmp; /* cache ptr to request packet */ + rpl = &oldconn->rmp; /* cache ptr to reply packet */ + + if (madeconn) { /* no active connection above; abort */ + rpl->r_rrpl.rmp_retcode = RMP_E_ABORT; + retval = 1; + goto sendpkt; + } + + /* + * Make sure Session ID's match. + */ + if (ntohs(req->r_rrq.rmp_session) != + ((rpl->r_type == RMP_BOOT_REPL)? ntohs(rpl->r_brpl.rmp_session): + ntohs(rpl->r_rrpl.rmp_session))) { + syslog(LOG_ERR, "SendReadRepl: bad session id (%s)", + EnetStr(rconn)); + rpl->r_rrpl.rmp_retcode = RMP_E_BADSID; + retval = 1; + goto sendpkt; + } + + /* + * If the requester asks for more data than we can fit, + * silently clamp the request size down to RMPREADDATA. + * + * N.B. I do not know if this is "legal", however it seems + * to work. This is necessary for bpfwrite() on machines + * with MCLBYTES less than 1514. + */ + if (ntohs(req->r_rrq.rmp_size) > RMPREADDATA) + req->r_rrq.rmp_size = htons(RMPREADDATA); + + /* + * Position read head on file according to info in request packet. + */ + GETWORD(req->r_rrq.rmp_offset, size); + if (lseek(oldconn->bootfd, (off_t)size, L_SET) < 0) { + syslog(LOG_ERR, "SendReadRepl: lseek: %m (%s)", + EnetStr(rconn)); + rpl->r_rrpl.rmp_retcode = RMP_E_ABORT; + retval = 1; + goto sendpkt; + } + + /* + * Read data directly into reply packet. + */ + if ((size = read(oldconn->bootfd, &rpl->r_rrpl.rmp_data, + (int) ntohs(req->r_rrq.rmp_size))) <= 0) { + if (size < 0) { + syslog(LOG_ERR, "SendReadRepl: read: %m (%s)", + EnetStr(rconn)); + rpl->r_rrpl.rmp_retcode = RMP_E_ABORT; + } else { + rpl->r_rrpl.rmp_retcode = RMP_E_EOF; + } + retval = 1; + goto sendpkt; + } + + /* + * Set success indication. + */ + rpl->r_rrpl.rmp_retcode = RMP_E_OKAY; + +sendpkt: + /* + * Set up assorted fields in reply packet. + */ + rpl->r_rrpl.rmp_type = RMP_READ_REPL; + COPYWORD(req->r_rrq.rmp_offset, rpl->r_rrpl.rmp_offset); + rpl->r_rrpl.rmp_session = req->r_rrq.rmp_session; + + oldconn->rmplen = RMPREADSIZE(size); /* set size of packet */ + + retval &= SendPacket(oldconn); /* send packet */ + + if (madeconn) /* clean up after ourself */ + FreeConn(oldconn); + + return (retval); +} + +/* +** BootDone -- free up memory allocated for a connection. +** +** Parameters: +** rconn - incoming boot complete packet. +** +** Returns: +** 1 on success, 0 on failure. +** +** Side Effects: +** none. +*/ +int +BootDone(rconn) + RMPCONN *rconn; +{ + RMPCONN *oldconn; + struct rmp_packet *rpl; + + /* + * If we cant find the connection, ignore the request. + */ + if ((oldconn = FindConn(rconn)) == NULL) { + syslog(LOG_ERR, "BootDone: no existing connection (%s)", + EnetStr(rconn)); + return(0); + } + + rpl = &oldconn->rmp; /* cache ptr to RMP packet */ + + /* + * Make sure Session ID's match. + */ + if (ntohs(rconn->rmp.r_rrq.rmp_session) != + ((rpl->r_type == RMP_BOOT_REPL)? ntohs(rpl->r_brpl.rmp_session): + ntohs(rpl->r_rrpl.rmp_session))) { + syslog(LOG_ERR, "BootDone: bad session id (%s)", + EnetStr(rconn)); + return(0); + } + + RemoveConn(oldconn); /* remove connection */ + + syslog(LOG_INFO, "%s: boot complete", EnetStr(rconn)); + + return(1); +} + +/* +** SendPacket -- send an RMP packet to a remote host. +** +** Parameters: +** rconn - packet to be sent. +** +** Returns: +** 1 on success, 0 on failure. +** +** Side Effects: +** none. +*/ +int +SendPacket(rconn) + register RMPCONN *rconn; +{ + /* + * Set Ethernet Destination address to Source (BPF and the enet + * driver will take care of getting our source address set). + */ + bcopy((char *)&rconn->rmp.hp_hdr.saddr[0], + (char *)&rconn->rmp.hp_hdr.daddr[0], RMP_ADDRLEN); +#ifdef __FreeBSD__ + /* BPF (incorrectly) wants this in host order. */ + rconn->rmp.hp_hdr.len = rconn->rmplen - sizeof(struct hp_hdr); +#else + rconn->rmp.hp_hdr.len = htons(rconn->rmplen - sizeof(struct hp_hdr)); +#endif + + /* + * Reverse 802.2/HP Extended Source & Destination Access Pts. + */ + rconn->rmp.hp_llc.dxsap = htons(HPEXT_SXSAP); + rconn->rmp.hp_llc.sxsap = htons(HPEXT_DXSAP); + + /* + * Last time this connection was active. + */ + (void) gettimeofday(&rconn->tstamp, (struct timezone *)0); + + if (DbgFp != NULL) /* display packet */ + DispPkt(rconn,DIR_SENT); + + /* + * Send RMP packet to remote host. + */ + return(BpfWrite(rconn)); +} diff --git a/libexec/rbootd/utils.c b/libexec/rbootd/utils.c new file mode 100644 index 000000000000..5d37a25bd9ea --- /dev/null +++ b/libexec/rbootd/utils.c @@ -0,0 +1,557 @@ +/* $NetBSD: utils.c,v 1.6 1995/11/14 08:41:47 thorpej Exp $ */ + +/* + * Copyright (c) 1988, 1992 The University of Utah and the Center + * for Software Science (CSS). + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Center for Software Science of the University of Utah Computer + * Science Department. CSS requests users of this software to return + * to css-dist@cs.utah.edu any improvements that they make and grant + * CSS redistribution rights. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)utils.c 8.1 (Berkeley) 6/4/93 + * + * From: Utah Hdr: utils.c 3.1 92/07/06 + * Author: Jeff Forys, University of Utah CSS + */ + +#ifndef lint +/*static char sccsid[] = "@(#)utils.c 8.1 (Berkeley) 6/4/93";*/ +static char rcsid[] = "$NetBSD: utils.c,v 1.6 1995/11/14 08:41:47 thorpej Exp $"; +#endif /* not lint */ + +#include <sys/param.h> + +#include <fcntl.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <time.h> +#include <unistd.h> +#include "defs.h" + +/* +** DispPkt -- Display the contents of an RMPCONN packet. +** +** Parameters: +** rconn - packet to be displayed. +** direct - direction packet is going (DIR_*). +** +** Returns: +** Nothing. +** +** Side Effects: +** None. +*/ +void +DispPkt(rconn, direct) + RMPCONN *rconn; + int direct; +{ + static char BootFmt[] = "\t\tRetCode:%u SeqNo:%lx SessID:%x Vers:%u"; + static char ReadFmt[] = "\t\tRetCode:%u Offset:%lx SessID:%x\n"; + + struct tm *tmp; + register struct rmp_packet *rmp; + int i, omask; + u_int32_t t; + + /* + * Since we will be working with RmpConns as well as DbgFp, we + * must block signals that can affect either. + */ + omask = sigblock(sigmask(SIGHUP)|sigmask(SIGUSR1)|sigmask(SIGUSR2)); + + if (DbgFp == NULL) { /* sanity */ + (void) sigsetmask(omask); + return; + } + + /* display direction packet is going using '>>>' or '<<<' */ + fputs((direct==DIR_RCVD)?"<<< ":(direct==DIR_SENT)?">>> ":"", DbgFp); + + /* display packet timestamp */ + tmp = localtime((time_t *)&rconn->tstamp.tv_sec); + fprintf(DbgFp, "%02d:%02d:%02d.%06ld ", tmp->tm_hour, tmp->tm_min, + tmp->tm_sec, rconn->tstamp.tv_usec); + + /* display src or dst addr and information about network interface */ + fprintf(DbgFp, "Addr: %s Intf: %s\n", EnetStr(rconn), IntfName); + + rmp = &rconn->rmp; + + /* display IEEE 802.2 Logical Link Control header */ + (void) fprintf(DbgFp, "\t802.2 LLC: DSAP:%x SSAP:%x CTRL:%x\n", + rmp->hp_llc.dsap, rmp->hp_llc.ssap, ntohs(rmp->hp_llc.cntrl)); + + /* display HP extensions to 802.2 Logical Link Control header */ + (void) fprintf(DbgFp, "\tHP Ext: DXSAP:%x SXSAP:%x\n", + ntohs(rmp->hp_llc.dxsap), ntohs(rmp->hp_llc.sxsap)); + + /* + * Display information about RMP packet using type field to + * determine what kind of packet this is. + */ + switch(rmp->r_type) { + case RMP_BOOT_REQ: /* boot request */ + (void) fprintf(DbgFp, "\tBoot Request:"); + GETWORD(rmp->r_brq.rmp_seqno, t); + if (ntohs(rmp->r_brq.rmp_session) == RMP_PROBESID) { + if (WORDZE(rmp->r_brq.rmp_seqno)) + fputs(" (Send Server ID)", DbgFp); + else + fprintf(DbgFp," (Send Filename #%u)",t); + } + (void) fputc('\n', DbgFp); + (void) fprintf(DbgFp, BootFmt, rmp->r_brq.rmp_retcode, + t, ntohs(rmp->r_brq.rmp_session), + ntohs(rmp->r_brq.rmp_version)); + (void) fprintf(DbgFp, "\n\t\tMachine Type: "); + for (i = 0; i < RMP_MACHLEN; i++) + (void) fputc(rmp->r_brq.rmp_machtype[i], DbgFp); + DspFlnm(rmp->r_brq.rmp_flnmsize, &rmp->r_brq.rmp_flnm); + break; + case RMP_BOOT_REPL: /* boot reply */ + fprintf(DbgFp, "\tBoot Reply:\n"); + GETWORD(rmp->r_brpl.rmp_seqno, t); + (void) fprintf(DbgFp, BootFmt, rmp->r_brpl.rmp_retcode, + t, ntohs(rmp->r_brpl.rmp_session), + ntohs(rmp->r_brpl.rmp_version)); + DspFlnm(rmp->r_brpl.rmp_flnmsize,&rmp->r_brpl.rmp_flnm); + break; + case RMP_READ_REQ: /* read request */ + (void) fprintf(DbgFp, "\tRead Request:\n"); + GETWORD(rmp->r_rrq.rmp_offset, t); + (void) fprintf(DbgFp, ReadFmt, rmp->r_rrq.rmp_retcode, + t, ntohs(rmp->r_rrq.rmp_session)); + (void) fprintf(DbgFp, "\t\tNoOfBytes: %u\n", + ntohs(rmp->r_rrq.rmp_size)); + break; + case RMP_READ_REPL: /* read reply */ + (void) fprintf(DbgFp, "\tRead Reply:\n"); + GETWORD(rmp->r_rrpl.rmp_offset, t); + (void) fprintf(DbgFp, ReadFmt, rmp->r_rrpl.rmp_retcode, + t, ntohs(rmp->r_rrpl.rmp_session)); + (void) fprintf(DbgFp, "\t\tNoOfBytesSent: %d\n", + rconn->rmplen - RMPREADSIZE(0)); + break; + case RMP_BOOT_DONE: /* boot complete */ + (void) fprintf(DbgFp, "\tBoot Complete:\n"); + (void) fprintf(DbgFp, "\t\tRetCode:%u SessID:%x\n", + rmp->r_done.rmp_retcode, + ntohs(rmp->r_done.rmp_session)); + break; + default: /* ??? */ + (void) fprintf(DbgFp, "\tUnknown Type:(%d)\n", + rmp->r_type); + } + (void) fputc('\n', DbgFp); + (void) fflush(DbgFp); + + (void) sigsetmask(omask); /* reset old signal mask */ +} + + +/* +** GetEtherAddr -- convert an RMP (Ethernet) address into a string. +** +** An RMP BOOT packet has been received. Look at the type field +** and process Boot Requests, Read Requests, and Boot Complete +** packets. Any other type will be dropped with a warning msg. +** +** Parameters: +** addr - array of RMP_ADDRLEN bytes. +** +** Returns: +** Pointer to static string representation of `addr'. +** +** Side Effects: +** None. +** +** Warnings: +** - The return value points to a static buffer; it must +** be copied if it's to be saved. +*/ +char * +GetEtherAddr(addr) + u_int8_t *addr; +{ + static char Hex[] = "0123456789abcdef"; + static char etherstr[RMP_ADDRLEN*3]; + register int i; + register char *cp; + + /* + * For each byte in `addr', convert it to "<hexchar><hexchar>:". + * The last byte does not get a trailing `:' appended. + */ + i = 0; + cp = etherstr; + for(;;) { + *cp++ = Hex[*addr >> 4 & 0xf]; + *cp++ = Hex[*addr++ & 0xf]; + if (++i == RMP_ADDRLEN) + break; + *cp++ = ':'; + } + *cp = '\0'; + + return(etherstr); +} + + +/* +** DispFlnm -- Print a string of bytes to DbgFp (often, a file name). +** +** Parameters: +** size - number of bytes to print. +** flnm - address of first byte. +** +** Returns: +** Nothing. +** +** Side Effects: +** - Characters are sent to `DbgFp'. +*/ +void +DspFlnm(size, flnm) + register u_int size; + register char *flnm; +{ + register int i; + + (void) fprintf(DbgFp, "\n\t\tFile Name (%u): <", size); + for (i = 0; i < size; i++) + (void) fputc(*flnm++, DbgFp); + (void) fputs(">\n", DbgFp); +} + + +/* +** NewClient -- allocate memory for a new CLIENT. +** +** Parameters: +** addr - RMP (Ethernet) address of new client. +** +** Returns: +** Ptr to new CLIENT or NULL if we ran out of memory. +** +** Side Effects: +** - Memory will be malloc'd for the new CLIENT. +** - If malloc() fails, a log message will be generated. +*/ +CLIENT * +NewClient(addr) + u_int8_t *addr; +{ + CLIENT *ctmp; + + if ((ctmp = (CLIENT *) malloc(sizeof(CLIENT))) == NULL) { + syslog(LOG_ERR, "NewClient: out of memory (%s)", + GetEtherAddr(addr)); + return(NULL); + } + + bzero(ctmp, sizeof(CLIENT)); + bcopy(addr, &ctmp->addr[0], RMP_ADDRLEN); + return(ctmp); +} + +/* +** FreeClient -- free linked list of Clients. +** +** Parameters: +** None. +** +** Returns: +** Nothing. +** +** Side Effects: +** - All malloc'd memory associated with the linked list of +** CLIENTS will be free'd; `Clients' will be set to NULL. +** +** Warnings: +** - This routine must be called with SIGHUP blocked. +*/ +void +FreeClients() +{ + register CLIENT *ctmp; + + while (Clients != NULL) { + ctmp = Clients; + Clients = Clients->next; + FreeClient(ctmp); + } +} + +/* +** NewStr -- allocate memory for a character array. +** +** Parameters: +** str - null terminated character array. +** +** Returns: +** Ptr to new character array or NULL if we ran out of memory. +** +** Side Effects: +** - Memory will be malloc'd for the new character array. +** - If malloc() fails, a log message will be generated. +*/ +char * +NewStr(str) + char *str; +{ + char *stmp; + + if ((stmp = (char *)malloc((unsigned) (strlen(str)+1))) == NULL) { + syslog(LOG_ERR, "NewStr: out of memory (%s)", str); + return(NULL); + } + + (void) strcpy(stmp, str); + return(stmp); +} + +/* +** To save time, NewConn and FreeConn maintain a cache of one RMPCONN +** in `LastFree' (defined below). +*/ + +static RMPCONN *LastFree = NULL; + +/* +** NewConn -- allocate memory for a new RMPCONN connection. +** +** Parameters: +** rconn - initialization template for new connection. +** +** Returns: +** Ptr to new RMPCONN or NULL if we ran out of memory. +** +** Side Effects: +** - Memory may be malloc'd for the new RMPCONN (if not cached). +** - If malloc() fails, a log message will be generated. +*/ +RMPCONN * +NewConn(rconn) + RMPCONN *rconn; +{ + RMPCONN *rtmp; + + if (LastFree == NULL) { /* nothing cached; make a new one */ + if ((rtmp = (RMPCONN *) malloc(sizeof(RMPCONN))) == NULL) { + syslog(LOG_ERR, "NewConn: out of memory (%s)", + EnetStr(rconn)); + return(NULL); + } + } else { /* use the cached RMPCONN */ + rtmp = LastFree; + LastFree = NULL; + } + + /* + * Copy template into `rtmp', init file descriptor to `-1' and + * set ptr to next elem NULL. + */ + bcopy((char *)rconn, (char *)rtmp, sizeof(RMPCONN)); + rtmp->bootfd = -1; + rtmp->next = NULL; + + return(rtmp); +} + +/* +** FreeConn -- Free memory associated with an RMPCONN connection. +** +** Parameters: +** rtmp - ptr to RMPCONN to be free'd. +** +** Returns: +** Nothing. +** +** Side Effects: +** - Memory associated with `rtmp' may be free'd (or cached). +** - File desc associated with `rtmp->bootfd' will be closed. +*/ +void +FreeConn(rtmp) + register RMPCONN *rtmp; +{ + /* + * If the file descriptor is in use, close the file. + */ + if (rtmp->bootfd >= 0) { + (void) close(rtmp->bootfd); + rtmp->bootfd = -1; + } + + if (LastFree == NULL) /* cache for next time */ + rtmp = LastFree; + else /* already one cached; free this one */ + free((char *)rtmp); +} + +/* +** FreeConns -- free linked list of RMPCONN connections. +** +** Parameters: +** None. +** +** Returns: +** Nothing. +** +** Side Effects: +** - All malloc'd memory associated with the linked list of +** connections will be free'd; `RmpConns' will be set to NULL. +** - If LastFree is != NULL, it too will be free'd & NULL'd. +** +** Warnings: +** - This routine must be called with SIGHUP blocked. +*/ +void +FreeConns() +{ + register RMPCONN *rtmp; + + while (RmpConns != NULL) { + rtmp = RmpConns; + RmpConns = RmpConns->next; + FreeConn(rtmp); + } + + if (LastFree != NULL) { + free((char *)LastFree); + LastFree = NULL; + } +} + +/* +** AddConn -- Add a connection to the linked list of connections. +** +** Parameters: +** rconn - connection to be added. +** +** Returns: +** Nothing. +** +** Side Effects: +** - RmpConn will point to new connection. +** +** Warnings: +** - This routine must be called with SIGHUP blocked. +*/ +void +AddConn(rconn) + register RMPCONN *rconn; +{ + if (RmpConns != NULL) + rconn->next = RmpConns; + RmpConns = rconn; +} + +/* +** FindConn -- Find a connection in the linked list of connections. +** +** We use the RMP (Ethernet) address as the basis for determining +** if this is the same connection. According to the Remote Maint +** Protocol, we can only have one connection with any machine. +** +** Parameters: +** rconn - connection to be found. +** +** Returns: +** Matching connection from linked list or NULL if not found. +** +** Side Effects: +** None. +** +** Warnings: +** - This routine must be called with SIGHUP blocked. +*/ +RMPCONN * +FindConn(rconn) + register RMPCONN *rconn; +{ + register RMPCONN *rtmp; + + for (rtmp = RmpConns; rtmp != NULL; rtmp = rtmp->next) + if (bcmp((char *)&rconn->rmp.hp_hdr.saddr[0], + (char *)&rtmp->rmp.hp_hdr.saddr[0], RMP_ADDRLEN) == 0) + break; + + return(rtmp); +} + +/* +** RemoveConn -- Remove a connection from the linked list of connections. +** +** Parameters: +** rconn - connection to be removed. +** +** Returns: +** Nothing. +** +** Side Effects: +** - If found, an RMPCONN will cease to exist and it will +** be removed from the linked list. +** +** Warnings: +** - This routine must be called with SIGHUP blocked. +*/ +void +RemoveConn(rconn) + register RMPCONN *rconn; +{ + register RMPCONN *thisrconn, *lastrconn; + + if (RmpConns == rconn) { /* easy case */ + RmpConns = RmpConns->next; + FreeConn(rconn); + } else { /* must traverse linked list */ + lastrconn = RmpConns; /* set back ptr */ + thisrconn = lastrconn->next; /* set current ptr */ + while (thisrconn != NULL) { + if (rconn == thisrconn) { /* found it */ + lastrconn->next = thisrconn->next; + FreeConn(thisrconn); + break; + } + lastrconn = thisrconn; + thisrconn = thisrconn->next; + } + } +} |