home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-10-11 | 93.4 KB | 3,745 lines |
- Newsgroups: comp.sources.unix
- From: gwr@mc.com (Gordon W. Ross)
- Subject: v27i064: bootp-2.2.B - RFC 1048 "bootp" server (w/ vendor extensions), Part02/02
- References: <1.750376278.23845@gw.home.vix.com>
- Sender: unix-sources-moderator@gw.home.vix.com
- Approved: vixie@gw.home.vix.com
-
- Submitted-By: gwr@mc.com (Gordon W. Ross)
- Posting-Number: Volume 27, Issue 64
- Archive-Name: bootp-2.2.B/part02
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 2 (of 2)."
- # Contents: bootpd.c readfile.c
- # Wrapped by vixie@gw.home.vix.com on Mon Oct 11 14:48:26 1993
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'bootpd.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'bootpd.c'\"
- else
- echo shar: Extracting \"'bootpd.c'\" \(40573 characters\)
- sed "s/^X//" >'bootpd.c' <<'END_OF_FILE'
- X#ifndef _BLURB_
- X#define _BLURB_
- X/************************************************************************
- X Copyright 1988, 1991 by Carnegie Mellon University
- X
- X All Rights Reserved
- X
- XPermission to use, copy, modify, and distribute this software and its
- Xdocumentation for any purpose and without fee is hereby granted, provided
- Xthat the above copyright notice appear in all copies and that both that
- Xcopyright notice and this permission notice appear in supporting
- Xdocumentation, and that the name of Carnegie Mellon University not be used
- Xin advertising or publicity pertaining to distribution of the software
- Xwithout specific, written prior permission.
- X
- XCARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
- XSOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
- XIN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
- XDAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
- XPROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
- XACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
- XSOFTWARE.
- X************************************************************************/
- X#endif /* _BLURB_ */
- X
- X
- X#ifndef lint
- Xstatic char sccsid[] = "@(#)bootp.c 1.1 (Stanford) 1/22/86";
- Xstatic char rcsid[] = "$Header: /afs/andrew.cmu.edu/netdev/src/cmu/bootp-public/RCS/bootpd.c,v 1.3 1991/11/01 10:02:29 ww0n Exp ww0n $";
- X#endif
- X
- X
- X/*
- X * BOOTP (bootstrap protocol) server daemon.
- X *
- X * Answers BOOTP request packets from booting client machines.
- X * See [SRI-NIC]<RFC>RFC951.TXT for a description of the protocol.
- X * See [SRI-NIC]<RFC>RFC1048.TXT for vendor-information extensions.
- X * See accompanying man page -- bootpd.8
- X *
- X *
- X * HISTORY
- X *
- X * 01/22/86 Bill Croft at Stanford University
- X * Created.
- X *
- X * 07/30/86 David Kovar at Carnegie Mellon University
- X * Modified to work at CMU.
- X *
- X * 07/24/87 Drew D. Perkins at Carnegie Mellon University
- X * Modified to use syslog instead of Kovar's
- X * routines. Add debugging dumps. Many other fixups.
- X *
- X * 07/15/88 Walter L. Wimer at Carnegie Mellon University
- X * Added vendor information to conform to RFC1048.
- X * Adopted termcap-like file format to support above.
- X * Added hash table lookup instead of linear search.
- X * Other cleanups.
- X *
- X *
- X * BUGS
- X *
- X * Currently mallocs memory in a very haphazard manner. As such, most of
- X * the program ends up core-resident all the time just to follow all the
- X * stupid pointers around. . . .
- X *
- X */
- X
- X
- X
- X
- X#include <sys/types.h>
- X#include <sys/socket.h>
- X#include <sys/ioctl.h>
- X#include <sys/file.h>
- X#include <sys/time.h>
- X#include <sys/stat.h>
- X#include <net/if.h>
- X#if defined(SUNOS4) || defined(SVR4)
- X#include <sys/sockio.h>
- X#include <net/if_arp.h>
- X#endif
- X#include <netinet/in.h>
- X#include <stdlib.h>
- X#include <signal.h>
- X#include <stdio.h>
- X#ifdef SVR4
- X#include <sys/termios.h> /* Why? */
- X#include <string.h>
- X#include <sys/fcntl.h> /* Why? */
- X#else
- X#include <strings.h>
- X#endif
- X#include <errno.h>
- X#include <ctype.h>
- X#include <netdb.h>
- X#ifdef SYSLOG
- X#include <syslog.h>
- X#endif
- X#include "bootp.h"
- X#include "hash.h"
- X#include "bootpd.h"
- X
- X#define HASHTABLESIZE 257 /* Hash table size (prime) */
- X#define DEFAULT_TIMEOUT 15L /* Default timeout in minutes */
- X#define MAXPKT (3*512) /* Maximum packet size */
- X
- X#ifdef DEBUG
- X#define CONFIG_FILE "bootptab.debug"
- X#endif /* XXX */
- X
- X#ifndef CONFIG_FILE
- X#define CONFIG_FILE "/etc/bootptab"
- X#endif
- X#ifndef DUMP_FILE
- X#define DUMP_FILE "/etc/bootpd.dump"
- X#endif
- X
- X#ifdef SVR4
- X#define bcopy(a,b,c) memcpy(b,a,c)
- X#define bzero(p,l) memset(p,0,l)
- X#define bcmp(a,b,c) memcmp(a,b,c)
- X#define index(a,b) strchr(a,b)
- X#endif
- X
- X
- X
- X/*
- X * Externals, forward declarations, and global variables
- X */
- X
- Xextern char Version[];
- Xextern char *sys_errlist[];
- Xextern int errno, sys_nerr;
- X
- Xvoid usage();
- Xvoid dump_host();
- Xvoid list_ipaddresses();
- X#ifdef VEND_CMU
- Xvoid dovend_cmu();
- X#endif
- Xvoid dovend_rfc1048();
- Xboolean hwlookcmp();
- Xboolean iplookcmp();
- Xvoid insert_generic();
- Xvoid insert_ip();
- Xvoid dumptab();
- Xint chk_access();
- Xvoid report();
- Xchar *get_errmsg();
- Xvoid answer_request();
- Xvoid forward_reply();
- X
- X/*
- X * IP port numbers for client and server obtained from /etc/services
- X */
- X
- Xu_short bootps_port, bootpc_port;
- X
- X
- X/*
- X * Internet socket and interface config structures
- X */
- X
- Xstruct sockaddr server_addr;
- Xstruct sockaddr client_addr;
- Xstruct ifreq ifreq[10]; /* Holds interface configuration */
- Xstruct ifconf ifconf; /* Int. config ioctl block (pnts to ifreq) */
- Xstruct arpreq arpreq; /* Arp request ioctl block */
- X
- X
- X/*
- X * General
- X */
- X
- Xint debug = 0; /* Debugging flag (level) */
- Xint s; /* Socket file descriptor */
- Xchar *pktbuf;
- Xint pktlen;
- Xstruct timezone tzp; /* Time zone offset for clients */
- Xstruct timeval tp; /* Time (extra baggage) */
- Xlong secondswest; /* Time zone offset in seconds */
- X
- X/*
- X * Globals below are associated with the bootp database file (bootptab).
- X */
- X
- Xchar *bootptab = NULL;
- X#ifdef DEBUG
- Xchar *bootpd_dump = NULL;
- X#endif
- X
- X
- X
- X/*
- X * Vendor magic cookies for CMU and RFC1048
- X */
- X
- Xunsigned char vm_cmu[4] = VM_CMU;
- Xunsigned char vm_rfc1048[4] = VM_RFC1048;
- Xunsigned char vm_zero[4] = { 0, 0, 0, 0 };
- X
- X
- X/*
- X * Hardware address lengths (in bytes) and network name based on hardware
- X * type code. List in order specified by Assigned Numbers RFC; Array index
- X * is hardware type code. Entries marked as zero are unknown to the author
- X * at this time. . . .
- X */
- X
- Xstruct hwinfo hwinfolist[] = {
- X { 0, "Reserved" }, /* Type 0: Reserved (don't use this) */
- X { 6, "Ethernet" }, /* Type 1: 10Mb Ethernet (48 bits) */
- X { 1, "3Mb Ethernet" }, /* Type 2: 3Mb Ethernet (8 bits) */
- X { 0, "AX.25" }, /* Type 3: Amateur Radio AX.25 */
- X { 1, "ProNET" }, /* Type 4: Proteon ProNET Token Ring */
- X { 0, "Chaos" }, /* Type 5: Chaos */
- X { 6, "IEEE 802" }, /* Type 6: IEEE 802 Networks */
- X { 0, "ARCNET" } /* Type 7: ARCNET */
- X};
- Xint hwinfocnt = sizeof(hwinfolist) / sizeof(hwinfolist[0]);
- X
- X/*
- X * Main hash tables
- X */
- X
- Xhash_tbl *hwhashtable;
- Xhash_tbl *iphashtable;
- Xhash_tbl *nmhashtable;
- X
- X
- X
- X
- X/*
- X * Initialization such as command-line processing is done and then the main
- X * server loop is started.
- X */
- X
- Xmain(argc, argv)
- X int argc;
- X char **argv;
- X{
- X struct timeval actualtimeout, *timeout;
- X struct bootp *bp;
- X struct servent *servp;
- X struct sockaddr_in *s_sin;
- X char *stmp;
- X int n, sa_len, ca_len;
- X int nfound, readfds;
- X int standalone;
- X
- X stmp = NULL;
- X actualtimeout.tv_usec = 0L;
- X actualtimeout.tv_sec = 60 * DEFAULT_TIMEOUT;
- X timeout = &actualtimeout;
- X s_sin = (struct sockaddr_in *) &server_addr;
- X
- X /* Get space for receiving packets and composing replies. */
- X pktbuf = malloc(MAXPKT);
- X bp = (struct bootp *) pktbuf;
- X
- X /*
- X * Check to see if a socket was passed to us from inetd.
- X *
- X * Use getsockname() to determine if descriptor 0 is indeed a socket
- X * (and thus we are probably a child of inetd) or if it is instead
- X * something else and we are running standalone.
- X */
- X s = 0;
- X sa_len = sizeof(server_addr);
- X bzero((char *) &server_addr, sa_len);
- X errno = 0;
- X standalone = TRUE;
- X if (getsockname(s, &server_addr, &sa_len) == 0) {
- X /*
- X * Descriptor 0 is a socket. Assume we are a child of inetd.
- X */
- X if (s_sin->sin_family == AF_INET) {
- X standalone = FALSE;
- X bootps_port = ntohs(s_sin->sin_port);
- X } else {
- X report(LOG_INFO, "getsockname: not an INET socket\n");
- X }
- X }
- X
- X /*
- X * Read switches.
- X */
- X for (argc--, argv++; argc > 0; argc--, argv++) {
- X if (argv[0][0] == '-') {
- X switch (argv[0][1]) {
- X case 't':
- X if (argv[0][2]) {
- X stmp = &(argv[0][2]);
- X } else {
- X argc--;
- X argv++;
- X stmp = argv[0];
- X }
- X if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
- X fprintf(stderr,
- X "bootpd: invalid timeout specification\n");
- X break;
- X }
- X actualtimeout.tv_sec = (long) (60 * n);
- X /*
- X * If the actual timeout is zero, pass a NULL pointer
- X * to select so it blocks indefinitely, otherwise,
- X * point to the actual timeout value.
- X */
- X timeout = (n > 0) ? &actualtimeout : NULL;
- X break;
- X case 'd':
- X if (argv[0][2]) {
- X stmp = &(argv[0][2]);
- X } else if (argv[1][0] == '-') {
- X /*
- X * Backwards-compatible behavior:
- X * no parameter, so just increment the debug flag.
- X */
- X debug++;
- X break;
- X } else {
- X argc--;
- X argv++;
- X stmp = argv[0];
- X }
- X if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
- X fprintf(stderr,
- X "bootpd: invalid debug level\n");
- X break;
- X }
- X debug = n;
- X break;
- X case 's':
- X standalone = TRUE;
- X break;
- X case 'i':
- X standalone = FALSE;
- X break;
- X default:
- X fprintf(stderr, "bootpd: unknown switch: -%c\n",
- X argv[0][1]);
- X usage();
- X break;
- X }
- X } else {
- X if (!bootptab) {
- X bootptab = argv[0];
- X#ifdef DEBUG
- X } else if (!bootpd_dump) {
- X bootpd_dump = argv[0];
- X#endif
- X } else {
- X fprintf(stderr, "bootpd: unknown argument: %s\n", argv[0]);
- X usage();
- X }
- X }
- X }
- X
- X
- X /*
- X * Set default file names if not specified on command line
- X */
- X if (!bootptab) {
- X bootptab = CONFIG_FILE;
- X }
- X#ifdef DEBUG
- X if (!bootpd_dump) {
- X bootpd_dump = DUMP_FILE;
- X }
- X#endif
- X
- X
- X if (standalone) {
- X /*
- X * Go into background and disassociate from controlling terminal.
- X * XXX - This is not the POSIX way... -gwr
- X */
- X if (debug < 3) {
- X if (fork())
- X exit(0);
- X for (n = 0; n < 10; n++)
- X (void) close(n);
- X (void) open("/", O_RDONLY);
- X (void) dup2(0, 1);
- X (void) dup2(0, 2);
- X n = open("/dev/tty", O_RDWR);
- X if (n >= 0) {
- X ioctl(n, TIOCNOTTY, (char *) 0);
- X (void) close(n);
- X }
- X }
- X /*
- X * Nuke any timeout value
- X */
- X timeout = NULL;
- X }
- X
- X
- X#ifdef SYSLOG
- X /*
- X * Initialize logging.
- X */
- X#ifndef LOG_CONS
- X#define LOG_CONS 0 /* Don't bother if not defined... */
- X#endif
- X#ifndef LOG_DAEMON
- X#define LOG_DAEMON 0
- X#endif
- X openlog("bootpd", LOG_PID | LOG_CONS, LOG_DAEMON);
- X#endif
- X
- X /*
- X * Log startup
- X */
- X report(LOG_INFO, "%s", Version);
- X
- X /*
- X * Get our timezone offset so we can give it to clients if the
- X * configuration file doesn't specify one.
- X */
- X if (gettimeofday(&tp, &tzp) < 0) {
- X secondswest = 0L; /* Assume GMT for lack of anything better */
- X report(LOG_ERR, "gettimeofday: %s\n", get_errmsg());
- X } else {
- X secondswest = 60L * tzp.tz_minuteswest; /* Convert to seconds */
- X }
- X
- X /*
- X * Allocate hash tables for hardware address, ip address, and hostname
- X */
- X hwhashtable = hash_Init(HASHTABLESIZE);
- X iphashtable = hash_Init(HASHTABLESIZE);
- X nmhashtable = hash_Init(HASHTABLESIZE);
- X if (!(hwhashtable && iphashtable && nmhashtable)) {
- X report(LOG_ERR, "Unable to allocate hash tables.\n");
- X exit(1);
- X }
- X
- X
- X /*
- X * Read the bootptab file once immediately upon startup.
- X */
- X readtab();
- X
- X
- X if (standalone) {
- X /*
- X * Create a socket.
- X */
- X if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
- X report(LOG_ERR, "socket: %s\n", get_network_errmsg());
- X exit(1);
- X }
- X
- X /*
- X * Get server's listening port number
- X */
- X servp = getservbyname("bootps", "udp");
- X if (servp) {
- X bootps_port = ntohs((u_short) servp->s_port);
- X } else {
- X report(LOG_ERR,
- X "udp/bootps: unknown service -- assuming port %d\n",
- X IPPORT_BOOTPS);
- X bootps_port = (u_short) IPPORT_BOOTPS;
- X }
- X
- X /*
- X * Bind socket to BOOTPS port.
- X */
- X s_sin->sin_family = AF_INET;
- X s_sin->sin_addr.s_addr = INADDR_ANY;
- X s_sin->sin_port = htons(bootps_port);
- X if (bind(s, &server_addr, sizeof(*s_sin)) < 0) {
- X report(LOG_ERR, "bind: %s\n", get_network_errmsg());
- X exit(1);
- X }
- X }
- X
- X
- X /*
- X * Get destination port number so we can reply to client
- X */
- X servp = getservbyname("bootpc", "udp");
- X if (servp) {
- X bootpc_port = ntohs(servp->s_port);
- X } else {
- X report(LOG_ERR,
- X "udp/bootpc: unknown service -- assuming port %d\n",
- X IPPORT_BOOTPC);
- X bootpc_port = (u_short) IPPORT_BOOTPC;
- X }
- X
- X
- X /*
- X * Determine network configuration.
- X */
- X ifconf.ifc_len = sizeof(ifreq);
- X ifconf.ifc_req = ifreq;
- X if ((ioctl(s, SIOCGIFCONF, (caddr_t) &ifconf) < 0) ||
- X (ifconf.ifc_len <= 0)) {
- X report(LOG_ERR, "ioctl: %s\n", get_network_errmsg());
- X exit(1);
- X }
- X
- X
- X /*
- X * Set up signals to read or dump the table.
- X */
- X if ((int) signal(SIGHUP, readtab) < 0) {
- X report(LOG_ERR, "signal: %s\n", get_errmsg());
- X exit(1);
- X }
- X#ifdef DEBUG
- X if ((int) signal(SIGUSR1, dumptab) < 0) {
- X report(LOG_ERR, "signal: %s\n", get_errmsg());
- X exit(1);
- X }
- X#endif
- X
- X /*
- X * Process incoming requests.
- X */
- X for (;;) {
- X readfds = 1 << s;
- X nfound = select(s + 1, (fd_set *)&readfds, NULL, NULL, timeout);
- X if (nfound < 0) {
- X if (errno != EINTR) {
- X report(LOG_ERR, "select: %s\n", get_errmsg());
- X }
- X continue;
- X }
- X if (!(readfds & (1 << s))) {
- X report(LOG_INFO, "exiting after %ld minutes of inactivity\n",
- X actualtimeout.tv_sec / 60);
- X exit(0);
- X }
- X ca_len = sizeof(client_addr);
- X n = recvfrom(s, pktbuf, MAXPKT, 0, &client_addr, &ca_len);
- X if (n <= 0) {
- X continue;
- X }
- X
- X if (n < sizeof(struct bootp)) {
- X if (debug) {
- X report(LOG_INFO, "received short packet\n");
- X }
- X continue;
- X }
- X pktlen = n;
- X
- X readtab(); /* maybe re-read bootptab */
- X switch (bp->bp_op) {
- X case BOOTREQUEST:
- X /* Handle a request by answering with a reply. */
- X answer_request();
- X break;
- X
- X case BOOTREPLY:
- X /* Handle a reply by forwarding it to the client. */
- X forward_reply();
- X break;
- X }
- X }
- X}
- X
- X
- X
- X
- X/*
- X * Print "usage" message and exit
- X */
- X
- Xvoid usage()
- X{
- X fprintf(stderr,
- X"usage: bootpd [-d level] [-i] [-s] [-t timeout] [configfile [dumpfile]]\n");
- X fprintf(stderr, "\t -d n\tset debug level\n");
- X fprintf(stderr, "\t -i\tforce inetd mode (run as child of inetd)\n");
- X fprintf(stderr, "\t -s\tforce standalone mode (run without inetd)\n");
- X fprintf(stderr, "\t -t n\tset inetd exit timeout to n minutes\n");
- X exit(1);
- X}
- X
- X
- X
- X/*
- X * Process BOOTREQUEST packet.
- X *
- X * (Note, this version of the bootpd.c server never forwards
- X * the request to another server. In our environment the
- X * stand-alone gateways perform that function.)
- X *
- X * (Also this version does not interpret the hostname field of
- X * the request packet; it COULD do a name->address lookup and
- X * forward the request there.)
- X */
- Xvoid
- Xanswer_request()
- X{
- X register struct bootp *bp = (struct bootp *) pktbuf;
- X register struct host *hp;
- X register int n;
- X char *path;
- X struct host dummyhost;
- X long bootsize;
- X unsigned hlen, hashcode;
- X char realpath[1024];
- X
- X bp->bp_op = BOOTREPLY;
- X if (bp->bp_ciaddr.s_addr == 0) {
- X /*
- X * client doesnt know his IP address,
- X * search by hardware address.
- X */
- X if (debug) {
- X report(LOG_INFO, "request from %s address %s\n",
- X netname(bp->bp_htype),
- X haddrtoa(bp->bp_chaddr, bp->bp_htype));
- X }
- X
- X dummyhost.htype = bp->bp_htype;
- X hlen = haddrlength(bp->bp_htype);
- X bcopy(bp->bp_chaddr, dummyhost.haddr, hlen);
- X hashcode = hash_HashFunction(bp->bp_chaddr, hlen);
- X hp = (struct host *) hash_Lookup(hwhashtable, hashcode, hwlookcmp,
- X &dummyhost);
- X if (hp == NULL) {
- X /* XXX - Do we need more control over this noise? -gwr */
- X if (debug)
- X report(LOG_INFO, "unknown client %s address %s\n",
- X netname(bp->bp_htype),
- X haddrtoa(bp->bp_chaddr, bp->bp_htype));
- X return; /* not found */
- X }
- X (bp->bp_yiaddr).s_addr = hp->iaddr.s_addr;
- X
- X } else {
- X
- X /*
- X * search by IP address.
- X */
- X if (debug) {
- X report(LOG_INFO, "request from IP addr %s\n",
- X inet_ntoa(bp->bp_ciaddr));
- X }
- X dummyhost.iaddr.s_addr = bp->bp_ciaddr.s_addr;
- X hashcode = hash_HashFunction((char *) &(bp->bp_ciaddr.s_addr), 4);
- X hp = (struct host *) hash_Lookup(iphashtable, hashcode, iplookcmp,
- X &dummyhost);
- X if (hp == NULL) {
- X report(LOG_NOTICE,
- X "IP address not found: %s\n", inet_ntoa(bp->bp_ciaddr));
- X return;
- X }
- X }
- X
- X if (debug) {
- X report(LOG_INFO, "found %s %s\n", inet_ntoa(hp->iaddr),
- X hp->hostname->string);
- X }
- X
- X /*
- X * If a specific TFTP server address was specified in the bootptab file,
- X * fill it in, otherwise zero it.
- X */
- X (bp->bp_siaddr).s_addr = (hp->flags.bootserver) ?
- X hp->bootserver.s_addr : 0L;
- X
- X /*
- X * This next line is a bit of a mystery. It seems to be vestigial
- X * code (from Stanford???) which should probably be axed.
- X */
- X if (strcmp(bp->bp_file, "sunboot14") == 0)
- X bp->bp_file[0] = 0; /* pretend it's null */
- X
- X
- X /*
- X * Fill in the client's proper bootfile.
- X *
- X * If the client specifies an absolute path, try that file with a
- X * ".host" suffix and then without. If the file cannot be found, no
- X * reply is made at all.
- X *
- X * [ I think this policy is too complicated. Why not just send the
- X * reply if we know how, whether or not the file exists? -gwr ]
- X *
- X * If the client specifies a null or relative file, use the following
- X * table to determine the appropriate action:
- X *
- X * Homedir Bootfile Client's file
- X * specified? specified? specification Action
- X * -------------------------------------------------------------------
- X * No No Null Send null filename
- X * No No Relative Discard request
- X * No Yes Null Send if absolute else null
- X * No Yes Relative Discard request
- X * Yes No Null Send null filename
- X * Yes No Relative Lookup with ".host"
- X * Yes Yes Null Send home/boot or bootfile
- X * Yes Yes Relative Lookup with ".host"
- X *
- X */
- X
- X if (hp->flags.tftpdir) {
- X strcpy(realpath, hp->tftpdir->string);
- X path = &realpath[strlen(realpath)];
- X } else {
- X path = realpath;
- X }
- X
- X if (bp->bp_file[0]) {
- X /*
- X * The client specified a file.
- X */
- X if (bp->bp_file[0] == '/') {
- X strcpy(path, bp->bp_file); /* Absolute pathname */
- X } else {
- X if (hp->flags.homedir) {
- X strcpy(path, hp->homedir->string);
- X strcat(path, "/");
- X strcat(path, bp->bp_file);
- X } else {
- X report(LOG_NOTICE,
- X "requested file \"%s\" not found: hd unspecified\n",
- X bp->bp_file);
- X return;
- X }
- X }
- X } else {
- X /*
- X * No file specified by the client.
- X */
- X if (hp->flags.bootfile && ((hp->bootfile->string)[0] == '/')) {
- X strcpy(path, hp->bootfile->string);
- X } else if (hp->flags.homedir && hp->flags.bootfile) {
- X strcpy(path, hp->homedir->string);
- X strcat(path, "/");
- X strcat(path, hp->bootfile->string);
- X } else {
- X bzero(bp->bp_file, sizeof(bp->bp_file));
- X goto skip_file; /* Don't bother trying to access the file */
- X }
- X }
- X
- X /*
- X * First try to find the file with a ".host" suffix
- X */
- X n = strlen(path);
- X strcat(path, ".");
- X strcat(path, hp->hostname->string);
- X if (chk_access(realpath, &bootsize) < 0) {
- X path[n] = 0; /* Try it without the suffix */
- X if (chk_access(realpath, &bootsize) < 0) {
- X if (bp->bp_file[0]) {
- X /*
- X * Client wanted specific file
- X * and we didn't have it.
- X */
- X report(LOG_NOTICE,
- X "requested file not found: \"%s\"\n", path);
- X return;
- X } else {
- X /*
- X * Client didn't ask for a specific file and we couldn't
- X * access the default file, so just zero-out the bootfile
- X * field in the packet and continue processing the reply.
- X */
- X bzero(bp->bp_file, sizeof(bp->bp_file));
- X goto skip_file;
- X }
- X }
- X }
- X strcpy(bp->bp_file, path);
- X
- Xskip_file: ;
- X
- X
- X
- X if (debug > 1) {
- X report(LOG_INFO, "vendor magic field is %d.%d.%d.%d\n",
- X (int) ((bp->bp_vend)[0]),
- X (int) ((bp->bp_vend)[1]),
- X (int) ((bp->bp_vend)[2]),
- X (int) ((bp->bp_vend)[3]));
- X }
- X
- X /*
- X * If this host isn't set for automatic vendor info then copy the
- X * specific cookie into the bootp packet, thus forcing a certain
- X * reply format.
- X */
- X if (!hp->flags.vm_auto) {
- X /*
- X * If the client supplies a vendor magic number,
- X * bootp probably should not change it...
- X */
- X if (debug > 1 && bcmp(bp->bp_vend, vm_zero, 4)) {
- X report(LOG_INFO, "vendor magic field forced\n");
- X }
- X bcopy(hp->vm_cookie, bp->bp_vend, 4);
- X }
- X
- X /*
- X * Figure out the format for the vendor-specific info.
- X */
- X if (!bcmp(bp->bp_vend, vm_rfc1048, 4)) {
- X /* RFC1048 conformant bootp client */
- X dovend_rfc1048(bp, hp, bootsize);
- X if (debug > 1) {
- X report(LOG_INFO, "sending reply (with RFC1048 options)\n");
- X }
- X }
- X#ifdef VEND_CMU
- X else if (!bcmp(bp->bp_vend, vm_cmu, 4)) {
- X dovend_cmu(bp, hp);
- X if (debug > 1) {
- X report(LOG_INFO, "sending reply (with CMU options)\n");
- X }
- X }
- X#endif
- X else if (!bcmp(bp->bp_vend, vm_zero, 4)) {
- X if (debug > 1) {
- X report(LOG_INFO, "sending reply (no options)\n");
- X }
- X }
- X else {
- X if (debug > 1) {
- X report(LOG_INFO, "sending reply (unknown options)\n");
- X }
- X }
- X
- X sendreply(0);
- X}
- X
- X
- X
- X/*
- X * Process BOOTREPLY packet (something is using us as a gateway).
- X */
- X
- Xvoid
- Xforward_reply()
- X{
- X if (debug) {
- X report(LOG_INFO, "processing boot reply\n");
- X }
- X sendreply(1);
- X}
- X
- X
- X
- X/*
- X * Send a reply packet to the client. 'forward' flag is set if we are
- X * not the originator of this reply packet.
- X */
- Xsendreply(forward)
- X int forward;
- X{
- X register struct bootp *bp = (struct bootp *) pktbuf;
- X struct in_addr dst; /* XXX */
- X struct sockaddr_in *c_sin;
- X
- X c_sin = (struct sockaddr_in *) &client_addr;
- X
- X c_sin->sin_port = htons(bootpc_port);
- X /*
- X * If the client IP address is specified, use that
- X * else if gateway IP address is specified, use that
- X * else make a temporary arp cache entry for the client's NEW
- X * IP/hardware address and use that.
- X */
- X if (bp->bp_ciaddr.s_addr) {
- X dst = bp->bp_ciaddr;
- X } else if (bp->bp_giaddr.s_addr && forward == 0) {
- X dst = bp->bp_giaddr;
- X c_sin->sin_port = htons(bootps_port);
- X } else {
- X dst = bp->bp_yiaddr;
- X setarp(&dst, bp->bp_chaddr, bp->bp_hlen);
- X }
- X
- X if (forward == 0) {
- X /*
- X * If we are originating this reply, we
- X * need to find our own interface address to
- X * put in the bp_siaddr field of the reply.
- X * If this server is multi-homed, pick the
- X * 'best' interface (the one on the same net
- X * as the client).
- X */
- X int maxmatch = 0;
- X int len, m;
- X register struct ifreq *ifrq, *ifrmax;
- X
- X ifrmax = ifrq = &ifreq[0];
- X len = ifconf.ifc_len;
- X for (; len > 0; len -= sizeof(ifreq[0]), ifrq++) {
- X m = nmatch(&dst, &((struct sockaddr_in *)
- X (&ifrq->ifr_addr))->sin_addr);
- X if (m > maxmatch) {
- X maxmatch = m;
- X ifrmax = ifrq;
- X }
- X }
- X
- X /* XXX - Should put anything here? :gw=: ? */
- X if (bp->bp_giaddr.s_addr == 0) {
- X if (maxmatch == 0) {
- X return;
- X }
- X bp->bp_giaddr = ((struct sockaddr_in *)
- X (&ifrmax->ifr_addr))->sin_addr;
- X }
- X
- X /*
- X * If a specific TFTP server address wasn't specified
- X * in the bootptab file, fill in our own address.
- X */
- X if (bp->bp_siaddr.s_addr == 0) {
- X bp->bp_siaddr = ((struct sockaddr_in *)
- X (&ifrmax->ifr_addr))->sin_addr;
- X }
- X }
- X
- X c_sin->sin_addr = dst;
- X /* Send reply with same size packet as request used. */
- X if (sendto(s, pktbuf, pktlen, 0,
- X &client_addr, sizeof(*c_sin)) < 0) {
- X report(LOG_ERR, "sendto: %s\n", get_network_errmsg());
- X }
- X} /* sendreply */
- X
- X
- X
- X/*
- X * Return the number of leading bytes matching in the
- X * internet addresses supplied.
- X */
- Xnmatch(ca,cb)
- X register char *ca, *cb;
- X{
- X register n,m;
- X
- X for (m = n = 0 ; n < 4 ; n++) {
- X if (*ca++ != *cb++)
- X return(m);
- X m++;
- X }
- X return(m);
- X}
- X
- X
- X
- X/*
- X * Setup the arp cache so that IP address 'ia' will be temporarily
- X * bound to hardware address 'ha' of length 'len'.
- X */
- Xsetarp(ia, ha, len)
- X struct in_addr *ia;
- X byte *ha;
- X int len;
- X{
- X struct sockaddr_in *si;
- X
- X bzero((caddr_t)&arpreq, sizeof(arpreq));
- X
- X arpreq.arp_pa.sa_family = AF_INET;
- X si = (struct sockaddr_in *) &arpreq.arp_pa;
- X si->sin_addr = *ia;
- X
- X arpreq.arp_flags = ATF_INUSE | ATF_COM;
- X
- X bcopy(ha, arpreq.arp_ha.sa_data, len);
- X
- X if (ioctl(s, SIOCSARP, (caddr_t)&arpreq) < 0) {
- X report(LOG_ERR, "ioctl(SIOCSARP): %s\n", get_network_errmsg());
- X }
- X}
- X
- X
- X
- X/*
- X * This call checks read access to a file. It returns 0 if the file given
- X * by "path" exists and is publically readable. A value of -1 is returned if
- X * access is not permitted or an error occurs. Successful calls also
- X * return the file size in bytes using the long pointer "filesize".
- X *
- X * The read permission bit for "other" users is checked. This bit must be
- X * set for tftpd(8) to allow clients to read the file.
- X */
- X
- Xint chk_access(path, filesize)
- Xchar *path;
- Xlong *filesize;
- X{
- X struct stat st;
- X
- X if ((stat(path, &st) == 0) && (st.st_mode & (S_IREAD >> 6))) {
- X *filesize = (long) st.st_size;
- X return 0;
- X } else {
- X return -1;
- X }
- X}
- X
- X
- X
- X#ifdef DEBUG
- X
- X/*
- X * Dump the internal memory database to bootpd_dump.
- X */
- X
- Xvoid dumptab()
- X{
- X register int n;
- X register struct host *hp;
- X register FILE *fp;
- X long t;
- X
- X /*
- X * Open bootpd.dump file.
- X */
- X if ((fp = fopen(bootpd_dump, "w")) == NULL) {
- X report(LOG_ERR, "error opening \"%s\": %s\n", bootpd_dump,
- X get_errmsg());
- X exit(1);
- X }
- X
- X t = time(NULL);
- X fprintf(fp, "\n# %s\n", Version);
- X fprintf(fp, "# %s: dump of bootp server database.\n", bootpd_dump);
- X fprintf(fp, "#\n# Dump taken %s", ctime(&t));
- X fprintf(fp, "#\n#\n# Legend:\n");
- X fprintf(fp, "#\thd -- home directory\n");
- X fprintf(fp, "#\tbf -- bootfile\n");
- X fprintf(fp, "#\tbs -- bootfile size in 512-octet blocks\n");
- X fprintf(fp, "#\tcs -- cookie servers\n");
- X fprintf(fp, "#\tds -- domain name servers\n");
- X fprintf(fp, "#\tgw -- gateways\n");
- X fprintf(fp, "#\tha -- hardware address\n");
- X fprintf(fp, "#\thd -- home directory for bootfiles\n");
- X fprintf(fp, "#\tht -- hardware type\n");
- X fprintf(fp, "#\tim -- impress servers\n");
- X fprintf(fp, "#\tip -- host IP address\n");
- X fprintf(fp, "#\tlg -- log servers\n");
- X fprintf(fp, "#\tlp -- LPR servers\n");
- X fprintf(fp, "#\tns -- IEN-116 name servers\n");
- X fprintf(fp, "#\trl -- resource location protocol servers\n");
- X fprintf(fp, "#\tsm -- subnet mask\n");
- X fprintf(fp, "#\tto -- time offset (seconds)\n");
- X fprintf(fp, "#\tts -- time servers\n\n\n");
- X
- X n = 0;
- X for (hp = (struct host *) hash_FirstEntry(nmhashtable); hp != NULL;
- X hp = (struct host *) hash_NextEntry(nmhashtable)) {
- X dump_host(fp, hp);
- X fprintf(fp, "\n");
- X n++;
- X }
- X fclose(fp);
- X
- X report(LOG_INFO, "dumped %d entries to \"%s\".\n", n, bootpd_dump);
- X}
- X
- X
- X
- X/*
- X * Dump all the available information on the host pointed to by "hp".
- X * The output is sent to the file pointed to by "fp".
- X */
- X
- Xvoid dump_host(fp, hp)
- XFILE *fp;
- Xstruct host *hp;
- X{
- X register int i;
- X register byte *dataptr;
- X
- X if (hp) {
- X if (hp->hostname) {
- X fprintf(fp, "%s:", hp->hostname->string);
- X }
- X if (hp->flags.bootfile) {
- X fprintf(fp, "bf=%s:", hp->bootfile->string);
- X }
- X if (hp->flags.bootsize) {
- X fprintf(fp, "bs=");
- X if (hp->flags.bootsize_auto) {
- X fprintf(fp, "auto:");
- X } else {
- X fprintf(fp, "%d:", hp->bootsize);
- X }
- X }
- X if (hp->flags.cookie_server) {
- X fprintf(fp, "cs=");
- X list_ipaddresses(fp, hp->cookie_server);
- X fprintf(fp, ":");
- X }
- X if (hp->flags.domain_server) {
- X fprintf(fp, "ds=");
- X list_ipaddresses(fp, hp->domain_server);
- X fprintf(fp, ":");
- X }
- X if (hp->flags.gateway) {
- X fprintf(fp, "gw=");
- X list_ipaddresses(fp, hp->gateway);
- X fprintf(fp, ":");
- X }
- X if (hp->flags.homedir) {
- X fprintf(fp, "hd=%s:", hp->homedir->string);
- X }
- X if (hp->flags.name_switch && hp->flags.send_name) {
- X fprintf(fp, "hn:");
- X }
- X if (hp->flags.htype) {
- X fprintf(fp, "ht=%u:", (unsigned) hp->htype);
- X if (hp->flags.haddr) {
- X fprintf(fp, "ha=%s:", haddrtoa(hp->haddr, hp->htype));
- X }
- X }
- X if (hp->flags.impress_server) {
- X fprintf(fp, "im=");
- X list_ipaddresses(fp, hp->impress_server);
- X fprintf(fp, ":");
- X }
- X if (hp->flags.iaddr) {
- X fprintf(fp, "ip=%s:", inet_ntoa(hp->iaddr));
- X }
- X if (hp->flags.log_server) {
- X fprintf(fp, "lg=");
- X list_ipaddresses(fp, hp->log_server);
- X fprintf(fp, ":");
- X }
- X if (hp->flags.lpr_server) {
- X fprintf(fp, "lp=");
- X list_ipaddresses(fp, hp->lpr_server);
- X fprintf(fp, ":");
- X }
- X if (hp->flags.name_server) {
- X fprintf(fp, "ns=");
- X list_ipaddresses(fp, hp->name_server);
- X fprintf(fp, ":");
- X }
- X if (hp->flags.rlp_server) {
- X fprintf(fp, "rl=");
- X list_ipaddresses(fp, hp->rlp_server);
- X fprintf(fp, ":");
- X }
- X if (hp->flags.bootserver) {
- X fprintf(fp, "sa=%s:", inet_ntoa(hp->bootserver));
- X }
- X if (hp->flags.subnet_mask) {
- X fprintf(fp, "sm=%s:", inet_ntoa(hp->subnet_mask));
- X }
- X if (hp->flags.tftpdir) {
- X fprintf(fp, "td=%s:", hp->tftpdir->string);
- X }
- X if (hp->flags.time_offset) {
- X if (hp->flags.timeoff_auto) {
- X fprintf(fp, "to=auto:");
- X } else {
- X fprintf(fp, "to=%ld:", hp->time_offset);
- X }
- X }
- X if (hp->flags.time_server) {
- X fprintf(fp, "ts=");
- X list_ipaddresses(fp, hp->time_server);
- X fprintf(fp, ":");
- X }
- X if (hp->flags.vendor_magic) {
- X fprintf(fp, "vm=");
- X if (hp->flags.vm_auto) {
- X fprintf(fp, "auto:");
- X } else if (!bcmp(hp->vm_cookie, vm_cmu, 4)) {
- X fprintf(fp, "cmu:");
- X } else if (!bcmp(hp->vm_cookie, vm_rfc1048, 4)) {
- X fprintf(fp, "rfc1048");
- X } else {
- X fprintf(fp, "%d.%d.%d.%d:",
- X (int) ((hp->vm_cookie)[0]),
- X (int) ((hp->vm_cookie)[1]),
- X (int) ((hp->vm_cookie)[2]),
- X (int) ((hp->vm_cookie)[3]));
- X }
- X }
- X if (hp->flags.generic) {
- X fprintf(fp, "generic=");
- X dataptr = hp->generic->data;
- X for (i = hp->generic->length; i > 0; i--) {
- X fprintf(fp, "%02X", (int) *dataptr++);
- X }
- X fprintf(fp, ":");
- X }
- X }
- X}
- X
- X
- X
- X/*
- X * Dump an entire struct in_addr_list of IP addresses to the indicated file.
- X *
- X * The addresses are printed in standard ASCII "dot" notation and separated
- X * from one another by a single space. A single leading space is also
- X * printed before the first adddress.
- X *
- X * Null lists produce no output (and no error).
- X */
- X
- Xvoid list_ipaddresses(fp, ipptr)
- X FILE *fp;
- X struct in_addr_list *ipptr;
- X{
- X register unsigned count;
- X register struct in_addr *addrptr;
- X
- X if (ipptr) {
- X count = ipptr->addrcount;
- X addrptr = ipptr->addr;
- X if (count-- > 0) {
- X fprintf(fp, "%s", inet_ntoa(*addrptr++));
- X while (count-- > 0) {
- X fprintf(fp, " %s", inet_ntoa(*addrptr++));
- X }
- X }
- X }
- X}
- X#endif /* DEBUG */
- X
- X
- X
- X#ifdef VEND_CMU
- X
- X/*
- X * Insert the CMU "vendor" data for the host pointed to by "hp" into the
- X * bootp packet pointed to by "bp".
- X */
- X
- Xvoid dovend_cmu(bp, hp)
- X register struct bootp *bp;
- X register struct host *hp;
- X{
- X struct cmu_vend *vendp;
- X register struct in_addr_list *taddr;
- X
- X /*
- X * Initialize the entire vendor field to zeroes.
- X */
- X bzero(bp->bp_vend, sizeof(bp->bp_vend));
- X
- X /*
- X * Fill in vendor information. Subnet mask, default gateway,
- X * domain name server, ien name server, time server
- X */
- X vendp = (struct cmu_vend *) bp->bp_vend;
- X if (hp->flags.subnet_mask) {
- X (vendp->v_smask).s_addr = hp->subnet_mask.s_addr;
- X (vendp->v_flags) |= VF_SMASK;
- X if (hp->flags.gateway) {
- X (vendp->v_dgate).s_addr = hp->gateway->addr->s_addr;
- X }
- X }
- X if (hp->flags.domain_server) {
- X taddr = hp->domain_server;
- X if (taddr->addrcount > 0) {
- X (vendp->v_dns1).s_addr = (taddr->addr)[0].s_addr;
- X if (taddr->addrcount > 1) {
- X (vendp->v_dns2).s_addr = (taddr->addr)[1].s_addr;
- X }
- X }
- X }
- X if (hp->flags.name_server) {
- X taddr = hp->name_server;
- X if (taddr->addrcount > 0) {
- X (vendp->v_ins1).s_addr = (taddr->addr)[0].s_addr;
- X if (taddr->addrcount > 1) {
- X (vendp->v_ins2).s_addr = (taddr->addr)[1].s_addr;
- X }
- X }
- X }
- X if (hp->flags.time_server) {
- X taddr = hp->time_server;
- X if (taddr->addrcount > 0) {
- X (vendp->v_ts1).s_addr = (taddr->addr)[0].s_addr;
- X if (taddr->addrcount > 1) {
- X (vendp->v_ts2).s_addr = (taddr->addr)[1].s_addr;
- X }
- X }
- X }
- X strcpy(vendp->v_magic, vm_cmu);
- X
- X} /* dovend_cmu */
- X
- X#endif /* VEND_CMU */
- X
- X
- X
- X/*
- X * Fill in the RFC1048 options. All tag and length bytes provided
- X * by the client must be left where they are. Data associated with
- X * each option are updated if we have a value for the option.
- X *
- X * This implementation does not change any tag or length bytes.
- X *
- X * One could append additional options when there is room after the
- X * end record but this implementation does not do so. One would need
- X * a way to know which options should be "forced" into the list.
- X */
- Xvoid dovend_rfc1048(bp, hp, bootsize)
- X register struct bootp *bp;
- X register struct host *hp;
- X long bootsize; /* "auto" value, from stat() */
- X{
- X int i, n, len;
- X byte *vp, *ep;
- X byte tag;
- X char *tmpstr;
- X unsigned long ul;
- X unsigned short us;
- X
- X /*
- X * Compute pointers to beginning and end of option area.
- X * Note that options (formerly "vendor data") are now
- X * allowed to extend to the end of the packet, and are
- X * not limited to a maximum of BP_VEND_LEN bytes.
- X * That value is the MINIMUM size of the option area.
- X * (See the IETF draft: Clarifications and Extensions
- X * for the Bootstrap Protocol, W. Wimer, Sept. 1992.)
- X */
- X vp = bp->bp_vend;
- X ep = ((char *)bp) + pktlen;
- X
- X /* Step over the magic cookie (checked by caller). */
- X vp += 4;
- X
- X while (vp < ep) {
- X tag = *vp++;
- X
- X /* Check for tags with no data first. */
- X if (tag == TAG_PAD)
- X continue;
- X if (tag == TAG_END)
- X return;
- X
- X /* Now scan the length byte. */
- X len = *vp++;
- X
- X if (vp + len >= ep) {
- X report(LOG_ERR, "truncated field in vendor data\n");
- X /* do the best we can... */
- X len = ep - vp;
- X }
- X
- X switch (tag) {
- X
- X case TAG_SUBNET_MASK: /* may demand len==4 */
- X if (len >= 4) {
- X ul = hp->subnet_mask.s_addr;
- X bcopy((char*)&ul, vp, 4);
- X }
- X break;
- X
- X case TAG_TIME_OFFSET: /* may demand len==4 */
- X if (len >= 4) {
- X ul = (hp->flags.timeoff_auto) ?
- X secondswest : hp->time_offset;
- X ul = htonl(ul);
- X bcopy((char*)&ul, vp, 4);
- X }
- X break;
- X
- X case TAG_GATEWAY:
- X if (hp->flags.gateway)
- X insert_ip(hp->gateway, vp, len);
- X break;
- X
- X case TAG_TIME_SERVER:
- X if (hp->flags.time_server)
- X insert_ip(hp->time_server, vp, len);
- X break;
- X
- X case TAG_NAME_SERVER:
- X if (hp->flags.name_server)
- X insert_ip(hp->name_server, vp, len);
- X break;
- X
- X case TAG_DOMAIN_SERVER:
- X if (hp->flags.domain_server)
- X insert_ip(hp->domain_server, vp, len);
- X break;
- X
- X case TAG_LOG_SERVER:
- X if (hp->flags.log_server)
- X insert_ip(hp->log_server, vp, len);
- X break;
- X
- X case TAG_COOKIE_SERVER:
- X if (hp->flags.cookie_server)
- X insert_ip(hp->cookie_server, vp, len);
- X break;
- X
- X case TAG_LPR_SERVER:
- X if (hp->flags.lpr_server)
- X insert_ip(hp->lpr_server, vp, len);
- X break;
- X
- X case TAG_IMPRESS_SERVER:
- X if (hp->flags.impress_server)
- X insert_ip(hp->impress_server, vp, len);
- X break;
- X
- X case TAG_RLP_SERVER:
- X if (hp->flags.rlp_server)
- X insert_ip(hp->rlp_server, vp, len);
- X break;
- X
- X case TAG_HOSTNAME: /* of client */
- X if (hp->flags.name_switch &&
- X hp->flags.send_name) {
- X
- X /* Room for the whole name? */
- X n = strlen(hp->hostname->string);
- X if (n < len) {
- X bcopy(hp->hostname->string, vp, n);
- X } else {
- X /*
- X * Not enough room for fully qualified hostname,
- X * try stripping off the domain parts.
- X */
- X if (debug > 1)
- X report(LOG_INFO, "shortening hostname to fit\n");
- X tmpstr = index(hp->hostname->string, '.');
- X if (tmpstr) {
- X n = tmpstr - hp->hostname->string;
- X bcopy(hp->hostname->string, vp, n);
- X }
- X }
- X }
- X break;
- X
- X case TAG_BOOTSIZE:
- X if (len >= 2) {
- X if (hp->flags.bootsize_auto)
- X us = (bootsize + 511) / 512; /* Round up */
- X else us = hp->bootsize;
- X bcopy((char*)&us, vp, 2);
- X }
- X break;
- X
- X default:
- X if (hp->flags.generic)
- X insert_generic(tag, hp->generic, vp, len);
- X break;
- X
- X } /* switch (tag) */
- X vp += len;
- X } /* while */
- X return;
- X} /* dovend_rfc1048 */
- X
- X
- X
- X/*
- X * Compare function to determine whether two hardware addresses are
- X * equivalent. Returns TRUE if "host1" and "host2" are equivalent, FALSE
- X * otherwise.
- X *
- X * This function is used when retrieving elements from the hardware address
- X * hash table.
- X */
- X
- Xboolean hwlookcmp(host1, host2)
- X struct host *host1, *host2;
- X{
- X if (host1->htype != host2->htype) {
- X return FALSE;
- X }
- X if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
- X return FALSE;
- X }
- X return TRUE;
- X}
- X
- X
- X
- X
- X/*
- X * Compare function for doing IP address hash table lookup.
- X */
- X
- Xboolean iplookcmp(host1, host2)
- X struct host *host1, *host2;
- X{
- X return (host1->iaddr.s_addr == host2->iaddr.s_addr);
- X}
- X
- X
- X
- X/*
- X * Copy a list of IP addresses to the memory buffer "dest".
- X * The "iplist" is a pointer to a list of IP addresses
- X * (struct in_addr_list), and "len" points to an integer which
- X * indicates the size of the "dest" buffer.
- X *
- X * This is used to fill the vendor-specific area of a bootp packet in
- X * conformance to RFC1048.
- X */
- X
- Xvoid insert_ip(iplist, dest, len)
- X struct in_addr_list *iplist;
- X byte *dest;
- X int len; /* space for this list */
- X{
- X register struct in_addr *addrptr;
- X register unsigned addrcount;
- X
- X if (!iplist) return;
- X
- X addrptr = iplist->addr;
- X addrcount = iplist->addrcount;
- X while ((len >= 4) && (addrcount > 0)) {
- X bcopy(addrptr, dest, 4);
- X addrptr++;
- X addrcount--;
- X dest += 4;
- X len -= 4;
- X }
- X}
- X
- X
- X
- X/*
- X * Find an RFC1048 record of type "tag" and copy it to "dest".
- X * The data in "gendata" is assumed to already in RFC1048 format.
- X */
- X
- Xvoid insert_generic(tag, gendata, dest, destlen)
- X int tag;
- X struct shared_bindata *gendata;
- X byte *dest;
- X int destlen;
- X{
- X byte *srcptr, *ep;
- X register int t, n;
- X
- X if (!gendata) return;
- X
- X srcptr = gendata->data;
- X ep = srcptr + gendata->length;
- X
- X /* Search the generic records for a tag of the desired type. */
- X while (srcptr < ep) {
- X t = *srcptr++;
- X n = *srcptr++;
- X
- X if (t == tag) {
- X /* Copy whatever fits. */
- X if (n > destlen)
- X n = destlen;
- X bcopy(srcptr, dest, n);
- X return;
- X }
- X srcptr += n;
- X }
- X}
- X
- X
- X
- X
- X/*
- X * Convert a hardware address to an ASCII string.
- X */
- X
- Xchar *haddrtoa(haddr, htype)
- X register byte *haddr;
- X byte htype;
- X{
- X static char haddrbuf[2 * MAXHADDRLEN + 1];
- X register char *bufptr;
- X register unsigned count;
- X
- X bufptr = haddrbuf;
- X for (count = haddrlength(htype); count > 0; count--) {
- X sprintf(bufptr, "%02X", (unsigned) (*haddr++ & 0xFF));
- X bufptr += 2;
- X }
- X return (haddrbuf);
- X}
- X
- X
- X
- X/*
- X * Return pointer to static string which gives full filesystem error message.
- X */
- X
- Xchar *get_errmsg()
- X{
- X static char errmsg[80];
- X
- X if (errno < sys_nerr) {
- X return sys_errlist[errno];
- X } else {
- X sprintf(errmsg, "Error %d", errno);
- X return errmsg;
- X }
- X}
- X
- X
- X
- X/*
- X * This routine reports errors and such via stderr and syslog() if
- X * appopriate. It just helps avoid a lot of "#ifdef SYSLOG" constructs
- X * from being scattered throughout the code.
- X *
- X * The syntax is identical to syslog(3), but %m is not considered special
- X * for output to stderr (i.e. you'll see "%m" in the output. . .). Also,
- X * control strings should normally end with \n since newlines aren't
- X * automatically generated for stderr output (whereas syslog strips out all
- X * newlines and adds its own at the end).
- X */
- X
- X/*VARARGS2*/
- Xvoid report(priority, fmt, p0, p1, p2, p3, p4)
- X int priority;
- X char *fmt;
- X{
- X#ifdef LOG_SALERT
- X static char *levelnames[] = {
- X "unknown level: ",
- X "alert(1): ",
- X "subalert(2): ",
- X "emergency(3): ",
- X "error(4): ",
- X "critical(5): ",
- X "warning(6): ",
- X "notice(7): ",
- X "information(8):",
- X "debug(9): ",
- X "unknown level: "
- X };
- X#else
- X static char *levelnames[] = {
- X "emergency(0): ",
- X "alert(1): ",
- X "critical(2): ",
- X "error(3): ",
- X "warning(4): ",
- X "notice(5): ",
- X "information(6):",
- X "debug(7): ",
- X "unknown level: "
- X };
- X#endif
- X
- X if ((priority < 0) || (priority >= sizeof(levelnames)/sizeof(char *))) {
- X priority = sizeof(levelnames) / sizeof(char *) - 1;
- X }
- X
- X /*
- X * Print the message
- X */
- X if (debug > 2) {
- X fprintf(stderr, "bootpd: %s ", levelnames[priority]);
- X fprintf(stderr, fmt, p0, p1, p2, p3, p4);
- X }
- X#ifdef SYSLOG
- X syslog(priority, fmt, p0, p1, p2, p3, p4);
- X#endif
- X}
- END_OF_FILE
- if test 40573 -ne `wc -c <'bootpd.c'`; then
- echo shar: \"'bootpd.c'\" unpacked with wrong size!
- fi
- # end of 'bootpd.c'
- fi
- if test -f 'readfile.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'readfile.c'\"
- else
- echo shar: Extracting \"'readfile.c'\" \(49372 characters\)
- sed "s/^X//" >'readfile.c' <<'END_OF_FILE'
- X#ifndef _BLURB_
- X#define _BLURB_
- X/************************************************************************
- X Copyright 1988, 1991 by Carnegie Mellon University
- X
- X All Rights Reserved
- X
- XPermission to use, copy, modify, and distribute this software and its
- Xdocumentation for any purpose and without fee is hereby granted, provided
- Xthat the above copyright notice appear in all copies and that both that
- Xcopyright notice and this permission notice appear in supporting
- Xdocumentation, and that the name of Carnegie Mellon University not be used
- Xin advertising or publicity pertaining to distribution of the software
- Xwithout specific, written prior permission.
- X
- XCARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
- XSOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
- XIN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
- XDAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
- XPROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
- XACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
- XSOFTWARE.
- X************************************************************************/
- X#endif /* _BLURB_ */
- X
- X
- X#ifndef lint
- Xstatic char rcsid[] = "$Header: /afs/andrew.cmu.edu/netdev/src/cmu/bootp-public/RCS/readfile.c,v 1.3 1991/11/01 10:02:29 ww0n Exp ww0n $";
- X#endif
- X
- X
- X/*
- X * bootpd configuration file reading code.
- X *
- X * The routines in this file deal with reading, interpreting, and storing
- X * the information found in the bootpd configuration file (usually
- X * /etc/bootptab).
- X */
- X
- X
- X#include <stdio.h>
- X#ifdef SVR4
- X#include <string.h>
- X#else
- X#include <strings.h>
- X#endif
- X#include <ctype.h>
- X#include <sys/errno.h>
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#include <sys/file.h>
- X#include <sys/time.h>
- X#include <netinet/in.h>
- X#ifdef SYSLOG
- X#include <syslog.h>
- X#endif
- X#include "bootp.h"
- X#include "hash.h"
- X#include "bootpd.h"
- X
- X#ifdef SVR4
- X#define bcopy(a,b,c) memcpy(b,a,c)
- X#define bzero(p,l) memset(p,0,l)
- X#define bcmp(a,b,c) memcmp(a,b,c)
- X#endif
- X
- X#define SUCCESS 0
- X#define E_END_OF_ENTRY (-1)
- X#define E_SYNTAX_ERROR (-2)
- X#define E_UNKNOWN_SYMBOL (-3)
- X#define E_BAD_IPADDR (-4)
- X#define E_BAD_HADDR (-5)
- X#define E_BAD_SMASK (-6)
- X#define E_BAD_TIMEOFF (-7)
- X#define E_BAD_VM_COOKIE (-8)
- X#define E_BAD_HTYPE (-9)
- X#define E_BAD_BOOTSIZE (-10)
- X#define E_BAD_BOOT_SERVER (-11)
- X#define E_BAD_HOMEDIR (-12)
- X#define E_BAD_TFTPDIR (-13)
- X
- X#define SYM_NULL 0
- X#define SYM_BOOTFILE 1
- X#define SYM_COOKIE_SERVER 2
- X#define SYM_DOMAIN_SERVER 3
- X#define SYM_GATEWAY 4
- X#define SYM_HADDR 5
- X#define SYM_HOMEDIR 6
- X#define SYM_HTYPE 7
- X#define SYM_IMPRESS_SERVER 8
- X#define SYM_IPADDR 9
- X#define SYM_LOG_SERVER 10
- X#define SYM_LPR_SERVER 11
- X#define SYM_NAME_SERVER 12
- X#define SYM_RLP_SERVER 13
- X#define SYM_SUBNET_MASK 14
- X#define SYM_TIME_OFFSET 15
- X#define SYM_TIME_SERVER 16
- X#define SYM_VENDOR_MAGIC 17
- X#define SYM_SIMILAR_ENTRY 18
- X#define SYM_NAME_SWITCH 19
- X#define SYM_BOOTSIZE 20
- X#define SYM_BOOT_SERVER 22
- X#define SYM_TFTPDIR 23
- X
- X#define OP_ADDITION 1 /* Operations on tags */
- X#define OP_DELETION 2
- X#define OP_BOOLEAN 3
- X
- X#define MAXINADDRS 16 /* Max size of an IP address list */
- X#define MAXBUFLEN 64 /* Max temp buffer space */
- X#define MAXENTRYLEN 2048 /* Max size of an entire entry */
- X
- XPRIVATE int process_entry();
- XPRIVATE eval_symbol();
- XPRIVATE boolean goodname();
- XPRIVATE prs_inetaddr();
- XPRIVATE int interp_byte();
- X
- X
- X/*
- X * Structure used to map a configuration-file symbol (such as "ds") to a
- X * unique integer.
- X */
- X
- Xstruct symbolmap {
- X char *symbol;
- X int symbolcode;
- X};
- X
- X
- Xstruct htypename {
- X char *name;
- X byte htype;
- X};
- X
- X
- XPRIVATE int nhosts; /* Number of hosts (/w hw or IP address) */
- XPRIVATE int nentries; /* Total number of entries */
- XPRIVATE long modtime = 0; /* Last modification time of bootptab */
- X
- X
- X/*
- X * List of symbolic names used in the bootptab file. The order and actual
- X * values of the symbol codes (SYM_. . .) are unimportant, but they must
- X * all be unique.
- X */
- X
- XPRIVATE struct symbolmap symbol_list[] = {
- X { "bf", SYM_BOOTFILE },
- X { "bs", SYM_BOOTSIZE },
- X { "cs", SYM_COOKIE_SERVER },
- X { "ds", SYM_DOMAIN_SERVER },
- X { "gw", SYM_GATEWAY },
- X { "ha", SYM_HADDR },
- X { "hd", SYM_HOMEDIR },
- X { "hn", SYM_NAME_SWITCH },
- X { "ht", SYM_HTYPE },
- X { "im", SYM_IMPRESS_SERVER },
- X { "ip", SYM_IPADDR },
- X { "lg", SYM_LOG_SERVER },
- X { "lp", SYM_LPR_SERVER },
- X { "ns", SYM_NAME_SERVER },
- X { "rl", SYM_RLP_SERVER },
- X { "sa", SYM_BOOT_SERVER },
- X { "sm", SYM_SUBNET_MASK },
- X { "tc", SYM_SIMILAR_ENTRY },
- X { "td", SYM_TFTPDIR },
- X { "to", SYM_TIME_OFFSET },
- X { "ts", SYM_TIME_SERVER },
- X { "vm", SYM_VENDOR_MAGIC },
- X};
- X
- X
- X/*
- X * List of symbolic names for hardware types. Name translates into
- X * hardware type code listed with it. Names must begin with a letter
- X * and must be all lowercase. This is searched linearly, so put
- X * commonly-used entries near the beginning.
- X */
- X
- XPRIVATE struct htypename htnamemap[] = {
- X { "ethernet", HTYPE_ETHERNET },
- X { "ethernet3", HTYPE_EXP_ETHERNET },
- X { "ether", HTYPE_ETHERNET },
- X { "ether3", HTYPE_EXP_ETHERNET },
- X { "ieee802", HTYPE_IEEE802 },
- X { "tr", HTYPE_IEEE802 },
- X { "token-ring", HTYPE_IEEE802 },
- X { "pronet", HTYPE_PRONET },
- X { "chaos", HTYPE_CHAOS },
- X { "arcnet", HTYPE_ARCNET },
- X { "ax.25", HTYPE_AX25 }
- X};
- X
- X
- X
- X/*
- X * Externals and forward declarations.
- X */
- X
- Xextern char *malloc();
- Xextern boolean iplookcmp();
- Xextern int errno;
- X
- XPRIVATE char *smalloc();
- XPRIVATE void fill_defaults();
- XPRIVATE void del_string();
- XPRIVATE void del_bindata();
- XPRIVATE void del_iplist();
- XPRIVATE void free_host();
- XPRIVATE u_long get_u_long();
- XPRIVATE void process_generic();
- XPRIVATE char *get_string();
- XPRIVATE struct shared_string *get_shared_string();
- XPRIVATE void read_entry();
- XPRIVATE boolean nullcmp();
- XPRIVATE boolean nmcmp();
- XPRIVATE boolean hwinscmp();
- XPRIVATE void adjust();
- XPRIVATE void eat_whitespace();
- XPRIVATE void makelower();
- XPRIVATE struct in_addr_list *get_addresses();
- XPRIVATE byte *prs_haddr();
- X
- X
- X
- X
- X
- X/*
- X * Read bootptab database file. Avoid rereading the file if the
- X * write date hasn't changed since the last time we read it.
- X */
- X
- Xvoid readtab()
- X{
- X struct host *hp;
- X FILE *fp;
- X struct stat st;
- X unsigned hashcode, buflen;
- X static char buffer[MAXENTRYLEN];
- X#ifdef DEBUG
- X char timestr[26];
- X#endif
- X
- X /*
- X * Check the last modification time.
- X */
- X if (stat(bootptab, &st) < 0) {
- X report(LOG_ERR, "stat on \"%s\": %s\n", bootptab, get_errmsg());
- X return;
- X }
- X#ifdef DEBUG
- X if (debug > 3) {
- X strcpy(timestr, ctime(&(st.st_mtime)));
- X report(LOG_INFO, "bootptab mtime is %s",
- X timestr);
- X }
- X#endif
- X if (st.st_mtime == modtime && st.st_nlink) {
- X /*
- X * hasn't been modified or deleted yet.
- X */
- X return;
- X }
- X report(LOG_INFO, "reading %s\"%s\"\n",
- X (modtime != 0L) ? "new " : "",
- X bootptab);
- X
- X /*
- X * Open bootptab file.
- X */
- X if ((fp = fopen(bootptab, "r")) == NULL) {
- X report(LOG_ERR, "error opening \"%s\": %s\n", bootptab, get_errmsg());
- X return;
- X }
- X
- X /*
- X * Record file modification time.
- X */
- X if (fstat(fileno(fp), &st) < 0) {
- X report(LOG_ERR, "fstat: %s\n", get_errmsg());
- X fclose(fp);
- X return;
- X }
- X modtime = st.st_mtime;
- X
- X /*
- X * Entirely erase all hash tables.
- X */
- X hash_Reset(hwhashtable, free_host);
- X hash_Reset(iphashtable, free_host);
- X hash_Reset(nmhashtable, free_host);
- X
- X nhosts = 0;
- X nentries = 0;
- X while (TRUE) {
- X buflen = sizeof(buffer);
- X read_entry(fp, buffer, &buflen);
- X if (buflen == 0) { /* More entries? */
- X break;
- X }
- X hp = (struct host *) smalloc(sizeof(struct host));
- X
- X /*
- X * Get individual info
- X */
- X hp->flags.vm_auto = TRUE;
- X bcopy(vm_rfc1048, hp->vm_cookie, 4);
- X if (process_entry(hp, buffer) < 0) {
- X free_host(hp);
- X continue;
- X }
- X
- X if ((hp->flags.htype && hp->flags.haddr) || hp->flags.iaddr) {
- X nhosts++;
- X }
- X if (hp->flags.htype && hp->flags.haddr) {
- X hashcode = hash_HashFunction(hp->haddr, haddrlength(hp->htype));
- X if (hash_Insert(hwhashtable, hashcode, hwinscmp, hp, hp) < 0) {
- X report(LOG_WARNING, "duplicate %s address: %s\n",
- X netname(hp->htype),
- X haddrtoa(hp->haddr, hp->htype));
- X free_host(hp);
- X continue;
- X }
- X }
- X if (hp->flags.iaddr) {
- X hashcode = hash_HashFunction(&(hp->iaddr.s_addr), 4);
- X if (hash_Insert(iphashtable, hashcode, nullcmp, hp, hp) < 0) {
- X report(LOG_ERR,
- X "hash_Insert() failed on IP address insertion\n");
- X }
- X }
- X
- X hashcode = hash_HashFunction(hp->hostname->string,
- X strlen(hp->hostname->string));
- X if (hash_Insert(nmhashtable, hashcode, nullcmp, hp->hostname->string, hp) < 0) {
- X report(LOG_ERR,
- X "hash_Insert() failed on insertion of hostname: \"%s\"\n",
- X hp->hostname->string);
- X }
- X nentries++;
- X }
- X
- Xdone:
- X fclose(fp);
- X report(LOG_INFO, "read %d entries (%d hosts) from \"%s\"\n",
- X nentries, nhosts, bootptab);
- X return;
- X}
- X
- X
- X
- X/*
- X * Read an entire host entry from the file pointed to by "fp" and insert it
- X * into the memory pointed to by "buffer". Leading whitespace and comments
- X * starting with "#" are ignored (removed). Backslashes (\) always quote
- X * the next character except that newlines preceeded by a backslash cause
- X * line-continuation onto the next line. The entry is terminated by a
- X * newline character which is not preceeded by a backslash. Sequences
- X * surrounded by double quotes are taken literally (including newlines, but
- X * not backslashes).
- X *
- X * The "bufsiz" parameter points to an unsigned int which specifies the
- X * maximum permitted buffer size. Upon return, this value will be replaced
- X * with the actual length of the entry (not including the null terminator).
- X *
- X * This code is a little scary. . . . I don't like using gotos in C
- X * either, but I first wrote this as an FSM diagram and gotos seemed like
- X * the easiest way to implement it. Maybe later I'll clean it up.
- X */
- X
- XPRIVATE void read_entry(fp, buffer, bufsiz)
- XFILE *fp;
- Xchar *buffer;
- Xunsigned *bufsiz;
- X{
- X int c, length;
- X
- X length = 0;
- X
- X /*
- X * Eat whitespace, blank lines, and comment lines.
- X */
- Xtop:
- X c = fgetc(fp);
- X if (c < 0) {
- X goto done; /* Exit if end-of-file */
- X }
- X if (isspace(c)) {
- X goto top; /* Skip over whitespace */
- X }
- X if (c == '#') {
- X while (TRUE) { /* Eat comments after # */
- X c = fgetc(fp);
- X if (c < 0) {
- X goto done; /* Exit if end-of-file */
- X }
- X if (c == '\n') {
- X goto top; /* Try to read the next line */
- X }
- X }
- X }
- X ungetc(c, fp); /* Other character, push it back to reprocess it */
- X
- X
- X /*
- X * Now we're actually reading a data entry. Get each character and
- X * assemble it into the data buffer, processing special characters like
- X * double quotes (") and backslashes (\).
- X */
- X
- Xmainloop:
- X c = fgetc(fp);
- X switch (c) {
- X case EOF:
- X case '\n':
- X goto done; /* Exit on EOF or newline */
- X case '\\':
- X c = fgetc(fp); /* Backslash, read a new character */
- X if (c < 0) {
- X goto done; /* Exit on EOF */
- X }
- X *buffer++ = c; /* Store the literal character */
- X length++;
- X if (length < *bufsiz - 1) {
- X goto mainloop;
- X } else {
- X goto done;
- X }
- X case '"':
- X *buffer++ = '"'; /* Store double-quote */
- X length++;
- X if (length >= *bufsiz - 1) {
- X goto done;
- X }
- X while (TRUE) { /* Special quote processing loop */
- X c = fgetc(fp);
- X switch (c) {
- X case EOF:
- X goto done; /* Exit on EOF . . . */
- X case '"':
- X *buffer++ = '"'; /* Store matching quote */
- X length++;
- X if (length < *bufsiz - 1) {
- X goto mainloop; /* And continue main loop */
- X } else {
- X goto done;
- X }
- X case '\\':
- X if ((c = fgetc(fp)) < 0) { /* Backslash */
- X goto done; /* EOF. . . .*/
- X } /* else fall through */
- X default:
- X *buffer++ = c; /* Other character, store it */
- X length++;
- X if (length >= *bufsiz - 1) {
- X goto done;
- X }
- X }
- X }
- X case ':':
- X *buffer++ = c; /* Store colons */
- X length++;
- X if (length >= *bufsiz - 1) {
- X goto done;
- X }
- X
- X do { /* But remove whitespace after them */
- X c = fgetc(fp);
- X if ((c < 0) || (c == '\n')) {
- X goto done;
- X }
- X } while (isspace(c)); /* Skip whitespace */
- X
- X if (c == '\\') { /* Backslash quotes next character */
- X c = fgetc(fp);
- X if (c < 0) {
- X goto done;
- X }
- X if (c == '\n') {
- X goto top; /* Backslash-newline continuation */
- X }
- X }
- X /* fall through if "other" character */
- X default:
- X *buffer++ = c; /* Store other characters */
- X length++;
- X if (length >= *bufsiz - 1) {
- X goto done;
- X }
- X }
- X goto mainloop; /* Keep going */
- X
- Xdone:
- X *buffer = '\0'; /* Terminate string */
- X *bufsiz = length; /* Tell the caller its length */
- X}
- X
- X
- X
- X/*
- X * Parse out all the various tags and parameters in the host entry pointed
- X * to by "src". Stuff all the data into the appropriate fields of the
- X * host structure pointed to by "host". If there is any problem with the
- X * entry, an error message is reported via report(), no further processing
- X * is done, and -1 is returned. Successful calls return 0.
- X *
- X * (Some errors probably shouldn't be so completely fatal. . . .)
- X */
- X
- XPRIVATE int process_entry(host, src)
- Xstruct host *host;
- Xchar *src;
- X{
- X int retval;
- X
- X if (!host || *src == '\0') {
- X return -1;
- X }
- X host->hostname = get_shared_string(&src);
- X if (!goodname(host->hostname->string)) {
- X report(LOG_ERR, "bad hostname: \"%s\"\n", host->hostname->string);
- X del_string(host->hostname);
- X return -1;
- X }
- X adjust(&src);
- X while (TRUE) {
- X retval = eval_symbol(&src, host);
- X switch (retval) {
- X case SUCCESS:
- X break;
- X case E_SYNTAX_ERROR:
- X report(LOG_ERR, "syntax error in entry for host \"%s\"\n",
- X host->hostname->string);
- X return -1;
- X case E_UNKNOWN_SYMBOL:
- X report(LOG_ERR, "unknown symbol in entry for host \"%s\"\n",
- X host->hostname->string);
- X return -1;
- X case E_BAD_IPADDR:
- X report(LOG_ERR, "bad IP address for host \"%s\"\n",
- X host->hostname->string);
- X return -1;
- X case E_BAD_HADDR:
- X report(LOG_ERR, "bad hardware address for host \"%s\"\n",
- X host->hostname->string);
- X return -1;
- X case E_BAD_SMASK:
- X report(LOG_ERR, "bad subnet mask for host \"%s\"\n",
- X host->hostname->string);
- X return -1;
- X case E_BAD_TIMEOFF:
- X report(LOG_ERR, "bad time offset for host \"%s\"\n",
- X host->hostname->string);
- X return -1;
- X case E_BAD_VM_COOKIE:
- X report(LOG_ERR, "bad vendor magic cookie for host \"%s\"\n",
- X host->hostname->string);
- X return -1;
- X case E_BAD_HOMEDIR:
- X report(LOG_ERR, "bad home directory for host \"%s\"\n",
- X host->hostname->string);
- X return -1;
- X case E_BAD_TFTPDIR:
- X report(LOG_ERR, "bad TFTP directory for host \"%s\"\n",
- X host->hostname->string);
- X return -1;
- X case E_BAD_BOOT_SERVER:
- X report(LOG_ERR, "bad boot server IP address for host \"%s\"\n",
- X host->hostname->string);
- X return -1;
- X case E_END_OF_ENTRY:
- X default:
- X#if 0
- X /*
- X * For now, don't try to make-up a subnet mask if one
- X * wasn't specified.
- X *
- X * This algorithm is also not entirely correct.
- X */
- X if (!(hp->flags.subnet_mask)) {
- X /*
- X * Try to deduce the subnet mask from the network class
- X */
- X value = (ntohl(value) >> 30) & 0x03;
- X switch (value) {
- X case 0:
- X case 1:
- X hp->subnet_mask.s_addr = htonl(0xFF000000L);
- X break;
- X case 2:
- X hp->subnet_mask.s_addr = htonl(0xFFFF0000L);
- X break;
- X case 3:
- X hp->subnet_mask.s_addr = htonl(0xFFFFFF00L);
- X break;
- X }
- X hp->flags.subnet_mask = TRUE;
- X }
- X#endif
- X /*
- X * And now we're done with this entry
- X */
- X return 0;
- X }
- X adjust(&src);
- X }
- X}
- X
- X
- X
- X/*
- X * Evaluate the two-character tag symbol pointed to by "symbol" and place
- X * the data in the structure pointed to by "hp". The pointer pointed to
- X * by "symbol" is updated to point past the source string (but may not
- X * point to the next tag entry).
- X *
- X * Obviously, this need a few more comments. . . .
- X */
- X
- XPRIVATE eval_symbol(symbol, hp)
- Xchar **symbol;
- Xstruct host *hp;
- X{
- X char tmpstr[MAXSTRINGLEN];
- X byte *tmphaddr, *ustr;
- X struct shared_string *ss;
- X struct symbolmap *symbolptr;
- X u_long value;
- X long timeoff;
- X int i, numsymbols;
- X unsigned len;
- X int optype; /* Indicates boolean, addition, or deletion */
- X
- X if ((*symbol)[0] == '\0') {
- X return E_END_OF_ENTRY;
- X }
- X if ((*symbol)[0] == ':') {
- X return SUCCESS;
- X }
- X if ((*symbol)[0] == 'T') { /* generic symbol */
- X (*symbol)++;
- X value = get_u_long(symbol);
- X eat_whitespace(symbol);
- X if ((*symbol)[0] != '=') {
- X return E_SYNTAX_ERROR;
- X }
- X (*symbol)++;
- X if (!(hp->generic)) {
- X hp->generic = (struct shared_bindata *)
- X smalloc(sizeof(struct shared_bindata));
- X }
- X process_generic(symbol, &(hp->generic), (byte) (value & 0xFF));
- X hp->flags.generic = TRUE;
- X return SUCCESS;
- X }
- X
- X eat_whitespace(symbol);
- X
- X /*
- X * Determine the type of operation to be done on this symbol
- X */
- X switch ((*symbol)[2]) {
- X case '=':
- X optype = OP_ADDITION;
- X break;
- X case '@':
- X optype = OP_DELETION;
- X break;
- X case ':':
- X case '\0':
- X optype = OP_BOOLEAN;
- X break;
- X default:
- X return E_SYNTAX_ERROR;
- X }
- X
- X symbolptr = symbol_list;
- X numsymbols = sizeof(symbol_list) / sizeof(struct symbolmap);
- X for (i = 0; i < numsymbols; i++) {
- X if (((symbolptr->symbol)[0] == (*symbol)[0]) &&
- X ((symbolptr->symbol)[1] == (*symbol)[1])) {
- X break;
- X }
- X symbolptr++;
- X }
- X if (i >= numsymbols) {
- X return E_UNKNOWN_SYMBOL;
- X }
- X
- X /*
- X * Skip past the = or @ character (to point to the data) if this
- X * isn't a boolean operation. For boolean operations, just skip
- X * over the two-character tag symbol (and nothing else. . . .).
- X */
- X (*symbol) += (optype == OP_BOOLEAN) ? 2 : 3;
- X
- X switch (symbolptr->symbolcode) {
- X case SYM_BOOTFILE:
- X switch (optype) {
- X case OP_ADDITION:
- X if (ss = get_shared_string(symbol)) {
- X if (hp->bootfile) {
- X del_string(hp->bootfile);
- X }
- X hp->bootfile = ss;
- X hp->flags.bootfile = TRUE;
- X }
- X break;
- X case OP_DELETION:
- X if (hp->bootfile) {
- X del_string(hp->bootfile);
- X }
- X hp->bootfile = NULL;
- X hp->flags.bootfile = FALSE;
- X break;
- X case OP_BOOLEAN:
- X return E_SYNTAX_ERROR;
- X }
- X break;
- X
- X case SYM_COOKIE_SERVER:
- X switch (optype) {
- X case OP_ADDITION:
- X if (hp->flags.cookie_server && hp->cookie_server) {
- X del_iplist(hp->cookie_server);
- X }
- X hp->cookie_server = get_addresses(symbol);
- X hp->flags.cookie_server = TRUE;
- X break;
- X case OP_DELETION:
- X if (hp->flags.cookie_server && hp->cookie_server) {
- X del_iplist(hp->cookie_server);
- X }
- X hp->cookie_server = NULL;
- X hp->flags.cookie_server = FALSE;
- X break;
- X case OP_BOOLEAN:
- X return E_SYNTAX_ERROR;
- X }
- X break;
- X
- X case SYM_DOMAIN_SERVER:
- X switch (optype) {
- X case OP_ADDITION:
- X if (hp->flags.domain_server && hp->domain_server) {
- X del_iplist(hp->domain_server);
- X }
- X hp->domain_server = get_addresses(symbol);
- X hp->flags.domain_server = TRUE;
- X break;
- X case OP_DELETION:
- X if (hp->flags.domain_server && hp->domain_server) {
- X del_iplist(hp->domain_server);
- X }
- X hp->domain_server = NULL;
- X hp->flags.domain_server = FALSE;
- X break;
- X case OP_BOOLEAN:
- X return E_SYNTAX_ERROR;
- X }
- X break;
- X
- X case SYM_GATEWAY:
- X switch (optype) {
- X case OP_ADDITION:
- X if (hp->flags.gateway && hp->gateway) {
- X del_iplist(hp->gateway);
- X }
- X hp->gateway = get_addresses(symbol);
- X hp->flags.gateway = TRUE;
- X break;
- X case OP_DELETION:
- X if (hp->flags.gateway && hp->gateway) {
- X del_iplist(hp->gateway);
- X }
- X hp->gateway = NULL;
- X hp->flags.gateway = FALSE;
- X break;
- X case OP_BOOLEAN:
- X return E_SYNTAX_ERROR;
- X }
- X break;
- X
- X case SYM_HADDR:
- X switch (optype) {
- X case OP_ADDITION:
- X if (hp->flags.htype && hp->htype &&
- X (tmphaddr = prs_haddr(symbol, hp->htype))) {
- X bcopy(tmphaddr, hp->haddr, haddrlength(hp->htype));
- X hp->flags.haddr = TRUE;
- X } else {
- X return E_BAD_HADDR;
- X }
- X break;
- X case OP_DELETION:
- X hp->flags.haddr = FALSE;
- X break;
- X case OP_BOOLEAN:
- X return E_SYNTAX_ERROR;
- X }
- X break;
- X
- X case SYM_HOMEDIR:
- X switch (optype) {
- X case OP_ADDITION:
- X if (ss = get_shared_string(symbol)) {
- X if ((ss->string)[0] == '/') {
- X if (hp->homedir) {
- X del_string(hp->homedir);
- X }
- X hp->homedir = ss;
- X hp->flags.homedir = TRUE;
- X } else {
- X return E_BAD_HOMEDIR;
- X }
- X } else {
- X return E_BAD_HOMEDIR;
- X }
- X break;
- X case OP_DELETION:
- X if (hp->homedir) {
- X del_string(hp->homedir);
- X }
- X hp->homedir = NULL;
- X hp->flags.homedir = FALSE;
- X break;
- X case OP_BOOLEAN:
- X return E_SYNTAX_ERROR;
- X }
- X break;
- X
- X case SYM_HTYPE:
- X switch (optype) {
- X case OP_ADDITION:
- X value = 0L; /* Assume an illegal value */
- X eat_whitespace(symbol);
- X if (isdigit(**symbol)) {
- X value = get_u_long(symbol);
- X } else {
- X len = sizeof(tmpstr);
- X (void) get_string(symbol, tmpstr, &len);
- X makelower(tmpstr);
- X numsymbols = sizeof(htnamemap) /
- X sizeof(struct htypename);
- X for (i = 0; i < numsymbols; i++) {
- X if (!strcmp(htnamemap[i].name, tmpstr)) {
- X break;
- X }
- X }
- X if (i < numsymbols) {
- X value = htnamemap[i].htype;
- X }
- X }
- X if ((value < 0) || (value >= hwinfocnt)) {
- X return E_BAD_HTYPE;
- X }
- X hp->htype = (byte) (value & 0xFF);
- X hp->flags.htype = TRUE;
- X break;
- X case OP_DELETION:
- X hp->flags.htype = FALSE;
- X break;
- X case OP_BOOLEAN:
- X return E_SYNTAX_ERROR;
- X }
- X break;
- X
- X case SYM_IMPRESS_SERVER:
- X switch (optype) {
- X case OP_ADDITION:
- X if (hp->flags.impress_server && hp->impress_server) {
- X del_iplist(hp->impress_server);
- X }
- X hp->impress_server = get_addresses(symbol);
- X hp->flags.impress_server = TRUE;
- X break;
- X case OP_DELETION:
- X if (hp->flags.impress_server && hp->impress_server) {
- X del_iplist(hp->impress_server);
- X }
- X hp->impress_server = NULL;
- X hp->flags.impress_server = FALSE;
- X break;
- X case OP_BOOLEAN:
- X return E_SYNTAX_ERROR;
- X }
- X break;
- X
- X case SYM_IPADDR:
- X switch (optype) {
- X case OP_ADDITION:
- X if (prs_inetaddr(symbol, &value) < 0) {
- X return E_BAD_IPADDR;
- X } else {
- X hp->iaddr.s_addr = value;
- X hp->flags.iaddr = TRUE;
- X }
- X break;
- X case OP_DELETION:
- X hp->flags.iaddr = FALSE;
- X break;
- X case OP_BOOLEAN:
- X return E_SYNTAX_ERROR;
- X }
- X break;
- X
- X case SYM_LOG_SERVER:
- X switch (optype) {
- X case OP_ADDITION:
- X if (hp->flags.log_server && hp->log_server) {
- X del_iplist(hp->log_server);
- X }
- X hp->log_server = get_addresses(symbol);
- X hp->flags.log_server = TRUE;
- X break;
- X case OP_DELETION:
- X if (hp->flags.log_server && hp->log_server) {
- X del_iplist(hp->log_server);
- X }
- X hp->log_server = NULL;
- X hp->flags.log_server = FALSE;
- X break;
- X case OP_BOOLEAN:
- X return E_SYNTAX_ERROR;
- X }
- X break;
- X
- X case SYM_LPR_SERVER:
- X switch (optype) {
- X case OP_ADDITION:
- X if (hp->flags.lpr_server && hp->lpr_server) {
- X del_iplist(hp->lpr_server);
- X }
- X hp->lpr_server = get_addresses(symbol);
- X hp->flags.lpr_server = TRUE;
- X break;
- X case OP_DELETION:
- X if (hp->flags.lpr_server && hp->lpr_server) {
- X del_iplist(hp->lpr_server);
- X }
- X hp->lpr_server = NULL;
- X hp->flags.lpr_server = FALSE;
- X break;
- X case OP_BOOLEAN:
- X return E_SYNTAX_ERROR;
- X }
- X break;
- X
- X case SYM_NAME_SERVER:
- X switch (optype) {
- X case OP_ADDITION:
- X if (hp->flags.name_server && hp->name_server) {
- X del_iplist(hp->name_server);
- X }
- X hp->name_server = get_addresses(symbol);
- X hp->flags.name_server = TRUE;
- X break;
- X case OP_DELETION:
- X if (hp->flags.name_server && hp->name_server) {
- X del_iplist(hp->name_server);
- X }
- X hp->name_server = NULL;
- X hp->flags.name_server = FALSE;
- X break;
- X case OP_BOOLEAN:
- X return E_SYNTAX_ERROR;
- X }
- X break;
- X
- X case SYM_RLP_SERVER:
- X switch (optype) {
- X case OP_ADDITION:
- X if (hp->flags.rlp_server && hp->rlp_server) {
- X del_iplist(hp->rlp_server);
- X }
- X hp->rlp_server = get_addresses(symbol);
- X hp->flags.rlp_server = TRUE;
- X break;
- X case OP_DELETION:
- X if (hp->flags.rlp_server && hp->rlp_server) {
- X del_iplist(hp->rlp_server);
- X }
- X hp->rlp_server = NULL;
- X hp->flags.rlp_server = FALSE;
- X break;
- X case OP_BOOLEAN:
- X return E_SYNTAX_ERROR;
- X }
- X break;
- X
- X case SYM_SUBNET_MASK:
- X switch (optype) {
- X case OP_ADDITION:
- X if (prs_inetaddr(symbol, &value) < 0) {
- X return E_BAD_SMASK;
- X } else {
- X hp->subnet_mask.s_addr = value;
- X hp->flags.subnet_mask = TRUE;
- X }
- X break;
- X case OP_DELETION:
- X hp->flags.subnet_mask = FALSE;
- X break;
- X case OP_BOOLEAN:
- X return E_SYNTAX_ERROR;
- X }
- X break;
- X
- X case SYM_TIME_OFFSET:
- X switch (optype) {
- X case OP_ADDITION:
- X len = sizeof(tmpstr);
- X (void) get_string(symbol, tmpstr, &len);
- X if (!strncmp(tmpstr, "auto", 4)) {
- X hp->flags.timeoff_auto = TRUE;
- X hp->flags.time_offset = TRUE;
- X } else {
- X if (sscanf(tmpstr, "%ld", &timeoff) != 1) {
- X return E_BAD_TIMEOFF;
- X } else {
- X hp->time_offset = timeoff;
- X hp->flags.timeoff_auto = FALSE;
- X hp->flags.time_offset = TRUE;
- X }
- X }
- X break;
- X case OP_DELETION:
- X hp->flags.time_offset = FALSE;
- X break;
- X case OP_BOOLEAN:
- X return E_SYNTAX_ERROR;
- X }
- X break;
- X
- X case SYM_TIME_SERVER:
- X switch (optype) {
- X case OP_ADDITION:
- X if (hp->flags.time_server && hp->time_server) {
- X del_iplist(hp->time_server);
- X }
- X hp->time_server = get_addresses(symbol);
- X hp->flags.time_server = TRUE;
- X break;
- X case OP_DELETION:
- X if (hp->flags.time_server && hp->time_server) {
- X del_iplist(hp->time_server);
- X }
- X hp->time_server = NULL;
- X hp->flags.time_server = FALSE;
- X break;
- X case OP_BOOLEAN:
- X return E_SYNTAX_ERROR;
- X }
- X break;
- X
- X case SYM_VENDOR_MAGIC:
- X switch (optype) {
- X case OP_ADDITION:
- X if (!strncmp(*symbol, "auto", 4)) {
- X hp->flags.vm_auto = TRUE; /* Make it auto */
- X } else if (!strncmp(*symbol, "rfc1048", 7) ||
- X !strncmp(*symbol, "rfc1084", 7)) {
- X hp->flags.vm_auto = FALSE; /* Make it manual */
- X bcopy(vm_rfc1048, hp->vm_cookie, 4);
- X } else if (!strncmp(*symbol, "cmu", 3)) {
- X hp->flags.vm_auto = FALSE; /* Make it manual */
- X bcopy(vm_cmu, hp->vm_cookie, 4);
- X } else {
- X if (prs_inetaddr(symbol, &value) < 0) {
- X return E_BAD_VM_COOKIE;
- X }
- X hp->flags.vm_auto = FALSE; /* Make it manual */
- X ustr = hp->vm_cookie;
- X bcopy((char*)&value, ustr, sizeof(long));
- X }
- X hp->flags.vendor_magic = TRUE;
- X break;
- X case OP_DELETION:
- X hp->flags.vendor_magic = FALSE;
- X break;
- X case OP_BOOLEAN:
- X hp->flags.vm_auto = TRUE;
- X hp->flags.vendor_magic = TRUE;
- X break;
- X }
- X break;
- X
- X case SYM_SIMILAR_ENTRY:
- X switch (optype) {
- X case OP_ADDITION:
- X fill_defaults(hp, symbol);
- X break;
- X default:
- X return E_SYNTAX_ERROR;
- X }
- X break;
- X
- X case SYM_NAME_SWITCH:
- X switch (optype) {
- X case OP_ADDITION:
- X return E_SYNTAX_ERROR;
- X case OP_DELETION:
- X hp->flags.send_name = FALSE;
- X hp->flags.name_switch = FALSE;
- X break;
- X case OP_BOOLEAN:
- X hp->flags.send_name = TRUE;
- X hp->flags.name_switch = TRUE;
- X break;
- X }
- X break;
- X
- X case SYM_BOOTSIZE:
- X switch (optype) {
- X case OP_ADDITION:
- X if (!strncmp(*symbol, "auto", 4)) {
- X hp->flags.bootsize = TRUE;
- X hp->flags.bootsize_auto = TRUE;
- X } else {
- X hp->bootsize = (unsigned int) get_u_long(symbol);
- X hp->flags.bootsize = TRUE;
- X hp->flags.bootsize_auto = FALSE;
- X }
- X break;
- X case OP_DELETION:
- X hp->flags.bootsize = FALSE;
- X break;
- X case OP_BOOLEAN:
- X hp->flags.bootsize = TRUE;
- X hp->flags.bootsize_auto = TRUE;
- X break;
- X }
- X break;
- X
- X case SYM_BOOT_SERVER:
- X switch (optype) {
- X case OP_ADDITION:
- X if (prs_inetaddr(symbol, &value) < 0) {
- X return E_BAD_BOOT_SERVER;
- X } else {
- X hp->bootserver.s_addr = value;
- X hp->flags.bootserver = TRUE;
- X }
- X break;
- X case OP_DELETION:
- X hp->flags.bootserver = FALSE;
- X break;
- X case OP_BOOLEAN:
- X return E_SYNTAX_ERROR;
- X }
- X break;
- X
- X case SYM_TFTPDIR:
- X switch (optype) {
- X case OP_ADDITION:
- X if (ss = get_shared_string(symbol)) {
- X if ((ss->string)[0] == '/') {
- X if (hp->tftpdir) {
- X del_string(hp->tftpdir);
- X }
- X hp->tftpdir = ss;
- X hp->flags.tftpdir = TRUE;
- X } else {
- X return E_BAD_TFTPDIR;
- X }
- X } else {
- X return E_BAD_TFTPDIR;
- X }
- X break;
- X case OP_DELETION:
- X if (hp->tftpdir) {
- X del_string(hp->tftpdir);
- X }
- X hp->tftpdir = NULL;
- X hp->flags.tftpdir = FALSE;
- X break;
- X case OP_BOOLEAN:
- X return E_SYNTAX_ERROR;
- X }
- X break;
- X
- X default:
- X return E_UNKNOWN_SYMBOL;
- X }
- X return SUCCESS;
- X}
- X
- X
- X
- X/*
- X * Read a string from the buffer indirectly pointed to through "src" and
- X * move it into the buffer pointed to by "dest". A pointer to the maximum
- X * allowable length of the string (including null-terminator) is passed as
- X * "length". The actual length of the string which was read is returned in
- X * the unsigned integer pointed to by "length". This value is the same as
- X * that which would be returned by applying the strlen() function on the
- X * destination string (i.e the terminating null is not counted as a
- X * character). Trailing whitespace is removed from the string. For
- X * convenience, the function returns the new value of "dest".
- X *
- X * The string is read until the maximum number of characters, an unquoted
- X * colon (:), or a null character is read. The return string in "dest" is
- X * null-terminated.
- X */
- X
- XPRIVATE char *get_string(src, dest, length)
- Xchar **src, *dest;
- Xunsigned *length;
- X{
- X int n, len, quoteflag;
- X
- X quoteflag = FALSE;
- X n = 0;
- X len = *length - 1;
- X while ((n < len) && (**src)) {
- X if (!quoteflag && (**src == ':')) {
- X break;
- X }
- X if (**src == '"') {
- X (*src)++;
- X quoteflag = !quoteflag;
- X continue;
- X }
- X if (**src == '\\') {
- X (*src)++;
- X if (! **src) {
- X break;
- X }
- X }
- X *dest++ = *(*src)++;
- X n++;
- X }
- X
- X /*
- X * Remove that troublesome trailing whitespace. . .
- X */
- X while ((n > 0) && isspace(dest[-1])) {
- X dest--;
- X n--;
- X }
- X
- X *dest = '\0';
- X *length = n;
- X return dest;
- X}
- X
- X
- X
- X/*
- X * Read the string indirectly pointed to by "src", update the caller's
- X * pointer, and return a pointer to a malloc'ed shared_string structure
- X * containing the string.
- X *
- X * The string is read using the same rules as get_string() above.
- X */
- X
- XPRIVATE struct shared_string *get_shared_string(src)
- Xchar **src;
- X{
- X char retstring[MAXSTRINGLEN];
- X struct shared_string *s;
- X unsigned length;
- X
- X length = sizeof(retstring);
- X (void) get_string(src, retstring, &length);
- X
- X s = (struct shared_string *) smalloc(sizeof(struct shared_string)
- X + length);
- X s->linkcount = 1;
- X strcpy(s->string, retstring);
- X
- X return s;
- X}
- X
- X
- X
- X/*
- X * Load RFC1048 generic information directly into a memory buffer.
- X *
- X * "src" indirectly points to the ASCII representation of the generic data.
- X * "dest" points to a string structure which is updated to point to a new
- X * string with the new data appended to the old string. The old string is
- X * freed.
- X *
- X * The given tag value is inserted with the new data.
- X *
- X * The data may be represented as either a stream of hexadecimal numbers
- X * representing bytes (any or all bytes may optionally start with '0x' and
- X * be separated with periods ".") or as a quoted string of ASCII
- X * characters (the quotes are required).
- X */
- X
- XPRIVATE void process_generic(src, dest, tagvalue)
- Xchar **src;
- Xstruct shared_bindata **dest;
- Xbyte tagvalue;
- X{
- X byte tmpbuf[MAXBUFLEN];
- X byte *str;
- X struct shared_bindata *bdata;
- X int newlength, oldlength;
- X
- X str = tmpbuf;
- X *str++ = tagvalue; /* Store tag value */
- X str++; /* Skip over length field */
- X if ((*src)[0] == '"') { /* ASCII data */
- X newlength = sizeof(tmpbuf) - 2; /* Set maximum allowed length */
- X (void) get_string(src, str, &newlength);
- X } else { /* Numeric data */
- X newlength = 0;
- X while (newlength < sizeof(tmpbuf) - 2) {
- X if (interp_byte(src, str++) < 0) {
- X break;
- X } else {
- X newlength++;
- X }
- X if (**src == '.') {
- X (*src)++;
- X }
- X }
- X }
- X tmpbuf[1] = (byte) (newlength & 0xFF);
- X oldlength = ((*dest)->length);
- X bdata = (struct shared_bindata *) smalloc(sizeof(struct shared_bindata)
- X + oldlength + newlength + 1);
- X if (oldlength > 0) {
- X bcopy((*dest)->data, bdata->data, oldlength);
- X }
- X bcopy(tmpbuf, bdata->data + oldlength, newlength + 2);
- X bdata->length = oldlength + newlength + 2;
- X bdata->linkcount = 1;
- X if (*dest) {
- X del_bindata(*dest);
- X }
- X *dest = bdata;
- X}
- X
- X
- X
- X/*
- X * Verify that the given string makes sense as a hostname (according to
- X * Appendix 1, page 29 of RFC882).
- X *
- X * Return TRUE for good names, FALSE otherwise.
- X */
- X
- XPRIVATE boolean goodname(hostname)
- Xregister char *hostname;
- X{
- X do {
- X if (!isalpha(*hostname++)) { /* First character must be a letter */
- X return FALSE;
- X }
- X while (isalnum(*hostname) || (*hostname == '-')) {
- X hostname++; /* Alphanumeric or a hyphen */
- X }
- X if (!isalnum(hostname[-1])) { /* Last must be alphanumeric */
- X return FALSE;
- X }
- X if (*hostname == '\0') { /* Done? */
- X return TRUE;
- X }
- X } while (*hostname++ == '.'); /* Dot, loop for next label */
- X
- X return FALSE; /* If it's not a dot, lose */
- X}
- X
- X
- X
- X/*
- X * Null compare function -- always returns FALSE so an element is always
- X * inserted into a hash table (i.e. there is never a collision with an
- X * existing element).
- X */
- X
- XPRIVATE boolean nullcmp(host1, host2)
- Xstruct host *host1, *host2;
- X{
- X return FALSE;
- X}
- X
- X
- X/*
- X * Function for comparing a string with the hostname field of a host
- X * structure.
- X */
- X
- XPRIVATE boolean nmcmp(name, hp)
- Xchar *name;
- Xstruct host *hp;
- X{
- X return !strcmp(name, hp->hostname->string);
- X}
- X
- X
- X/*
- X * Compare function to determine whether two hardware addresses are
- X * equivalent. Returns TRUE if "host1" and "host2" are equivalent, FALSE
- X * otherwise.
- X *
- X * If the hardware addresses of "host1" and "host2" are identical, but
- X * they are on different IP subnets, this function returns FALSE.
- X *
- X * This function is used when inserting elements into the hardware address
- X * hash table.
- X */
- X
- XPRIVATE boolean hwinscmp(host1, host2)
- Xstruct host *host1, *host2;
- X{
- X if (host1->htype != host2->htype) {
- X return FALSE;
- X }
- X if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
- X return FALSE;
- X }
- X if ((host1->subnet_mask.s_addr) == (host2->subnet_mask.s_addr)) {
- X if (((host1->iaddr.s_addr) & (host1->subnet_mask.s_addr)) !=
- X ((host2->iaddr.s_addr) & (host2->subnet_mask.s_addr))) {
- X return FALSE;
- X }
- X }
- X return TRUE;
- X}
- X
- X
- X
- X/*
- X * Process the "similar entry" symbol.
- X *
- X * The host specified as the value of the "tc" symbol is used as a template
- X * for the current host entry. Symbol values not explicitly set in the
- X * current host entry are inferred from the template entry.
- X */
- X
- XPRIVATE void fill_defaults(hp, src)
- Xstruct host *hp;
- Xchar **src;
- X{
- X unsigned tlen, hashcode;
- X struct host *hp2, thp;
- X char tstring[MAXSTRINGLEN];
- X
- X tlen = sizeof(tstring);
- X (void) get_string(src, tstring, &tlen);
- X if (goodname(tstring)) {
- X hashcode = hash_HashFunction(tstring, tlen);
- X hp2 = (struct host *) hash_Lookup(nmhashtable, hashcode, nmcmp,
- X tstring);
- X } else {
- X thp.iaddr.s_addr = inet_addr(tstring);
- X hashcode = hash_HashFunction(&(thp.iaddr.s_addr), 4);
- X hp2 = (struct host *) hash_Lookup(iphashtable, hashcode, iplookcmp,
- X &thp);
- X }
- X if (hp2 == NULL) {
- X report(LOG_ERR, "can't find tc=\"%s\"\n", tstring);
- X } else {
- X /*
- X * Assignments inside "if" conditionals are intended here.
- X */
- X if (!hp->flags.cookie_server) {
- X if (hp->flags.cookie_server = hp2->flags.cookie_server) {
- X hp->cookie_server = hp2->cookie_server;
- X (hp->cookie_server->linkcount)++;
- X }
- X }
- X if (!hp->flags.domain_server) {
- X if (hp->flags.domain_server = hp2->flags.domain_server) {
- X hp->domain_server = hp2->domain_server;
- X (hp->domain_server->linkcount)++;
- X }
- X }
- X if (!hp->flags.gateway) {
- X if (hp->flags.gateway = hp2->flags.gateway) {
- X hp->gateway = hp2->gateway;
- X (hp->gateway->linkcount)++;
- X }
- X }
- X if (!hp->flags.impress_server) {
- X if (hp->flags.impress_server = hp2->flags.impress_server) {
- X hp->impress_server = hp2->impress_server;
- X (hp->impress_server->linkcount)++;
- X }
- X }
- X if (!hp->flags.log_server) {
- X if (hp->flags.log_server = hp2->flags.log_server) {
- X hp->log_server = hp2->log_server;
- X (hp->log_server->linkcount)++;
- X }
- X }
- X if (!hp->flags.lpr_server) {
- X if (hp->flags.lpr_server = hp2->flags.lpr_server) {
- X hp->lpr_server = hp2->lpr_server;
- X (hp->lpr_server->linkcount)++;
- X }
- X }
- X if (!hp->flags.name_server) {
- X if (hp->flags.name_server = hp2->flags.name_server) {
- X hp->name_server = hp2->name_server;
- X (hp->name_server->linkcount)++;
- X }
- X }
- X if (!hp->flags.rlp_server) {
- X if (hp->flags.rlp_server = hp2->flags.rlp_server) {
- X hp->rlp_server = hp2->rlp_server;
- X (hp->rlp_server->linkcount)++;
- X }
- X }
- X if (!hp->flags.time_server) {
- X if (hp->flags.time_server = hp2->flags.time_server) {
- X hp->time_server = hp2->time_server;
- X (hp->time_server->linkcount)++;
- X }
- X }
- X if (!hp->flags.homedir) {
- X if (hp->flags.homedir = hp2->flags.homedir) {
- X hp->homedir = hp2->homedir;
- X (hp->homedir->linkcount)++;
- X }
- X }
- X if (!hp->flags.bootfile) {
- X if (hp->flags.bootfile = hp2->flags.bootfile) {
- X hp->bootfile = hp2->bootfile;
- X (hp->bootfile->linkcount)++;
- X }
- X }
- X if (!hp->flags.generic) {
- X if (hp->flags.generic = hp2->flags.generic) {
- X hp->generic = hp2->generic;
- X (hp->generic->linkcount)++;
- X }
- X }
- X if (!hp->flags.vendor_magic) {
- X hp->flags.vm_auto = hp2->flags.vm_auto;
- X if (hp->flags.vendor_magic = hp2->flags.vendor_magic) {
- X bcopy(hp2->vm_cookie, hp->vm_cookie, 4);
- X }
- X }
- X if (!hp->flags.name_switch) {
- X if (hp->flags.name_switch = hp2->flags.name_switch) {
- X hp->flags.send_name = hp2->flags.send_name;
- X }
- X }
- X if (!hp->flags.htype) {
- X if (hp->flags.htype = hp2->flags.htype) {
- X hp->htype = hp2->htype;
- X }
- X }
- X if (!hp->flags.time_offset) {
- X if (hp->flags.time_offset = hp2->flags.time_offset) {
- X hp->flags.timeoff_auto = hp2->flags.timeoff_auto;
- X hp->time_offset = hp2->time_offset;
- X }
- X }
- X if (!hp->flags.subnet_mask) {
- X if (hp->flags.subnet_mask = hp2->flags.subnet_mask) {
- X hp->subnet_mask.s_addr = hp2->subnet_mask.s_addr;
- X }
- X }
- X if (!hp->flags.bootsize) {
- X if (hp->flags.bootsize = hp2->flags.bootsize) {
- X hp->flags.bootsize_auto = hp2->flags.bootsize_auto;
- X hp->bootsize = hp2->bootsize;
- X }
- X }
- X if (!hp->flags.tftpdir) {
- X if (hp->flags.tftpdir = hp2->flags.tftpdir) {
- X hp->tftpdir = hp2->tftpdir;
- X (hp->tftpdir->linkcount)++;
- X }
- X }
- X }
- X}
- X
- X
- X
- X/*
- X * This function adjusts the caller's pointer to point just past the
- X * first-encountered colon. If it runs into a null character, it leaves
- X * the pointer pointing to it.
- X */
- X
- XPRIVATE void adjust(s)
- Xchar **s;
- X{
- X register char *t;
- X
- X t = *s;
- X while (*t && (*t != ':')) {
- X t++;
- X }
- X if (*t) {
- X t++;
- X }
- X *s = t;
- X}
- X
- X
- X
- X
- X/*
- X * This function adjusts the caller's pointer to point to the first
- X * non-whitespace character. If it runs into a null character, it leaves
- X * the pointer pointing to it.
- X */
- X
- XPRIVATE void eat_whitespace(s)
- Xchar **s;
- X{
- X register char *t;
- X
- X t = *s;
- X while (*t && isspace(*t)) {
- X t++;
- X }
- X *s = t;
- X}
- X
- X
- X
- X/*
- X * This function converts the given string to all lowercase.
- X */
- X
- XPRIVATE void makelower(s)
- Xchar *s;
- X{
- X while (*s) {
- X if (isupper(*s)) {
- X *s = tolower(*s);
- X }
- X s++;
- X }
- X}
- X
- X
- X
- X/*
- X *
- X * N O T E :
- X *
- X * In many of the functions which follow, a parameter such as "src" or
- X * "symbol" is passed as a pointer to a pointer to something. This is
- X * done for the purpose of letting the called function update the
- X * caller's copy of the parameter (i.e. to effect call-by-reference
- X * parameter passing). The value of the actual parameter is only used
- X * to locate the real parameter of interest and then update this indirect
- X * parameter.
- X *
- X * I'm sure somebody out there won't like this. . . .
- X *
- X *
- X */
- X
- X
- X
- X/*
- X * "src" points to a character pointer which points to an ASCII string of
- X * whitespace-separated IP addresses. A pointer to an in_addr_list
- X * structure containing the list of addresses is returned. NULL is
- X * returned if no addresses were found at all. The pointer pointed to by
- X * "src" is updated to point to the first non-address (illegal) character.
- X */
- X
- XPRIVATE struct in_addr_list *get_addresses(src)
- Xchar **src;
- X{
- X struct in_addr tmpaddrlist[MAXINADDRS];
- X struct in_addr *address1, *address2;
- X struct in_addr_list *result;
- X unsigned addrcount, totalsize;
- X
- X address1 = tmpaddrlist;
- X for (addrcount = 0; addrcount < MAXINADDRS; addrcount++) {
- X while (**src && isspace(**src)) { /* Skip whitespace */
- X (*src)++;
- X }
- X if (! **src) { /* Quit if nothing more */
- X break;
- X }
- X if (prs_inetaddr(src, &(address1->s_addr)) < 0) {
- X break;
- X }
- X address1++; /* Point to next address slot */
- X }
- X if (addrcount < 1) {
- X result = NULL;
- X } else {
- X totalsize = sizeof(struct in_addr_list)
- X + (addrcount - 1) * sizeof(struct in_addr);
- X result = (struct in_addr_list *) smalloc(totalsize);
- X result->linkcount = 1;
- X result->addrcount = addrcount;
- X address1 = tmpaddrlist;
- X address2 = result->addr;
- X for (; addrcount > 0; addrcount--) {
- X address2->s_addr = address1->s_addr;
- X address1++;
- X address2++;
- X }
- X }
- X return result;
- X}
- X
- X
- X
- X/*
- X * prs_inetaddr(src, result)
- X *
- X * "src" is a value-result parameter; the pointer it points to is updated
- X * to point to the next data position. "result" points to an unsigned long
- X * in which an address is returned.
- X *
- X * This function parses the IP address string in ASCII "dot notation" pointed
- X * to by (*src) and places the result (in network byte order) in the unsigned
- X * long pointed to by "result". For malformed addresses, -1 is returned,
- X * (*src) points to the first illegal character, and the unsigned long pointed
- X * to by "result" is unchanged. Successful calls return 0.
- X */
- X
- XPRIVATE prs_inetaddr(src, result)
- Xchar **src;
- Xu_long *result;
- X{
- X register u_long value;
- X u_long parts[4], *pp = parts;
- X int n;
- X
- X if (!isdigit(**src)) {
- X return -1;
- X }
- Xloop:
- X value = get_u_long(src);
- X if (**src == '.') {
- X /*
- X * Internet format:
- X * a.b.c.d
- X * a.b.c (with c treated as 16-bits)
- X * a.b (with b treated as 24 bits)
- X */
- X if (pp >= parts + 4) {
- X return (-1);
- X }
- X *pp++ = value;
- X (*src)++;
- X goto loop;
- X }
- X /*
- X * Check for trailing characters.
- X */
- X if (**src && !(isspace(**src) || (**src == ':'))) {
- X return (-1);
- X }
- X *pp++ = value;
- X /*
- X * Construct the address according to
- X * the number of parts specified.
- X */
- X n = pp - parts;
- X switch (n) {
- X case 1: /* a -- 32 bits */
- X value = parts[0];
- X break;
- X case 2: /* a.b -- 8.24 bits */
- X value = (parts[0] << 24) | (parts[1] & 0xFFFFFF);
- X break;
- X case 3: /* a.b.c -- 8.8.16 bits */
- X value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
- X (parts[2] & 0xFFFF);
- X break;
- X case 4: /* a.b.c.d -- 8.8.8.8 bits */
- X value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
- X ((parts[2] & 0xFF) << 8) | (parts[3] & 0xFF);
- X break;
- X default:
- X return (-1);
- X }
- X *result = htonl(value);
- X return (0);
- X}
- X
- X
- X
- X/*
- X * "src" points to a pointer which in turn points to a hexadecimal ASCII
- X * string. This string is interpreted as a hardware address and returned
- X * as a pointer to the actual hardware address, represented as an array of
- X * bytes.
- X *
- X * The ASCII string must have the proper number of digits for the specified
- X * hardware type (e.g. twelve digits for a 48-bit Ethernet address).
- X * Two-digit sequences (bytes) may be separated with periods (.) and/or
- X * prefixed with '0x' for readability, but this is not required.
- X *
- X * For bad addresses, the pointer which "src" points to is updated to point
- X * to the start of the first two-digit sequence which was bad, and the
- X * function returns a NULL pointer.
- X */
- X
- XPRIVATE byte *prs_haddr(src, htype)
- Xchar **src;
- Xbyte htype;
- X{
- X static byte haddr[MAXHADDRLEN];
- X byte *hptr;
- X unsigned hlen;
- X
- X hlen = haddrlength(htype); /* Get length of this address type */
- X hptr = haddr;
- X while (hptr < haddr + hlen) {
- X if (**src == '.') {
- X (*src)++;
- X }
- X if (interp_byte(src, hptr++) < 0) {
- X return NULL;
- X }
- X }
- X return haddr;
- X}
- X
- X
- X
- X/*
- X * "src" is a pointer to a character pointer which in turn points to a
- X * hexadecimal ASCII representation of a byte. This byte is read, the
- X * character pointer is updated, and the result is deposited into the
- X * byte pointed to by "retbyte".
- X *
- X * The usual '0x' notation is allowed but not required. The number must be
- X * a two digit hexadecimal number. If the number is invalid, "src" and
- X * "retbyte" are left untouched and -1 is returned as the function value.
- X * Successful calls return 0.
- X */
- X
- XPRIVATE int interp_byte(src, retbyte)
- Xchar **src;
- Xbyte *retbyte;
- X{
- X int v;
- X
- X if ((*src)[0] == '0' && (*src)[1] == 'x' || (*src)[1] == 'X') {
- X (*src) += 2; /* allow 0x for hex, but don't require it */
- X }
- X if (!isxdigit((*src)[0]) || !isxdigit((*src)[1])) {
- X return -1;
- X }
- X if (sscanf(*src, "%2x", &v) != 1) {
- X return -1;
- X }
- X (*src) += 2;
- X *retbyte = (byte) (v & 0xFF);
- X return 0;
- X}
- X
- X
- X
- X/*
- X * The parameter "src" points to a character pointer which points to an
- X * ASCII string representation of an unsigned number. The number is
- X * returned as an unsigned long and the character pointer is updated to
- X * point to the first illegal character.
- X */
- X
- XPRIVATE u_long get_u_long(src)
- Xchar **src;
- X{
- X register u_long value, base;
- X char c;
- X
- X /*
- X * Collect number up to first illegal character. Values are specified
- X * as for C: 0x=hex, 0=octal, other=decimal.
- X */
- X value = 0;
- X base = 10;
- X if (**src == '0') {
- X base = 8, (*src)++;
- X }
- X if (**src == 'x' || **src == 'X') {
- X base = 16, (*src)++;
- X }
- X while (c = **src) {
- X if (isdigit(c)) {
- X value = (value * base) + (c - '0');
- X (*src)++;
- X continue;
- X }
- X if (base == 16 && isxdigit(c)) {
- X value = (value << 4) + ((c & ~32) + 10 - 'A');
- X (*src)++;
- X continue;
- X }
- X break;
- X }
- X return value;
- X}
- X
- X
- X
- X/*
- X * Routines for deletion of data associated with the main data structure.
- X */
- X
- X
- X/*
- X * Frees the entire host data structure given. Does nothing if the passed
- X * pointer is NULL.
- X */
- X
- XPRIVATE void free_host(hostptr)
- Xstruct host *hostptr;
- X{
- X if (hostptr) {
- X del_iplist(hostptr->cookie_server);
- X del_iplist(hostptr->domain_server);
- X del_iplist(hostptr->gateway);
- X del_iplist(hostptr->impress_server);
- X del_iplist(hostptr->log_server);
- X del_iplist(hostptr->lpr_server);
- X del_iplist(hostptr->name_server);
- X del_iplist(hostptr->rlp_server);
- X del_iplist(hostptr->time_server);
- X del_string(hostptr->hostname);
- X del_string(hostptr->homedir);
- X del_string(hostptr->bootfile);
- X del_string(hostptr->tftpdir);
- X del_bindata(hostptr->generic);
- X free((char *) hostptr);
- X }
- X}
- X
- X
- X
- X/*
- X * Decrements the linkcount on the given IP address data structure. If the
- X * linkcount goes to zero, the memory associated with the data is freed.
- X */
- X
- XPRIVATE void del_iplist(iplist)
- Xstruct in_addr_list *iplist;
- X{
- X if (iplist) {
- X if (! (--(iplist->linkcount))) {
- X free((char *) iplist);
- X }
- X }
- X}
- X
- X
- X
- X/*
- X * Decrements the linkcount on a string data structure. If the count
- X * goes to zero, the memory associated with the string is freed. Does
- X * nothing if the passed pointer is NULL.
- X */
- X
- XPRIVATE void del_string(stringptr)
- Xstruct shared_string *stringptr;
- X{
- X if (stringptr) {
- X if (! (--(stringptr->linkcount))) {
- X free((char *) stringptr);
- X }
- X }
- X}
- X
- X
- X
- X/*
- X * Decrements the linkcount on a shared_bindata data structure. If the
- X * count goes to zero, the memory associated with the data is freed. Does
- X * nothing if the passed pointer is NULL.
- X */
- X
- XPRIVATE void del_bindata(dataptr)
- Xstruct shared_bindata *dataptr;
- X{
- X if (dataptr) {
- X if (! (--(dataptr->linkcount))) {
- X free((char *) dataptr);
- X }
- X }
- X}
- X
- X
- X
- X
- X/* smalloc() -- safe malloc()
- X *
- X * Always returns a valid pointer (if it returns at all). The allocated
- X * memory is initialized to all zeros. If malloc() returns an error, a
- X * message is printed using the report() function and the program aborts
- X * with a status of 1.
- X */
- X
- XPRIVATE char *smalloc(nbytes)
- Xunsigned nbytes;
- X{
- X char *retvalue;
- X
- X retvalue = malloc(nbytes);
- X if (!retvalue) {
- X report(LOG_ERR, "malloc() failure -- exiting\n");
- X exit(1);
- X }
- X bzero(retvalue, nbytes);
- X return retvalue;
- X}
- END_OF_FILE
- if test 49372 -ne `wc -c <'readfile.c'`; then
- echo shar: \"'readfile.c'\" unpacked with wrong size!
- fi
- # end of 'readfile.c'
- fi
- echo shar: End of archive 2 \(of 2\).
- cp /dev/null ark2isdone
- MISSING=""
- for I in 1 2 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked both archives.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-