bootp-2.4.3/ 2755 125 65 0 5735637604 5651 bootp-2.4.3/Announce.old 644 125 65 12735 5626215761 10205 [ Old announcement from version 2.2: ] 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). [ Old announcement from version 2.1: ] 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 or Drew Perkins . [ Changed: now please send mail to: ] Good luck, Walt Wimer Network Development Carnegie Mellon University [ Old announcement from version 2.0: ] Subject: RFC-1048 compatible BOOTP server now available An RFC-1048 (BOOTP Vendor Information Extensions) compatible BOOTP (RFC-951) server 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.0.tar. This is an enhanced version of the existing CMU BOOTP server which was derived from the original BOOTP server created by Bill Croft at Stanford. New features and changes in version 2.0 include: o Full support for the vendor information extensions described in RFC-1048. o Faster response time (host lookup via hash table instead of linear search). o New termcap-like configuration file format which allows greater flexibility in specifying the variable vendor information of RFC-1048. Host entries may refer to other hosts as templates so that redundant information need be specified only once. o Continued support for the CMU vendor information format. The server may be configured on a per-host basis to always reply with a certain vendor information format or to reply based on the client's request. o Expanded logging. o The server may now be run by inetd or as a standalone program like the old version. o The configuration and debugging dump files may be specified on the command line. The server has been successfully tested on the following machines: IBM RT PC running ACIS 4.3 (4.3 BSD) Sun 3/50 running SunOS 3.5 DEC MicroVAX II running Ultrix 1.1 DEC MicroVAX II running Ultrix 2.2 Please direct questions, comments, and bug reports to Walt Wimer or Drew Perkins . [ Changed: now please send mail to: ] Sincerely, Walt Wimer Network Development Carnegie Mellon University bootp-2.4.3/Announce 644 125 65 4546 5720731411 7377 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 in version 2.4 include: 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=:ys=:nt=: ConvOldTab.sh to convert old (1.1) bootptab to new format. Permits extended-length replies with more option data. Problems fixed in this version: 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: NetBSD-1.0 (BSD-4.4 derivative) 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) Linux 1.1.81 OSF/1 (DEC Alpha CPU) Please direct questions, comments, and bug reports to: Gordon W. Ross Mercury Computer Systems gwr@mc.com 199 Riverneck Road 508-256-1300 Chelmsford, MA 01824-2820 ing "request from hardware address ABCDEF012345", the message is now "request from Ethernet address ABCEDF012345", or "request from IEEE802 address bootp-2.4.3/Changes 644 125 65 23471 5735637247 7241 Changes, most recent first Date, Real Name what... --> bootp-2.4.3 03/27/96 gwr@mc.com (Gordon W. Ross) Use LOG_NOTICE in place of LOG_INFO for messages related to unsatisfied clients [at request of ] Fix the irix Makefile targets, and other misc. 03/25/95 gwr@mc.com (Gordon W. Ross) Corrected a bug I introduced into SunOS setarp, where bad IP address caused "network unreachable" errors. [Thanks to andrew@ntplx.net (Andrew Lindh) for the fix!] --> bootp-2.4.2 01/14/95 middelin@polyware.iaf.nl (Pauline Middelink) Corrected support for the Linux networking code. Fixed lots of warnings (gcc -Wall) Added "linux" Makefile target. 01/02/95 Jukka Ukkonen Allow bootptab syntax: ha="0:0:c0:80:e8:a7" 11/30/94 Tonny van Lankveld Fix reporting of duplicate Ethernet addresses. 09/06/94 longyear@netcom.com (Al Longyear) Better setarp for linux, allows non-ether types. 09/02/94 Robert MacKinnon Add support for IBM's AIX 3.2.5 08/30/94 piercarl@ltd.c-d.com (Piercarlo Grandi) Fix select calls on linux (modifies timeval arg). Fix setarp (specify Ethernet type for now). 08/27/94 drew@drewsun.FEITH.COM (Andrew B. Sudell) Add support for Wollongong Win-TCP (SysVr4 variant). 08/24/94 gwr@mc.com (Gordon W. Ross) Use sigaction() on systems that define SA_NOCLDSTOP (a symbol required by POSIX) for HP/UX and others. --> bootp-2.4.1 08/24/94 gwr@mc.com (Gordon W. Ross) Fix bug in boot file name generation (missing init) --> bootp-2.4.0 08/20/94 gwr@mc.com (Gordon W. Ross) Fix code to build bootfile name based on combination of client requested name and bootfile specifications. Behave similarly with or without CHECK_FILE_ACCESS. 07/30/94 Dirk Koeppen Add "min wait" option (mw) to cause bootpd to ignore requests from clients that have not waited long enough. Add code to honor client requests containing the DHCP option "Maximum Message Size" and use its value to determine the size of the reply message. --> bootp-2.3.8 06/25/94 Christos Zoulas Add "-h" flag to override host name (affects default IP address provided in reply messages. (Also minor bug fix) 05/27/94 gwr@mc.com (Gordon W. Ross) Add code to call "arp -s IPADDR HWADDR" on systems that do not provide an SIOCSARP ioctl (i.e. NetBSD) --> bootp-2.3.7 05/05/94 Walter Wong Reduce noize at debug level one, where log messages are generated only for hosts that are recognized and replied to by bootpd. (At request of HP folks.) 04/30/94 gwr@mc.com (Gordon W. Ross) Use memxxx functions unless USE_BFUNCS is defined. Added -f option to bootptest (requested file). 04/29/94 tpaquett@ita.lgc.com (Trevor Paquette) Remove call to haddr_conv802() in sendreply(). The setarp should get the non-transformed address. 04/27/94 gwr@mc.com Improve logic for building bootfile pathname, so a path will be put in the reply if either the client or bootpd specifies a boot file. (Needed for NetBSD diskless boot) 04/25/94 shamash@boxhill.com (Ari Shamash) Fix prs_inetaddr() so it allows '_' in hostnames. 04/16/94 gwr@mc.com (Gordon W. Ross) Fix setarp for SVR4 (needs to use I_STR ioctl) Thanks to several people: (all sent the same fix) Barney Wolff , bear@upsys.se (Bj|rn Sj|holm), Michael Kuschke , 03/25/95 Ulrich Heuer Make option string lengths not include a null terminator. The trailing null breaks some clients. 03/15/94 "Edmund J. Sutcliffe" Add support for the "EX" option: Execute a program before sending a BOOTREPLY to a client. Support for this option is conditional on YORK_EX_OPTION. 03/10/94 Nigel Metheringham Make getether.c work on Linux. 03/09/94 Koch@Math.Uni-Duisburg.DE (Peter Koch) Add missing MANDIR definition to Makefile. 03/08/94 Jeroen.Scheerder@let.ruu.nl Fix args to report in getether code for Ultrix. Run install individually for each program. --> bootp-2.3.6 03/07/94 gwr@mc.com Cleanup for release (run gnu indent, tab-size=4) 02/24/94 Jeroen.Scheerder@let.ruu.nl Allow underscore in host names - readfile.c:goodname() Add ConvOldTab.sh - converts 1.1 bootptab to new format. 02/20/94 gwr@mc.com (Gordon W. Ross) Make readfile tolerant of hardware addresses that start with a letter. (If lookup_hwa() fails, assume numeric.) Fix whitespace skip before :vm= auto: and avoid lookup. 02/12/94 walker@zk3.dec.com (Mary Walker) Added support for 64-bit longs (for the DEC Alpha) Allow ieee802 hardware address in bit-reversed oreder 02/07/94 hl@tekla.fi (Harald Lundberg) Fix conflict with DUMP_FILE in syslog.h on OSF1 Use int for (struct bootp).bp_xid (for DEC Alpha) Added Ultrix support to bootptest (getether) 02/06/94 brezak@ch.hp.com (John Brezak) Add man-page and install targets to Makefile.NetBSD Add getether support for NetBSD 02/05/94 gwr@mc.com (Gordon W. Ross) Added tags 40,41,42 (NIS domain, NIS server, NTP server) Add stub to getether for machines not yet supported. --> bootp-2.3.5 01/29/94 gwr@mc.com (Gordon W. Ross) Make bootpgw put a correct address in "giaddr" when the client request came via broadcast. 01/22/94 gwr@mc.com (Gordon W. Ross) Fix syslog call (missing "facility" code) Add SVR4/Streams support to getif() and getether() Fix getif bug (matched when it should not) Macro-ize lots of similar cases in readfile.c 12/27/93 brezak@ch.hp.com (John Brezak) Remove all newlines passed to syslog(3) Add /etc/ethers support for NetBSD. 12/18/93 gwr@mc.com (Gordon W. Ross) Fix bootptest IP address printing. Fix byte-order bugs in bootpgw and bootptest. Clean-up signed/unsigned mismatches. Back out SLIP support changes for now (code fragment saved in ToDo). --> bootp-2.3.4 (beta test release) 12/12/93 gwr@mc.com (Gordon W. Ross) Fixed several more NULL references in readfile. Added proper length checks to option insertions. --> bootp-2.3.3 (beta test release) 12/09/93 gwr@mc.com (Gordon W. Ross) Added ASSERT checks to readfile.c:fill_defaults() 12/08/93 brezak@ch.hp.com (John Brezak) New Makefile.NetBSD Added setsid() and #ifdef TIOCNOTTY (bootpd.c, bootpgw.c) Moved #include out of #ifdef SUNOS Fixed several multiple declaration problems 12/04/93 gwr@mc.com (Gordon W. Ross) Re-implemented Extension File support based on work by Jason Zions Added support for Reply-Address-Override to support HP clients (need reply sent to broadcast address) from David R. Linn --> bootp-2.3.2 (beta test release) 11/27/93 gwr@mc.com (Gordon W. Ross) Incorporated bootptest into the bootp release. Added ANSI function prototypes everywhere. 11/17/93 dpm@depend.com (David P. Maynard) Added automatic SLIP address determination. (This is NOT dynamic IP address assignment.) Cleaned up some type warnings from gcc. 11/11/93 gwr@mc.com (Gordon W. Ross) Works (again) with no -DSYSLOGD defined. Provide a default value for the subnet mask. More #ifdef's for SunOS specific code (lookup_hwa) Added a simple BOOTP gateway program: bootpgw Reorganized for more code sharing (with bootpgw) --> bootp-2.3.1 (alpha test release) 11/08/93 gwr@mc.com (Gordon W. Ross) Back-out changes to honor option structure in request (this needs to be a per-client option). Merged changes from NetBSD and Columbia versions. Allow host name anywhere IP address is expected. Add null terminators to option strings. Add missing symbols to dump routine, dump symbols in alphabetical order, one tag per line. --> bootp-2.2.D (posted as patch 2) 10/19/93 gwr@mc.com (Gordon W. Ross) Fix references to free memory (leads to core dumps). --> bootp-2.2.C (posted as patch 1) 10/14/93 gwr@mc.com (Gordon W. Ross) Fix data access alignment problems on SPARC/Solaris. --> bootp-2.2.B (posted to usenet) 10/11/93 gwr@mc.com (Gordon W. Ross) Allow extended-length BOOTP packets (more vendor options) Honor option format specified in client requests. Added Solaris-2.X changes from db@sunbim.be (Danny Backx). All history before this point may be inaccurate. Please send changes if any of the credits are incorrect. -gwr --> bootp-2.2+NetBSD released 08/27/93 brezak@ch.hp.com (John Brezak) Added RFC 1396 support (tags 14-17) --> bootp-2.2+NetBSD (version?) ??/??/93 mckim@lerc.nasa.gov (Jim McKim) Ported to NetBSD (see Makefile.NetBSD) Set server host name in responses. Check all interfaces in address match routine. --> bootp-2.2+FdC released 01/27/93 Frank da Cruz Added RFC 1395 information: Merit dump file, client domain name, swap server address, root path. --> bootp-2.2alpha released 11/14/91 Walter L. Wimer Add "td" to TFTP directory for "secure" (chroot) TFTP. Add "sa" tag to set explicit server address. Automatically determine if child of inetd. Use RFC 1048 format when request has magic number zero. Fixed various bugs. Give bootptab a separate man page. --> bootp-2.1 released 01/09/89 Walter L. Wimer Check world read bit on TFTP boot file. Add support for rfc1085 "bootfile size" tag. Add generic tags. Fix byte order of rfc1048 data. Fix various crashing bugs. --> bootp-2.0 released 07/15/88 Walter L. Wimer 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. --> bootp-1.3(?) released 07/24/87 Drew D. Perkins Modified to use syslog instead of Kovar's routines. Add debugging dumps. Many other fixups. --> bootp-1.2(?) released 07/30/86 David Kovar at Carnegie Mellon University Modified to work at CMU. --> bootp-1.1 released 01/22/86 Bill Croft at Stanford University Original created. k> Make getether.c work on Linux. 03/09/94 Koch@Math.Uni-Duisburg.DE (Peter Koch) Add missing MANDIR definition to Makefile. 03/08/94 Jeroen.Scheerder@let.ruu.nl Fix args to report in getetherbootp-2.4.3/.indent.pro 644 125 65 220 5536707352 7744 -nbad -nbap -nbbb -nbc -br -bli4 -c33 -cd33 -cdb -ce -ci4 -cli0 -cp1 -d0 -di0 -nfc1 -nfca -i4 -ip4 -l75 -lp -npcs -psl -sc -nsob -nss -ts4 ProblemsÀСREADMETà¢ToDoEsð¥bootp.h¦bootpd.8§bootpd.c,´bootpd.h,@¹ bootpef.8@Tº bootpef.cThÆ bootpgw.ch|Ç bootptab.5|”È bootptab.cmuÈ¬Ë bootptab.mcsËÀÌ bootptest.8ÔÍ bootptest.cèÎ bootptesbootp-2.4.3/ConvOldTab.sh 755 125 65 7305 5536722235 10245 #!/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` " 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 age: `basename $0` " 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 bootp-2.4.3/Installation 644 125 65 1346 5522042412 10261 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" Ülookup.hp.cøÝ patchlevel.hÌÞ print-bootp.cø$ß readfile.c.8à readfile.heLäreport.cile`åreport.ht.ctæ strerror.chˆë syslog.confœìsyslog.hg.c°í trygetea.chÄî trygbootp-2.4.3/Makefile 644 125 65 12511 5735633232 7365 # # Makefile for the BOOTP programs: # bootpd - BOOTP server daemon # bootpef - BOOTP extension file builder # bootpgw - BOOTP gateway daemon # bootptest - BOOTP tester (client) # # OPTion DEFinitions: # Remove the -DVEND_CMU if you don't wish to support the "CMU vendor format" # in addition to the RFC1048 format. Leaving out DEBUG saves little. OPTDEFS= -DSYSLOG -DVEND_CMU -DDEBUG # Uncomment and edit this to choose the facility code used for syslog. # LOG_FACILITY= "-DLOG_BOOTP=LOG_LOCAL2" # SYStem DEFinitions: # Either uncomment some of the following, or do: # "make sunos4" (or "make sunos5", etc.) # SYSDEFS= -DSUNOS -DETC_ETHERS # SYSDEFS= -DSVR4 # SYSLIBS= -lsocket -lnsl # Uncomment this if your system does not provide streror(3) # STRERROR=strerror.o # FILE DEFinitions: # 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=\"/usr/etc/bootpd.dump\" #FILEDEFS= $(CONFFILE) $(DUMPFILE) # MORE DEFinitions (whatever you might want to add) # One might define NDEBUG (to remove "assert()" checks). MOREDEFS= INSTALL=/usr/bin/install DESTDIR= BINDIR=/usr/etc MANDIR=/usr/local/man CFLAGS= $(OPTDEFS) $(SYSDEFS) $(FILEDEFS) $(MOREDEFS) PROGS= bootpd bootpef bootpgw bootptest TESTS= trylook trygetif trygetea all: $(PROGS) $(TESTS) system: install install: $(PROGS) -for f in $(PROGS) ;\ do \ $(INSTALL) -c -s $$f $(DESTDIR)$(BINDIR) ;\ done MAN5= bootptab.5 MAN8= bootpd.8 bootpef.8 bootptest.8 install.man: $(MAN5) $(MAN8) -for f in $(MAN5) ;\ do \ $(INSTALL) -c -m 644 $$f $(DESTDIR)$(MANDIR)/man5 ;\ done -for f in $(MAN8) ;\ do \ $(INSTALL) -c -m 644 $$f $(DESTDIR)$(MANDIR)/man8 ;\ done clean: -rm -f core *.o -rm -f $(PROGS) $(TESTS) distclean: -rm -f *.BAK *.CKP *~ .emacs* # # Handy targets for systems needing special treatment: # (Most POSIX systems should work with just "make all") # # DEC/OSF1 on the Alpha alpha: $(MAKE) SYSDEFS="-DETC_ETHERS -Dint32=int -D_SOCKADDR_LEN" \ STRERROR=strerror.o # Control Data EP/IX 1.4.3 system, BSD 4.3 mode epix143: $(MAKE) CC="cc -systype bsd43" \ SYSDEFS="-Dconst= -D_SIZE_T -DNO_UNISTD -DUSE_BFUNCS" \ STRERROR=strerror.o # Control Data EP/IX 2.1.1 system, SVR4 mode epix211: $(MAKE) CC="cc -systype svr4" \ SYSDEFS="-DSVR4" \ SYSLIBS="-lsocket -lnsl" # IRIX 5.X (Silicon Graphics) irix: $(MAKE) SYSDEFS= SYSLIBS= # Linux 1.1.80+ on [34]86 linux: $(MAKE) SYSDEFS="-O6 -Wall -fomit-frame-pointer" # SunOS 4.X sunos4: $(MAKE) SYSDEFS="-DSUNOS -DETC_ETHERS" \ STRERROR=strerror.o # Solaris 2.X (i.e. SunOS 5.X) sunos5: $(MAKE) SYSDEFS="-DSVR4 -DETC_ETHERS" \ SYSLIBS="-lsocket -lnsl" # Solaris 2.X (i.e. SunOS 5.X) with GCC. Note that GCC normally # defines __STDC__=1 which breaks many Solaris header files... sunos5gcc: $(MAKE) SYSDEFS="-DSVR4 -DETC_ETHERS -D__STDC__=0" \ SYSLIBS="-lsocket -lnsl" CC="gcc -Wall" # UNIX System V Rel. 3 svr3: $(MAKE) SYSDEFS="-DSYSV" # UNIX System V Rel. 4 svr4: $(MAKE) SYSDEFS="-DSVR4" \ SYSLIBS="-lsocket -lnsl" # AT&T/GIS - Both AT&T StarServer and NCR 3000 # may work for others using Wollongong's WIN-TCP wollongong gis : $(MAKE) SYSDEFS="-DSVR4 -DWIN_TCP" \ SYSLIBS="-lsocket -lnsl" # # How to build each program: # OBJ_D= bootpd.o dovend.o readfile.o hash.o dumptab.o \ lookup.o getif.o hwaddr.o tzone.o report.o $(STRERROR) bootpd: $(OBJ_D) $(CC) -o $@ $(OBJ_D) $(SYSLIBS) OBJ_EF= bootpef.o dovend.o readfile.o hash.o dumptab.o \ lookup.o hwaddr.o tzone.o report.o $(STRERROR) bootpef: $(OBJ_EF) $(CC) -o $@ $(OBJ_EF) $(SYSLIBS) OBJ_GW= bootpgw.o getif.o hwaddr.o report.o $(STRERROR) bootpgw: $(OBJ_GW) $(CC) -o $@ $(OBJ_GW) $(SYSLIBS) OBJ_TEST= bootptest.o print-bootp.o getif.o getether.o \ report.o $(STRERROR) bootptest: $(OBJ_TEST) $(CC) -o $@ $(OBJ_TEST) $(SYSLIBS) # This is just for testing the lookup functions. TRYLOOK= trylook.o lookup.o report.o $(STRERROR) trylook : $(TRYLOOK) $(CC) -o $@ $(TRYLOOK) $(SYSLIBS) # This is just for testing getif. TRYGETIF= trygetif.o getif.o report.o $(STRERROR) trygetif : $(TRYGETIF) $(CC) -o $@ $(TRYGETIF) $(SYSLIBS) # This is just for testing getether. TRYGETEA= trygetea.o getether.o report.o $(STRERROR) trygetea : $(TRYGETEA) $(CC) -o $@ $(TRYGETEA) $(SYSLIBS) # This rule just keeps the LOG_BOOTP define localized. report.o : report.c $(CC) $(CFLAGS) $(LOG_FACILITY) -c $< # Punt SunOS -target noise .c.o: $(CC) $(CFLAGS) -c $< # # Header file dependencies: # bootpd.o : bootp.h bptypes.h hash.h hwaddr.h bootpd.h dovend.h bootpd.o : readfile.h report.h tzone.h patchlevel.h getif.h bootpef.o : bootp.h bptypes.h hash.h hwaddr.h bootpd.h dovend.h bootpef.o : readfile.h report.h tzone.h patchlevel.h bootpgw.o : bootp.h bptypes.h getif.h hwaddr.h report.h patchlevel.h bootptest.o : bootp.h bptypes.h bootptest.h getif.h patchlevel.h dovend.o : bootp.h bptypes.h bootpd.h hash.h hwaddr.h report.h dovend.h dumptab.o : bootp.h bptypes.h hash.h hwaddr.h report.h patchlevel.h bootpd.h getif.o : getif.h report.h hash.o : hash.h hwaddr.o : bptypes.h hwaddr.h report.h lookup.o : bootp.h bptypes.h lookup.h report.h print-bootp.o : bootp.h bptypes.h bootptest.h readfile.o : bootp.h bptypes.h hash.h hwaddr.h lookup.h readfile.h readfile.o : report.h tzone.h bootpd.h report.o : report.h tzone.o : bptypes.h report.h tzone.h and changed to alter the default # filenames bootpd uses for its configuration and dump files. #CONFFILE= -DCONFIG_FILE=\"/usr/etc/bootptab\" #DUMPFILE= -DDUMPTAB_FILE=\"/usr/etc/bootbootp-2.4.3/Problems 644 125 65 5117 5735635015 7420 Common problems and ways to work around them: Bootpd complains: "bind: Address already in use" and fails to start. You are already running something that has bound the BOOTP listening port number. Check /etc/inetd.conf or the equivalent for a bootp line (or in startup files). 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) My PC clients running Sun's PC-NFS Pro v1.1 fail to receive acceptable responses from the bootp server. These clients send a request with the DHCP "message length" option and the (new) BOOTP "broadcast flag" both set. The bootp server (on SunOS) will send a fragmented reply unless you override the length with :ms=1024: (or less). The "broadcast flag" is not yet supported, but there is a simple work-around, just add :ra=255.255.255.255: for any clients that need their reply broadcasted. You may need to use a differnet broadcast address. (Thanks to Ivan Auger ) STRERROR=strerror.o # Solaris 2.X (i.e. SunOS 5.X) sunos5: $(MAKE) SYSDEFS="-DSVR4 -DETC_ETHERS" \ SYSLIBS="-lsocket -lnsl" # Solaris 2.X (i.e. SunOS 5.X) with GCC. Note that GCC normally # defines __STDC__=1 which breaks many Solaris header files... sunos5gcc: $(MAKE) SYSDEFS="-DSVR4 -DETC_ETHERS -D__STDC__=0" \ SYSLIBS="-lsocket -lnsl" CC="gcc -Wall" # UNIX System V Rel. 3 svr3: $(MAKE) SYSDEFS="-DSYSV" # UNIX Systbootp-2.4.3/README 644 125 65 12250 5720671020 6574 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. Please direct questions, comments, and bug reports to the list: You can subscribe to this mailing list by sending mail to: bootp-request@andrew.cmu.edu (The body of the message should contain: "Add ") [ From the NetBSD README file: ] BOOTPD is a useful adjunct to the nfs diskless boot EPROM code. The alternatives for initiating a boot of a kernel across a network 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. [ From the CMU README file: ] Notes: 1) BOOTP was originally designed and implemented by Bill Croft at Stanford. Much of the credit for the ideas and the code goes to him. We've added code to support the vendor specific area of the packet as specified in RFC1048. We've also improved the host lookup algorithm and added some extra logging. 2) The server now uses syslog to do logging. Specifically it uses the 4.3bsd version. I've #ifdef'd all of these calls. If you are running 4.2 you should compile without the -DSYSLOG switch. 3) You must update your /etc/services file to contain the following two lines: bootps 67/udp bootp # BOOTP Server bootpc 68/udp # BOOTP Client 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. Type 'make'. The options at present are: -DSYSLOG which enables logging code, -DDEBUG which enables table dumping via signals, and -DVEND_CMU which enables the CMU extensions for CMU PC/IP. Edit the bootptab. The man page and the comments in the file should explain how to go about doing so. If you have any problems, let me know. 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. 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 need to update /etc/bootptab. Just edit it as before. Once you write it back out, bootpd will notice that there is a new copy and will reread it the next time it gets a request. If your bootp clients don't get a response then several things might be wrong. Most often, the entry for that host is not in the database. Check the hardware address and then check the entry and make sure everything is right. Other problems include the server machine crashing, bad cables, and the like. If your network is very congested you should try making your bootp clients send additional requests before giving up. November 7, 1988 Walter L. Wimer Drew D. Perkins ww0n@andrew.cmu.edu ddp@andrew.cmu.edu (412) 268-6252 (412) 268-8576 4910 Forbes Ave Pittsburgh, PA 15213 [ Contents description by file: ] Announce* Text of release announcements Changes Change history, reverse chronological ConvOldTab.sh Script to convert old (1.x) bootptab files Installation Instructions for building and installing Makefile* for "make" README This file ToDo Things not yet done 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 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) getether.h header for above 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 tptab. The man page and the comments in the file should explain how to go about doing so. If you have any problems, let me know. 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. The following is a sample /etc/inetd.cobootp-2.4.3/ToDo 644 125 65 4273 5720702005 6470 ToDo: -*- text -*- ---------------------------------------------------------------------- Memory allocation locality: 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. . . . ---------------------------------------------------------------------- Input parser: The reader implemented in readfile.c could use improvement. Some sort of "data-driven" parser should be used so the big switch statements would have only one case for each data type instead of one case for every recognized option symbol. Then adding a new tag would involve only adding a new element to the data table describing known symbols. Hopefully, this would shrink the code a bit too. -gwr ---------------------------------------------------------------------- SLIP Initialization via BOOTP: In the function handle_request(), both in bootpd and bootpgw, we might want to add code like the following just before testing the client IP address field for zero. (bp->bp_ciaddr == 0) (David suggests we leave this out for now. -gwr) #if 1 /* XXX - Experimental */ /* * SLIP initialization support. * * If this packet came from a SLIP driver that does * automatic IP address initialization, then the socket * will have the IP address and the packet will * have zeros for both the IP and HW addresses. * * Thanks to David P. Maynard * for explaining how this works. -gwr */ if ((bp->bp_ciaddr.s_addr == 0) && (bp->bp_htype == 0)) { /* Pretend the client knows its address. It will soon. */ bp->bp_ciaddr = recv_addr.sin_addr; if (debug) report(LOG_INFO, "fixed blank request from IP addr %s", inet_ntoa(recv_addr.sin_addr)); } #endif ---------------------------------------------------------------------- DHCP Support: There is a set of patches from Jeanette Pauline Middelink to add DHCP support. Those patches will be integrated into the BOOTP release stream very soon, but if you can't wait, you can get them from: nimbus.anu.edu.au:/pub/tridge/samba/contributed/DHCP.patch ---------------------------------------------------------------------- e and the comments in the file should explain how to go about doing so. If you have any problems, let me know. 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. The following is a sample /etc/inetd.cobootp-2.4.3/bootp.h 644 125 65 11671 5626153415 7226 /************************************************************************ 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. ************************************************************************/ /* * Bootstrap Protocol (BOOTP). RFC951 and RFC1395. * * $Id: bootp.h $ * * * This file specifies the "implementation-independent" BOOTP protocol * information which is common to both client and server. * */ #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 int32 bp_xid; /* transaction ID */ unsigned short bp_secs; /* seconds since boot began */ unsigned short bp_flags; /* RFC1532 broadcast, etc. */ struct in_addr bp_ciaddr; /* client IP address */ struct in_addr bp_yiaddr; /* 'your' IP address */ 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 */ 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. */ }; /* * UDP port numbers, server and client. */ #define IPPORT_BOOTPS 67 #define IPPORT_BOOTPC 68 #define BOOTREPLY 2 #define BOOTREQUEST 1 /* * Hardware types from Assigned Numbers RFC. */ #define HTYPE_ETHERNET 1 #define HTYPE_EXP_ETHERNET 2 #define HTYPE_AX25 3 #define HTYPE_PRONET 4 #define HTYPE_CHAOS 5 #define HTYPE_IEEE802 6 #define HTYPE_ARCNET 7 /* * Vendor magic cookie (v_magic) for CMU */ #define VM_CMU "CMU" /* * Vendor magic cookie (v_magic) for RFC1048 */ #define VM_RFC1048 { 99, 130, 83, 99 } /* * 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) #define TAG_GATEWAY ((unsigned char) 3) #define TAG_TIME_SERVER ((unsigned char) 4) #define TAG_NAME_SERVER ((unsigned char) 5) #define TAG_DOMAIN_SERVER ((unsigned char) 6) #define TAG_LOG_SERVER ((unsigned char) 7) #define TAG_COOKIE_SERVER ((unsigned char) 8) #define TAG_LPR_SERVER ((unsigned char) 9) #define TAG_IMPRESS_SERVER ((unsigned char) 10) #define TAG_RLP_SERVER ((unsigned char) 11) #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) /* DHCP maximum message size. */ #define TAG_MAX_MSGSZ ((unsigned char) 57) /* XXX - Add new tags here */ /* * "vendor" data permitted for CMU bootp clients. */ struct cmu_vend { 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 */ int32 v_unused[6]; /* currently unused */ }; /* v_flags values */ #define VF_SMASK 1 /* Subnet mask field contains valid data */ be wrong. Most often, the entry for that host is not in the databbootp-2.4.3/bootpd.8 644 125 65 16401 5503436411 7300 .\" Copyright (c) 1988, 1989, 1991 Carnegie Mellon University .\" .\" $Header: $ .\" .TH BOOTPD 8 "November 06, 1993" "Carnegie Mellon University" .SH NAME bootpd, bootpgw \- Internet Boot Protocol server/gateway .SH SYNOPSIS .B bootpd [ .B \-i .B \-s .B \-t timeout .B \-d level .B \-c chdir\-path ] [ .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 (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 /etc/bootpgw bootpgw server .PP This mode of operation is referred to as "inetd mode" and causes .I bootpd (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 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 particularly useful when .I bootpd 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.) Standalone mode is less useful for .I bootgw which has very little start up delay because it does not read a configuration file. .PP Either program automatically detects whether it was invoked from inetd or from a shell and automatically selects the appropriate mode. The .B \-s or .B \-i 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 Both .I bootpd 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 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 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 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 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 Database file read by .IR bootpd . .TP /etc/bootpd.dump 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 CREDITS .PP This distribution is currently maintained by Walter L. Wimer . .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 Enhancements and bug\-fixes have been contributed by: (in alphabetical order) .br Danny Backx .br John Brezak .br Frank da Cruz .br David R. Linn .br Jim McKim .br Gordon W. Ross .br Jason Zions .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 evel 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 existencbootp-2.4.3/bootpd.c 644 125 65 102006 5735630133 7374 /************************************************************************ 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. ************************************************************************/ /* * BOOTP (bootstrap protocol) server daemon. * * Answers BOOTP request packets from booting client machines. * See [SRI-NIC]RFC951.TXT for a description of the protocol. * See [SRI-NIC]RFC1048.TXT for vendor-information extensions. * See RFC 1395 for option tags 14-17. * See accompanying man page -- bootpd.8 * * HISTORY * See ./Changes * * BUGS * See ./ToDo */ #include #include #include #include #include #include #include #include #include #include #include /* inet_ntoa */ #ifndef NO_UNISTD #include #endif #include #include #include #include #include #include #include #include #include #ifdef NO_SETSID # include /* for O_RDONLY, etc */ #endif #ifndef USE_BFUNCS # include /* 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" #ifndef CONFIG_FILE #define CONFIG_FILE "/etc/bootptab" #endif #ifndef DUMPTAB_FILE #define DUMPTAB_FILE "/tmp/bootpd.dump" #endif /* * Externals, forward declarations, and global variables */ #ifdef __STDC__ #define P(args) args #else #define P(args) () #endif extern void dumptab P((char *)); PRIVATE void catcher P((int)); PRIVATE int chk_access P((char *, int32 *)); #ifdef VEND_CMU PRIVATE void dovend_cmu P((struct bootp *, struct host *)); #endif 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 */ 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 */ }; /* * General */ int s; /* Socket file descriptor */ char *pktbuf; /* Receive packet buffer */ int pktlen; char *progname; char *chdir_path; struct in_addr my_ip_addr; struct utsname my_uname; char *hostname; /* Flags set by signal catcher. */ PRIVATE int do_readtab = 0; PRIVATE int do_dumptab = 0; /* * Globals below are associated with the bootp database file (bootptab). */ char *bootptab = CONFIG_FILE; char *bootpd_dump = DUMPTAB_FILE; /* * 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; #ifdef SA_NOCLDSTOP /* Have POSIX sigaction(2). */ struct sigaction sa; #endif 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(MAX_MSG_SIZE); 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"); } } /* * Set defaults that might be changed by option switches. */ stmp = NULL; timeout = &actualtimeout; if (uname(&my_uname) < 0) { fprintf(stderr, "bootpd: can't get hostname\n"); exit(1); } hostname = my_uname.nodename; /* * 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 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': /* override hostname */ if (argv[0][2]) { stmp = &(argv[0][2]); } else { argc--; argv++; stmp = argv[0]; } if (!stmp) { fprintf(stderr, "bootpd: missing hostname\n"); break; } hostname = stmp; 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; default: fprintf(stderr, "%s: unknown switch: -%c\n", progname, argv[0][1]); usage(); break; } /* switch */ } /* for args */ /* * Override default file names if specified on the command line. */ if (argc > 0) bootptab = argv[0]; if (argc > 1) bootpd_dump = argv[1]; /* * Get my hostname and IP address. */ 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 */ /* * Nuke any timeout value */ timeout = NULL; } /* 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); } /* Get the timezone. */ tzone_init(); /* Allocate hash tables. */ rdtab_init(); /* * Read the bootptab file. */ 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 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; } /* * Set up signals to read or dump the table. */ #ifdef SA_NOCLDSTOP /* Have POSIX sigaction(2). */ sa.sa_handler = catcher; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; if (sigaction(SIGHUP, &sa, NULL) < 0) { report(LOG_ERR, "sigaction: %s", get_errmsg()); exit(1); } if (sigaction(SIGUSR1, &sa, NULL) < 0) { report(LOG_ERR, "sigaction: %s", get_errmsg()); exit(1); } #else /* SA_NOCLDSTOP */ /* Old-fashioned UNIX signals */ if ((int) signal(SIGHUP, catcher) < 0) { report(LOG_ERR, "signal: %s", get_errmsg()); exit(1); } if ((int) signal(SIGUSR1, catcher) < 0) { report(LOG_ERR, "signal: %s", get_errmsg()); exit(1); } #endif /* SA_NOCLDSTOP */ /* * Process incoming requests. */ for (;;) { struct timeval tv; readfds = 1 << s; if (timeout) tv = *timeout; nfound = select(s + 1, (fd_set *)&readfds, NULL, NULL, (timeout) ? &tv : NULL); 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, MAX_MSG_SIZE, 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_NOTICE, "received short packet"); } continue; } pktlen = n; readtab(0); /* maybe re-read bootptab */ switch (bp->bp_op) { case BOOTREQUEST: handle_request(); break; case BOOTREPLY: handle_reply(); break; } } } /* * Print "usage" message and exit */ PRIVATE void usage() { 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; #if !defined(SA_NOCLDSTOP) && defined(SYSV) /* For older "System V" derivatives with no sigaction(). */ signal(sig, catcher); #endif } /* * Process BOOTREQUEST packet. * * 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.) */ PRIVATE void handle_request() { struct bootp *bp = (struct bootp *) pktbuf; struct host *hp = NULL; struct host dummyhost; int32 bootsize = 0; unsigned hlen, hashcode; int32 dest; char realpath[1024]; char *clntpath; char *homedir, *bootfile; int n; /* XXX - SLIP init: Set bp_ciaddr = recv_addr here? */ /* * 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(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); } /* Convert the request into a reply. */ 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) report(LOG_NOTICE, "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) { report(LOG_NOTICE, "IP address not found: %s", inet_ntoa(bp->bp_ciaddr)); } return; } } if (debug) { report(LOG_INFO, "found %s (%s)", inet_ntoa(hp->iaddr), hp->hostname->string); } /* * If there is a response delay threshold, ignore requests * with a timestamp lower than the threshold. */ if (hp->flags.min_wait) { u_int32 t = (u_int32) ntohs(bp->bp_secs); if (t < hp->min_wait) { if (debug > 1) report(LOG_INFO, "ignoring request due to timestamp (%d < %d)", t, hp->min_wait); return; } } #ifdef YORK_EX_OPTION /* * 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 * * XXX - This could compromise security if a non-trusted user * managed to write an entry in the bootptab with :ex=trojan: * so I would leave this turned off unless you need it. -gwr */ /* Run a program, passing the client name as a parameter. */ if (hp->flags.exec_file) { char tst[100]; /* XXX - Check string lengths? -gwr */ strcpy (tst, hp->exec_file->string); 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 /* * 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 * */ /* * XXX - I don't like the policy of ignoring a client when the * boot file is not accessible. The TFTP server might not be * running on the same machine as the BOOTP server, in which * case checking accessibility of the boot file is pointless. * * Therefore, file accessibility is now demanded ONLY if you * define CHECK_FILE_ACCESS in the Makefile options. -gwr */ /* * The "real" path is as seen by the BOOTP daemon on this * machine, while the client path is relative to the TFTP * daemon chroot directory (i.e. /tftpboot). */ if (hp->flags.tftpdir) { strcpy(realpath, hp->tftpdir->string); clntpath = &realpath[strlen(realpath)]; } else { realpath[0] = '\0'; clntpath = realpath; } /* * Determine client's requested homedir and bootfile. */ homedir = NULL; bootfile = NULL; if (bp->bp_file[0]) { homedir = bp->bp_file; bootfile = strrchr(homedir, '/'); if (bootfile) { if (homedir == bootfile) homedir = NULL; *bootfile++ = '\0'; } else { /* no "/" in the string */ bootfile = homedir; homedir = NULL; } if (debug > 2) { report(LOG_INFO, "requested path=\"%s\" file=\"%s\"", (homedir) ? homedir : "", (bootfile) ? bootfile : ""); } } /* * Specifications in bootptab override client requested values. */ if (hp->flags.homedir) homedir = hp->homedir->string; if (hp->flags.bootfile) bootfile = hp->bootfile->string; /* * Construct bootfile path. */ if (homedir) { if (homedir[0] != '/') strcat(clntpath, "/"); strcat(clntpath, homedir); homedir = NULL; } if (bootfile) { if (bootfile[0] != '/') strcat(clntpath, "/"); strcat(clntpath, bootfile); bootfile = NULL; } /* * First try to find the file with a ".host" suffix */ n = strlen(clntpath); strcat(clntpath, "."); strcat(clntpath, hp->hostname->string); if (chk_access(realpath, &bootsize) < 0) { clntpath[n] = 0; /* Try it without the suffix */ if (chk_access(realpath, &bootsize) < 0) { /* neither "file.host" nor "file" was found */ #ifdef CHECK_FILE_ACCESS if (bp->bp_file[0]) { /* * Client wanted specific file * and we didn't have it. */ report(LOG_NOTICE, "requested file not found: \"%s\"", clntpath); return; } /* * 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 null_file_name; #else /* CHECK_FILE_ACCESS */ /* Complain only if boot file size was needed. */ if (hp->flags.bootsize_auto) { report(LOG_ERR, "can not determine size of file \"%s\"", clntpath); } #endif /* CHECK_FILE_ACCESS */ } } strncpy(bp->bp_file, clntpath, BP_FILE_LEN); if (debug > 2) report(LOG_INFO, "bootfile=\"%s\"", clntpath); #ifdef CHECK_FILE_ACCESS null_file_name: #endif /* CHECK_FILE_ACCESS */ /* * Handle vendor options based on magic number. */ 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 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 { 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. */ PRIVATE void handle_reply() { if (debug) { report(LOG_INFO, "processing boot reply"); } /* 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. */ PRIVATE void sendreply(forward, dst_override) int forward; int32 dst_override; { struct bootp *bp = (struct bootp *) pktbuf; struct in_addr dst; u_short port = bootpc_port; unsigned char *ha; int len, haf; /* * XXX - Should honor bp_flags "broadcast" bit here. * Temporary workaround: use the :ra=ADDR: option to * set the reply address to the broadcast address. */ /* * 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. */ 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; port = bootps_port; if (debug > 1) { report(LOG_INFO, "sending reply to gateway %s", inet_ntoa(dst)); } } else { dst = bp->bp_yiaddr; ha = bp->bp_chaddr; len = bp->bp_hlen; if (len > MAXHADDRLEN) len = MAXHADDRLEN; haf = (int) bp->bp_htype; if (haf == 0) haf = HTYPE_ETHERNET; if (debug > 1) report(LOG_INFO, "setarp %s - %s", inet_ntoa(dst), haddrtoa(ha, len)); setarp(s, &dst, haf, ha, len); } 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). Of course, the client may * be on the other side of a BOOTP gateway... */ 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; } /* XXX - No need to set bp_giaddr here. */ /* 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; /* 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 */ /* nmatch() - now in getif.c */ /* setarp() - now in hwaddr.c */ /* * 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 * return the file size in bytes using the long pointer "filesize". * * The read permission bit for "other" users is checked. This bit must be * set for tftpd(8) to allow clients to read the file. */ PRIVATE int chk_access(path, filesize) char *path; int32 *filesize; { struct stat st; if ((stat(path, &st) == 0) && (st.st_mode & (S_IREAD >> 6))) { *filesize = (int32) st.st_size; return 0; } else { return -1; } } /* * Now in dumptab.c : * dumptab() * dump_host() * list_ipaddresses() */ #ifdef VEND_CMU /* * Insert the CMU "vendor" data for the host pointed to by "hp" into the * bootp packet pointed to by "bp". */ PRIVATE void dovend_cmu(bp, hp) struct bootp *bp; struct host *hp; { 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; 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) { 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; } } } /* Log message now done by caller. */ } /* dovend_cmu */ #endif /* VEND_CMU */ /* * Insert the RFC1048 vendor data for the host pointed to by "hp" into the * bootp packet pointed to by "bp". */ #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; { int bytesleft, len; byte *vp; static char noroom[] = "%s: No room for \"%s\" option"; vp = bp->bp_vend; if (hp->flags.msg_size) { pktlen = hp->msg_size; } else { /* * If the request was longer than the official length, build * a response of that same length where the additional length * is assumed to be part of the bp_vend (options) area. */ if (pktlen > sizeof(*bp)) { if (debug > 1) report(LOG_INFO, "request message length=%d", pktlen); } /* * Check whether the request contains the option: * Maximum DHCP Message Size (RFC1533 sec. 9.8) * and if so, override the response length with its value. * This request must lie within the first BP_VEND_LEN * bytes of the option space. */ { byte *p, *ep; byte tag, len; short msgsz = 0; p = vp + 4; ep = p + BP_VEND_LEN - 4; while (p < ep) { tag = *p++; /* Check for tags with no data first. */ if (tag == TAG_PAD) continue; if (tag == TAG_END) break; /* Now scan the length byte. */ len = *p++; switch (tag) { case TAG_MAX_MSGSZ: if (len == 2) { bcopy(p, (char*)&msgsz, 2); msgsz = ntohs(msgsz); } break; case TAG_SUBNET_MASK: /* XXX - Should preserve this if given... */ break; } /* swtich */ p += len; } if (msgsz > sizeof(*bp)) { if (debug > 1) report(LOG_INFO, "request has DHCP msglen=%d", msgsz); pktlen = msgsz; } } } if (pktlen < sizeof(*bp)) { report(LOG_ERR, "invalid response length=%d", pktlen); pktlen = sizeof(*bp); } bytesleft = ((byte*)bp + pktlen) - vp; if (pktlen > sizeof(*bp)) { if (debug > 1) report(LOG_INFO, "extended reply, length=%d, options=%d", pktlen, bytesleft); } /* Copy in the magic cookie */ bcopy(vm_rfc1048, vp, 4); vp += 4; bytesleft -= 4; 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.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 */ } /* * This one is special: Remaining options go in the ext file. * Only the subnet_mask, bootsize, and gateway should precede. */ 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. */ } /* * The remaining options are inserted by the following * function (which is shared with bootpef.c). * Keep back one byte for the TAG_END. */ len = dovend_rfc1497(hp, vp, bytesleft - 1); vp += len; bytesleft -= len; /* There should be at least one byte left. */ NEED(1, "(end)"); *vp++ = TAG_END; bytesleft--; /* Log message done by caller. */ if (bytesleft > 0) { /* * Zero out any remaining part of the vendor area. */ bzero(vp, bytesleft); } } /* dovend_rfc1048 */ #undef NEED /* * Now in readfile.c: * hwlookcmp() * iplookcmp() */ /* haddrtoa() - now in hwaddr.c */ /* * Now in dovend.c: * insert_ip() * insert_generic() * insert_u_long() */ /* get_errmsg() - now in report.c */ /* * 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: */ p->bp_hlen; if (len > MAXHADDRLEN) len = MAXHADDRLEN; haf = (int) bp->bp_htype; if (haf == 0) haf = HTYPE_ETHERNET; if (debug > 1) report(LOG_INFO, "setarp %s - %s", inet_ntoa(dst), haddrtoa(ha, len)); setarp(s, &dst, haf, ha, len); } 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.bootp-2.4.3/bootpd.h 644 125 65 12277 5615560005 7370 /************************************************************************ 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. ************************************************************************/ /* * 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 #endif #ifndef FALSE #define FALSE 0 #endif #ifndef PRIVATE #define PRIVATE static #endif #ifndef SIGUSR1 #define SIGUSR1 30 /* From 4.3 */ #endif #define MAXSTRINGLEN 80 /* Max string length */ /* Local definitions: */ #define MAX_MSG_SIZE (3*512) /* Maximum packet size */ /* * Return pointer to static string which gives full network error message. */ #define get_network_errmsg get_errmsg /* * 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 int linkcount, addrcount; struct in_addr addr[1]; /* Dynamically extended */ }; /* * Data structures used to hold shared strings and shared binary data. * The linkcount must be set appropriately. */ struct shared_string { unsigned int linkcount; char string[1]; /* Dynamically extended */ }; struct shared_bindata { unsigned int linkcount, length; byte data[1]; /* Dynamically extended */ }; /* * Flag structure which indicates which symbols have been defined for a * given host. This information is used to determine which data should or * should not be reported in the bootp packet vendor info field. */ struct flag { unsigned bootfile :1, bootserver :1, bootsize :1, bootsize_auto :1, cookie_server :1, domain_server :1, gateway :1, generic :1, haddr :1, homedir :1, htype :1, impress_server :1, iaddr :1, log_server :1, lpr_server :1, name_server :1, name_switch :1, rlp_server :1, send_name :1, subnet_mask :1, tftpdir :1, time_offset :1, time_server :1, dump_file :1, domain_name :1, swap_server :1, root_path :1, exten_file :1, reply_addr :1, nis_domain :1, nis_server :1, ntp_server :1, exec_file :1, msg_size :1, min_wait :1, /* XXX - Add new tags here */ vm_cookie :1; }; /* * The flags structure contains TRUE flags for all the fields which * are considered valid, regardless of whether they were explicitly * specified or indirectly inferred from another entry. * * The gateway and the various server fields all point to a shared list of * IP addresses. * * The hostname, home directory, and bootfile are all shared strings. * * The generic data field is a shared binary data structure. It is used to * hold future RFC1048 vendor data until bootpd is updated to understand it. * * The vm_cookie field specifies the four-octet vendor magic cookie to use * if it is desired to always send the same response to a given host. * * Hopefully, the rest is self-explanatory. */ struct host { unsigned linkcount; /* hash list inserts */ struct flag flags; /* ALL valid fields */ struct in_addr_list *cookie_server, *domain_server, *gateway, *impress_server, *log_server, *lpr_server, *name_server, *rlp_server, *time_server, *nis_server, *ntp_server; struct shared_string *bootfile, *hostname, *domain_name, *homedir, *tftpdir, *dump_file, *exten_file, *root_path, *nis_domain, *exec_file; struct shared_bindata *generic; byte vm_cookie[4], htype, /* RFC826 says this should be 16-bits but RFC951 only allocates 1 byte. . . */ haddr[MAXHADDRLEN]; int32 time_offset; unsigned int32 bootsize, msg_size, min_wait; struct in_addr bootserver, iaddr, 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; p->gateway, &vp, &bytesleft); } } 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)bootp-2.4.3/bootpef.8 644 125 65 2233 5502141064 7421 .\" 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 d future RFC1048 vendor data until bootpd is updated to understand it. * * The vm_cookie field specifies the four-octet vendor magic cookie to use * if it is desired to always send the same response to a given host. * * Hopefully, the rest is self-explanatory. */ struct host { unsigned linkcount; /* hash list inserts */ struct flag bootp-2.4.3/bootpef.c 644 125 65 15676 5720456560 7547 /************************************************************************ 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. ************************************************************************/ /* * 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 #else #include #endif #include #include #include #include /* inet_ntoa */ #ifndef NO_UNISTD #include #endif #include #include #include #include #include #include #ifndef USE_BFUNCS #include /* 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 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; 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); } /* mktagfile */ /* * 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: */ brace-offset: -4 * c-label-offset: -4 * c-brace-offset: 0 * Endbootp-2.4.3/bootpgw.c 644 125 65 37364 5720471746 7573 /* * 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. ************************************************************************/ /* * BOOTPGW is typically used to forward BOOTP client requests from * one subnet to a BOOTP server on a different subnet. */ #include #include #include #include #include #include #include #include #include #include #include /* inet_ntoa */ #ifndef NO_UNISTD #include #endif #include #include #include #include #include #include #include #include #include #ifdef NO_SETSID # include /* for O_RDONLY, etc */ #endif #ifndef USE_BFUNCS # include /* 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 MAX_MSG_SIZE (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. */ struct in_addr my_ip_addr; struct utsname my_uname; char *hostname; /* * 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(MAX_MSG_SIZE); 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; if (uname(&my_uname) < 0) { fprintf(stderr, "bootpgw: can't get hostname\n"); exit(1); } hostname = my_uname.nodename; hep = gethostbyname(hostname); 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 (;;) { struct timeval tv; readfds = 1 << s; if (timeout) tv = *timeout; nfound = select(s + 1, (fd_set *)&readfds, NULL, NULL, (timeout) ? &tv : NULL); 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, MAX_MSG_SIZE, 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; 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; struct ifreq *ifr; /* * 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 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; unsigned char *ha; int len, haf; 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; haf = (int) bp->bp_htype; if (haf == 0) haf = HTYPE_ETHERNET; if (debug > 1) report(LOG_INFO, "setarp %s - %s", inet_ntoa(bp->bp_yiaddr), haddrtoa(ha, len)); setarp(s, &bp->bp_yiaddr, haf, 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: */ gw: 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",bootp-2.4.3/bootptab.5 644 125 65 24365 5524024621 7627 .\" Copyright (c) 1988, 1989, 1991 Carnegie Mellon University .\" .\" $Header: $ .\" .TH BOOTPTAB 5 "October 31, 1991" "Carnegie Mellon University" .UC 6 .SH NAME bootptab \- Internet Bootstrap Protocol server database .SH DESCRIPTION The .I bootptab file is the configuration database file for .IR bootpd , the Internet Bootstrap Protocol server. It's format is similar to that of .IR termcap (5) in which two-character case-sensitive tag symbols are used to represent host parameters. These parameter declarations are separated by colons (:), with a general format of: .PP .I " hostname:tg=value. . . :tg=value. . . :tg=value. . . ." .PP where .I hostname is the actual name of a bootp client (or a "dummy entry"), and .I tg 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 :). The currently recognized tags are: .PP .br bf Bootfile .br bs Bootfile size in 512-octet blocks .br cs Cookie server address list .br df Merit dump file .br dn Domain name .br ds Domain name server address list .br ef Extension file .br gw Gateway address list .br ha Host hardware address .br hd Bootfile home directory .br hn Send client's hostname to client .br ht Host hardware type (see Assigned Numbers RFC) .br im Impress server address list .br ip Host IP address .br lg Log server address list .br lp LPR server address list .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 .br sa TFTP server address client should use .br sm Host subnet mask .br sw Swap server address .br tc Table continuation (points to similar "template" host entry) .br td TFTP root directory used by "secure" TFTP servers .br to Time offset in seconds from UTC .br 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, .RI T n , where .I n is an RFC1084 vendor field tag number. Thus it is possible to immediately take advantage of future extensions to RFC1084 without being forced to modify .I bootpd first. Generic data may be represented as either a stream of hexadecimal numbers or as a quoted string of ASCII characters. The length of the generic data is automatically determined and inserted into the proper field(s) of the RFC1084-style bootp reply. .PP The following tags take a whitespace-separated list of IP addresses: .BR cs , .BR ds , .BR gw , .BR im , .BR lg , .BR lp , .BR ns , .BR nt , .BR ra , .BR rl , and .BR ts . The .BR ip , .BR sa , .BR sw , .BR sm , and .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'). 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 tag specifies the hardware type code as either an unsigned decimal, octal, or hexadecimal integer or one of the following symbolic names: .B ethernet or .B ether for 10Mb Ethernet, .B ethernet3 or .B ether3 for 3Mb experimental Ethernet, .BR ieee802 , .BR tr , or .B token-ring for IEEE 802 networks, .B pronet for Proteon ProNET Token Ring, or .BR chaos , .BR arcnet , or .B ax.25 for Chaos, ARCNET, and AX.25 Amateur Radio networks, respectively. The .B ha 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 .B ha tag must be preceded by the .B ht 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 values of the .B hd and .B bf symbols determine how the server fills in the bootfile field of the bootp reply packet. .PP If the client provides a file name it is left as is. Otherwise, if the .B bf option is specified its value is copied into the reply packet. If the .B hd 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 provide a security feature to change their root directory using the .IR chroot (2) system call. The .B td 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 .B td tag. For example, if the real absolute path to your BOOTP client bootfile is /tftpboot/bootfiles/bootimage, and .IR tftpd uses /tftpboot as its "secure" directory, then specify the following in .IR bootptab : .PP .br :td=/tftpboot:hd=/bootfiles:bf=bootimage: .PP If your bootfiles are located directly in /tftpboot, use: .PP .br :td=/tftpboot:hd=/:bf=bootimage: .PP The .B sa tag may be used to specify the IP address of the particular TFTP server you wish the client to use. In the absence of this tag, .I bootpd will tell the client to perform TFTP to the same machine .I bootpd is running on. .PP The time offset .B to may be either a signed decimal integer specifying the client's time zone offset in seconds from UTC, or the keyword .B auto which uses the server's time zone offset. Specifying the .B to symbol as a boolean has the same effect as specifying .B auto as its value. .PP The bootfile size .B bs may be either a decimal, octal, or hexadecimal integer specifying the size of the bootfile in 512-octet blocks, or the keyword .B auto which causes the server to automatically calculate the bootfile size at each request. As with the time offset, specifying the .B bs symbol as a boolean has the same effect as specifying .B auto as its value. .PP The vendor magic cookie selector (the .B vm tag) may take one of the following keywords: .B auto (indicating that vendor information is determined by the client's request), .B rfc1048 or .B rfc1084 (which always forces an RFC1084-style reply), or .B cmu (which always forces a CMU-style reply). .PP The .B hn tag is strictly a boolean tag; it does not take the usual equals-sign and value. It's presence indicates that the hostname should be sent to RFC1084 clients. .I Bootpd attempts to send the entire hostname as it is specified in the configuration file; if this will not fit into the reply packet, the name is shortened to just the host field (up to the first period, if present) and then tried. In no case is an arbitrarily-truncated hostname sent (if nothing reasonable will fit, nothing is sent). .PP Often, many host entries share common values for certain tags (such as name servers, etc.). Rather than repeatedly specifying these tags, a full specification can be listed for one host entry and shared by others via the .B tc (table continuation) mechanism. Often, the template entry is a dummy host which doesn't actually exist and never sends bootp requests. This feature is similar to the .B tc feature of .IR termcap (5) for similar terminals. Note that .I bootpd allows the .B tc tag symbol to appear anywhere in the host entry, unlike .I termcap which requires it to be the last tag. Information explicitly specified for a host always overrides information implied by a .B tc tag symbol, regardless of its location within the entry. The value of the .B tc tag may be the hostname or IP address of any host entry previously listed in the configuration file. .PP Sometimes it is necessary to delete a specific tag after it has been inferred via .BR tc . This can be done using the construction .IB tag @ which removes the effect of .I tag as in .IR termcap (5). For example, to completely undo an IEN-116 name server specification, use ":ns@:" at an appropriate place in the configuration entry. After removal with .BR @ , a tag is eligible to be set again through the .B tc mechanism. .PP Blank lines and lines beginning with "#" are ignored in the configuration file. Host entries are separated from one another by newlines; a single host entry may be extended over multiple lines if the lines end with a backslash (\\). It is also acceptable for lines to be longer than 80 characters. Tags may appear in any order, with the following exceptions: the hostname must be the very first field in an entry, and the hardware type must precede the hardware address. .PP An example .I /etc/bootptab file follows: .PP .nf # Sample bootptab file (domain=andrew.cmu.edu) .default:\\ :hd=/usr/boot:bf=null:\\ :ds=netserver, lancaster:\\ :ns=pcs2, pcs1:\\ :ts=pcs2, pcs1:\\ :sm=255.255.255.0:\\ :gw=gw.cs.cmu.edu:\\ :hn:to=-18000: 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: # 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 .SH "SEE ALSO" .br bootpd(8), tftpd(8), .br DARPA Internet Request For Comments RFC951, RFC1048, RFC1084, Assigned Numbers QUEST: 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 bootp-2.4.3/bootptab.cmu 644 125 65 10221 5542107672 10241 # /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: PP The vendor magic cookie selector (the .B vm tag) may take one of the following keywords: .B auto (indicating that vendor information is determined by the client's request), .B rfc1048 or .B rfc1084 (which always forces an RFC1084-style reply), or .B cmu (which always forces a CMU-style reply). .PP The .B hn tag is strictly a boolean tag; it does not take the usubootp-2.4.3/bootptab.mcs 644 125 65 4753 5735634063 10237 # /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" empty, run bootpd with the "-c /tftpboot" switch # so path names (boot files) will be interpreted relative to the same # directory as tftpd will use when opening files. .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 bach: tc=.subnet16:ha="08:00:20:04:98:8d":bf=boot.sun4m: xanadu:tc=.subnet17:ha="00:80:42:42:04:c7":bf=boot.sun4c: r:tc=.subnet19:ha=00Dbootp-2.4.3/bootptest.8 644 125 65 3247 5625233460 10024 .\" 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 \-f .I bootfile ] [ .B \-h ] [ .B \-m .I magic_number ] .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 \-f .I bootfile Fill in the boot file field of the request with .IR bootfile . .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. .TP .B \-m .I magic_number Initialize the first word of the vendor options field with .IR magic_number . .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 . 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 :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 bootp-2.4.3/bootptest.c 644 125 65 25776 5720670371 10134 /* * 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 was 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. Gordon W. Ross * * 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 */ char *usage = "bootptest [-h] server-name [vendor-data-template-file]"; #include #include #include #include #include #include #include #include #include #include /* inet_ntoa */ #ifndef NO_UNISTD #include #endif #include #include #include #include #include #include #include #include #include "bootp.h" #include "bootptest.h" #include "getif.h" #include "getether.h" #include "patchlevel.h" static void send_request(); #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 *sndbuf; /* Send packet buffer */ char *rcvbuf; /* Receive packet buffer */ struct utsname my_uname; char *hostname; /* * 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. */ void 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, fromlen, recvcnt; int use_hwa = 0; int32 vend_magic; 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); /* * Verify that "struct bootp" has the correct official size. * (Catch evil compilers that do struct padding.) */ assert(sizeof(struct bootp) == BP_MINPKTSZ); if (uname(&my_uname) < 0) { fprintf(stderr, "%s: can't get hostname\n", argv[0]); exit(1); } hostname = my_uname.nodename; sndbuf = malloc(BUFLEN); rcvbuf = malloc(BUFLEN); if (!sndbuf || !rcvbuf) { printf("malloc failed\n"); exit(1); } /* default magic number */ bcopy(vm_rfc1048, (char*)&vend_magic, 4); /* 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; case 'm': /* Magic number value. */ if (argc < 2) goto error; argc--; argv++; vend_magic = inet_addr(*argv); 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, (char*)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. */ 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((char*)&vend_magic, bp->bp_vend, 4); if (vend_magic) 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 in the last second. * 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); } static void 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++) != '\0') { 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: */ cbootp-2.4.3/bootptest.h 644 125 65 1232 5560357721 10101 /* 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 cützone.hý getether.hn_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); bootbootp-2.4.3/bptypes.h 644 125 65 457 5530227725 7531 /* 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 */ àÜlookup.hashøÝ patchlevel.høÞ print-bootp.c$ß readfile.c8à readfile.hLäreport.chh`åreport.hh.tæ strerror.ceˆëbootp-2.4.3/dovend.c 644 125 65 23657 5720440024 7352 /* * dovend.c : Inserts all but the first few vendor options. */ #include #include #include /* inet_ntoa */ #include #include #include #include #include #ifndef USE_BFUNCS # include /* 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; 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). */ char *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: */ r dump_file. Add 2 to account for * TAG_DUMP_FILE and length. */ len = sbootp-2.4.3/dovend.h 644 125 65 441 5530227217 7307 /* 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  patchlevel.høÞ print-bootp.c$ß readfile.c8à readfile.hLäreport.ch`åreport.hhtæ strerror.chˆë syslog.confœìsyslog.hnf°íbootp-2.4.3/dumptab.c 644 125 65 21471 5720457121 7525 /* * dumptab.c - handles dumping the database */ #include #include #include /* inet_ntoa */ #include #include #include #include #ifndef USE_BFUNCS #include /* 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\ #\tex -- exec file (YORK_EX_OPTION)\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\ #\tms -- message size\n\ #\tmw -- min wait (secs)\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.exec_file) { fprintf(fp, "\\\n\t:ex=%s:", hp->exec_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.msg_size) { fprintf(fp, "\\\n\t:ms=%d:", hp->msg_size); } if (hp->flags.min_wait) { fprintf(fp, "\\\n\t:mw=%d:", hp->min_wait); } 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: */ 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 *bootp-2.4.3/getether.c 644 125 65 21752 5720456102 7700 /* * 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. */ #include #include #ifndef NO_UNISTD #include #endif #include #include #include "getether.h" #include "report.h" #define EALEN 6 #if defined(ultrix) || (defined(__osf__) && defined(__alpha)) /* * This is really easy on Ultrix! Thanks to * Harald Lundberg 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 #include /* 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 #include /* needed by net_if.h */ #include /* for NIOCBIND */ #include /* 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 for this code. */ #include #include #include #include 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 #include #include #include #ifndef NULL #define NULL 0 #endif int 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 and * updated by Pauline Middelink * * 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 #include #include /* struct ifreq */ #include /* Needed for IOCTL defs */ int getether(ifname, eap) char *ifname, *eap; { int rc = -1; int fd; struct ifreq phys; memset(&phys, 0, 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 { memcpy(eap, &phys.ifr_hwaddr.sa_data, 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 int 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: */ the size of the "destbootp-2.4.3/getif.c 644 125 65 6141 5720476377 7162 /* * getif.c : get an interface structure */ #include #include #include #if defined(SUNOS) || defined(SVR4) #include #endif #ifdef SVR4 #include #endif #ifdef _AIX32 #include /* for struct timeval in net/if.h */ #endif #include /* for struct ifreq */ #include #ifndef NO_UNISTD #include #endif #include #include #include #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: */ (*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 dlbootp-2.4.3/getif.h 644 125 65 175 5470722765 7145 /* getif.h */ #ifdef __STDC__ extern struct ifreq *getif(int, struct in_addr *); #else extern struct ifreq *getif(); #endif hwaddr.h¸ÌÛlookup.cÌàÜlookup.hàøÝ patchlevel.hÝÞ print-bootp.cÞ$ß readfile.c$8à readfile.h8Läreport.cL`åreport.h`tæ strerror.ctˆë syslog.confœìsyslog.hœ°í trygetea.c°Äî trygetif.cÄØô trylook.cØèùtzone.cübootp-2.4.3/hash.c 644 125 65 24125 5720452740 7015 /************************************************************************ 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. ************************************************************************/ /* * Generalized hash table ADT * * Provides multiple, dynamically-allocated, variable-sized hash tables on * various data and keys. * * This package attempts to follow some of the coding conventions suggested * by Bob Sidebotham and the AFS Clean Code Committee of the * Information Technology Center at Carnegie Mellon. */ #include #include #ifndef USE_BFUNCS #include /* 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. * * This routine creates and intializes a hash table of size "tablesize" * entries. Successful calls return a pointer to the hash table (which must * be passed to other hash routines to identify the hash table). Failed * calls return NULL. */ hash_tbl * hash_Init(tablesize) unsigned tablesize; { register hash_tbl *hashtblptr; register unsigned totalsize; 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]; } } else { hashtblptr = NULL; /* Disallow zero-length tables */ } return hashtblptr; /* NULL if failure */ } /* * 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_FreeMembers(bucketptr, free_data) hash_member *bucketptr; hash_freefp free_data; { hash_member *nextbucket; while (bucketptr) { nextbucket = bucketptr->next; (*free_data) (bucketptr->data); free((char *) bucketptr); bucketptr = nextbucket; } } /* * This routine re-initializes the hash table. It frees all the allocated * memory and resets all bucket pointers to NULL. */ 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_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. * * For each byte of the string, this function left-shifts the value in an * accumulator and then adds the byte into the accumulator. The contents of * the accumulator is returned after the entire string has been processed. * It is assumed that this result will be used as the "hashcode" parameter in * calls to other functions in this package. These functions automatically * adjust the hashcode for the size of each hashtable. * * This algorithm probably works best when the hash table size is a prime * number. * * Hopefully, this function is better than the previous one which returned * the sum of the squares of all the bytes. I'm still open to other * suggestions for a default hash function. The programmer is more than * welcome to supply his/her own hash function as that is one of the design * features of this package. */ 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; } /* * 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; 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 */ } memberptr = memberptr->next; } 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 * its uniqueness. * * If the insertion is successful 0 is returned. If a matching entry * already exists in the given bucket of the hash table, or some other error * occurs, -1 is returned and the insertion is not done. */ int hash_Insert(hashtable, hashcode, compare, key, element) hash_tbl *hashtable; unsigned hashcode; hash_cmpfp compare; hash_datum *key, *element; { 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 = (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; hash_cmpfp compare; hash_datum *key; hash_freefp free_data; { hash_member *memberptr, *tempptr; hash_member *previous = NULL; 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; /* * Stop hashi_FreeMembers() from deleting the whole list! */ memberptr->next = NULL; hashi_FreeMembers(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_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. * * If the data entry is found, a pointer to it is returned. Otherwise, * NULL is returned. */ 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); } memberptr = memberptr->next; } return NULL; } /* * Return the next available entry in the hashtable for a linear search */ 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) { /* * 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; { 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: */ THER #endif /* __linux__ */ /* If we don't know how on this system, just return an error. */ #ifndef GETETHER int 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: */ the size of the "destbootp-2.4.3/hash.h 644 125 65 11606 5501645670 7025 #ifndef HASH_H #define HASH_H /* hash.h */ /************************************************************************ 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. ************************************************************************/ /* * Generalized hash table ADT * * Provides multiple, dynamically-allocated, variable-sized hash tables on * various data and keys. * * This package attempts to follow some of the coding conventions suggested * by Bob Sidebotham and the AFS Clean Code Committee. */ /* * The user must supply the following: * * 1. A comparison function which is declared as: * * int compare(data1, data2) * hash_datum *data1, *data2; * * This function must compare the desired fields of data1 and * data2 and return TRUE (1) if the data should be considered * equivalent (i.e. have the same key value) or FALSE (0) * otherwise. This function is called through a pointer passed to * the various hashtable functions (thus pointers to different * functions may be passed to effect different tests on different * hash tables). * * Internally, all the functions of this package always call the * compare function with the "key" parameter as the first parameter, * and a full data element as the second parameter. Thus, the key * and element arguments to functions such as hash_Lookup() may * actually be of different types and the programmer may provide a * compare function which compares the two different object types * as desired. * * Example: * * int compare(key, element) * char *key; * struct some_complex_structure *element; * { * return !strcmp(key, element->name); * } * * key = "John C. Doe" * element = &some_complex_structure * hash_Lookup(table, hashcode, compare, key); * * 2. A hash function yielding an unsigned integer value to be used * as the hashcode (index into the hashtable). Thus, the user * may hash on whatever data is desired and may use several * different hash functions for various different hash tables. * The actual hash table index will be the passed hashcode modulo * the hash table size. * * A generalized hash function, hash_HashFunction(), is included * with this package to make things a little easier. It is not * guarenteed to use the best hash algorithm in existence. . . . */ /* * Various hash table definitions */ /* * Define "hash_datum" as a universal data type */ #ifdef __STDC__ typedef void hash_datum; #else typedef char hash_datum; #endif typedef struct hash_memberstruct hash_member; typedef struct hash_tblstruct hash_tbl; typedef struct hash_tblstruct_hdr hash_tblhdr; struct hash_memberstruct { hash_member *next; hash_datum *data; }; struct hash_tblstruct_hdr { unsigned size, bucketnum; hash_member *member; }; struct hash_tblstruct { unsigned size, bucketnum; hash_member *member; /* Used for linear dump */ hash_member *table[1]; /* Dynamically extended */ }; /* 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 */ xt; } } return retval; } /* * Locate and return the data entry associated with the given key. * * If the data ebootp-2.4.3/hwaddr.c 644 125 65 21021 5735624032 7334 /* * hwaddr.c - routines that deal with hardware addresses. * (i.e. Ethernet) */ #include #include #include #include #if defined(SUNOS) || defined(SVR4) #include #endif #ifdef SVR4 #include #include #include #endif #ifdef _AIX32 #include /* for struct timeval in net/if.h */ #include /* for struct ifnet in net/if_arp.h */ #endif #include #include #ifdef WIN_TCP #include #include #endif #include #ifndef NO_UNISTD #include #endif #include #ifndef USE_BFUNCS /* Yes, memcpy is OK here (no overlapped copies). */ #include #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 #ifndef ATF_INUSE /* Not defined on some systems (i.e. Linux) */ #define ATF_INUSE 0 #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, hafamily, haddr, halen) int s; /* socket fd */ struct in_addr *ia; /* protocol address */ int hafamily; /* HW address family */ u_char *haddr; /* HW address data */ int halen; { #ifdef SIOCSARP #ifdef WIN_TCP /* This is an SVR4 with different networking code from * Wollongong WIN-TCP. Not quite like the Lachman code. * Code from: drew@drewsun.FEITH.COM (Andrew B. Sudell) */ #undef SIOCSARP #define SIOCSARP ARP_ADD struct arptab arpreq; /* Arp table entry */ bzero((caddr_t) &arpreq, sizeof(arpreq)); arpreq.at_flags = ATF_COM; /* Set up IP address */ arpreq.at_in = ia->s_addr; /* Set up Hardware Address */ bcopy(haddr, arpreq.at_enaddr, halen); /* Set the Date Link type. */ /* XXX - Translate (hafamily) to dltype somehow? */ arpreq.at_dltype = DL_ETHER; #else /* WIN_TCP */ /* Good old Berkeley way. */ struct arpreq arpreq; /* Arp request ioctl block */ struct sockaddr_in *si; char *p; 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. */ #ifdef __linux__ /* XXX - Do others need this? -gwr */ /* * Linux requires the sa_family field set. * longyear@netcom.com (Al Longyear) */ arpreq.arp_ha.sa_family = hafamily; #endif /* linux */ /* This variable is just to help catch type mismatches. */ p = arpreq.arp_ha.sa_data; bcopy(haddr, p, halen); #endif /* WIN_TCP */ #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 , * bear@upsys.se (Bj|rn Sj|holm), * Michael Kuschke , */ { int fd; struct strioctl iocb; 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 */ #else /* SIOCSARP */ /* * Oh well, SIOCSARP is not defined. Just run arp(8). * Need to delete partial entry first on some systems. * XXX - Gag! */ int status; char buf[256]; char *a; extern char *inet_ntoa(); a = inet_ntoa(*ia); sprintf(buf, "arp -d %s; arp -s %s %s temp", a, a, haddrtoa(haddr, halen)); if (debug > 2) report(LOG_INFO, buf); status = system(buf); if (status) report(LOG_ERR, "arp failed, exit code=0x%x", status); return; #endif /* SIOCSARP */ } /* * 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: */ ucket = 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. */ hbootp-2.4.3/hwaddr.h 644 125 65 1712 5720467405 7331 /* 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 *, int, 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 */ .ic_timout = 0; iocb.ic_dp = (char *)&arpreq; iocbbootp-2.4.3/lookup.c 644 125 65 4450 5720477026 7366 /* * lookup.c - Lookup IP address, HW address, netmask */ #include #include #ifdef _AIX32 #include /* for struct timeval in net/if.h */ #endif #include #include #ifdef ETC_ETHERS #include extern int ether_hostton(); #endif #include #include #ifndef USE_BFUNCS #include /* 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: */ xFF)); 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 bootp-2.4.3/lookup.h 644 125 65 477 5536731511 7355 /* 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 getif.cØô trylook.cœèùtzone.cützone.hý getether.hK here (no overlapped copies). */ #define bcopy(a,b,c) memcpy(b,a,c) #endif #include "bootp.bootp-2.4.3/patchlevel.h 644 125 65 77 5735575253 10161 /* patchlevel.h */ #define VERSION "2.4" #define PATCHLEVEL 3 Þ print-bootp.c$ß readfile.c8à readfile.hLäreport.ch`åreport.hhÞtæ strerror.c$ˆë syslog.confœìsyslog.hnf°í trygetea.cÄî trygetif.cØô trylook.cèùtzone.cützone.hý getether.hý getether.hK here (no overlapped copies). */ #define bcopy(a,b,c) memcpy(b,a,c) #endif #include "bootp.bootp-2.4.3/print-bootp.c 644 125 65 30254 5720477131 10350 /* * 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: */ #include #include #include #include #ifdef _AIX32 #include /* for struct timeval in net/if.h */ #endif #include #include #include #include #include "bootp.h" #include "bootptest.h" /* These decode the vendor data. */ extern int printfn(); 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 rfc1048_print(bp, length) register u_char *bp; int length; { u_char tag; u_char *ep; register int len; 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 */ /* 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: */ p_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 verbobootp-2.4.3/readfile.c 644 125 65 135156 5720463745 7703 /************************************************************************ 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. ************************************************************************/ /* * bootpd configuration file reading code. * * The routines in this file deal with reading, interpreting, and storing * the information found in the bootpd configuration file (usually * /etc/bootptab). */ #include #include #include #include #include #include #include #include #include #include #include #include #ifndef USE_BFUNCS #include /* 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_HWADDR (-5) #define E_BAD_LONGWORD (-6) #define E_BAD_HWATYPE (-7) #define E_BAD_PATHNAME (-8) #define E_BAD_VALUE (-9) /* 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_HWADDR 5 #define SYM_HOMEDIR 6 #define SYM_HTYPE 7 #define SYM_IMPRESS_SERVER 8 #define SYM_IPADDR 9 #define SYM_LOG_SERVER 10 #define SYM_LPR_SERVER 11 #define SYM_NAME_SERVER 12 #define SYM_RLP_SERVER 13 #define SYM_SUBNET_MASK 14 #define SYM_TIME_OFFSET 15 #define SYM_TIME_SERVER 16 #define SYM_VENDOR_MAGIC 17 #define SYM_SIMILAR_ENTRY 18 #define SYM_NAME_SWITCH 19 #define SYM_BOOTSIZE 20 #define SYM_BOOT_SERVER 22 #define SYM_TFTPDIR 23 #define SYM_DUMP_FILE 24 #define SYM_DOMAIN_NAME 25 #define SYM_SWAP_SERVER 26 #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 */ #define SYM_EXEC_FILE 33 /* YORK_EX_OPTION */ #define SYM_MSG_SIZE 34 #define SYM_MIN_WAIT 35 /* 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 256 /* 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; }; struct htypename { char *name; byte htype; }; 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 * values of the symbol codes (SYM_. . .) are unimportant, but they must * all be unique. */ PRIVATE struct symbolmap symbol_list[] = { {"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}, {"ex", SYM_EXEC_FILE}, /* YORK_EX_OPTION */ {"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}, {"ms", SYM_MSG_SIZE}, {"mw", SYM_MIN_WAIT}, {"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 */ }; /* * List of symbolic names for hardware types. Name translates into * hardware type code listed with it. Names must begin with a letter * and must be all lowercase. This is searched linearly, so put * commonly-used entries near the beginning. */ 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} }; /* * Externals and forward declarations. */ #ifdef __STDC__ #define P(args) args #else #define P(args) () #endif extern boolean iplookcmp(); 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); } } /* * Read bootptab database file. Avoid rereading the file if the * write date hasn't changed since the last time we read it. */ void readtab(force) int force; { 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", bootptab, get_errmsg()); return; } #ifdef DEBUG 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 ((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); /* * Open bootptab file. */ if ((fp = fopen(bootptab, "r")) == NULL) { report(LOG_ERR, "error opening \"%s\": %s", bootptab, get_errmsg()); return; } /* * Record file modification time. */ if (fstat(fileno(fp), &st) < 0) { report(LOG_ERR, "fstat: %s", get_errmsg()); fclose(fp); return; } 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; } 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, haddrlength(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++; } nentries++; } 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 * starting with "#" are ignored (removed). Backslashes (\) always quote * the next character except that newlines preceeded by a backslash cause * line-continuation onto the next line. The entry is terminated by a * newline character which is not preceeded by a backslash. Sequences * surrounded by double quotes are taken literally (including newlines, but * not backslashes). * * The "bufsiz" parameter points to an unsigned int which specifies the * maximum permitted buffer size. Upon return, this value will be replaced * with the actual length of the entry (not including the null terminator). * * This code is a little scary. . . . I don't like using gotos in C * either, but I first wrote this as an FSM diagram and gotos seemed like * 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; { 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 */ } } } 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 (\). */ mainloop: c = fgetc(fp); switch (c) { case EOF: case '\n': 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; } 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; } } } 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; } } 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 */ } } /* 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 */ } /* * 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 * host structure pointed to by "host". If there is any problem with the * entry, an error message is reported via report(), no further processing * is done, and -1 is returned. Successful calls return 0. * * (Some errors probably shouldn't be so completely fatal. . . .) */ PRIVATE int process_entry(host, src) struct host *host; char *src; { int retval; char *msg; if (!host || *src == '\0') { return -1; } host->hostname = get_shared_string(&src); #if 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 '/')"; case E_BAD_VALUE: msg = "bad value"; 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) /* Parse an unsigned integer value for MEMBER */ #define PARSE_UINT(MEMBER) do \ { \ if (optype == OP_BOOLEAN) \ return E_SYNTAX_ERROR; \ hp->flags.MEMBER = FALSE; \ if (optype == OP_ADDITION) { \ value = get_u_long(symbol); \ hp->MEMBER = value; \ 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 * point to the next tag entry). * * Obviously, this need a few more comments. . . . */ PRIVATE int eval_symbol(symbol, hp) char **symbol; struct host *hp; { char tmpstr[MAXSTRINGLEN]; byte *tmphaddr; struct symbolmap *symbolptr; u_int32 value; int32 timeoff; int i, numsymbols; unsigned len; int optype; /* Indicates boolean, addition, or deletion */ eat_whitespace(symbol); /* Make sure this is set before returning. */ current_tagname[0] = (*symbol)[0]; current_tagname[1] = (*symbol)[1]; current_tagname[2] = 0; 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", (int)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; case '@': optype = OP_DELETION; break; case ':': case '\0': 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; } 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: PARSE_STR(bootfile); break; case SYM_COOKIE_SERVER: PARSE_IAL(cookie_server); break; case SYM_DOMAIN_SERVER: PARSE_IAL(domain_server); break; case SYM_GATEWAY: PARSE_IAL(gateway); break; 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; } break; case SYM_HOMEDIR: PARSE_STR(homedir); break; case SYM_HTYPE: 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 (value >= hwinfocnt) { return E_BAD_HWATYPE; } hp->htype = (byte) (value & 0xFF); hp->flags.htype = TRUE; } break; case SYM_IMPRESS_SERVER: PARSE_IAL(impress_server); break; case SYM_IPADDR: PARSE_IA1(iaddr); break; case SYM_LOG_SERVER: PARSE_IAL(log_server); break; case SYM_LPR_SERVER: PARSE_IAL(lpr_server); break; case SYM_NAME_SERVER: PARSE_IAL(name_server); break; case SYM_RLP_SERVER: PARSE_IAL(rlp_server); break; case SYM_SUBNET_MASK: PARSE_IA1(subnet_mask); break; case SYM_TIME_OFFSET: 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 { if (sscanf(tmpstr, "%d", (int*)&timeoff) != 1) return E_BAD_LONGWORD; hp->time_offset = timeoff; } hp->flags.time_offset = TRUE; } break; case SYM_TIME_SERVER: PARSE_IAL(time_server); break; case SYM_VENDOR_MAGIC: 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; } } break; case SYM_SIMILAR_ENTRY: switch (optype) { case OP_ADDITION: fill_defaults(hp, symbol); break; default: return E_SYNTAX_ERROR; } break; case SYM_NAME_SWITCH: switch (optype) { case OP_ADDITION: return E_SYNTAX_ERROR; case OP_DELETION: 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; case SYM_BOOTSIZE: 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; case OP_DELETION: hp->flags.bootsize = FALSE; break; case OP_BOOLEAN: hp->flags.bootsize = TRUE; hp->flags.bootsize_auto = TRUE; break; } break; case SYM_BOOT_SERVER: PARSE_IA1(bootserver); break; case SYM_TFTPDIR: PARSE_STR(tftpdir); if ((hp->tftpdir != NULL) && (hp->tftpdir->string[0] != '/')) return E_BAD_PATHNAME; break; case SYM_DUMP_FILE: PARSE_STR(dump_file); break; case SYM_DOMAIN_NAME: PARSE_STR(domain_name); break; case SYM_SWAP_SERVER: 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; #ifdef YORK_EX_OPTION case SYM_EXEC_FILE: PARSE_STR(exec_file); break; #endif case SYM_MSG_SIZE: PARSE_UINT(msg_size); if (hp->msg_size < BP_MINPKTSZ || hp->msg_size > MAX_MSG_SIZE) return E_BAD_VALUE; break; case SYM_MIN_WAIT: PARSE_UINT(min_wait); break; /* XXX - Add new tags here */ default: 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 * allowable length of the string (including null-terminator) is passed as * "length". The actual length of the string which was read is returned in * the unsigned integer pointed to by "length". This value is the same as * that which would be returned by applying the strlen() function on the * destination string (i.e the terminating null is not counted as a * character). Trailing whitespace is removed from the string. For * convenience, the function returns the new value of "dest". * * The string is read until the maximum number of characters, an unquoted * colon (:), or a null character is read. The return string in "dest" is * null-terminated. */ 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; } if (**src == '\\') { (*src)++; if (!**src) { break; } } *dest++ = *(*src)++; n++; } /* * Remove that troublesome trailing whitespace. . . */ while ((n > 0) && isspace(dest[-1])) { dest--; n--; } *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 * containing the string. * * The string is read using the same rules as get_string() above. */ PRIVATE struct shared_string * get_shared_string(src) char **src; { char retstring[MAXSTRINGLEN]; struct shared_string *s; unsigned 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); return s; } /* * Load RFC1048 generic information directly into a memory buffer. * * "src" indirectly points to the ASCII representation of the generic data. * "dest" points to a string structure which is updated to point to a new * string with the new data appended to the old string. The old string is * freed. * * The given tag value is inserted with the new data. * * The data may be represented as either a stream of hexadecimal numbers * representing bytes (any or all bytes may optionally start with '0x' and * be separated with periods ".") or as a quoted string of ASCII * characters (the quotes are required). */ 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; 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). * * Return TRUE for good names, FALSE otherwise. */ PRIVATE boolean goodname(hostname) register char *hostname; { 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 */ } /* * 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(d1, d2) hash_datum *d1, *d2; { return FALSE; } /* * Function for comparing a string with the hostname field of a host * structure. */ boolean nmcmp(d1, d2) hash_datum *d1, *d2; { char *name = (char *) d1; /* XXX - OK? */ struct host *hp = (struct host *) d2; return !strcmp(name, hp->hostname->string); } /* * Compare function to determine whether two hardware addresses are * equivalent. Returns TRUE if "host1" and "host2" are equivalent, FALSE * otherwise. * * If the hardware addresses of "host1" and "host2" are identical, but * they are on different IP subnets, this function returns FALSE. * * This function is used when inserting elements into the hardware address * hash table. */ PRIVATE boolean hwinscmp(d1, d2) hash_datum *d1, *d2; { 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; } /* 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; { 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; } 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.bootsize) { 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); #ifdef YORK_EX_OPTION DUP_LINK(exec_file); #endif DUP_COPY(msg_size); DUP_COPY(min_wait); /* 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; { register char *t; t = *s; while (*t && (*t != ':')) { t++; } if (*t) { t++; } *s = t; } /* * This function adjusts the caller's pointer to point to the first * non-whitespace character. If it runs into a null character, it leaves * the pointer pointing to it. */ PRIVATE void eat_whitespace(s) char **s; { register char *t; t = *s; while (*t && isspace(*t)) { t++; } *s = t; } /* * This function converts the given string to all lowercase. */ PRIVATE void makelower(s) char *s; { while (*s) { if (isupper(*s)) { *s = tolower(*s); } s++; } } /* * * N O T E : * * In many of the functions which follow, a parameter such as "src" or * "symbol" is passed as a pointer to a pointer to something. This is * done for the purpose of letting the called function update the * caller's copy of the parameter (i.e. to effect call-by-reference * parameter passing). The value of the actual parameter is only used * to locate the real parameter of interest and then update this indirect * 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 * structure containing the list of addresses is returned. NULL is * returned if no addresses were found at all. The pointer pointed to by * "src" is updated to point to the first non-address (illegal) character. */ 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 (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 */ } 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) * * "src" is a value-result parameter; the pointer it points to is updated * to point to the next data position. "result" points to an unsigned long * in which an address is returned. * * This function parses the IP address string in ASCII "dot notation" pointed * to by (*src) and places the result (in network byte order) in the unsigned * long pointed to by "result". For malformed addresses, -1 is returned, * (*src) points to the first illegal character, and the unsigned long pointed * to by "result" is unchanged. Successful calls return 0. */ PRIVATE int prs_inetaddr(src, result) char **src; u_int32 *result; { char tmpstr[MAXSTRINGLEN]; register u_int32 value; u_int32 parts[4], *pp; int n; char *s, *t; /* 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; } /* * 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) */ 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); } #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); } /* * "src" points to a pointer which in turn points to a hexadecimal ASCII * string. This string is interpreted as a hardware address and returned * as a pointer to the actual hardware address, represented as an array of * bytes. * * The ASCII string must have the proper number of digits for the specified * hardware type (e.g. twelve digits for a 48-bit Ethernet address). * Two-digit sequences (bytes) may be separated with periods (.) and/or * prefixed with '0x' for readability, but this is not required. * * For bad addresses, the pointer which "src" points to is updated to point * to the start of the first two-digit sequence which was bad, and the * function returns a NULL pointer. */ PRIVATE byte * prs_haddr(src, htype) char **src; u_int htype; { 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; } tmplen = sizeof(tmpstr); get_string(src, tmpstr, &tmplen); p = tmpstr; /* 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. */ } hap = haddr; while (hap < haddr + hal) { if ((*p == '.') || (*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 * character pointer is updated, and the result is deposited into the * byte pointed to by "retbyte". * * The usual '0x' notation is allowed but not required. The number must be * a two digit hexadecimal number. If the number is invalid, "src" and * "retbyte" are left untouched and -1 is returned as the function value. * Successful calls return 0. */ 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; } /* * The parameter "src" points to a character pointer which points to an * ASCII string representation of an unsigned number. The number is * returned as an unsigned long and the character pointer is updated to * point to the first illegal character. */ PRIVATE u_int32 get_u_long(src) char **src; { 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)++; } 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; } return value; } /* * Routines for deletion of data associated with the main data structure. */ /* * Frees the entire host data structure given. Does nothing if the passed * pointer is NULL. */ PRIVATE void free_host(hmp) hash_datum *hmp; { 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); del_iplist(hostptr->impress_server); del_iplist(hostptr->log_server); del_iplist(hostptr->lpr_server); 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->root_path); del_string(hostptr->domain_name); del_string(hostptr->dump_file); del_string(hostptr->exten_file); del_string(hostptr->nis_domain); #ifdef YORK_EX_OPTION del_string(hostptr->exec_file); #endif /* * 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; { if (iplist) { if (!(--(iplist->linkcount))) { free((char *) iplist); } } } /* * Decrements the linkcount on a string data structure. If the count * goes to zero, the memory associated with the string is freed. Does * nothing if the passed pointer is NULL. */ PRIVATE void del_string(stringptr) struct shared_string *stringptr; { if (stringptr) { if (!(--(stringptr->linkcount))) { free((char *) stringptr); } } } /* * Decrements the linkcount on a shared_bindata data structure. If the * count goes to zero, the memory associated with the data is freed. Does * nothing if the passed pointer is NULL. */ PRIVATE void del_bindata(dataptr) struct shared_bindata *dataptr; { if (dataptr) { if (!(--(dataptr->linkcount))) { free((char *) dataptr); } } } /* smalloc() -- safe malloc() * * Always returns a valid pointer (if it returns at all). The allocated * memory is initialized to all zeros. If malloc() returns an error, a * message is printed using the report() function and the program aborts * with a status of 1. */ 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; { 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: */ *src)) return -1; *pp++ = get_u_long(src); if (**src == '.') { if (pp < (parts + 4)) { (*src)++; goto loop; } return (-1); } #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 -- 32bootp-2.4.3/readfile.h 644 125 65 565 5530227637 7620 /* 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 1->iaddr.s_addr == host2->iaddr.s_addr); } /* * Local Variables: * tab-width: 4 * c-indent-level: 4 * c-argdecl-indent: 4 * c-continubootp-2.4.3/report.c 644 125 65 5221 5544563654 7374 /* * report() - calls syslog */ #ifdef __STDC__ #include #else #include #endif #include #include #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: */ */ 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. */ } hap = haddr; while (hap < haddr + hal) { if ((*p == '.') || (*p == ':')) p++; if (interp_byte(&p, hap++) < 0bootp-2.4.3/report.h 644 125 65 325 5501650655 7350 /* 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 zone.cützone.hý getether.hndef 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; { stderrbootp-2.4.3/strerror.c 644 125 65 605 5536717265 7724 /* * strerror() - for those systems that don't have it yet. * Doing it this way avoids yet another ifdef... */ /* These are part of the C library. (See perror.3) */ extern char *sys_errlist[]; extern int sys_nerr; static char errmsg[80]; char * strerror(en) int en; { if ((0 <= en) && (en < sys_nerr)) return sys_errlist[en]; sprintf(errmsg, "Error %d", en); return errmsg; } u get stderr until you call * report_init() */ static int stderr_only = 1; void report_init(nolog) int nolog; { stderrbootp-2.4.3/syslog.conf 644 125 65 4124 5505356702 10074 # # 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 || (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 bootp-2.4.3/syslog.h 644 125 65 1460 5510637525 7377 /* * 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 ar/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 * bootp-2.4.3/trygetea.c 644 125 65 1634 5720666772 7712 /* * trygetea.c - test program for getether.c */ #include #include #if defined(SUNOS) || defined(SVR4) #include #endif #ifdef _AIX32 #include /* for struct timeval in net/if.h */ #endif #include /* for struct ifreq */ #include #include /* inet_ntoa */ #include #include #include #include #include "getether.h" int debug = 0; char *progname; void main(argc, argv) int argc; 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], (char*)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); } *.alert;kern.err;daemon.err;user.none operator *.alert;user.none root *.emerg;user.none * bootp-2.4.3/trygetif.c 644 125 65 2514 5720477547 7721 /* * trygetif.c - test program for getif.c */ #include #include #if defined(SUNOS) || defined(SVR4) #include #endif #ifdef _AIX32 #include /* for struct timeval in net/if.h */ #endif #include /* for struct ifreq */ #include #include /* inet_ntoa */ #include #include #include #include #include "getif.h" int debug = 0; char *progname; void main(argc, argv) int argc; char **argv; { struct hostent *hep; struct sockaddr_in *sip; /* Interface address */ struct ifreq *ifr; struct in_addr dst_addr; struct in_addr *dap; int 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); } 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 facibootp-2.4.3/trylook.c 644 125 65 1441 5720456630 7553 /* * trylook.c - test program for lookup.c */ #include #include #include #include "report.h" #include "lookup.h" extern char *ether_ntoa(); extern char *inet_ntoa(); int debug = 0; char *progname; void main(argc, argv) int argc; 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 */ printf(" hwa="); hwa = lookup_hwa(argv[i], 1); if (!hwa) printf("?\n"); else { int i; for (i = 0; i < 6; i++) printf(":%x", hwa[i] & 0xFF); putchar('\n'); } } exit(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 bootp-2.4.3/tzone.c 644 125 65 2021 5536717332 7206 /* * tzone.c - get the timezone * * This is shared by bootpd and bootpef */ #ifdef SVR4 /* XXX - Is this really SunOS specific? -gwr */ /* This is in but only visible if (__STDC__ == 1). */ extern long timezone; #else /* SVR4 */ /* BSD or SunOS */ # include # include #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 */ } 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); } 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 facibootp-2.4.3/tzone.h 644 125 65 102 5530214523 7155 /* tzone.h */ extern int32 secondswest; extern void tzone_init(); tether.h */ #ifdef SVR4 /* XXX - Is this really SunOS specific? -gwr */ /* This is in but only visible if (__STDC__ == 1). */ extern long timezone; #else /* SVR4 */ /* BSD or SunOS */ # include # include #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 *bootp-2.4.3/getether.h 644 125 65 166 5720455557 7656 /* getether.h */ #ifdef __STDC__ extern int getether(char *ifname, char *eaptr); #else extern int getether(); #endif unOS specific? -gwr */ /* This is in but only visible if (__STDC__ == 1). */ extern long timezone; #else /* SVR4 */ /* BSD or SunOS */ # include # include #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 */* * trygetif.c - test program for getif.c */ #include #include #if defined(SUNOS) || defined(SVR4) #include #endif #ifdef _AIX32 #include /* for struct timeval in net/if.h */ #endif #include /* for struct ifreq */ #include #include /* inet_ntoa */ #include #include #include #include #include "getif.h" int debug = 0; char *progname; void main(argc, argv) int argc; char **argv; { struct hostent *hep; struct sockaddr_in *sip; /* Interface address */ struct ifreq *ifr; struct in_addr dst_addr; struct in_addr *dap; int 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); } 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 facibootp-2.4.3/trylook.c 644 125 65 1441 5720456630 7553