rbootd-2.0.orig/0042775000000000000000000000000006523470715012322 5ustar rootrootrbootd-2.0.orig/Makefile0100644000000000000000000000032606523442502013745 0ustar rootroot# 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 rbootd-2.0.orig/Makefile.linux0100644000000000000000000000104306523457524015112 0ustar rootroot# Linux Makefile for rbootd: PMM 1996 (pm215@cam.ac.uk) # Installation's fairly obvious - put rbootd and rbootd.8 in appropriate # places. PROG= rbootd SRCS= pcap.c conf.c parseconf.c rbootd.c rmpproto.c utils.c OBJS = pcap.o conf.o parseconf.o rbootd.o rmpproto.o utils.o MAN= rbootd.8 # We used to -lbsd but that seems to have gone away with glibc... LFLAGS = -lpcap # -Wall picks up all the static char rcsid[] stuff but is otherwise clean CFLAGS = -O2 -Wall rbootd: $(OBJS) $(CC) -o $@ $(OBJS) $(LFLAGS) clean: rm -f *.o rm -f rbootd rbootd-2.0.orig/bpf.c0100644000000000000000000002520306523442502013221 0ustar rootroot/* $NetBSD: bpf.c,v 1.6 1995/11/14 08:41:42 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.6 1995/11/14 08:41:42 thorpej Exp $"; #endif /* not lint */ #include #include #include #include #include #include #include #include #include #include #include #include #include #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, SIOCADDMULTI, (caddr_t)&ifr) < 0) { syslog(LOG_WARNING, "bpf: can't add mcast addr (%m), setting promiscuous mode"); 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; } rbootd-2.0.orig/conf.c0100644000000000000000000000753506523442502013407 0ustar rootroot/* $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 #include #include #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 */ rbootd-2.0.orig/defs.h0100644000000000000000000001566006523457277013425 0ustar rootroot/* $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" #ifdef __linux__ #include #include #include /* for htons() and ntohs() */ #endif /* ** Common #define's and external variables. All other files should ** include this. */ /* * This may be defined in , if not, it's defined here. */ #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 64 #endif /* * SIGUSR1 and SIGUSR2 are defined in 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 *)); #ifndef __linux__ /* BPF functions, for BSDish systems */ void BpfClose __P((void)); char *BpfGetIntfName __P((char **)); int BpfOpen __P((void)); int BpfRead __P((RMPCONN *, int)); int BpfWrite __P((RMPCONN *)); #else /* Linux version uses pcap library: */ void PcapOpen(); char *PcapGetIntfName(char **); void PcapHandler(u_char *user, const struct pcap_pkthdr *h, const u_char *sp); int PcapDispatch(void (*usrhandler)(RMPCONN rconn)); void PcapClose(); void DealWithPacket(RMPCONN rconn); /* this is in rbootd.c... PMM */ int PcapWrite(RMPCONN* rconn); /* not actually using libpcap, but... */ #endif 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 *)); rbootd-2.0.orig/pcap.c0100664000000000000000000002150506523467547013420 0ustar rootroot/* pcap.c - does roughly the job of bpf.c from the NetBSD version sources * * This code was written in about 1996 by * Peter Maydell , and revised * in 1998 to clean it up a little... * * On the positive side, this code is rather less nasty than bpf.c, * primarily because a lot of lower-level stuff has vanished into libpcap. * * Provides : * PcapGetIntfName(char* errmsg) get first ethernet interface name, * or put an error message into errmsg buffer * * PcapOpen() open the packet filter, etc * PcapDispatch(handlerfcn) dispatch a packet if one present * PcapHandler() internal function - passes packets to * user's handler. * PcapClose() close filter, deinitialise, etc * * The legal bumph from the NetBSD sources is huge. Consider it said. */ #include #include /* socket(), sendto() */ #include /* htons(), ntohs() */ #include /* ioctl() */ #include /* close() */ #include /* syslog() */ #include /* struct ifreq */ #include /* ETH_P_ALL */ #include /* strncpy(), bcopy() */ #include "defs.h" static pcap_t *pdesc = NULL; /* packet capture descriptor */ static char errbuf[PCAP_ERRBUF_SIZE]; /* buffer we use to get error msgs */ /* PcapOpen() - open & init packet filter. No params/return code. * If we encounter an error, we stop here (since that's what BpfOpen does) */ void PcapOpen() { int n; /* First we open the device. We use promiscuous mode as I have no * idea whether or not pcap supports multicast. Besides, there's not * going to be much net traffic for *my* application :-> * We set capture length to twice the size of the RMP packet * as a cheap way to detect oversize packets. This is a nasty hack... */ pdesc = pcap_open_live(IntfName, 3 * sizeof(struct rmp_packet), 1, 1000, errbuf); if (pdesc == NULL) { syslog(LOG_ERR, "pcap: couldn't open filter: %s",errbuf); Exit(0); } /* check we're being used on an Ethernet device */ n = pcap_datalink(pdesc); if (n != DLT_EN10MB) { syslog(LOG_ERR, "pcap: %s: datalink type %d unsupported",IntfName, n); Exit(0); } /* Now set the filter program; this is straight from bpf.c */ { #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 (pcap_setfilter(pdesc, &bpf_pgm) != 0) { syslog(LOG_ERR, "pcap: failed to set filter (bug?)"); Exit(0); } } } /* PcapGetIntfName - get name of the first ethernet device in the system. * We ignore loopback. We return 0 if none found, and then *errmsg * explains why. Why do we pass the errmsg buffer as char**? We only * dereference it here, and we use address-of to pass it in rbootd.c... * Ah well, presumably there was a reason :-> */ char* PcapGetIntfName(char **errmsg) { /* We'll assume this function is suitable... */ char* netdev = pcap_lookupdev(errbuf); /* find a device */ if ((int)netdev == -1) { strncpy(*errmsg,pcap_lookupdev(errbuf),strlen(*errmsg)); return NULL; /* flag error to caller */ } return netdev; /* device found - return ptr to its name */ } /* var used to pass the user's handler from PcapDispatch to PcapHandler */ static void (*uhandler)(RMPCONN rconn); void PcapHandler(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) { /* Called when we get a packet. Sort it out into the right format for * the user's handler. Then call that. * This is probably the only really tricky bit in this file. * user is just the ptr passed to pcap_dispatch() - we don't use it. * h is ptr to the header. sp is the pointer to the actual packet. * You can get h->caplen bytes of data from sp onwards. * Header length is just sizeof(struct pcap_pkthdr). */ RMPCONN rconn; /* fill this in with packet details */ register int datlen, caplen; /* declared register because bpf.c does... */ datlen = h->len; /* length of this packet (untruncated) */ caplen = h->caplen; /* max. captured bytes */ /* First we ensure we got a complete packet of the right size! */ if (caplen < datlen) syslog(LOG_ERR, "bpf: truncated packet dropped (%d of %d bytes)", caplen, datlen); else if (datlen > sizeof(struct rmp_packet)) syslog(LOG_ERR, "bpf: oversized packet dropped (%d bytes)", caplen); else { /* fill in fields in rconn and pass packet to user handler */ rconn.rmplen = datlen; bcopy((char *)&h->ts, (char *)&rconn.tstamp, sizeof(struct timeval)); bcopy(sp, (char *)&rconn.rmp, datlen); /* and copy packet over */ uhandler(rconn); } } /* PcapDispatch(handlerfcn) : just an interface to the real * dispatch / handler code... * Takes one parameter - the user's handler, which has prototype: * void DealWithPacket(RMPCONN rconn); */ int PcapDispatch(void (*usrhandler)(RMPCONN rconn)) { int retcode; /* First we save ptr to the user's handler code */ uhandler = usrhandler; /* Then we use pcap_dispatch() to start things off, using a ptr to the real PcapHandler() */ retcode = pcap_dispatch(pdesc, 1, PcapHandler, NULL); /* We return the errorcode ( < 0 for errors) * but we syslog it here, since only we know the pdesc */ if (retcode < 0) syslog(LOG_ERR, "pcap: dispatch failed: %s", pcap_geterr(pdesc)); return retcode; } /* PcapClose() - close filter, deinitialise anything we did, etc. */ void PcapClose() { /* call pcap_close() to shut down interface... ...but only if we've already opened it! */ if (pdesc != NULL) pcap_close(pdesc); /* now do our own deinit, if any */ } /* We also need to be able to write packets to the Ethernet... This facility isn't provided by libpcap, but the subroutine's in this source file anyway. */ int PcapWrite(RMPCONN* rconn) { /* write rconn direct to ethernet */ /* What we get in an RMPCONN: * rconn->rmp is a struct rmp_packet * rconn->rmplen is the length of said packet * rconn->tstamp * rconn->bootfd filedesc of open bootfile * rconn->next ptr to next RMPCONN... * * All we need to do is fill out source addr and send rconn->rmp. * This is all BpfWrite does, although there it's the BPF that does * the adding of source address. * NOTE : we do *not* just set the source addr in the rconn we get given! * We copy the old source addr and reset it, since code in rmpproto.c * depends on the source address being the address of the *destination* * machine. (see the comment in rmp * * Bits of this code borrowed from a post by * Jamie Lokier (jamie@rebellion.co.uk) giving source for a program that * used SOCK_PACKET. Documentation on this facility is *really* rare... */ int s,cs; struct sockaddr sa; char saveaddr[RMP_ADDRLEN]; sa.sa_family = AF_INET; strcpy (sa.sa_data, IntfName); s=socket(AF_INET, SOCK_PACKET, htons(ETH_P_ALL)); if (s == -1) { syslog(LOG_ERR, "attempt to open socket for write failed!"); return 1; } /* Get the source address for the packets. */ { struct ifreq req; int status; strcpy (req.ifr_name, IntfName); status = ioctl (s, SIOCGIFHWADDR, &req); if (status == -1) { syslog(LOG_ERR, "SIOCGIFHWADDR: couldn't get source address!"); return 0; } /* save old source addr, then write real source addr into packet */ memcpy (saveaddr, &(rconn->rmp.hp_hdr.saddr), RMP_ADDRLEN); memcpy (&(rconn->rmp.hp_hdr.saddr), req.ifr_hwaddr.sa_data, RMP_ADDRLEN); } /* perform the actual raw packet send */ cs = sendto(s, &(rconn->rmp), rconn->rmplen, 0, &sa, sizeof(sa)); /* restore previous contents of the source address field before return */ memcpy (&(rconn->rmp.hp_hdr.saddr),saveaddr, RMP_ADDRLEN); close (s); if (cs == -1) { syslog (LOG_ERR, "sendto: failed to send packet!"); return 0; } return 1; /* success */ } rbootd-2.0.orig/parseconf.c0100644000000000000000000002343006523442503014433 0ustar rootroot/* $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 #include #include #include #include #include #include #include #include #include #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); } rbootd-2.0.orig/pathnames.h0100644000000000000000000000514206523442503014440 0ustar rootroot/* $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 "/export/hp/rbootd" #define _PATH_RBOOTDPID "/var/run/rbootd.pid" rbootd-2.0.orig/rbootd.80100644000000000000000000001301706523442503013671 0ustar rootroot.\" $NetBSD: rbootd.8,v 1.3 1995/08/21 17:05: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: @(#)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. rbootd-2.0.orig/rbootd.c0100644000000000000000000003263706523457175013770 0ustar rootroot/* $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 #include #include #ifndef __linux__ /* not relevant to Linux */ #include #endif #include #include #include #include #include #include #include #include #include "defs.h" extern char *__progname; /* from crt0.o */ int main(argc, argv) int argc; char *argv[]; { int c, omask; #ifdef __linux__ int nowtime; /* used in Linux version of timeout code */ #else int maxfds, fd; fd_set rset; #endif /* * 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 { #ifdef __linux__ /* don't have warnx */ fprintf(stderr,"too many config files (`%s' ignored)\n", argv[optind]); #else warnx("too many config files (`%s' ignored)\n", argv[optind]); #endif } } 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)) #ifndef __linux__ err(1, "can't detach from terminal"); #else { /* Linux has no err() */ fprintf(stderr, "can't detach from terminal"); exit(1); } #endif (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; #ifdef __linux__ if ((IntfName = PcapGetIntfName(&errmsg)) == NULL ) { #else if ((IntfName = BpfGetIntfName(&errmsg)) == NULL) { #endif 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); #ifndef __linux__ /* This is a bit of a huge ifdef because the Linux main loop is totally different due to the restrictions of the pcap functions... Analysis of main loop: First we initialise the packet filter. Then we wait for a packet (with possible timeout if also dealing with existing connections) If we timed out, we handle stale connections and loop If we error, exit. Otherwise we BpfRead the packet and deal with it. The while() loop and the doread variable are so that we read all packets that arrived this time, but no more (ie only read() on first packet of a bunch.) Adaptation to libpcap: We initialise the filter with pcap_open_live() and pcap_set_filter(). Then we wait for packets and dispatch them to a function handle_pcap_packet() which we write (this will essentially be the innards of the while() loop) We can use pcap_dispatch() to deal with any packets currently available, putting this in a loop which tests the time and times out connections appropriately. PMM 1996 */ /* * 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); } } } } #else /* Linux main loop code below: */ /* Open and initialise a BPF filter */ PcapOpen(); (void) sigsetmask(omask); /* allow reconfig's */ nowtime = time(NULL); for(;;) { /* * Main loop: dispatch packets. After a given timeout, * check and delete stale connections. */ if(PcapDispatch(DealWithPacket) < 0) { /* error - logged already by PcapDispatch... */ /* can we ever get errors that don't mean anything? */ } if (time(NULL) > nowtime + RMP_TIMEOUT) { DoTimeout(); /* stale connection check */ nowtime = time(NULL); } } } void DealWithPacket(RMPCONN rconn) { /* this just deals with a single packet. code is from the while() loop of the NetBSD code */ CLIENT* client; int omask; 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)); } else { ProcessPacket(&rconn,client); } (void) sigsetmask(omask); } #endif /* __linux__ */ /* ** 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"); #ifdef __linux__ PcapClose(); #else BpfClose(); #endif 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); } } rbootd-2.0.orig/rmp.h0100644000000000000000000001065506523442503013263 0ustar rootroot/* $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. */ #ifndef __linux__ #define RMP_MAX_PACKET MIN(1514,MCLBYTES) #else /* This is not guaranteed to work right - it's the defines for MCLBYTES from the i386 NetBSD include files (in param.h) #define MCLSHIFT 11 convert bytes to m_buf clusters #define MCLBYTES (1 << MCLSHIFT) size of a m_buf cluster net result is: */ #define MCLBYTES 2048 /* Sadly, gcc thinks that RMP_MAX_PACKET isn't a constant if we use MIN - probably because /usr/include/bsd/bsd.h defines MIN using ?: So we use a hardwired value :-< */ /*#define RMP_MAX_PACKET MIN(1514,MCLBYTES) */ #define RMP_MAX_PACKET 1514 /* If anybody knows what the Right Thing to do for Linux here is, feel free to bugfix :-> This seems to work, at least... */ #endif #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 */ }; rbootd-2.0.orig/rmp_var.h0100644000000000000000000002221506523442503014126 0ustar rootroot/* $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 rbootd-2.0.orig/rmpproto.c0100644000000000000000000004051006523442503014333 0ustar rootroot/* $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 #include #include #include #include #include #include #include #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); #ifdef __linux__ if (lseek(oldconn->bootfd, (off_t)size, SEEK_SET) < 0) { #else if (lseek(oldconn->bootfd, (off_t)size, L_SET) < 0) { #endif 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. */ #ifdef __linux__ return(PcapWrite(rconn)); #else return(BpfWrite(rconn)); #endif } rbootd-2.0.orig/utils.c0100644000000000000000000003406506523442503013621 0ustar rootroot/* $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 #include #include #include #include #include #include #include #include #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 ":". * 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; } } }