summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgwr <gwr@NetBSD.org>1994-05-24 15:19:56 +0000
committergwr <gwr@NetBSD.org>1994-05-24 15:19:56 +0000
commit438d67fe4e073750dfca3245e8a2bac11187b223 (patch)
tree5f8eeb02ac62cac4202c3e627246b061b51ed1b4
parent0645f8963f663d296322b025a9e0c1dff377718f (diff)
Wholesale update to bootp-2.3.7 release.
-rw-r--r--libexec/bootpd/Announce-2.137
-rw-r--r--libexec/bootpd/Announce-2.251
-rw-r--r--libexec/bootpd/Announce-2.358
-rw-r--r--libexec/bootpd/ConvOldTab.sh141
-rw-r--r--libexec/bootpd/Installation29
-rw-r--r--libexec/bootpd/Makefile44
-rw-r--r--libexec/bootpd/Problems47
-rw-r--r--libexec/bootpd/README109
-rw-r--r--libexec/bootpd/bootp.h51
-rw-r--r--libexec/bootpd/bootpd.8335
-rw-r--r--libexec/bootpd/bootpd.c2453
-rw-r--r--libexec/bootpd/bootpd.h120
-rw-r--r--libexec/bootpd/bootpef.852
-rw-r--r--libexec/bootpd/bootpef.c347
-rw-r--r--libexec/bootpd/bootpgw.c675
-rw-r--r--libexec/bootpd/bootptab.5165
-rw-r--r--libexec/bootpd/bootptab.cmu124
-rw-r--r--libexec/bootpd/bootptab.mcs93
-rw-r--r--libexec/bootpd/bootptest.856
-rw-r--r--libexec/bootpd/bootptest.c484
-rw-r--r--libexec/bootpd/bootptest.h30
-rw-r--r--libexec/bootpd/bptypes.h23
-rw-r--r--libexec/bootpd/dovend.c413
-rw-r--r--libexec/bootpd/dovend.h13
-rw-r--r--libexec/bootpd/dumptab.c370
-rw-r--r--libexec/bootpd/getether.c374
-rw-r--r--libexec/bootpd/getif.c145
-rw-r--r--libexec/bootpd/getif.h7
-rw-r--r--libexec/bootpd/hash.c453
-rw-r--r--libexec/bootpd/hash.h57
-rw-r--r--libexec/bootpd/hwaddr.c265
-rw-r--r--libexec/bootpd/hwaddr.h39
-rw-r--r--libexec/bootpd/lookup.c126
-rw-r--r--libexec/bootpd/lookup.h15
-rw-r--r--libexec/bootpd/patchlevel.h3
-rw-r--r--libexec/bootpd/print-bootp.c500
-rw-r--r--libexec/bootpd/readfile.c2922
-rw-r--r--libexec/bootpd/readfile.h19
-rw-r--r--libexec/bootpd/report.c154
-rw-r--r--libexec/bootpd/report.h13
-rw-r--r--libexec/bootpd/syslog.conf63
-rw-r--r--libexec/bootpd/syslog.h25
-rw-r--r--libexec/bootpd/trygetea.c46
-rw-r--r--libexec/bootpd/trygetif.c68
-rw-r--r--libexec/bootpd/trylook.c50
-rw-r--r--libexec/bootpd/tzone.c44
-rw-r--r--libexec/bootpd/tzone.h3
47 files changed, 8239 insertions, 3472 deletions
diff --git a/libexec/bootpd/Announce-2.1 b/libexec/bootpd/Announce-2.1
new file mode 100644
index 00000000000..28ddca6a63e
--- /dev/null
+++ b/libexec/bootpd/Announce-2.1
@@ -0,0 +1,37 @@
+Subject: Updated RFC1048 BOOTP server now available
+
+Well, no surprise, bootpd 2.0 had a few bugs. A new improved version,
+bootpd 2.1, is now available for anonymous FTP from lancaster.andrew.cmu.edu
+(128.2.13.21). The new server can be found in pub/bootp.2.1.tar.
+
+Bug fixes and improvements in version 2.1 include:
+
+o The definition of "access to the bootfile" has been changed to require the
+ public read access bit to be set. This is required by tftpd(8), so the
+ server will not reply with a file which a client cannot obtain via TFTP.
+o The RFC1084 bootfile size tag has been implemented. It allows either
+ automatic or manual specification of the bootfile size in 512-octet blocks.
+o Generic tags now work as advertised.
+o A subtle bug which caused strange parsing behavior under certain conditions
+ has been fixed.
+o The RFC1048 vendor information now has the correct byte order on
+ little-endien machines such as the VAX.
+o Failure to specify the bootfile home directory and/or default bootfile in
+ the configuration file no longer causes server crashes. The server now
+ makes a reasonably intelligent choice if this configuration information is
+ missing. This is documented in the man page.
+o BOOTP requests from clients which already know their IP addresses no longer
+ cause server crashes.
+
+
+
+Please direct questions, comments, and bug reports to
+Walt Wimer <ww0n@andrew.cmu.edu> or Drew Perkins <ddp@andrew.cmu.edu>.
+
+
+
+Good luck,
+
+Walt Wimer
+Network Development
+Carnegie Mellon University
diff --git a/libexec/bootpd/Announce-2.2 b/libexec/bootpd/Announce-2.2
new file mode 100644
index 00000000000..34f2e3982a5
--- /dev/null
+++ b/libexec/bootpd/Announce-2.2
@@ -0,0 +1,51 @@
+
+New features in version 2.2 include:
+
+o A new "td" tag allows the specification of a "TFTP directory" for use
+ with so-called "secure" implementations of tftpd which chroot(2) to a
+ particular directory.
+
+o A new "sa" tag allows the explicit specification of the TFTP
+ "server address." Formerly, the 'siaddr' field of the BOOTREPLY was
+ always filled with the IP address of the BOOTP server. The "sa" tag
+ now allows the BOOTP server and the TFTP server to be two different
+ machines, if desired.
+
+o The server now automatically determines whether it is running as a
+ standalone program (e.g. invoked by hand from a shell) or as a child of
+ /etc/inetd. The -s option and a new -i option are provided to force
+ standalone or inetd mode if necessary.
+
+o When the vendor magic cookie is zero, BOOTP replies now default to the
+ RFC 1084 vendor format, rather than the old CMU format. This helps
+ interoperability with uncooperative BOOTP clients which want RFC 1084
+ format but don't bother filling in the magic cookie properly to tell
+ the server... *sigh* (This makes the ":vm=rfc1048:" tag unnecessary
+ in most cases now. Oh, the "vm" tag now accepts "rfc1084" as well as
+ "rfc1048" -- they mean the same thing.)
+
+o Log messages now include the specific network type. For example, rather
+ than saying "request from hardware address ABCDEF012345", the message is
+ now "request from Ethernet address ABCEDF012345", or "request from
+ IEEE802 address 4000A1B2C3D4".
+
+
+Bug fixes in this version include:
+
+o The automatic bootfile-size calculation now works correctly when the
+ file size is an exact multiple of 512 octets. It used to return a number
+ which was one 512-octet unit greater than necessary.
+
+o A bug in comparing subnet masks has been fixed.
+
+o A bug in calculating the size of the vendor information area when
+ inserting the hostname has been fixed.
+
+
+Other changes:
+
+o The man page has been split into two man pages. One covers the server
+ itself (bootpd.8) and the other covers the configuration file format
+ (bootptab.5).
+
+
diff --git a/libexec/bootpd/Announce-2.3 b/libexec/bootpd/Announce-2.3
new file mode 100644
index 00000000000..0eef6547752
--- /dev/null
+++ b/libexec/bootpd/Announce-2.3
@@ -0,0 +1,58 @@
+
+This is an enhanced version of the CMU BOOTP server which was derived
+from the original BOOTP server created by Bill Croft at Stanford.
+This version merges most of the enhancements and bug-fixes from the
+NetBSD, Columbia, and other versions.
+
+New features:
+
+ Added a simple BOOTP gateway program: bootpgw
+ Allow host name anywhere IP address is expected.
+ Automatically lookup the IP address when the name of a
+ bootptab entry is a valid hostname.
+ (Dummy entries names should start with '.')
+ Merged changes from NetBSD and Columbia versions.
+ Merged changes for Solaris-2.X and SVR4 systems.
+ Combined bootptest into the bootp release.
+ Merged tag 18 support (:ef=...:) from Jason Zions.
+ Use :ef=extension_file_name: and make the
+ extension files for all clients using bootpef.
+ Merged HP compatibility (:ra=...:) from David R Linn.
+ Allows you to override the reply address.
+ (i.e. send the reply to a broadcast address)
+ Add /etc/ethers support for NetBSD.
+ More systems support getether (Ultrix, OSF, NetBSD)
+ Added RFC 1533 tags 40,41,42
+ :yd=<NIS domain>:ys=<NIS server>:nt=<NTP server>:
+ ConvOldTab.sh to convert old (1.1) bootptab to new format.
+
+Fixes included:
+ Fixed references to free host structures.
+ (used to cause core dump on Solaris)
+ Remove change that added null terminator to string options.
+ (this annoyed some clients...)
+ Add missing symbols to dump routine, fix order.
+ Works (again) with no -DSYSLOGD defined.
+ Fixed several more NULL references in readfile.
+ Added proper length checks to option insertions.
+ Fixed bootptest IP address printing.
+ Cleaned-up signed/unsigned and byteorder bugs.
+ Added SVR4/Streams support to getif and getether
+ Removed extra newlines in syslog messages.
+ Specify facility code when calling syslog(3)
+ When lookup_hwa fails, assume numeric HW address.
+
+Systems on which I have seen this code work:
+ SunOS 4.X (Solaris 1.X)
+ SunOS 5.X (Solaris 2.X)
+ System V/386 Rel. 4.0
+
+Systems on which others say this code works:
+ CDC EP/IX (1.4.3, 2.1.1)
+ DEC Ultrix (4.2, 4.3)
+ NetBSD (Current-1/94)
+ OSF/1 (DEC Alpha CPU)
+
+Gordon W. Ross Mercury Computer Systems
+gwr@mc.com 199 Riverneck Road
+508-256-1300 Chelmsford, MA 01824-2820
diff --git a/libexec/bootpd/ConvOldTab.sh b/libexec/bootpd/ConvOldTab.sh
new file mode 100644
index 00000000000..00683f0c049
--- /dev/null
+++ b/libexec/bootpd/ConvOldTab.sh
@@ -0,0 +1,141 @@
+#!/bin/sh
+# convert_bootptab Jeroen.Scheerder@let.ruu.nl 02/25/94
+# This script can be used to convert bootptab files in old format
+# to new (termcap-like) bootptab files
+#
+# The old format - real entries are commented out by '###'
+#
+# Old-style bootp files consist of two sections.
+# The first section has two entries:
+# First, a line that specifies the home directory
+# (where boot file paths are relative to)
+
+###/tftpboot
+
+# The next non-empty non-comment line specifies the default bootfile
+
+###no-file
+
+# End of first section - indicated by '%%' at the start of the line
+
+###%%
+
+# The remainder of this file contains one line per client
+# interface with the information shown by the table headings
+# below. The host name is also tried as a suffix for the
+# bootfile when searching the home directory (that is,
+# bootfile.host)
+#
+# Note that htype is always 1, indicating the hardware type Ethernet.
+# Conversion therefore always yields ':ha=ether:'.
+#
+# host htype haddr iaddr bootfile
+#
+
+###somehost 1 00:0b:ad:01:de:ad 128.128.128.128 dummy
+
+# That's all for the description of the old format.
+# For the new-and-improved format, see bootptab(5).
+
+set -u$DX
+
+case $#
+in 2 ) OLDTAB=$1 ; NEWTAB=$2 ;;
+ * ) echo "Usage: `basename $0` <Input> <Output>"
+ exit 1
+esac
+
+if [ ! -r $OLDTAB ]
+then
+ echo "`basename $0`: $OLDTAB does not exist or is unreadable."
+ exit 1
+fi
+
+if touch $NEWTAB 2> /dev/null
+then
+ :
+else
+ echo "`basename $0`: cannot write to $NEWTAB."
+ exit 1
+fi
+
+
+cat << END_OF_HEADER >> $NEWTAB
+# /etc/bootptab: database for bootp server (/etc/bootpd)
+# This file was generated automagically
+
+# Blank lines and lines beginning with '#' are ignored.
+#
+# Legend: (see bootptab.5)
+# first field -- hostname (not indented)
+# bf -- bootfile
+# bs -- bootfile size in 512-octet blocks
+# cs -- cookie servers
+# df -- dump file name
+# dn -- domain name
+# ds -- domain name servers
+# ef -- extension file
+# gw -- gateways
+# ha -- hardware address
+# hd -- home directory for bootfiles
+# hn -- host name set for client
+# ht -- hardware type
+# im -- impress servers
+# ip -- host IP address
+# lg -- log servers
+# lp -- LPR servers
+# ns -- IEN-116 name servers
+# ra -- reply address
+# rl -- resource location protocol servers
+# rp -- root path
+# sa -- boot server address
+# sm -- subnet mask
+# sw -- swap server
+# tc -- template host (points to similar host entry)
+# td -- TFTP directory
+# to -- time offset (seconds)
+# ts -- time servers
+# vm -- vendor magic number
+# Tn -- generic option tag n
+#
+# Be careful about including backslashes where they're needed. Weird (bad)
+# things can happen when a backslash is omitted where one is intended.
+# Also, note that generic option data must be either a string or a
+# sequence of bytes where each byte is a two-digit hex value.
+
+# First, we define a global entry which specifies the stuff every host uses.
+# (Host name lookups are relative to the domain: your.domain.name)
+
+END_OF_HEADER
+
+# Fix up HW addresses in aa:bb:cc:dd:ee:ff and aa-bb-cc-dd-ee-ff style first
+# Then awk our stuff together
+sed -e 's/[:-]//g' < $OLDTAB | \
+nawk 'BEGIN { PART = 0 ; FIELD=0 ; BOOTPATH="unset" ; BOOTFILE="unset" }
+ /^%%/ {
+ PART = 1
+ printf ".default:\\\n\t:ht=ether:\\\n\t:hn:\\\n\t:dn=your.domain.name:\\\n\t:ds=your,dns,servers:\\\n\t:sm=255.255.0.0:\\\n\t:hd=%s:\\\n\t:rp=%s:\\\n\t:td=%s:\\\n\t:bf=%s:\\\n\t:to=auto:\n\n", BOOTPATH, BOOTPATH, BOOTPATH, BOOTFILE
+ next
+ }
+ /^$/ { next }
+ /^#/ { next }
+ {
+ if ( PART == 0 && FIELD < 2 )
+ {
+ if ( FIELD == 0 ) BOOTPATH=$1
+ if ( FIELD == 1 ) BOOTFILE=$1
+ FIELD++
+ }
+ }
+ {
+ if ( PART == 1 )
+ {
+ HOST=$1
+ HA=$3
+ IP=$4
+ BF=$5
+ printf "%s:\\\n\t:tc=.default:\\\n\t:ha=0x%s:\\\n\t:ip=%s:\\\n\t:bf=%s:\n", HOST, HA, IP, BF
+ }
+ }' >> $NEWTAB
+
+exit 0
diff --git a/libexec/bootpd/Installation b/libexec/bootpd/Installation
new file mode 100644
index 00000000000..466cabce0cd
--- /dev/null
+++ b/libexec/bootpd/Installation
@@ -0,0 +1,29 @@
+
+Installation instructions for SunOS
+
+Compile the executable:
+For SunOS 4.X:
+ make sunos4
+For SunOS 5.X: (Solaris)
+ make sunos5
+
+Install the executables:
+
+ make install
+
+Edit (or create) the bootptab:
+(See bootptab.sample and bootptab.5 manual entry)
+ edit /etc/bootptab
+
+Edit /etc/services to add these two lines:
+bootps 67/udp bootp # BOOTP Server
+bootpc 68/udp # BOOTP Client
+
+Edit /etc/inetd.conf to add the line:
+bootp dgram udp wait root /usr/etc/bootpd bootpd -i
+
+If you compiled report.c with LOG_LOCAL2 (defined in the Makefile)
+then you may want to capture syslog messages from BOOTP by changing
+your syslog.conf file. (See the sample syslog.conf file here).
+Test the change with: logger -t test -p local2.info "message"
+
diff --git a/libexec/bootpd/Makefile b/libexec/bootpd/Makefile
index de5eeaa903c..00f228b7fca 100644
--- a/libexec/bootpd/Makefile
+++ b/libexec/bootpd/Makefile
@@ -1,10 +1,50 @@
+# The next few lines may be uncommented and changed to alter the default
+# filenames bootpd uses for its configuration and dump files.
+#CONFFILE=-DCONFIG_FILE=\"/usr/etc/bootptab\"
+DUMPFILE=-DDUMPTAB_FILE=\"/var/run/bootpd.dump\"
+FILESPECS=${CONFFILE} ${DUMPFILE}
+
# Remove the -DVEND_CMU if you don't wish to support the "CMU vendor format"
# in addition to the RFC1048 format.
PROG= bootpd
-CFLAGS+=-DSYSLOG -DDEBUG -DVEND_CMU
-SRCS= bootpd.c readfile.c hash.c Version.c
+# Note: PRIVATE=static is defined by default in bootpd.h
+CFLAGS+=-DETC_ETHERS -DSYSLOG -DDEBUG -DVEND_CMU ${FILESPECS}
+SRCS= bootpd.c dovend.c readfile.c hash.c dumptab.c \
+ lookup.c getif.c hwaddr.c report.c tzone.c
MAN5= bootptab.0
MAN8= bootpd.0
+MLINKS= bootpd.8 bootpgw.8
+
+BINDIR=/usr/sbin
+
.include <bsd.prog.mk>
+
+# Additional targets (bootpd is done automatically)
+all: bootpef bootpef.0 bootpgw bootptest bootptest.0
+CLEANFILES+= bootpef bootpgw bootptest
+
+bootpef: bootpef.o dovend.o readfile.o hash.o dumptab.o \
+ lookup.o hwaddr.o report.o tzone.o
+ ${CC} -o ${.TARGET} ${CFLAGS} ${LDFLAGS} ${.ALLSRC} ${LIBS}
+
+bootpgw: bootpgw.o getif.o hwaddr.o report.o
+ ${CC} -o ${.TARGET} ${CFLAGS} ${LDFLAGS} ${.ALLSRC} ${LIBS}
+
+print-bootp.o : print-bootp.c
+ ${CC} ${CFLAGS} -DBOOTPTEST -c ${.IMPSRC}
+
+bootptest: bootptest.o print-bootp.o getif.o getether.o report.o
+ ${CC} -o ${.TARGET} ${CFLAGS} ${LDFLAGS} ${.ALLSRC} ${LIBS}
+
+bootpef.0: bootpef.8
+bootptest.0: bootptest.8
+
+install:
+ install ${COPY} ${STRIP} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ bootpef ${DESTDIR}${BINDIR}
+ install ${COPY} ${STRIP} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ bootpgw ${DESTDIR}${BINDIR}
+ ${MINSTALL} bootpef.0 ${DESTDIR}${MANDIR}8${MANSUBDIR}
+
diff --git a/libexec/bootpd/Problems b/libexec/bootpd/Problems
new file mode 100644
index 00000000000..9478676eca4
--- /dev/null
+++ b/libexec/bootpd/Problems
@@ -0,0 +1,47 @@
+
+Common problems and ways to work around them:
+
+Bootpd complains that it "can not get IP addr for HOSTNAME"
+
+ If the entry is a "dummy" (not a real host) used only for
+ reference by other entries, put '.' in front of the name.
+
+ If the entry is for a real client and the IP address for
+ the client can not be found using gethostbyname(), specify
+ the IP address for the client using numeric form.
+
+Bootpd takes a long time to finish parsing the bootptab file:
+
+ Excessive startup time is usually caused by waiting for
+ timeouts on failed DNS lookup operations. If this is the
+ problem, find the client names for which DNS lookup fails
+ and change the bootptab to specify the IP addresses for
+ those clients using numeric form.
+
+ When bootptab entries do not specify an ip address, bootpd
+ attempts to lookup the tagname as a host name to find the
+ IP address. To suppress this default action, either make
+ the entry a "dummy" or specify its IP numeric address.
+
+ If your DNS lookups work but are just slow, consider either
+ running bootpd on the same machine as the DNS server or
+ running a caching DNS server on the host running bootpd.
+
+My huge bootptab file causes startup time to be so long that clients
+give up waiting for a reply.
+
+ Truly huge bootptab files make "inetd" mode impractical.
+ Start bootpd in "standalone" mode when the server boots.
+
+ Another possibility is to run one bootpd on each network
+ segment so each one can have a smaller bootptab. Only one
+ instance of bootpd may run on one server, so you would need
+ to use a different server for each network segment.
+
+My bootp clients are given responses with a boot file name that is
+not a fully specified path.
+
+ Make sure the TFTP directory or home directory tags are set:
+ :td=/tftpboot: (or)
+ :hd=/usr/boot: (for example)
+
diff --git a/libexec/bootpd/README b/libexec/bootpd/README
index f99f2efc341..88dd6f8fc48 100644
--- a/libexec/bootpd/README
+++ b/libexec/bootpd/README
@@ -1,4 +1,19 @@
-This is a port of bootpd (CMU version 2.2a) to NetBSD-current.
+
+This is an enhanced version of the CMU BOOTP server which was derived
+from the original BOOTP server created by Bill Croft at Stanford.
+This version merges all the enhancements and bug-fixes from the
+NetBSD, Columbia, and other versions.
+
+If you have problems or questions about this version, send email to:
+ gwr@mc.com (Gordon W. Ross)
+
+For general questions about BOOTP, send email to the list:
+ bootp@andrew.cmu.edu
+You can subscribe to this mailing list by sending mail to:
+ bootp-request@andrew.cmu.edu
+(The body of the message should contain: "Add <your-address>")
+
+[ From the NetBSD README file: ]
BOOTPD is a useful adjunct to the nfs diskless boot EPROM code.
@@ -7,39 +22,7 @@ are to use RARP protocol, or BOOTP protocol. BOOTP is more flexible;
it allows additional items of information to be returned to the
booting client; it also supports booting across gateways.
-There are two parts to this package:
-
-- The bootpd sources to be compiled and installed.
-
-- A patch to etc/services and etc/inetd.conf to define the bootpd
-network service names and to define the bootpd task to inetd. These
-items are in the PATCH file.
-
-If you have problems or questions about this port, send me email at
-mckim@lerc.nasa.gov
-
-- Jim McKim
-
-enclosed below is the original README:
-
-
-This directory contains the source for the CMU BOOTP server. The files
-include:
-
-README This file
-bootpd.8 The manual page
-bootp.h The protocol header file
-bootpd.h The server header file
-bootpd.c The main server module
-readfile.c The configuration file-reading routines
-hash.h The hash table header file
-hash.c The hash table module
-Version.c The version module
-newvers.sh A shell script to generate new version numbers
-Makefile The makefile
-bootptab An example database file for the server
-gmods Text describing optional gateway modifications
-
+[ From the CMU README file: ]
Notes:
1) BOOTP was originally designed and implemented by Bill Croft at Stanford.
@@ -53,13 +36,16 @@ Notes:
should compile without the -DSYSLOG switch.
3) You must update your /etc/services file to contain the following two lines:
- bootps 67/udp # bootp server
- bootpc 68/udp # bootp client
+ bootps 67/udp bootp # BOOTP Server
+ bootpc 68/udp # BOOTP Client
-4) The code and the bootptab should be reasonably well commented. If you
- have any questions, just let us know.
+4) Edit the bootptab. It has some explanitory comments, and there
+ is a manual entry describing its format (bootptab.5)
+ If you have any questions, just let us know.
Construction:
+ [ See the file Installation which is more up-to-date. -gwr ]
+
Make sure all of the files exist first. If anything is missing,
please contact either Walt Wimer or Drew Perkins by E-mail or phone.
Addresses and phone numbers are listed below.
@@ -74,7 +60,9 @@ Construction:
Type 'make install'. This should put all of the files in the right place.
Edit your /etc/rc.local or /etc/inetd.conf file to start up bootpd upon
- reboot.
+ reboot. The following is a sample /etc/inetd.conf entry:
+ # BOOTP server
+ bootps dgram udp wait root /usr/etc/bootpd bootpd -i
Care and feeding:
If you change the interface cards on your host or add new hosts you will
@@ -100,3 +88,46 @@ ww0n@andrew.cmu.edu ddp@andrew.cmu.edu
4910 Forbes Ave
Pittsburgh, PA 15213
+[ Contents description by file: ]
+
+Announce* Text of release announcements
+Installation Instructions for building and installing
+Makefile* for "make"
+README This file
+bootp.h The protocol header file
+bootpd.8 Manual page for bootpd, boopgw
+bootpd.c BOOTP server main module
+bootpd.h header for above (and others)
+bootpef.8 Manual page for bootpef
+bootpef.c BOOTP extension file compiler
+bootpgw.c BOOTP gateway main module
+bootptab.5 A manual describing the bootptab format
+bootptab.cmu A sample database file for the server
+bootptab.mcs Another sample from <gwr@mc.com>
+bootptest.8 Manual page for bootptest
+bootptest.c BOOTP test program (fake client)
+bootptest.h header for above
+dovend.c Vendor Option builder (for bootpd, bootpef)
+dovend.h header for above
+dumptab.c Implements debugging dump for bootpd
+getether.c For bootptest (not used yet)
+getif.c Get network interface info.
+getif.h header for above
+hash.c The hash table module
+hash.h header for above
+hwaddr.c Hardware address support
+hwaddr.h header for above
+lookup.c Internet Protocol address lookup
+lookup.h header for above
+patchlevel.h Holds version numbers
+print-bootp.c Prints BOOTP packets (taken from BSD tcpdump)
+readfile.c The configuration file-reading routines
+readfile.h header for above
+report.c Does syslog-style messages
+report.h header for above
+strerror.c Library errno-to-string (for systems lacking it)
+syslog.conf Sample config file for syslogd(8)
+syslog.h For systems that lack syslog(3)
+try*.c Test programs (for debugging)
+tzone.c Get timezone offset
+tzone.h header for above
diff --git a/libexec/bootpd/bootp.h b/libexec/bootpd/bootp.h
index fa09299d2c7..912d1f6c02f 100644
--- a/libexec/bootpd/bootp.h
+++ b/libexec/bootpd/bootp.h
@@ -1,5 +1,3 @@
-#ifndef _BLURB_
-#define _BLURB_
/************************************************************************
Copyright 1988, 1991 by Carnegie Mellon University
@@ -21,12 +19,11 @@ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
************************************************************************/
-#endif /* _BLURB_ */
/*
* Bootstrap Protocol (BOOTP). RFC951 and RFC1395.
*
- * $Header: /cvsroot/src/libexec/bootpd/Attic/bootp.h,v 1.1 1994/04/18 05:15:52 glass Exp $
+ * $Header: /cvsroot/src/libexec/bootpd/Attic/bootp.h,v 1.2 1994/05/24 15:20:08 gwr Exp $
*
*
* This file specifies the "implementation-independent" BOOTP protocol
@@ -34,17 +31,20 @@ SOFTWARE.
*
*/
+#include "bptypes.h" /* for int32, u_int32 */
+
#define BP_CHADDR_LEN 16
#define BP_SNAME_LEN 64
#define BP_FILE_LEN 128
#define BP_VEND_LEN 64
+#define BP_MINPKTSZ 300 /* to check sizeof(struct bootp) */
struct bootp {
unsigned char bp_op; /* packet opcode type */
unsigned char bp_htype; /* hardware addr type */
unsigned char bp_hlen; /* hardware addr length */
unsigned char bp_hops; /* gateway hops */
- unsigned long bp_xid; /* transaction ID */
+ unsigned int32 bp_xid; /* transaction ID */
unsigned short bp_secs; /* seconds since boot began */
unsigned short bp_unused;
struct in_addr bp_ciaddr; /* client IP address */
@@ -52,9 +52,10 @@ struct bootp {
struct in_addr bp_siaddr; /* server IP address */
struct in_addr bp_giaddr; /* gateway IP address */
unsigned char bp_chaddr[BP_CHADDR_LEN]; /* client hardware address */
- unsigned char bp_sname[BP_SNAME_LEN]; /* server host name */
- unsigned char bp_file[BP_FILE_LEN]; /* boot file name */
+ char bp_sname[BP_SNAME_LEN]; /* server host name */
+ char bp_file[BP_FILE_LEN]; /* boot file name */
unsigned char bp_vend[BP_VEND_LEN]; /* vendor-specific area */
+ /* note that bp_vend can be longer, extending to end of packet. */
};
/*
@@ -69,7 +70,6 @@ struct bootp {
/*
* Hardware types from Assigned Numbers RFC.
*/
-#define HTYPE_DIRECT 0 /* non-standard */
#define HTYPE_ETHERNET 1
#define HTYPE_EXP_ETHERNET 2
#define HTYPE_AX25 3
@@ -91,10 +91,11 @@ struct bootp {
/*
- * RFC1395 tag values used to specify what information is being supplied in
- * the vendor field of the packet.
+ * Tag values used to specify what information is being supplied in
+ * the vendor (options) data area of the packet.
*/
-
+/* RFC 1048 */
+#define TAG_END ((unsigned char) 255)
#define TAG_PAD ((unsigned char) 0)
#define TAG_SUBNET_MASK ((unsigned char) 1)
#define TAG_TIME_OFFSET ((unsigned char) 2)
@@ -107,14 +108,20 @@ struct bootp {
#define TAG_LPR_SERVER ((unsigned char) 9)
#define TAG_IMPRESS_SERVER ((unsigned char) 10)
#define TAG_RLP_SERVER ((unsigned char) 11)
-#define TAG_HOSTNAME ((unsigned char) 12)
-#define TAG_BOOTSIZE ((unsigned char) 13)
-#define TAG_DUMPFILE ((unsigned char) 14)
-#define TAG_DOMAINNAME ((unsigned char) 15)
-#define TAG_SWAPSERVER ((unsigned char) 16)
-#define TAG_ROOTPATH ((unsigned char) 17)
-#define TAG_END ((unsigned char) 255)
-
+#define TAG_HOST_NAME ((unsigned char) 12)
+#define TAG_BOOT_SIZE ((unsigned char) 13)
+/* RFC 1395 */
+#define TAG_DUMP_FILE ((unsigned char) 14)
+#define TAG_DOMAIN_NAME ((unsigned char) 15)
+#define TAG_SWAP_SERVER ((unsigned char) 16)
+#define TAG_ROOT_PATH ((unsigned char) 17)
+/* RFC 1497 */
+#define TAG_EXTEN_FILE ((unsigned char) 18)
+/* RFC 1533 */
+#define TAG_NIS_DOMAIN ((unsigned char) 40)
+#define TAG_NIS_SERVER ((unsigned char) 41)
+#define TAG_NTP_SERVER ((unsigned char) 42)
+/* XXX - Add new tags here */
/*
@@ -122,14 +129,14 @@ struct bootp {
*/
struct cmu_vend {
- unsigned char v_magic[4]; /* magic number */
- unsigned long v_flags; /* flags/opcodes, etc. */
+ char v_magic[4]; /* magic number */
+ unsigned int32 v_flags; /* flags/opcodes, etc. */
struct in_addr v_smask; /* Subnet mask */
struct in_addr v_dgate; /* Default gateway */
struct in_addr v_dns1, v_dns2; /* Domain name servers */
struct in_addr v_ins1, v_ins2; /* IEN-116 name servers */
struct in_addr v_ts1, v_ts2; /* Time servers */
- unsigned char v_unused[25]; /* currently unused */
+ int32 v_unused[6]; /* currently unused */
};
diff --git a/libexec/bootpd/bootpd.8 b/libexec/bootpd/bootpd.8
index aeaa3f2a4d0..cca20b94570 100644
--- a/libexec/bootpd/bootpd.8
+++ b/libexec/bootpd/bootpd.8
@@ -1,14 +1,12 @@
.\" Copyright (c) 1988, 1989, 1991 Carnegie Mellon University
.\"
-.\" $Header: /cvsroot/src/libexec/bootpd/Attic/bootpd.8,v 1.1 1994/04/18 05:15:53 glass Exp $
+.\" $Header: /cvsroot/src/libexec/bootpd/Attic/bootpd.8,v 1.2 1994/05/24 15:20:09 gwr Exp $
.\"
-.TH BOOTPD 8 "November 11, 1991" "Carnegie Mellon University"
-.UC 6
-
+.TH BOOTPD 8 "November 06, 1993" "Carnegie Mellon University"
.SH NAME
-bootpd \- Internet Boot Protocol server
+bootpd, bootpgw \- Internet Boot Protocol server/gateway
.SH SYNOPSIS
-.B /usr/libexec/bootpd
+.B bootpd
[
.B \-i
.B \-s
@@ -16,149 +14,292 @@ bootpd \- Internet Boot Protocol server
timeout
.B \-d
level
+.B \-c
+chdir\-path
]
[
-.I configfile
+.I bootptab
[
.I dumpfile
] ]
+.br
+.B bootpgw
+[
+.B \-i
+.B \-s
+.B \-t
+timeout
+.B \-d
+level
+] server
.SH DESCRIPTION
.I Bootpd
-implements an Internet Bootstrap Protocol server as defined in RFC951,
-RFC1048, and RFC1084. It is normally run by
-.I /usr/sbin/inetd
-by including the following line in the file
-.IR /etc/inetd.conf :
+implements an Internet Bootstrap Protocol (BOOTP) server as defined in
+RFC951, RFC1532, and RFC1533.
+.I Bootpgw
+implements a simple BOOTP gateway which can be used to forward
+requests and responses between clients on one subnet and a
+BOOTP server (i.e.
+.IR bootpd )
+on another subnet. While either
+.I bootpd
+or
+.I bootpgw
+will forward BOOTREPLY packets, only
+.I bootpgw
+will forward BOOTREQUEST packets.
.PP
+One host on each network segment is normally configured to run either
+.I bootpd
+or
+.I bootpgw
+from
+.I inetd
+by including one of the following lines in the file
+.IR /etc/inetd.conf :
+.IP
+bootps dgram udp wait root /etc/bootpd bootpd bootptab
.br
- bootps dgram udp wait root /usr/libexec/bootpd bootpd
+bootps dgram udp wait root /etc/bootpgw bootpgw server
.PP
This mode of operation is referred to as "inetd mode" and causes
.I bootpd
-to be started only when a boot request arrives. If
-.I bootpd
-does not receive another boot request within fifteen minutes of the last one
+(or
+.IR bootpgw )
+to be started only when a boot request arrives. If it does not
+receive another packet within fifteen minutes of the last one
it received, it will exit to conserve system resources. The
.B \-t
-switch may be used to specify a different timeout value in minutes (e.g.
--t 20). A timeout value of zero means forever.
+option controls this timeout (see OPTIONS).
.PP
It is also possible to run
.I bootpd
+(or
+.IR bootpgw )
in "standalone mode" (without
.IR inetd )
by simply invoking it from a shell like any other regular command.
-Standalone mode is probably the desired mode of operation for large network
-installations with many BOOTP clients. (The greater the number of clients
-listed in the configuration database,
-.IR /etc/bootptab ,
-the longer it takes
-.I bootpd
-to start up. To ensure quick response to clients in a large network,
-it is better to start
+Standalone mode is particularly useful when
.I bootpd
-once during the server machine's bootup sequence. This can be done by invoking
+is used with a large configuration database, where the start up
+delay might otherwise prevent timely response to client requests.
+(Automatic start up in standalone mode can be done by invoking
.I bootpd
from within
.IR /etc/rc.local ,
for example.)
-.
-In standalone mode, the
-.B \-t
-switch has no effect since
-.I bootpd
-will never exit.
+Standalone mode is less useful for
+.I bootgw
+which
+has very little start up delay because
+it does not read a configuration file.
.PP
-The server automatically detects whether it was invoked from inetd or from a
-shell and automatically selects the appropriate mode. For compatibility with
-older versions of
-.IR bootpd ,
-the
+Either program automatically detects whether it was invoked from inetd
+or from a shell and automatically selects the appropriate mode.
+The
.B \-s
-switch may be used to force standalone operation. Similarly, the
+or
.B \-i
-switch may be used to force the inetd mode of operation. Normally, though,
-it should be unnecessary to use these switches.
-.PP
-The
-.B \-d
-switch takes a numeric parameter which sets the level of debugging output.
+option may be used to force standalone or inetd mode respectively
+(see OPTIONS).
+.SH OPTIONS
+.TP
+.BI \-t \ timeout
+Specifies the
+.I timeout
+value (in minutes) that a
+.I bootpd
+or
+.I bootpgw
+process will wait for a BOOTP packet before exiting.
+If no packets are recieved for
+.I timeout
+seconds, then the program will exit.
+A timeout value of zero means "run forever".
+In standalone mode, this option is forced to zero.
+.TP
+.BI \-d \ debug\-level
+Sets the
+.I debug\-level
+variable that controls the amount of debugging messages generated.
For example, -d4 or -d 4 will set the debugging level to 4.
For compatibility with older versions of
.IR bootpd ,
omitting the numeric parameter (i.e. just -d) will
simply increment the debug level by one.
+.TP
+.BI \-c \ chdir\-path
+Sets the current directory used by
+.I bootpd
+while checking the existence and size of client boot files. This is
+useful when client boot files are specified as relative pathnames, and
+.I bootpd
+needs to use the same current directory as the TFTP server
+(typically /tftpboot). This option is not recoginzed by
+.IR bootpgw .
+.TP
+.B \-i
+Force inetd mode. This option is obsolete, but remains for
+compatibility with older versions of
+.IR bootpd .
+.TP
+.B \-s
+Force standalone mode. This option is obsolete, but remains for
+compatibility with older versions of
+.IR bootpd .
+.TP
+.I bootptab
+Specifies the name of the configuration file from which
+.I bootpd
+loads its database of known clients and client options
+.RI ( bootpd
+only).
+.TP
+.I dumpfile
+Specifies the name of the file that
+.I bootpd
+will dump its internal database into when it receives a
+SIGUSR1 signal
+.RI ( bootpd
+only). This option is only recognized if
+.I bootpd
+was compiled with the -DDEBUG flag.
+.TP
+.I server
+Specifies the name of a BOOTP server to which
+.I bootpgw
+will forward all BOOTREQUEST packets it receives
+.RI ( bootpgw
+only).
+.SH OPERATION
.PP
-Upon startup,
+Both
.I bootpd
-first reads its configuration file,
-.IR /etc/bootptab ,
-and then begins listening for BOOTREQUEST packets.
+and
+.I bootpgw
+operate similarly in that both listen for any packets sent to the
+.I bootps
+port, and both simply forward any BOOTREPLY packets.
+They differ in their handling of BOOTREQUEST packets.
.PP
-.I Bootpd
-looks in
-.I /etc/services
-to find the UDP port numbers it should use. Two entries are extracted:
-.BR bootps ,
-the bootp server listening port, and
-.BR bootpc ,
-the destination port used to reply to clients. If the port numbers cannot
-be determined this way,
-.I bootpd
-defaults to using 67 for the server and 68 for the client.
+When
+.I bootpgw
+is started, it determines the address of a BOOTP server
+whose name is provided as a command line parameter. When
+.I bootpgw
+receives a BOOTREQUEST packet, it sets the "gateway address"
+and "hop count" fields in the packet and forwards the packet
+to the BOOTP server at the address determined earlier.
+Requests are forwarded only if they indicate that
+the client has been waiting for at least three seconds.
.PP
-.I Bootpd
-completely reloads its configuration file when it receives a hangup signal,
-SIGHUP, or when it receives a BOOTREQUEST packet and detects that the file
-has been updated. If
+When
+.I bootpd
+is started it reads a configuration file, (normally
+.IR /etc/bootptab )
+that initializes the internal database of known clients and client
+options. This internal database is reloaded
+from the configuration file when
+.I bootpd
+receives a hangup signal (SIGHUP) or when it discovers that the
+configuration file has changed.
+.PP
+When
+.I bootpd
+receives a BOOTREQUEST packet, it
+.\" checks the modification time of the
+.\" configuration file and reloads the database if necessary. Then it
+looks for a database entry matching the client request.
+If the client is known,
.I bootpd
-is compiled with the -DDEBUG option, receipt of a SIGUSR1 signal causes it
-to dump its memory-resident database to
-the file
+composes a BOOTREPLY packet using the database entry found above,
+and sends the reply to the client (possibly using a gateway).
+If the client is unknown, the request is discarded
+(with a notice if debug > 0).
+.PP
+If
+.I bootpd
+is compiled with the -DDEBUG option, receipt of a SIGUSR1 signal causes
+it to dump its internal database to the file
.I /etc/bootpd.dump
-or the command-line-specified dumpfile.
-
+or the dumpfile specified as a command line parameter.
+.PP
+During initialization, both programs
+determine the UDP port numbers to be used by calling
+.I getservbyname
+(which nomally uses
+.IR /etc/services).
+Two service names (and port numbers) are used:
+.IP
+bootps \- BOOTP Server listening port
+.br
+bootpc \- BOOTP Client destination port
+.LP
+If the port numbers cannot
+be determined using
+.I getservbyname
+then the values default to boopts=67 and bootpc=68.
.SH FILES
+.TP 20
/etc/bootptab
-.br
+Database file read by
+.IR bootpd .
+.TP
/etc/bootpd.dump
-.br
+Debugging dump file created by
+.IR bootpd .
+.TP
/etc/services
+Internet service numbers.
+.TP
+/tftpboot
+Current directory typically used by the TFTP server and
+.IR bootpd .
.SH BUGS
Individual host entries must not exceed 1024 characters.
-.SH HISTORY
+.SH CREDITS
+.PP
+This distribution is currently maintained by
+Walter L. Wimer <walt+@cmu.edu>.
+.PP
+The original BOOTP server was created by
+Bill Croft at Stanford University in January 1986.
+.PP
+The current version of
+.I bootpd
+is primarily the work of David Kovar,
+Drew D. Perkins, and Walter L. Wimer,
+at Carnegie Mellon University.
.TP
-22-Jan-86 Bill Croft at Stanford University
+Enhancements and bug\-fixes have been contributed by:
+(in alphabetical order)
.br
-Created.
-
-.TP
-30-Jul-86 David Kovar at Carnegie Mellon University
+Danny Backx <db@sunbim.be>
.br
-Modified to CMU specifications.
-
-.TP
-24-Jul-87 Drew D. Perkins at Carnegie Mellon University
+John Brezak <brezak@ch.hp.com>
.br
-Modified to use syslog. Added debugging dumps. Other bug fixes.
-
-.TP
-17-Jul-88 Walter L. Wimer at Carnegie Mellon University
+Frank da Cruz <fdc@cc.columbia.edu>
.br
-Added vendor information to conform to RFC1048.
-Adopted termcap-like file format to allow variable data.
-
-.TP
-11-Nov-91 Walter L. Wimer at Carnegie Mellon University
+David R. Linn <drl@vuse.vanderbilt.edu>
.br
-Added TFTP directory- and server-specification features. Added automatic
-detection of inetd/standalone mode, making -s switch no longer necessary.
-Other minor improvements and bug fixes.
-
-.SH "SEE ALSO"
+Jim McKim <mckim@lerc.nasa.gov>
.br
-bootptab(5), inetd(8), tftpd(8),
+Gordon W. Ross <gwr@mc.com>
.br
-DARPA Internet Request For Comments RFC951, RFC1048, RFC1084, Assigned Numbers
+Jason Zions <jazz@hal.com>
+.SH "SEE ALSO"
+.LP
+bootptab(5), inetd(8), tftpd(8)
+.LP
+DARPA Internet Request For Comments:
+.TP 10
+RFC951
+Bootstrap Protocol
+.TP 10
+RFC1532
+Clarifications and Extensions for the Bootstrap Protocol
+.TP 10
+RFC1533
+DHCP Options and BOOTP Vendor Extensions
diff --git a/libexec/bootpd/bootpd.c b/libexec/bootpd/bootpd.c
index a264c284cd2..35f9c700251 100644
--- a/libexec/bootpd/bootpd.c
+++ b/libexec/bootpd/bootpd.c
@@ -1,5 +1,3 @@
-#ifndef _BLURB_
-#define _BLURB_
/************************************************************************
Copyright 1988, 1991 by Carnegie Mellon University
@@ -21,54 +19,29 @@ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
************************************************************************/
-#endif /* _BLURB_ */
-
#ifndef lint
-static char sccsid[] = "@(#)bootp.c 1.1 (Stanford) 1/22/86";
-static char rcsid[] = "$Header: /cvsroot/src/libexec/bootpd/Attic/bootpd.c,v 1.1 1994/04/18 05:15:54 glass Exp $";
+static char rcsid[] = "$Id: bootpd.c,v 1.2 1994/05/24 15:20:10 gwr Exp $";
#endif
-
/*
* BOOTP (bootstrap protocol) server daemon.
*
* Answers BOOTP request packets from booting client machines.
* See [SRI-NIC]<RFC>RFC951.TXT for a description of the protocol.
* See [SRI-NIC]<RFC>RFC1048.TXT for vendor-information extensions.
+ * See RFC 1395 for option tags 14-17.
* See accompanying man page -- bootpd.8
*
- *
* HISTORY
- *
- * 01/22/86 Bill Croft at Stanford University
- * Created.
- *
- * 07/30/86 David Kovar at Carnegie Mellon University
- * Modified to work at CMU.
- *
- * 07/24/87 Drew D. Perkins at Carnegie Mellon University
- * Modified to use syslog instead of Kovar's
- * routines. Add debugging dumps. Many other fixups.
- *
- * 07/15/88 Walter L. Wimer at Carnegie Mellon University
- * Added vendor information to conform to RFC1048.
- * Adopted termcap-like file format to support above.
- * Added hash table lookup instead of linear search.
- * Other cleanups.
- *
+ * See ./Changes
*
* BUGS
- *
- * Currently mallocs memory in a very haphazard manner. As such, most of
- * the program ends up core-resident all the time just to follow all the
- * stupid pointers around. . . .
- *
+ * See ./ToDo
*/
-
#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
@@ -76,32 +49,60 @@ static char rcsid[] = "$Header: /cvsroot/src/libexec/bootpd/Attic/bootpd.c,v 1.1
#include <sys/file.h>
#include <sys/time.h>
#include <sys/stat.h>
+
#include <net/if.h>
-#ifdef SUNOS40
-#include <sys/sockio.h>
-#include <net/if_arp.h>
-#endif
#include <netinet/in.h>
+#include <arpa/inet.h> /* inet_ntoa */
+
+#ifndef NO_UNISTD
+#include <unistd.h>
+#endif
+#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
-#include <strings.h>
+#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <netdb.h>
#include <syslog.h>
+#include <assert.h>
+
+#ifdef NO_SETSID
+# include <fcntl.h> /* for O_RDONLY, etc */
+#endif
+
+#ifdef SVR4
+/* Using sigset() avoids the need to re-arm each time. */
+#define signal sigset
+#endif
+
+#ifndef USE_BFUNCS
+# include <memory.h>
+/* Yes, memcpy is OK here (no overlapped copies). */
+# define bcopy(a,b,c) memcpy(b,a,c)
+# define bzero(p,l) memset(p,0,l)
+# define bcmp(a,b,c) memcmp(a,b,c)
+#endif
#include "bootp.h"
#include "hash.h"
+#include "hwaddr.h"
#include "bootpd.h"
+#include "dovend.h"
+#include "getif.h"
+#include "readfile.h"
+#include "report.h"
+#include "tzone.h"
+#include "patchlevel.h"
-#define HASHTABLESIZE 257 /* Hash table size (prime) */
-#define DEFAULT_TIMEOUT 15L /* Default timeout in minutes */
+/* Local definitions: */
+#define MAXPKT (3*512) /* Maximum packet size */
#ifndef CONFIG_FILE
#define CONFIG_FILE "/etc/bootptab"
#endif
-#ifndef DUMP_FILE
-#define DUMP_FILE "/etc/bootpd.dump"
+#ifndef DUMPTAB_FILE
+#define DUMPTAB_FILE "/tmp/bootpd.dump"
#endif
@@ -110,28 +111,26 @@ static char rcsid[] = "$Header: /cvsroot/src/libexec/bootpd/Attic/bootpd.c,v 1.1
* Externals, forward declarations, and global variables
*/
-extern char Version[];
-#ifndef __NetBSD__
-extern char *sys_errlist[];
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
#endif
-extern int errno, sys_nerr;
-void usage();
-void insert_u_long();
-void dump_host();
-void list_ipaddresses();
+extern void dumptab P((char *));
+
+PRIVATE void catcher P((int));
+PRIVATE int chk_access P((char *, int32 *));
#ifdef VEND_CMU
-void dovend_cmu();
+PRIVATE void dovend_cmu P((struct bootp *, struct host *));
#endif
-void dovend_rfc1048();
-boolean hwlookcmp();
-boolean iplookcmp();
-void insert_generic();
-void insert_ip();
-int dumptab();
-int chk_access();
-void report();
-char *get_errmsg();
+PRIVATE void dovend_rfc1048 P((struct bootp *, struct host *, int32));
+PRIVATE void handle_reply P((void));
+PRIVATE void handle_request P((void));
+PRIVATE void sendreply P((int forward, int32 dest_override));
+PRIVATE void usage P((void));
+
+#undef P
/*
* IP port numbers for client and server obtained from /etc/services
@@ -144,417 +143,411 @@ u_short bootps_port, bootpc_port;
* Internet socket and interface config structures
*/
-struct sockaddr_in s_in;
-struct sockaddr_in from; /* Packet source */
-struct ifreq ifreq[10]; /* Holds interface configuration */
-struct ifconf ifconf; /* Int. config ioctl block (pnts to ifreq) */
-struct arpreq arpreq; /* Arp request ioctl block */
+struct sockaddr_in bind_addr; /* Listening */
+struct sockaddr_in recv_addr; /* Packet source */
+struct sockaddr_in send_addr; /* destination */
/*
- * General
+ * option defaults
*/
-
-int debug = 0; /* Debugging flag (level) */
-int s; /* Socket file descriptor */
-byte buf[1024]; /* Receive packet buffer */
-struct timezone tzp; /* Time zone offset for clients */
-struct timeval tp; /* Time (extra baggage) */
-long secondswest; /* Time zone offset in seconds */
-char hostname[MAXHOSTNAMELEN]; /* System host name */
+int debug = 0; /* Debugging flag (level) */
+struct timeval actualtimeout =
+{ /* fifteen minutes */
+ 15 * 60L, /* tv_sec */
+ 0 /* tv_usec */
+};
/*
- * Globals below are associated with the bootp database file (bootptab).
+ * General
*/
-char *bootptab = NULL;
-#ifdef DEBUG
-char *bootpd_dump = NULL;
+int s; /* Socket file descriptor */
+char *pktbuf; /* Receive packet buffer */
+int pktlen;
+char *progname;
+char *chdir_path;
+char hostname[MAXHOSTNAMELEN]; /* System host name */
+struct in_addr my_ip_addr;
+#ifdef YORK_EX_OPTION
+char *exec_file_name;
#endif
-
+/* Flags set by signal catcher. */
+PRIVATE int do_readtab = 0;
+PRIVATE int do_dumptab = 0;
/*
- * Vendor magic cookies for CMU and RFC1048
+ * Globals below are associated with the bootp database file (bootptab).
*/
-unsigned char vm_cmu[4] = VM_CMU;
-unsigned char vm_rfc1048[4] = VM_RFC1048;
+char *bootptab = CONFIG_FILE;
+char *bootpd_dump = DUMPTAB_FILE;
+
/*
- * Hardware address lengths (in bytes) and network name based on hardware
- * type code. List in order specified by Assigned Numbers RFC; Array index
- * is hardware type code. Entries marked as zero are unknown to the author
- * at this time. . . .
+ * Initialization such as command-line processing is done and then the
+ * main server loop is started.
*/
-struct hwinfo hwinfolist[MAXHTYPES + 1] = {
- { 0, "Reserved" }, /* Type 0: Reserved (don't use this) */
- { 6, "Ethernet" }, /* Type 1: 10Mb Ethernet (48 bits) */
- { 1, "3Mb Ethernet" }, /* Type 2: 3Mb Ethernet (8 bits) */
- { 0, "AX.25" }, /* Type 3: Amateur Radio AX.25 */
- { 1, "ProNET" }, /* Type 4: Proteon ProNET Token Ring */
- { 0, "Chaos" }, /* Type 5: Chaos */
- { 6, "IEEE 802" }, /* Type 6: IEEE 802 Networks */
- { 0, "ARCNET" } /* Type 7: ARCNET */
-};
+void
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ struct timeval *timeout;
+ struct bootp *bp;
+ struct servent *servp;
+ struct hostent *hep;
+ char *stmp;
+ int n, ba_len, ra_len;
+ int nfound, readfds;
+ int standalone;
+
+ progname = strrchr(argv[0], '/');
+ if (progname) progname++;
+ else progname = argv[0];
+ /*
+ * Initialize logging.
+ */
+ report_init(0); /* uses progname */
-/*
- * Main hash tables
- */
+ /*
+ * Log startup
+ */
+ report(LOG_INFO, "version %s.%d", VERSION, PATCHLEVEL);
-hash_tbl *hwhashtable;
-hash_tbl *iphashtable;
-hash_tbl *nmhashtable;
+ /* Debugging for compilers with struct padding. */
+ assert(sizeof(struct bootp) == BP_MINPKTSZ);
+ /* Get space for receiving packets and composing replies. */
+ pktbuf = malloc(MAXPKT);
+ if (!pktbuf) {
+ report(LOG_ERR, "malloc failed");
+ exit(1);
+ }
+ bp = (struct bootp *) pktbuf;
-
+ /*
+ * Check to see if a socket was passed to us from inetd.
+ *
+ * Use getsockname() to determine if descriptor 0 is indeed a socket
+ * (and thus we are probably a child of inetd) or if it is instead
+ * something else and we are running standalone.
+ */
+ s = 0;
+ ba_len = sizeof(bind_addr);
+ bzero((char *) &bind_addr, ba_len);
+ errno = 0;
+ standalone = TRUE;
+ if (getsockname(s, (struct sockaddr *) &bind_addr, &ba_len) == 0) {
+ /*
+ * Descriptor 0 is a socket. Assume we are a child of inetd.
+ */
+ if (bind_addr.sin_family == AF_INET) {
+ standalone = FALSE;
+ bootps_port = ntohs(bind_addr.sin_port);
+ } else {
+ /* Some other type of socket? */
+ report(LOG_ERR, "getsockname: not an INET socket");
+ }
+ }
-/*
- * Initialization such as command-line processing is done and then the main
- * server loop is started.
- */
+ /*
+ * Set defaults that might be changed by option switches.
+ */
+ stmp = NULL;
+ timeout = &actualtimeout;
-main(argc, argv)
- int argc;
- char **argv;
-{
- struct timeval actualtimeout, *timeout;
- struct bootp *bp = (struct bootp *) buf;
- struct servent *servp;
- char *stmp;
- int n, tolen, fromlen;
- int nfound, readfds;
- int standalone;
-
- stmp = NULL;
- standalone = FALSE;
- actualtimeout.tv_usec = 0L;
- actualtimeout.tv_sec = 60 * DEFAULT_TIMEOUT;
- timeout = &actualtimeout;
-
-
- /*
- * Assume a socket was passed to us from inetd.
- *
- * Use getsockname() to determine if descriptor 0 is indeed a socket
- * (and thus we are probably a child of inetd) or if it is instead
- * something else and we are running standalone.
- */
- s = 0;
- tolen = sizeof(s_in);
- bzero((char *) &s_in, tolen);
- errno = 0;
- if (getsockname(s, (struct sockaddr *) &s_in, &tolen) == 0) {
/*
- * Descriptor 0 is a socket. Assume we're running as a child of inetd.
+ * Read switches.
*/
- bootps_port = ntohs(s_in.sin_port);
- standalone = FALSE;
- } else {
- if (errno == ENOTSOCK) {
- /*
- * Descriptor 0 is NOT a socket. Run in standalone mode.
- */
- standalone = TRUE;
- } else {
- /*
- * Something else went wrong. Punt.
- */
- fprintf(stderr, "bootpd: getsockname: %s\n",
- get_network_errmsg());
- exit(1);
- }
- }
-
-
- /*
- * Read switches.
- */
- for (argc--, argv++; argc > 0; argc--, argv++) {
- if (argv[0][0] == '-') {
- switch (argv[0][1]) {
- case 't':
- if (argv[0][2]) {
- stmp = &(argv[0][2]);
- } else {
- argc--;
- argv++;
- stmp = argv[0];
- }
- if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
- fprintf(stderr,
- "bootpd: invalid timeout specification\n");
+ for (argc--, argv++; argc > 0; argc--, argv++) {
+ if (argv[0][0] != '-')
+ break;
+ switch (argv[0][1]) {
+
+ case 'c': /* chdir_path */
+ if (argv[0][2]) {
+ stmp = &(argv[0][2]);
+ } else {
+ argc--;
+ argv++;
+ stmp = argv[0];
+ }
+ if (!stmp || (stmp[0] != '/')) {
+ fprintf(stderr,
+ "bootpd: invalid chdir specification\n");
+ break;
+ }
+ chdir_path = stmp;
+ break;
+
+ case 'd': /* debug level */
+ if (argv[0][2]) {
+ stmp = &(argv[0][2]);
+ } else if (argv[1] && argv[1][0] == '-') {
+ /*
+ * Backwards-compatible behavior:
+ * no parameter, so just increment the debug flag.
+ */
+ debug++;
+ break;
+ } else {
+ argc--;
+ argv++;
+ stmp = argv[0];
+ }
+ if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
+ fprintf(stderr,
+ "%s: invalid debug level\n", progname);
+ break;
+ }
+ debug = n;
+ break;
+
+ case 'i': /* inetd mode */
+ standalone = FALSE;
break;
- }
- actualtimeout.tv_sec = (long) (60 * n);
- /*
- * If the actual timeout is zero, pass a NULL pointer
- * to select so it blocks indefinitely, otherwise,
- * point to the actual timeout value.
- */
- timeout = (n > 0) ? &actualtimeout : NULL;
- break;
- case 'd':
- if (argv[0][2]) {
- stmp = &(argv[0][2]);
- } else if (argv[1] && argv[1][0] == '-') {
+
+ case 's': /* standalone mode */
+ standalone = TRUE;
+ break;
+
+ case 't': /* timeout */
+ if (argv[0][2]) {
+ stmp = &(argv[0][2]);
+ } else {
+ argc--;
+ argv++;
+ stmp = argv[0];
+ }
+ if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
+ fprintf(stderr,
+ "%s: invalid timeout specification\n", progname);
+ break;
+ }
+ actualtimeout.tv_sec = (int32) (60 * n);
/*
- * Backwards-compatible behavior:
- * no parameter, so just increment the debug flag.
+ * If the actual timeout is zero, pass a NULL pointer
+ * to select so it blocks indefinitely, otherwise,
+ * point to the actual timeout value.
*/
- debug++;
+ timeout = (n > 0) ? &actualtimeout : NULL;
break;
- } else {
- argc--;
- argv++;
- stmp = argv[0];
- }
- if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
- fprintf(stderr,
- "bootpd: invalid debug level\n");
+
+#ifdef YORK_EX_OPTION
+ case 'x':
+ if (argc < 2) {
+ fprintf(stderr, "missing exec_file_name\n");
+ break;
+ }
+ argc--; argv++;
+ exec_file_name = argv[1];
break;
- }
- debug = n;
- break;
- case 's':
- standalone = TRUE;
- break;
- case 'i':
- standalone = FALSE;
- break;
- default:
- fprintf(stderr, "bootpd: unknown switch: -%c\n",
- argv[0][1]);
- usage();
- break;
- }
- } else {
- if (!bootptab) {
- bootptab = argv[0];
-#ifdef DEBUG
- } else if (!bootpd_dump) {
- bootpd_dump = argv[0];
-#endif
- } else {
- fprintf(stderr, "bootpd: unknown argument: %s\n", argv[0]);
- usage();
- }
- }
- }
+#endif /* YORK_EX_OPTION */
- /*
- * Get hostname.
- */
- if (gethostname(hostname, sizeof(hostname)) == -1) {
- fprintf(stderr, "bootpd: can't get hostname\n");
- exit(1);
- }
-
- /*
- * Set default file names if not specified on command line
- */
- if (!bootptab) {
- bootptab = CONFIG_FILE;
- }
-#ifdef DEBUG
- if (!bootpd_dump) {
- bootpd_dump = DUMP_FILE;
- }
-#endif
+ default:
+ fprintf(stderr, "%s: unknown switch: -%c\n",
+ progname, argv[0][1]);
+ usage();
+ break;
+ } /* switch */
+ } /* for args */
- if (standalone) {
/*
- * Go into background and disassociate from controlling terminal.
+ * Override default file names if specified on the command line.
*/
- if (debug < 3) {
- if (fork())
- exit(0);
- for (n = 0; n < 10; n++)
- (void) close(n);
- (void) open("/", O_RDONLY);
- (void) dup2(0, 1);
- (void) dup2(0, 2);
- n = open("/dev/tty", O_RDWR);
- if (n >= 0) {
- ioctl(n, TIOCNOTTY, (char *) 0);
- (void) close(n);
- }
- }
+ if (argc > 0)
+ bootptab = argv[0];
+
+ if (argc > 1)
+ bootpd_dump = argv[1];
+
/*
- * Nuke any timeout value
+ * Get my hostname and IP address.
*/
- timeout = NULL;
- }
+ if (gethostname(hostname, sizeof(hostname)) == -1) {
+ fprintf(stderr, "bootpd: can't get hostname\n");
+ exit(1);
+ }
+ hep = gethostbyname(hostname);
+ if (!hep) {
+ fprintf(stderr, "Can not get my IP address\n");
+ exit(1);
+ }
+ bcopy(hep->h_addr, (char *)&my_ip_addr, sizeof(my_ip_addr));
+ if (standalone) {
+ /*
+ * Go into background and disassociate from controlling terminal.
+ */
+ if (debug < 3) {
+ if (fork())
+ exit(0);
+#ifdef NO_SETSID
+ setpgrp(0,0);
+#ifdef TIOCNOTTY
+ n = open("/dev/tty", O_RDWR);
+ if (n >= 0) {
+ ioctl(n, TIOCNOTTY, (char *) 0);
+ (void) close(n);
+ }
+#endif /* TIOCNOTTY */
+#else /* SETSID */
+ if (setsid() < 0)
+ perror("setsid");
+#endif /* SETSID */
+ } /* if debug < 3 */
-#ifdef SYSLOG
- /*
- * Initialize logging.
- */
-#ifndef LOG_CONS
-#define LOG_CONS 0 /* Don't bother if not defined... */
-#endif
-#ifndef LOG_DAEMON
-#define LOG_DAEMON 0
-#endif
- openlog("bootpd", LOG_PID | LOG_CONS, LOG_DAEMON);
-#endif
+ /*
+ * Nuke any timeout value
+ */
+ timeout = NULL;
- /*
- * Log startup
- */
- report(LOG_INFO, "%s", Version);
-
- /*
- * Get our timezone offset so we can give it to clients if the
- * configuration file doesn't specify one.
- */
- if (gettimeofday(&tp, &tzp) < 0) {
- secondswest = 0L; /* Assume GMT for lack of anything better */
- report(LOG_ERR, "gettimeofday: %s\n", get_errmsg());
- } else {
- secondswest = 60L * tzp.tz_minuteswest; /* Convert to seconds */
- }
-
- /*
- * Allocate hash tables for hardware address, ip address, and hostname
- */
- hwhashtable = hash_Init(HASHTABLESIZE);
- iphashtable = hash_Init(HASHTABLESIZE);
- nmhashtable = hash_Init(HASHTABLESIZE);
- if (!(hwhashtable && iphashtable && nmhashtable)) {
- report(LOG_ERR, "Unable to allocate hash tables.\n");
- exit(1);
- }
+ } /* if standalone (1st) */
+ /* Set the cwd (i.e. to /tftpboot) */
+ if (chdir_path) {
+ if (chdir(chdir_path) < 0)
+ report(LOG_ERR, "%s: chdir failed", chdir_path);
+ }
- /*
- * Read the bootptab file once immediately upon startup.
- */
- readtab();
+ /* Get the timezone. */
+ tzone_init();
+ /* Allocate hash tables. */
+ rdtab_init();
- if (standalone) {
/*
- * Create a socket.
+ * Read the bootptab file.
*/
- if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
- report(LOG_ERR, "socket: %s\n", get_network_errmsg());
- exit(1);
- }
+ readtab(1); /* force read */
+
+ if (standalone) {
+
+ /*
+ * Create a socket.
+ */
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ report(LOG_ERR, "socket: %s", get_network_errmsg());
+ exit(1);
+ }
+
+ /*
+ * Get server's listening port number
+ */
+ servp = getservbyname("bootps", "udp");
+ if (servp) {
+ bootps_port = ntohs((u_short) servp->s_port);
+ } else {
+ bootps_port = (u_short) IPPORT_BOOTPS;
+ report(LOG_ERR,
+ "udp/bootps: unknown service -- assuming port %d",
+ bootps_port);
+ }
+
+ /*
+ * Bind socket to BOOTPS port.
+ */
+ bind_addr.sin_family = AF_INET;
+ bind_addr.sin_addr.s_addr = INADDR_ANY;
+ bind_addr.sin_port = htons(bootps_port);
+ if (bind(s, (struct sockaddr *) &bind_addr,
+ sizeof(bind_addr)) < 0)
+ {
+ report(LOG_ERR, "bind: %s", get_network_errmsg());
+ exit(1);
+ }
+ } /* if standalone (2nd)*/
/*
- * Get server's listening port number
+ * Get destination port number so we can reply to client
*/
- servp = getservbyname("bootps", "udp");
+ servp = getservbyname("bootpc", "udp");
if (servp) {
- bootps_port = ntohs((u_short) servp->s_port);
+ bootpc_port = ntohs(servp->s_port);
} else {
- report(LOG_ERR,
- "udp/bootps: unknown service -- assuming port %d\n",
- IPPORT_BOOTPS);
- bootps_port = (u_short) IPPORT_BOOTPS;
+ report(LOG_ERR,
+ "udp/bootpc: unknown service -- assuming port %d",
+ IPPORT_BOOTPC);
+ bootpc_port = (u_short) IPPORT_BOOTPC;
}
/*
- * Bind socket to BOOTPS port.
+ * Set up signals to read or dump the table.
*/
- s_in.sin_family = AF_INET;
- s_in.sin_addr.s_addr = INADDR_ANY;
- s_in.sin_port = htons(bootps_port);
- if (bind(s, (struct sockaddr *) &s_in, sizeof(s_in)) < 0) {
- report(LOG_ERR, "bind: %s\n", get_network_errmsg());
- exit(1);
- }
- }
-
-
- /*
- * Get destination port number so we can reply to client
- */
- servp = getservbyname("bootpc", "udp");
- if (servp) {
- bootpc_port = ntohs(servp->s_port);
- } else {
- report(LOG_ERR,
- "udp/bootpc: unknown service -- assuming port %d\n",
- IPPORT_BOOTPC);
- bootpc_port = (u_short) IPPORT_BOOTPC;
- }
-
-
- /*
- * Determine network configuration.
- */
- ifconf.ifc_len = sizeof(ifreq);
- ifconf.ifc_req = ifreq;
- if ((ioctl(s, SIOCGIFCONF, (caddr_t) &ifconf) < 0) ||
- (ifconf.ifc_len <= 0)) {
- report(LOG_ERR, "ioctl: %s\n", get_network_errmsg());
- exit(1);
- }
-
-
- /*
- * Set up signals to read or dump the table.
- */
- if ((int) signal(SIGHUP, readtab) < 0) {
- report(LOG_ERR, "signal: %s\n", get_errmsg());
- exit(1);
- }
-#ifdef DEBUG
- if ((int) signal(SIGUSR1, dumptab) < 0) {
- report(LOG_ERR, "signal: %s\n", get_errmsg());
- exit(1);
- }
-#endif
-
- /*
- * Process incoming requests.
- */
- for (;;) {
- readfds = 1 << s;
- nfound = select(s + 1, &readfds, NULL, NULL, timeout);
- if (nfound < 0) {
- if (errno != EINTR) {
- report(LOG_ERR, "select: %s\n", get_errmsg());
- }
- continue;
+ if ((int) signal(SIGHUP, catcher) < 0) {
+ report(LOG_ERR, "signal: %s", get_errmsg());
+ exit(1);
}
- if (!(readfds & (1 << s))) {
- report(LOG_INFO, "exiting after %ld minutes of inactivity\n",
- actualtimeout.tv_sec / 60);
- exit(0);
- }
- fromlen = sizeof(from);
- n = recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr *) &from,
- &fromlen);
- if (n <= 0) {
- continue;
+ if ((int) signal(SIGUSR1, catcher) < 0) {
+ report(LOG_ERR, "signal: %s", get_errmsg());
+ exit(1);
}
- if (n < sizeof(struct bootp)) {
- if (debug) {
- report(LOG_INFO, "received short packet\n");
- }
- continue;
- }
+ /*
+ * Process incoming requests.
+ */
+ for (;;) {
+ readfds = 1 << s;
+ nfound = select(s + 1, (fd_set *)&readfds, NULL, NULL, timeout);
+ if (nfound < 0) {
+ if (errno != EINTR) {
+ report(LOG_ERR, "select: %s", get_errmsg());
+ }
+ /*
+ * Call readtab() or dumptab() here to avoid the
+ * dangers of doing I/O from a signal handler.
+ */
+ if (do_readtab) {
+ do_readtab = 0;
+ readtab(1); /* force read */
+ }
+ if (do_dumptab) {
+ do_dumptab = 0;
+ dumptab(bootpd_dump);
+ }
+ continue;
+ }
+ if (!(readfds & (1 << s))) {
+ if (debug > 1)
+ report(LOG_INFO, "exiting after %ld minutes of inactivity",
+ actualtimeout.tv_sec / 60);
+ exit(0);
+ }
+ ra_len = sizeof(recv_addr);
+ n = recvfrom(s, pktbuf, MAXPKT, 0,
+ (struct sockaddr *) &recv_addr, &ra_len);
+ if (n <= 0) {
+ continue;
+ }
+ if (debug > 1) {
+ report(LOG_INFO, "recvd pkt from IP addr %s",
+ inet_ntoa(recv_addr.sin_addr));
+ }
+ if (n < sizeof(struct bootp)) {
+ if (debug) {
+ report(LOG_INFO, "received short packet");
+ }
+ continue;
+ }
+ pktlen = n;
- readtab(); /* maybe re-read bootptab */
- switch (bp->bp_op) {
- case BOOTREQUEST:
- request();
- break;
+ readtab(0); /* maybe re-read bootptab */
- case BOOTREPLY:
- reply();
- break;
+ switch (bp->bp_op) {
+ case BOOTREQUEST:
+ handle_request();
+ break;
+ case BOOTREPLY:
+ handle_reply();
+ break;
+ }
}
- }
}
@@ -564,15 +557,33 @@ main(argc, argv)
* Print "usage" message and exit
*/
-void usage()
+PRIVATE void
+usage()
{
- fprintf(stderr,
-"usage: bootpd [-d level] [-i] [-s] [-t timeout] [configfile [dumpfile]]\n");
- fprintf(stderr, "\t -d n\tset debug level\n");
- fprintf(stderr, "\t -i\tforce inetd mode (run as child of inetd)\n");
- fprintf(stderr, "\t -s\tforce standalone mode (run without inetd)\n");
- fprintf(stderr, "\t -t n\tset inetd exit timeout to n minutes\n");
- exit(1);
+ fprintf(stderr,
+ "usage: bootpd [-d level] [-i] [-s] [-t timeout] [configfile [dumpfile]]\n");
+ fprintf(stderr, "\t -c n\tset current directory\n");
+ fprintf(stderr, "\t -d n\tset debug level\n");
+ fprintf(stderr, "\t -i\tforce inetd mode (run as child of inetd)\n");
+ fprintf(stderr, "\t -s\tforce standalone mode (run without inetd)\n");
+ fprintf(stderr, "\t -t n\tset inetd exit timeout to n minutes\n");
+ exit(1);
+}
+
+/* Signal catchers */
+PRIVATE void
+catcher(sig)
+ int sig;
+{
+ if (sig == SIGHUP)
+ do_readtab = 1;
+ if (sig == SIGUSR1)
+ do_dumptab = 1;
+#ifdef SYSV
+ /* For older "System V" derivatives with no sigset(). */
+ /* XXX - Should just do it the POSIX way (sigaction). */
+ signal(sig, catcher);
+#endif
}
@@ -580,402 +591,527 @@ void usage()
/*
* Process BOOTREQUEST packet.
*
- * (Note, this version of the bootpd.c server never forwards
- * the request to another server. In our environment the
- * stand-alone gateways perform that function.)
+ * Note: This version of the bootpd.c server never forwards
+ * a request to another server. That is the job of a gateway
+ * program such as the "bootpgw" program included here.
*
* (Also this version does not interpret the hostname field of
* the request packet; it COULD do a name->address lookup and
* forward the request there.)
*/
-request()
+PRIVATE void
+handle_request()
{
- struct bootp *bp = (struct bootp *) buf;
- struct host *hp;
- int n;
- char *path;
- struct host dummyhost;
- long bootsize;
- unsigned hlen, hashcode;
- char realpath[1024];
-
- /*
- * If the servername field is set, compare it against us.
- * If we're not being addressed, ignore this request.
- * If the server name field is null, throw in our name.
- */
- if (strlen(bp->bp_sname)) {
- if (strcmp((char *)bp->bp_sname, hostname)) {
- return;
- }
- } else {
- strcpy((char *)bp->bp_sname, hostname);
- }
- bp->bp_op = BOOTREPLY;
- if (bp->bp_ciaddr.s_addr == 0) {
+ struct bootp *bp = (struct bootp *) pktbuf;
+ struct host *hp = NULL;
+ struct host dummyhost;
+ int32 bootsize = 0;
+ unsigned hlen, hashcode;
+ int32 dest;
+#ifdef CHECK_FILE_ACCESS
+ char realpath[1024];
+ char *path;
+ int n;
+#endif
+
+ /* XXX - SLIP init: Set bp_ciaddr = recv_addr here? */
+
/*
- * client doesnt know his IP address,
- * search by hardware address.
+ * If the servername field is set, compare it against us.
+ * If we're not being addressed, ignore this request.
+ * If the server name field is null, throw in our name.
*/
- if (debug) {
- report(LOG_INFO, "request from %s address %s\n",
- netname(bp->bp_htype),
- haddrtoa(bp->bp_chaddr, bp->bp_htype));
+ if (strlen(bp->bp_sname)) {
+ if (strcmp(bp->bp_sname, hostname)) {
+ if (debug)
+ report(LOG_INFO, "\
+ignoring request for server %s from client at %s address %s",
+ bp->bp_sname, netname(bp->bp_htype),
+ haddrtoa(bp->bp_chaddr, bp->bp_hlen));
+ /* XXX - Is it correct to ignore such a request? -gwr */
+ return;
+ }
+ } else {
+ strcpy(bp->bp_sname, hostname);
}
- dummyhost.htype = bp->bp_htype;
- hlen = haddrlength(bp->bp_htype);
- bcopy(bp->bp_chaddr, dummyhost.haddr, hlen);
- hashcode = hash_HashFunction(bp->bp_chaddr, hlen);
- hp = (struct host *) hash_Lookup(hwhashtable, hashcode, hwlookcmp,
- &dummyhost);
- if (hp == NULL) {
- report(LOG_NOTICE, "%s address not found: %s\n",
- netname(bp->bp_htype),
- haddrtoa(bp->bp_chaddr, bp->bp_htype));
- return; /* not found */
+ bp->bp_op = BOOTREPLY;
+ if (bp->bp_ciaddr.s_addr == 0) {
+ /*
+ * client doesnt know his IP address,
+ * search by hardware address.
+ */
+ if (debug > 1) {
+ report(LOG_INFO, "request from %s address %s",
+ netname(bp->bp_htype),
+ haddrtoa(bp->bp_chaddr, bp->bp_hlen));
+ }
+ hlen = haddrlength(bp->bp_htype);
+ if (hlen != bp->bp_hlen) {
+ report(LOG_NOTICE, "bad addr len from from %s address %s",
+ netname(bp->bp_htype),
+ haddrtoa(bp->bp_chaddr, hlen));
+ }
+ dummyhost.htype = bp->bp_htype;
+ bcopy(bp->bp_chaddr, dummyhost.haddr, hlen);
+ hashcode = hash_HashFunction(bp->bp_chaddr, hlen);
+ hp = (struct host *) hash_Lookup(hwhashtable, hashcode, hwlookcmp,
+ &dummyhost);
+ if (hp == NULL &&
+ bp->bp_htype == HTYPE_IEEE802)
+ {
+ /* Try again with address in "canonical" form. */
+ haddr_conv802(bp->bp_chaddr, dummyhost.haddr, hlen);
+ if (debug > 1) {
+ report(LOG_INFO, "\
+HW addr type is IEEE 802. convert to %s and check again\n",
+ haddrtoa(dummyhost.haddr, bp->bp_hlen));
+ }
+ hashcode = hash_HashFunction(dummyhost.haddr, hlen);
+ hp = (struct host *) hash_Lookup(hwhashtable, hashcode,
+ hwlookcmp, &dummyhost);
+ }
+ if (hp == NULL) {
+ /*
+ * XXX - Add dynamic IP address assignment?
+ */
+ if (debug > 1)
+ report(LOG_INFO, "unknown client %s address %s",
+ netname(bp->bp_htype),
+ haddrtoa(bp->bp_chaddr, bp->bp_hlen));
+ return; /* not found */
+ }
+ (bp->bp_yiaddr).s_addr = hp->iaddr.s_addr;
+
+ } else {
+
+ /*
+ * search by IP address.
+ */
+ if (debug > 1) {
+ report(LOG_INFO, "request from IP addr %s",
+ inet_ntoa(bp->bp_ciaddr));
+ }
+ dummyhost.iaddr.s_addr = bp->bp_ciaddr.s_addr;
+ hashcode = hash_HashFunction((u_char *) &(bp->bp_ciaddr.s_addr), 4);
+ hp = (struct host *) hash_Lookup(iphashtable, hashcode, iplookcmp,
+ &dummyhost);
+ if (hp == NULL) {
+ if (debug > 1) {
+ report(LOG_NOTICE, "IP address not found: %s",
+ inet_ntoa(bp->bp_ciaddr));
+ }
+ return;
+ }
}
- (bp->bp_yiaddr).s_addr = hp->iaddr.s_addr;
- } else {
-
- /*
- * search by IP address.
- */
if (debug) {
- report(LOG_INFO, "request from IP addr %s\n",
- inet_ntoa(bp->bp_ciaddr));
+ report(LOG_INFO, "found %s (%s)", inet_ntoa(hp->iaddr),
+ hp->hostname->string);
}
- dummyhost.iaddr.s_addr = bp->bp_ciaddr.s_addr;
- hashcode = hash_HashFunction((char *) &(bp->bp_ciaddr.s_addr), 4);
- hp = (struct host *) hash_Lookup(iphashtable, hashcode, iplookcmp,
- &dummyhost);
- if (hp == NULL) {
- report(LOG_NOTICE,
- "IP address not found: %s\n", inet_ntoa(bp->bp_ciaddr));
- return;
- }
- }
-
- if (debug) {
- report(LOG_INFO, "found %s %s\n", inet_ntoa(hp->iaddr),
- hp->hostname->string);
- }
-
- /*
- * If a specific TFTP server address was specified in the bootptab file,
- * fill it in, otherwise zero it.
- */
- (bp->bp_siaddr).s_addr = (hp->flags.bootserver) ?
- hp->bootserver.s_addr : 0L;
-
- /*
- * This next line is a bit of a mystery. It seems to be vestigial
- * code (from Stanford???) which should probably be axed.
- */
- if (strcmp(bp->bp_file, "sunboot14") == 0)
- bp->bp_file[0] = 0; /* pretend it's null */
-
-
- /*
- * Fill in the client's proper bootfile.
- *
- * If the client specifies an absolute path, try that file with a
- * ".host" suffix and then without. If the file cannot be found, no
- * reply is made at all.
- *
- * If the client specifies a null or relative file, use the following
- * table to determine the appropriate action:
- *
- * Homedir Bootfile Client's file
- * specified? specified? specification Action
- * -------------------------------------------------------------------
- * No No Null Send null filename
- * No No Relative Discard request
- * No Yes Null Send if absolute else null
- * No Yes Relative Discard request
- * Yes No Null Send null filename
- * Yes No Relative Lookup with ".host"
- * Yes Yes Null Send home/boot or bootfile
- * Yes Yes Relative Lookup with ".host"
- *
- */
-
- if (hp->flags.tftpdir) {
- strcpy(realpath, hp->tftpdir->string);
- path = &realpath[strlen(realpath)];
- } else {
- path = realpath;
- }
-
- if (bp->bp_file[0]) {
+
+#ifdef YORK_EX_OPTION
/*
- * The client specified a file.
+ * The need for the "ex" tag arose out of the need to empty
+ * shared networked drives on diskless PCs. This solution is
+ * not very clean but it does work fairly well.
+ * Written by Edmund J. Sutcliffe <edmund@york.ac.uk>
*/
- if (bp->bp_file[0] == '/') {
- strcpy(path, bp->bp_file); /* Absolute pathname */
- } else {
- if (hp->flags.homedir) {
- strcpy(path, hp->homedir->string);
- strcat(path, "/");
- strcat(path, bp->bp_file);
- } else {
- report(LOG_NOTICE,
- "requested file \"%s\" not found: hd unspecified\n",
- bp->bp_file);
- return;
- }
- }
- } else {
+ /* Run a program, passing the client name as a parameter. */
+ if (exec_file_name) {
+ char tst[100];
+ strcpy (tst, exec_file_name);
+ strcat (tst, " ");
+ strcat (tst, hp->hostname->string);
+ strcat (tst, " &");
+ if (debug)
+ report(LOG_INFO, "executing %s", tst);
+ system(tst); /* Hope this finishes soon... */
+ }
+#endif /* YORK_EX_OPTION */
+
+ /*
+ * If a specific TFTP server address was specified in the bootptab file,
+ * fill it in, otherwise zero it.
+ * XXX - Rather than zero it, should it be the bootpd address? -gwr
+ */
+ (bp->bp_siaddr).s_addr = (hp->flags.bootserver) ?
+ hp->bootserver.s_addr : 0L;
+
+#ifdef STANFORD_PROM_COMPAT
+ /*
+ * Stanford bootp PROMs (for a Sun?) have no way to leave
+ * the boot file name field blank (because the boot file
+ * name is automatically generated from some index).
+ * As a work-around, this little hack allows those PROMs to
+ * specify "sunboot14" with the same effect as a NULL name.
+ * (The user specifies boot device 14 or some such magic.)
+ */
+ if (strcmp(bp->bp_file, "sunboot14") == 0)
+ bp->bp_file[0] = '\0'; /* treat it as unspecified */
+#endif
+
/*
- * No file specified by the client.
+ * Fill in the client's proper bootfile.
+ *
+ * If the client specifies an absolute path, try that file with a
+ * ".host" suffix and then without. If the file cannot be found, no
+ * reply is made at all.
+ *
+ * If the client specifies a null or relative file, use the following
+ * table to determine the appropriate action:
+ *
+ * Homedir Bootfile Client's file
+ * specified? specified? specification Action
+ * -------------------------------------------------------------------
+ * No No Null Send null filename
+ * No No Relative Discard request
+ * No Yes Null Send if absolute else null
+ * No Yes Relative Discard request *XXX
+ * Yes No Null Send null filename
+ * Yes No Relative Lookup with ".host"
+ * Yes Yes Null Send home/boot or bootfile
+ * Yes Yes Relative Lookup with ".host" *XXX
+ *
*/
- if (hp->flags.bootfile && ((hp->bootfile->string)[0] == '/')) {
- strcpy(path, hp->bootfile->string);
- } else if (hp->flags.homedir && hp->flags.bootfile) {
- strcpy(path, hp->homedir->string);
- strcat(path, "/");
- strcat(path, hp->bootfile->string);
+
+ /*
+ * XXX - I think the above policy is too complicated. When the
+ * boot file is missing, it is not obvious why bootpd will not
+ * respond to client requests. Define CHECK_FILE_ACCESS if you
+ * want the original complicated policy, otherwise bootpd will
+ * no longer check for existence of the boot file. -gwr
+ */
+
+#ifdef CHECK_FILE_ACCESS
+
+ if (hp->flags.tftpdir) {
+ strcpy(realpath, hp->tftpdir->string);
+ path = &realpath[strlen(realpath)];
} else {
- bzero(bp->bp_file, sizeof(bp->bp_file));
- goto skip_file; /* Don't bother trying to access the file */
+ path = realpath;
}
- }
-
- /*
- * First try to find the file with a ".host" suffix
- */
- n = strlen(path);
- strcat(path, ".");
- strcat(path, hp->hostname->string);
- if (chk_access(realpath, &bootsize) < 0) {
- path[n] = 0; /* Try it without the suffix */
- if (chk_access(realpath, &bootsize) < 0) {
- if (bp->bp_file[0]) {
+
+ if (bp->bp_file[0]) {
/*
- * Client wanted specific file
- * and we didn't have it.
+ * The client specified a file.
*/
- report(LOG_NOTICE,
- "requested file not found: \"%s\"\n", path);
- return;
- } else {
+ if (bp->bp_file[0] == '/') {
+ strcpy(path, bp->bp_file); /* Absolute pathname */
+ } else {
+ if (hp->flags.homedir) {
+ strcpy(path, hp->homedir->string);
+ strcat(path, "/");
+ strcat(path, bp->bp_file);
+ } else {
+ report(LOG_NOTICE,
+ "requested file \"%s\" not found: hd unspecified",
+ bp->bp_file);
+ return;
+ }
+ }
+ } else {
/*
- * Client didn't ask for a specific file and we couldn't
- * access the default file, so just zero-out the bootfile
- * field in the packet and continue processing the reply.
+ * No file specified by the client.
*/
- bzero(bp->bp_file, sizeof(bp->bp_file));
- goto skip_file;
- }
+ if (hp->flags.bootfile && ((hp->bootfile->string)[0] == '/')) {
+ strcpy(path, hp->bootfile->string);
+ } else if (hp->flags.homedir && hp->flags.bootfile) {
+ strcpy(path, hp->homedir->string);
+ strcat(path, "/");
+ strcat(path, hp->bootfile->string);
+ } else {
+ bzero(bp->bp_file, sizeof(bp->bp_file));
+ goto skip_file; /* Don't bother trying to access the file */
+ }
}
- }
- strcpy(bp->bp_file, path);
-skip_file: ;
+ /*
+ * First try to find the file with a ".host" suffix
+ */
+ n = strlen(path);
+ strcat(path, ".");
+ strcat(path, hp->hostname->string);
+ if (chk_access(realpath, &bootsize) < 0) {
+ path[n] = 0; /* Try it without the suffix */
+ if (chk_access(realpath, &bootsize) < 0) {
+ if (bp->bp_file[0]) {
+ /*
+ * Client wanted specific file
+ * and we didn't have it.
+ */
+ report(LOG_NOTICE,
+ "requested file not found: \"%s\"", path);
+ return;
+ } else {
+ /*
+ * Client didn't ask for a specific file and we couldn't
+ * access the default file, so just zero-out the bootfile
+ * field in the packet and continue processing the reply.
+ */
+ bzero(bp->bp_file, sizeof(bp->bp_file));
+ goto skip_file;
+ }
+ }
+ }
+ strcpy(bp->bp_file, path);
+ skip_file:
+ ;
+#else /* CHECK_FILE_ACCESS */
- if (debug > 1) {
- report(LOG_INFO, "vendor magic field is %d.%d.%d.%d\n",
- (int) ((bp->bp_vend)[0]),
- (int) ((bp->bp_vend)[1]),
- (int) ((bp->bp_vend)[2]),
- (int) ((bp->bp_vend)[3]));
- }
-
- /*
- * If this host isn't set for automatic vendor info then copy the
- * specific cookie into the bootp packet, thus forcing a certain
- * reply format.
- */
- if (!hp->flags.vm_auto) {
- bcopy(hp->vm_cookie, bp->bp_vend, 4);
- }
-
- /*
- * Figure out the format for the vendor-specific info.
- */
- if (!bcmp(bp->bp_vend, vm_cmu, 4)) {
- /* Not an RFC1048 bootp client */
+ /*
+ * This implements a simple response policy, where bootpd
+ * will fail to respond only if it knows nothing about
+ * the client that sent the request. This plugs in the
+ * boot file name but does not demand that it exist.
+ *
+ * If either the client or the server specifies a boot file,
+ * build the path name for it. Server boot file preferred.
+ */
+ if (bp->bp_file[0] || hp->flags.bootfile) {
+ char requested_file[BP_FILE_LEN];
+ char *given_file;
+ char *p = bp->bp_file;
+ int space = BP_FILE_LEN;
+ int n;
+
+ /* Save client's requested file name. */
+ strncpy(requested_file, bp->bp_file, BP_FILE_LEN);
+
+ /* If tftpdir is set, insert it. */
+ if (hp->flags.tftpdir) {
+ n = strlen(hp->tftpdir->string);
+ if ((n+1) >= space)
+ goto nospc;
+ strcpy(p, hp->tftpdir->string);
+ p += n;
+ space -= n;
+ }
+
+ /* If homedir is set, insert it. */
+ if (hp->flags.homedir) {
+ n = strlen(hp->homedir->string);
+ if ((n+1) >= space)
+ goto nospc;
+ strcpy(p, hp->homedir->string);
+ p += n;
+ space -= n;
+ }
+
+ /* Finally, append the boot file name. */
+ if (hp->flags.bootfile)
+ given_file = hp->bootfile->string;
+ else
+ given_file = requested_file;
+ assert(given_file);
+ n = strlen(given_file);
+ if ((n+1) >= space)
+ goto nospc;
+ strcpy(p, given_file);
+ p += n;
+ space -= n;
+ *p = '\0';
+
+ if (space <= 0) {
+ nospc:
+ report(LOG_ERR, "boot file path too long (%s)",
+ hp->hostname->string);
+ }
+ }
+
+ /* Determine boot file size if requested. */
+ if (hp->flags.bootsize_auto) {
+ if (bp->bp_file[0] == '\0' ||
+ chk_access(bp->bp_file, &bootsize) < 0)
+ {
+ report(LOG_ERR, "can not determine boot file size for %s",
+ hp->hostname->string);
+ }
+ }
+
+#endif /* CHECK_FILE_ACCESS */
+
+
+ if (debug > 1) {
+ report(LOG_INFO, "vendor magic field is %d.%d.%d.%d",
+ (int) ((bp->bp_vend)[0]),
+ (int) ((bp->bp_vend)[1]),
+ (int) ((bp->bp_vend)[2]),
+ (int) ((bp->bp_vend)[3]));
+ }
+ /*
+ * If this host isn't set for automatic vendor info then copy the
+ * specific cookie into the bootp packet, thus forcing a certain
+ * reply format. Only force reply format if user specified it.
+ */
+ if (hp->flags.vm_cookie) {
+ /* Slam in the user specified magic number. */
+ bcopy(hp->vm_cookie, bp->bp_vend, 4);
+ }
+ /*
+ * Figure out the format for the vendor-specific info.
+ * Note that bp->bp_vend may have been set above.
+ */
+ if (!bcmp(bp->bp_vend, vm_rfc1048, 4)) {
+ /* RFC1048 conformant bootp client */
+ dovend_rfc1048(bp, hp, bootsize);
+ if (debug > 1) {
+ report(LOG_INFO, "sending reply (with RFC1048 options)");
+ }
+ }
#ifdef VEND_CMU
- dovend_cmu(bp, hp);
-#else
- dovend_rfc1048(bp, hp, bootsize);
+ else if (!bcmp(bp->bp_vend, vm_cmu, 4)) {
+ dovend_cmu(bp, hp);
+ if (debug > 1) {
+ report(LOG_INFO, "sending reply (with CMU options)");
+ }
+ }
#endif
- } else {
- /* RFC1048 conformant bootp client */
- dovend_rfc1048(bp, hp, bootsize);
- }
- sendreply(0);
+ else {
+ if (debug > 1) {
+ report(LOG_INFO, "sending reply (with no options)");
+ }
+ }
+
+ dest = (hp->flags.reply_addr) ?
+ hp->reply_addr.s_addr : 0L;
+
+ /* not forwarded */
+ sendreply(0, dest);
}
-
/*
- * Process BOOTREPLY packet (something is using us as a gateway).
+ * Process BOOTREPLY packet.
*/
-
-reply()
+PRIVATE void
+handle_reply()
{
if (debug) {
- report(LOG_INFO, "processing boot reply\n");
+ report(LOG_INFO, "processing boot reply");
}
- sendreply(1);
+ /* forwarded, no destination override */
+ sendreply(1, 0);
}
-
/*
* Send a reply packet to the client. 'forward' flag is set if we are
* not the originator of this reply packet.
*/
-sendreply(forward)
- int forward;
+PRIVATE void
+sendreply(forward, dst_override)
+ int forward;
+ int32 dst_override;
{
- struct bootp *bp = (struct bootp *) buf;
+ struct bootp *bp = (struct bootp *) pktbuf;
struct in_addr dst;
- struct sockaddr_in to;
-
- to = s_in;
+ u_short port = bootpc_port;
+#if 0
+ u_char canon_haddr[MAXHADDRLEN];
+#endif
+ unsigned char *ha;
+ int len;
- to.sin_port = htons(bootpc_port);
/*
- * If the client IP address is specified, use that
+ * If the destination address was specified explicitly
+ * (i.e. the broadcast address for HP compatiblity)
+ * then send the response to that address. Otherwise,
+ * act in accordance with RFC951:
+ * If the client IP address is specified, use that
* else if gateway IP address is specified, use that
- * else make a temporary arp cache entry for the client's NEW
- * IP/hardware address and use that.
+ * else make a temporary arp cache entry for the client's
+ * NEW IP/hardware address and use that.
*/
- if (bp->bp_ciaddr.s_addr) {
+ if (dst_override) {
+ dst.s_addr = dst_override;
+ if (debug > 1) {
+ report(LOG_INFO, "reply address override: %s",
+ inet_ntoa(dst));
+ }
+ } else if (bp->bp_ciaddr.s_addr) {
dst = bp->bp_ciaddr;
} else if (bp->bp_giaddr.s_addr && forward == 0) {
dst = bp->bp_giaddr;
- to.sin_port = htons(bootps_port);
+ port = bootps_port;
+ if (debug > 1) {
+ report(LOG_INFO, "sending reply to gateway %s",
+ inet_ntoa(dst));
+ }
} else {
dst = bp->bp_yiaddr;
- setarp(&dst, bp->bp_chaddr, bp->bp_hlen);
+ ha = bp->bp_chaddr;
+ len = bp->bp_hlen;
+ if (len > MAXHADDRLEN)
+ len = MAXHADDRLEN;
+#if 0
+ /*
+ * XXX - Is this necessary, given that the HW address
+ * in bp_chaddr was left as the client provided it?
+ * Does some DEC version of TCP/IP need this? -gwr
+ */
+ if (bp->bp_htype == HTYPE_IEEE802) {
+ haddr_conv802(ha, canon_haddr, len);
+ ha = canon_haddr;
+ }
+#endif
+ if (debug > 1)
+ report(LOG_INFO, "setarp %s - %s",
+ inet_ntoa(dst), haddrtoa(ha, len));
+ setarp(s, &dst, ha, len);
}
- if (forward == 0) {
+ if ((forward == 0) &&
+ (bp->bp_siaddr.s_addr == 0))
+ {
+ struct ifreq *ifr;
+ struct in_addr siaddr;
/*
* If we are originating this reply, we
* need to find our own interface address to
* put in the bp_siaddr field of the reply.
* If this server is multi-homed, pick the
* 'best' interface (the one on the same net
- * as the client).
+ * as the client). Of course, the client may
+ * be on the other side of a BOOTP gateway...
*/
-#if 0
- int maxmatch = 0;
- int len, m;
- struct ifreq *ifrq, *ifrmax;
-
- ifrmax = ifrq = &ifreq[0];
- len = ifconf.ifc_len;
- for (; len > 0; len -= sizeof(ifreq[0]), ifrq++) {
- m = nmatch(&dst, &((struct sockaddr_in *)
- (&ifrq->ifr_addr))->sin_addr);
- if (m > maxmatch) {
- maxmatch = m;
- ifrmax = ifrq;
- }
- }
-#endif
- int maxmatch = 0;
- int len, m;
- struct ifreq *ifrq, *ifrmax;
- char *p;
-
- ifrmax = &ifreq[0];
- p = (char *)&ifreq[0];
- len = ifconf.ifc_len;
- for (; len > 0; ) {
- ifrq = (struct ifreq *)p;
- m = nmatch(&dst, &((struct sockaddr_in *)
- (&ifrq->ifr_addr))->sin_addr);
- if (m > maxmatch) {
- maxmatch = m;
- ifrmax = ifrq;
- }
- p += ifrq->ifr_addr.sa_len + IFNAMSIZ;
- len -= ifrq->ifr_addr.sa_len + IFNAMSIZ;
+ ifr = getif(s, &dst);
+ if (ifr) {
+ struct sockaddr_in *sip;
+ sip = (struct sockaddr_in *) &(ifr->ifr_addr);
+ siaddr = sip->sin_addr;
+ } else {
+ /* Just use my "official" IP address. */
+ siaddr = my_ip_addr;
}
- if (bp->bp_giaddr.s_addr == 0) {
- if (maxmatch == 0) {
- return;
- }
- bp->bp_giaddr = ((struct sockaddr_in *)
- (&ifrmax->ifr_addr))->sin_addr;
- }
+ /* XXX - No need to set bp_giaddr here. */
- /*
- * If a specific TFTP server address wasn't specified
- * in the bootptab file, fill in our own address.
- */
- if (bp->bp_siaddr.s_addr == 0) {
- bp->bp_siaddr = ((struct sockaddr_in *)
- (&ifrmax->ifr_addr))->sin_addr;
- }
+ /* Finally, set the server address field. */
+ bp->bp_siaddr = siaddr;
}
+ /* Set up socket address for send. */
+ send_addr.sin_family = AF_INET;
+ send_addr.sin_port = htons(port);
+ send_addr.sin_addr = dst;
- to.sin_addr = dst;
- if (sendto(s, bp, sizeof(struct bootp), 0, (struct sockaddr *) &to,
- sizeof(to)) < 0) {
- report(LOG_ERR, "sendto: %s\n", get_network_errmsg());
+ /* Send reply with same size packet as request used. */
+ if (sendto(s, pktbuf, pktlen, 0,
+ (struct sockaddr *) &send_addr,
+ sizeof(send_addr)) < 0)
+ {
+ report(LOG_ERR, "sendto: %s", get_network_errmsg());
}
-}
-
+} /* sendreply */
-/*
- * Return the number of leading bytes matching in the
- * internet addresses supplied.
- */
-nmatch(ca,cb)
- char *ca, *cb;
-{
- int n,m;
-
- for (m = n = 0 ; n < 4 ; n++) {
- if (*ca++ != *cb++)
- return(m);
- m++;
- }
- return(m);
-}
-
+/* nmatch() - now in getif.c */
+/* setarp() - now in hwaddr.c */
/*
- * Setup the arp cache so that IP address 'ia' will be temporarily
- * bound to hardware address 'ha' of length 'len'.
- */
-setarp(ia, ha, len)
- struct in_addr *ia;
- byte *ha;
- int len;
-{
- struct sockaddr_in *si;
-
- bzero((caddr_t)&arpreq, sizeof(arpreq));
-
- arpreq.arp_pa.sa_family = AF_INET;
- si = (struct sockaddr_in *) &arpreq.arp_pa;
- si->sin_addr = *ia;
-
- arpreq.arp_flags = ATF_INUSE | ATF_COM;
-
- bcopy(ha, arpreq.arp_ha.sa_data, len);
-
- if (ioctl(s, SIOCSARP, (caddr_t)&arpreq) < 0) {
- report(LOG_ERR, "ioctl(SIOCSARP): %s\n", get_network_errmsg());
- }
-}
-
-
-
-/*
* This call checks read access to a file. It returns 0 if the file given
* by "path" exists and is publically readable. A value of -1 is returned if
* access is not permitted or an error occurs. Successful calls also
@@ -985,749 +1121,214 @@ setarp(ia, ha, len)
* set for tftpd(8) to allow clients to read the file.
*/
-int chk_access(path, filesize)
-char *path;
-long *filesize;
+PRIVATE int
+chk_access(path, filesize)
+ char *path;
+ int32 *filesize;
{
- struct stat buf;
-
- if ((stat(path, &buf) == 0) && (buf.st_mode & (S_IREAD >> 6))) {
- *filesize = (long) buf.st_size;
- return 0;
- } else {
- return -1;
- }
-}
+ struct stat st;
+ if ((stat(path, &st) == 0) && (st.st_mode & (S_IREAD >> 6))) {
+ *filesize = (int32) st.st_size;
+ return 0;
+ } else {
+ return -1;
+ }
+}
-#ifdef DEBUG
-
/*
- * Dump the internal memory database to bootpd_dump.
+ * Now in dumptab.c :
+ * dumptab()
+ * dump_host()
+ * list_ipaddresses()
*/
-dumptab()
-{
- int n;
- struct host *hp;
- FILE *fp;
- long t;
-
- /*
- * Open bootpd.dump file.
- */
- if ((fp = fopen(bootpd_dump, "w")) == NULL) {
- report(LOG_ERR, "error opening \"%s\": %s\n", bootpd_dump,
- get_errmsg());
- exit(1);
- }
-
- t = time(NULL);
- fprintf(fp, "\n# %s\n", Version);
- fprintf(fp, "# %s: dump of bootp server database.\n", bootpd_dump);
- fprintf(fp, "#\n# Dump taken %s", ctime(&t));
- fprintf(fp, "#\n#\n# Legend:\n");
- fprintf(fp, "#\tbf -- bootfile\n");
- fprintf(fp, "#\tbs -- bootfile size in 512-octet blocks\n");
- fprintf(fp, "#\tcs -- cookie servers\n");
- fprintf(fp, "#\tdf -- dump file name\n");
- fprintf(fp, "#\tdn -- domain name\n");
- fprintf(fp, "#\tds -- domain name servers\n");
- fprintf(fp, "#\tgw -- gateways\n");
- fprintf(fp, "#\tha -- hardware address\n");
- fprintf(fp, "#\thd -- home directory for bootfiles\n");
- fprintf(fp, "#\tht -- hardware type\n");
- fprintf(fp, "#\tim -- impress servers\n");
- fprintf(fp, "#\tip -- host IP address\n");
- fprintf(fp, "#\tlg -- log servers\n");
- fprintf(fp, "#\tlp -- LPR servers\n");
- fprintf(fp, "#\tns -- IEN-116 name servers\n");
- fprintf(fp, "#\trl -- resource location protocol servers\n");
- fprintf(fp, "#\trp -- root path\n");
- fprintf(fp, "#\tsm -- subnet mask\n");
- fprintf(fp, "#\tsw -- swap server\n");
- fprintf(fp, "#\tto -- time offset (seconds)\n");
- fprintf(fp, "#\tts -- time servers\n\n\n");
-
- n = 0;
- for (hp = (struct host *) hash_FirstEntry(nmhashtable); hp != NULL;
- hp = (struct host *) hash_NextEntry(nmhashtable)) {
- dump_host(fp, hp);
- fprintf(fp, "\n");
- n++;
- }
- fclose(fp);
-
- report(LOG_INFO, "dumped %d entries to \"%s\".\n", n, bootpd_dump);
-}
-
-
+#ifdef VEND_CMU
/*
- * Dump all the available information on the host pointed to by "hp".
- * The output is sent to the file pointed to by "fp".
+ * Insert the CMU "vendor" data for the host pointed to by "hp" into the
+ * bootp packet pointed to by "bp".
*/
-void dump_host(fp, hp)
-FILE *fp;
-struct host *hp;
+PRIVATE void
+dovend_cmu(bp, hp)
+ struct bootp *bp;
+ struct host *hp;
{
- int i;
- byte *dataptr;
+ struct cmu_vend *vendp;
+ struct in_addr_list *taddr;
- if (hp) {
- if (hp->hostname) {
- fprintf(fp, "%s:", hp->hostname->string);
- }
- if (hp->flags.bootfile) {
- fprintf(fp, "bf=%s:", hp->bootfile->string);
- }
- if (hp->flags.bootsize) {
- fprintf(fp, "bs=");
- if (hp->flags.bootsize_auto) {
- fprintf(fp, "auto:");
- } else {
- fprintf(fp, "%d:", hp->bootsize);
- }
- }
- if (hp->flags.cookie_server) {
- fprintf(fp, "cs=");
- list_ipaddresses(fp, hp->cookie_server);
- fprintf(fp, ":");
+ /*
+ * Initialize the entire vendor field to zeroes.
+ */
+ bzero(bp->bp_vend, sizeof(bp->bp_vend));
+
+ /*
+ * Fill in vendor information. Subnet mask, default gateway,
+ * domain name server, ien name server, time server
+ */
+ vendp = (struct cmu_vend *) bp->bp_vend;
+ strcpy(vendp->v_magic, (char *)vm_cmu);
+ if (hp->flags.subnet_mask) {
+ (vendp->v_smask).s_addr = hp->subnet_mask.s_addr;
+ (vendp->v_flags) |= VF_SMASK;
+ if (hp->flags.gateway) {
+ (vendp->v_dgate).s_addr = hp->gateway->addr->s_addr;
+ }
}
if (hp->flags.domain_server) {
- fprintf(fp, "ds=");
- list_ipaddresses(fp, hp->domain_server);
- fprintf(fp, ":");
- }
- if (hp->flags.gateway) {
- fprintf(fp, "gw=");
- list_ipaddresses(fp, hp->gateway);
- fprintf(fp, ":");
- }
- if (hp->flags.homedir) {
- fprintf(fp, "hd=%s:", hp->homedir->string);
- }
- if (hp->flags.name_switch && hp->flags.send_name) {
- fprintf(fp, "hn:");
- }
- if (hp->flags.htype) {
- fprintf(fp, "ht=%u:", (unsigned) hp->htype);
- if (hp->flags.haddr) {
- fprintf(fp, "ha=%s:", haddrtoa(hp->haddr, hp->htype));
- }
- }
- if (hp->flags.impress_server) {
- fprintf(fp, "im=");
- list_ipaddresses(fp, hp->impress_server);
- fprintf(fp, ":");
- }
- if (hp->flags.swap_server) {
- fprintf(fp, "sw=%s:", inet_ntoa(hp->subnet_mask));
- }
- if (hp->flags.iaddr) {
- fprintf(fp, "ip=%s:", inet_ntoa(hp->iaddr));
- }
- if (hp->flags.log_server) {
- fprintf(fp, "lg=");
- list_ipaddresses(fp, hp->log_server);
- fprintf(fp, ":");
- }
- if (hp->flags.lpr_server) {
- fprintf(fp, "lp=");
- list_ipaddresses(fp, hp->lpr_server);
- fprintf(fp, ":");
+ taddr = hp->domain_server;
+ if (taddr->addrcount > 0) {
+ (vendp->v_dns1).s_addr = (taddr->addr)[0].s_addr;
+ if (taddr->addrcount > 1) {
+ (vendp->v_dns2).s_addr = (taddr->addr)[1].s_addr;
+ }
+ }
}
if (hp->flags.name_server) {
- fprintf(fp, "ns=");
- list_ipaddresses(fp, hp->name_server);
- fprintf(fp, ":");
- }
- if (hp->flags.rlp_server) {
- fprintf(fp, "rl=");
- list_ipaddresses(fp, hp->rlp_server);
- fprintf(fp, ":");
- }
- if (hp->flags.bootserver) {
- fprintf(fp, "sa=%s:", inet_ntoa(hp->bootserver));
- }
- if (hp->flags.subnet_mask) {
- fprintf(fp, "sm=%s:", inet_ntoa(hp->subnet_mask));
- }
- if (hp->flags.tftpdir) {
- fprintf(fp, "td=%s:", hp->tftpdir->string);
- }
- if (hp->flags.rootpath) {
- fprintf(fp, "rp=%s:", hp->rootpath->string);
- }
- if (hp->flags.domainname) {
- fprintf(fp, "dn=%s:", hp->domainname->string);
- }
- if (hp->flags.dumpfile) {
- fprintf(fp, "df=%s:", hp->dumpfile->string);
- }
- if (hp->flags.time_offset) {
- if (hp->flags.timeoff_auto) {
- fprintf(fp, "to=auto:");
- } else {
- fprintf(fp, "to=%ld:", hp->time_offset);
- }
+ taddr = hp->name_server;
+ if (taddr->addrcount > 0) {
+ (vendp->v_ins1).s_addr = (taddr->addr)[0].s_addr;
+ if (taddr->addrcount > 1) {
+ (vendp->v_ins2).s_addr = (taddr->addr)[1].s_addr;
+ }
+ }
}
if (hp->flags.time_server) {
- fprintf(fp, "ts=");
- list_ipaddresses(fp, hp->time_server);
- fprintf(fp, ":");
- }
- if (hp->flags.vendor_magic) {
- fprintf(fp, "vm=");
- if (hp->flags.vm_auto) {
- fprintf(fp, "auto:");
- } else if (!bcmp(hp->vm_cookie, vm_cmu, 4)) {
- fprintf(fp, "cmu:");
- } else if (!bcmp(hp->vm_cookie, vm_rfc1048, 4)) {
- fprintf(fp, "rfc1048");
- } else {
- fprintf(fp, "%d.%d.%d.%d:",
- (int) ((hp->vm_cookie)[0]),
- (int) ((hp->vm_cookie)[1]),
- (int) ((hp->vm_cookie)[2]),
- (int) ((hp->vm_cookie)[3]));
- }
- }
- if (hp->flags.generic) {
- fprintf(fp, "generic=");
- dataptr = hp->generic->data;
- for (i = hp->generic->length; i > 0; i--) {
- fprintf(fp, "%02X", (int) *dataptr++);
- }
- fprintf(fp, ":");
- }
- }
-}
-
-
-
-/*
- * Dump an entire struct in_addr_list of IP addresses to the indicated file.
- *
- * The addresses are printed in standard ASCII "dot" notation and separated
- * from one another by a single space. A single leading space is also
- * printed before the first adddress.
- *
- * Null lists produce no output (and no error).
- */
-
-void list_ipaddresses(fp, ipptr)
- FILE *fp;
- struct in_addr_list *ipptr;
-{
- unsigned count;
- struct in_addr *addrptr;
-
- if (ipptr) {
- count = ipptr->addrcount;
- addrptr = ipptr->addr;
- if (count-- > 0) {
- fprintf(fp, "%s", inet_ntoa(*addrptr++));
- while (count-- > 0) {
- fprintf(fp, " %s", inet_ntoa(*addrptr++));
- }
+ taddr = hp->time_server;
+ if (taddr->addrcount > 0) {
+ (vendp->v_ts1).s_addr = (taddr->addr)[0].s_addr;
+ if (taddr->addrcount > 1) {
+ (vendp->v_ts2).s_addr = (taddr->addr)[1].s_addr;
+ }
+ }
}
- }
-}
-#endif /* DEBUG */
+ /* Log message now done by caller. */
+} /* dovend_cmu */
+#endif /* VEND_CMU */
-#ifdef VEND_CMU
/*
- * Insert the CMU "vendor" data for the host pointed to by "hp" into the
+ * Insert the RFC1048 vendor data for the host pointed to by "hp" into the
* bootp packet pointed to by "bp".
*/
-
-void dovend_cmu(bp, hp)
- struct bootp *bp;
- struct host *hp;
+#define NEED(LEN, MSG) do \
+ if (bytesleft < (LEN)) { \
+ report(LOG_NOTICE, noroom, \
+ hp->hostname->string, MSG); \
+ return; \
+ } while (0)
+PRIVATE void
+dovend_rfc1048(bp, hp, bootsize)
+ struct bootp *bp;
+ struct host *hp;
+ int32 bootsize;
{
- struct cmu_vend *vendp;
- struct in_addr_list *taddr;
-
- /*
- * Initialize the entire vendor field to zeroes.
- */
- bzero(bp->bp_vend, sizeof(bp->bp_vend));
-
- /*
- * Fill in vendor information. Subnet mask, default gateway,
- * domain name server, ien name server, time server
- */
- vendp = (struct cmu_vend *) bp->bp_vend;
- if (hp->flags.subnet_mask) {
- (vendp->v_smask).s_addr = hp->subnet_mask.s_addr;
- (vendp->v_flags) |= VF_SMASK;
- if (hp->flags.gateway) {
- (vendp->v_dgate).s_addr = hp->gateway->addr->s_addr;
- }
- }
- if (hp->flags.domain_server) {
- taddr = hp->domain_server;
- if (taddr->addrcount > 0) {
- (vendp->v_dns1).s_addr = (taddr->addr)[0].s_addr;
- if (taddr->addrcount > 1) {
- (vendp->v_dns2).s_addr = (taddr->addr)[1].s_addr;
- }
- }
- }
- if (hp->flags.name_server) {
- taddr = hp->name_server;
- if (taddr->addrcount > 0) {
- (vendp->v_ins1).s_addr = (taddr->addr)[0].s_addr;
- if (taddr->addrcount > 1) {
- (vendp->v_ins2).s_addr = (taddr->addr)[1].s_addr;
- }
- }
- }
- if (hp->flags.time_server) {
- taddr = hp->time_server;
- if (taddr->addrcount > 0) {
- (vendp->v_ts1).s_addr = (taddr->addr)[0].s_addr;
- if (taddr->addrcount > 1) {
- (vendp->v_ts2).s_addr = (taddr->addr)[1].s_addr;
- }
- }
- }
- strcpy(vendp->v_magic, vm_cmu);
-
- if (debug > 1) {
- report(LOG_INFO, "sending CMU-style reply\n");
- }
-}
+ int bytesleft, len;
+ byte *vp;
+ char *tmpstr;
-#endif /* VEND_CMU */
-
-
+ static char noroom[] = "%s: No room for \"%s\" option";
-/*
- * Insert the RFC1048 vendor data for the host pointed to by "hp" into the
- * bootp packet pointed to by "bp".
- */
+ vp = bp->bp_vend;
+ bytesleft = sizeof(bp->bp_vend); /* Initial vendor area size */
+ bcopy(vm_rfc1048, vp, 4); /* Copy in the magic cookie */
+ vp += 4;
+ bytesleft -= 4;
-void dovend_rfc1048(bp, hp, bootsize)
- struct bootp *bp;
- struct host *hp;
- long bootsize;
-{
- int bytesleft, len;
- byte *vp;
- char *tmpstr;
-
- vp = bp->bp_vend;
- bytesleft = sizeof(bp->bp_vend); /* Initial vendor area size */
- bcopy(vm_rfc1048, vp, 4); /* Copy in the magic cookie */
- vp += 4;
- bytesleft -= 4;
-
- if (hp->flags.time_offset) {
- *vp++ = TAG_TIME_OFFSET; /* -1 byte */
- *vp++ = 4; /* -1 byte */
- if (hp->flags.timeoff_auto) {
- insert_u_long(htonl(secondswest), &vp);
- } else {
- insert_u_long(htonl(hp->time_offset), &vp); /* -4 bytes */
- }
- bytesleft -= 6;
- }
- if (hp->flags.subnet_mask) {
- *vp++ = TAG_SUBNET_MASK; /* -1 byte */
- *vp++ = 4; /* -1 byte */
- insert_u_long(hp->subnet_mask.s_addr, &vp); /* -4 bytes */
- bytesleft -= 6; /* Fix real count */
- if (hp->flags.gateway) {
- insert_ip(TAG_GATEWAY, hp->gateway, &vp, &bytesleft);
- }
- }
- if (hp->flags.bootsize) {
- bootsize = (hp->flags.bootsize_auto) ?
- ((bootsize + 511) / 512) : (hp->bootsize); /* Round up */
- *vp++ = TAG_BOOTSIZE;
- *vp++ = 2;
- *vp++ = (byte) ((bootsize >> 8) & 0xFF);
- *vp++ = (byte) (bootsize & 0xFF);
- bytesleft -= 4; /* Tag, length, and 16 bit blocksize */
- }
- if (hp->flags.swap_server) {
- *vp++ = TAG_SWAPSERVER; /* -1 byte */
- *vp++ = 4; /* -1 byte */
- insert_u_long(hp->swapserver.s_addr, &vp); /* -4 bytes */
- bytesleft -= 6; /* Fix real count */
- }
- if (hp->flags.rootpath) {
- /*
- * Check for room for rootpath. Add 2 to account for
- * TAG_ROOTPATH and length.
- */
- len = strlen(hp->rootpath->string);
- if ((len + 2) <= bytesleft) {
- *vp++ = TAG_ROOTPATH;
- *vp++ = (byte) (len & 0xFF);
- bcopy(hp->rootpath->string, vp, len);
- vp += len;
- bytesleft -= len + 2;
- }
- }
- if (hp->flags.dumpfile) {
- /*
- * Check for room for dumpfile. Add 2 to account for
- * TAG_DUMPFILE and length.
- */
- len = strlen(hp->dumpfile->string);
- if ((len + 2) <= bytesleft) {
- *vp++ = TAG_DUMPFILE;
- *vp++ = (byte) (len & 0xFF);
- bcopy(hp->dumpfile->string, vp, len);
- vp += len;
- bytesleft -= len + 2;
+ if (hp->flags.subnet_mask) {
+ /* always enough room here. */
+ *vp++ = TAG_SUBNET_MASK;/* -1 byte */
+ *vp++ = 4; /* -1 byte */
+ insert_u_long(hp->subnet_mask.s_addr, &vp); /* -4 bytes */
+ bytesleft -= 6; /* Fix real count */
+ if (hp->flags.gateway) {
+ (void) insert_ip(TAG_GATEWAY,
+ hp->gateway,
+ &vp, &bytesleft);
+ }
}
- }
- if (hp->flags.domain_server) {
- insert_ip(TAG_DOMAIN_SERVER, hp->domain_server, &vp, &bytesleft);
- }
- if (hp->flags.domainname) {
- /*
- * Check for room for domainname. Add 2 to account for
- * TAG_DOMAINNAME and length.
- */
- len = strlen(hp->domainname->string);
- if ((len + 2) <= bytesleft) {
- *vp++ = TAG_DOMAINNAME;
- *vp++ = (byte) (len & 0xFF);
- bcopy(hp->domainname->string, vp, len);
- vp += len;
- bytesleft -= len + 2;
+ if (hp->flags.bootsize) {
+ /* always enough room here */
+ bootsize = (hp->flags.bootsize_auto) ?
+ ((bootsize + 511) / 512) : (hp->bootsize); /* Round up */
+ *vp++ = TAG_BOOT_SIZE;
+ *vp++ = 2;
+ *vp++ = (byte) ((bootsize >> 8) & 0xFF);
+ *vp++ = (byte) (bootsize & 0xFF);
+ bytesleft -= 4; /* Tag, length, and 16 bit blocksize */
}
- }
- if (hp->flags.name_server) {
- insert_ip(TAG_NAME_SERVER, hp->name_server, &vp, &bytesleft);
- }
- if (hp->flags.rlp_server) {
- insert_ip(TAG_RLP_SERVER, hp->rlp_server, &vp, &bytesleft);
- }
- if (hp->flags.time_server) {
- insert_ip(TAG_TIME_SERVER, hp->time_server, &vp, &bytesleft);
- }
- if (hp->flags.lpr_server) {
- insert_ip(TAG_LPR_SERVER, hp->lpr_server, &vp, &bytesleft);
- }
- if (hp->flags.name_switch && hp->flags.send_name) {
/*
- * Check for room for hostname. Add 2 to account for
- * TAG_HOSTNAME and length.
+ * This one is special: Remaining options go in the ext file.
+ * Only the subnet_mask, bootsize, and gateway should precede.
*/
- len = strlen(hp->hostname->string);
- if ((len + 2) > bytesleft) {
- /*
- * Not enough room for full (domain-qualified) hostname, try
- * stripping it down to just the first field (host).
- */
- tmpstr = hp->hostname->string;
- len = 0;
- while (*tmpstr && (*tmpstr != '.')) {
- tmpstr++;
- len++;
- }
- }
- if ((len + 2) <= bytesleft) {
- *vp++ = TAG_HOSTNAME;
- *vp++ = (byte) (len & 0xFF);
- bcopy(hp->hostname->string, vp, len);
- vp += len;
- bytesleft -= len + 2;
+ if (hp->flags.exten_file) {
+ /*
+ * Check for room for exten_file. Add 3 to account for
+ * TAG_EXTEN_FILE, length, and TAG_END.
+ */
+ len = strlen(hp->exten_file->string);
+ NEED((len + 3), "ef");
+ *vp++ = TAG_EXTEN_FILE;
+ *vp++ = (byte) (len & 0xFF);
+ bcopy(hp->exten_file->string, vp, len);
+ vp += len;
+ *vp++ = TAG_END;
+ bytesleft -= len + 3;
+ return; /* no more options here. */
}
- }
- if (hp->flags.cookie_server) {
- insert_ip(TAG_COOKIE_SERVER, hp->cookie_server, &vp, &bytesleft);
- }
- if (hp->flags.log_server) {
- insert_ip(TAG_LOG_SERVER, hp->log_server, &vp, &bytesleft);
- }
-
- if (hp->flags.generic) {
- insert_generic(hp->generic, &vp, &bytesleft);
- }
-
- if (bytesleft >= 1) {
- *vp++ = TAG_END;
- bytesleft--;
- }
-
- if (debug > 1) {
- report(LOG_INFO, "sending RFC1048-style reply\n");
- }
-
- if (bytesleft > 0) {
/*
- * Zero out any remaining part of the vendor area.
+ * The remaining options are inserted by the following
+ * function (which is shared with bootpef.c).
+ * Keep back one byte for the TAG_END.
*/
- bzero(vp, bytesleft);
- }
-}
+ len = dovend_rfc1497(hp, vp, bytesleft - 1);
+ vp += len;
+ bytesleft -= len;
-
-
-/*
- * Compare function to determine whether two hardware addresses are
- * equivalent. Returns TRUE if "host1" and "host2" are equivalent, FALSE
- * otherwise.
- *
- * This function is used when retrieving elements from the hardware address
- * hash table.
- */
-
-boolean hwlookcmp(host1, host2)
- struct host *host1, *host2;
-{
- if (host1->htype != host2->htype) {
- return FALSE;
- }
- if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
- return FALSE;
- }
- return TRUE;
-}
-
-
-
-
-/*
- * Compare function for doing IP address hash table lookup.
- */
-
-boolean iplookcmp(host1, host2)
- struct host *host1, *host2;
-{
- return (host1->iaddr.s_addr == host2->iaddr.s_addr);
-}
-
-
-
-/*
- * Insert a tag value, a length value, and a list of IP addresses into the
- * memory buffer indirectly pointed to by "dest". "tag" is the RFC1048 tag
- * number to use, "iplist" is a pointer to a list of IP addresses
- * (struct in_addr_list), and "bytesleft" points to an integer which
- * indicates the size of the "dest" buffer. The number of IP addresses
- * actually inserted
- *
- * This is used to fill the vendor-specific area of a bootp packet in
- * conformance to RFC1048.
- */
-
-void insert_ip(tag, iplist, dest, bytesleft)
- byte tag;
- struct in_addr_list *iplist;
- byte **dest;
- int *bytesleft;
-{
- struct in_addr *addrptr;
- unsigned addrcount;
- byte *d;
-
- if (iplist && (*bytesleft >= 6)) {
- d = *dest; /* Save pointer for later */
- **dest = tag;
- (*dest) += 2;
- (*bytesleft) -= 2; /* Account for tag and length */
- addrptr = iplist->addr;
- addrcount = iplist->addrcount;
- while ((*bytesleft >= 4) && (addrcount > 0)) {
- insert_u_long(addrptr->s_addr, dest);
- addrptr++;
- addrcount--;
- (*bytesleft) -= 4; /* Four bytes per address */
- }
- d[1] = (byte) ((*dest - d - 2) & 0xFF);
- }
-}
-
-
-
-/*
- * Insert generic data into a bootp packet. The data is assumed to already
- * be in RFC1048 format. It is inserted using a first-fit algorithm which
- * attempts to insert as many tags as possible. Tags and data which are
- * too large to fit are skipped; any remaining tags are tried until they
- * have all been exhausted.
- */
+ /* There should be at least one byte left. */
+ NEED(1, "(end)");
+ *vp++ = TAG_END;
+ bytesleft--;
-void insert_generic(gendata, buff, bytesleft)
- struct shared_bindata *gendata;
- byte **buff;
- int *bytesleft;
-{
- byte *srcptr;
- int length, numbytes;
-
- if (gendata) {
- srcptr = gendata->data;
- length = gendata->length;
- while ((length > 0) && (*bytesleft > 0)) {
- switch (*srcptr) {
- case TAG_END:
- length = 0; /* Force an exit on next iteration */
- break;
- case TAG_PAD:
- *(*buff)++ = *srcptr++;
- (*bytesleft)--;
- length--;
- break;
- default:
- numbytes = srcptr[1] + 2;
- if (*bytesleft >= numbytes) {
- bcopy(srcptr, *buff, numbytes);
- (*buff) += numbytes;
- (*bytesleft) -= numbytes;
- }
- srcptr += numbytes;
- length -= numbytes;
- break;
- }
+ /* Log message done by caller. */
+ if (bytesleft > 0) {
+ /*
+ * Zero out any remaining part of the vendor area.
+ */
+ bzero(vp, bytesleft);
}
- }
-}
-
-
+} /* dovend_rfc1048 */
+#undef NEED
/*
- * Convert a hardware address to an ASCII string.
+ * Now in readfile.c:
+ * hwlookcmp()
+ * iplookcmp()
*/
-char *haddrtoa(haddr, htype)
- byte *haddr;
- byte htype;
-{
- static char haddrbuf[2 * MAXHADDRLEN + 1];
- char *bufptr;
- unsigned count;
-
- bufptr = haddrbuf;
- for (count = haddrlength(htype); count > 0; count--) {
- sprintf(bufptr, "%02X", (unsigned) (*haddr++ & 0xFF));
- bufptr += 2;
- }
- return (haddrbuf);
-}
-
-
-
+/* haddrtoa() - now in hwaddr.c */
/*
- * Insert the unsigned long "value" into memory starting at the byte
- * pointed to by the byte pointer (*dest). (*dest) is updated to
- * point to the next available byte.
- *
- * Since it is desirable to internally store network addresses in network
- * byte order (in struct in_addr's), this routine expects longs to be
- * passed in network byte order.
- *
- * However, due to the nature of the main algorithm, the long must be in
- * host byte order, thus necessitating the use of ntohl() first.
+ * Now in dovend.c:
+ * insert_ip()
+ * insert_generic()
+ * insert_u_long()
*/
-void insert_u_long(value, dest)
- unsigned long value;
- byte **dest;
-{
- byte *temp;
- int n;
-
- value = ntohl(value); /* Must use host byte order here */
- temp = (*dest += 4);
- for (n = 4; n > 0; n--) {
- *--temp = (byte) (value & 0xFF);
- value >>= 8;
- }
- /* Final result is network byte order */
-}
-
-
+/* get_errmsg() - now in report.c */
/*
- * Return pointer to static string which gives full filesystem error message.
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
*/
-
-char *get_errmsg()
-{
- static char errmsg[80];
-
- if (errno < sys_nerr) {
- return sys_errlist[errno];
- } else {
- sprintf(errmsg, "Error %d", errno);
- return errmsg;
- }
-}
-
-
-
-/*
- * This routine reports errors and such via stderr and syslog() if
- * appopriate. It just helps avoid a lot of "#ifdef SYSLOG" constructs
- * from being scattered throughout the code.
- *
- * The syntax is identical to syslog(3), but %m is not considered special
- * for output to stderr (i.e. you'll see "%m" in the output. . .). Also,
- * control strings should normally end with \n since newlines aren't
- * automatically generated for stderr output (whereas syslog strips out all
- * newlines and adds its own at the end).
- */
-
-/*VARARGS2*/
-void report(priority, fmt, p0, p1, p2, p3, p4)
- int priority;
- char *fmt;
-{
-#ifdef LOG_SALERT
- static char *levelnames[] = {
- "unknown level: ",
- "alert(1): ",
- "subalert(2): ",
- "emergency(3): ",
- "error(4): ",
- "critical(5): ",
- "warning(6): ",
- "notice(7): ",
- "information(8):",
- "debug(9): ",
- "unknown level: "
- };
-#else
- static char *levelnames[] = {
- "emergency(0): ",
- "alert(1): ",
- "critical(2): ",
- "error(3): ",
- "warning(4): ",
- "notice(5): ",
- "information(6):",
- "debug(7): ",
- "unknown level: "
- };
-#endif
-
- if ((priority < 0) || (priority >= sizeof(levelnames)/sizeof(char *))) {
- priority = sizeof(levelnames) / sizeof(char *) - 1;
- }
-
- /*
- * Print the message
- */
- if (debug > 2) {
- fprintf(stderr, "bootpd: %s ", levelnames[priority]);
- fprintf(stderr, fmt, p0, p1, p2, p3, p4);
- }
-#ifdef SYSLOG
- syslog(priority, fmt, p0, p1, p2, p3, p4);
-#endif
-}
diff --git a/libexec/bootpd/bootpd.h b/libexec/bootpd/bootpd.h
index 94fb86e855f..716204a10d4 100644
--- a/libexec/bootpd/bootpd.h
+++ b/libexec/bootpd/bootpd.h
@@ -1,5 +1,3 @@
-#ifndef _BLURB_
-#define _BLURB_
/************************************************************************
Copyright 1988, 1991 by Carnegie Mellon University
@@ -21,13 +19,15 @@ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
************************************************************************/
-#endif /* _BLURB_ */
/*
* bootpd.h -- common header file for all the modules of the bootpd program.
*/
+#include "bptypes.h"
+#include "hash.h"
+#include "hwaddr.h"
#ifndef TRUE
#define TRUE 1
@@ -44,17 +44,8 @@ SOFTWARE.
#define SIGUSR1 30 /* From 4.3 <signal.h> */
#endif
-#define MAXHTYPES 7 /* Number of htypes defined */
-#define MAXHADDRLEN 6 /* Max hw address length in bytes */
#define MAXSTRINGLEN 80 /* Max string length */
-/*
- * Return the length in bytes of a hardware address of the given type.
- * Return the canonical name of the network of the given type.
- */
-#define haddrlength(type) ((hwinfolist[(int) (type)]).hlen)
-#define netname(type) ((hwinfolist[(int) (type)]).name)
-
/*
* Return pointer to static string which gives full network error message.
@@ -63,59 +54,13 @@ SOFTWARE.
/*
- * Variables shared among modules.
- */
-
-extern int debug;
-extern char *bootptab;
-
-extern struct hwinfo hwinfolist[];
-
-extern hash_tbl *hwhashtable;
-extern hash_tbl *iphashtable;
-extern hash_tbl *nmhashtable;
-extern unsigned char vm_cmu[4];
-extern unsigned char vm_rfc1048[4];
-
-
-/*
- * Functions shared among modules
- */
-
-extern void report();
-extern char *get_errmsg();
-extern char *haddrtoa();
-extern int readtab();
-
-
-
-/*
- * Nice typedefs. . .
- */
-
-typedef int boolean;
-typedef unsigned char byte;
-
-
-/*
- * This structure holds information about a specific network type. The
- * length of the network hardware address is stored in "hlen".
- * The string pointed to by "name" is the cononical name of the network.
- */
-struct hwinfo {
- unsigned hlen;
- char *name;
-};
-
-
-/*
* Data structure used to hold an arbitrary-lengthed list of IP addresses.
* The list may be shared among multiple hosts by setting the linkcount
* appropriately.
*/
struct in_addr_list {
- unsigned linkcount, addrcount;
+ unsigned int linkcount, addrcount;
struct in_addr addr[1]; /* Dynamically extended */
};
@@ -126,12 +71,12 @@ struct in_addr_list {
*/
struct shared_string {
- unsigned linkcount;
+ unsigned int linkcount;
char string[1]; /* Dynamically extended */
};
struct shared_bindata {
- unsigned linkcount, length;
+ unsigned int linkcount, length;
byte data[1]; /* Dynamically extended */
};
@@ -165,14 +110,18 @@ struct flag {
subnet_mask :1,
tftpdir :1,
time_offset :1,
- timeoff_auto :1,
time_server :1,
- vendor_magic :1,
- dumpfile :1,
- domainname :1,
+ dump_file :1,
+ domain_name :1,
swap_server :1,
- rootpath :1,
- vm_auto :1;
+ root_path :1,
+ exten_file :1,
+ reply_addr :1,
+ nis_domain :1,
+ nis_server :1,
+ ntp_server :1,
+ /* XXX - Add new tags here */
+ vm_cookie :1;
};
@@ -197,6 +146,7 @@ struct flag {
*/
struct host {
+ unsigned linkcount; /* hash list inserts */
struct flag flags; /* ALL valid fields */
struct in_addr_list *cookie_server,
*domain_server,
@@ -206,23 +156,47 @@ struct host {
*lpr_server,
*name_server,
*rlp_server,
- *time_server;
+ *time_server,
+ *nis_server,
+ *ntp_server;
struct shared_string *bootfile,
*hostname,
- *domainname,
+ *domain_name,
*homedir,
*tftpdir,
- *dumpfile,
- *rootpath;
+ *dump_file,
+ *exten_file,
+ *root_path,
+ *nis_domain;
struct shared_bindata *generic;
byte vm_cookie[4],
htype, /* RFC826 says this should be 16-bits but
RFC951 only allocates 1 byte. . . */
haddr[MAXHADDRLEN];
- long time_offset;
+ int32 time_offset;
unsigned int bootsize;
struct in_addr bootserver,
iaddr,
- swapserver,
+ swap_server,
+ reply_addr,
subnet_mask;
+ /* XXX - Add new tags here (or above as appropriate) */
};
+
+
+
+/*
+ * Variables shared among modules.
+ */
+
+extern int debug;
+extern char *bootptab;
+extern char *progname;
+
+extern u_char vm_cmu[4];
+extern u_char vm_rfc1048[4];
+
+extern hash_tbl *hwhashtable;
+extern hash_tbl *iphashtable;
+extern hash_tbl *nmhashtable;
+
diff --git a/libexec/bootpd/bootpef.8 b/libexec/bootpd/bootpef.8
new file mode 100644
index 00000000000..0f0b1fc7b43
--- /dev/null
+++ b/libexec/bootpd/bootpef.8
@@ -0,0 +1,52 @@
+.\" bootpef.8
+.TH BOOTPEF 8 "4 Dec 1993" "MAINTENANCE COMMANDS"
+.SH NAME
+bootpef \- BOOTP Extension File compiler
+.SH SYNOPSIS
+.LP
+.B bootpef
+.RI [ "-c chdir" ]
+.RI [ "-d debug-level" ]
+.RI [ "-f config-file" ]
+.RI [ client-name " [...]]"
+.SH DESCRIPTION
+.B bootpef
+builds the
+.I Extension Path
+files described by RFC 1497 (tag 18).
+If any
+.I client-name
+arguments are specified, then
+.I bootpef
+compiles the extension files for only those clients.
+.SH OPTIONS
+.TP
+.BI \-c \ chdir\-path
+Sets the current directory used by
+.I bootpef
+while creating extension files. This is useful when the
+extension file names are specified as relative pathnames, and
+.I bootpef
+needs to use the same current directory as the TFTP server
+(typically /tftpboot).
+.TP
+.BI \-d \ debug\-level
+Sets the
+.I debug\-level
+variable that controls the amount of debugging messages generated.
+For example, -d4 or -d 4 will set the debugging level to 4.
+.TP
+.BI \-f \ config\-file
+Set the name of the config file that specifies the option
+data to be sent to each client.
+.SH "SEE ALSO"
+bootpd(8), tftpd(8)
+.SH REFERENCES
+.TP
+RFC951
+BOOTSTRAP PROTOCOL (BOOTP)
+.TP
+RFC1497
+BOOTP Vendor Information Extensions
+
+
diff --git a/libexec/bootpd/bootpef.c b/libexec/bootpd/bootpef.c
new file mode 100644
index 00000000000..e035ef24231
--- /dev/null
+++ b/libexec/bootpd/bootpef.c
@@ -0,0 +1,347 @@
+/************************************************************************
+ Copyright 1988, 1991 by Carnegie Mellon University
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted, provided
+that the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of Carnegie Mellon University not be used
+in advertising or publicity pertaining to distribution of the software
+without specific, written prior permission.
+
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+************************************************************************/
+
+#ifndef lint
+static char rcsid[] = "$Header: /cvsroot/src/libexec/bootpd/Attic/bootpef.c,v 1.1 1994/05/24 15:20:16 gwr Exp $";
+#endif
+
+
+/*
+ * bootpef - BOOTP Extension File generator
+ * Makes an "Extension File" for each host entry that
+ * defines an and Extension File. (See RFC1497, tag 18.)
+ *
+ * HISTORY
+ * See ./Changes
+ *
+ * BUGS
+ * See ./ToDo
+ */
+
+
+
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h> /* inet_ntoa */
+
+#ifndef NO_UNISTD
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <syslog.h>
+
+#ifndef USE_BFUNCS
+#include <memory.h>
+/* Yes, memcpy is OK here (no overlapped copies). */
+#define bcopy(a,b,c) memcpy(b,a,c)
+#define bzero(p,l) memset(p,0,l)
+#define bcmp(a,b,c) memcmp(a,b,c)
+#endif
+
+#include "bootp.h"
+#include "hash.h"
+#include "hwaddr.h"
+#include "bootpd.h"
+#include "dovend.h"
+#include "readfile.h"
+#include "report.h"
+#include "tzone.h"
+#include "patchlevel.h"
+
+#define BUFFERSIZE 0x4000
+
+#ifndef CONFIG_FILE
+#define CONFIG_FILE "/etc/bootptab"
+#endif
+
+
+
+/*
+ * Externals, forward declarations, and global variables
+ */
+
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+static void dovend_rfc1048 P((struct bootp *, struct host *, int32));
+static void mktagfile P((struct host *));
+static void usage P((void));
+
+#undef P
+
+
+/*
+ * General
+ */
+
+char *progname;
+char *chdir_path;
+int debug = 0; /* Debugging flag (level) */
+byte *buffer;
+
+/*
+ * Globals below are associated with the bootp database file (bootptab).
+ */
+
+char *bootptab = CONFIG_FILE;
+
+
+/*
+ * Print "usage" message and exit
+ */
+static void
+usage()
+{
+ fprintf(stderr,
+ "usage: $s [ -c chdir ] [-d level] [-f configfile] [host...]\n");
+ fprintf(stderr, "\t -c n\tset current directory\n");
+ fprintf(stderr, "\t -d n\tset debug level\n");
+ fprintf(stderr, "\t -f n\tconfig file name\n");
+ exit(1);
+}
+
+
+/*
+ * Initialization such as command-line processing is done and then the
+ * main server loop is started.
+ */
+void
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ struct host *hp;
+ char *stmp;
+ int n;
+
+ progname = strrchr(argv[0], '/');
+ if (progname) progname++;
+ else progname = argv[0];
+
+ /* Get work space for making tag 18 files. */
+ buffer = (byte *) malloc(BUFFERSIZE);
+ if (!buffer) {
+ report(LOG_ERR, "malloc failed");
+ exit(1);
+ }
+ /*
+ * Set defaults that might be changed by option switches.
+ */
+ stmp = NULL;
+
+ /*
+ * Read switches.
+ */
+ for (argc--, argv++; argc > 0; argc--, argv++) {
+ if (argv[0][0] != '-')
+ break;
+ switch (argv[0][1]) {
+
+ case 'c': /* chdir_path */
+ if (argv[0][2]) {
+ stmp = &(argv[0][2]);
+ } else {
+ argc--;
+ argv++;
+ stmp = argv[0];
+ }
+ if (!stmp || (stmp[0] != '/')) {
+ fprintf(stderr,
+ "bootpd: invalid chdir specification\n");
+ break;
+ }
+ chdir_path = stmp;
+ break;
+
+ case 'd': /* debug */
+ if (argv[0][2]) {
+ stmp = &(argv[0][2]);
+ } else if (argv[1] && argv[1][0] == '-') {
+ /*
+ * Backwards-compatible behavior:
+ * no parameter, so just increment the debug flag.
+ */
+ debug++;
+ break;
+ } else {
+ argc--;
+ argv++;
+ stmp = argv[0];
+ }
+ if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
+ fprintf(stderr,
+ "bootpd: invalid debug level\n");
+ break;
+ }
+ debug = n;
+ break;
+
+ case 'f': /* config file */
+ if (argv[0][2]) {
+ stmp = &(argv[0][2]);
+ } else {
+ argc--;
+ argv++;
+ stmp = argv[0];
+ }
+ bootptab = stmp;
+ break;
+
+ default:
+ fprintf(stderr, "bootpd: unknown switch: -%c\n",
+ argv[0][1]);
+ usage();
+ break;
+ }
+ }
+
+ /* Get the timezone. */
+ tzone_init();
+
+ /* Allocate hash tables. */
+ rdtab_init();
+
+ /*
+ * Read the bootptab file.
+ */
+ readtab(1); /* force read */
+
+ /* Set the cwd (i.e. to /tftpboot) */
+ if (chdir_path) {
+ if (chdir(chdir_path) < 0)
+ report(LOG_ERR, "%s: chdir failed", chdir_path);
+ }
+ /* If there are host names on the command line, do only those. */
+ if (argc > 0) {
+ unsigned int tlen, hashcode;
+
+ while (argc) {
+ tlen = strlen(argv[0]);
+ hashcode = hash_HashFunction((u_char *)argv[0], tlen);
+ hp = (struct host *) hash_Lookup(nmhashtable,
+ hashcode,
+ nmcmp, argv[0]);
+ if (!hp) {
+ printf("%s: no matching entry\n", argv[0]);
+ exit(1);
+ }
+ if (!hp->flags.exten_file) {
+ printf("%s: no extension file\n", argv[0]);
+ exit(1);
+ }
+ mktagfile(hp);
+ argv++;
+ argc--;
+ }
+ exit(0);
+ }
+ /* No host names specified. Do them all. */
+ hp = (struct host *) hash_FirstEntry(nmhashtable);
+ while (hp != NULL) {
+ mktagfile(hp);
+ hp = (struct host *) hash_NextEntry(nmhashtable);
+ }
+}
+
+
+
+/*
+ * Make a "TAG 18" file for this host.
+ * (Insert the RFC1497 options.)
+ */
+
+static void
+mktagfile(hp)
+ struct host *hp;
+{
+ FILE *fp;
+ int bytesleft, len;
+ byte *vp;
+ char *tmpstr;
+
+ if (!hp->flags.exten_file)
+ return;
+
+ vp = buffer;
+ bytesleft = BUFFERSIZE;
+ bcopy(vm_rfc1048, vp, 4); /* Copy in the magic cookie */
+ vp += 4;
+ bytesleft -= 4;
+
+ /*
+ * The "extension file" options are appended by the following
+ * function (which is shared with bootpd.c).
+ */
+ len = dovend_rfc1497(hp, vp, bytesleft);
+ vp += len;
+ bytesleft -= len;
+
+ if (bytesleft < 1) {
+ report(LOG_ERR, "%s: too much option data",
+ hp->exten_file->string);
+ return;
+ }
+ *vp++ = TAG_END;
+ bytesleft--;
+
+ /* Write the buffer to the extension file. */
+ printf("Updating \"%s\"\n", hp->exten_file->string);
+ if ((fp = fopen(hp->exten_file->string, "w")) == NULL) {
+ report(LOG_ERR, "error opening \"%s\": %s",
+ hp->exten_file->string, get_errmsg());
+ return;
+ }
+ len = vp - buffer;
+ if (len != fwrite(buffer, 1, len, fp)) {
+ report(LOG_ERR, "write failed on \"%s\" : %s",
+ hp->exten_file->string, get_errmsg());
+ }
+ fclose(fp);
+
+} /* dovend_rfc1048 */
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/libexec/bootpd/bootpgw.c b/libexec/bootpd/bootpgw.c
new file mode 100644
index 00000000000..cdf11244dae
--- /dev/null
+++ b/libexec/bootpd/bootpgw.c
@@ -0,0 +1,675 @@
+/*
+ * bootpgw.c - BOOTP GateWay
+ * This program forwards BOOTP Request packets to a BOOTP server.
+ */
+
+/************************************************************************
+ Copyright 1988, 1991 by Carnegie Mellon University
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted, provided
+that the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of Carnegie Mellon University not be used
+in advertising or publicity pertaining to distribution of the software
+without specific, written prior permission.
+
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+************************************************************************/
+
+#ifndef lint
+static char rcsid[] = "$Header: /cvsroot/src/libexec/bootpd/Attic/bootpgw.c,v 1.1 1994/05/24 15:20:18 gwr Exp $";
+#endif
+
+/*
+ * BOOTPGW is typically used to forward BOOTP client requests from
+ * one subnet to a BOOTP server on a different subnet.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h> /* inet_ntoa */
+
+#ifndef NO_UNISTD
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <syslog.h>
+#include <assert.h>
+
+#ifdef NO_SETSID
+# include <fcntl.h> /* for O_RDONLY, etc */
+#endif
+
+#ifndef USE_BFUNCS
+# include <memory.h>
+/* Yes, memcpy is OK here (no overlapped copies). */
+# define bcopy(a,b,c) memcpy(b,a,c)
+# define bzero(p,l) memset(p,0,l)
+# define bcmp(a,b,c) memcmp(a,b,c)
+#endif
+
+#include "bootp.h"
+#include "getif.h"
+#include "hwaddr.h"
+#include "report.h"
+#include "patchlevel.h"
+
+/* Local definitions: */
+#define MAXPKT (3*512) /* Maximum packet size */
+#define TRUE 1
+#define FALSE 0
+#define get_network_errmsg get_errmsg
+
+
+
+/*
+ * Externals, forward declarations, and global variables
+ */
+
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+static void usage P((void));
+static void handle_reply P((void));
+static void handle_request P((void));
+
+#undef P
+
+/*
+ * IP port numbers for client and server obtained from /etc/services
+ */
+
+u_short bootps_port, bootpc_port;
+
+
+/*
+ * Internet socket and interface config structures
+ */
+
+struct sockaddr_in bind_addr; /* Listening */
+struct sockaddr_in recv_addr; /* Packet source */
+struct sockaddr_in send_addr; /* destination */
+
+
+/*
+ * option defaults
+ */
+int debug = 0; /* Debugging flag (level) */
+struct timeval actualtimeout =
+{ /* fifteen minutes */
+ 15 * 60L, /* tv_sec */
+ 0 /* tv_usec */
+};
+u_int maxhops = 4; /* Number of hops allowed for requests. */
+u_int minwait = 3; /* Number of seconds client must wait before
+ its bootrequest packets are forwarded. */
+
+/*
+ * General
+ */
+
+int s; /* Socket file descriptor */
+char *pktbuf; /* Receive packet buffer */
+int pktlen;
+char *progname;
+char *servername;
+int32 server_ipa; /* Real server IP address, network order. */
+
+char myhostname[64];
+struct in_addr my_ip_addr;
+
+
+
+
+/*
+ * Initialization such as command-line processing is done and then the
+ * main server loop is started.
+ */
+
+void
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ struct timeval *timeout;
+ struct bootp *bp;
+ struct servent *servp;
+ struct hostent *hep;
+ char *stmp;
+ int n, ba_len, ra_len;
+ int nfound, readfds;
+ int standalone;
+
+ progname = strrchr(argv[0], '/');
+ if (progname) progname++;
+ else progname = argv[0];
+
+ /*
+ * Initialize logging.
+ */
+ report_init(0); /* uses progname */
+
+ /*
+ * Log startup
+ */
+ report(LOG_INFO, "version %s.%d", VERSION, PATCHLEVEL);
+
+ /* Debugging for compilers with struct padding. */
+ assert(sizeof(struct bootp) == BP_MINPKTSZ);
+
+ /* Get space for receiving packets and composing replies. */
+ pktbuf = malloc(MAXPKT);
+ if (!pktbuf) {
+ report(LOG_ERR, "malloc failed");
+ exit(1);
+ }
+ bp = (struct bootp *) pktbuf;
+
+ /*
+ * Check to see if a socket was passed to us from inetd.
+ *
+ * Use getsockname() to determine if descriptor 0 is indeed a socket
+ * (and thus we are probably a child of inetd) or if it is instead
+ * something else and we are running standalone.
+ */
+ s = 0;
+ ba_len = sizeof(bind_addr);
+ bzero((char *) &bind_addr, ba_len);
+ errno = 0;
+ standalone = TRUE;
+ if (getsockname(s, (struct sockaddr *) &bind_addr, &ba_len) == 0) {
+ /*
+ * Descriptor 0 is a socket. Assume we are a child of inetd.
+ */
+ if (bind_addr.sin_family == AF_INET) {
+ standalone = FALSE;
+ bootps_port = ntohs(bind_addr.sin_port);
+ } else {
+ /* Some other type of socket? */
+ report(LOG_INFO, "getsockname: not an INET socket");
+ }
+ }
+ /*
+ * Set defaults that might be changed by option switches.
+ */
+ stmp = NULL;
+ timeout = &actualtimeout;
+ gethostname(myhostname, sizeof(myhostname));
+ hep = gethostbyname(myhostname);
+ if (!hep) {
+ printf("Can not get my IP address\n");
+ exit(1);
+ }
+ bcopy(hep->h_addr, (char *)&my_ip_addr, sizeof(my_ip_addr));
+
+ /*
+ * Read switches.
+ */
+ for (argc--, argv++; argc > 0; argc--, argv++) {
+ if (argv[0][0] != '-')
+ break;
+ switch (argv[0][1]) {
+
+ case 'd': /* debug level */
+ if (argv[0][2]) {
+ stmp = &(argv[0][2]);
+ } else if (argv[1] && argv[1][0] == '-') {
+ /*
+ * Backwards-compatible behavior:
+ * no parameter, so just increment the debug flag.
+ */
+ debug++;
+ break;
+ } else {
+ argc--;
+ argv++;
+ stmp = argv[0];
+ }
+ if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
+ fprintf(stderr,
+ "%s: invalid debug level\n", progname);
+ break;
+ }
+ debug = n;
+ break;
+
+ case 'h': /* hop count limit */
+ if (argv[0][2]) {
+ stmp = &(argv[0][2]);
+ } else {
+ argc--;
+ argv++;
+ stmp = argv[0];
+ }
+ if (!stmp || (sscanf(stmp, "%d", &n) != 1) ||
+ (n < 0) || (n > 16))
+ {
+ fprintf(stderr,
+ "bootpgw: invalid hop count limit\n");
+ break;
+ }
+ maxhops = (u_int)n;
+ break;
+
+ case 'i': /* inetd mode */
+ standalone = FALSE;
+ break;
+
+ case 's': /* standalone mode */
+ standalone = TRUE;
+ break;
+
+ case 't': /* timeout */
+ if (argv[0][2]) {
+ stmp = &(argv[0][2]);
+ } else {
+ argc--;
+ argv++;
+ stmp = argv[0];
+ }
+ if (!stmp || (sscanf(stmp, "%d", &n) != 1) || (n < 0)) {
+ fprintf(stderr,
+ "%s: invalid timeout specification\n", progname);
+ break;
+ }
+ actualtimeout.tv_sec = (int32) (60 * n);
+ /*
+ * If the actual timeout is zero, pass a NULL pointer
+ * to select so it blocks indefinitely, otherwise,
+ * point to the actual timeout value.
+ */
+ timeout = (n > 0) ? &actualtimeout : NULL;
+ break;
+
+ case 'w': /* wait time */
+ if (argv[0][2]) {
+ stmp = &(argv[0][2]);
+ } else {
+ argc--;
+ argv++;
+ stmp = argv[0];
+ }
+ if (!stmp || (sscanf(stmp, "%d", &n) != 1) ||
+ (n < 0) || (n > 60))
+ {
+ fprintf(stderr,
+ "bootpgw: invalid wait time\n");
+ break;
+ }
+ minwait = (u_int)n;
+ break;
+
+ default:
+ fprintf(stderr, "%s: unknown switch: -%c\n",
+ progname, argv[0][1]);
+ usage();
+ break;
+
+ } /* switch */
+ } /* for args */
+
+ /* Make sure server name argument is suplied. */
+ servername = argv[0];
+ if (!servername) {
+ fprintf(stderr, "bootpgw: missing server name\n");
+ usage();
+ }
+ /*
+ * Get address of real bootp server.
+ */
+ if (isdigit(servername[0]))
+ server_ipa = inet_addr(servername);
+ else {
+ hep = gethostbyname(servername);
+ if (!hep) {
+ fprintf(stderr, "bootpgw: can't get addr for %s\n", servername);
+ exit(1);
+ }
+ bcopy(hep->h_addr, (char *)&server_ipa, sizeof(server_ipa));
+ }
+
+ if (standalone) {
+ /*
+ * Go into background and disassociate from controlling terminal.
+ * XXX - This is not the POSIX way (Should use setsid). -gwr
+ */
+ if (debug < 3) {
+ if (fork())
+ exit(0);
+#ifdef NO_SETSID
+ setpgrp(0,0);
+#ifdef TIOCNOTTY
+ n = open("/dev/tty", O_RDWR);
+ if (n >= 0) {
+ ioctl(n, TIOCNOTTY, (char *) 0);
+ (void) close(n);
+ }
+#endif /* TIOCNOTTY */
+#else /* SETSID */
+ if (setsid() < 0)
+ perror("setsid");
+#endif /* SETSID */
+ } /* if debug < 3 */
+ /*
+ * Nuke any timeout value
+ */
+ timeout = NULL;
+
+ /*
+ * Here, bootpd would do:
+ * chdir
+ * tzone_init
+ * rdtab_init
+ * readtab
+ */
+
+ /*
+ * Create a socket.
+ */
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ report(LOG_ERR, "socket: %s", get_network_errmsg());
+ exit(1);
+ }
+ /*
+ * Get server's listening port number
+ */
+ servp = getservbyname("bootps", "udp");
+ if (servp) {
+ bootps_port = ntohs((u_short) servp->s_port);
+ } else {
+ bootps_port = (u_short) IPPORT_BOOTPS;
+ report(LOG_ERR,
+ "udp/bootps: unknown service -- assuming port %d",
+ bootps_port);
+ }
+
+ /*
+ * Bind socket to BOOTPS port.
+ */
+ bind_addr.sin_family = AF_INET;
+ bind_addr.sin_port = htons(bootps_port);
+ bind_addr.sin_addr.s_addr = INADDR_ANY;
+ if (bind(s, (struct sockaddr *) &bind_addr,
+ sizeof(bind_addr)) < 0)
+ {
+ report(LOG_ERR, "bind: %s", get_network_errmsg());
+ exit(1);
+ }
+ } /* if standalone */
+ /*
+ * Get destination port number so we can reply to client
+ */
+ servp = getservbyname("bootpc", "udp");
+ if (servp) {
+ bootpc_port = ntohs(servp->s_port);
+ } else {
+ report(LOG_ERR,
+ "udp/bootpc: unknown service -- assuming port %d",
+ IPPORT_BOOTPC);
+ bootpc_port = (u_short) IPPORT_BOOTPC;
+ }
+
+ /* no signal catchers */
+
+ /*
+ * Process incoming requests.
+ */
+ for (;;) {
+ readfds = 1 << s;
+ nfound = select(s + 1, (fd_set *)&readfds, NULL, NULL, timeout);
+ if (nfound < 0) {
+ if (errno != EINTR) {
+ report(LOG_ERR, "select: %s", get_errmsg());
+ }
+ continue;
+ }
+ if (!(readfds & (1 << s))) {
+ report(LOG_INFO, "exiting after %ld minutes of inactivity",
+ actualtimeout.tv_sec / 60);
+ exit(0);
+ }
+ ra_len = sizeof(recv_addr);
+ n = recvfrom(s, pktbuf, MAXPKT, 0,
+ (struct sockaddr *) &recv_addr, &ra_len);
+ if (n <= 0) {
+ continue;
+ }
+ if (debug > 3) {
+ report(LOG_INFO, "recvd pkt from IP addr %s",
+ inet_ntoa(recv_addr.sin_addr));
+ }
+ if (n < sizeof(struct bootp)) {
+ if (debug) {
+ report(LOG_INFO, "received short packet");
+ }
+ continue;
+ }
+ pktlen = n;
+
+ switch (bp->bp_op) {
+ case BOOTREQUEST:
+ handle_request();
+ break;
+ case BOOTREPLY:
+ handle_reply();
+ break;
+ }
+ }
+}
+
+
+
+
+/*
+ * Print "usage" message and exit
+ */
+
+static void
+usage()
+{
+ fprintf(stderr,
+ "usage: bootpgw [-d level] [-i] [-s] [-t timeout] server\n");
+ fprintf(stderr, "\t -d n\tset debug level\n");
+ fprintf(stderr, "\t -h n\tset max hop count\n");
+ fprintf(stderr, "\t -i\tforce inetd mode (run as child of inetd)\n");
+ fprintf(stderr, "\t -s\tforce standalone mode (run without inetd)\n");
+ fprintf(stderr, "\t -t n\tset inetd exit timeout to n minutes\n");
+ fprintf(stderr, "\t -w n\tset min wait time (secs)\n");
+ exit(1);
+}
+
+
+
+/*
+ * Process BOOTREQUEST packet.
+ *
+ * Note, this just forwards the request to a real server.
+ */
+static void
+handle_request()
+{
+ struct bootp *bp = (struct bootp *) pktbuf;
+ struct ifreq *ifr;
+ u_short secs, hops;
+
+ /* XXX - SLIP init: Set bp_ciaddr = recv_addr here? */
+
+ if (debug) {
+ report(LOG_INFO, "request from %s",
+ inet_ntoa(recv_addr.sin_addr));
+ }
+ /* Has the client been waiting long enough? */
+ secs = ntohs(bp->bp_secs);
+ if (secs < minwait)
+ return;
+
+ /* Has this packet hopped too many times? */
+ hops = ntohs(bp->bp_hops);
+ if (++hops > maxhops) {
+ report(LOG_NOTICE, "reqest from %s reached hop limit",
+ inet_ntoa(recv_addr.sin_addr));
+ return;
+ }
+ bp->bp_hops = htons(hops);
+
+ /*
+ * Here one might discard a request from the same subnet as the
+ * real server, but we can assume that the real server will send
+ * a reply to the client before it waits for minwait seconds.
+ */
+
+ /* If gateway address is not set, put in local interface addr. */
+ if (bp->bp_giaddr.s_addr == 0) {
+#if 0 /* BUG */
+ struct sockaddr_in *sip;
+ /*
+ * XXX - This picks the wrong interface when the receive addr
+ * is the broadcast address. There is no portable way to
+ * find out which interface a broadcast was received on. -gwr
+ * (Thanks to <walker@zk3.dec.com> for finding this bug!)
+ */
+ ifr = getif(s, &recv_addr.sin_addr);
+ if (!ifr) {
+ report(LOG_NOTICE, "no interface for request from %s",
+ inet_ntoa(recv_addr.sin_addr));
+ return;
+ }
+ sip = (struct sockaddr_in *) &(ifr->ifr_addr);
+ bp->bp_giaddr = sip->sin_addr;
+#else /* BUG */
+ /*
+ * XXX - Just set "giaddr" to our "official" IP address.
+ * RFC 1532 says giaddr MUST be set to the address of the
+ * interface on which the request was received. Setting
+ * it to our "default" IP address is not strictly correct,
+ * but is good enough to allow the real BOOTP server to
+ * get the reply back here. Then, before we forward the
+ * reply to the client, the giaddr field is corrected.
+ * (In case the client uses giaddr, which it should not.)
+ * See handle_reply()
+ */
+ bp->bp_giaddr = my_ip_addr;
+#endif /* BUG */
+
+ /*
+ * XXX - DHCP says to insert a subnet mask option into the
+ * options area of the request (if vendor magic == std).
+ */
+ }
+ /* Set up socket address for send. */
+ send_addr.sin_family = AF_INET;
+ send_addr.sin_port = htons(bootps_port);
+ send_addr.sin_addr.s_addr = server_ipa;
+
+ /* Send reply with same size packet as request used. */
+ if (sendto(s, pktbuf, pktlen, 0,
+ (struct sockaddr *) &send_addr,
+ sizeof(send_addr)) < 0)
+ {
+ report(LOG_ERR, "sendto: %s", get_network_errmsg());
+ }
+}
+
+
+
+/*
+ * Process BOOTREPLY packet.
+ */
+static void
+handle_reply()
+{
+ struct bootp *bp = (struct bootp *) pktbuf;
+ struct ifreq *ifr;
+ struct sockaddr_in *sip;
+ u_char canon_haddr[MAXHADDRLEN];
+ unsigned char *ha;
+ int len;
+
+ if (debug) {
+ report(LOG_INFO, " reply for %s",
+ inet_ntoa(bp->bp_yiaddr));
+ }
+ /* Make sure client is directly accessible. */
+ ifr = getif(s, &(bp->bp_yiaddr));
+ if (!ifr) {
+ report(LOG_NOTICE, "no interface for reply to %s",
+ inet_ntoa(bp->bp_yiaddr));
+ return;
+ }
+#if 1 /* Experimental (see BUG above) */
+/* #ifdef CATER_TO_OLD_CLIENTS ? */
+ /*
+ * The giaddr field has been set to our "default" IP address
+ * which might not be on the same interface as the client.
+ * In case the client looks at giaddr, (which it should not)
+ * giaddr is now set to the address of the correct interface.
+ */
+ sip = (struct sockaddr_in *) &(ifr->ifr_addr);
+ bp->bp_giaddr = sip->sin_addr;
+#endif
+
+ /* Set up socket address for send to client. */
+ send_addr.sin_family = AF_INET;
+ send_addr.sin_addr = bp->bp_yiaddr;
+ send_addr.sin_port = htons(bootpc_port);
+
+ /* Create an ARP cache entry for the client. */
+ ha = bp->bp_chaddr;
+ len = bp->bp_hlen;
+ if (len > MAXHADDRLEN)
+ len = MAXHADDRLEN;
+ if (bp->bp_htype == HTYPE_IEEE802) {
+ haddr_conv802(ha, canon_haddr, len);
+ ha = canon_haddr;
+ }
+ if (debug > 1)
+ report(LOG_INFO, "setarp %s - %s",
+ inet_ntoa(bp->bp_yiaddr), haddrtoa(ha, len));
+ setarp(s, &bp->bp_yiaddr, ha, len);
+
+ /* Send reply with same size packet as request used. */
+ if (sendto(s, pktbuf, pktlen, 0,
+ (struct sockaddr *) &send_addr,
+ sizeof(send_addr)) < 0)
+ {
+ report(LOG_ERR, "sendto: %s", get_network_errmsg());
+ }
+}
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/libexec/bootpd/bootptab.5 b/libexec/bootpd/bootptab.5
index 39f51216578..9ccd6cbf6c9 100644
--- a/libexec/bootpd/bootptab.5
+++ b/libexec/bootpd/bootptab.5
@@ -1,6 +1,6 @@
.\" Copyright (c) 1988, 1989, 1991 Carnegie Mellon University
.\"
-.\" $Header: /cvsroot/src/libexec/bootpd/Attic/bootptab.5,v 1.1 1994/04/18 05:15:58 glass Exp $
+.\" $Header: /cvsroot/src/libexec/bootpd/Attic/bootptab.5,v 1.2 1994/05/24 15:20:19 gwr Exp $
.\"
.TH BOOTPTAB 5 "October 31, 1991" "Carnegie Mellon University"
.UC 6
@@ -23,9 +23,13 @@ colons (:), with a general format of:
.PP
where
.I hostname
-is the actual name of a bootp client and
+is the actual name of a bootp client (or a "dummy entry"), and
.I tg
-is a two-character tag symbol. Most tags must be followed by an equals-sign
+is a two-character tag symbol. Dummy entries have an invalid hostname
+(one with a "." as the first character) and are used to provide
+default values used by other entries via the
+.B tc=.dummy-entry
+mechanism. Most tags must be followed by an equals-sign
and a value as above. Some may also appear in a boolean form with no
value (i.e.
.RI : tg :).
@@ -44,6 +48,8 @@ The currently recognized tags are:
.br
ds Domain name server address list
.br
+ ef Extension file
+.br
gw Gateway address list
.br
ha Host hardware address
@@ -64,6 +70,10 @@ The currently recognized tags are:
.br
ns IEN-116 name server address list
.br
+ nt NTP (time) Server (RFC 1129)
+.br
+ ra Reply address override
+.br
rl Resource location protocol server address list
.br
rp Root path to mount as root
@@ -83,6 +93,10 @@ The currently recognized tags are:
ts Time server address list
.br
vm Vendor magic cookie selector
+.br
+ yd YP (NIS) domain name
+.br
+ ys YP (NIS) server address
.PP
There is also a generic tag,
@@ -105,6 +119,8 @@ The following tags take a whitespace-separated list of IP addresses:
.BR lg ,
.BR lp ,
.BR ns ,
+.BR nt ,
+.BR ra ,
.BR rl ,
and
.BR ts .
@@ -112,12 +128,22 @@ The
.BR ip ,
.BR sa ,
.BR sw ,
+.BR sm ,
and
-.B sm
+.B ys
tags each take a single IP address.
-All IP addresses are specified in standard Internet "dot" notation and may use
-decimal, octal, or hexadecimal numbers (octal numbers begin with 0,
-hexadecimal numbers begin with '0x' or '0X').
+All IP addresses are specified in standard Internet "dot" notation
+and may use decimal, octal, or hexadecimal numbers
+(octal numbers begin with 0, hexadecimal numbers begin with '0x' or '0X').
+Any IP addresses may alternatively be specified as a hostname, causing
+.I bootpd
+to lookup the IP address for that host name using gethostbyname(3).
+If the
+.B ip
+tag is not specified,
+.I bootpd
+will determine the IP address using the entry name as the host name.
+(Dummy entries use an invalid host name to avoid automatic IP lookup.)
.PP
The
.B ht
@@ -145,7 +171,8 @@ or
for Chaos, ARCNET, and AX.25 Amateur Radio networks, respectively.
The
.B ha
-tag takes a hardware address which
+tag takes a hardware address which may be specified as a host name
+or in numeric form. Note that the numeric form
.I must
be specified in hexadecimal; optional periods and/or a leading '0x' may be
included for readability. The
@@ -155,6 +182,10 @@ tag must be preceded by the
tag (either explicitly or implicitly; see
.B tc
below).
+If the hardware address is not specified and the type is specified
+as either "ethernet" or "ieee802", then
+.I bootpd
+will try to determine the hardware address using ether_hton(3).
.PP
The hostname, home directory, and bootfile are ASCII strings which may be
optionally surrounded by double quotes ("). The client's request and the
@@ -165,42 +196,18 @@ and
symbols determine how the server fills in the bootfile field of the bootp
reply packet.
.PP
-If the client specifies an absolute pathname and that file exists on the
-server machine, that pathname is returned in the reply packet. If the file
-cannot be found, the request is discarded; no reply is sent. If the client
-specifies a relative pathname, a full pathname is formed by prepending the
-value of the
-.B hd
-tag and testing for existence of the file. If the
-.B hd
-tag is not supplied in the configuration file or if the resulting boot file
-cannot be found, then the request is discarded.
-.PP
-Clients which specify null boot files will always elicit a reply from the
-server. The exact reply will again depend upon the
-.B hd
-and
+If the client provides a file name it is left as is.
+Otherwise, if the
.B bf
-tags. If the
-.B bf
-tag gives an absolute pathname and the file exists, that pathname is returned
-in the reply packet. Otherwise, if the
+option is specified its value is copied into the reply packet.
+If the
.B hd
-and
-.B bf
-tags together specify an accessible file, that filename is returned in the
-reply. If a complete filename cannot be determined or the file does not
-exist, the reply will contain a zeroed-out bootfile field.
-.PP
-In all these cases, existence of the file means that, in addition to actually
-being present, the file must have its public read access bit set, since this
-is required by
-.IR tftpd (8)
-to permit the file transfer. Also, all filenames are first tried as
-.I filename.hostname
-and then simply as
-.IR filename ,
-thus providing for individual per-host bootfiles.
+option is specified as well, its value is prepended to the
+boot file copied into the reply packet.
+The existence of the boot file is checked only if the
+.BR bs =auto
+option is used (to determine the boot file size).
+A reply may be sent whether or not the boot file exists.
.PP
Some newer versions of
.I tftpd
@@ -214,6 +221,9 @@ tag may be used to inform
.I bootpd
of this special root directory used by
.IR tftpd .
+(One may alternatively use the
+.I bootpd
+"-c chdir" option.)
The
.B hd
tag is actually relative to the root directory specified by the
@@ -343,57 +353,38 @@ An example
.I /etc/bootptab
file follows:
.PP
+.nf
+ # Sample bootptab file (domain=andrew.cmu.edu)
-.br
- # Sample bootptab file
-
-.br
- default1:\\
-.br
+ .default:\\
:hd=/usr/boot:bf=null:\\
-.br
- :ds=128.2.35.50 128.2.13.21:\\
-.br
- :ns=0x80020b4d 0x80020ffd:\\
-.br
- :ts=0x80020b4d 0x80020ffd:\\
-.br
- :sm=255.255.0.0:gw=0x8002fe24:\\
-.br
- :hn:vm=auto:to=-18000:\\
-.br
- :T37=0x12345927AD3BCF:T99="Special ASCII string":
+ :ds=netserver, lancaster:\\
+ :ns=pcs2, pcs1:\\
+ :ts=pcs2, pcs1:\\
+ :sm=255.255.255.0:\\
+ :gw=gw.cs.cmu.edu:\\
+ :hn:to=-18000:
-.br
- carnegie:ht=6:ha=7FF8100000AF:ip=128.2.11.1:tc=default1:
-.br
- baldwin:ht=1:ha=0800200159C3:ip=128.2.11.10:tc=default1:
-.br
- wylie:ht=1:ha=00DD00CADF00:ip=128.2.11.100:tc=default1:
-.br
- arnold:ht=1:ha=0800200102AD:ip=128.2.11.102:tc=default1:
-.br
- bairdford:ht=1:ha=08002B02A2F9:ip=128.2.11.103:tc=default1:
-.br
- bakerstown:ht=1:ha=08002B0287C8:ip=128.2.11.104:tc=default1:
-
-.br
- # Special domain name server for next host
-.br
- butlerjct:ht=1:ha=08002001560D:ip=128.2.11.108:ds=128.2.13.42:tc=default1:
+ carnegie:ht=6:ha=7FF8100000AF:tc=.default:
+ baldwin:ht=1:ha=0800200159C3:tc=.default:
+ wylie:ht=1:ha=00DD00CADF00:tc=.default:
+ arnold:ht=1:ha=0800200102AD:tc=.default:
+ bairdford:ht=1:ha=08002B02A2F9:tc=.default:
+ bakerstown:ht=1:ha=08002B0287C8:tc=.default:
-.br
- gastonville:ht=6:ha=7FFF81000A47:ip=128.2.11.115:tc=default1:
-.br
- hahntown:ht=6:ha=7FFF81000434:ip=128.2.11.117:tc=default1:
-.br
- hickman:ht=6:ha=7FFF810001BA:ip=128.2.11.118:tc=default1:
-.br
- lowber:ht=1:ha=00DD00CAF000:ip=128.2.11.121:tc=default1:
-.br
- mtoliver:ht=1:ha=00DD00FE1600:ip=128.2.11.122:tc=default1:
+ # Special domain name server and option tags for next host
+ butlerjct:ha=08002001560D:ds=128.2.13.42:\\
+ :T37=0x12345927AD3BCF:\\
+ :T99="Special ASCII string":\\
+ :tc=.default:
+ gastonville:ht=6:ha=7FFF81000A47:tc=.default:
+ hahntown:ht=6:ha=7FFF81000434:tc=.default:
+ hickman:ht=6:ha=7FFF810001BA:tc=.default:
+ lowber:ht=1:ha=00DD00CAF000:tc=.default:
+ mtoliver:ht=1:ha=00DD00FE1600:tc=.default:
+.fi
.SH FILES
/etc/bootptab
diff --git a/libexec/bootpd/bootptab.cmu b/libexec/bootpd/bootptab.cmu
new file mode 100644
index 00000000000..66212d421a2
--- /dev/null
+++ b/libexec/bootpd/bootptab.cmu
@@ -0,0 +1,124 @@
+# /etc/bootptab: database for bootp server (/etc/bootpd)
+# (I've hacked on this but can't test it... -gwr)
+
+# Blank lines and lines beginning with '#' are ignored.
+#
+# Legend: (see bootptab.5)
+# first field -- hostname (not indented)
+# bf -- bootfile
+# bs -- bootfile size in 512-octet blocks
+# cs -- cookie servers
+# df -- dump file name
+# dn -- domain name
+# ds -- domain name servers
+# ef -- extension file
+# gw -- gateways
+# ha -- hardware address
+# hd -- home directory for bootfiles
+# hn -- host name set for client
+# ht -- hardware type
+# im -- impress servers
+# ip -- host IP address
+# lg -- log servers
+# lp -- LPR servers
+# ns -- IEN-116 name servers
+# ra -- reply address
+# rl -- resource location protocol servers
+# rp -- root path
+# sa -- boot server address
+# sm -- subnet mask
+# sw -- swap server
+# tc -- template host (points to similar host entry)
+# td -- TFTP directory
+# to -- time offset (seconds)
+# ts -- time servers
+# vm -- vendor magic number
+# Tn -- generic option tag n
+#
+# Be careful about including backslashes where they're needed. Weird (bad)
+# things can happen when a backslash is omitted where one is intended.
+# Also, note that generic option data must be either a string or a
+# sequence of bytes where each byte is a two-digit hex value.
+
+# First, we define a global entry which specifies the stuff every host uses.
+# (Host name lookups are relative to the domain: andrew.cmu.edu)
+.default:\
+ :hn:dn=cmu.edu:\
+ :hd=/usr/boot:\
+ :ds=netserver, lancaster:\
+ :ns=pcs2, pcs1:\
+ :ts=pcs2, pcs1:\
+ :sm=255.255.0.0:\
+ :gw=gw.cs.cmu.edu:\
+ to=auto:
+
+
+# Next, we can define different master entries for each subnet. . .
+.subnet13 :sm=255.255.255.0:gw=128.2.13.1 :tc=.default:
+.subnet19 :sm=255.255.255.0:gw=128.2.19.1 :tc=.default:
+.subnet232 :sm=255.255.255.0:gw=128.2.232.1 :tc=.default:
+
+#
+# We should be able to use as many levels of indirection as desired. Use
+# your imagination. . .
+#
+
+
+# Individual entries (could also have different servers for some/all of these
+# hosts, but we don't really use this feature at CMU):
+
+carnegie:tc=.subnet13:ht=ieee802:ha=7FF8100000AF:
+baldwin:tc=.subnet19:ha=0800200159C3:
+wylie:tc=.subnet232:ha=00DD00CADF00:
+arnold:tc=.subnet19:ha=0800200102AD:
+bairdford:tc=.subnet19:ha=08002B02A2F9:
+bakerstown:tc=.subnet19:ha=08002B0287C8:
+butlerjct:tc=.subnet232:ha=08002001560D:
+gastonville:tc=.subnet232:ht=ieee802:ha=7FFF81000A47:
+hahntown:tc=.subnet13:ht=ieee802:ha=7FFF81000434:
+hickman:tc=.subnet19:ht=ieee802:ha=7FFF810001BA:
+lowber:tc=.subnet13:ha=00DD00CAF000:
+mtoliver:tc=.subnet19:ha=00DD00FE1600:
+osborne:tc=.subnet232:ha=00DD00CAD600:
+russelton:tc=.subnet232:ha=080020017FC3:
+thornburg:tc=.subnet13:ha=080020012A33:
+
+
+# Hmmm. . . Let's throw in some whitespace for readability. . . .
+
+andrew: tc=.subnet19:ha=00DD00C88900:
+birdville: tc=.subnet19:ha=00DD00FE2D00:
+coudersport: tc=.subnet13:ha=00DD00CB1E00:
+bridgeville: tc=.subnet232:ha=080020011394:
+franklin: tc=.subnet19:ha=08002B02A5D5:
+hollidaysburg: tc=.subnet19:ht=ieee802:ha=7FFF810002C8:
+honesdale: tc=.subnet19:ha=08002B02F83F:
+huntingdon: tc=.subnet19:ha=08002B02E410:
+indiana: tc=.subnet13:ha=08002B029BEC:
+jimthorpe: tc=.subnet232:ha=08002B02FBBA:
+kittanning: tc=.subnet232:ha=08002B0273FC:
+lebanon: tc=.subnet232:ha=08002B037F67:
+lewisburg: tc=.subnet19:ha=50005A1A0DE4:
+middleburg: tc=.subnet232:ha=00DD00FE1200:
+aspinwall: tc=.subnet13:ha=08002B03C163:
+berlin: tc=.subnet13:ha=00DD000A4400:
+norristown: tc=.subnet13:ha=08002001455B:
+pottsville: tc=.subnet13:ha=00DD000A3700:
+ridgway: tc=.subnet19:ha=08002B029425:
+scranton: tc=.subnet232:ha=0800200113A1:
+chalfont: tc=.subnet13:ha=08002001124B:
+washington: tc=.subnet19:ha=00DD00656E00:
+wellsboro: tc=.subnet13:ha=00DD00CB1C00:
+bb1: tc=.subnet19:ha=00DD000A1F00:
+adamstown: tc=.subnet13:ha=08002B02D0E6:
+beta: tc=.subnet19:ha=02070100B197:
+carbondale: tc=.subnet232:ha=08002B022A73:
+clairton: tc=.subnet19:ha=080020010FD1:
+egypt: tc=.subnet13:ha=00DD00847B00:
+fairchance: tc=.subnet232:ha=00DD000AB100:
+fairhope: tc=.subnet232:ha=00DD00CB0800:
+galeton: tc=.subnet232:ha=08002001138C:
+imperial: tc=.subnet232:ha=08002001130C:
+kingston: tc=.subnet232:ha=080020011382:
+knox: tc=.subnet232:ha=50005A1A0D2A:
+lakecity: tc=.subnet13:ha=080020011380:
diff --git a/libexec/bootpd/bootptab.mcs b/libexec/bootpd/bootptab.mcs
new file mode 100644
index 00000000000..c12ef71d6fd
--- /dev/null
+++ b/libexec/bootpd/bootptab.mcs
@@ -0,0 +1,93 @@
+# /etc/bootptab: database for bootp server (/etc/bootpd)
+# Last update: gwr, Sun Dec 12 19:00:00 EDT 1993
+# Blank lines and lines beginning with '#' are ignored.
+#
+# Legend: (see bootptab.5)
+# first field -- hostname (not indented)
+# bf -- bootfile
+# bs -- bootfile size in 512-octet blocks
+# cs -- cookie servers
+# df -- dump file name
+# dn -- domain name
+# ds -- domain name servers
+# ef -- extension file
+# gw -- gateways
+# ha -- hardware address
+# hd -- home directory for bootfiles
+# hn -- host name set for client
+# ht -- hardware type
+# im -- impress servers
+# ip -- host IP address
+# lg -- log servers
+# lp -- LPR servers
+# ns -- IEN-116 name servers
+# ra -- reply address
+# rl -- resource location protocol servers
+# rp -- root path
+# sa -- boot server address
+# sm -- subnet mask
+# sw -- swap server
+# tc -- template host (points to similar host entry)
+# td -- TFTP directory
+# to -- time offset (seconds)
+# ts -- time servers
+# vm -- vendor magic number
+# Tn -- generic option tag n
+#
+# Be careful about including backslashes where they're needed. Weird (bad)
+# things can happen when a backslash is omitted where one is intended.
+# Also, note that generic option data must be either a string or a
+# sequence of bytes where each byte is a two-digit hex value.
+
+# First, we define a global entry which specifies the stuff every host uses.
+
+# If you leave "td" and "hd" unset, run bootpd with the "-c /tftpboot"
+# switch so path names (boot files) will be interpreted relative to
+# the same directory as tftpd will use as its CWD.
+.default:\
+ :hn:dn="mc.com":\
+ :td=/tftpboot:\
+ :ds=merlin, jericho:\
+ :to=auto:
+
+# Next, we can define different master entries for each subnet. . .
+
+.subnet16:\
+ :tc=.default:\
+ :sm=255.255.255.0:\
+ :gw=merlin:\
+ :sa=merlin:
+
+.subnet17:\
+ :tc=.default:\
+ :sm=255.255.255.0:\
+ :gw=merlin-gw:\
+ :sa=merlin-gw:
+
+#
+# We should be able to use as many levels of indirection as desired. Use
+# your imagination. . .
+#
+
+# Individual entries (could also have different servers for some/all of these
+# hosts, but we don't really use this feature at CMU):
+
+# Emulex terminal server
+emulex: tc=.subnet16:ha=00.00.C9.00.42.E0:bf=P4KTL0E:
+
+# Lantronix eps1
+eps1: tc=.subnet16:ha=00.80.A3.04.1D.78:
+
+# Tadpole 885 board.
+tp885: tc=.subnet17:ha=08.00.4C.00.2F.74:bf=tp885sys2.cfe:
+
+# MVME147 VxWorks board.
+mvme147:tc=.subnet17:ha=08.00.3e.20.da.47:bf=mv147vxw.st:
+
+# These are just for testing
+
+walnut:tc=.subnet16:ha=walnut:sa=merlin-gw:\
+ :td@:hd=/export/walnut/:
+
+banana:tc=.subnet17:ha=banana:bf=boot.sun4c:
+thor:tc=.subnet17:ha=thor:bf=boot.sun4e:
diff --git a/libexec/bootpd/bootptest.8 b/libexec/bootpd/bootptest.8
new file mode 100644
index 00000000000..a564bcf0a33
--- /dev/null
+++ b/libexec/bootpd/bootptest.8
@@ -0,0 +1,56 @@
+.\" bootptest.8
+.TH BOOTPTEST 8 "10 June 1993" "MAINTENANCE COMMANDS"
+.SH NAME
+bootptest \- send BOOTP queries and print responses
+.SH SYNOPSIS
+.LP
+.B bootptest
+[
+.B \-h
+]
+.I server\-name
+.RI [ template-file ]
+.SH DESCRIPTION
+.B bootptest
+sends BOOTP requests to the host specified as
+.I server\-name
+at one\-second intervals until either a response is received,
+or until ten requests have gone unanswered.
+After a response is received,
+.B bootptest
+will wait one more second listening for additional responses.
+.SH OPTIONS
+.TP
+.B \-h
+Use the hardware (Ethernet) address to identify the client.
+By default, the IP address is copied into the request
+indicating that this client already knows its IP address.
+.LP
+A
+.I template-file
+may be specified, in which case
+.B bootptest
+uses the (binary) contents of this file to initialize the
+.I options
+area of the request packet.
+.SH CREDITS
+.LP
+The bootptest program is a combination of original and derived works.
+The main program module (bootptest.c) is original work by
+Gordon W. Ross <gwr@mc.com>.
+The packet printing module (print-bootp.c) is a slightly modified
+version of a file from the BSD tcpdump program.
+.LP
+This program includes software developed by the University of
+California, Lawrence Berkeley Laboratory and its contributors.
+(See the copyright notice in print-bootp.c)
+.SH "SEE ALSO"
+.LP
+bootpd(8)
+.SH REFERENCES
+.TP
+RFC951
+BOOTSTRAP PROTOCOL (BOOTP)
+.TP
+RFC1048
+BOOTP Vendor Information Extensions
diff --git a/libexec/bootpd/bootptest.c b/libexec/bootpd/bootptest.c
new file mode 100644
index 00000000000..b288641232e
--- /dev/null
+++ b/libexec/bootpd/bootptest.c
@@ -0,0 +1,484 @@
+/*
+ * bootptest.c - Test out a bootp server.
+ *
+ * This simple program was put together from pieces taken from
+ * various places, including the CMU BOOTP client and server.
+ * The packet printing routine is from the Berkeley "tcpdump"
+ * program with some enhancements I added. The print-bootp.c
+ * file is shared with my copy of "tcpdump" and therefore uses
+ * some unusual utility routines that would normally be provided
+ * by various parts of the tcpdump program.
+ *
+ * Boilerplate:
+ *
+ * This program includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory and its contributors.
+ * (See the copyright notice in print-bootp.c)
+ *
+ * The remainder of this program is public domain. You may do
+ * whatever you like with it except claim that you wrote it.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * HISTORY:
+ *
+ * 12/02/93 Released version 1.4 (with bootp-2.3.2)
+ * 11/05/93 Released version 1.3
+ * 10/14/93 Released version 1.2
+ * 10/11/93 Released version 1.1
+ * 09/28/93 Released version 1.0
+ * 09/93 Original developed by Gordon W. Ross <gwr@mc.com>
+ */
+
+char *usage = "bootptest [-h] server-name [vendor-data-template-file]";
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h> /* inet_ntoa */
+
+#include <stdlib.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <assert.h>
+
+#include "bootp.h"
+#include "bootptest.h"
+#include "getif.h"
+#include "patchlevel.h"
+
+#define LOG_ERR 1
+#define BUFLEN 1024
+#define WAITSECS 1
+#define MAXWAIT 10
+
+int vflag = 1;
+int tflag = 0;
+int thiszone;
+char *progname;
+unsigned char *packetp;
+unsigned char *snapend;
+int snaplen;
+
+
+/*
+ * IP port numbers for client and server obtained from /etc/services
+ */
+
+u_short bootps_port, bootpc_port;
+
+
+/*
+ * Internet socket and interface config structures
+ */
+
+struct sockaddr_in sin_server; /* where to send requests */
+struct sockaddr_in sin_client; /* for bind and listen */
+struct sockaddr_in sin_from; /* Packet source */
+u_char eaddr[16]; /* Ethernet address */
+
+/*
+ * General
+ */
+
+int debug = 1; /* Debugging flag (level) */
+char hostname[64];
+char *sndbuf; /* Send packet buffer */
+char *rcvbuf; /* Receive packet buffer */
+
+/*
+ * Vendor magic cookies for CMU and RFC1048
+ */
+
+unsigned char vm_cmu[4] = VM_CMU;
+unsigned char vm_rfc1048[4] = VM_RFC1048;
+short secs; /* How long client has waited */
+
+char *get_errmsg();
+extern void bootp_print();
+
+/*
+ * Initialization such as command-line processing is done, then
+ * the receiver loop is started. Die when interrupted.
+ */
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ struct bootp *bp;
+ struct servent *sep;
+ struct hostent *hep;
+
+ char *servername = NULL;
+ char *vendor_file = NULL;
+ char *bp_file = NULL;
+ int32 server_addr; /* inet addr, network order */
+ int s; /* Socket file descriptor */
+ int n, tolen, fromlen, recvcnt;
+ int use_hwa = 0;
+ int32 xid;
+
+ progname = strrchr(argv[0], '/');
+ if (progname)
+ progname++;
+ else
+ progname = argv[0];
+ argc--;
+ argv++;
+
+ if (debug)
+ printf("%s: version %s.%d\n", progname, VERSION, PATCHLEVEL);
+
+ /* Debugging for compilers with struct padding. */
+ assert(sizeof(struct bootp) == BP_MINPKTSZ);
+
+ sndbuf = malloc(BUFLEN);
+ rcvbuf = malloc(BUFLEN);
+ if (!sndbuf || !rcvbuf) {
+ printf("malloc failed\n");
+ exit(1);
+ }
+ /* Handle option switches. */
+ while (argc > 0) {
+ if (argv[0][0] != '-')
+ break;
+ switch (argv[0][1]) {
+
+ case 'f': /* File name to reqest. */
+ if (argc < 2)
+ goto error;
+ argc--; argv++;
+ bp_file = *argv;
+ break;
+
+ case 'h': /* Use hardware address. */
+ use_hwa = 1;
+ break;
+
+ error:
+ default:
+ puts(usage);
+ exit(1);
+
+ }
+ argc--;
+ argv++;
+ }
+
+ /* Get server name (or address) for query. */
+ if (argc > 0) {
+ servername = *argv;
+ argc--;
+ argv++;
+ }
+ /* Get optional vendor-data-template-file. */
+ if (argc > 0) {
+ vendor_file = *argv;
+ argc--;
+ argv++;
+ }
+ if (!servername) {
+ printf("missing server name.\n");
+ puts(usage);
+ exit(1);
+ }
+ /*
+ * Create a socket.
+ */
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ perror("socket");
+ exit(1);
+ }
+ /*
+ * Get server's listening port number
+ */
+ sep = getservbyname("bootps", "udp");
+ if (sep) {
+ bootps_port = ntohs((u_short) sep->s_port);
+ } else {
+ fprintf(stderr, "udp/bootps: unknown service -- using port %d\n",
+ IPPORT_BOOTPS);
+ bootps_port = (u_short) IPPORT_BOOTPS;
+ }
+
+ /*
+ * Set up server socket address (for send)
+ */
+ if (servername) {
+ if (isdigit(servername[0]))
+ server_addr = inet_addr(servername);
+ else {
+ hep = gethostbyname(servername);
+ if (!hep) {
+ fprintf(stderr, "%s: unknown host\n", servername);
+ exit(1);
+ }
+ bcopy(hep->h_addr, &server_addr, sizeof(server_addr));
+ }
+ } else {
+ /* Get broadcast address */
+ /* XXX - not yet */
+ server_addr = INADDR_ANY;
+ }
+ sin_server.sin_family = AF_INET;
+ sin_server.sin_port = htons(bootps_port);
+ sin_server.sin_addr.s_addr = server_addr;
+
+ /*
+ * Get client's listening port number
+ */
+ sep = getservbyname("bootpc", "udp");
+ if (sep) {
+ bootpc_port = ntohs(sep->s_port);
+ } else {
+ fprintf(stderr, "udp/bootpc: unknown service -- using port %d\n",
+ IPPORT_BOOTPC);
+ bootpc_port = (u_short) IPPORT_BOOTPC;
+ }
+
+ /*
+ * Set up client socket address (for listen)
+ */
+ sin_client.sin_family = AF_INET;
+ sin_client.sin_port = htons(bootpc_port);
+ sin_client.sin_addr.s_addr = INADDR_ANY;
+
+ /*
+ * Bind client socket to BOOTPC port.
+ */
+ if (bind(s, (struct sockaddr *) &sin_client, sizeof(sin_client)) < 0) {
+ perror("bind BOOTPC port");
+ if (errno == EACCES)
+ fprintf(stderr, "You need to run this as root\n");
+ exit(1);
+ }
+ /*
+ * Build a request.
+ */
+ bp = (struct bootp *) sndbuf;
+ bzero(bp, sizeof(*bp));
+ bp->bp_op = BOOTREQUEST;
+ xid = (int32) getpid();
+ bp->bp_xid = (u_int32) htonl(xid);
+ if (bp_file)
+ strncpy(bp->bp_file, bp_file, BP_FILE_LEN);
+
+ /*
+ * Fill in the hardware address (or client IP address)
+ */
+ if (use_hwa) {
+ struct ifreq *ifr;
+
+ ifr = getif(s, &sin_server.sin_addr);
+ if (!ifr) {
+ printf("No interface for %s\n", servername);
+ exit(1);
+ }
+ if (getether(ifr->ifr_name, eaddr)) {
+ printf("Can not get ether addr for %s\n", ifr->ifr_name);
+ exit(1);
+ }
+ /* Copy Ethernet address into request packet. */
+ bp->bp_htype = 1;
+ bp->bp_hlen = 6;
+ bcopy(eaddr, bp->bp_chaddr, bp->bp_hlen);
+ } else {
+ /* Fill in the client IP address. */
+ gethostname(hostname, sizeof(hostname));
+ hep = gethostbyname(hostname);
+ if (!hep) {
+ printf("Can not get my IP address\n");
+ exit(1);
+ }
+ bcopy(hep->h_addr, &bp->bp_ciaddr, hep->h_length);
+ }
+
+ /*
+ * Copy in the default vendor data.
+ */
+ bcopy(vm_rfc1048, bp->bp_vend, sizeof(vm_rfc1048));
+ bp->bp_vend[4] = TAG_END;
+
+ /*
+ * Read in the "options" part of the request.
+ * This also determines the size of the packet.
+ */
+ snaplen = sizeof(*bp);
+ if (vendor_file) {
+ int fd = open(vendor_file, 0);
+ if (fd < 0) {
+ perror(vendor_file);
+ exit(1);
+ }
+ /* Compute actual space for options. */
+ n = BUFLEN - sizeof(*bp) + BP_VEND_LEN;
+ n = read(fd, bp->bp_vend, n);
+ close(fd);
+ if (n < 0) {
+ perror(vendor_file);
+ exit(1);
+ }
+ printf("read %d bytes of vendor template\n", n);
+ if (n > BP_VEND_LEN) {
+ printf("warning: extended options in use (len > %d)\n",
+ BP_VEND_LEN);
+ snaplen += (n - BP_VEND_LEN);
+ }
+ }
+ /*
+ * Set globals needed by print_bootp
+ * (called by send_request)
+ */
+ packetp = (unsigned char *) eaddr;
+ snapend = (unsigned char *) sndbuf + snaplen;
+
+ /* Send a request once per second while waiting for replies. */
+ recvcnt = 0;
+ bp->bp_secs = secs = 0;
+ send_request(s);
+ while (1) {
+ struct timeval tv;
+ int readfds;
+
+ tv.tv_sec = WAITSECS;
+ tv.tv_usec = 0L;
+ readfds = (1 << s);
+ n = select(s + 1, (fd_set *) & readfds, NULL, NULL, &tv);
+ if (n < 0) {
+ perror("select");
+ break;
+ }
+ if (n == 0) {
+ /*
+ * We have not received a response since the last send.
+ * If we have ever received any responses, exit now.
+ * Otherwise, bump the "wait time" field and re-send.
+ */
+ if (recvcnt > 0)
+ exit(0);
+ secs += WAITSECS;
+ if (secs > MAXWAIT)
+ break;
+ bp->bp_secs = htons(secs);
+ send_request(s);
+ continue;
+ }
+ fromlen = sizeof(sin_from);
+ n = recvfrom(s, rcvbuf, BUFLEN, 0,
+ (struct sockaddr *) &sin_from, &fromlen);
+ if (n <= 0) {
+ continue;
+ }
+ if (n < sizeof(struct bootp)) {
+ printf("received short packet\n");
+ continue;
+ }
+ recvcnt++;
+
+ /* Print the received packet. */
+ printf("Recvd from %s", inet_ntoa(sin_from.sin_addr));
+ /* set globals needed by bootp_print() */
+ snaplen = n;
+ snapend = (unsigned char *) rcvbuf + snaplen;
+ bootp_print(rcvbuf, n, sin_from.sin_port, 0);
+ putchar('\n');
+ /*
+ * This no longer exits immediately after receiving
+ * one response because it is useful to know if the
+ * client might get multiple responses. This code
+ * will now listen for one second after a response.
+ */
+ }
+ fprintf(stderr, "no response from %s\n", servername);
+ exit(1);
+}
+
+send_request(s)
+ int s;
+{
+ /* Print the request packet. */
+ printf("Sending to %s", inet_ntoa(sin_server.sin_addr));
+ bootp_print(sndbuf, snaplen, sin_from.sin_port, 0);
+ putchar('\n');
+
+ /* Send the request packet. */
+ if (sendto(s, sndbuf, snaplen, 0,
+ (struct sockaddr *) &sin_server,
+ sizeof(sin_server)) < 0)
+ {
+ perror("sendto server");
+ exit(1);
+ }
+}
+
+/*
+ * Print out a filename (or other ascii string).
+ * Return true if truncated.
+ */
+int
+printfn(s, ep)
+ register u_char *s, *ep;
+{
+ register u_char c;
+
+ putchar('"');
+ while (c = *s++) {
+ if (s > ep) {
+ putchar('"');
+ return (1);
+ }
+ if (!isascii(c)) {
+ c = toascii(c);
+ putchar('M');
+ putchar('-');
+ }
+ if (!isprint(c)) {
+ c ^= 0x40; /* DEL to ?, others to alpha */
+ putchar('^');
+ }
+ putchar(c);
+ }
+ putchar('"');
+ return (0);
+}
+
+/*
+ * Convert an IP addr to a string.
+ * (like inet_ntoa, but ina is a pointer)
+ */
+char *
+ipaddr_string(ina)
+ struct in_addr *ina;
+{
+ static char b[24];
+ u_char *p;
+
+ p = (u_char *) ina;
+ sprintf(b, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
+ return (b);
+}
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/libexec/bootpd/bootptest.h b/libexec/bootpd/bootptest.h
new file mode 100644
index 00000000000..27f78ba963b
--- /dev/null
+++ b/libexec/bootpd/bootptest.h
@@ -0,0 +1,30 @@
+/* bootptest.h */
+/*
+ * Hacks for sharing print-bootp.c between tcpdump and bootptest.
+ */
+#define ESRC(p) (p)
+#define EDST(p) (p)
+
+#ifndef USE_BFUNCS
+/* Use mem/str functions */
+/* There are no overlapped copies, so memcpy is OK. */
+#define bcopy(a,b,c) memcpy(b,a,c)
+#define bzero(p,l) memset(p,0,l)
+#define bcmp(a,b,c) memcmp(a,b,c)
+#endif
+
+extern int vflag; /* verbose flag */
+
+/* global pointers to beginning and end of current packet (during printing) */
+extern unsigned char *packetp;
+extern unsigned char *snapend;
+
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+extern char *ipaddr_string P((struct in_addr *));
+
+#undef P
diff --git a/libexec/bootpd/bptypes.h b/libexec/bootpd/bptypes.h
new file mode 100644
index 00000000000..537da4e5e57
--- /dev/null
+++ b/libexec/bootpd/bptypes.h
@@ -0,0 +1,23 @@
+/* bptypes.h */
+
+#ifndef BPTYPES_H
+#define BPTYPES_H
+
+/*
+ * 32 bit integers are different types on various architectures
+ */
+
+#ifndef int32
+#define int32 long
+#endif
+typedef unsigned int32 u_int32;
+
+/*
+ * Nice typedefs. . .
+ */
+
+typedef int boolean;
+typedef unsigned char byte;
+
+
+#endif /* BPTYPES_H */
diff --git a/libexec/bootpd/dovend.c b/libexec/bootpd/dovend.c
new file mode 100644
index 00000000000..ba6ab288b8b
--- /dev/null
+++ b/libexec/bootpd/dovend.c
@@ -0,0 +1,413 @@
+/*
+ * dovend.c : Inserts all but the first few vendor options.
+ */
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h> /* inet_ntoa */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <syslog.h>
+
+#ifndef USE_BFUNCS
+# include <memory.h>
+/* Yes, memcpy is OK here (no overlapped copies). */
+# define bcopy(a,b,c) memcpy(b,a,c)
+# define bzero(p,l) memset(p,0,l)
+# define bcmp(a,b,c) memcmp(a,b,c)
+# define index strchr
+#endif
+
+#include "bootp.h"
+#include "bootpd.h"
+#include "report.h"
+#include "dovend.h"
+
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+PRIVATE int insert_generic P((struct shared_bindata *, byte **, int *));
+
+/*
+ * Insert the 2nd part of the options into an option buffer.
+ * Return amount of space used.
+ *
+ * This inserts everything EXCEPT:
+ * magic cookie, subnet mask, gateway, bootsize, extension file
+ * Those are handled separately (in bootpd.c) to allow this function
+ * to be shared between bootpd and bootpef.
+ *
+ * When an "extension file" is in use, the options inserted by
+ * this function go into the exten_file, not the bootp response.
+ */
+
+int
+dovend_rfc1497(hp, buf, len)
+ struct host *hp;
+ byte *buf;
+ int len;
+{
+ int bytesleft = len;
+ byte *vp = buf;
+ char *tmpstr;
+
+ static char noroom[] = "%s: No room for \"%s\" option";
+#define NEED(LEN, MSG) do \
+ if (bytesleft < (LEN)) { \
+ report(LOG_NOTICE, noroom, \
+ hp->hostname->string, MSG); \
+ return (vp - buf); \
+ } while (0)
+
+ /*
+ * Note that the following have already been inserted:
+ * magic_cookie, subnet_mask, gateway, bootsize
+ *
+ * The remaining options are inserted in order of importance.
+ * (Of course the importance of each is a matter of opinion.)
+ * The option insertion order should probably be configurable.
+ *
+ * This is the order used in the NetBSD version. Can anyone
+ * explain why the time_offset and swap_server are first?
+ * Also, why is the hostname so far down the list? -gwr
+ */
+
+ if (hp->flags.time_offset) {
+ NEED(6, "to");
+ *vp++ = TAG_TIME_OFFSET;/* -1 byte */
+ *vp++ = 4; /* -1 byte */
+ insert_u_long(htonl(hp->time_offset), &vp); /* -4 bytes */
+ bytesleft -= 6;
+ }
+ /*
+ * swap server, root path, dump path
+ */
+ if (hp->flags.swap_server) {
+ NEED(6, "sw");
+ /* There is just one SWAP_SERVER, so it is not an iplist. */
+ *vp++ = TAG_SWAP_SERVER;/* -1 byte */
+ *vp++ = 4; /* -1 byte */
+ insert_u_long(hp->swap_server.s_addr, &vp); /* -4 bytes */
+ bytesleft -= 6; /* Fix real count */
+ }
+ if (hp->flags.root_path) {
+ /*
+ * Check for room for root_path. Add 2 to account for
+ * TAG_ROOT_PATH and length.
+ */
+ len = strlen(hp->root_path->string);
+ NEED((len + 2), "rp");
+ *vp++ = TAG_ROOT_PATH;
+ *vp++ = (byte) (len & 0xFF);
+ bcopy(hp->root_path->string, vp, len);
+ vp += len;
+ bytesleft -= len + 2;
+ }
+ if (hp->flags.dump_file) {
+ /*
+ * Check for room for dump_file. Add 2 to account for
+ * TAG_DUMP_FILE and length.
+ */
+ len = strlen(hp->dump_file->string);
+ NEED((len + 2), "df");
+ *vp++ = TAG_DUMP_FILE;
+ *vp++ = (byte) (len & 0xFF);
+ bcopy(hp->dump_file->string, vp, len);
+ vp += len;
+ bytesleft -= len + 2;
+ }
+ /*
+ * DNS server and domain
+ */
+ if (hp->flags.domain_server) {
+ if (insert_ip(TAG_DOMAIN_SERVER,
+ hp->domain_server,
+ &vp, &bytesleft))
+ NEED(8, "ds");
+ }
+ if (hp->flags.domain_name) {
+ /*
+ * Check for room for domain_name. Add 2 to account for
+ * TAG_DOMAIN_NAME and length.
+ */
+ len = strlen(hp->domain_name->string);
+ NEED((len + 2), "dn");
+ *vp++ = TAG_DOMAIN_NAME;
+ *vp++ = (byte) (len & 0xFF);
+ bcopy(hp->domain_name->string, vp, len);
+ vp += len;
+ bytesleft -= len + 2;
+ }
+ /*
+ * NIS (YP) server and domain
+ */
+ if (hp->flags.nis_server) {
+ if (insert_ip(TAG_NIS_SERVER,
+ hp->nis_server,
+ &vp, &bytesleft))
+ NEED(8, "ds");
+ }
+ if (hp->flags.nis_domain) {
+ /*
+ * Check for room for nis_domain. Add 2 to account for
+ * TAG_NIS_DOMAIN and length.
+ */
+ len = strlen(hp->nis_domain->string);
+ NEED((len + 2), "dn");
+ *vp++ = TAG_NIS_DOMAIN;
+ *vp++ = (byte) (len & 0xFF);
+ bcopy(hp->nis_domain->string, vp, len);
+ vp += len;
+ bytesleft -= len + 2;
+ }
+ /* IEN 116 name server */
+ if (hp->flags.name_server) {
+ if (insert_ip(TAG_NAME_SERVER,
+ hp->name_server,
+ &vp, &bytesleft))
+ NEED(8, "ns");
+ }
+ if (hp->flags.rlp_server) {
+ if (insert_ip(TAG_RLP_SERVER,
+ hp->rlp_server,
+ &vp, &bytesleft))
+ NEED(8, "rl");
+ }
+ /* Time server (RFC 868) */
+ if (hp->flags.time_server) {
+ if (insert_ip(TAG_TIME_SERVER,
+ hp->time_server,
+ &vp, &bytesleft))
+ NEED(8, "ts");
+ }
+ /* NTP (time) Server (RFC 1129) */
+ if (hp->flags.ntp_server) {
+ if (insert_ip(TAG_NTP_SERVER,
+ hp->ntp_server,
+ &vp, &bytesleft))
+ NEED(8, "ts");
+ }
+ /*
+ * I wonder: If the hostname were "promoted" into the BOOTP
+ * response part, might these "extension" files possibly be
+ * shared between several clients?
+ *
+ * Also, why not just use longer BOOTP packets with all the
+ * additional length used as option data. This bootpd version
+ * already supports that feature by replying with the same
+ * packet length as the client request packet. -gwr
+ */
+ if (hp->flags.name_switch && hp->flags.send_name) {
+ /*
+ * Check for room for hostname. Add 2 to account for
+ * TAG_HOST_NAME and length.
+ */
+ len = strlen(hp->hostname->string);
+#if 0
+ /*
+ * XXX - Too much magic. The user can always set the hostname
+ * to the short version in the bootptab file. -gwr
+ */
+ if ((len + 2) > bytesleft) {
+ /*
+ * Not enough room for full (domain-qualified) hostname, try
+ * stripping it down to just the first field (host).
+ */
+ tmpstr = hp->hostname->string;
+ len = 0;
+ while (*tmpstr && (*tmpstr != '.')) {
+ tmpstr++;
+ len++;
+ }
+ }
+#endif
+ NEED((len + 2), "hn");
+ *vp++ = TAG_HOST_NAME;
+ *vp++ = (byte) (len & 0xFF);
+ bcopy(hp->hostname->string, vp, len);
+ vp += len;
+ bytesleft -= len + 2;
+ }
+ /*
+ * The rest of these are less important, so they go last.
+ */
+ if (hp->flags.lpr_server) {
+ if (insert_ip(TAG_LPR_SERVER,
+ hp->lpr_server,
+ &vp, &bytesleft))
+ NEED(8, "lp");
+ }
+ if (hp->flags.cookie_server) {
+ if (insert_ip(TAG_COOKIE_SERVER,
+ hp->cookie_server,
+ &vp, &bytesleft))
+ NEED(8, "cs");
+ }
+ if (hp->flags.log_server) {
+ if (insert_ip(TAG_LOG_SERVER,
+ hp->log_server,
+ &vp, &bytesleft))
+ NEED(8, "lg");
+ }
+ /*
+ * XXX - Add new tags here (to insert options)
+ */
+ if (hp->flags.generic) {
+ if (insert_generic(hp->generic, &vp, &bytesleft))
+ NEED(64, "(generic)");
+ }
+ /*
+ * The end marker is inserted by the caller.
+ */
+ return (vp - buf);
+#undef NEED
+} /* dovend_rfc1497 */
+
+
+
+/*
+ * Insert a tag value, a length value, and a list of IP addresses into the
+ * memory buffer indirectly pointed to by "dest". "tag" is the RFC1048 tag
+ * number to use, "iplist" is a pointer to a list of IP addresses
+ * (struct in_addr_list), and "bytesleft" points to an integer which
+ * indicates the size of the "dest" buffer.
+ *
+ * Return zero if everything fits.
+ *
+ * This is used to fill the vendor-specific area of a bootp packet in
+ * conformance to RFC1048.
+ */
+
+int
+insert_ip(tag, iplist, dest, bytesleft)
+ byte tag;
+ struct in_addr_list *iplist;
+ byte **dest;
+ int *bytesleft;
+{
+ struct in_addr *addrptr;
+ unsigned addrcount = 1;
+ byte *d;
+
+ if (iplist == NULL)
+ return (0);
+
+ if (*bytesleft >= 6) {
+ d = *dest; /* Save pointer for later */
+ **dest = tag;
+ (*dest) += 2;
+ (*bytesleft) -= 2; /* Account for tag and length */
+ addrptr = iplist->addr;
+ addrcount = iplist->addrcount;
+ while ((*bytesleft >= 4) && (addrcount > 0)) {
+ insert_u_long(addrptr->s_addr, dest);
+ addrptr++;
+ addrcount--;
+ (*bytesleft) -= 4; /* Four bytes per address */
+ }
+ d[1] = (byte) ((*dest - d - 2) & 0xFF);
+ }
+ return (addrcount);
+}
+
+
+
+/*
+ * Insert generic data into a bootp packet. The data is assumed to already
+ * be in RFC1048 format. It is inserted using a first-fit algorithm which
+ * attempts to insert as many tags as possible. Tags and data which are
+ * too large to fit are skipped; any remaining tags are tried until they
+ * have all been exhausted.
+ * Return zero if everything fits.
+ */
+
+static int
+insert_generic(gendata, buff, bytesleft)
+ struct shared_bindata *gendata;
+ byte **buff;
+ int *bytesleft;
+{
+ byte *srcptr;
+ int length, numbytes;
+ int skipped = 0;
+
+ if (gendata == NULL)
+ return (0);
+
+ srcptr = gendata->data;
+ length = gendata->length;
+ while ((length > 0) && (*bytesleft > 0)) {
+ switch (*srcptr) {
+ case TAG_END:
+ length = 0; /* Force an exit on next iteration */
+ break;
+ case TAG_PAD:
+ *(*buff)++ = *srcptr++;
+ (*bytesleft)--;
+ length--;
+ break;
+ default:
+ numbytes = srcptr[1] + 2;
+ if (*bytesleft < numbytes)
+ skipped += numbytes;
+ else {
+ bcopy(srcptr, *buff, numbytes);
+ (*buff) += numbytes;
+ (*bytesleft) -= numbytes;
+ }
+ srcptr += numbytes;
+ length -= numbytes;
+ break;
+ }
+ } /* while */
+ return (skipped);
+}
+
+/*
+ * Insert the unsigned long "value" into memory starting at the byte
+ * pointed to by the byte pointer (*dest). (*dest) is updated to
+ * point to the next available byte.
+ *
+ * Since it is desirable to internally store network addresses in network
+ * byte order (in struct in_addr's), this routine expects longs to be
+ * passed in network byte order.
+ *
+ * However, due to the nature of the main algorithm, the long must be in
+ * host byte order, thus necessitating the use of ntohl() first.
+ */
+
+void
+insert_u_long(value, dest)
+ u_int32 value;
+ byte **dest;
+{
+ byte *temp;
+ int n;
+
+ value = ntohl(value); /* Must use host byte order here */
+ temp = (*dest += 4);
+ for (n = 4; n > 0; n--) {
+ *--temp = (byte) (value & 0xFF);
+ value >>= 8;
+ }
+ /* Final result is network byte order */
+}
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/libexec/bootpd/dovend.h b/libexec/bootpd/dovend.h
new file mode 100644
index 00000000000..b30c982d8e2
--- /dev/null
+++ b/libexec/bootpd/dovend.h
@@ -0,0 +1,13 @@
+/* dovend.h */
+
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+extern int dovend_rfc1497 P((struct host *hp, u_char *buf, int len));
+extern int insert_ip P((int, struct in_addr_list *, u_char **, int *));
+extern void insert_u_long P((u_int32, u_char **));
+
+#undef P
diff --git a/libexec/bootpd/dumptab.c b/libexec/bootpd/dumptab.c
new file mode 100644
index 00000000000..e22c2715d31
--- /dev/null
+++ b/libexec/bootpd/dumptab.c
@@ -0,0 +1,370 @@
+/*
+ * dumptab.c - handles dumping the database
+ */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h> /* inet_ntoa */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <time.h>
+
+#ifndef USE_BFUNCS
+#include <memory.h>
+/* Yes, memcpy is OK here (no overlapped copies). */
+#define bcopy(a,b,c) memcpy(b,a,c)
+#define bzero(p,l) memset(p,0,l)
+#define bcmp(a,b,c) memcmp(a,b,c)
+#endif
+
+#include "bootp.h"
+#include "hash.h"
+#include "hwaddr.h"
+#include "report.h"
+#include "patchlevel.h"
+#include "bootpd.h"
+
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+static void dump_generic P((FILE *, struct shared_bindata *));
+static void dump_host P((FILE *, struct host *));
+static void list_ipaddresses P((FILE *, struct in_addr_list *));
+
+#undef P
+
+#ifndef DEBUG
+void
+dumptab(filename)
+ char *filename;
+{
+ report(LOG_INFO, "No dumptab support!");
+}
+
+#else /* DEBUG */
+
+/*
+ * Dump the internal memory database to bootpd_dump.
+ */
+
+void
+dumptab(filename)
+ char *filename;
+{
+ int n;
+ struct host *hp;
+ FILE *fp;
+ long t;
+ /* Print symbols in alphabetical order for reader's convenience. */
+ static char legend[] = "#\n# Legend:\t(see bootptab.5)\n\
+#\tfirst field -- hostname (not indented)\n\
+#\tbf -- bootfile\n\
+#\tbs -- bootfile size in 512-octet blocks\n\
+#\tcs -- cookie servers\n\
+#\tdf -- dump file name\n\
+#\tdn -- domain name\n\
+#\tds -- domain name servers\n\
+#\tef -- extension file\n\
+#\tgw -- gateways\n\
+#\tha -- hardware address\n\
+#\thd -- home directory for bootfiles\n\
+#\thn -- host name set for client\n\
+#\tht -- hardware type\n\
+#\tim -- impress servers\n\
+#\tip -- host IP address\n\
+#\tlg -- log servers\n\
+#\tlp -- LPR servers\n\
+#\tns -- IEN-116 name servers\n\
+#\tnt -- NTP servers (RFC 1129)\n\
+#\tra -- reply address override\n\
+#\trl -- resource location protocol servers\n\
+#\trp -- root path\n\
+#\tsa -- boot server address\n\
+#\tsm -- subnet mask\n\
+#\tsw -- swap server\n\
+#\ttc -- template host (points to similar host entry)\n\
+#\ttd -- TFTP directory\n\
+#\tto -- time offset (seconds)\n\
+#\tts -- time servers\n\
+#\tvm -- vendor magic number\n\
+#\tyd -- YP (NIS) domain\n\
+#\tys -- YP (NIS) servers\n\
+#\tTn -- generic option tag n\n\
+\n";
+
+ /*
+ * Open bootpd.dump file.
+ */
+ if ((fp = fopen(filename, "w")) == NULL) {
+ report(LOG_ERR, "error opening \"%s\": %s",
+ filename, get_errmsg());
+ exit(1);
+ }
+ t = time(NULL);
+ fprintf(fp, "\n# %s %s.%d\n", progname, VERSION, PATCHLEVEL);
+ fprintf(fp, "# %s: dump of bootp server database.\n", filename);
+ fprintf(fp, "# Dump taken %s", ctime(&t));
+ fwrite(legend, 1, sizeof(legend) - 1, fp);
+
+ n = 0;
+ for (hp = (struct host *) hash_FirstEntry(nmhashtable); hp != NULL;
+ hp = (struct host *) hash_NextEntry(nmhashtable)) {
+ dump_host(fp, hp);
+ fprintf(fp, "\n");
+ n++;
+ }
+ fclose(fp);
+
+ report(LOG_INFO, "dumped %d entries to \"%s\".", n, filename);
+}
+
+
+
+/*
+ * Dump all the available information on the host pointed to by "hp".
+ * The output is sent to the file pointed to by "fp".
+ */
+
+static void
+dump_host(fp, hp)
+ FILE *fp;
+ struct host *hp;
+{
+ /* Print symbols in alphabetical order for reader's convenience. */
+ if (hp) {
+ fprintf(fp, "%s:", (hp->hostname ?
+ hp->hostname->string : "?"));
+ if (hp->flags.bootfile) {
+ fprintf(fp, "\\\n\t:bf=%s:", hp->bootfile->string);
+ }
+ if (hp->flags.bootsize) {
+ fprintf(fp, "\\\n\t:bs=");
+ if (hp->flags.bootsize_auto) {
+ fprintf(fp, "auto:");
+ } else {
+ fprintf(fp, "%d:", hp->bootsize);
+ }
+ }
+ if (hp->flags.cookie_server) {
+ fprintf(fp, "\\\n\t:cs=");
+ list_ipaddresses(fp, hp->cookie_server);
+ fprintf(fp, ":");
+ }
+ if (hp->flags.dump_file) {
+ fprintf(fp, "\\\n\t:df=%s:", hp->dump_file->string);
+ }
+ if (hp->flags.domain_name) {
+ fprintf(fp, "\\\n\t:dn=%s:", hp->domain_name->string);
+ }
+ if (hp->flags.domain_server) {
+ fprintf(fp, "\\\n\t:ds=");
+ list_ipaddresses(fp, hp->domain_server);
+ fprintf(fp, ":");
+ }
+ if (hp->flags.exten_file) {
+ fprintf(fp, "\\\n\t:ef=%s:", hp->exten_file->string);
+ }
+ if (hp->flags.gateway) {
+ fprintf(fp, "\\\n\t:gw=");
+ list_ipaddresses(fp, hp->gateway);
+ fprintf(fp, ":");
+ }
+ /* FdC: swap_server (see below) */
+ if (hp->flags.homedir) {
+ fprintf(fp, "\\\n\t:hd=%s:", hp->homedir->string);
+ }
+ /* FdC: dump_file (see above) */
+ /* FdC: domain_name (see above) */
+ /* FdC: root_path (see below) */
+ if (hp->flags.name_switch && hp->flags.send_name) {
+ fprintf(fp, "\\\n\t:hn:");
+ }
+ if (hp->flags.htype) {
+ int hlen = haddrlength(hp->htype);
+ fprintf(fp, "\\\n\t:ht=%u:", (unsigned) hp->htype);
+ if (hp->flags.haddr) {
+ fprintf(fp, "ha=%s:",
+ haddrtoa(hp->haddr, hlen));
+ }
+ }
+ if (hp->flags.impress_server) {
+ fprintf(fp, "\\\n\t:im=");
+ list_ipaddresses(fp, hp->impress_server);
+ fprintf(fp, ":");
+ }
+ /* NetBSD: swap_server (see below) */
+ if (hp->flags.iaddr) {
+ fprintf(fp, "\\\n\t:ip=%s:", inet_ntoa(hp->iaddr));
+ }
+ if (hp->flags.log_server) {
+ fprintf(fp, "\\\n\t:lg=");
+ list_ipaddresses(fp, hp->log_server);
+ fprintf(fp, ":");
+ }
+ if (hp->flags.lpr_server) {
+ fprintf(fp, "\\\n\t:lp=");
+ list_ipaddresses(fp, hp->lpr_server);
+ fprintf(fp, ":");
+ }
+ if (hp->flags.name_server) {
+ fprintf(fp, "\\\n\t:ns=");
+ list_ipaddresses(fp, hp->name_server);
+ fprintf(fp, ":");
+ }
+ if (hp->flags.ntp_server) {
+ fprintf(fp, "\\\n\t:nt=");
+ list_ipaddresses(fp, hp->ntp_server);
+ fprintf(fp, ":");
+ }
+ if (hp->flags.reply_addr) {
+ fprintf(fp, "\\\n\t:ra=%s:", inet_ntoa(hp->reply_addr));
+ }
+ if (hp->flags.rlp_server) {
+ fprintf(fp, "\\\n\t:rl=");
+ list_ipaddresses(fp, hp->rlp_server);
+ fprintf(fp, ":");
+ }
+ if (hp->flags.root_path) {
+ fprintf(fp, "\\\n\t:rp=%s:", hp->root_path->string);
+ }
+ if (hp->flags.bootserver) {
+ fprintf(fp, "\\\n\t:sa=%s:", inet_ntoa(hp->bootserver));
+ }
+ if (hp->flags.subnet_mask) {
+ fprintf(fp, "\\\n\t:sm=%s:", inet_ntoa(hp->subnet_mask));
+ }
+ if (hp->flags.swap_server) {
+ fprintf(fp, "\\\n\t:sw=%s:", inet_ntoa(hp->subnet_mask));
+ }
+ if (hp->flags.tftpdir) {
+ fprintf(fp, "\\\n\t:td=%s:", hp->tftpdir->string);
+ }
+ /* NetBSD: rootpath (see above) */
+ /* NetBSD: domainname (see above) */
+ /* NetBSD: dumpfile (see above) */
+ if (hp->flags.time_offset) {
+ fprintf(fp, "\\\n\t:to=%ld:", hp->time_offset);
+ }
+ if (hp->flags.time_server) {
+ fprintf(fp, "\\\n\t:ts=");
+ list_ipaddresses(fp, hp->time_server);
+ fprintf(fp, ":");
+ }
+ if (hp->flags.vm_cookie) {
+ fprintf(fp, "\\\n\t:vm=");
+ if (!bcmp(hp->vm_cookie, vm_rfc1048, 4)) {
+ fprintf(fp, "rfc1048:");
+ } else if (!bcmp(hp->vm_cookie, vm_cmu, 4)) {
+ fprintf(fp, "cmu:");
+ } else {
+ fprintf(fp, "%d.%d.%d.%d:",
+ (int) ((hp->vm_cookie)[0]),
+ (int) ((hp->vm_cookie)[1]),
+ (int) ((hp->vm_cookie)[2]),
+ (int) ((hp->vm_cookie)[3]));
+ }
+ }
+ if (hp->flags.nis_domain) {
+ fprintf(fp, "\\\n\t:yd=%s:",
+ hp->nis_domain->string);
+ }
+ if (hp->flags.nis_server) {
+ fprintf(fp, "\\\n\t:ys=");
+ list_ipaddresses(fp, hp->nis_server);
+ fprintf(fp, ":");
+ }
+ /*
+ * XXX - Add new tags here (or above,
+ * so they print in alphabetical order).
+ */
+
+ if (hp->flags.generic) {
+ dump_generic(fp, hp->generic);
+ }
+ }
+}
+
+
+static void
+dump_generic(fp, generic)
+ FILE *fp;
+ struct shared_bindata *generic;
+{
+ u_char *bp = generic->data;
+ u_char *ep = bp + generic->length;
+ u_char tag;
+ int len;
+
+ while (bp < ep) {
+ tag = *bp++;
+ if (tag == TAG_PAD)
+ continue;
+ if (tag == TAG_END)
+ return;
+ len = *bp++;
+ if (bp + len > ep) {
+ fprintf(fp, " #junk in generic! :");
+ return;
+ }
+ fprintf(fp, "\\\n\t:T%d=", tag);
+ while (len) {
+ fprintf(fp, "%02X", *bp);
+ bp++;
+ len--;
+ if (len)
+ fprintf(fp, ".");
+ }
+ fprintf(fp, ":");
+ }
+}
+
+
+
+/*
+ * Dump an entire struct in_addr_list of IP addresses to the indicated file.
+ *
+ * The addresses are printed in standard ASCII "dot" notation and separated
+ * from one another by a single space. A single leading space is also
+ * printed before the first adddress.
+ *
+ * Null lists produce no output (and no error).
+ */
+
+static void
+list_ipaddresses(fp, ipptr)
+ FILE *fp;
+ struct in_addr_list *ipptr;
+{
+ unsigned count;
+ struct in_addr *addrptr;
+
+ if (ipptr) {
+ count = ipptr->addrcount;
+ addrptr = ipptr->addr;
+ while (count > 0) {
+ fprintf(fp, "%s", inet_ntoa(*addrptr++));
+ count--;
+ if (count)
+ fprintf(fp, ", ");
+ }
+ }
+}
+
+#endif /* DEBUG */
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/libexec/bootpd/getether.c b/libexec/bootpd/getether.c
new file mode 100644
index 00000000000..d131b50f7f8
--- /dev/null
+++ b/libexec/bootpd/getether.c
@@ -0,0 +1,374 @@
+/*
+ * getether.c : get the ethernet address of an interface
+ *
+ * All of this code is quite system-specific. As you may well
+ * guess, it took a good bit of detective work to figure out!
+ *
+ * If you figure out how to do this on another system,
+ * please let me know. <gwr@mc.com>
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <ctype.h>
+#include <syslog.h>
+
+#include "report.h"
+#define EALEN 6
+
+#if defined(ultrix) || (defined(__osf__) && defined(__alpha))
+/*
+ * This is really easy on Ultrix! Thanks to
+ * Harald Lundberg <hl@tekla.fi> for this code.
+ *
+ * The code here is not specific to the Alpha, but that was the
+ * only symbol we could find to identify DEC's version of OSF.
+ * (Perhaps we should just define DEC in the Makefile... -gwr)
+ */
+
+#include <sys/ioctl.h>
+#include <net/if.h> /* struct ifdevea */
+
+getether(ifname, eap)
+ char *ifname, *eap;
+{
+ int rc = -1;
+ int fd;
+ struct ifdevea phys;
+ bzero(&phys, sizeof(phys));
+ strcpy(phys.ifr_name, ifname);
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ report(LOG_ERR, "getether: socket(INET,DGRAM) failed");
+ return -1;
+ }
+ if (ioctl(fd, SIOCRPHYSADDR, &phys) < 0) {
+ report(LOG_ERR, "getether: ioctl SIOCRPHYSADDR failed");
+ } else {
+ bcopy(&phys.current_pa[0], eap, EALEN);
+ rc = 0;
+ }
+ close(fd);
+ return rc;
+}
+
+#define GETETHER
+#endif /* ultrix|osf1 */
+
+
+#ifdef SUNOS
+
+#include <sys/sockio.h>
+#include <sys/time.h> /* needed by net_if.h */
+#include <net/nit_if.h> /* for NIOCBIND */
+#include <net/if.h> /* for struct ifreq */
+
+getether(ifname, eap)
+ char *ifname; /* interface name from ifconfig structure */
+ char *eap; /* Ether address (output) */
+{
+ int rc = -1;
+
+ struct ifreq ifrnit;
+ int nit;
+
+ bzero((char *) &ifrnit, sizeof(ifrnit));
+ strncpy(&ifrnit.ifr_name[0], ifname, IFNAMSIZ);
+
+ nit = open("/dev/nit", 0);
+ if (nit < 0) {
+ report(LOG_ERR, "getether: open /dev/nit: %s",
+ get_errmsg());
+ return rc;
+ }
+ do {
+ if (ioctl(nit, NIOCBIND, &ifrnit) < 0) {
+ report(LOG_ERR, "getether: NIOCBIND on nit");
+ break;
+ }
+ if (ioctl(nit, SIOCGIFADDR, &ifrnit) < 0) {
+ report(LOG_ERR, "getether: SIOCGIFADDR on nit");
+ break;
+ }
+ bcopy(&ifrnit.ifr_addr.sa_data[0], eap, EALEN);
+ rc = 0;
+ } while (0);
+ close(nit);
+ return rc;
+}
+
+#define GETETHER
+#endif /* SUNOS */
+
+
+#if defined(__386BSD__) || defined(__NetBSD__)
+/* Thanks to John Brezak <brezak@ch.hp.com> for this code. */
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+
+getether(ifname, eap)
+ char *ifname; /* interface name from ifconfig structure */
+ char *eap; /* Ether address (output) */
+{
+ int fd, rc = -1;
+ register int n;
+ struct ifreq ibuf[16], ifr;
+ struct ifconf ifc;
+ register struct ifreq *ifrp, *ifend;
+
+ /* Fetch the interface configuration */
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ report(LOG_ERR, "getether: socket %s: %s", ifname, get_errmsg());
+ return (fd);
+ }
+ ifc.ifc_len = sizeof(ibuf);
+ ifc.ifc_buf = (caddr_t) ibuf;
+ if (ioctl(fd, SIOCGIFCONF, (char *) &ifc) < 0 ||
+ ifc.ifc_len < sizeof(struct ifreq)) {
+ report(LOG_ERR, "getether: SIOCGIFCONF: %s", get_errmsg);
+ goto out;
+ }
+ /* Search interface configuration list for link layer address. */
+ ifrp = ibuf;
+ ifend = (struct ifreq *) ((char *) ibuf + ifc.ifc_len);
+ while (ifrp < ifend) {
+ /* Look for interface */
+ if (strcmp(ifname, ifrp->ifr_name) == 0 &&
+ ifrp->ifr_addr.sa_family == AF_LINK &&
+ ((struct sockaddr_dl *) &ifrp->ifr_addr)->sdl_type == IFT_ETHER) {
+ bcopy(LLADDR((struct sockaddr_dl *) &ifrp->ifr_addr), eap, EALEN);
+ rc = 0;
+ break;
+ }
+ /* Bump interface config pointer */
+ n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
+ if (n < sizeof(*ifrp))
+ n = sizeof(*ifrp);
+ ifrp = (struct ifreq *) ((char *) ifrp + n);
+ }
+
+ out:
+ close(fd);
+ return (rc);
+}
+
+#define GETETHER
+#endif /* __NetBSD__ */
+
+
+#ifdef SVR4
+/*
+ * This is for "Streams TCP/IP" by Lachman Associates.
+ * They sure made this cumbersome! -gwr
+ */
+
+#include <sys/sockio.h>
+#include <sys/dlpi.h>
+#include <stropts.h>
+#ifndef NULL
+#define NULL 0
+#endif
+
+getether(ifname, eap)
+ char *ifname; /* interface name from ifconfig structure */
+ char *eap; /* Ether address (output) */
+{
+ int rc = -1;
+ char devname[32];
+ char tmpbuf[sizeof(union DL_primitives) + 16];
+ struct strbuf cbuf;
+ int fd, flags;
+ union DL_primitives *dlp;
+ char *enaddr;
+ int unit = -1; /* which unit to attach */
+
+ sprintf(devname, "/dev/%s", ifname);
+ fd = open(devname, 2);
+ if (fd < 0) {
+ /* Try without the trailing digit. */
+ char *p = devname + 5;
+ while (isalpha(*p))
+ p++;
+ if (isdigit(*p)) {
+ unit = *p - '0';
+ *p = '\0';
+ }
+ fd = open(devname, 2);
+ if (fd < 0) {
+ report(LOG_ERR, "getether: open %s: %s",
+ devname, get_errmsg());
+ return rc;
+ }
+ }
+#ifdef DL_ATTACH_REQ
+ /*
+ * If this is a "Style 2" DLPI, then we must "attach" first
+ * to tell the driver which unit (board, port) we want.
+ * For now, decide this based on the device name.
+ * (Should do "info_req" and check dl_provider_style ...)
+ */
+ if (unit >= 0) {
+ memset(tmpbuf, 0, sizeof(tmpbuf));
+ dlp = (union DL_primitives *) tmpbuf;
+ dlp->dl_primitive = DL_ATTACH_REQ;
+ dlp->attach_req.dl_ppa = unit;
+ cbuf.buf = tmpbuf;
+ cbuf.len = DL_ATTACH_REQ_SIZE;
+ if (putmsg(fd, &cbuf, NULL, 0) < 0) {
+ report(LOG_ERR, "getether: attach: putmsg: %s", get_errmsg());
+ goto out;
+ }
+ /* Recv the ack. */
+ cbuf.buf = tmpbuf;
+ cbuf.maxlen = sizeof(tmpbuf);
+ flags = 0;
+ if (getmsg(fd, &cbuf, NULL, &flags) < 0) {
+ report(LOG_ERR, "getether: attach: getmsg: %s", get_errmsg());
+ goto out;
+ }
+ /*
+ * Check the type, etc.
+ */
+ if (dlp->dl_primitive == DL_ERROR_ACK) {
+ report(LOG_ERR, "getether: attach: dlpi_errno=%d, unix_errno=%d",
+ dlp->error_ack.dl_errno,
+ dlp->error_ack.dl_unix_errno);
+ goto out;
+ }
+ if (dlp->dl_primitive != DL_OK_ACK) {
+ report(LOG_ERR, "getether: attach: not OK or ERROR");
+ goto out;
+ }
+ } /* unit >= 0 */
+#endif /* DL_ATTACH_REQ */
+
+ /*
+ * Get the Ethernet address the same way the ARP module
+ * does when it is pushed onto a new stream (bind).
+ * One should instead be able just do an dl_info_req
+ * but many drivers do not supply the hardware address
+ * in the response to dl_info_req (they MUST supply it
+ * for dl_bind_ack because the ARP module requires it).
+ */
+ memset(tmpbuf, 0, sizeof(tmpbuf));
+ dlp = (union DL_primitives *) tmpbuf;
+ dlp->dl_primitive = DL_BIND_REQ;
+ dlp->bind_req.dl_sap = 0x8FF; /* XXX - Unused SAP */
+ cbuf.buf = tmpbuf;
+ cbuf.len = DL_BIND_REQ_SIZE;
+ if (putmsg(fd, &cbuf, NULL, 0) < 0) {
+ report(LOG_ERR, "getether: bind: putmsg: %s", get_errmsg());
+ goto out;
+ }
+ /* Recv the ack. */
+ cbuf.buf = tmpbuf;
+ cbuf.maxlen = sizeof(tmpbuf);
+ flags = 0;
+ if (getmsg(fd, &cbuf, NULL, &flags) < 0) {
+ report(LOG_ERR, "getether: bind: getmsg: %s", get_errmsg());
+ goto out;
+ }
+ /*
+ * Check the type, etc.
+ */
+ if (dlp->dl_primitive == DL_ERROR_ACK) {
+ report(LOG_ERR, "getether: bind: dlpi_errno=%d, unix_errno=%d",
+ dlp->error_ack.dl_errno,
+ dlp->error_ack.dl_unix_errno);
+ goto out;
+ }
+ if (dlp->dl_primitive != DL_BIND_ACK) {
+ report(LOG_ERR, "getether: bind: not OK or ERROR");
+ goto out;
+ }
+ if (dlp->bind_ack.dl_addr_offset == 0) {
+ report(LOG_ERR, "getether: bind: ack has no address");
+ goto out;
+ }
+ if (dlp->bind_ack.dl_addr_length < EALEN) {
+ report(LOG_ERR, "getether: bind: ack address truncated");
+ goto out;
+ }
+ /*
+ * Copy the Ethernet address out of the message.
+ */
+ enaddr = tmpbuf + dlp->bind_ack.dl_addr_offset;
+ memcpy(eap, enaddr, EALEN);
+ rc = 0;
+
+ out:
+ close(fd);
+ return rc;
+}
+
+#define GETETHER
+#endif /* SVR4 */
+
+
+#ifdef linux
+/*
+ * This is really easy on Linux! This version (for linux)
+ * written by Nigel Metheringham <nigelm@ohm.york.ac.uk>
+ *
+ * The code is almost identical to the Ultrix code - however
+ * the names are different to confuse the innocent :-)
+ * Most of this code was stolen from the Ultrix bit above.
+ */
+
+#include <sys/ioctl.h>
+#include <net/if.h> /* struct ifreq */
+
+/* In a properly configured system this should be either sys/socketio.h
+ or sys/sockios.h, but on my distribution these don't line up correctly */
+#include <linux/sockios.h> /* Needed for IOCTL defs */
+
+getether(ifname, eap)
+ char *ifname, *eap;
+{
+ int rc = -1;
+ int fd;
+ struct ifreq phys;
+ bzero(&phys, sizeof(phys));
+ strcpy(phys.ifr_name, ifname);
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ report(LOG_ERR, "getether: socket(INET,DGRAM) failed");
+ return -1;
+ }
+ if (ioctl(fd, SIOCGIFHWADDR, &phys) < 0) {
+ report(LOG_ERR, "getether: ioctl SIOCGIFHWADDR failed");
+ } else {
+ bcopy(phys.ifr_hwaddr, eap, EALEN);
+ rc = 0;
+ }
+ close(fd);
+ return rc;
+}
+
+#define GETETHER
+#endif /* linux */
+
+
+/* If we don't know how on this system, just return an error. */
+#ifndef GETETHER
+getether(ifname, eap)
+ char *ifname, *eap;
+{
+ return -1;
+}
+
+#endif /* !GETETHER */
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/libexec/bootpd/getif.c b/libexec/bootpd/getif.c
new file mode 100644
index 00000000000..6cc16496ae4
--- /dev/null
+++ b/libexec/bootpd/getif.c
@@ -0,0 +1,145 @@
+/*
+ * getif.c : get an interface structure
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+#if defined(SUNOS) || defined(SVR4)
+#include <sys/sockio.h>
+#endif
+#ifdef SVR4
+#include <sys/stropts.h>
+#endif
+
+#include <net/if.h> /* for struct ifreq */
+#include <netinet/in.h>
+
+#ifndef NO_UNISTD
+#include <unistd.h>
+#endif
+#include <syslog.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "getif.h"
+#include "report.h"
+
+#ifdef __bsdi__
+#define BSD 43
+#endif
+
+static struct ifreq ifreq[10]; /* Holds interface configuration */
+static struct ifconf ifconf; /* points to ifreq */
+
+static int nmatch();
+
+/* Return a pointer to the interface struct for the passed address. */
+struct ifreq *
+getif(s, addrp)
+ int s; /* socket file descriptor */
+ struct in_addr *addrp; /* destination address on interface */
+{
+ int maxmatch;
+ int len, m, incr;
+ struct ifreq *ifrq, *ifrmax;
+ struct sockaddr_in *sip;
+ char *p;
+
+ /* If no address was supplied, just return NULL. */
+ if (!addrp)
+ return (struct ifreq *) 0;
+
+ /* Get the interface config if not done already. */
+ if (ifconf.ifc_len == 0) {
+#ifdef SVR4
+ /*
+ * SysVr4 returns garbage if you do this the obvious way!
+ * This one took a while to figure out... -gwr
+ */
+ struct strioctl ioc;
+ ioc.ic_cmd = SIOCGIFCONF;
+ ioc.ic_timout = 0;
+ ioc.ic_len = sizeof(ifreq);
+ ioc.ic_dp = (char *) ifreq;
+ m = ioctl(s, I_STR, (char *) &ioc);
+ ifconf.ifc_len = ioc.ic_len;
+ ifconf.ifc_req = ifreq;
+#else /* SVR4 */
+ ifconf.ifc_len = sizeof(ifreq);
+ ifconf.ifc_req = ifreq;
+ m = ioctl(s, SIOCGIFCONF, (caddr_t) & ifconf);
+#endif /* SVR4 */
+ if ((m < 0) || (ifconf.ifc_len <= 0)) {
+ report(LOG_ERR, "ioctl SIOCGIFCONF");
+ return (struct ifreq *) 0;
+ }
+ }
+ maxmatch = 7; /* this many bits or less... */
+ ifrmax = (struct ifreq *) 0;/* ... is not a valid match */
+ p = (char *) ifreq;
+ len = ifconf.ifc_len;
+ while (len > 0) {
+ ifrq = (struct ifreq *) p;
+ sip = (struct sockaddr_in *) &ifrq->ifr_addr;
+ m = nmatch(addrp, &(sip->sin_addr));
+ if (m > maxmatch) {
+ maxmatch = m;
+ ifrmax = ifrq;
+ }
+ /* XXX - Could this be just #ifndef IFNAMSIZ instead? -gwr */
+#if (BSD - 0) < 43
+ /* BSD not defined or earlier than 4.3 */
+ incr = sizeof(*ifrq);
+#else /* NetBSD */
+ incr = ifrq->ifr_addr.sa_len + IFNAMSIZ;
+#endif /* NetBSD */
+
+ p += incr;
+ len -= incr;
+ }
+
+ return ifrmax;
+}
+
+/*
+ * Return the number of leading bits matching in the
+ * internet addresses supplied.
+ */
+static int
+nmatch(ca, cb)
+ u_char *ca, *cb; /* ptrs to IP address, network order */
+{
+ u_int m = 0; /* count of matching bits */
+ u_int n = 4; /* bytes left, then bitmask */
+
+ /* Count matching bytes. */
+ while (n && (*ca == *cb)) {
+ ca++;
+ cb++;
+ m += 8;
+ n--;
+ }
+ /* Now count matching bits. */
+ if (n) {
+ n = 0x80;
+ while (n && ((*ca & n) == (*cb & n))) {
+ m++;
+ n >>= 1;
+ }
+ }
+ return (m);
+}
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/libexec/bootpd/getif.h b/libexec/bootpd/getif.h
new file mode 100644
index 00000000000..c51dafd2095
--- /dev/null
+++ b/libexec/bootpd/getif.h
@@ -0,0 +1,7 @@
+/* getif.h */
+
+#ifdef __STDC__
+extern struct ifreq *getif(int, struct in_addr *);
+#else
+extern struct ifreq *getif();
+#endif
diff --git a/libexec/bootpd/hash.c b/libexec/bootpd/hash.c
index a0a3d980683..e78001b732a 100644
--- a/libexec/bootpd/hash.c
+++ b/libexec/bootpd/hash.c
@@ -1,5 +1,3 @@
-#ifndef _BLURB_
-#define _BLURB_
/************************************************************************
Copyright 1988, 1991 by Carnegie Mellon University
@@ -21,11 +19,9 @@ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
************************************************************************/
-#endif /* _BLURB_ */
-
#ifndef lint
-static char rcsid[] = "$Header: /cvsroot/src/libexec/bootpd/Attic/hash.c,v 1.1 1994/04/18 05:16:01 glass Exp $";
+static char rcsid[] = "$Header: /cvsroot/src/libexec/bootpd/Attic/hash.c,v 1.2 1994/05/24 15:20:37 gwr Exp $";
#endif
@@ -41,19 +37,44 @@ static char rcsid[] = "$Header: /cvsroot/src/libexec/bootpd/Attic/hash.c,v 1.1 1
*/
+#include <sys/types.h>
+#include <stdlib.h>
+
+#ifndef USE_BFUNCS
+#include <memory.h>
+/* Yes, memcpy is OK here (no overlapped copies). */
+#define bcopy(a,b,c) memcpy(b,a,c)
+#define bzero(p,l) memset(p,0,l)
+#define bcmp(a,b,c) memcmp(a,b,c)
+#endif
+
#include "hash.h"
#define TRUE 1
#define FALSE 0
+#ifndef NULL
#define NULL 0
+#endif
/*
* This can be changed to make internal routines visible to debuggers, etc.
*/
+#ifndef PRIVATE
#define PRIVATE static
+#endif
+
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+PRIVATE void hashi_FreeMembers P((hash_member *, hash_freefp));
+#undef P
+
/*
* Hash table initialization routine.
*
@@ -63,47 +84,48 @@ static char rcsid[] = "$Header: /cvsroot/src/libexec/bootpd/Attic/hash.c,v 1.1 1
* calls return NULL.
*/
-hash_tbl *hash_Init(tablesize)
-unsigned tablesize;
+hash_tbl *
+hash_Init(tablesize)
+ unsigned tablesize;
{
- register hash_tbl *hashtblptr;
- register unsigned totalsize;
+ register hash_tbl *hashtblptr;
+ register unsigned totalsize;
- if (tablesize > 0) {
- totalsize = sizeof(hash_tbl)
+ if (tablesize > 0) {
+ totalsize = sizeof(hash_tbl)
+ sizeof(hash_member *) * (tablesize - 1);
- hashtblptr = (hash_tbl *) malloc(totalsize);
- if (hashtblptr) {
- bzero((char *) hashtblptr, totalsize);
- hashtblptr->size = tablesize; /* Success! */
- hashtblptr->bucketnum = 0;
- hashtblptr->member = (hashtblptr->table)[0];
+ hashtblptr = (hash_tbl *) malloc(totalsize);
+ if (hashtblptr) {
+ bzero((char *) hashtblptr, totalsize);
+ hashtblptr->size = tablesize; /* Success! */
+ hashtblptr->bucketnum = 0;
+ hashtblptr->member = (hashtblptr->table)[0];
+ }
+ } else {
+ hashtblptr = NULL; /* Disallow zero-length tables */
}
- } else {
- hashtblptr = NULL; /* Disallow zero-length tables */
- }
- return hashtblptr; /* NULL if failure */
+ return hashtblptr; /* NULL if failure */
}
-
+
/*
- * Recursively frees an entire linked list of bucket members (used in the open
+ * Frees an entire linked list of bucket members (used in the open
* hashing scheme). Does nothing if the passed pointer is NULL.
*/
-PRIVATE void hashi_FreeMember(bucketptr, free_data)
-hash_member *bucketptr;
-void (*free_data)();
+PRIVATE void
+hashi_FreeMembers(bucketptr, free_data)
+ hash_member *bucketptr;
+ hash_freefp free_data;
{
- if (bucketptr) {
- /*
- * Free next member if necessary
- */
- hashi_FreeMember(bucketptr->next, free_data);
- (*free_data)(bucketptr->data);
- free((char *) bucketptr);
- }
+ hash_member *nextbucket;
+ while (bucketptr) {
+ nextbucket = bucketptr->next;
+ (*free_data) (bucketptr->data);
+ free((char *) bucketptr);
+ bucketptr = nextbucket;
+ }
}
@@ -114,24 +136,25 @@ void (*free_data)();
* memory and resets all bucket pointers to NULL.
*/
-void hash_Reset(hashtable, free_data)
-hash_tbl *hashtable;
-void (*free_data)();
+void
+hash_Reset(hashtable, free_data)
+ hash_tbl *hashtable;
+ hash_freefp free_data;
{
- hash_member **bucketptr;
- unsigned i;
-
- bucketptr = hashtable->table;
- for (i = 0; i < hashtable->size; i++) {
- hashi_FreeMember(*bucketptr, free_data);
- *bucketptr++ = NULL;
- }
- hashtable->bucketnum = 0;
- hashtable->member = (hashtable->table)[0];
-}
+ hash_member **bucketptr;
+ unsigned i;
+ bucketptr = hashtable->table;
+ for (i = 0; i < hashtable->size; i++) {
+ hashi_FreeMembers(*bucketptr, free_data);
+ *bucketptr++ = NULL;
+ }
+ hashtable->bucketnum = 0;
+ hashtable->member = (hashtable->table)[0];
+}
+
/*
* Generic hash function to calculate a hash code from the given string.
*
@@ -152,47 +175,49 @@ void (*free_data)();
* features of this package.
*/
-unsigned hash_HashFunction(string, len)
-unsigned char *string;
-register unsigned len;
+unsigned
+hash_HashFunction(string, len)
+ unsigned char *string;
+ register unsigned len;
{
- register unsigned accum;
-
- accum = 0;
- for (; len > 0; len--) {
- accum <<= 1;
- accum += (unsigned) (*string++ & 0xFF);
- }
- return accum;
-}
+ register unsigned accum;
+ accum = 0;
+ for (; len > 0; len--) {
+ accum <<= 1;
+ accum += (unsigned) (*string++ & 0xFF);
+ }
+ return accum;
+}
+
/*
* Returns TRUE if at least one entry for the given key exists; FALSE
* otherwise.
*/
-int hash_Exists(hashtable, hashcode, compare, key)
-hash_tbl *hashtable;
-unsigned hashcode;
-int (*compare)();
-hash_datum *key;
+int
+hash_Exists(hashtable, hashcode, compare, key)
+ hash_tbl *hashtable;
+ unsigned hashcode;
+ hash_cmpfp compare;
+ hash_datum *key;
{
- register hash_member *memberptr;
-
- memberptr = (hashtable->table)[hashcode % (hashtable->size)];
- while (memberptr) {
- if ((*compare)(key, memberptr->data)) {
- return TRUE; /* Entry does exist */
+ register hash_member *memberptr;
+
+ memberptr = (hashtable->table)[hashcode % (hashtable->size)];
+ while (memberptr) {
+ if ((*compare) (key, memberptr->data)) {
+ return TRUE; /* Entry does exist */
+ }
+ memberptr = memberptr->next;
}
- memberptr = memberptr->next;
- }
- return FALSE; /* Entry does not exist */
+ return FALSE; /* Entry does not exist */
}
-
+
/*
* Insert the data item "element" into the hash table using "hashcode"
* to determine the bucket number, and "compare" and "key" to determine
@@ -203,95 +228,96 @@ hash_datum *key;
* occurs, -1 is returned and the insertion is not done.
*/
-int hash_Insert(hashtable, hashcode, compare, key, element)
-hash_tbl *hashtable;
-unsigned hashcode;
-int (*compare)();
-hash_datum *key, *element;
+int
+hash_Insert(hashtable, hashcode, compare, key, element)
+ hash_tbl *hashtable;
+ unsigned hashcode;
+ hash_cmpfp compare;
+ hash_datum *key, *element;
{
- hash_member *memberptr, *temp;
-
- hashcode %= hashtable->size;
- if (hash_Exists(hashtable, hashcode, compare, key)) {
- return -1; /* At least one entry already exists */
- }
- memberptr = (hashtable->table)[hashcode];
- temp = (hash_member *) malloc(sizeof(hash_member));
- if (temp) {
- (hashtable->table)[hashcode] = temp;
+ hash_member *temp;
+
+ hashcode %= hashtable->size;
+ if (hash_Exists(hashtable, hashcode, compare, key)) {
+ return -1; /* At least one entry already exists */
+ }
+ temp = (hash_member *) malloc(sizeof(hash_member));
+ if (!temp)
+ return -1; /* malloc failed! */
+
temp->data = element;
- temp->next = memberptr;
- return 0; /* Success */
- } else {
- return -1; /* malloc failed! */
- }
+ temp->next = (hashtable->table)[hashcode];
+ (hashtable->table)[hashcode] = temp;
+ return 0; /* Success */
}
-
+
/*
* Delete all data elements which match the given key. If at least one
* element is found and the deletion is successful, 0 is returned.
* If no matching elements can be found in the hash table, -1 is returned.
*/
-int hash_Delete(hashtable, hashcode, compare, key, free_data)
-hash_tbl *hashtable;
-unsigned hashcode;
-int (*compare)();
-hash_datum *key;
-void (*free_data)();
+int
+hash_Delete(hashtable, hashcode, compare, key, free_data)
+ hash_tbl *hashtable;
+ unsigned hashcode;
+ hash_cmpfp compare;
+ hash_datum *key;
+ hash_freefp free_data;
{
- hash_member *memberptr, *previous, *tempptr;
- int retval;
-
- retval = -1;
- hashcode %= hashtable->size;
-
- /*
- * Delete the first member of the list if it matches. Since this moves
- * the second member into the first position we have to keep doing this
- * over and over until it no longer matches.
- */
- memberptr = (hashtable->table)[hashcode];
- while (memberptr && (*compare)(key, memberptr->data)) {
- (hashtable->table)[hashcode] = memberptr->next;
+ hash_member *memberptr, *tempptr;
+ hash_member *previous = NULL;
+ int retval;
+
+ retval = -1;
+ hashcode %= hashtable->size;
+
/*
- * Stop hashi_FreeMember() from recursively deleting the whole list!
+ * Delete the first member of the list if it matches. Since this moves
+ * the second member into the first position we have to keep doing this
+ * over and over until it no longer matches.
*/
- memberptr->next = NULL;
- hashi_FreeMember(memberptr, free_data);
memberptr = (hashtable->table)[hashcode];
- retval = 0;
- }
-
- /*
- * Now traverse the rest of the list
- */
- if (memberptr) {
- previous = memberptr;
- memberptr = memberptr->next;
- }
- while (memberptr) {
- if ((*compare)(key, memberptr->data)) {
- tempptr = memberptr;
- previous->next = memberptr = memberptr->next;
- /*
- * Put the brakes on hashi_FreeMember(). . . .
- */
- tempptr->next = NULL;
- hashi_FreeMember(tempptr, free_data);
- retval = 0;
- } else {
- previous = memberptr;
- memberptr = memberptr->next;
+ while (memberptr && (*compare) (key, memberptr->data)) {
+ (hashtable->table)[hashcode] = memberptr->next;
+ /*
+ * Stop hashi_FreeMembers() from deleting the whole list!
+ */
+ memberptr->next = NULL;
+ hashi_FreeMembers(memberptr, free_data);
+ memberptr = (hashtable->table)[hashcode];
+ retval = 0;
}
- }
- return retval;
-}
+ /*
+ * Now traverse the rest of the list
+ */
+ if (memberptr) {
+ previous = memberptr;
+ memberptr = memberptr->next;
+ }
+ while (memberptr) {
+ if ((*compare) (key, memberptr->data)) {
+ tempptr = memberptr;
+ previous->next = memberptr = memberptr->next;
+ /*
+ * Put the brakes on hashi_FreeMembers(). . . .
+ */
+ tempptr->next = NULL;
+ hashi_FreeMembers(tempptr, free_data);
+ retval = 0;
+ } else {
+ previous = memberptr;
+ memberptr = memberptr->next;
+ }
+ }
+ return retval;
+}
+
/*
* Locate and return the data entry associated with the given key.
*
@@ -299,88 +325,101 @@ void (*free_data)();
* NULL is returned.
*/
-hash_datum *hash_Lookup(hashtable, hashcode, compare, key)
-hash_tbl *hashtable;
-unsigned hashcode;
-int (*compare)();
-hash_datum *key;
+hash_datum *
+hash_Lookup(hashtable, hashcode, compare, key)
+ hash_tbl *hashtable;
+ unsigned hashcode;
+ hash_cmpfp compare;
+ hash_datum *key;
{
- hash_member *memberptr;
-
- memberptr = (hashtable->table)[hashcode % (hashtable->size)];
- while (memberptr) {
- if ((*compare)(key, memberptr->data)) {
- return (memberptr->data);
+ hash_member *memberptr;
+
+ memberptr = (hashtable->table)[hashcode % (hashtable->size)];
+ while (memberptr) {
+ if ((*compare) (key, memberptr->data)) {
+ return (memberptr->data);
+ }
+ memberptr = memberptr->next;
}
- memberptr = memberptr->next;
- }
- return NULL;
+ return NULL;
}
-
+
/*
* Return the next available entry in the hashtable for a linear search
*/
-hash_datum *hash_NextEntry(hashtable)
-hash_tbl *hashtable;
+hash_datum *
+hash_NextEntry(hashtable)
+ hash_tbl *hashtable;
{
- register unsigned bucket;
- register hash_member *memberptr;
-
- /*
- * First try to pick up where we left off.
- */
- memberptr = hashtable->member;
- if (memberptr) {
- hashtable->member = memberptr->next; /* Set up for next call */
- return memberptr->data; /* Return the data */
- }
-
- /*
- * We hit the end of a chain, so look through the array of buckets
- * until we find a new chain (non-empty bucket) or run out of buckets.
- */
- bucket = hashtable->bucketnum + 1;
- while ((bucket < hashtable->size) &&
- !(memberptr = (hashtable->table)[bucket])) {
- bucket++;
- }
-
- /*
- * Check to see if we ran out of buckets.
- */
- if (bucket >= hashtable->size) {
+ register unsigned bucket;
+ register hash_member *memberptr;
+
/*
- * Reset to top of table for next call.
+ * First try to pick up where we left off.
*/
- hashtable->bucketnum = 0;
- hashtable->member = (hashtable->table)[0];
+ memberptr = hashtable->member;
+ if (memberptr) {
+ hashtable->member = memberptr->next; /* Set up for next call */
+ return memberptr->data; /* Return the data */
+ }
/*
- * But return end-of-table indication to the caller this time.
+ * We hit the end of a chain, so look through the array of buckets
+ * until we find a new chain (non-empty bucket) or run out of buckets.
*/
- return NULL;
- }
-
- /*
- * Must have found a non-empty bucket.
- */
- hashtable->bucketnum = bucket;
- hashtable->member = memberptr->next; /* Set up for next call */
- return memberptr->data; /* Return the data */
-}
+ bucket = hashtable->bucketnum + 1;
+ while ((bucket < hashtable->size) &&
+ !(memberptr = (hashtable->table)[bucket])) {
+ bucket++;
+ }
+ /*
+ * Check to see if we ran out of buckets.
+ */
+ if (bucket >= hashtable->size) {
+ /*
+ * Reset to top of table for next call.
+ */
+ hashtable->bucketnum = 0;
+ hashtable->member = (hashtable->table)[0];
+ /*
+ * But return end-of-table indication to the caller this time.
+ */
+ return NULL;
+ }
+ /*
+ * Must have found a non-empty bucket.
+ */
+ hashtable->bucketnum = bucket;
+ hashtable->member = memberptr->next; /* Set up for next call */
+ return memberptr->data; /* Return the data */
+}
+
/*
* Return the first entry in a hash table for a linear search
*/
-hash_datum *hash_FirstEntry(hashtable)
-hash_tbl *hashtable;
+hash_datum *
+hash_FirstEntry(hashtable)
+ hash_tbl *hashtable;
{
- hashtable->bucketnum = 0;
- hashtable->member = (hashtable->table)[0];
- return hash_NextEntry(hashtable);
+ hashtable->bucketnum = 0;
+ hashtable->member = (hashtable->table)[0];
+ return hash_NextEntry(hashtable);
}
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/libexec/bootpd/hash.h b/libexec/bootpd/hash.h
index 2a1d8b8e5a3..51d0a5ebd33 100644
--- a/libexec/bootpd/hash.h
+++ b/libexec/bootpd/hash.h
@@ -1,5 +1,6 @@
-#ifndef _BLURB_
-#define _BLURB_
+#ifndef HASH_H
+#define HASH_H
+/* hash.h */
/************************************************************************
Copyright 1988, 1991 by Carnegie Mellon University
@@ -21,8 +22,6 @@ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
************************************************************************/
-#endif /* _BLURB_ */
-
/*
* Generalized hash table ADT
@@ -91,10 +90,6 @@ SOFTWARE.
*/
-#ifndef __HASHXYZ973__
-
-#define __HASHXYZ973__
-
/*
* Define "hash_datum" as a universal data type
*/
@@ -124,14 +119,40 @@ struct hash_tblstruct {
hash_member *table[1]; /* Dynamically extended */
};
-extern hash_tbl *hash_Init();
-extern void hash_Reset();
-extern unsigned hash_HashFunction();
-extern int hash_Exists();
-extern int hash_Insert();
-extern int hash_Delete();
-extern hash_datum *hash_Lookup();
-extern hash_datum *hash_FirstEntry();
-extern hash_datum *hash_NextEntry();
-
+/* ANSI function prototypes or empty arg list? */
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
#endif
+
+typedef int (*hash_cmpfp) P((hash_datum *, hash_datum *));
+typedef void (*hash_freefp) P((hash_datum *));
+
+extern hash_tbl *hash_Init P((u_int tablesize));
+
+extern void hash_Reset P((hash_tbl *tbl, hash_freefp));
+
+extern unsigned hash_HashFunction P((u_char *str, u_int len));
+
+extern int hash_Exists P((hash_tbl *, u_int code,
+ hash_cmpfp, hash_datum *key));
+
+extern int hash_Insert P((hash_tbl *, u_int code,
+ hash_cmpfp, hash_datum *key,
+ hash_datum *element));
+
+extern int hash_Delete P((hash_tbl *, u_int code,
+ hash_cmpfp, hash_datum *key,
+ hash_freefp));
+
+extern hash_datum *hash_Lookup P((hash_tbl *, u_int code,
+ hash_cmpfp, hash_datum *key));
+
+extern hash_datum *hash_FirstEntry P((hash_tbl *));
+
+extern hash_datum *hash_NextEntry P((hash_tbl *));
+
+#undef P
+
+#endif /* HASH_H */
diff --git a/libexec/bootpd/hwaddr.c b/libexec/bootpd/hwaddr.c
new file mode 100644
index 00000000000..95418c53aac
--- /dev/null
+++ b/libexec/bootpd/hwaddr.c
@@ -0,0 +1,265 @@
+/*
+ * hwaddr.c - routines that deal with hardware addresses.
+ * (i.e. Ethernet)
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+#if defined(SUNOS) || defined(SVR4)
+#include <sys/sockio.h>
+#endif
+#ifdef SVR4
+#include <sys/stream.h>
+#include <stropts.h>
+#include <fcntl.h>
+#endif
+
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#ifndef NO_UNISTD
+#include <unistd.h>
+#endif
+#include <syslog.h>
+
+#ifndef USE_BFUNCS
+/* Yes, memcpy is OK here (no overlapped copies). */
+#include <memory.h>
+#define bcopy(a,b,c) memcpy(b,a,c)
+#define bzero(p,l) memset(p,0,l)
+#define bcmp(a,b,c) memcmp(a,b,c)
+#endif
+
+#include "bptypes.h"
+#include "hwaddr.h"
+#include "report.h"
+
+extern int debug;
+
+/*
+ * Hardware address lengths (in bytes) and network name based on hardware
+ * type code. List in order specified by Assigned Numbers RFC; Array index
+ * is hardware type code. Entries marked as zero are unknown to the author
+ * at this time. . . .
+ */
+
+struct hwinfo hwinfolist[] =
+{
+ {0, "Reserved"}, /* Type 0: Reserved (don't use this) */
+ {6, "Ethernet"}, /* Type 1: 10Mb Ethernet (48 bits) */
+ {1, "3Mb Ethernet"}, /* Type 2: 3Mb Ethernet (8 bits) */
+ {0, "AX.25"}, /* Type 3: Amateur Radio AX.25 */
+ {1, "ProNET"}, /* Type 4: Proteon ProNET Token Ring */
+ {0, "Chaos"}, /* Type 5: Chaos */
+ {6, "IEEE 802"}, /* Type 6: IEEE 802 Networks */
+ {0, "ARCNET"} /* Type 7: ARCNET */
+};
+int hwinfocnt = sizeof(hwinfolist) / sizeof(hwinfolist[0]);
+
+
+/*
+ * Setup the arp cache so that IP address 'ia' will be temporarily
+ * bound to hardware address 'ha' of length 'len'.
+ */
+void
+setarp(s, ia, ha, len)
+ int s; /* socket fd */
+ struct in_addr *ia;
+ u_char *ha;
+ int len;
+{
+ struct arpreq arpreq; /* Arp request ioctl block */
+ struct sockaddr_in *si;
+#ifdef SVR4
+ int fd;
+ struct strioctl iocb;
+#endif /* SVR4 */
+
+ bzero((caddr_t) & arpreq, sizeof(arpreq));
+ arpreq.arp_flags = ATF_INUSE | ATF_COM;
+
+ /* Set up the protocol address. */
+ arpreq.arp_pa.sa_family = AF_INET;
+ si = (struct sockaddr_in *) &arpreq.arp_pa;
+ si->sin_addr = *ia;
+
+ /* Set up the hardware address. */
+ bcopy(ha, arpreq.arp_ha.sa_data, len);
+
+#ifdef SVR4
+ /*
+ * And now the stuff for System V Rel 4.x which does not
+ * appear to allow SIOCxxx ioctls on a socket descriptor.
+ * Thanks to several people: (all sent the same fix)
+ * Barney Wolff <barney@databus.com>,
+ * bear@upsys.se (Bj|rn Sj|holm),
+ * Michael Kuschke <Michael.Kuschke@Materna.DE>,
+ */
+ if ((fd=open("/dev/arp", O_RDWR)) < 0) {
+ report(LOG_ERR, "open /dev/arp: %s\n", get_errmsg());
+ }
+ iocb.ic_cmd = SIOCSARP;
+ iocb.ic_timout = 0;
+ iocb.ic_dp = (char *)&arpreq;
+ iocb.ic_len = sizeof(arpreq);
+ if (ioctl(fd, I_STR, (caddr_t)&iocb) < 0) {
+ report(LOG_ERR, "ioctl I_STR: %s\n", get_errmsg());
+ }
+ close (fd);
+
+#else /* SVR4 */
+ /*
+ * On SunOS, the ioctl sometimes returns ENXIO, and it
+ * appears to happen when the ARP cache entry you tried
+ * to add is already in the cache. (Sigh...)
+ * XXX - Should this error simply be ignored? -gwr
+ */
+ if (ioctl(s, SIOCSARP, (caddr_t) & arpreq) < 0) {
+ report(LOG_ERR, "ioctl SIOCSARP: %s", get_errmsg());
+ }
+#endif /* SVR4 */
+}
+
+
+/*
+ * Convert a hardware address to an ASCII string.
+ */
+char *
+haddrtoa(haddr, hlen)
+ u_char *haddr;
+ int hlen;
+{
+ static char haddrbuf[3 * MAXHADDRLEN + 1];
+ char *bufptr;
+
+ if (hlen > MAXHADDRLEN)
+ hlen = MAXHADDRLEN;
+
+ bufptr = haddrbuf;
+ while (hlen > 0) {
+ sprintf(bufptr, "%02X.", (unsigned) (*haddr++ & 0xFF));
+ bufptr += 3;
+ hlen--;
+ }
+ bufptr[-1] = 0;
+ return (haddrbuf);
+}
+
+
+/*
+ * haddr_conv802()
+ * --------------
+ *
+ * Converts a backwards address to a canonical address and a canonical address
+ * to a backwards address.
+ *
+ * INPUTS:
+ * adr_in - pointer to six byte string to convert (unsigned char *)
+ * addr_len - how many bytes to convert
+ *
+ * OUTPUTS:
+ * addr_out - The string is updated to contain the converted address.
+ *
+ * CALLER:
+ * many
+ *
+ * DATA:
+ * Uses conv802table to bit-reverse the address bytes.
+ */
+
+static u_char conv802table[256] =
+{
+ /* 0x00 */ 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
+ /* 0x08 */ 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
+ /* 0x10 */ 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
+ /* 0x18 */ 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
+ /* 0x20 */ 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
+ /* 0x28 */ 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
+ /* 0x30 */ 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
+ /* 0x38 */ 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
+ /* 0x40 */ 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
+ /* 0x48 */ 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
+ /* 0x50 */ 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
+ /* 0x58 */ 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
+ /* 0x60 */ 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
+ /* 0x68 */ 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
+ /* 0x70 */ 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
+ /* 0x78 */ 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
+ /* 0x80 */ 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
+ /* 0x88 */ 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
+ /* 0x90 */ 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
+ /* 0x98 */ 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
+ /* 0xA0 */ 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
+ /* 0xA8 */ 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
+ /* 0xB0 */ 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
+ /* 0xB8 */ 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
+ /* 0xC0 */ 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
+ /* 0xC8 */ 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
+ /* 0xD0 */ 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
+ /* 0xD8 */ 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
+ /* 0xE0 */ 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
+ /* 0xE8 */ 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
+ /* 0xF0 */ 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
+ /* 0xF8 */ 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF,
+};
+
+void
+haddr_conv802(addr_in, addr_out, len)
+ register u_char *addr_in, *addr_out;
+ int len;
+{
+ u_char *lim;
+
+ lim = addr_out + len;
+ while (addr_out < lim)
+ *addr_out++ = conv802table[*addr_in++];
+}
+
+#if 0
+/*
+ * For the record, here is a program to generate the
+ * bit-reverse table above.
+ */
+static int
+bitrev(n)
+ int n;
+{
+ int i, r;
+
+ r = 0;
+ for (i = 0; i < 8; i++) {
+ r <<= 1;
+ r |= (n & 1);
+ n >>= 1;
+ }
+ return r;
+}
+
+main()
+{
+ int i;
+ for (i = 0; i <= 0xFF; i++) {
+ if ((i & 7) == 0)
+ printf("/* 0x%02X */", i);
+ printf(" 0x%02X,", bitrev(i));
+ if ((i & 7) == 7)
+ printf("\n");
+ }
+}
+
+#endif
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/libexec/bootpd/hwaddr.h b/libexec/bootpd/hwaddr.h
new file mode 100644
index 00000000000..dea7158be8c
--- /dev/null
+++ b/libexec/bootpd/hwaddr.h
@@ -0,0 +1,39 @@
+/* hwaddr.h */
+#ifndef HWADDR_H
+#define HWADDR_H
+
+#define MAXHADDRLEN 8 /* Max hw address length in bytes */
+
+/*
+ * This structure holds information about a specific network type. The
+ * length of the network hardware address is stored in "hlen".
+ * The string pointed to by "name" is the cononical name of the network.
+ */
+struct hwinfo {
+ unsigned int hlen;
+ char *name;
+};
+
+extern struct hwinfo hwinfolist[];
+extern int hwinfocnt;
+
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+extern void setarp P((int, struct in_addr *, u_char *, int));
+extern char *haddrtoa P((u_char *, int));
+extern void haddr_conv802 P((u_char *, u_char *, int));
+
+#undef P
+
+/*
+ * Return the length in bytes of a hardware address of the given type.
+ * Return the canonical name of the network of the given type.
+ */
+#define haddrlength(type) ((hwinfolist[(int) (type)]).hlen)
+#define netname(type) ((hwinfolist[(int) (type)]).name)
+
+#endif /* HWADDR_H */
diff --git a/libexec/bootpd/lookup.c b/libexec/bootpd/lookup.c
new file mode 100644
index 00000000000..2a30a59b2c3
--- /dev/null
+++ b/libexec/bootpd/lookup.c
@@ -0,0 +1,126 @@
+/*
+ * lookup.c - Lookup IP address, HW address, netmask
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#ifdef ETC_ETHERS
+#include <netinet/if_ether.h>
+extern int ether_hostton();
+#endif
+
+#include <netdb.h>
+#include <syslog.h>
+
+#ifndef USE_BFUNCS
+#include <memory.h>
+/* Yes, memcpy is OK here (no overlapped copies). */
+#define bcopy(a,b,c) memcpy(b,a,c)
+#endif
+
+#include "bootp.h"
+#include "lookup.h"
+#include "report.h"
+
+/*
+ * Lookup an Ethernet address and return it.
+ * Return NULL if addr not found.
+ */
+u_char *
+lookup_hwa(hostname, htype)
+ char *hostname;
+ int htype;
+{
+ switch (htype) {
+
+ /* XXX - How is this done on other systems? -gwr */
+#ifdef ETC_ETHERS
+ case HTYPE_ETHERNET:
+ case HTYPE_IEEE802:
+ {
+ static struct ether_addr ea;
+ /* This does a lookup in /etc/ethers */
+ if (ether_hostton(hostname, &ea)) {
+ report(LOG_ERR, "no HW addr for host \"%s\"",
+ hostname);
+ return (u_char *) 0;
+ }
+ return (u_char *) & ea;
+ }
+#endif /* ETC_ETHERS */
+
+ default:
+ report(LOG_ERR, "no lookup for HW addr type %d", htype);
+ } /* switch */
+
+ /* If the system can't do it, just return an error. */
+ return (u_char *) 0;
+}
+
+
+/*
+ * Lookup an IP address.
+ * Return non-zero on failure.
+ */
+int
+lookup_ipa(hostname, result)
+ char *hostname;
+ u_int32 *result;
+{
+ struct hostent *hp;
+ hp = gethostbyname(hostname);
+ if (!hp)
+ return -1;
+ bcopy(hp->h_addr, result, sizeof(*result));
+ return 0;
+}
+
+
+/*
+ * Lookup a netmask
+ * Return non-zero on failure.
+ *
+ * XXX - This is OK as a default, but to really make this automatic,
+ * we would need to get the subnet mask from the ether interface.
+ * If this is wrong, specify the correct value in the bootptab.
+ */
+int
+lookup_netmask(addr, result)
+ u_int32 addr; /* both in network order */
+ u_int32 *result;
+{
+ int32 m, a;
+
+ a = ntohl(addr);
+ m = 0;
+
+ if (IN_CLASSA(a))
+ m = IN_CLASSA_NET;
+
+ if (IN_CLASSB(a))
+ m = IN_CLASSB_NET;
+
+ if (IN_CLASSC(a))
+ m = IN_CLASSC_NET;
+
+ if (!m)
+ return -1;
+ *result = htonl(m);
+ return 0;
+}
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/libexec/bootpd/lookup.h b/libexec/bootpd/lookup.h
new file mode 100644
index 00000000000..04805d8915c
--- /dev/null
+++ b/libexec/bootpd/lookup.h
@@ -0,0 +1,15 @@
+/* lookup.h */
+
+#include "bptypes.h" /* for int32, u_int32 */
+
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+extern u_char *lookup_hwa P((char *hostname, int htype));
+extern int lookup_ipa P((char *hostname, u_int32 *addr));
+extern int lookup_netmask P((u_int32 addr, u_int32 *mask));
+
+#undef P
diff --git a/libexec/bootpd/patchlevel.h b/libexec/bootpd/patchlevel.h
new file mode 100644
index 00000000000..d48f9d2ec9e
--- /dev/null
+++ b/libexec/bootpd/patchlevel.h
@@ -0,0 +1,3 @@
+/* patchlevel.h */
+#define VERSION "2.3"
+#define PATCHLEVEL 7
diff --git a/libexec/bootpd/print-bootp.c b/libexec/bootpd/print-bootp.c
new file mode 100644
index 00000000000..b6819ddae20
--- /dev/null
+++ b/libexec/bootpd/print-bootp.c
@@ -0,0 +1,500 @@
+/*
+ * Copyright (c) 1988-1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Format and print bootp packets.
+ *
+ * This file was copied from tcpdump-2.1.1 and modified.
+ * There is an e-mail list for tcpdump: <tcpdump@ee.lbl.gov>
+ */
+#ifndef lint
+static char rcsid[] =
+"@(#) $Header: /cvsroot/src/libexec/bootpd/Attic/print-bootp.c,v 1.1 1994/05/24 15:20:45 gwr Exp $";
+/* 93/10/10 <gwr@mc.com> New data-driven option print routine. */
+#endif
+
+#include <stdio.h>
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "bootp.h"
+
+#ifdef BOOTPTEST
+#include "bootptest.h"
+#else /* BOOTPTEST */
+#include "interface.h"
+#include "addrtoname.h"
+#endif /* BOOTPTEST */
+
+/* These decode the vendor data. */
+static void rfc1048_print();
+static void cmu_print();
+static void other_print();
+static void dump_hex();
+
+/*
+ * Print bootp requests
+ */
+void
+bootp_print(bp, length, sport, dport)
+ struct bootp *bp;
+ int length;
+ u_short sport, dport;
+{
+ static char tstr[] = " [|bootp]";
+ static unsigned char vm_cmu[4] = VM_CMU;
+ static unsigned char vm_rfc1048[4] = VM_RFC1048;
+ u_char *ep;
+ int vdlen;
+
+#define TCHECK(var, l) if ((u_char *)&(var) > ep - l) goto trunc
+
+ /* Note funny sized packets */
+ if (length != sizeof(struct bootp))
+ (void) printf(" [len=%d]", length);
+
+ /* 'ep' points to the end of avaible data. */
+ ep = (u_char *) snapend;
+
+ switch (bp->bp_op) {
+
+ case BOOTREQUEST:
+ /* Usually, a request goes from a client to a server */
+ if (sport != IPPORT_BOOTPC || dport != IPPORT_BOOTPS)
+ printf(" (request)");
+ break;
+
+ case BOOTREPLY:
+ /* Usually, a reply goes from a server to a client */
+ if (sport != IPPORT_BOOTPS || dport != IPPORT_BOOTPC)
+ printf(" (reply)");
+ break;
+
+ default:
+ printf(" bootp-#%d", bp->bp_op);
+ }
+
+ /* The usual hardware address type is 1 (10Mb Ethernet) */
+ if (bp->bp_htype != 1)
+ printf(" htype:%d", bp->bp_htype);
+
+ /* The usual length for 10Mb Ethernet address is 6 bytes */
+ if (bp->bp_hlen != 6)
+ printf(" hlen:%d", bp->bp_hlen);
+
+ /* Client's Hardware address */
+ if (bp->bp_hlen) {
+ register struct ether_header *eh;
+ register char *e;
+
+ TCHECK(bp->bp_chaddr[0], 6);
+ eh = (struct ether_header *) packetp;
+ if (bp->bp_op == BOOTREQUEST)
+ e = (char *) ESRC(eh);
+ else if (bp->bp_op == BOOTREPLY)
+ e = (char *) EDST(eh);
+ else
+ e = 0;
+ if (e == 0 || bcmp((char *) bp->bp_chaddr, e, 6))
+ dump_hex(bp->bp_chaddr, bp->bp_hlen);
+ }
+ /* Only print interesting fields */
+ if (bp->bp_hops)
+ printf(" hops:%d", bp->bp_hops);
+
+ if (bp->bp_xid)
+ printf(" xid:%d", ntohl(bp->bp_xid));
+
+ if (bp->bp_secs)
+ printf(" secs:%d", ntohs(bp->bp_secs));
+
+ /* Client's ip address */
+ TCHECK(bp->bp_ciaddr, sizeof(bp->bp_ciaddr));
+ if (bp->bp_ciaddr.s_addr)
+ printf(" C:%s", ipaddr_string(&bp->bp_ciaddr));
+
+ /* 'your' ip address (bootp client) */
+ TCHECK(bp->bp_yiaddr, sizeof(bp->bp_yiaddr));
+ if (bp->bp_yiaddr.s_addr)
+ printf(" Y:%s", ipaddr_string(&bp->bp_yiaddr));
+
+ /* Server's ip address */
+ TCHECK(bp->bp_siaddr, sizeof(bp->bp_siaddr));
+ if (bp->bp_siaddr.s_addr)
+ printf(" S:%s", ipaddr_string(&bp->bp_siaddr));
+
+ /* Gateway's ip address */
+ TCHECK(bp->bp_giaddr, sizeof(bp->bp_giaddr));
+ if (bp->bp_giaddr.s_addr)
+ printf(" G:%s", ipaddr_string(&bp->bp_giaddr));
+
+ TCHECK(bp->bp_sname[0], sizeof(bp->bp_sname));
+ if (*bp->bp_sname) {
+ printf(" sname:");
+ if (printfn(bp->bp_sname, ep)) {
+ fputs(tstr + 1, stdout);
+ return;
+ }
+ }
+ TCHECK(bp->bp_file[0], sizeof(bp->bp_file));
+ if (*bp->bp_file) {
+ printf(" file:");
+ if (printfn(bp->bp_file, ep)) {
+ fputs(tstr + 1, stdout);
+ return;
+ }
+ }
+ /* Don't try to decode the vendor buffer unless we're verbose */
+ if (vflag <= 0)
+ return;
+
+ vdlen = sizeof(bp->bp_vend);
+ /* Vendor data can extend to the end of the packet. */
+ if (vdlen < (ep - bp->bp_vend))
+ vdlen = (ep - bp->bp_vend);
+
+ TCHECK(bp->bp_vend[0], vdlen);
+ printf(" vend");
+ if (!bcmp(bp->bp_vend, vm_rfc1048, sizeof(u_int32)))
+ rfc1048_print(bp->bp_vend, vdlen);
+ else if (!bcmp(bp->bp_vend, vm_cmu, sizeof(u_int32)))
+ cmu_print(bp->bp_vend, vdlen);
+ else
+ other_print(bp->bp_vend, vdlen);
+
+ return;
+ trunc:
+ fputs(tstr, stdout);
+#undef TCHECK
+}
+
+/*
+ * Option description data follows.
+ * These are decribed in: RFC-1048, RFC-1395, RFC-1497, RFC-1533
+ *
+ * The first char of each option string encodes the data format:
+ * ?: unknown
+ * a: ASCII
+ * b: byte (8-bit)
+ * i: inet address
+ * l: int32
+ * s: short (16-bit)
+ */
+char *
+rfc1048_opts[] = {
+ /* Originally from RFC-1048: */
+ "?PAD", /* 0: Padding - special, no data. */
+ "iSM", /* 1: subnet mask (RFC950)*/
+ "lTZ", /* 2: time offset, seconds from UTC */
+ "iGW", /* 3: gateways (or routers) */
+ "iTS", /* 4: time servers (RFC868) */
+ "iINS", /* 5: IEN name servers (IEN116) */
+ "iDNS", /* 6: domain name servers (RFC1035)(1034?) */
+ "iLOG", /* 7: MIT log servers */
+ "iCS", /* 8: cookie servers (RFC865) */
+ "iLPR", /* 9: lpr server (RFC1179) */
+ "iIPS", /* 10: impress servers (Imagen) */
+ "iRLP", /* 11: resource location servers (RFC887) */
+ "aHN", /* 12: host name (ASCII) */
+ "sBFS", /* 13: boot file size (in 512 byte blocks) */
+
+ /* Added by RFC-1395: */
+ "aDUMP", /* 14: Merit Dump File */
+ "aDNAM", /* 15: Domain Name (for DNS) */
+ "iSWAP", /* 16: Swap Server */
+ "aROOT", /* 17: Root Path */
+
+ /* Added by RFC-1497: */
+ "aEXTF", /* 18: Extensions Path (more options) */
+
+ /* Added by RFC-1533: (many, many options...) */
+#if 1 /* These might not be worth recognizing by name. */
+
+ /* IP Layer Parameters, per-host (RFC-1533, sect. 4) */
+ "bIP-forward", /* 19: IP Forwarding flag */
+ "bIP-srcroute", /* 20: IP Source Routing Enable flag */
+ "iIP-filters", /* 21: IP Policy Filter (addr pairs) */
+ "sIP-maxudp", /* 22: IP Max-UDP reassembly size */
+ "bIP-ttlive", /* 23: IP Time to Live */
+ "lIP-pmtuage", /* 24: IP Path MTU aging timeout */
+ "sIP-pmtutab", /* 25: IP Path MTU plateau table */
+
+ /* IP parameters, per-interface (RFC-1533, sect. 5) */
+ "sIP-mtu-sz", /* 26: IP MTU size */
+ "bIP-mtu-sl", /* 27: IP MTU all subnets local */
+ "bIP-bcast1", /* 28: IP Broadcast Addr ones flag */
+ "bIP-mask-d", /* 29: IP do mask discovery */
+ "bIP-mask-s", /* 30: IP do mask supplier */
+ "bIP-rt-dsc", /* 31: IP do router discovery */
+ "iIP-rt-sa", /* 32: IP router solicitation addr */
+ "iIP-routes", /* 33: IP static routes (dst,router) */
+
+ /* Link Layer parameters, per-interface (RFC-1533, sect. 6) */
+ "bLL-trailer", /* 34: do tralier encapsulation */
+ "lLL-arp-tmo", /* 35: ARP cache timeout */
+ "bLL-ether2", /* 36: Ethernet version 2 (IEEE 802.3) */
+
+ /* TCP parameters (RFC-1533, sect. 7) */
+ "bTCP-def-ttl", /* 37: default time to live */
+ "lTCP-KA-tmo", /* 38: keepalive time interval */
+ "bTCP-KA-junk", /* 39: keepalive sends extra junk */
+
+ /* Application and Service Parameters (RFC-1533, sect. 8) */
+ "aNISDOM", /* 40: NIS Domain (Sun YP) */
+ "iNISSRV", /* 41: NIS Servers */
+ "iNTPSRV", /* 42: NTP (time) Servers (RFC 1129) */
+ "?VSINFO", /* 43: Vendor Specific Info (encapsulated) */
+ "iNBiosNS", /* 44: NetBIOS Name Server (RFC-1001,1..2) */
+ "iNBiosDD", /* 45: NetBIOS Datagram Dist. Server. */
+ "bNBiosNT", /* 46: NetBIOS Note Type */
+ "?NBiosS", /* 47: NetBIOS Scope */
+ "iXW-FS", /* 48: X Window System Font Servers */
+ "iXW-DM", /* 49: X Window System Display Managers */
+
+ /* DHCP extensions (RFC-1533, sect. 9) */
+#endif
+};
+#define KNOWN_OPTIONS (sizeof(rfc1048_opts) / sizeof(rfc1048_opts[0]))
+
+static void print_string();
+
+static void
+rfc1048_print(bp, length)
+ register u_char *bp;
+ int length;
+{
+ u_char tag;
+ u_char *ep;
+ register int len, j;
+ u_int32 ul;
+ u_short us;
+ struct in_addr ia;
+ char *optstr;
+
+ printf("-rfc1395");
+
+ /* Step over magic cookie */
+ bp += sizeof(int32);
+ /* Setup end pointer */
+ ep = bp + length;
+ while (bp < ep) {
+ tag = *bp++;
+ /* Check for tags with no data first. */
+ if (tag == TAG_PAD)
+ continue;
+ if (tag == TAG_END)
+ return;
+ if (tag < KNOWN_OPTIONS) {
+ optstr = rfc1048_opts[tag];
+ printf(" %s:", optstr + 1);
+ } else {
+ printf(" T%d:", tag);
+ optstr = "?";
+ }
+ /* Now scan the length byte. */
+ len = *bp++;
+ if (bp + len > ep) {
+ /* truncated option */
+ printf(" |(%d>%d)", len, ep - bp);
+ return;
+ }
+ /* Print the option value(s). */
+ switch (optstr[0]) {
+
+ case 'a': /* ASCII string */
+ printfn(bp, bp + len);
+ bp += len;
+ len = 0;
+ break;
+
+ case 's': /* Word formats */
+ while (len >= 2) {
+ bcopy((char *) bp, (char *) &us, 2);
+ printf("%d", ntohs(us));
+ bp += 2;
+ len -= 2;
+ if (len) printf(",");
+ }
+ if (len) printf("(junk=%d)", len);
+ break;
+
+ case 'l': /* Long words */
+ while (len >= 4) {
+ bcopy((char *) bp, (char *) &ul, 4);
+ printf("%d", ntohl(ul));
+ bp += 4;
+ len -= 4;
+ if (len) printf(",");
+ }
+ if (len) printf("(junk=%d)", len);
+ break;
+
+ case 'i': /* INET addresses */
+ while (len >= 4) {
+ bcopy((char *) bp, (char *) &ia, 4);
+ printf("%s", ipaddr_string(&ia));
+ bp += 4;
+ len -= 4;
+ if (len) printf(",");
+ }
+ if (len) printf("(junk=%d)", len);
+ break;
+
+ case 'b':
+ default:
+ break;
+
+ } /* switch */
+
+ /* Print as characters, if appropriate. */
+ if (len) {
+ dump_hex(bp, len);
+ if (isascii(*bp) && isprint(*bp)) {
+ printf("(");
+ printfn(bp, bp + len);
+ printf(")");
+ }
+ bp += len;
+ len = 0;
+ }
+ } /* while bp < ep */
+}
+
+static void
+cmu_print(bp, length)
+ register u_char *bp;
+ int length;
+{
+ struct cmu_vend *v;
+ u_char *ep;
+
+ printf("-cmu");
+
+ v = (struct cmu_vend *) bp;
+ if (length < sizeof(*v)) {
+ printf(" |L=%d", length);
+ return;
+ }
+ /* Setup end pointer */
+ ep = bp + length;
+
+ /* Subnet mask */
+ if (v->v_flags & VF_SMASK) {
+ printf(" SM:%s", ipaddr_string(&v->v_smask));
+ }
+ /* Default gateway */
+ if (v->v_dgate.s_addr)
+ printf(" GW:%s", ipaddr_string(&v->v_dgate));
+
+ /* Domain name servers */
+ if (v->v_dns1.s_addr)
+ printf(" DNS1:%s", ipaddr_string(&v->v_dns1));
+ if (v->v_dns2.s_addr)
+ printf(" DNS2:%s", ipaddr_string(&v->v_dns2));
+
+ /* IEN-116 name servers */
+ if (v->v_ins1.s_addr)
+ printf(" INS1:%s", ipaddr_string(&v->v_ins1));
+ if (v->v_ins2.s_addr)
+ printf(" INS2:%s", ipaddr_string(&v->v_ins2));
+
+ /* Time servers */
+ if (v->v_ts1.s_addr)
+ printf(" TS1:%s", ipaddr_string(&v->v_ts1));
+ if (v->v_ts2.s_addr)
+ printf(" TS2:%s", ipaddr_string(&v->v_ts2));
+
+}
+
+
+/*
+ * Print out arbitrary, unknown vendor data.
+ */
+
+static void
+other_print(bp, length)
+ register u_char *bp;
+ int length;
+{
+ u_char *ep; /* end pointer */
+ u_char *zp; /* points one past last non-zero byte */
+ register int i, j;
+
+ /* Setup end pointer */
+ ep = bp + length;
+
+ /* Find the last non-zero byte. */
+ for (zp = ep; zp > bp; zp--) {
+ if (zp[-1] != 0)
+ break;
+ }
+
+ /* Print the all-zero case in a compact representation. */
+ if (zp == bp) {
+ printf("-all-zero");
+ return;
+ }
+ printf("-unknown");
+
+ /* Are there enough trailing zeros to make "00..." worthwhile? */
+ if (zp + 2 > ep)
+ zp = ep; /* print them all normally */
+
+ /* Now just print all the non-zero data. */
+ while (bp < zp) {
+ printf(".%02X", *bp);
+ bp++;
+ }
+
+ if (zp < ep)
+ printf(".00...");
+
+ return;
+}
+
+static void
+dump_hex(bp, len)
+ u_char *bp;
+ int len;
+{
+ while (len > 0) {
+ printf("%02X", *bp);
+ bp++;
+ len--;
+ if (len) printf(".");
+ }
+}
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/libexec/bootpd/readfile.c b/libexec/bootpd/readfile.c
index 6bebb3ff6fe..f3950268948 100644
--- a/libexec/bootpd/readfile.c
+++ b/libexec/bootpd/readfile.c
@@ -1,5 +1,3 @@
-#ifndef _BLURB_
-#define _BLURB_
/************************************************************************
Copyright 1988, 1991 by Carnegie Mellon University
@@ -21,11 +19,9 @@ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
************************************************************************/
-#endif /* _BLURB_ */
-
#ifndef lint
-static char rcsid[] = "$Header: /cvsroot/src/libexec/bootpd/Attic/readfile.c,v 1.1 1994/04/18 05:16:03 glass Exp $";
+static char rcsid[] = "$Header: /cvsroot/src/libexec/bootpd/Attic/readfile.c,v 1.2 1994/05/24 15:20:47 gwr Exp $";
#endif
@@ -38,45 +34,60 @@ static char rcsid[] = "$Header: /cvsroot/src/libexec/bootpd/Attic/readfile.c,v 1
*/
-#include <stdio.h>
-#include <strings.h>
-#include <ctype.h>
#include <sys/errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/time.h>
#include <netinet/in.h>
-#ifdef SYSLOG
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
#include <syslog.h>
+
+#ifndef USE_BFUNCS
+#include <memory.h>
+/* Yes, memcpy is OK here (no overlapped copies). */
+#define bcopy(a,b,c) memcpy(b,a,c)
+#define bzero(p,l) memset(p,0,l)
+#define bcmp(a,b,c) memcmp(a,b,c)
#endif
+
#include "bootp.h"
#include "hash.h"
+#include "hwaddr.h"
+#include "lookup.h"
+#include "readfile.h"
+#include "report.h"
+#include "tzone.h"
#include "bootpd.h"
+#define HASHTABLESIZE 257 /* Hash table size (prime) */
+/* Non-standard hardware address type (see bootp.h) */
+#define HTYPE_DIRECT 0
+
+/* Error codes returned by eval_symbol: */
#define SUCCESS 0
#define E_END_OF_ENTRY (-1)
#define E_SYNTAX_ERROR (-2)
#define E_UNKNOWN_SYMBOL (-3)
#define E_BAD_IPADDR (-4)
-#define E_BAD_HADDR (-5)
-#define E_BAD_SMASK (-6)
-#define E_BAD_TIMEOFF (-7)
-#define E_BAD_VM_COOKIE (-8)
-#define E_BAD_HTYPE (-9)
-#define E_BAD_BOOTSIZE (-10)
-#define E_BAD_BOOT_SERVER (-11)
-#define E_BAD_HOMEDIR (-12)
-#define E_BAD_TFTPDIR (-13)
-#define E_BAD_SWAP_SERVER (-14)
+#define E_BAD_HWADDR (-5)
+#define E_BAD_LONGWORD (-6)
+#define E_BAD_HWATYPE (-7)
+#define E_BAD_PATHNAME (-8)
+/* Tag idendities. */
#define SYM_NULL 0
#define SYM_BOOTFILE 1
#define SYM_COOKIE_SERVER 2
#define SYM_DOMAIN_SERVER 3
#define SYM_GATEWAY 4
-#define SYM_HADDR 5
+#define SYM_HWADDR 5
#define SYM_HOMEDIR 6
#define SYM_HTYPE 7
#define SYM_IMPRESS_SERVER 8
@@ -94,42 +105,49 @@ static char rcsid[] = "$Header: /cvsroot/src/libexec/bootpd/Attic/readfile.c,v 1
#define SYM_BOOTSIZE 20
#define SYM_BOOT_SERVER 22
#define SYM_TFTPDIR 23
-#define SYM_DUMPFILE 24
+#define SYM_DUMP_FILE 24
#define SYM_DOMAIN_NAME 25
#define SYM_SWAP_SERVER 26
-#define SYM_ROOTPATH 27
-
-#define OP_ADDITION 1 /* Operations on tags */
+#define SYM_ROOT_PATH 27
+#define SYM_EXTEN_FILE 28
+#define SYM_REPLY_ADDR 29
+#define SYM_NIS_DOMAIN 30 /* RFC 1533 */
+#define SYM_NIS_SERVER 31 /* RFC 1533 */
+#define SYM_NTP_SERVER 32 /* RFC 1533 */
+/* XXX - Add new tags here */
+
+#define OP_ADDITION 1 /* Operations on tags */
#define OP_DELETION 2
#define OP_BOOLEAN 3
-#define MAXINADDRS 16 /* Max size of an IP address list */
-#define MAXBUFLEN 64 /* Max temp buffer space */
+#define MAXINADDRS 16 /* Max size of an IP address list */
+#define MAXBUFLEN 64 /* Max temp buffer space */
#define MAXENTRYLEN 2048 /* Max size of an entire entry */
-
+
/*
* Structure used to map a configuration-file symbol (such as "ds") to a
* unique integer.
*/
struct symbolmap {
- char *symbol;
- int symbolcode;
+ char *symbol;
+ int symbolcode;
};
struct htypename {
- char *name;
- byte htype;
+ char *name;
+ byte htype;
};
-PRIVATE int nhosts; /* Number of hosts (/w hw or IP address) */
-PRIVATE int nentries; /* Total number of entries */
-PRIVATE long modtime = 0; /* Last modification time of bootptab */
-
+PRIVATE int nhosts; /* Number of hosts (/w hw or IP address) */
+PRIVATE int nentries; /* Total number of entries */
+PRIVATE int32 modtime = 0; /* Last modification time of bootptab */
+PRIVATE char *current_hostname; /* Name of the current entry. */
+PRIVATE char current_tagname[8];
/*
* List of symbolic names used in the bootptab file. The order and actual
@@ -138,32 +156,38 @@ PRIVATE long modtime = 0; /* Last modification time of bootptab */
*/
PRIVATE struct symbolmap symbol_list[] = {
- { "bf", SYM_BOOTFILE },
- { "bs", SYM_BOOTSIZE },
- { "cs", SYM_COOKIE_SERVER },
- { "df", SYM_DUMPFILE },
- { "dn", SYM_DOMAIN_NAME },
- { "ds", SYM_DOMAIN_SERVER },
- { "gw", SYM_GATEWAY },
- { "ha", SYM_HADDR },
- { "hd", SYM_HOMEDIR },
- { "hn", SYM_NAME_SWITCH },
- { "ht", SYM_HTYPE },
- { "im", SYM_IMPRESS_SERVER },
- { "ip", SYM_IPADDR },
- { "lg", SYM_LOG_SERVER },
- { "lp", SYM_LPR_SERVER },
- { "ns", SYM_NAME_SERVER },
- { "rl", SYM_RLP_SERVER },
- { "rp", SYM_ROOTPATH },
- { "sa", SYM_BOOT_SERVER },
- { "sm", SYM_SUBNET_MASK },
- { "sw", SYM_SWAP_SERVER },
- { "tc", SYM_SIMILAR_ENTRY },
- { "td", SYM_TFTPDIR },
- { "to", SYM_TIME_OFFSET },
- { "ts", SYM_TIME_SERVER },
- { "vm", SYM_VENDOR_MAGIC },
+ {"bf", SYM_BOOTFILE},
+ {"bs", SYM_BOOTSIZE},
+ {"cs", SYM_COOKIE_SERVER},
+ {"df", SYM_DUMP_FILE},
+ {"dn", SYM_DOMAIN_NAME},
+ {"ds", SYM_DOMAIN_SERVER},
+ {"ef", SYM_EXTEN_FILE},
+ {"gw", SYM_GATEWAY},
+ {"ha", SYM_HWADDR},
+ {"hd", SYM_HOMEDIR},
+ {"hn", SYM_NAME_SWITCH},
+ {"ht", SYM_HTYPE},
+ {"im", SYM_IMPRESS_SERVER},
+ {"ip", SYM_IPADDR},
+ {"lg", SYM_LOG_SERVER},
+ {"lp", SYM_LPR_SERVER},
+ {"ns", SYM_NAME_SERVER},
+ {"nt", SYM_NTP_SERVER},
+ {"ra", SYM_REPLY_ADDR},
+ {"rl", SYM_RLP_SERVER},
+ {"rp", SYM_ROOT_PATH},
+ {"sa", SYM_BOOT_SERVER},
+ {"sm", SYM_SUBNET_MASK},
+ {"sw", SYM_SWAP_SERVER},
+ {"tc", SYM_SIMILAR_ENTRY},
+ {"td", SYM_TFTPDIR},
+ {"to", SYM_TIME_OFFSET},
+ {"ts", SYM_TIME_SERVER},
+ {"vm", SYM_VENDOR_MAGIC},
+ {"yd", SYM_NIS_DOMAIN},
+ {"ys", SYM_NIS_SERVER},
+ /* XXX - Add new tags here */
};
@@ -175,21 +199,21 @@ PRIVATE struct symbolmap symbol_list[] = {
*/
PRIVATE struct htypename htnamemap[] = {
- { "ethernet", HTYPE_ETHERNET },
- { "ethernet3", HTYPE_EXP_ETHERNET },
- { "ether", HTYPE_ETHERNET },
- { "ether3", HTYPE_EXP_ETHERNET },
- { "ieee802", HTYPE_IEEE802 },
- { "tr", HTYPE_IEEE802 },
- { "token-ring", HTYPE_IEEE802 },
- { "pronet", HTYPE_PRONET },
- { "chaos", HTYPE_CHAOS },
- { "arcnet", HTYPE_ARCNET },
- { "ax.25", HTYPE_AX25 },
- { "direct", HTYPE_DIRECT },
- { "serial", HTYPE_DIRECT },
- { "slip", HTYPE_DIRECT },
- { "ppp", HTYPE_DIRECT }
+ {"ethernet", HTYPE_ETHERNET},
+ {"ethernet3", HTYPE_EXP_ETHERNET},
+ {"ether", HTYPE_ETHERNET},
+ {"ether3", HTYPE_EXP_ETHERNET},
+ {"ieee802", HTYPE_IEEE802},
+ {"tr", HTYPE_IEEE802},
+ {"token-ring", HTYPE_IEEE802},
+ {"pronet", HTYPE_PRONET},
+ {"chaos", HTYPE_CHAOS},
+ {"arcnet", HTYPE_ARCNET},
+ {"ax.25", HTYPE_AX25},
+ {"direct", HTYPE_DIRECT},
+ {"serial", HTYPE_DIRECT},
+ {"slip", HTYPE_DIRECT},
+ {"ppp", HTYPE_DIRECT}
};
@@ -198,32 +222,93 @@ PRIVATE struct htypename htnamemap[] = {
* Externals and forward declarations.
*/
-extern char *malloc();
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
extern boolean iplookcmp();
-extern int errno;
-
-PRIVATE char *smalloc();
-PRIVATE void fill_defaults();
-PRIVATE void del_string();
-PRIVATE void del_bindata();
-PRIVATE void del_iplist();
-PRIVATE void free_host();
-PRIVATE u_long get_u_long();
-PRIVATE void process_generic();
-PRIVATE char *get_string();
-PRIVATE struct shared_string *get_shared_string();
-PRIVATE void read_entry();
-PRIVATE boolean nullcmp();
-PRIVATE boolean nmcmp();
-PRIVATE boolean hwinscmp();
-PRIVATE void adjust();
-PRIVATE void eat_whitespace();
-PRIVATE void makelower();
-PRIVATE struct in_addr_list *get_addresses();
-PRIVATE byte *prs_haddr();
+boolean nmcmp P((hash_datum *, hash_datum *));
+
+PRIVATE void
+ adjust P((char **));
+PRIVATE void
+ del_string P((struct shared_string *));
+PRIVATE void
+ del_bindata P((struct shared_bindata *));
+PRIVATE void
+ del_iplist P((struct in_addr_list *));
+PRIVATE void
+ eat_whitespace P((char **));
+PRIVATE int
+ eval_symbol P((char **, struct host *));
+PRIVATE void
+ fill_defaults P((struct host *, char **));
+PRIVATE void
+ free_host P((hash_datum *));
+PRIVATE struct in_addr_list *
+ get_addresses P((char **));
+PRIVATE struct shared_string *
+ get_shared_string P((char **));
+PRIVATE char *
+ get_string P((char **, char *, u_int *));
+PRIVATE u_int32
+ get_u_long P((char **));
+PRIVATE boolean
+ goodname P((char *));
+PRIVATE boolean
+ hwinscmp P((hash_datum *, hash_datum *));
+PRIVATE int
+ interp_byte P((char **, byte *));
+PRIVATE void
+ makelower P((char *));
+PRIVATE boolean
+ nullcmp P((hash_datum *, hash_datum *));
+PRIVATE int
+ process_entry P((struct host *, char *));
+PRIVATE int
+ process_generic P((char **, struct shared_bindata **, u_int));
+PRIVATE byte *
+ prs_haddr P((char **, u_int));
+PRIVATE int
+ prs_inetaddr P((char **, u_int32 *));
+PRIVATE void
+ read_entry P((FILE *, char *, u_int *));
+PRIVATE char *
+ smalloc P((u_int));
+
+#undef P
+
+/*
+ * Vendor magic cookies for CMU and RFC1048
+ */
+u_char vm_cmu[4] = VM_CMU;
+u_char vm_rfc1048[4] = VM_RFC1048;
+/*
+ * Main hash tables
+ */
+hash_tbl *hwhashtable;
+hash_tbl *iphashtable;
+hash_tbl *nmhashtable;
+/*
+ * Allocate hash tables for hardware address, ip address, and hostname
+ * (shared by bootpd and bootpef)
+ */
+void
+rdtab_init()
+{
+ hwhashtable = hash_Init(HASHTABLESIZE);
+ iphashtable = hash_Init(HASHTABLESIZE);
+ nmhashtable = hash_Init(HASHTABLESIZE);
+ if (!(hwhashtable && iphashtable && nmhashtable)) {
+ report(LOG_ERR, "Unable to allocate hash tables.");
+ exit(1);
+ }
+}
/*
@@ -231,126 +316,170 @@ PRIVATE byte *prs_haddr();
* write date hasn't changed since the last time we read it.
*/
-int readtab()
+void
+readtab(force)
+ int force;
{
- struct host *hp;
- FILE *fp;
- struct stat st;
- unsigned hashcode, buflen;
- static char buffer[MAXENTRYLEN];
-#ifdef DEBUG
- char timestr[26];
-#endif
+ struct host *hp;
+ FILE *fp;
+ struct stat st;
+ unsigned hashcode, buflen;
+ static char buffer[MAXENTRYLEN];
- /*
- * Check the last modification time.
- */
- if (stat(bootptab, &st) < 0) {
- report(LOG_ERR, "stat on \"%s\": %s\n", bootptab, get_errmsg());
- return -1;
- }
+ /*
+ * Check the last modification time.
+ */
+ if (stat(bootptab, &st) < 0) {
+ report(LOG_ERR, "stat on \"%s\": %s",
+ bootptab, get_errmsg());
+ return;
+ }
#ifdef DEBUG
- if (debug > 3) {
- strcpy(timestr, ctime(&(st.st_mtime)));
- report(LOG_INFO, "bootptab mtime is %s",
- timestr);
- }
+ if (debug > 3) {
+ char timestr[28];
+ strcpy(timestr, ctime(&(st.st_mtime)));
+ /* zap the newline */
+ timestr[24] = '\0';
+ report(LOG_INFO, "bootptab mtime: %s",
+ timestr);
+ }
#endif
- if (st.st_mtime == modtime && st.st_nlink) {
+ if ((force == 0) &&
+ (st.st_mtime == modtime) &&
+ st.st_nlink) {
+ /*
+ * hasn't been modified or deleted yet.
+ */
+ return;
+ }
+ if (debug)
+ report(LOG_INFO, "reading %s\"%s\"",
+ (modtime != 0L) ? "new " : "",
+ bootptab);
+
/*
- * hasn't been modified or deleted yet.
+ * Open bootptab file.
*/
- return 0;
- }
- report(LOG_INFO, "reading %s\"%s\"\n",
- (modtime != 0L) ? "new " : "",
- bootptab);
-
- /*
- * Open bootptab file.
- */
- if ((fp = fopen(bootptab, "r")) == NULL) {
- report(LOG_ERR, "error opening \"%s\": %s\n", bootptab, get_errmsg());
- return -1;
- }
-
- /*
- * Record file modification time.
- */
- if (fstat(fileno(fp), &st) < 0) {
- report(LOG_ERR, "fstat: %s\n", get_errmsg());
- fclose(fp);
- return -1;
- }
- modtime = st.st_mtime;
-
- /*
- * Entirely erase all hash tables.
- */
- hash_Reset(hwhashtable, free_host);
- hash_Reset(iphashtable, free_host);
- hash_Reset(nmhashtable, free_host);
-
- nhosts = 0;
- nentries = 0;
- while (TRUE) {
- buflen = sizeof(buffer);
- read_entry(fp, buffer, &buflen);
- if (buflen == 0) { /* More entries? */
- break;
+ if ((fp = fopen(bootptab, "r")) == NULL) {
+ report(LOG_ERR, "error opening \"%s\": %s", bootptab, get_errmsg());
+ return;
}
- hp = (struct host *) smalloc(sizeof(struct host));
-
/*
- * Get individual info
+ * Record file modification time.
*/
- hp->flags.vm_auto = TRUE;
- bcopy(vm_rfc1048, hp->vm_cookie, 4);
- if (process_entry(hp, buffer) < 0) {
- free_host(hp);
- continue;
+ if (fstat(fileno(fp), &st) < 0) {
+ report(LOG_ERR, "fstat: %s", get_errmsg());
+ fclose(fp);
+ return;
}
+ modtime = st.st_mtime;
- if ((hp->flags.htype && hp->flags.haddr) || hp->flags.iaddr) {
- nhosts++;
- }
- if (hp->flags.htype && hp->flags.haddr) {
- hashcode = hash_HashFunction(hp->haddr, haddrlength(hp->htype));
- if (hash_Insert(hwhashtable, hashcode, hwinscmp, hp, hp) < 0) {
- report(LOG_WARNING, "duplicate %s address: %s\n",
- netname(hp->htype),
- haddrtoa(hp->haddr, hp->htype));
- free_host(hp);
- continue;
- }
- }
- if (hp->flags.iaddr) {
- hashcode = hash_HashFunction(&(hp->iaddr.s_addr), 4);
- if (hash_Insert(iphashtable, hashcode, nullcmp, hp, hp) < 0) {
- report(LOG_ERR,
- "hash_Insert() failed on IP address insertion\n");
- }
- }
+ /*
+ * Entirely erase all hash tables.
+ */
+ hash_Reset(hwhashtable, free_host);
+ hash_Reset(iphashtable, free_host);
+ hash_Reset(nmhashtable, free_host);
+
+ nhosts = 0;
+ nentries = 0;
+ while (TRUE) {
+ buflen = sizeof(buffer);
+ read_entry(fp, buffer, &buflen);
+ if (buflen == 0) { /* More entries? */
+ break;
+ }
+ hp = (struct host *) smalloc(sizeof(struct host));
+ bzero((char *) hp, sizeof(*hp));
+ /* the link count it zero */
+
+ /*
+ * Get individual info
+ */
+ if (process_entry(hp, buffer) < 0) {
+ hp->linkcount = 1;
+ free_host((hash_datum *) hp);
+ continue;
+ }
+ /*
+ * If this is not a dummy entry, and the IP or HW
+ * address is not yet set, try to get them here.
+ * Dummy entries have . as first char of name.
+ */
+ if (goodname(hp->hostname->string)) {
+ char *hn = hp->hostname->string;
+ u_int32 value;
+ if (hp->flags.iaddr == 0) {
+ if (lookup_ipa(hn, &value)) {
+ report(LOG_ERR, "can not get IP addr for %s", hn);
+ report(LOG_ERR, "(dummy names should start with '.')");
+ } else {
+ hp->iaddr.s_addr = value;
+ hp->flags.iaddr = TRUE;
+ }
+ }
+ /* Set default subnet mask. */
+ if (hp->flags.subnet_mask == 0) {
+ if (lookup_netmask(hp->iaddr.s_addr, &value)) {
+ report(LOG_ERR, "can not get netmask for %s", hn);
+ } else {
+ hp->subnet_mask.s_addr = value;
+ hp->flags.subnet_mask = TRUE;
+ }
+ }
+ }
+ if (hp->flags.iaddr) {
+ nhosts++;
+ }
+ /* Register by HW addr if known. */
+ if (hp->flags.htype && hp->flags.haddr) {
+ /* We will either insert it or free it. */
+ hp->linkcount++;
+ hashcode = hash_HashFunction(hp->haddr, haddrlength(hp->htype));
+ if (hash_Insert(hwhashtable, hashcode, hwinscmp, hp, hp) < 0) {
+ report(LOG_NOTICE, "duplicate %s address: %s",
+ netname(hp->htype),
+ haddrtoa(hp->haddr, hp->htype));
+ free_host((hash_datum *) hp);
+ continue;
+ }
+ }
+ /* Register by IP addr if known. */
+ if (hp->flags.iaddr) {
+ hashcode = hash_HashFunction((u_char *) & (hp->iaddr.s_addr), 4);
+ if (hash_Insert(iphashtable, hashcode, nullcmp, hp, hp) < 0) {
+ report(LOG_ERR,
+ "hash_Insert() failed on IP address insertion");
+ } else {
+ /* Just inserted the host struct in a new hash list. */
+ hp->linkcount++;
+ }
+ }
+ /* Register by Name (always known) */
+ hashcode = hash_HashFunction((u_char *) hp->hostname->string,
+ strlen(hp->hostname->string));
+ if (hash_Insert(nmhashtable, hashcode, nullcmp,
+ hp->hostname->string, hp) < 0) {
+ report(LOG_ERR,
+ "hash_Insert() failed on insertion of hostname: \"%s\"",
+ hp->hostname->string);
+ } else {
+ /* Just inserted the host struct in a new hash list. */
+ hp->linkcount++;
+ }
- hashcode = hash_HashFunction(hp->hostname->string,
- strlen(hp->hostname->string));
- if (hash_Insert(nmhashtable, hashcode, nullcmp, hp->hostname->string, hp) < 0) {
- report(LOG_ERR,
- "hash_Insert() failed on insertion of hostname: \"%s\"\n",
- hp->hostname->string);
+ nentries++;
}
- nentries++;
- }
-
-done:
- fclose(fp);
- report(LOG_INFO, "read %d entries (%d hosts) from \"%s\"\n",
- nentries, nhosts, bootptab);
- return 0;
-}
+ fclose(fp);
+ if (debug)
+ report(LOG_INFO, "read %d entries (%d hosts) from \"%s\"",
+ nentries, nhosts, bootptab);
+ return;
+}
+
/*
* Read an entire host entry from the file pointed to by "fp" and insert it
* into the memory pointed to by "buffer". Leading whitespace and comments
@@ -370,135 +499,135 @@ done:
* the easiest way to implement it. Maybe later I'll clean it up.
*/
-PRIVATE void read_entry(fp, buffer, bufsiz)
-FILE *fp;
-char *buffer;
-unsigned *bufsiz;
+PRIVATE void
+read_entry(fp, buffer, bufsiz)
+ FILE *fp;
+ char *buffer;
+ unsigned *bufsiz;
{
- int c, length;
-
- length = 0;
-
- /*
- * Eat whitespace, blank lines, and comment lines.
- */
-top:
- c = fgetc(fp);
- if (c < 0) {
- goto done; /* Exit if end-of-file */
- }
- if (isspace(c)) {
- goto top; /* Skip over whitespace */
- }
- if (c == '#') {
- while (TRUE) { /* Eat comments after # */
- c = fgetc(fp);
- if (c < 0) {
- goto done; /* Exit if end-of-file */
- }
- if (c == '\n') {
- goto top; /* Try to read the next line */
- }
+ int c, length;
+
+ length = 0;
+
+ /*
+ * Eat whitespace, blank lines, and comment lines.
+ */
+ top:
+ c = fgetc(fp);
+ if (c < 0) {
+ goto done; /* Exit if end-of-file */
+ }
+ if (isspace(c)) {
+ goto top; /* Skip over whitespace */
}
- }
- ungetc(c, fp); /* Other character, push it back to reprocess it */
+ if (c == '#') {
+ while (TRUE) { /* Eat comments after # */
+ c = fgetc(fp);
+ if (c < 0) {
+ goto done; /* Exit if end-of-file */
+ }
+ if (c == '\n') {
+ goto top; /* Try to read the next line */
+ }
+ }
+ }
+ ungetc(c, fp); /* Other character, push it back to reprocess it */
- /*
- * Now we're actually reading a data entry. Get each character and
- * assemble it into the data buffer, processing special characters like
- * double quotes (") and backslashes (\).
- */
+ /*
+ * Now we're actually reading a data entry. Get each character and
+ * assemble it into the data buffer, processing special characters like
+ * double quotes (") and backslashes (\).
+ */
-mainloop:
- c = fgetc(fp);
- switch (c) {
- case EOF:
+ mainloop:
+ c = fgetc(fp);
+ switch (c) {
+ case EOF:
case '\n':
- goto done; /* Exit on EOF or newline */
+ goto done; /* Exit on EOF or newline */
case '\\':
- c = fgetc(fp); /* Backslash, read a new character */
- if (c < 0) {
- goto done; /* Exit on EOF */
- }
- *buffer++ = c; /* Store the literal character */
- length++;
- if (length < *bufsiz - 1) {
- goto mainloop;
- } else {
- goto done;
- }
+ c = fgetc(fp); /* Backslash, read a new character */
+ if (c < 0) {
+ goto done; /* Exit on EOF */
+ }
+ *buffer++ = c; /* Store the literal character */
+ length++;
+ if (length < *bufsiz - 1) {
+ goto mainloop;
+ } else {
+ goto done;
+ }
case '"':
- *buffer++ = '"'; /* Store double-quote */
- length++;
- if (length >= *bufsiz - 1) {
- goto done;
- }
- while (TRUE) { /* Special quote processing loop */
- c = fgetc(fp);
- switch (c) {
- case EOF:
- goto done; /* Exit on EOF . . . */
- case '"':
- *buffer++ = '"'; /* Store matching quote */
- length++;
- if (length < *bufsiz - 1) {
- goto mainloop; /* And continue main loop */
- } else {
- goto done;
- }
- case '\\':
- if ((c = fgetc(fp)) < 0) { /* Backslash */
- goto done; /* EOF. . . .*/
- } /* else fall through */
- default:
- *buffer++ = c; /* Other character, store it */
- length++;
- if (length >= *bufsiz - 1) {
- goto done;
+ *buffer++ = '"'; /* Store double-quote */
+ length++;
+ if (length >= *bufsiz - 1) {
+ goto done;
+ }
+ while (TRUE) { /* Special quote processing loop */
+ c = fgetc(fp);
+ switch (c) {
+ case EOF:
+ goto done; /* Exit on EOF . . . */
+ case '"':
+ *buffer++ = '"';/* Store matching quote */
+ length++;
+ if (length < *bufsiz - 1) {
+ goto mainloop; /* And continue main loop */
+ } else {
+ goto done;
+ }
+ case '\\':
+ if ((c = fgetc(fp)) < 0) { /* Backslash */
+ goto done; /* EOF. . . .*/
+ } /* else fall through */
+ default:
+ *buffer++ = c; /* Other character, store it */
+ length++;
+ if (length >= *bufsiz - 1) {
+ goto done;
+ }
}
}
- }
case ':':
- *buffer++ = c; /* Store colons */
- length++;
- if (length >= *bufsiz - 1) {
- goto done;
- }
-
- do { /* But remove whitespace after them */
- c = fgetc(fp);
- if ((c < 0) || (c == '\n')) {
- goto done;
+ *buffer++ = c; /* Store colons */
+ length++;
+ if (length >= *bufsiz - 1) {
+ goto done;
}
- } while (isspace(c)); /* Skip whitespace */
+ do { /* But remove whitespace after them */
+ c = fgetc(fp);
+ if ((c < 0) || (c == '\n')) {
+ goto done;
+ }
+ } while (isspace(c)); /* Skip whitespace */
- if (c == '\\') { /* Backslash quotes next character */
- c = fgetc(fp);
- if (c < 0) {
- goto done;
- }
- if (c == '\n') {
- goto top; /* Backslash-newline continuation */
+ if (c == '\\') { /* Backslash quotes next character */
+ c = fgetc(fp);
+ if (c < 0) {
+ goto done;
+ }
+ if (c == '\n') {
+ goto top; /* Backslash-newline continuation */
+ }
}
- }
- /* fall through if "other" character */
+ /* fall through if "other" character */
default:
- *buffer++ = c; /* Store other characters */
- length++;
- if (length >= *bufsiz - 1) {
- goto done;
- }
- }
- goto mainloop; /* Keep going */
-
-done:
- *buffer = '\0'; /* Terminate string */
- *bufsiz = length; /* Tell the caller its length */
-}
+ *buffer++ = c; /* Store other characters */
+ length++;
+ if (length >= *bufsiz - 1) {
+ goto done;
+ }
+ }
+ goto mainloop; /* Keep going */
+ done:
+ *buffer = '\0'; /* Terminate string */
+ *bufsiz = length; /* Tell the caller its length */
+}
+
/*
* Parse out all the various tags and parameters in the host entry pointed
* to by "src". Stuff all the data into the appropriate fields of the
@@ -509,112 +638,128 @@ done:
* (Some errors probably shouldn't be so completely fatal. . . .)
*/
-PRIVATE int process_entry(host, src)
-struct host *host;
-char *src;
+PRIVATE int
+process_entry(host, src)
+ struct host *host;
+ char *src;
{
- int retval;
-
- if (!host || *src == '\0') {
- return -1;
- }
- host->hostname = get_shared_string(&src);
- if (!goodname(host->hostname->string)) {
- report(LOG_ERR, "bad hostname: \"%s\"\n", host->hostname->string);
- del_string(host->hostname);
- return -1;
- }
- adjust(&src);
- while (TRUE) {
- retval = eval_symbol(&src, host);
- switch (retval) {
- case SUCCESS:
- break;
- case E_SYNTAX_ERROR:
- report(LOG_ERR, "syntax error in entry for host \"%s\"\n",
- host->hostname->string);
- return -1;
- case E_UNKNOWN_SYMBOL:
- report(LOG_ERR, "unknown symbol in entry for host \"%s\"\n",
- host->hostname->string);
- return -1;
- case E_BAD_IPADDR:
- report(LOG_ERR, "bad IP address for host \"%s\"\n",
- host->hostname->string);
- return -1;
- case E_BAD_HADDR:
- report(LOG_ERR, "bad hardware address for host \"%s\"\n",
- host->hostname->string);
- return -1;
- case E_BAD_SMASK:
- report(LOG_ERR, "bad subnet mask for host \"%s\"\n",
- host->hostname->string);
- return -1;
- case E_BAD_TIMEOFF:
- report(LOG_ERR, "bad time offset for host \"%s\"\n",
- host->hostname->string);
- return -1;
- case E_BAD_VM_COOKIE:
- report(LOG_ERR, "bad vendor magic cookie for host \"%s\"\n",
- host->hostname->string);
- return -1;
- case E_BAD_HOMEDIR:
- report(LOG_ERR, "bad home directory for host \"%s\"\n",
- host->hostname->string);
- return -1;
- case E_BAD_TFTPDIR:
- report(LOG_ERR, "bad TFTP directory for host \"%s\"\n",
- host->hostname->string);
- return -1;
- case E_BAD_BOOT_SERVER:
- report(LOG_ERR, "bad boot server IP address for host \"%s\"\n",
- host->hostname->string);
- return -1;
- case E_BAD_SWAP_SERVER:
- report(LOG_ERR, "bad swap server IP address for host \"%s\"\n",
- host->hostname->string);
+ int retval;
+ char *msg;
+
+ if (!host || *src == '\0') {
return -1;
- case E_END_OF_ENTRY:
- default:
+ }
+ host->hostname = get_shared_string(&src);
#if 0
- /*
- * For now, don't try to make-up a subnet mask if one
- * wasn't specified.
- *
- * This algorithm is also not entirely correct.
- */
- if (!(hp->flags.subnet_mask)) {
- /*
- * Try to deduce the subnet mask from the network class
- */
- value = (ntohl(value) >> 30) & 0x03;
- switch (value) {
- case 0:
- case 1:
- hp->subnet_mask.s_addr = htonl(0xFF000000L);
- break;
- case 2:
- hp->subnet_mask.s_addr = htonl(0xFFFF0000L);
- break;
- case 3:
- hp->subnet_mask.s_addr = htonl(0xFFFFFF00L);
- break;
- }
- hp->flags.subnet_mask = TRUE;
- }
-#endif
- /*
- * And now we're done with this entry
- */
- return 0;
+ /* Be more liberal for the benefit of dummy tag names. */
+ if (!goodname(host->hostname->string)) {
+ report(LOG_ERR, "bad hostname: \"%s\"", host->hostname->string);
+ del_string(host->hostname);
+ return -1;
}
+#endif
+ current_hostname = host->hostname->string;
adjust(&src);
- }
+ while (TRUE) {
+ retval = eval_symbol(&src, host);
+ if (retval == SUCCESS) {
+ adjust(&src);
+ continue;
+ }
+ if (retval == E_END_OF_ENTRY) {
+ /* The default subnet mask is set in readtab() */
+ return 0;
+ }
+ /* Some kind of error. */
+ switch (retval) {
+ case E_SYNTAX_ERROR:
+ msg = "bad syntax";
+ break;
+ case E_UNKNOWN_SYMBOL:
+ msg = "unknown symbol";
+ break;
+ case E_BAD_IPADDR:
+ msg = "bad INET address";
+ break;
+ case E_BAD_HWADDR:
+ msg = "bad hardware address";
+ break;
+ case E_BAD_LONGWORD:
+ msg = "bad longword value";
+ break;
+ case E_BAD_HWATYPE:
+ msg = "bad HW address type";
+ break;
+ case E_BAD_PATHNAME:
+ msg = "bad pathname (need leading '/')";
+ default:
+ msg = "unkown error";
+ break;
+ } /* switch */
+ report(LOG_ERR, "in entry named \"%s\", symbol \"%s\": %s",
+ current_hostname, current_tagname, msg);
+ return -1;
+ }
}
-
/*
+ * Macros for use in the function below:
+ */
+
+/* Parse one INET address stored directly in MEMBER. */
+#define PARSE_IA1(MEMBER) do \
+{ \
+ if (optype == OP_BOOLEAN) \
+ return E_SYNTAX_ERROR; \
+ hp->flags.MEMBER = FALSE; \
+ if (optype == OP_ADDITION) { \
+ if (prs_inetaddr(symbol, &value) < 0) \
+ return E_BAD_IPADDR; \
+ hp->MEMBER.s_addr = value; \
+ hp->flags.MEMBER = TRUE; \
+ } \
+} while (0)
+
+/* Parse a list of INET addresses pointed to by MEMBER */
+#define PARSE_IAL(MEMBER) do \
+{ \
+ if (optype == OP_BOOLEAN) \
+ return E_SYNTAX_ERROR; \
+ if (hp->flags.MEMBER) { \
+ hp->flags.MEMBER = FALSE; \
+ assert(hp->MEMBER); \
+ del_iplist(hp->MEMBER); \
+ hp->MEMBER = NULL; \
+ } \
+ if (optype == OP_ADDITION) { \
+ hp->MEMBER = get_addresses(symbol); \
+ if (hp->MEMBER == NULL) \
+ return E_SYNTAX_ERROR; \
+ hp->flags.MEMBER = TRUE; \
+ } \
+} while (0)
+
+/* Parse a shared string pointed to by MEMBER */
+#define PARSE_STR(MEMBER) do \
+{ \
+ if (optype == OP_BOOLEAN) \
+ return E_SYNTAX_ERROR; \
+ if (hp->flags.MEMBER) { \
+ hp->flags.MEMBER = FALSE; \
+ assert(hp->MEMBER); \
+ del_string(hp->MEMBER); \
+ hp->MEMBER = NULL; \
+ } \
+ if (optype == OP_ADDITION) { \
+ hp->MEMBER = get_shared_string(symbol); \
+ if (hp->MEMBER == NULL) \
+ return E_SYNTAX_ERROR; \
+ hp->flags.MEMBER = TRUE; \
+ } \
+} while (0)
+
+/*
* Evaluate the two-character tag symbol pointed to by "symbol" and place
* the data in the structure pointed to by "hp". The pointer pointed to
* by "symbol" is updated to point past the source string (but may not
@@ -622,664 +767,350 @@ char *src;
*
* Obviously, this need a few more comments. . . .
*/
-
-PRIVATE eval_symbol(symbol, hp)
-char **symbol;
-struct host *hp;
+PRIVATE int
+eval_symbol(symbol, hp)
+ char **symbol;
+ struct host *hp;
{
- char tmpstr[MAXSTRINGLEN];
- byte *tmphaddr, *ustr;
- struct shared_string *ss;
- struct symbolmap *symbolptr;
- u_long value;
- long timeoff;
- int i, numsymbols;
- unsigned len;
- int optype; /* Indicates boolean, addition, or deletion */
-
- if ((*symbol)[0] == '\0') {
- return E_END_OF_ENTRY;
- }
- if ((*symbol)[0] == ':') {
- return SUCCESS;
- }
- if ((*symbol)[0] == 'T') { /* generic symbol */
- (*symbol)++;
- value = get_u_long(symbol);
+ char tmpstr[MAXSTRINGLEN];
+ byte *tmphaddr;
+ struct shared_string *ss;
+ struct symbolmap *symbolptr;
+ u_int32 value;
+ int32 timeoff;
+ int i, numsymbols;
+ unsigned len;
+ int optype; /* Indicates boolean, addition, or deletion */
+
eat_whitespace(symbol);
- if ((*symbol)[0] != '=') {
- return E_SYNTAX_ERROR;
- }
- (*symbol)++;
- if (!(hp->generic)) {
- hp->generic = (struct shared_bindata *)
- smalloc(sizeof(struct shared_bindata));
- }
- process_generic(symbol, &(hp->generic), (byte) (value & 0xFF));
- hp->flags.generic = TRUE;
- return SUCCESS;
- }
- eat_whitespace(symbol);
+ /* Make sure this is set before returning. */
+ current_tagname[0] = (*symbol)[0];
+ current_tagname[1] = (*symbol)[1];
+ current_tagname[2] = 0;
- /*
- * Determine the type of operation to be done on this symbol
- */
- switch ((*symbol)[2]) {
+ if ((*symbol)[0] == '\0') {
+ return E_END_OF_ENTRY;
+ }
+ if ((*symbol)[0] == ':') {
+ return SUCCESS;
+ }
+ if ((*symbol)[0] == 'T') { /* generic symbol */
+ (*symbol)++;
+ value = get_u_long(symbol);
+ sprintf(current_tagname, "T%d", value);
+ eat_whitespace(symbol);
+ if ((*symbol)[0] != '=') {
+ return E_SYNTAX_ERROR;
+ }
+ (*symbol)++;
+ if (!(hp->generic)) {
+ hp->generic = (struct shared_bindata *)
+ smalloc(sizeof(struct shared_bindata));
+ }
+ if (process_generic(symbol, &(hp->generic), (byte) (value & 0xFF)))
+ return E_SYNTAX_ERROR;
+ hp->flags.generic = TRUE;
+ return SUCCESS;
+ }
+ /*
+ * Determine the type of operation to be done on this symbol
+ */
+ switch ((*symbol)[2]) {
case '=':
- optype = OP_ADDITION;
- break;
+ optype = OP_ADDITION;
+ break;
case '@':
- optype = OP_DELETION;
- break;
+ optype = OP_DELETION;
+ break;
case ':':
case '\0':
- optype = OP_BOOLEAN;
- break;
+ optype = OP_BOOLEAN;
+ break;
default:
- return E_SYNTAX_ERROR;
- }
-
- symbolptr = symbol_list;
- numsymbols = sizeof(symbol_list) / sizeof(struct symbolmap);
- for (i = 0; i < numsymbols; i++) {
- if (((symbolptr->symbol)[0] == (*symbol)[0]) &&
- ((symbolptr->symbol)[1] == (*symbol)[1])) {
- break;
+ return E_SYNTAX_ERROR;
}
- symbolptr++;
- }
- if (i >= numsymbols) {
- return E_UNKNOWN_SYMBOL;
- }
-
- /*
- * Skip past the = or @ character (to point to the data) if this
- * isn't a boolean operation. For boolean operations, just skip
- * over the two-character tag symbol (and nothing else. . . .).
- */
- (*symbol) += (optype == OP_BOOLEAN) ? 2 : 3;
-
- switch (symbolptr->symbolcode) {
+
+ symbolptr = symbol_list;
+ numsymbols = sizeof(symbol_list) / sizeof(struct symbolmap);
+ for (i = 0; i < numsymbols; i++) {
+ if (((symbolptr->symbol)[0] == (*symbol)[0]) &&
+ ((symbolptr->symbol)[1] == (*symbol)[1])) {
+ break;
+ }
+ symbolptr++;
+ }
+ if (i >= numsymbols) {
+ return E_UNKNOWN_SYMBOL;
+ }
+ /*
+ * Skip past the = or @ character (to point to the data) if this
+ * isn't a boolean operation. For boolean operations, just skip
+ * over the two-character tag symbol (and nothing else. . . .).
+ */
+ (*symbol) += (optype == OP_BOOLEAN) ? 2 : 3;
+
+ eat_whitespace(symbol);
+
+ /* The cases below are in order by symbolcode value. */
+ switch (symbolptr->symbolcode) {
+
case SYM_BOOTFILE:
- switch (optype) {
- case OP_ADDITION:
- if (ss = get_shared_string(symbol)) {
- if (hp->bootfile) {
- del_string(hp->bootfile);
- }
- hp->bootfile = ss;
- hp->flags.bootfile = TRUE;
- }
- break;
- case OP_DELETION:
- if (hp->bootfile) {
- del_string(hp->bootfile);
- }
- hp->bootfile = NULL;
- hp->flags.bootfile = FALSE;
- break;
- case OP_BOOLEAN:
- return E_SYNTAX_ERROR;
- }
- break;
+ PARSE_STR(bootfile);
+ break;
case SYM_COOKIE_SERVER:
- switch (optype) {
- case OP_ADDITION:
- if (hp->flags.cookie_server && hp->cookie_server) {
- del_iplist(hp->cookie_server);
- }
- hp->cookie_server = get_addresses(symbol);
- hp->flags.cookie_server = TRUE;
- break;
- case OP_DELETION:
- if (hp->flags.cookie_server && hp->cookie_server) {
- del_iplist(hp->cookie_server);
- }
- hp->cookie_server = NULL;
- hp->flags.cookie_server = FALSE;
- break;
- case OP_BOOLEAN:
- return E_SYNTAX_ERROR;
- }
- break;
+ PARSE_IAL(cookie_server);
+ break;
case SYM_DOMAIN_SERVER:
- switch (optype) {
- case OP_ADDITION:
- if (hp->flags.domain_server && hp->domain_server) {
- del_iplist(hp->domain_server);
- }
- hp->domain_server = get_addresses(symbol);
- hp->flags.domain_server = TRUE;
- break;
- case OP_DELETION:
- if (hp->flags.domain_server && hp->domain_server) {
- del_iplist(hp->domain_server);
- }
- hp->domain_server = NULL;
- hp->flags.domain_server = FALSE;
- break;
- case OP_BOOLEAN:
- return E_SYNTAX_ERROR;
- }
- break;
+ PARSE_IAL(domain_server);
+ break;
case SYM_GATEWAY:
- switch (optype) {
- case OP_ADDITION:
- if (hp->flags.gateway && hp->gateway) {
- del_iplist(hp->gateway);
- }
- hp->gateway = get_addresses(symbol);
- hp->flags.gateway = TRUE;
- break;
- case OP_DELETION:
- if (hp->flags.gateway && hp->gateway) {
- del_iplist(hp->gateway);
- }
- hp->gateway = NULL;
- hp->flags.gateway = FALSE;
- break;
- case OP_BOOLEAN:
- return E_SYNTAX_ERROR;
- }
- break;
+ PARSE_IAL(gateway);
+ break;
- case SYM_HADDR:
- switch (optype) {
- case OP_ADDITION:
- if (hp->flags.htype && hp->htype &&
- (tmphaddr = prs_haddr(symbol, hp->htype))) {
+ case SYM_HWADDR:
+ if (optype == OP_BOOLEAN)
+ return E_SYNTAX_ERROR;
+ hp->flags.haddr = FALSE;
+ if (optype == OP_ADDITION) {
+ /* Default the HW type to Ethernet */
+ if (hp->flags.htype == 0) {
+ hp->flags.htype = TRUE;
+ hp->htype = HTYPE_ETHERNET;
+ }
+ tmphaddr = prs_haddr(symbol, hp->htype);
+ if (!tmphaddr)
+ return E_BAD_HWADDR;
bcopy(tmphaddr, hp->haddr, haddrlength(hp->htype));
hp->flags.haddr = TRUE;
- } else {
- return E_BAD_HADDR;
- }
- break;
- case OP_DELETION:
- hp->flags.haddr = FALSE;
- break;
- case OP_BOOLEAN:
- return E_SYNTAX_ERROR;
- }
- break;
+ }
+ break;
case SYM_HOMEDIR:
- switch (optype) {
- case OP_ADDITION:
- if (ss = get_shared_string(symbol)) {
- if ((ss->string)[0] == '/') {
- if (hp->homedir) {
- del_string(hp->homedir);
- }
- hp->homedir = ss;
- hp->flags.homedir = TRUE;
- } else {
- return E_BAD_HOMEDIR;
- }
- } else {
- return E_BAD_HOMEDIR;
- }
- break;
- case OP_DELETION:
- if (hp->homedir) {
- del_string(hp->homedir);
- }
- hp->homedir = NULL;
- hp->flags.homedir = FALSE;
- break;
- case OP_BOOLEAN:
- return E_SYNTAX_ERROR;
- }
- break;
+ PARSE_STR(homedir);
+ if ((hp->homedir != NULL) &&
+ (hp->homedir->string[0] != '/'))
+ return E_BAD_PATHNAME;
+ break;
case SYM_HTYPE:
- switch (optype) {
- case OP_ADDITION:
- value = 0L; /* Assume an illegal value */
- eat_whitespace(symbol);
- if (isdigit(**symbol)) {
- value = get_u_long(symbol);
- } else {
- len = sizeof(tmpstr);
- (void) get_string(symbol, tmpstr, &len);
- makelower(tmpstr);
- numsymbols = sizeof(htnamemap) /
- sizeof(struct htypename);
- for (i = 0; i < numsymbols; i++) {
- if (!strcmp(htnamemap[i].name, tmpstr)) {
- break;
- }
+ if (optype == OP_BOOLEAN)
+ return E_SYNTAX_ERROR;
+ hp->flags.htype = FALSE;
+ if (optype == OP_ADDITION) {
+ value = 0L; /* Assume an illegal value */
+ eat_whitespace(symbol);
+ if (isdigit(**symbol)) {
+ value = get_u_long(symbol);
+ } else {
+ len = sizeof(tmpstr);
+ (void) get_string(symbol, tmpstr, &len);
+ makelower(tmpstr);
+ numsymbols = sizeof(htnamemap) /
+ sizeof(struct htypename);
+ for (i = 0; i < numsymbols; i++) {
+ if (!strcmp(htnamemap[i].name, tmpstr)) {
+ break;
+ }
+ }
+ if (i < numsymbols) {
+ value = htnamemap[i].htype;
+ }
}
- if (i < numsymbols) {
- value = htnamemap[i].htype;
+ if (value >= hwinfocnt) {
+ return E_BAD_HWATYPE;
}
- }
- if ((value < 0) || (value > MAXHTYPES)) {
- return E_BAD_HTYPE;
- }
- hp->htype = (byte) (value & 0xFF);
- hp->flags.htype = TRUE;
- break;
- case OP_DELETION:
- hp->flags.htype = FALSE;
- break;
- case OP_BOOLEAN:
- return E_SYNTAX_ERROR;
- }
- break;
+ hp->htype = (byte) (value & 0xFF);
+ hp->flags.htype = TRUE;
+ }
+ break;
case SYM_IMPRESS_SERVER:
- switch (optype) {
- case OP_ADDITION:
- if (hp->flags.impress_server && hp->impress_server) {
- del_iplist(hp->impress_server);
- }
- hp->impress_server = get_addresses(symbol);
- hp->flags.impress_server = TRUE;
- break;
- case OP_DELETION:
- if (hp->flags.impress_server && hp->impress_server) {
- del_iplist(hp->impress_server);
- }
- hp->impress_server = NULL;
- hp->flags.impress_server = FALSE;
- break;
- case OP_BOOLEAN:
- return E_SYNTAX_ERROR;
- }
- break;
+ PARSE_IAL(impress_server);
+ break;
case SYM_IPADDR:
- switch (optype) {
- case OP_ADDITION:
- if (prs_inetaddr(symbol, &value) < 0) {
- return E_BAD_IPADDR;
- } else {
- hp->iaddr.s_addr = value;
- hp->flags.iaddr = TRUE;
- }
- break;
- case OP_DELETION:
- hp->flags.iaddr = FALSE;
- break;
- case OP_BOOLEAN:
- return E_SYNTAX_ERROR;
- }
- break;
+ PARSE_IA1(iaddr);
+ break;
case SYM_LOG_SERVER:
- switch (optype) {
- case OP_ADDITION:
- if (hp->flags.log_server && hp->log_server) {
- del_iplist(hp->log_server);
- }
- hp->log_server = get_addresses(symbol);
- hp->flags.log_server = TRUE;
- break;
- case OP_DELETION:
- if (hp->flags.log_server && hp->log_server) {
- del_iplist(hp->log_server);
- }
- hp->log_server = NULL;
- hp->flags.log_server = FALSE;
- break;
- case OP_BOOLEAN:
- return E_SYNTAX_ERROR;
- }
- break;
+ PARSE_IAL(log_server);
+ break;
case SYM_LPR_SERVER:
- switch (optype) {
- case OP_ADDITION:
- if (hp->flags.lpr_server && hp->lpr_server) {
- del_iplist(hp->lpr_server);
- }
- hp->lpr_server = get_addresses(symbol);
- hp->flags.lpr_server = TRUE;
- break;
- case OP_DELETION:
- if (hp->flags.lpr_server && hp->lpr_server) {
- del_iplist(hp->lpr_server);
- }
- hp->lpr_server = NULL;
- hp->flags.lpr_server = FALSE;
- break;
- case OP_BOOLEAN:
- return E_SYNTAX_ERROR;
- }
- break;
+ PARSE_IAL(lpr_server);
+ break;
case SYM_NAME_SERVER:
- switch (optype) {
- case OP_ADDITION:
- if (hp->flags.name_server && hp->name_server) {
- del_iplist(hp->name_server);
- }
- hp->name_server = get_addresses(symbol);
- hp->flags.name_server = TRUE;
- break;
- case OP_DELETION:
- if (hp->flags.name_server && hp->name_server) {
- del_iplist(hp->name_server);
- }
- hp->name_server = NULL;
- hp->flags.name_server = FALSE;
- break;
- case OP_BOOLEAN:
- return E_SYNTAX_ERROR;
- }
- break;
+ PARSE_IAL(name_server);
+ break;
case SYM_RLP_SERVER:
- switch (optype) {
- case OP_ADDITION:
- if (hp->flags.rlp_server && hp->rlp_server) {
- del_iplist(hp->rlp_server);
- }
- hp->rlp_server = get_addresses(symbol);
- hp->flags.rlp_server = TRUE;
- break;
- case OP_DELETION:
- if (hp->flags.rlp_server && hp->rlp_server) {
- del_iplist(hp->rlp_server);
- }
- hp->rlp_server = NULL;
- hp->flags.rlp_server = FALSE;
- break;
- case OP_BOOLEAN:
- return E_SYNTAX_ERROR;
- }
- break;
+ PARSE_IAL(rlp_server);
+ break;
case SYM_SUBNET_MASK:
- switch (optype) {
- case OP_ADDITION:
- if (prs_inetaddr(symbol, &value) < 0) {
- return E_BAD_SMASK;
- } else {
- hp->subnet_mask.s_addr = value;
- hp->flags.subnet_mask = TRUE;
- }
- break;
- case OP_DELETION:
- hp->flags.subnet_mask = FALSE;
- break;
- case OP_BOOLEAN:
- return E_SYNTAX_ERROR;
- }
- break;
+ PARSE_IA1(subnet_mask);
+ break;
case SYM_TIME_OFFSET:
- switch (optype) {
- case OP_ADDITION:
- len = sizeof(tmpstr);
- (void) get_string(symbol, tmpstr, &len);
- if (!strncmp(tmpstr, "auto", 4)) {
- hp->flags.timeoff_auto = TRUE;
- hp->flags.time_offset = TRUE;
- } else {
- if (sscanf(tmpstr, "%ld", &timeoff) != 1) {
- return E_BAD_TIMEOFF;
+ if (optype == OP_BOOLEAN)
+ return E_SYNTAX_ERROR;
+ hp->flags.time_offset = FALSE;
+ if (optype == OP_ADDITION) {
+ len = sizeof(tmpstr);
+ (void) get_string(symbol, tmpstr, &len);
+ if (!strncmp(tmpstr, "auto", 4)) {
+ hp->time_offset = secondswest;
} else {
- hp->time_offset = timeoff;
- hp->flags.timeoff_auto = FALSE;
- hp->flags.time_offset = TRUE;
+ if (sscanf(tmpstr, "%d", &timeoff) != 1)
+ return E_BAD_LONGWORD;
+ hp->time_offset = timeoff;
}
- }
- break;
- case OP_DELETION:
- hp->flags.time_offset = FALSE;
- break;
- case OP_BOOLEAN:
- return E_SYNTAX_ERROR;
- }
- break;
+ hp->flags.time_offset = TRUE;
+ }
+ break;
case SYM_TIME_SERVER:
- switch (optype) {
- case OP_ADDITION:
- if (hp->flags.time_server && hp->time_server) {
- del_iplist(hp->time_server);
- }
- hp->time_server = get_addresses(symbol);
- hp->flags.time_server = TRUE;
- break;
- case OP_DELETION:
- if (hp->flags.time_server && hp->time_server) {
- del_iplist(hp->time_server);
- }
- hp->time_server = NULL;
- hp->flags.time_server = FALSE;
- break;
- case OP_BOOLEAN:
- return E_SYNTAX_ERROR;
- }
- break;
+ PARSE_IAL(time_server);
+ break;
case SYM_VENDOR_MAGIC:
- switch (optype) {
- case OP_ADDITION:
- if (!strncmp(*symbol, "auto", 4)) {
- hp->flags.vm_auto = TRUE; /* Make it auto */
- } else if (!strncmp(*symbol, "rfc1048", 7) ||
- !strncmp(*symbol, "rfc1084", 7)) {
- hp->flags.vm_auto = FALSE; /* Make it manual */
- bcopy(vm_rfc1048, hp->vm_cookie, 4);
- } else if (!strncmp(*symbol, "cmu", 3)) {
- hp->flags.vm_auto = FALSE; /* Make it manual */
- bcopy(vm_cmu, hp->vm_cookie, 4);
- } else {
- if (prs_inetaddr(symbol, &value) < 0) {
- return E_BAD_VM_COOKIE;
+ if (optype == OP_BOOLEAN)
+ return E_SYNTAX_ERROR;
+ hp->flags.vm_cookie = FALSE;
+ if (optype == OP_ADDITION) {
+ if (strncmp(*symbol, "auto", 4)) {
+ /* The string is not "auto" */
+ if (!strncmp(*symbol, "rfc", 3)) {
+ bcopy(vm_rfc1048, hp->vm_cookie, 4);
+ } else if (!strncmp(*symbol, "cmu", 3)) {
+ bcopy(vm_cmu, hp->vm_cookie, 4);
+ } else {
+ if (!isdigit(**symbol))
+ return E_BAD_IPADDR;
+ if (prs_inetaddr(symbol, &value) < 0)
+ return E_BAD_IPADDR;
+ bcopy(&value, hp->vm_cookie, 4);
+ }
+ hp->flags.vm_cookie = TRUE;
}
- hp->flags.vm_auto = FALSE; /* Make it manual */
- ustr = hp->vm_cookie;
- insert_u_long(value, &ustr);
- }
- hp->flags.vendor_magic = TRUE;
- break;
- case OP_DELETION:
- hp->flags.vendor_magic = FALSE;
- break;
- case OP_BOOLEAN:
- hp->flags.vm_auto = TRUE;
- hp->flags.vendor_magic = TRUE;
- break;
- }
- break;
+ }
+ break;
case SYM_SIMILAR_ENTRY:
- switch (optype) {
+ switch (optype) {
case OP_ADDITION:
- fill_defaults(hp, symbol);
- break;
+ fill_defaults(hp, symbol);
+ break;
default:
- return E_SYNTAX_ERROR;
- }
- break;
+ return E_SYNTAX_ERROR;
+ }
+ break;
case SYM_NAME_SWITCH:
- switch (optype) {
+ switch (optype) {
case OP_ADDITION:
- return E_SYNTAX_ERROR;
+ return E_SYNTAX_ERROR;
case OP_DELETION:
- hp->flags.send_name = FALSE;
- hp->flags.name_switch = FALSE;
- break;
+ hp->flags.send_name = FALSE;
+ hp->flags.name_switch = FALSE;
+ break;
case OP_BOOLEAN:
- hp->flags.send_name = TRUE;
- hp->flags.name_switch = TRUE;
- break;
- }
- break;
+ hp->flags.send_name = TRUE;
+ hp->flags.name_switch = TRUE;
+ break;
+ }
+ break;
case SYM_BOOTSIZE:
- switch (optype) {
+ switch (optype) {
case OP_ADDITION:
- if (!strncmp(*symbol, "auto", 4)) {
- hp->flags.bootsize = TRUE;
- hp->flags.bootsize_auto = TRUE;
- } else {
- hp->bootsize = (unsigned int) get_u_long(symbol);
- hp->flags.bootsize = TRUE;
- hp->flags.bootsize_auto = FALSE;
- }
- break;
+ if (!strncmp(*symbol, "auto", 4)) {
+ hp->flags.bootsize = TRUE;
+ hp->flags.bootsize_auto = TRUE;
+ } else {
+ hp->bootsize = (unsigned int) get_u_long(symbol);
+ hp->flags.bootsize = TRUE;
+ hp->flags.bootsize_auto = FALSE;
+ }
+ break;
case OP_DELETION:
- hp->flags.bootsize = FALSE;
- break;
+ hp->flags.bootsize = FALSE;
+ break;
case OP_BOOLEAN:
- hp->flags.bootsize = TRUE;
- hp->flags.bootsize_auto = TRUE;
- break;
- }
- break;
+ hp->flags.bootsize = TRUE;
+ hp->flags.bootsize_auto = TRUE;
+ break;
+ }
+ break;
case SYM_BOOT_SERVER:
- switch (optype) {
- case OP_ADDITION:
- if (prs_inetaddr(symbol, &value) < 0) {
- return E_BAD_BOOT_SERVER;
- } else {
- hp->bootserver.s_addr = value;
- hp->flags.bootserver = TRUE;
- }
- break;
- case OP_DELETION:
- hp->flags.bootserver = FALSE;
- break;
- case OP_BOOLEAN:
- return E_SYNTAX_ERROR;
- }
- break;
+ PARSE_IA1(bootserver);
+ break;
case SYM_TFTPDIR:
- switch (optype) {
- case OP_ADDITION:
- if (ss = get_shared_string(symbol)) {
- if ((ss->string)[0] == '/') {
- if (hp->tftpdir) {
- del_string(hp->tftpdir);
- }
- hp->tftpdir = ss;
- hp->flags.tftpdir = TRUE;
- } else {
- return E_BAD_TFTPDIR;
- }
- } else {
- return E_BAD_TFTPDIR;
- }
- break;
- case OP_DELETION:
- if (hp->tftpdir) {
- del_string(hp->tftpdir);
- }
- hp->tftpdir = NULL;
- hp->flags.tftpdir = FALSE;
- break;
- case OP_BOOLEAN:
- return E_SYNTAX_ERROR;
- }
- break;
+ PARSE_STR(tftpdir);
+ if ((hp->tftpdir != NULL) &&
+ (hp->tftpdir->string[0] != '/'))
+ return E_BAD_PATHNAME;
+ break;
- case SYM_DUMPFILE:
- switch (optype) {
- case OP_ADDITION:
- if (ss = get_shared_string(symbol)) {
- if (hp->dumpfile) {
- del_string(hp->dumpfile);
- }
- hp->dumpfile = ss;
- hp->flags.dumpfile = TRUE;
- }
- break;
- case OP_DELETION:
- if (hp->dumpfile) {
- del_string(hp->dumpfile);
- }
- hp->dumpfile = NULL;
- hp->flags.dumpfile = FALSE;
- break;
- case OP_BOOLEAN:
- return E_SYNTAX_ERROR;
- }
- break;
+ case SYM_DUMP_FILE:
+ PARSE_STR(dump_file);
+ break;
case SYM_DOMAIN_NAME:
- switch (optype) {
- case OP_ADDITION:
- if (ss = get_shared_string(symbol)) {
- if (hp->domainname) {
- del_string(hp->domainname);
- }
- hp->domainname = ss;
- hp->flags.domainname = TRUE;
- }
- break;
- case OP_DELETION:
- if (hp->domainname) {
- del_string(hp->domainname);
- }
- hp->domainname = NULL;
- hp->flags.domainname = FALSE;
- break;
- case OP_BOOLEAN:
- return E_SYNTAX_ERROR;
- }
- break;
+ PARSE_STR(domain_name);
+ break;
- case SYM_ROOTPATH:
- switch (optype) {
- case OP_ADDITION:
- if (ss = get_shared_string(symbol)) {
- if (hp->rootpath) {
- del_string(hp->rootpath);
- }
- hp->rootpath = ss;
- hp->flags.rootpath = TRUE;
- }
- break;
- case OP_DELETION:
- if (hp->rootpath) {
- del_string(hp->rootpath);
- }
- hp->rootpath = NULL;
- hp->flags.rootpath = FALSE;
- break;
- case OP_BOOLEAN:
- return E_SYNTAX_ERROR;
- }
- break;
-
case SYM_SWAP_SERVER:
- switch (optype) {
- case OP_ADDITION:
- if (prs_inetaddr(symbol, &value) < 0) {
- return E_BAD_SWAP_SERVER;
- } else {
- hp->swapserver.s_addr = value;
- hp->flags.swap_server = TRUE;
- }
- break;
- case OP_DELETION:
- hp->flags.swap_server = FALSE;
- break;
- case OP_BOOLEAN:
- return E_SYNTAX_ERROR;
- }
- break;
+ PARSE_IA1(swap_server);
+ break;
+
+ case SYM_ROOT_PATH:
+ PARSE_STR(root_path);
+ break;
+
+ case SYM_EXTEN_FILE:
+ PARSE_STR(exten_file);
+ break;
+
+ case SYM_REPLY_ADDR:
+ PARSE_IA1(reply_addr);
+ break;
+
+ case SYM_NIS_DOMAIN:
+ PARSE_STR(nis_domain);
+ break;
+
+ case SYM_NIS_SERVER:
+ PARSE_IAL(nis_server);
+ break;
+
+ case SYM_NTP_SERVER:
+ PARSE_IAL(ntp_server);
+ break;
+
+ /* XXX - Add new tags here */
default:
- return E_UNKNOWN_SYMBOL;
- }
- return SUCCESS;
-}
+ return E_UNKNOWN_SYMBOL;
+ } /* switch symbolcode */
+
+ return SUCCESS;
+}
+#undef PARSE_IA1
+#undef PARSE_IAL
+#undef PARSE_STR
+
+
/*
* Read a string from the buffer indirectly pointed to through "src" and
* move it into the buffer pointed to by "dest". A pointer to the maximum
@@ -1296,49 +1127,50 @@ struct host *hp;
* null-terminated.
*/
-PRIVATE char *get_string(src, dest, length)
-char **src, *dest;
-unsigned *length;
+PRIVATE char *
+get_string(src, dest, length)
+ char **src, *dest;
+ unsigned *length;
{
- int n, len, quoteflag;
-
- quoteflag = FALSE;
- n = 0;
- len = *length - 1;
- while ((n < len) && (**src)) {
- if (!quoteflag && (**src == ':')) {
- break;
- }
- if (**src == '"') {
- (*src)++;
- quoteflag = !quoteflag;
- continue;
+ int n, len, quoteflag;
+
+ quoteflag = FALSE;
+ n = 0;
+ len = *length - 1;
+ while ((n < len) && (**src)) {
+ if (!quoteflag && (**src == ':')) {
+ break;
+ }
+ if (**src == '"') {
+ (*src)++;
+ quoteflag = !quoteflag;
+ continue;
+ }
+ if (**src == '\\') {
+ (*src)++;
+ if (!**src) {
+ break;
+ }
+ }
+ *dest++ = *(*src)++;
+ n++;
}
- if (**src == '\\') {
- (*src)++;
- if (! **src) {
- break;
- }
+
+ /*
+ * Remove that troublesome trailing whitespace. . .
+ */
+ while ((n > 0) && isspace(dest[-1])) {
+ dest--;
+ n--;
}
- *dest++ = *(*src)++;
- n++;
- }
-
- /*
- * Remove that troublesome trailing whitespace. . .
- */
- while ((n > 0) && isspace(dest[-1])) {
- dest--;
- n--;
- }
-
- *dest = '\0';
- *length = n;
- return dest;
-}
+ *dest = '\0';
+ *length = n;
+ return dest;
+}
+
/*
* Read the string indirectly pointed to by "src", update the caller's
* pointer, and return a pointer to a malloc'ed shared_string structure
@@ -1347,26 +1179,27 @@ unsigned *length;
* The string is read using the same rules as get_string() above.
*/
-PRIVATE struct shared_string *get_shared_string(src)
-char **src;
+PRIVATE struct shared_string *
+get_shared_string(src)
+ char **src;
{
- char retstring[MAXSTRINGLEN];
- struct shared_string *s;
- unsigned length;
+ char retstring[MAXSTRINGLEN];
+ struct shared_string *s;
+ unsigned length;
- length = sizeof(retstring);
- (void) get_string(src, retstring, &length);
+ length = sizeof(retstring);
+ (void) get_string(src, retstring, &length);
- s = (struct shared_string *) smalloc(sizeof(struct shared_string)
- + length);
- s->linkcount = 1;
- strcpy(s->string, retstring);
+ s = (struct shared_string *) smalloc(sizeof(struct shared_string)
+ + length);
+ s->linkcount = 1;
+ strcpy(s->string, retstring);
- return s;
+ return s;
}
+
-
/*
* Load RFC1048 generic information directly into a memory buffer.
*
@@ -1383,53 +1216,57 @@ char **src;
* characters (the quotes are required).
*/
-PRIVATE void process_generic(src, dest, tagvalue)
-char **src;
-struct shared_bindata **dest;
-byte tagvalue;
+PRIVATE int
+process_generic(src, dest, tagvalue)
+ char **src;
+ struct shared_bindata **dest;
+ u_int tagvalue;
{
- byte tmpbuf[MAXBUFLEN];
- byte *str;
- struct shared_bindata *bdata;
- int newlength, oldlength;
-
- str = tmpbuf;
- *str++ = tagvalue; /* Store tag value */
- str++; /* Skip over length field */
- if ((*src)[0] == '"') { /* ASCII data */
- newlength = sizeof(tmpbuf) - 2; /* Set maximum allowed length */
- (void) get_string(src, str, &newlength);
- } else { /* Numeric data */
- newlength = 0;
- while (newlength < sizeof(tmpbuf) - 2) {
- if (interp_byte(src, str++) < 0) {
- break;
- } else {
- newlength++;
- }
- if (**src == '.') {
- (*src)++;
- }
- }
- }
- tmpbuf[1] = (byte) (newlength & 0xFF);
- oldlength = ((*dest)->length);
- bdata = (struct shared_bindata *) smalloc(sizeof(struct shared_bindata)
- + oldlength + newlength + 1);
- if (oldlength > 0) {
- bcopy((*dest)->data, bdata->data, oldlength);
- }
- bcopy(tmpbuf, bdata->data + oldlength, newlength + 2);
- bdata->length = oldlength + newlength + 2;
- bdata->linkcount = 1;
- if (*dest) {
- del_bindata(*dest);
- }
- *dest = bdata;
-}
+ byte tmpbuf[MAXBUFLEN];
+ byte *str;
+ struct shared_bindata *bdata;
+ u_int newlength, oldlength;
+
+ str = tmpbuf;
+ *str++ = (tagvalue & 0xFF); /* Store tag value */
+ str++; /* Skip over length field */
+ if ((*src)[0] == '"') { /* ASCII data */
+ newlength = sizeof(tmpbuf) - 2; /* Set maximum allowed length */
+ (void) get_string(src, (char *) str, &newlength);
+ newlength++; /* null terminator */
+ } else { /* Numeric data */
+ newlength = 0;
+ while (newlength < sizeof(tmpbuf) - 2) {
+ if (interp_byte(src, str++) < 0)
+ break;
+ newlength++;
+ if (**src == '.') {
+ (*src)++;
+ }
+ }
+ }
+ if ((*src)[0] != ':')
+ return -1;
+ tmpbuf[1] = (newlength & 0xFF);
+ oldlength = ((*dest)->length);
+ bdata = (struct shared_bindata *) smalloc(sizeof(struct shared_bindata)
+ + oldlength + newlength + 1);
+ if (oldlength > 0) {
+ bcopy((*dest)->data, bdata->data, oldlength);
+ }
+ bcopy(tmpbuf, bdata->data + oldlength, newlength + 2);
+ bdata->length = oldlength + newlength + 2;
+ bdata->linkcount = 1;
+ if (*dest) {
+ del_bindata(*dest);
+ }
+ *dest = bdata;
+ return 0;
+}
+
/*
* Verify that the given string makes sense as a hostname (according to
* Appendix 1, page 29 of RFC882).
@@ -1437,39 +1274,44 @@ byte tagvalue;
* Return TRUE for good names, FALSE otherwise.
*/
-PRIVATE boolean goodname(hostname)
-register char *hostname;
+PRIVATE boolean
+goodname(hostname)
+ register char *hostname;
{
- do {
- if (!isalpha(*hostname++)) { /* First character must be a letter */
- return FALSE;
- }
- while (isalnum(*hostname) || (*hostname == '-')) {
- hostname++; /* Alphanumeric or a hyphen */
- }
- if (!isalnum(hostname[-1])) { /* Last must be alphanumeric */
- return FALSE;
- }
- if (*hostname == '\0') { /* Done? */
- return TRUE;
- }
- } while (*hostname++ == '.'); /* Dot, loop for next label */
+ do {
+ if (!isalpha(*hostname++)) { /* First character must be a letter */
+ return FALSE;
+ }
+ while (isalnum(*hostname) ||
+ (*hostname == '-') ||
+ (*hostname == '_') )
+ {
+ hostname++; /* Alphanumeric or a hyphen */
+ }
+ if (!isalnum(hostname[-1])) { /* Last must be alphanumeric */
+ return FALSE;
+ }
+ if (*hostname == '\0') {/* Done? */
+ return TRUE;
+ }
+ } while (*hostname++ == '.'); /* Dot, loop for next label */
- return FALSE; /* If it's not a dot, lose */
+ return FALSE; /* If it's not a dot, lose */
}
-
+
/*
* Null compare function -- always returns FALSE so an element is always
* inserted into a hash table (i.e. there is never a collision with an
* existing element).
*/
-PRIVATE boolean nullcmp(host1, host2)
-struct host *host1, *host2;
+PRIVATE boolean
+nullcmp(d1, d2)
+ hash_datum *d1, *d2;
{
- return FALSE;
+ return FALSE;
}
@@ -1478,11 +1320,14 @@ struct host *host1, *host2;
* structure.
*/
-PRIVATE boolean nmcmp(name, hp)
-char *name;
-struct host *hp;
+boolean
+nmcmp(d1, d2)
+ hash_datum *d1, *d2;
{
- return !strcmp(name, hp->hostname->string);
+ char *name = (char *) d1; /* XXX - OK? */
+ struct host *hp = (struct host *) d2;
+
+ return !strcmp(name, hp->hostname->string);
}
@@ -1498,218 +1343,161 @@ struct host *hp;
* hash table.
*/
-PRIVATE boolean hwinscmp(host1, host2)
-struct host *host1, *host2;
+PRIVATE boolean
+hwinscmp(d1, d2)
+ hash_datum *d1, *d2;
{
- if (host1->htype != host2->htype) {
- return FALSE;
- }
- if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
- return FALSE;
- }
- if ((host1->subnet_mask.s_addr) == (host2->subnet_mask.s_addr)) {
- if (((host1->iaddr.s_addr) & (host1->subnet_mask.s_addr)) !=
- ((host2->iaddr.s_addr) & (host2->subnet_mask.s_addr))) {
- return FALSE;
+ struct host *host1 = (struct host *) d1;
+ struct host *host2 = (struct host *) d2;
+
+ if (host1->htype != host2->htype) {
+ return FALSE;
+ }
+ if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
+ return FALSE;
}
- }
- return TRUE;
+ /* XXX - Is the subnet_mask field set yet? */
+ if ((host1->subnet_mask.s_addr) == (host2->subnet_mask.s_addr)) {
+ if (((host1->iaddr.s_addr) & (host1->subnet_mask.s_addr)) !=
+ ((host2->iaddr.s_addr) & (host2->subnet_mask.s_addr)))
+ {
+ return FALSE;
+ }
+ }
+ return TRUE;
}
-
/*
+ * Macros for use in the function below:
+ */
+
+#define DUP_COPY(MEMBER) do \
+{ \
+ if (!hp->flags.MEMBER) { \
+ if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
+ hp->MEMBER = hp2->MEMBER; \
+ } \
+ } \
+} while (0)
+
+#define DUP_LINK(MEMBER) do \
+{ \
+ if (!hp->flags.MEMBER) { \
+ if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
+ assert(hp2->MEMBER); \
+ hp->MEMBER = hp2->MEMBER; \
+ (hp->MEMBER->linkcount)++; \
+ } \
+ } \
+} while (0)
+
+/*
* Process the "similar entry" symbol.
*
* The host specified as the value of the "tc" symbol is used as a template
* for the current host entry. Symbol values not explicitly set in the
* current host entry are inferred from the template entry.
*/
-
-PRIVATE void fill_defaults(hp, src)
-struct host *hp;
-char **src;
+PRIVATE void
+fill_defaults(hp, src)
+ struct host *hp;
+ char **src;
{
- unsigned tlen, hashcode;
- struct host *hp2, thp;
- char tstring[MAXSTRINGLEN];
-
- tlen = sizeof(tstring);
- (void) get_string(src, tstring, &tlen);
- if (goodname(tstring)) {
- hashcode = hash_HashFunction(tstring, tlen);
- hp2 = (struct host *) hash_Lookup(nmhashtable, hashcode, nmcmp,
- tstring);
- } else {
- thp.iaddr.s_addr = inet_addr(tstring);
- hashcode = hash_HashFunction(&(thp.iaddr.s_addr), 4);
- hp2 = (struct host *) hash_Lookup(iphashtable, hashcode, iplookcmp,
- &thp);
- }
- if (hp2 == NULL) {
- report(LOG_ERR, "can't find tc=\"%s\"\n", tstring);
- } else {
- /*
- * Assignments inside "if" conditionals are intended here.
- */
- if (!hp->flags.cookie_server) {
- if (hp->flags.cookie_server = hp2->flags.cookie_server) {
- hp->cookie_server = hp2->cookie_server;
- (hp->cookie_server->linkcount)++;
- }
- }
- if (!hp->flags.domain_server) {
- if (hp->flags.domain_server = hp2->flags.domain_server) {
- hp->domain_server = hp2->domain_server;
- (hp->domain_server->linkcount)++;
- }
- }
- if (!hp->flags.gateway) {
- if (hp->flags.gateway = hp2->flags.gateway) {
- hp->gateway = hp2->gateway;
- (hp->gateway->linkcount)++;
- }
- }
- if (!hp->flags.impress_server) {
- if (hp->flags.impress_server = hp2->flags.impress_server) {
- hp->impress_server = hp2->impress_server;
- (hp->impress_server->linkcount)++;
- }
- }
- if (!hp->flags.log_server) {
- if (hp->flags.log_server = hp2->flags.log_server) {
- hp->log_server = hp2->log_server;
- (hp->log_server->linkcount)++;
- }
- }
- if (!hp->flags.lpr_server) {
- if (hp->flags.lpr_server = hp2->flags.lpr_server) {
- hp->lpr_server = hp2->lpr_server;
- (hp->lpr_server->linkcount)++;
- }
+ unsigned int tlen, hashcode;
+ struct host *hp2;
+ char tstring[MAXSTRINGLEN];
+
+ tlen = sizeof(tstring);
+ (void) get_string(src, tstring, &tlen);
+ hashcode = hash_HashFunction((u_char *) tstring, tlen);
+ hp2 = (struct host *) hash_Lookup(nmhashtable, hashcode, nmcmp, tstring);
+
+ if (hp2 == NULL) {
+ report(LOG_ERR, "can't find tc=\"%s\"", tstring);
+ return;
}
- if (!hp->flags.name_server) {
- if (hp->flags.name_server = hp2->flags.name_server) {
- hp->name_server = hp2->name_server;
- (hp->name_server->linkcount)++;
- }
- }
- if (!hp->flags.rlp_server) {
- if (hp->flags.rlp_server = hp2->flags.rlp_server) {
- hp->rlp_server = hp2->rlp_server;
- (hp->rlp_server->linkcount)++;
- }
- }
- if (!hp->flags.time_server) {
- if (hp->flags.time_server = hp2->flags.time_server) {
- hp->time_server = hp2->time_server;
- (hp->time_server->linkcount)++;
- }
- }
- if (!hp->flags.homedir) {
- if (hp->flags.homedir = hp2->flags.homedir) {
- hp->homedir = hp2->homedir;
- (hp->homedir->linkcount)++;
- }
- }
- if (!hp->flags.bootfile) {
- if (hp->flags.bootfile = hp2->flags.bootfile) {
- hp->bootfile = hp2->bootfile;
- (hp->bootfile->linkcount)++;
- }
- }
- if (!hp->flags.generic) {
- if (hp->flags.generic = hp2->flags.generic) {
- hp->generic = hp2->generic;
- (hp->generic->linkcount)++;
- }
- }
- if (!hp->flags.vendor_magic) {
- hp->flags.vm_auto = hp2->flags.vm_auto;
- if (hp->flags.vendor_magic = hp2->flags.vendor_magic) {
- bcopy(hp2->vm_cookie, hp->vm_cookie, 4);
- }
+ DUP_LINK(bootfile);
+ DUP_LINK(cookie_server);
+ DUP_LINK(domain_server);
+ DUP_LINK(gateway);
+ /* haddr not copied */
+ DUP_LINK(homedir);
+ DUP_COPY(htype);
+
+ DUP_LINK(impress_server);
+ /* iaddr not copied */
+ DUP_LINK(log_server);
+ DUP_LINK(lpr_server);
+ DUP_LINK(name_server);
+ DUP_LINK(rlp_server);
+
+ DUP_COPY(subnet_mask);
+ DUP_COPY(time_offset);
+ DUP_LINK(time_server);
+
+ if (!hp->flags.vm_cookie) {
+ if ((hp->flags.vm_cookie = hp2->flags.vm_cookie)) {
+ bcopy(hp2->vm_cookie, hp->vm_cookie, 4);
+ }
}
if (!hp->flags.name_switch) {
- if (hp->flags.name_switch = hp2->flags.name_switch) {
- hp->flags.send_name = hp2->flags.send_name;
- }
- }
- if (!hp->flags.htype) {
- if (hp->flags.htype = hp2->flags.htype) {
- hp->htype = hp2->htype;
- }
- }
- if (!hp->flags.time_offset) {
- if (hp->flags.time_offset = hp2->flags.time_offset) {
- hp->flags.timeoff_auto = hp2->flags.timeoff_auto;
- hp->time_offset = hp2->time_offset;
- }
- }
- if (!hp->flags.subnet_mask) {
- if (hp->flags.subnet_mask = hp2->flags.subnet_mask) {
- hp->subnet_mask.s_addr = hp2->subnet_mask.s_addr;
- }
- }
- if (!hp->flags.swap_server) {
- if (hp->flags.swap_server = hp2->flags.swap_server) {
- hp->swapserver.s_addr = hp2->swapserver.s_addr;
- }
+ if ((hp->flags.name_switch = hp2->flags.name_switch)) {
+ hp->flags.send_name = hp2->flags.send_name;
+ }
}
if (!hp->flags.bootsize) {
- if (hp->flags.bootsize = hp2->flags.bootsize) {
- hp->flags.bootsize_auto = hp2->flags.bootsize_auto;
- hp->bootsize = hp2->bootsize;
- }
- }
- if (!hp->flags.tftpdir) {
- if (hp->flags.tftpdir = hp2->flags.tftpdir) {
- hp->tftpdir = hp2->tftpdir;
- (hp->tftpdir->linkcount)++;
- }
- }
- if (!hp->flags.rootpath) {
- if (hp->flags.rootpath = hp2->flags.rootpath) {
- hp->rootpath = hp2->rootpath;
- (hp->rootpath->linkcount)++;
- }
- }
- if (!hp->flags.domainname) {
- if (hp->flags.domainname = hp2->flags.domainname) {
- hp->domainname = hp2->domainname;
- (hp->domainname->linkcount)++;
- }
- }
- if (!hp->flags.dumpfile) {
- if (hp->flags.dumpfile = hp2->flags.dumpfile) {
- hp->dumpfile = hp2->dumpfile;
- (hp->dumpfile->linkcount)++;
- }
+ if ((hp->flags.bootsize = hp2->flags.bootsize)) {
+ hp->flags.bootsize_auto = hp2->flags.bootsize_auto;
+ hp->bootsize = hp2->bootsize;
+ }
}
- }
-}
+ DUP_COPY(bootserver);
+
+ DUP_LINK(tftpdir);
+ DUP_LINK(dump_file);
+ DUP_LINK(domain_name);
+
+ DUP_COPY(swap_server);
+ DUP_LINK(root_path);
+ DUP_LINK(exten_file);
+
+ DUP_COPY(reply_addr);
+
+ DUP_LINK(nis_domain);
+ DUP_LINK(nis_server);
+ DUP_LINK(ntp_server);
+
+ /* XXX - Add new tags here */
+ DUP_LINK(generic);
+
+}
+#undef DUP_COPY
+#undef DUP_LINK
+
/*
* This function adjusts the caller's pointer to point just past the
* first-encountered colon. If it runs into a null character, it leaves
* the pointer pointing to it.
*/
-PRIVATE void adjust(s)
-char **s;
+PRIVATE void
+adjust(s)
+ char **s;
{
- register char *t;
-
- t = *s;
- while (*t && (*t != ':')) {
- t++;
- }
- if (*t) {
- t++;
- }
- *s = t;
+ register char *t;
+
+ t = *s;
+ while (*t && (*t != ':')) {
+ t++;
+ }
+ if (*t) {
+ t++;
+ }
+ *s = t;
}
@@ -1721,16 +1509,17 @@ char **s;
* the pointer pointing to it.
*/
-PRIVATE void eat_whitespace(s)
-char **s;
+PRIVATE void
+eat_whitespace(s)
+ char **s;
{
- register char *t;
+ register char *t;
- t = *s;
- while (*t && isspace(*t)) {
- t++;
- }
- *s = t;
+ t = *s;
+ while (*t && isspace(*t)) {
+ t++;
+ }
+ *s = t;
}
@@ -1739,19 +1528,20 @@ char **s;
* This function converts the given string to all lowercase.
*/
-PRIVATE void makelower(s)
-char *s;
+PRIVATE void
+makelower(s)
+ char *s;
{
- while (*s) {
- if (isupper(*s)) {
- *s = tolower(*s);
+ while (*s) {
+ if (isupper(*s)) {
+ *s = tolower(*s);
+ }
+ s++;
}
- s++;
- }
}
-
+
/*
*
* N O T E :
@@ -1765,12 +1555,12 @@ char *s;
* parameter.
*
* I'm sure somebody out there won't like this. . . .
- *
+ * (Yea, because it usually makes code slower... -gwr)
*
*/
-
+
/*
* "src" points to a character pointer which points to an ASCII string of
* whitespace-separated IP addresses. A pointer to an in_addr_list
@@ -1779,48 +1569,49 @@ char *s;
* "src" is updated to point to the first non-address (illegal) character.
*/
-PRIVATE struct in_addr_list *get_addresses(src)
-char **src;
+PRIVATE struct in_addr_list *
+get_addresses(src)
+ char **src;
{
- struct in_addr tmpaddrlist[MAXINADDRS];
- struct in_addr *address1, *address2;
- struct in_addr_list *result;
- unsigned addrcount, totalsize;
-
- address1 = tmpaddrlist;
- for (addrcount = 0; addrcount < MAXINADDRS; addrcount++) {
- while (**src && isspace(**src)) { /* Skip whitespace */
- (*src)++;
- }
- if (! **src) { /* Quit if nothing more */
- break;
- }
- if (prs_inetaddr(src, &(address1->s_addr)) < 0) {
- break;
- }
- address1++; /* Point to next address slot */
- }
- if (addrcount < 1) {
- result = NULL;
- } else {
- totalsize = sizeof(struct in_addr_list)
- + (addrcount - 1) * sizeof(struct in_addr);
- result = (struct in_addr_list *) smalloc(totalsize);
- result->linkcount = 1;
- result->addrcount = addrcount;
+ struct in_addr tmpaddrlist[MAXINADDRS];
+ struct in_addr *address1, *address2;
+ struct in_addr_list *result;
+ unsigned addrcount, totalsize;
+
address1 = tmpaddrlist;
- address2 = result->addr;
- for (; addrcount > 0; addrcount--) {
- address2->s_addr = address1->s_addr;
- address1++;
- address2++;
+ for (addrcount = 0; addrcount < MAXINADDRS; addrcount++) {
+ while (isspace(**src) || (**src == ',')) {
+ (*src)++;
+ }
+ if (!**src) { /* Quit if nothing more */
+ break;
+ }
+ if (prs_inetaddr(src, &(address1->s_addr)) < 0) {
+ break;
+ }
+ address1++; /* Point to next address slot */
}
- }
- return result;
+ if (addrcount < 1) {
+ result = NULL;
+ } else {
+ totalsize = sizeof(struct in_addr_list)
+ + (addrcount - 1) * sizeof(struct in_addr);
+ result = (struct in_addr_list *) smalloc(totalsize);
+ result->linkcount = 1;
+ result->addrcount = addrcount;
+ address1 = tmpaddrlist;
+ address2 = result->addr;
+ for (; addrcount > 0; addrcount--) {
+ address2->s_addr = address1->s_addr;
+ address1++;
+ address2++;
+ }
+ }
+ return result;
}
-
+
/*
* prs_inetaddr(src, result)
*
@@ -1835,69 +1626,92 @@ char **src;
* to by "result" is unchanged. Successful calls return 0.
*/
-PRIVATE prs_inetaddr(src, result)
-char **src;
-u_long *result;
+PRIVATE int
+prs_inetaddr(src, result)
+ char **src;
+ u_int32 *result;
{
- register u_long value;
- u_long parts[4], *pp = parts;
- int n;
-
- if (!isdigit(**src)) {
- return -1;
- }
-loop:
- value = get_u_long(src);
- if (**src == '.') {
+ char tmpstr[MAXSTRINGLEN];
+ register u_int32 value;
+ u_int32 parts[4], *pp;
+ int n;
+ char *s, *t;
+
+#if 1 /* XXX - experimental */
+ /* Leading alpha char causes IP addr lookup. */
+ if (isalpha(**src)) {
+ /* Lookup IP address. */
+ s = *src;
+ t = tmpstr;
+ while ((isalnum(*s) || (*s == '.') ||
+ (*s == '-') || (*s == '_') ) &&
+ (t < &tmpstr[MAXSTRINGLEN - 1]) )
+ *t++ = *s++;
+ *t = '\0';
+ *src = s;
+
+ n = lookup_ipa(tmpstr, result);
+ if (n < 0)
+ report(LOG_ERR, "can not get IP addr for %s", tmpstr);
+ return n;
+ }
+#endif
+
/*
- * Internet format:
+ * Parse an address in Internet format:
* a.b.c.d
* a.b.c (with c treated as 16-bits)
* a.b (with b treated as 24 bits)
*/
- if (pp >= parts + 4) {
- return (-1);
+ pp = parts;
+ loop:
+ /* If it's not a digit, return error. */
+ if (!isdigit(**src))
+ return -1;
+ *pp++ = get_u_long(src);
+ if (**src == '.') {
+ if (pp < (parts + 4)) {
+ (*src)++;
+ goto loop;
+ }
+ return (-1);
}
- *pp++ = value;
- (*src)++;
- goto loop;
- }
- /*
- * Check for trailing characters.
- */
- if (**src && !(isspace(**src) || (**src == ':'))) {
- return (-1);
- }
- *pp++ = value;
- /*
- * Construct the address according to
- * the number of parts specified.
- */
- n = pp - parts;
- switch (n) {
- case 1: /* a -- 32 bits */
- value = parts[0];
- break;
- case 2: /* a.b -- 8.24 bits */
- value = (parts[0] << 24) | (parts[1] & 0xFFFFFF);
- break;
- case 3: /* a.b.c -- 8.8.16 bits */
- value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
- (parts[2] & 0xFFFF);
- break;
- case 4: /* a.b.c.d -- 8.8.8.8 bits */
- value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
- ((parts[2] & 0xFF) << 8) | (parts[3] & 0xFF);
- break;
+#if 0
+ /* This is handled by the caller. */
+ if (**src && !(isspace(**src) || (**src == ':'))) {
+ return (-1);
+ }
+#endif
+
+ /*
+ * Construct the address according to
+ * the number of parts specified.
+ */
+ n = pp - parts;
+ switch (n) {
+ case 1: /* a -- 32 bits */
+ value = parts[0];
+ break;
+ case 2: /* a.b -- 8.24 bits */
+ value = (parts[0] << 24) | (parts[1] & 0xFFFFFF);
+ break;
+ case 3: /* a.b.c -- 8.8.16 bits */
+ value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
+ (parts[2] & 0xFFFF);
+ break;
+ case 4: /* a.b.c.d -- 8.8.8.8 bits */
+ value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
+ ((parts[2] & 0xFF) << 8) | (parts[3] & 0xFF);
+ break;
default:
- return (-1);
- }
- *result = htonl(value);
- return (0);
+ return (-1);
+ }
+ *result = htonl(value);
+ return (0);
}
-
+
/*
* "src" points to a pointer which in turn points to a hexadecimal ASCII
* string. This string is interpreted as a hardware address and returned
@@ -1914,29 +1728,51 @@ loop:
* function returns a NULL pointer.
*/
-PRIVATE byte *prs_haddr(src, htype)
-char **src;
-byte htype;
+PRIVATE byte *
+prs_haddr(src, htype)
+ char **src;
+ u_int htype;
{
- static byte haddr[MAXHADDRLEN];
- byte *hptr;
- unsigned hlen;
-
- hlen = haddrlength(htype); /* Get length of this address type */
- hptr = haddr;
- while (hptr < haddr + hlen) {
- if (**src == '.') {
- (*src)++;
+ static byte haddr[MAXHADDRLEN];
+ byte *hap;
+ char tmpstr[MAXSTRINGLEN];
+ u_int tmplen;
+ unsigned hal;
+ char *p;
+
+ hal = haddrlength(htype); /* Get length of this address type */
+ if (hal <= 0) {
+ report(LOG_ERR, "Invalid addr type for HW addr parse");
+ return NULL;
}
- if (interp_byte(src, hptr++) < 0) {
- return NULL;
+ tmplen = sizeof(tmpstr);
+ get_string(src, tmpstr, &tmplen);
+ p = tmpstr;
+
+#if 1 /* XXX - experimental */
+ /* If it's a valid host name, try to lookup the HW address. */
+ if (goodname(p)) {
+ /* Lookup Hardware Address for hostname. */
+ if ((hap = lookup_hwa(p, htype)) != NULL)
+ return hap; /* success */
+ report(LOG_ERR, "Add 0x prefix if hex value starts with A-F");
+ /* OK, assume it must be numeric. */
}
- }
- return haddr;
-}
+#endif
+ hap = haddr;
+ while (hap < haddr + hal) {
+ if (*p == '.')
+ p++;
+ if (interp_byte(&p, hap++) < 0) {
+ return NULL;
+ }
+ }
+ return haddr;
+}
+
/*
* "src" is a pointer to a character pointer which in turn points to a
* hexadecimal ASCII representation of a byte. This byte is read, the
@@ -1949,28 +1785,31 @@ byte htype;
* Successful calls return 0.
*/
-PRIVATE int interp_byte(src, retbyte)
-char **src;
-byte *retbyte;
+PRIVATE int
+interp_byte(src, retbyte)
+ char **src;
+ byte *retbyte;
{
- int v;
-
- if ((*src)[0] == '0' && (*src)[1] == 'x' || (*src)[1] == 'X') {
- (*src) += 2; /* allow 0x for hex, but don't require it */
- }
- if (!isxdigit((*src)[0]) || !isxdigit((*src)[1])) {
- return -1;
- }
- if (sscanf(*src, "%2x", &v) != 1) {
- return -1;
- }
- (*src) += 2;
- *retbyte = (byte) (v & 0xFF);
- return 0;
-}
+ int v;
+ if ((*src)[0] == '0' &&
+ ((*src)[1] == 'x' ||
+ (*src)[1] == 'X')) {
+ (*src) += 2; /* allow 0x for hex, but don't require it */
+ }
+ if (!isxdigit((*src)[0]) || !isxdigit((*src)[1])) {
+ return -1;
+ }
+ if (sscanf(*src, "%2x", &v) != 1) {
+ return -1;
+ }
+ (*src) += 2;
+ *retbyte = (byte) (v & 0xFF);
+ return 0;
+}
+
/*
* The parameter "src" points to a character pointer which points to an
* ASCII string representation of an unsigned number. The number is
@@ -1978,42 +1817,45 @@ byte *retbyte;
* point to the first illegal character.
*/
-PRIVATE u_long get_u_long(src)
-char **src;
+PRIVATE u_int32
+get_u_long(src)
+ char **src;
{
- register u_long value, base;
- char c;
-
- /*
- * Collect number up to first illegal character. Values are specified
- * as for C: 0x=hex, 0=octal, other=decimal.
- */
- value = 0;
- base = 10;
- if (**src == '0') {
- base = 8, (*src)++;
- }
- if (**src == 'x' || **src == 'X') {
- base = 16, (*src)++;
- }
- while (c = **src) {
- if (isdigit(c)) {
- value = (value * base) + (c - '0');
- (*src)++;
- continue;
+ register u_int32 value, base;
+ char c;
+
+ /*
+ * Collect number up to first illegal character. Values are specified
+ * as for C: 0x=hex, 0=octal, other=decimal.
+ */
+ value = 0;
+ base = 10;
+ if (**src == '0') {
+ base = 8;
+ (*src)++;
+ }
+ if (**src == 'x' || **src == 'X') {
+ base = 16;
+ (*src)++;
}
- if (base == 16 && isxdigit(c)) {
- value = (value << 4) + ((c & ~32) + 10 - 'A');
- (*src)++;
- continue;
+ while ((c = **src)) {
+ if (isdigit(c)) {
+ value = (value * base) + (c - '0');
+ (*src)++;
+ continue;
+ }
+ if (base == 16 && isxdigit(c)) {
+ value = (value << 4) + ((c & ~32) + 10 - 'A');
+ (*src)++;
+ continue;
+ }
+ break;
}
- break;
- }
- return value;
+ return value;
}
-
+
/*
* Routines for deletion of data associated with the main data structure.
*/
@@ -2024,10 +1866,16 @@ char **src;
* pointer is NULL.
*/
-PRIVATE void free_host(hostptr)
-struct host *hostptr;
+PRIVATE void
+free_host(hmp)
+ hash_datum *hmp;
{
- if (hostptr) {
+ struct host *hostptr = (struct host *) hmp;
+ if (hostptr == NULL)
+ return;
+ assert(hostptr->linkcount > 0);
+ if (--(hostptr->linkcount))
+ return; /* Still has references */
del_iplist(hostptr->cookie_server);
del_iplist(hostptr->domain_server);
del_iplist(hostptr->gateway);
@@ -2037,33 +1885,49 @@ struct host *hostptr;
del_iplist(hostptr->name_server);
del_iplist(hostptr->rlp_server);
del_iplist(hostptr->time_server);
+ del_iplist(hostptr->nis_server);
+ del_iplist(hostptr->ntp_server);
+
+ /*
+ * XXX - Add new tags here
+ * (if the value is an IP list)
+ */
+
del_string(hostptr->hostname);
del_string(hostptr->homedir);
del_string(hostptr->bootfile);
del_string(hostptr->tftpdir);
- del_string(hostptr->rootpath);
- del_string(hostptr->domainname);
- del_string(hostptr->dumpfile);
+ del_string(hostptr->root_path);
+ del_string(hostptr->domain_name);
+ del_string(hostptr->dump_file);
+ del_string(hostptr->exten_file);
+ del_string(hostptr->nis_domain);
+
+ /*
+ * XXX - Add new tags here
+ * (if it is a shared string)
+ */
+
del_bindata(hostptr->generic);
free((char *) hostptr);
- }
}
-
+
/*
* Decrements the linkcount on the given IP address data structure. If the
* linkcount goes to zero, the memory associated with the data is freed.
*/
-PRIVATE void del_iplist(iplist)
-struct in_addr_list *iplist;
+PRIVATE void
+del_iplist(iplist)
+ struct in_addr_list *iplist;
{
- if (iplist) {
- if (! (--(iplist->linkcount))) {
- free((char *) iplist);
+ if (iplist) {
+ if (!(--(iplist->linkcount))) {
+ free((char *) iplist);
+ }
}
- }
}
@@ -2074,14 +1938,15 @@ struct in_addr_list *iplist;
* nothing if the passed pointer is NULL.
*/
-PRIVATE void del_string(stringptr)
-struct shared_string *stringptr;
+PRIVATE void
+del_string(stringptr)
+ struct shared_string *stringptr;
{
- if (stringptr) {
- if (! (--(stringptr->linkcount))) {
- free((char *) stringptr);
+ if (stringptr) {
+ if (!(--(stringptr->linkcount))) {
+ free((char *) stringptr);
+ }
}
- }
}
@@ -2092,18 +1957,19 @@ struct shared_string *stringptr;
* nothing if the passed pointer is NULL.
*/
-PRIVATE void del_bindata(dataptr)
-struct shared_bindata *dataptr;
+PRIVATE void
+del_bindata(dataptr)
+ struct shared_bindata *dataptr;
{
- if (dataptr) {
- if (! (--(dataptr->linkcount))) {
- free((char *) dataptr);
+ if (dataptr) {
+ if (!(--(dataptr->linkcount))) {
+ free((char *) dataptr);
+ }
}
- }
}
+
-
/* smalloc() -- safe malloc()
*
@@ -2113,16 +1979,70 @@ struct shared_bindata *dataptr;
* with a status of 1.
*/
-PRIVATE char *smalloc(nbytes)
-unsigned nbytes;
+PRIVATE char *
+smalloc(nbytes)
+ unsigned nbytes;
+{
+ char *retvalue;
+
+ retvalue = malloc(nbytes);
+ if (!retvalue) {
+ report(LOG_ERR, "malloc() failure -- exiting");
+ exit(1);
+ }
+ bzero(retvalue, nbytes);
+ return retvalue;
+}
+
+
+/*
+ * Compare function to determine whether two hardware addresses are
+ * equivalent. Returns TRUE if "host1" and "host2" are equivalent, FALSE
+ * otherwise.
+ *
+ * This function is used when retrieving elements from the hardware address
+ * hash table.
+ */
+
+boolean
+hwlookcmp(d1, d2)
+ hash_datum *d1, *d2;
{
- char *retvalue;
-
- retvalue = malloc(nbytes);
- if (!retvalue) {
- report(LOG_ERR, "malloc() failure -- exiting\n");
- exit(1);
- }
- bzero(retvalue, nbytes);
- return retvalue;
+ struct host *host1 = (struct host *) d1;
+ struct host *host2 = (struct host *) d2;
+
+ if (host1->htype != host2->htype) {
+ return FALSE;
+ }
+ if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
+ return FALSE;
+ }
+ return TRUE;
}
+
+
+/*
+ * Compare function for doing IP address hash table lookup.
+ */
+
+boolean
+iplookcmp(d1, d2)
+ hash_datum *d1, *d2;
+{
+ struct host *host1 = (struct host *) d1;
+ struct host *host2 = (struct host *) d2;
+
+ return (host1->iaddr.s_addr == host2->iaddr.s_addr);
+}
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/libexec/bootpd/readfile.h b/libexec/bootpd/readfile.h
new file mode 100644
index 00000000000..3913455857c
--- /dev/null
+++ b/libexec/bootpd/readfile.h
@@ -0,0 +1,19 @@
+/* readfile.h */
+
+#include "bptypes.h"
+#include "hash.h"
+
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+extern boolean hwlookcmp P((hash_datum *, hash_datum *));
+extern boolean iplookcmp P((hash_datum *, hash_datum *));
+extern boolean nmcmp P((hash_datum *, hash_datum *));
+extern void readtab P((int));
+extern void rdtab_init P((void));
+
+#undef P
+
diff --git a/libexec/bootpd/report.c b/libexec/bootpd/report.c
new file mode 100644
index 00000000000..4f7f03616a2
--- /dev/null
+++ b/libexec/bootpd/report.c
@@ -0,0 +1,154 @@
+/*
+ * report() - calls syslog
+ */
+
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#include <stdio.h>
+#include <syslog.h>
+
+#include "report.h"
+
+#ifndef LOG_NDELAY
+#define LOG_NDELAY 0
+#endif
+#ifndef LOG_DAEMON
+#define LOG_DAEMON 0
+#endif
+#ifndef LOG_BOOTP
+#define LOG_BOOTP LOG_DAEMON
+#endif
+
+extern int debug;
+extern char *progname;
+
+/*
+ * This is initialized so you get stderr until you call
+ * report_init()
+ */
+static int stderr_only = 1;
+
+void
+report_init(nolog)
+ int nolog;
+{
+ stderr_only = nolog;
+#ifdef SYSLOG
+ if (!stderr_only) {
+ openlog(progname, LOG_PID | LOG_NDELAY, LOG_BOOTP);
+ }
+#endif
+}
+
+/*
+ * This routine reports errors and such via stderr and syslog() if
+ * appopriate. It just helps avoid a lot of "#ifdef SYSLOG" constructs
+ * from being scattered throughout the code.
+ *
+ * The syntax is identical to syslog(3), but %m is not considered special
+ * for output to stderr (i.e. you'll see "%m" in the output. . .). Also,
+ * control strings should normally end with \n since newlines aren't
+ * automatically generated for stderr output (whereas syslog strips out all
+ * newlines and adds its own at the end).
+ */
+
+static char *levelnames[] = {
+#ifdef LOG_SALERT
+ "level(0): ",
+ "alert(1): ",
+ "alert(2): ",
+ "emerg(3): ",
+ "error(4): ",
+ "crit(5): ",
+ "warn(6): ",
+ "note(7): ",
+ "info(8): ",
+ "debug(9): ",
+ "level(?): "
+#else
+ "emerg(0): ",
+ "alert(1): ",
+ "crit(2): ",
+ "error(3): ",
+ "warn(4): ",
+ "note(5): ",
+ "info(6): ",
+ "debug(7): ",
+ "level(?): "
+#endif
+};
+static int numlevels = sizeof(levelnames) / sizeof(levelnames[0]);
+
+
+/*
+ * Print a log message using syslog(3) and/or stderr.
+ * The message passed in should not include a newline.
+ */
+#ifdef __STDC__
+void
+report(int priority, char *fmt,...)
+#else
+/*VARARGS2*/
+void
+report(priority, fmt, va_alist)
+ int priority;
+ char *fmt;
+ va_dcl
+#endif
+{
+ va_list ap;
+ static char buf[128];
+
+ if ((priority < 0) || (priority >= numlevels)) {
+ priority = numlevels - 1;
+ }
+#ifdef __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ vsprintf(buf, fmt, ap);
+ va_end(ap);
+
+ /*
+ * Print the message
+ */
+ if (stderr_only || (debug > 2)) {
+ fprintf(stderr, "%s: %s %s\n",
+ progname, levelnames[priority], buf);
+ }
+#ifdef SYSLOG
+ if (!stderr_only)
+ syslog((priority | LOG_BOOTP), "%s", buf);
+#endif
+}
+
+
+
+/*
+ * Return pointer to static string which gives full filesystem error message.
+ */
+char *
+get_errmsg()
+{
+ extern int errno;
+ extern char *strerror();
+
+ return strerror(errno);
+}
+
+/*
+ * Local Variables:
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-argdecl-indent: 4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: -4
+ * c-label-offset: -4
+ * c-brace-offset: 0
+ * End:
+ */
diff --git a/libexec/bootpd/report.h b/libexec/bootpd/report.h
new file mode 100644
index 00000000000..0bf63d60fbb
--- /dev/null
+++ b/libexec/bootpd/report.h
@@ -0,0 +1,13 @@
+/* report.h */
+
+#ifdef __STDC__
+#define P(args) args
+#else
+#define P(args) ()
+#endif
+
+extern void report_init P((int nolog));
+extern void report P((int, char *, ...));
+extern char *get_errmsg P((void));
+
+#undef P
diff --git a/libexec/bootpd/syslog.conf b/libexec/bootpd/syslog.conf
new file mode 100644
index 00000000000..2c135af4974
--- /dev/null
+++ b/libexec/bootpd/syslog.conf
@@ -0,0 +1,63 @@
+#
+# syslog configuration file for SunOS 4.X
+# (modified to do local2 separately)
+#
+# This file is processed by m4 so be careful to quote (`') names
+# that match m4 reserved words. Also, within ifdef's, arguments
+# containing commas must be quoted.
+#
+# Note: Have to exclude user from most lines so that user.alert
+# and user.emerg are not included, because old sendmails
+# will generate them for debugging information. If you
+# have no 4.2BSD based systems doing network logging, you
+# can remove all the special cases for "user" logging.
+
+#*.err;kern.debug;auth.notice;user.none /dev/console
+kern.debug;user,mail.crit;auth.notice /dev/console
+daemon,syslog,lpr,news,uucp,cron.err /dev/console
+
+#*.err;kern.debug;daemon,auth.notice;mail.crit;user.none /var/adm/messages
+kern.debug;user,mail.crit;auth.notice /var/adm/messages
+daemon.notice;syslog,news,uucp,cron.err /var/adm/messages
+
+lpr.debug /var/adm/lpd-errs
+
+*.alert;kern.err;daemon.err;user.none operator
+*.alert;user.none root
+
+*.emerg;user.none *
+
+# for loghost machines, to have authentication messages (su, login, etc.)
+# logged to a file, un-comment out the following line and adjust the file name
+# as appropriate.
+#
+# if a non-loghost machine chooses to have such messages
+# sent to the loghost machine, un-comment out the following line.
+#
+#auth.notice ifdef(`LOGHOST', /var/log/authlog, @loghost)
+
+mail.debug ifdef(`LOGHOST', /var/log/syslog, @loghost)
+
+# following line for compatibility with old sendmails. they will send
+# messages with no facility code, which will be turned into "user" messages
+# by the local syslog daemon. only the "loghost" machine needs the following
+# line, to cause these old sendmail log messages to be logged in the
+# mail syslog file.
+#
+ifdef(`LOGHOST',
+user.alert /var/log/syslog
+)
+#
+# non-loghost machines will use the following lines to cause "user"
+# log messages to be logged locally.
+#
+ifdef(`LOGHOST', ,
+user.err /dev/console
+user.err /var/adm/messages
+user.alert `root, operator'
+user.emerg *
+)
+
+# Local2: (bootpd, pppd)
+local2.debug /dev/console
+#local2.debug /var/log/local2
diff --git a/libexec/bootpd/syslog.h b/libexec/bootpd/syslog.h
new file mode 100644
index 00000000000..90d233fe612
--- /dev/null
+++ b/libexec/bootpd/syslog.h
@@ -0,0 +1,25 @@
+/*
+ * Fake syslog.h for systems without it (just defines priorities).
+ * To use this, compile with: -I/usr/include -I.
+ */
+
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+/*
+ * Priorities (these are ordered)
+ */
+#define LOG_EMERG 0 /* system is unusable */
+#define LOG_ALERT 1 /* action must be taken immediately */
+#define LOG_CRIT 2 /* critical conditions */
+#define LOG_ERR 3 /* error conditions */
+#define LOG_WARNING 4 /* warning conditions */
+#define LOG_NOTICE 5 /* normal but signification condition */
+#define LOG_INFO 6 /* informational */
+#define LOG_DEBUG 7 /* debug-level messages */
+
+/* XXX - Just in case: */
+#define openlog fake_syslog_openlog
diff --git a/libexec/bootpd/trygetea.c b/libexec/bootpd/trygetea.c
new file mode 100644
index 00000000000..e9314aede96
--- /dev/null
+++ b/libexec/bootpd/trygetea.c
@@ -0,0 +1,46 @@
+/*
+ * trygetea.c - test program for getether.c
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#if defined(SUNOS) || defined(SVR4)
+#include <sys/sockio.h>
+#endif
+
+#include <net/if.h> /* for struct ifreq */
+#include <netinet/in.h>
+#include <arpa/inet.h> /* inet_ntoa */
+
+#include <netdb.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+
+int debug = 0;
+char *progname;
+
+main(argc, argv)
+ char **argv;
+{
+ u_char ea[16]; /* Ethernet address */
+ int i;
+
+ progname = argv[0]; /* for report */
+
+ if (argc < 2) {
+ printf("need interface name\n");
+ exit(1);
+ }
+ if ((i = getether(argv[1], ea)) < 0) {
+ printf("Could not get Ethernet address (rc=%d)\n", i);
+ exit(1);
+ }
+ printf("Ether-addr");
+ for (i = 0; i < 6; i++)
+ printf(":%x", ea[i] & 0xFF);
+ printf("\n");
+
+ exit(0);
+}
diff --git a/libexec/bootpd/trygetif.c b/libexec/bootpd/trygetif.c
new file mode 100644
index 00000000000..c6bb098ab03
--- /dev/null
+++ b/libexec/bootpd/trygetif.c
@@ -0,0 +1,68 @@
+/*
+ * trygetif.c - test program for getif.c
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#if defined(SUNOS) || defined(SVR4)
+#include <sys/sockio.h>
+#endif
+
+#include <net/if.h> /* for struct ifreq */
+#include <netinet/in.h>
+#include <arpa/inet.h> /* inet_ntoa */
+
+#include <netdb.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "getif.h"
+
+int debug = 0;
+char *progname;
+
+main(argc, argv)
+ char **argv;
+{
+ struct hostent *hep;
+ struct sockaddr ea; /* Ethernet address */
+ struct sockaddr_in *sip; /* Interface address */
+ struct ifreq *ifr;
+ struct in_addr dst_addr;
+ struct in_addr *dap;
+ int i, s;
+
+ progname = argv[0]; /* for report */
+
+ dap = NULL;
+ if (argc > 1) {
+ dap = &dst_addr;
+ if (isdigit(argv[1][0]))
+ dst_addr.s_addr = inet_addr(argv[1]);
+ else {
+ hep = gethostbyname(argv[1]);
+ if (!hep) {
+ printf("gethostbyname(%s)\n", argv[1]);
+ exit(1);
+ }
+ memcpy(&dst_addr, hep->h_addr, sizeof(dst_addr));
+ }
+ }
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket open");
+ exit(1);
+ }
+ ifr = getif(s, dap);
+ if (!ifr) {
+ printf("no interface for address\n");
+ exit(1);
+ }
+ printf("Intf-name:%s\n", ifr->ifr_name);
+ sip = (struct sockaddr_in *) &(ifr->ifr_addr);
+ printf("Intf-addr:%s\n", inet_ntoa(sip->sin_addr));
+
+ exit(0);
+}
diff --git a/libexec/bootpd/trylook.c b/libexec/bootpd/trylook.c
new file mode 100644
index 00000000000..40652a21159
--- /dev/null
+++ b/libexec/bootpd/trylook.c
@@ -0,0 +1,50 @@
+/*
+ * trylook.c - test program for lookup.c
+ */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <stdio.h>
+
+#include "report.h"
+#include "lookup.h"
+
+extern char *ether_ntoa();
+extern char *inet_ntoa();
+
+int debug = 0;
+char *progname;
+
+main(argc, argv)
+ char **argv;
+{
+ int i;
+ struct in_addr in;
+ char *a;
+ u_char *hwa;
+
+ progname = argv[0]; /* for report */
+
+ for (i = 1; i < argc; i++) {
+
+ /* Host name */
+ printf("%s:", argv[i]);
+
+ /* IP addr */
+ if (lookup_ipa(argv[i], &in.s_addr))
+ a = "?";
+ else
+ a = inet_ntoa(in);
+ printf(" ipa=%s", a);
+
+ /* Ether addr */
+ hwa = lookup_hwa(argv[i], 1);
+ if (!hwa)
+ a = "?";
+ else
+ a = ether_ntoa(hwa);
+ printf(" hwa=%s\n", a);
+
+ }
+ exit(0);
+}
diff --git a/libexec/bootpd/tzone.c b/libexec/bootpd/tzone.c
new file mode 100644
index 00000000000..4adc4ae25c6
--- /dev/null
+++ b/libexec/bootpd/tzone.c
@@ -0,0 +1,44 @@
+/*
+ * tzone.c - get the timezone
+ *
+ * This is shared by bootpd and bootpef
+ */
+
+#ifdef SVR4
+/* XXX - Is this really SunOS specific? -gwr */
+/* This is in <time.h> but only visible if (__STDC__ == 1). */
+extern long timezone;
+#else /* SVR4 */
+/* BSD or SunOS */
+# include <sys/time.h>
+# include <syslog.h>
+#endif /* SVR4 */
+
+#include "bptypes.h"
+#include "report.h"
+#include "tzone.h"
+
+/* This is what other modules use. */
+int32 secondswest;
+
+/*
+ * Get our timezone offset so we can give it to clients if the
+ * configuration file doesn't specify one.
+ */
+void
+tzone_init()
+{
+#ifdef SVR4
+ /* XXX - Is this really SunOS specific? -gwr */
+ secondswest = timezone;
+#else /* SVR4 */
+ struct timezone tzp; /* Time zone offset for clients */
+ struct timeval tp; /* Time (extra baggage) */
+ if (gettimeofday(&tp, &tzp) < 0) {
+ secondswest = 0; /* Assume GMT for lack of anything better */
+ report(LOG_ERR, "gettimeofday: %s", get_errmsg());
+ } else {
+ secondswest = 60L * tzp.tz_minuteswest; /* Convert to seconds */
+ }
+#endif /* SVR4 */
+}
diff --git a/libexec/bootpd/tzone.h b/libexec/bootpd/tzone.h
new file mode 100644
index 00000000000..ddd67c4b625
--- /dev/null
+++ b/libexec/bootpd/tzone.h
@@ -0,0 +1,3 @@
+/* tzone.h */
+extern int32 secondswest;
+extern void tzone_init();