diff options
author | murray <murray@FreeBSD.org> | 2002-02-19 11:04:34 +0000 |
---|---|---|
committer | murray <murray@FreeBSD.org> | 2002-02-19 11:04:34 +0000 |
commit | 57b30d23e7c11fa1a8c8c23f27de40971872952f (patch) | |
tree | 229464d9b3244ab78e2784c9a0a1f78de317089a | |
parent | 7acb11388cf5d680b16902b8ed6f46c46dc4d47b (diff) | |
download | FreeBSD-src-57b30d23e7c11fa1a8c8c23f27de40971872952f.zip FreeBSD-src-57b30d23e7c11fa1a8c8c23f27de40971872952f.tar.gz |
Import ISC DHCP 3.0.1 RC6 client.
137 files changed, 56532 insertions, 7529 deletions
diff --git a/contrib/isc-dhcp/ANONCVS b/contrib/isc-dhcp/ANONCVS new file mode 100644 index 0000000..fa363db --- /dev/null +++ b/contrib/isc-dhcp/ANONCVS @@ -0,0 +1,129 @@ + Anonymous CVS Access for the ISC DHCP Distribution + +The ISC DHCP distribution can be accessed using "anonymous" CVS. +"Anonymous" cvs uses the CVS "pserver" mechanism to allow anybody on +the Internet to access a CVS repository without having to register in +any way. Anonymous CVS allows you to access changes as soon as the +DHCP developers commit them, rather than having to wait for the next +snapshot or patchlevel. Changes that have not yet been released yet +are not guaranteed to work, but they can nonetheless be useful in many +cases. + + TABLE OF CONTENTS + + 1. What is anonymous CVS? + 2. How can i start using it? + 3. Checking out the latest code in a release + 4. Checking out the latest code + 5. Checking out a specific release + 6. When to update + + WHAT IS ANONYMOUS CVS? + +Anonymous CVS also allows you to browse through the history of the +DHCP distribution, and examine the revision history of specific files +to see how they have changed between revisions, to try to figure out +why something that was working before is no longer working, or just to +see when a certain change was made. + + HOW CAN I START USING IT? + +To use anonymous CVS to access the DHCP distribution, you must first +"log in". You should only need to do this once, but it is a +necessary step, even though access is anonymous. Anonymous users log +in as user "nobody", password "nobody". To do this, type: + + cvs -d :pserver:nobody@dhcp.cvs.isc.org:/cvsroot login + +You will be prompted for a password - type "nobody". If you get some +kind of error indicating that cvs doesn't know how to log you in, you +are probably running an old version of cvs, and should upgrade. This +should work with cvs version 1.10. + +Once you have logged in, you can check out a version of the DHCP +distribution, so the next question is, which version? + + CHECKING OUT THE LATEST CODE IN A RELEASE + +There are currently four major versions of the distribution - Release +1, Release 2, Release 3, and the current development tree. Releases +1, 2 and 3 are branches in the CVS repository. To check out the +latest code on any of these branches, you would use a branch tag of +RELEASE_1, RELEASE_2 or RELEASE_3 in the following command: + + (setenv CVSROOT :pserver:nobody@dhcp.cvs.isc.org:/cvsroot; + cvs checkout -d dhcp-2.0 -r RELEASE_2 DHCP) + +Note that the example is for Release 2. + + CHECKING OUT THE LATEST CODE + +To check out the current engineering version, use: + + (setenv CVSROOT :pserver:nobody@dhcp.cvs.isc.org:/cvsroot; + cvs checkout -d dhcp-current DHCP) + +Note that the current engineering version is a work in progress, and +there is no real guarantee that it will work for you. + + CHECKING OUT A SPECIFIC RELEASE + +You can also check out specific versions of the DHCP distribution. +There are three kinds of version tags you may find - alpha tags, beta +tags and release tags. Alpha tags look like this: + + V#-ALPHA-YYYYMMDD + +# is the release number. YYYYMMDD is the date of the release, with a +4-digit year, the month expressed as a number (January=1), and the day +of the month specified as a number, with the first day of the month +being 1. + +Beta tags look like this: + + V#-BETA-%-PATCH-* + +Where # is the release number, % is the Beta number (usually 1) and * +is the patchlevel. In the future there may also be beta tags that +look like this: + + V#-#-BETA-%-PATCH-* + +Where #-# is the major version followed by the minor version - for +example, when the first 3.1 beta comes out, the tag will look like +this: + + V3-1-BETA-1-PATCH-0 + +Release tags look like this: + + V#-%-* + +Where # is the major version, % is the minor version, and * is the +patchlevel. So the tag for 1.0pl2 is V1-0-2, and to check it out, +you'd type: + + (setenv CVSROOT :pserver:nobody@dhcp.cvs.isc.org:/cvsroot; + cvs checkout -d dhcp-1.0pl2 -rV1-0-2 DHCP) + +Whenever changes are checked in to the ISC DHCP repository, or files +are tagged, a notice is sent to the dhcp-source-changes@isc.org +mailing list. You can subscribe to this list by sending mail to +dhcp-source-changes-request@isc.org, and you will then get immediate +notification when changes are made. You may find the volume of mail +on this list annoying, however. + + WHEN TO UPDATE + +We do not recommend that you do an update immediately after you see a +change on the dhcp-source-changes mailing list - instead, it's best to +wait a while to make sure that any changes that change depends on have +also been committed. Also, sometimes when development is being done +on two machines, the developers will check in a tentative change that +hasn't been tested at all so that they can update on a different +machine and test the change. The best way to avoid accidentally +getting one of these changes is to not update aggressively - when a +change is made, wait a while before updating, to make sure that it's +not going to be quickly followed by another change. + + diff --git a/contrib/isc-dhcp/COPYRIGHT b/contrib/isc-dhcp/COPYRIGHT new file mode 100644 index 0000000..0e5d81a --- /dev/null +++ b/contrib/isc-dhcp/COPYRIGHT @@ -0,0 +1,17 @@ +/* + * Copyright (c) 1996-1999 Internet Software Consortium. + * Use is subject to license terms which appear in the file named + * ISC-LICENSE that should have accompanied this file when you + * received it. If a file named ISC-LICENSE did not accompany this + * file, or you are not sure the one you have is correct, you may + * obtain an applicable copy of the license at: + * + * http://www.isc.org/isc-license-1.0.html. + * + * This file is part of the ISC DHCP distribution. The documentation + * associated with this file is listed in the file DOCUMENTATION, + * included in the top-level directory of this release. + * + * Support and other services are available for ISC products - see + * http://www.isc.org for more information. + */ diff --git a/contrib/isc-dhcp/Makefile b/contrib/isc-dhcp/Makefile new file mode 100644 index 0000000..e6c2d1e --- /dev/null +++ b/contrib/isc-dhcp/Makefile @@ -0,0 +1,96 @@ +# Makefile +# +# Copyright (c) 2000 Internet Software Consortium. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of Internet Software Consortium nor the names +# of its contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND +# CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# This software has been written for the Internet Software Consortium +# by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. +# To learn more about the Internet Software Consortium, see +# ``http://www.isc.org/''. To learn more about Vixie Enterprises, +# see ``http://www.vix.com''. To learn more about Nominum, Inc., see +# ``http://www.nominum.com''. +# + +all: + @sysname=`./configure --print-sysname`; \ + if [ ! -d work.$$sysname ]; then \ + echo No build directory for $$sysname - please run ./configure.; \ + else \ + (cd work.$$sysname; make all); \ + fi + +install: + @sysname=`./configure --print-sysname`; \ + if [ ! -d work.$$sysname ]; then \ + echo No build directory for $$sysname - please run ./configure.; \ + else \ + (cd work.$$sysname; make install); \ + fi + +depend: + @sysname=`./configure --print-sysname`; \ + if [ ! -d work.$$sysname ]; then \ + echo No build directory for $$sysname - please run ./configure.; \ + else \ + (cd work.$$sysname; make depend); \ + fi + +clean: + @sysname=`./configure --print-sysname`; \ + if [ ! -d work.$$sysname ]; then \ + echo No build directory for $$sysname - please run ./configure.; \ + else \ + (cd work.$$sysname; make clean); \ + fi + +realclean: + @sysname=`./configure --print-sysname`; \ + if [ ! -d work.$$sysname ]; then \ + echo No build directory for $$sysname - please run ./configure.; \ + else \ + (cd work.$$sysname; make realclean); \ + fi + +distclean: + @sysname=`./configure --print-sysname`; \ + if [ ! -d work.$$sysname ]; then \ + echo No build directory for $$sysname - please run ./configure.; \ + else \ + (cd work.$$sysname; make distclean); \ + fi + +links: + @sysname=`./configure --print-sysname`; \ + if [ ! -d work.$$sysname ]; then \ + echo No build directory for $$sysname - please run ./configure.; \ + else \ + (cd work.$$sysname; make links); \ + fi + diff --git a/contrib/isc-dhcp/Makefile.conf b/contrib/isc-dhcp/Makefile.conf index 509e32f..a8c64ac 100644 --- a/contrib/isc-dhcp/Makefile.conf +++ b/contrib/isc-dhcp/Makefile.conf @@ -1,53 +1,56 @@ # Makefile.conf # -# Copyright (c) 1996, 1997, 1998, 1999 The Internet Software Consortium. -# All rights reserved. +# Copyright (c) 1996-2000 Internet Software Consortium. +# Use is subject to license terms which appear in the file named +# ISC-LICENSE that should have accompanied this file when you +# received it. If a file named ISC-LICENSE did not accompany this +# file, or you are not sure the one you have is correct, you may +# obtain an applicable copy of the license at: # -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: +# http://www.isc.org/isc-license-1.0.html. # -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# 3. Neither the name of The Internet Software Consortium nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. +# This file is part of the ISC DHCP distribution. The documentation +# associated with this file is listed in the file DOCUMENTATION, +# included in the top-level directory of this release. # -# THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND -# CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, -# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -# THE INTERNET SOFTWARE CONSORTIUM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED -# OF THE POSSIBILITY OF SUCH DAMAGE. +# Support and other services are available for ISC products - see +# http://www.isc.org for more information. # ## Defaults... SCRIPT = none +USERBINDIR = /usr/bin BINDIR = /usr/sbin CLIENTBINDIR=/sbin -ADMMANEXT = .0 -FFMANEXT = .0 ADMMANDIR = /usr/share/man/cat8 +ADMMANEXT = .0 FFMANDIR = /usr/share/man/cat5 -INSTALL = install -c -MANINSTALL = install -c -m 444 +FFMANEXT = .0 +LIBMANDIR = /usr/share/man/cat3 +LIBMANEXT = .0 +USRMANDIR = /usr/share/man/cat1 +USRMANEXT = .0 +MANCAT = cat +INSTALL = install -c -m 444 +MANINSTALL = install -c CHMOD = chmod CATMANPAGES = -MANCAT = cat ETC = /etc VARRUN = /var/run VARDB = /var/db +LIBDIR=/usr/local/lib +INCDIR=/usr/local/include +LIBS = +COPTS = $(BINDDEF) $(CC_OPTIONS) +DEBUG = -g +RANLIB = ranlib +MKDEP = mkdep CLIENT_PATH = '"PATH=/usr/ucb:/usr/bin:/usr/sbin:/bin:/sbin"' +BINDLIB = ../minires/libres.a +BINDINC = +MINIRES = minires + # Major version number (if applicable) ##--majver-- MAJORVERSION=MajorVersion @@ -70,12 +73,12 @@ MINORVERSION=MinorVersion # removes the comment characters from the appropriate set of # assignments, and writes the output to Makefile. -## AIX 4.1.5.0 +## AIX 4.3 ##--aix-- #CF = cf/aix.h #CC=cc -Daix -#INSTALL=/usr/ucb/install -#MANINSTALL=/usr/ucb/install +#INSTALL=/usr/ucb/install -c +#MANINSTALL=/usr/ucb/install -c -m 444 #ADMMANEXT = .8 #FFMANEXT = .5 #VARRUN = /etc @@ -84,21 +87,25 @@ MINORVERSION=MinorVersion ## NEXTSTEP 3.x,4.x ##--nextstep-- -#LIBS = #CF = cf/nextstep.h #CC=cc -#COPTS = -Wall +#COPTS = -Wall $(BINDDEF) $(CC_OPTIONS) #BINDIR=/usr/etc #ADMMANDIR = /usr/local/man/cat8 #FFMANDIR = /usr/local/man/cat5 +#LIBMANDIR = /usr/local/man/cat3 +#USRMANDIR = /usr/local/man/cat1 #ADMMANEXT = .8 #FFMANEXT = .5 +#LIBMANEXT = .3 +#USRMANEXT = .3 #VARRUN = /etc #VARDB = /etc ##--nextstep-- ## SunOS 4.1 ##--sunos4-- +#CC = gcc #LIBS = -lresolv #CF = cf/sunos4.h #BINDIR=/usr/etc @@ -115,13 +122,20 @@ MINORVERSION=MinorVersion #MANINSTALL=/usr/ucb/install #LIBS = -lresolv -lsocket -lnsl -lgen #CC=gcc -#COPTS = -Wall -Wno-unused -Wno-implicit -Wno-comment \ -# -Wno-uninitialized -Wno-char-subscripts -Werror +#COPTS = $(BINDDEF) -Wall -Wno-unused -Wno-implicit -Wno-comment \ +# -Wno-uninitialized -Wno-char-subscripts -Wno-switch -Werror \ +# -DSOLARIS_MAJOR=$(MAJORVERSION) -DSOLARIS_MINOR=$(MINORVERSION) \ +# $(CC_OPTIONS) #CF = cf/sunos5-5.h -#ADMMANDIR = /usr/share/man/cat1m +#ADMMANDIR = /usr/share/man/man1m #ADMMANEXT = .1m -#FFMANDIR = /usr/share/man/cat4 +#FFMANDIR = /usr/share/man/man4 #FFMANEXT = .4 +#LIBMANDIR = /usr/share/man/man3 +#LIBMANEXT = .3 +#USRMANDIR = /usr/share/man/man1 +#USRMANEXT = .1 +#MANCAT = man #VARRUN = /etc #VARDB = /etc #SCRIPT=solaris @@ -131,14 +145,21 @@ MINORVERSION=MinorVersion ##--sunos5-cc-- #INSTALL=/usr/ucb/install #MANINSTALL=/usr/ucb/install -#LIBS = -lresolv -lsocket -lnsl -lgen +#LIBS = -lresolv -lsocket -lnsl -lgen #CC=cc -#COPTS = -D__svr4__ +#COPTS = -D__svr4__ $(BINDDEF) -erroff=E_END_OF_LOOP_CODE_NOT_REACHED \ +# -DSOLARIS_MAJOR=$(MAJORVERSION) -DSOLARIS_MINOR=$(MINORVERSION) \ +# $(CC_OPTIONS) #CF = cf/sunos5-5.h -#ADMMANDIR = /usr/share/man/cat1m +#ADMMANDIR = /usr/share/man/man1m #ADMMANEXT = .1m -#FFMANDIR = /usr/share/man/cat4 +#FFMANDIR = /usr/share/man/man4 #FFMANEXT = .4 +#LIBMANDIR = /usr/share/man/man3 +#LIBMANEXT = .3 +#USRMANDIR = /usr/share/man/man1 +#USRMANEXT = .1 +#MANCAT = man #VARRUN = /etc #VARDB = /etc #SCRIPT=solaris @@ -146,23 +167,35 @@ MINORVERSION=MinorVersion ## DEC Alpha/OSF1 ##--alphaosf-- -#CC=cc -std0 -#INSTALL=/usr/ucb/installbsd -#MANINSTALL=/usr/ucb/installbsd -#LIBS= +#COPTS = -std $(CC_OPTIONS) +#INSTALL=/usr/ucb/installbsd -c +#MANINSTALL=/usr/ucb/installbsd -c #CF = cf/alphaosf.h #ADMMANEXT = .8 #FFMANEXT = .5 #VARDB = /etc ##--alphaosf-- -## BSD/OS 2.1 +## BSD/OS 2.1 through 4.0 ##--bsdos-- -#LIBS= -lresolv +#LIBS = -lresolv #CC=gcc2 #CF = cf/bsdos.h +#SCRIPT=bsdos ##--bsdos-- +## BSD/OS 4.1 and higher. +##--bsdos-4.1-- +#CF = cf/bsdos.h +#SCRIPT=bsdos +##--bsdos-4.1-- + +## OpenBSD +##--openbsd-- +#CF = cf/openbsd.h +#SCRIPT=openbsd +##--openbsd-- + ## FreeBSD ##--freebsd-- #CF = cf/freebsd.h @@ -173,18 +206,47 @@ MINORVERSION=MinorVersion ##--rhapsody-- #CF = cf/rhapsody.h #COPTS = -Wall -Wno-unused -Wno-implicit -Wno-comment \ -# -Wno-uninitialized -Werror -pipe -#SCRIPT=rhapsody +# -Wno-uninitialized -Wno-switch -Werror -pipe $(BINDDEF) $(CC_OPTIONS) +##SCRIPT=rhapsody ##--rhapsody-- +## Darwin/MacOSX +##--darwin-- +#CF = cf/rhapsody.h +#COPTS = -Ddarwin -Wall -Wno-unused -Wno-implicit -Wno-comment \ +# -Wno-uninitialized -Wno-switch -Werror -pipe $(BINDDEF) $(CC_OPTIONS) +##SCRIPT=rhapsody +##--darwin-- + ## NetBSD ##--netbsd-- #CF = cf/netbsd.h -#COPTS = -Wall -Wstrict-prototypes -Wno-unused -Wno-implicit -Wno-comment \ -# -Wno-uninitialized -Werror -pipe +#COPTS = -Wall -Wstrict-prototypes -Wno-unused -Wno-comment \ +# -Wno-uninitialized -Werror \ +# -Wimplicit-function-declaration -Wpointer-arith -Wcast-qual \ +# -Wcast-align -Wwrite-strings -Wconversion -Wmissing-prototypes \ +# -Wmissing-declarations -Wnested-externs \ +# -pipe $(BINDDEF) $(CC_OPTIONS) #SCRIPT=netbsd +##MKDEP=makedepend ##--netbsd-- +## NetBSD nocast +## Some versions of the arm32 gcc have a problem in cast conversions. +## The Alpha definitely has a problem - if you pass '6' where a size_t +## is expected, you get a warning. So on these architectures, we do +## not ask for that sort of warning. +##--netbsd-nocast-- +#CF = cf/netbsd.h +#COPTS = -Wall -Wstrict-prototypes -Wno-unused -Wno-comment \ +# -Wno-uninitialized -Werror \ +# -Wimplicit-function-declaration -Wpointer-arith -Wcast-qual \ +# -Wwrite-strings -Wmissing-prototypes \ +# -Wmissing-declarations -Wnested-externs \ +# -pipe $(BINDDEF) $(CC_OPTIONS) +#SCRIPT=netbsd +##--netbsd-nocast-- + ## Ultrix ##--ultrix-- #BINDIR = /usr/etc @@ -196,66 +258,98 @@ MINORVERSION=MinorVersion #ADMMANEXT = .8 #FFMANDIR = /usr/man/man5 #FFMANEXT = .5 +#LIBMANDIR = /usr/man/cat3 +#LIBMANEXT = .3 +#USRMANDIR = /usr/man/cat1 +#USRMANEXT = .1 ##--ultrix-- ## Linux 1.x ##--linux-1-- -#COPTS = -DLINUX_MAJOR=$(MAJORVERSION) -DLINUX_MINOR=$(MINORVERSION) +#COPTS = -DLINUX_MAJOR=$(MAJORVERSION) -DLINUX_MINOR=$(MINORVERSION) \ +# $(BINDDEF) $(CC_OPTIONS) #CF = cf/linux.h #ADMMANDIR = /usr/man/man8 #ADMMANEXT = .8 #FFMANDIR = /usr/man/man5 #FFMANEXT = .5 +#LIBMANDIR = /usr/man/man3 +#LIBMANEXT = .3 +#USRMANDIR = /usr/man/man1 +#USRMANEXT = .1 #MANCAT = man #VARRUN = /var/run -#VARDB = /var/state/dhcp # see rationale in includes/cf/linux.h +#VARDB = /var/state/dhcp #SCRIPT=linux ##--linux-1-- ## Linux 2.0 ##--linux-2.0-- -#COPTS = -DLINUX_MAJOR=$(MAJORVERSION) -DLINUX_MINOR=$(MINORVERSION) +#COPTS = -DLINUX_MAJOR=$(MAJORVERSION) -DLINUX_MINOR=$(MINORVERSION) \ +# $(BINDDEF) $(CC_OPTIONS) #CF = cf/linux.h #ADMMANDIR = /usr/man/man8 #ADMMANEXT = .8 #FFMANDIR = /usr/man/man5 #FFMANEXT = .5 +#LIBMANDIR = /usr/man/man3 +#LIBMANEXT = .3 +#USRMANDIR = /usr/man/man1 +#USRMANEXT = .1 #MANCAT = man #VARRUN = /var/run -#VARDB = /var/state/dhcp # see rationale in includes/cf/linux.h +#VARDB = /var/state/dhcp #SCRIPT=linux ##--linux-2.0-- ## Linux 2.1 ##--linux-2.1-- -#COPTS = -DLINUX_MAJOR=$(MAJORVERSION) -DLINUX_MINOR=$(MINORVERSION) +#COPTS = -DLINUX_MAJOR=$(MAJORVERSION) -DLINUX_MINOR=$(MINORVERSION) \ +# $(BINDDEF) $(CC_OPTIONS) #CF = cf/linux.h #ADMMANDIR = /usr/man/man8 #ADMMANEXT = .8 -#FFMANDIR = /usr/share/man/man5 +#FFMANDIR = /usr/man/man5 #FFMANEXT = .5 +#LIBMANDIR = /usr/man/man3 +#LIBMANEXT = .3 +#USRMANDIR = /usr/man/man1 +#USRMANEXT = .1 #MANCAT = man #VARRUN = /var/run -#VARDB = /var/state/dhcp # see rationale in includes/cf/linux.h +#VARDB = /var/state/dhcp #SCRIPT=linux ##--linux-2.1-- ## Linux 2.2 ##--linux-2.2-- -#COPTS = -DLINUX_MAJOR=$(MAJORVERSION) -DLINUX_MINOR=$(MINORVERSION) +#COPTS = -DLINUX_MAJOR=$(MAJORVERSION) -DLINUX_MINOR=$(MINORVERSION) \ +# $(BINDDEF) $(CC_OPTIONS) #CF = cf/linux.h #ADMMANDIR = /usr/man/man8 #ADMMANEXT = .8 -#FFMANDIR = /usr/share/man/man5 +#FFMANDIR = /usr/man/man5 #FFMANEXT = .5 +#LIBMANDIR = /usr/man/man3 +#LIBMANEXT = .3 +#USRMANDIR = /usr/man/man1 +#USRMANEXT = .1 #MANCAT = man #VARRUN = /var/run -#VARDB = /var/state/dhcp # see rationale in includes/cf/linux.h +#VARDB = /var/state/dhcp #SCRIPT=linux ##--linux-2.2-- -## SCO -##--sco-- +## SCO UnixWare 7 +##--uw7-- +#CF = cf/uw7.h +#PREDEFINES=-DUW7 +#RANLIB=true +#LIBS = -lresolv -lsocket -lnsl -lgen +##--uw7-- + +## SCO (with standard cc compiler) +##--sco-cc-- #CF = cf/sco.h #PREDEFINES=-DSCO -DBROKEN_ANSI #BINDIR = /usr/etc @@ -271,7 +365,30 @@ MINORVERSION=MinorVersion #VARRUN = /etc #VARDB = /etc #CATMANPAGES= -##--sco-- +##--sco-cc-- + +## SCO (with GNU gcc compiler) +##--sco-gcc-- +#CF = cf/sco.h +#CC=gcc +#PREDEFINES=-DSCO +#LIBS = -lsocket +#USERBINDIR = /usr/local/dhcp/bin +#BINDIR = /usr/local/dhcp/bin +#CLIENTBINDIR = /usr/local/dhcp/bin +#ADMMANDIR = /usr/local/dhcp/man/cat.ADMN +#ADMMANEXT = .ADMN.Z +#FFMANDIR = /usr/local/dhcp/man/cat.SFF +#FFMANEXT = .SFF.Z +#INSTALL = /usr/local/bin/install +#MANFROM = < +#MANINSTALL = compress +#MANTO = > +#VARRUN = /usr/local/dhcp/var +#VARDB = /usr/local/dhcp/var +#CATMANPAGES= +#CLIENT_PATH = '"PATH=/bin:/etc:/usr/bin:/tcb/bin:/usr/bin/X11:/usr/local/bin:/usr/local/dhcp/bin"' +##--sco-gcc-- ## QNX ##--qnx-- @@ -280,9 +397,13 @@ MINORVERSION=MinorVersion #ADMMANEXT = .8 #FFMANDIR = /usr/man/man5 #FFMANEXT = .5 +#LIBMANDIR = /usr/man/man3 +#LIBMANEXT = .3 +#USRMANDIR = /usr/man/man1 +#USRMANEXT = .1 #MANCAT = man #VARRUN = /etc -#COPTS=-w3 -Dlint +#COPTS=-w3 -Dlint $(BINDDEF) $(CC_OPTIONS) #LFLAGS=$(DEBUG) "-Wl,op symfile" -l socket #MANINSTALL = /bin/true #INSTALL = cp @@ -290,6 +411,26 @@ MINORVERSION=MinorVersion #CLIENTBINDIR = /etc ##--qnx-- + +## QNX RTP (v6, NTO) +##--qnxnto-- +#CF = cf/qnx.h +#ADMMANDIR = /opt/man/man8 +#ADMMANEXT = .8 +#FFMANDIR = /opt/man/man5 +#FFMANEXT = .5 +#LIBMANDIR = /opt/man/man3 +#LIBMANEXT = .3 +#MANCAT = man +#COPTS=-w3 -Dlint $(BINDDEF) +#LFLAGS=-l socket +#MANINSTALL = /bin/cp +#INSTALL = /bin/cp +#BINDIR = /opt/sbin +#USERBINDIR= /opt/bin +#CLIENTBINDIR = /opt/sbin +##--qnxnto-- + ## CygWin32 ##--cygwin32-- #CF = cf/cygwin32.h @@ -297,6 +438,10 @@ MINORVERSION=MinorVersion #ADMMANEXT = .8 #FFMANDIR = /usr/man/man5 #FFMANEXT = .5 +#LIBMANDIR = /usr/man/man3 +#LIBMANEXT = .3 +#USRMANDIR = /usr/man/man1 +#USRMANEXT = .1 #VARRUN = /etc #MANINSTALL = /bin/true #INSTALL = cp @@ -313,16 +458,19 @@ MINORVERSION=MinorVersion ## IRIX 6.x ##--irix-- -#LIBS = -lbind -#LFLAGS=$(DEBUG) -L/usr/local/lib -Wl,-woff,84 -Wl,-woff,85 -Wl,-woff,134 +#LFLAGS=$(DEBUG) -Wl,-woff,84 -Wl,-woff,85 -Wl,-woff,134 #CC=gcc -#COPTS = -I/usr/local/include +#COPTS = -I/usr/local/include $(BINDDEF) $(CC_OPTIONS) #CF = cf/irix.h #BINDIR = /usr/local/etc #ADMMANDIR = /usr/local/man/man8 #ADMMANEXT = .8 #FFMANDIR = /usr/local/man/man5 #FFMANEXT = .5 +#LIBMANDIR = /usr/local/man/man3 +#LIBMANEXT = .3 +#USRMANDIR = /usr/local/man/man1 +#USRMANEXT = .1 #MANCAT = man #INSTALL = install #MANINSTALL = install @@ -331,3 +479,21 @@ MINORVERSION=MinorVersion #VARRUN = /etc #VARDB = /usr/local/etc/dhcp ##--irix-- + +## HP-UX +##--hpux-cc-- +#COPTS = $(BINDDEF) $(CC_OPTIONS) +#LFLAGS = -Wl,+vnocompatwarnings +#INSTALL = install -i +#MANINSTALL = install -i +##--hpux-cc-- + +## HP-UX with gcc +##--hpux-gcc-- +#CC = gcc +#CF = cf/hpux.h +#INSTALL = install -i +#ADMMANEXT = .8 +#FFMANEXT = .5 +#MANINSTALL = install -i -m 444 +##--hpux-gcc-- diff --git a/contrib/isc-dhcp/Makefile.dist b/contrib/isc-dhcp/Makefile.dist index e2dc4e2..7e4a2fc 100644 --- a/contrib/isc-dhcp/Makefile.dist +++ b/contrib/isc-dhcp/Makefile.dist @@ -1,78 +1,41 @@ # Makefile.dist # -# Copyright (c) 1996, 1997 The Internet Software Consortium. -# All rights reserved. +# Copyright (c) 1996-1999 Internet Software Consortium. +# Use is subject to license terms which appear in the file named +# ISC-LICENSE that should have accompanied this file when you +# received it. If a file named ISC-LICENSE did not accompany this +# file, or you are not sure the one you have is correct, you may +# obtain an applicable copy of the license at: # -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: +# http://www.isc.org/isc-license-1.0.html. # -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# 3. Neither the name of The Internet Software Consortium nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. +# This file is part of the ISC DHCP distribution. The documentation +# associated with this file is listed in the file DOCUMENTATION, +# included in the top-level directory of this release. # -# THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND -# CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, -# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -# THE INTERNET SOFTWARE CONSORTIUM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED -# OF THE POSSIBILITY OF SUCH DAMAGE. +# Support and other services are available for ISC products - see +# http://www.isc.org for more information. # -SUBDIRS= common server client relay +SUBDIRS= common $(MINIRES) dst omapip server client relay dhcpctl all: @for dir in ${SUBDIRS}; do \ echo "Making all in $$dir"; \ (cd $$dir; $(MAKE) all) || exit 1; \ done - @if [ `uname` = Linux ]; then \ - echo; \ - echo " !!!! WARNING !!!!"; \ - echo ; \ - echo "The default location for the dhcpd.leases file has \ -changed!!!"; \ - echo; \ - echo "It is now in /var/state/dhcp. If you are not"; \ - echo "installing this for the first time, please move your"; \ - echo "lease database to the new location before using this"; \ - echo "software."; \ - echo; \ - echo " !!!! WARNING !!!!"; \ - echo; \ - fi install: @for dir in ${SUBDIRS}; do \ echo "Installing in $$dir"; \ (cd $$dir; $(MAKE) install) || exit 1; \ done - @if [ `uname` = Linux ]; then \ - echo; \ - echo " !!!! WARNING !!!!"; \ - echo ; \ - echo "The default location for the dhcpd.leases file has \ -changed!!!"; \ - echo; \ - echo "It is now in /var/state/dhcp. If you are not"; \ - echo "installing this for the first time, please move your"; \ - echo "lease database to the new location before using this"; \ - echo "software."; \ - echo; \ - echo " !!!! WARNING !!!!"; \ - echo; \ - fi + +depend: + @for dir in ${SUBDIRS}; do \ + echo "Making dependencies in $$dir"; \ + (cd $$dir; $(MAKE) depend) || exit 1; \ + done clean: @for dir in ${SUBDIRS}; do \ @@ -92,3 +55,9 @@ distclean: (cd $$dir; $(MAKE) distclean) || exit 1; \ done @rm -f Makefile + +links: + @for dir in ${SUBDIRS}; do \ + echo "Making links in $$dir"; \ + (cd $$dir; $(MAKE) links) || exit 1; \ + done diff --git a/contrib/isc-dhcp/README b/contrib/isc-dhcp/README index 4c44400..530eb71 100644 --- a/contrib/isc-dhcp/README +++ b/contrib/isc-dhcp/README @@ -1,81 +1,82 @@ -<C><H4>Internet Software Consortium</H4></C> -<C><H4>Dynamic Host Configuration Protocol Distribution</H4></C> -<C><H4>Version 2 Patchlevel 5</H4></C> -<C><H4>September 6, 2000</H4></C> - -<C><H4>README FILE</H4></C> - -<P>You should read this file carefully before trying to install or use -the ISC DHCP Distribution.</P> - -<OL> -<C><B>TABLE OF CONTENTS</B></C> -<DL> -<DT><A HREF="#1"1</A><DD>WHERE TO FIND DOCUMENTATION -<DT><A HREF="#2"2</A><DD>RELEASE STATUS -<DT><A HREF="#3"3</A><DD>BUILDING THE DHCP DISTRIBUTION -<DT><A HREF="#4"4</A><DD>INSTALLING THE DHCP DISTRIBUTION -<DT><A HREF="#5"5</A><DD>USING THE DHCP DISTRIBUTION -<DL> -<DT><A HREF="#5.1"5.1</A><DD>LINUX -<DL> -<DT><A HREF="#5.1.1"5.1.1</A><DD>SO_ATTACH_FILTER UNDECLARED -<DT><A HREF="#5.1.2"5.1.2</A><DD>PROTOCOL NOT CONFIGURED -<DT><A HREF="#5.1.3"5.1.3</A><DD>BROADCAST -<DT><A HREF="#5.1.4"5.1.4</A><DD>FIREWALL RULES -<DT><A HREF="#5.1.5"5.1.5</A><DD>IP BOOTP AGENT -<DT><A HREF="#5.1.6"5.1.6</A><DD>MULTIPLE INTERFACES -</DL> -<DT><A HREF="#5.2"5.2</A><DD>SCO -<DT><A HREF="#5.3"5.3</A><DD>HP-UX -<DT><A HREF="#5.4"5.4</A><DD>ULTRIX -<DT><A HREF="#5.5"5.5</A><DD>FreeBSD -<DT><A HREF="#5.6"5.6</A><DD>NeXTSTEP -<DT><A HREF="#5.7"5.7</A><DD>SOLARIS -</DL> -<DT><A HREF="#6"6</A><DD>SUPPORT -<DL> -<DT><A HREF="#6.1"6.1</A><DD>HOW TO REPORT BUGS -</DL> -<DT><A HREF="#7"7</A><DD>KNOWN BUGS - -<H4 ID="1">Where to find documentation</H4> - -<P>Documentation for this software includes this README file, the + Internet Software Consortium DHCP Distribution + Version 3.0.1 + Release Candidate 6 + January 17, 2002 + + README FILE + +You should read this file carefully before trying to install or use +the ISC DHCP Distribution. + + TABLE OF CONTENTS + + 1 WHERE TO FIND DOCUMENTATION + 2 RELEASE STATUS + 3 BUILDING THE DHCP DISTRIBUTION + 3.1 UNPACKING IT + 3.2 CONFIGURING IT + 3.2.1 DYNAMIC DNS UPDATES + 3.2.2 LOCALLY DEFINED OPTIONS + 3.3 BUILDING IT + 4 INSTALLING THE DHCP DISTRIBUTION + 5 USING THE DHCP DISTRIBUTION + 5.1 FIREWALL RULES + 5.2 LINUX + 5.2.1 IF_TR.H NOT FOUND + 5.2.2 SO_ATTACH_FILTER UNDECLARED + 5.2.3 PROTOCOL NOT CONFIGURED + 5.2.4 BROADCAST + 5.2.6 IP BOOTP AGENT + 5.2.7 MULTIPLE INTERFACES + 5.3 SCO + 5.4 HP-UX + 5.5 ULTRIX + 5.6 FreeBSD + 5.7 NeXTSTEP + 5.8 SOLARIS + 6 SUPPORT + 6.1 HOW TO REPORT BUGS + + WHERE TO FIND DOCUMENTATION + +Documentation for this software includes this README file, the RELNOTES file, and the manual pages, which are in the server, common, -client and relay subdirectories. Internet standards relating to the -DHCP protocol are stored in the doc subdirectory. You will have the -best luck reading the manual pages if you build this software and then -install it, although you can read them directly out of the -distribution if you need to.</P> - -<P>DHCP server documentation is in the dhcpd man page. Information about +client and relay subdirectories. The README file (this file) includes +late-breaking operational and system-specific information that you +should read even if you don't want to read the manual pages, and that +you should *certainly* read if you run into trouble. Internet +standards relating to the DHCP protocol are stored in the doc +subdirectory. You will have the best luck reading the manual pages if +you build this software and then install it, although you can read +them directly out of the distribution if you need to. + +DHCP server documentation is in the dhcpd man page. Information about the DHCP server lease database is in the dhcpd.leases man page. Server configuration documentation is in the dhcpd.conf man page as well as the dhcp-options man page. A sample DHCP server configuration is in the file server/dhcpd.conf. The source for the dhcpd, dhcpd.leases and dhcpd.conf man pages is in the server/ sub- directory in the distribution. The source for the dhcp-options.5 -man page is in the common/ subdirectory.</P> +man page is in the common/ subdirectory. -<P>DHCP Client documentation is in the dhclient man page. DHCP client +DHCP Client documentation is in the dhclient man page. DHCP client configuration documentation is in the dhclient.conf man page and the dhcp-options man page. The DHCP client configuration script is documented in the dhclient-script man page. The format of the DHCP client lease database is documented in the dhclient.leases man page. The source for all these man pages is in the client/ subdirectory in the distribution. In addition, the dhcp-options man page should be -referred to for information about DHCP options.</P> +referred to for information about DHCP options. -<P>DHCP relay agent documentation is in the dhcrelay man page, the source -for which is distributed in the relay/ subdirectory.</P> +DHCP relay agent documentation is in the dhcrelay man page, the source +for which is distributed in the relay/ subdirectory. -<P>To read installed manual pages, use the man command. Type "man page" +To read installed manual pages, use the man command. Type "man page" where page is the name of the manual page. This will only work if you have installed the ISC DHCP distribution using the ``make install'' -command (described later).</P> +command (described later). -<P>If you want to read manual pages that aren't installed, you can type +If you want to read manual pages that aren't installed, you can type ``nroff -man page |more'' where page is the filename of the unformatted manual page. The filename of an unformatted manual page is the name of the manual page, followed by '.', followed by some @@ -83,78 +84,106 @@ number - 5 for documentation about files, and 8 for documentation about programs. For example, to read the dhcp-options man page, you would type ``nroff -man common/dhcp-options.5 |more'', assuming your current working directory is the top level directory of the ISC -DHCP Distribution.</P> +DHCP Distribution. -<P>If you do not have the nroff command, you can type ``more catpage'' +If you do not have the nroff command, you can type ``more catpage'' where catpage is the filename of the catted man page. Catted man pages names are the name of the manual page followed by ".cat" -followed by 5 or 8, as with unformatted manual pages.</P> +followed by 5 or 8, as with unformatted manual pages. -<P>Please note that until you install the manual pages, the pathnames of +Please note that until you install the manual pages, the pathnames of files to which they refer will not be correct for your operating -system.</P> - -<H4 ID="2">Release status</H4> - -<P>This is the final release of Version 2 of the Internet Software -Consortium DHCP Distribution. In version 2.0, this distribution -includes a DHCP server, a DHCP client, and a BOOTP/DHCP relay agent. -This release is stable.</P> - -<P>In this release, the server and relay agent currently work well on -NetBSD, Linux after kernel version 2.0.30, FreeBSD, BSD/OS, Ultrix, -Digital Alpha OSF/1, Solaris and SunOS 4.1.4. On AIX, HPUX, IRIX and -Linux 2.0.30, only a single broadcast network interface is supported. -They also runs on QNX as long as only one broadcast network interface -is configured and a host route is added from that interface to the -255.255.255.255 broadcast address.</P> - -<P>The DHCP client currently only knows how to configure the network on -NetBSD, FreeBSD, BSD/os, Linux, Solaris and NextStep. The client -depends on a system-dependent shell script to do network +system. + + RELEASE STATUS + +This is the second beta release of version 3.0 of the ISC DHCP +Distribution. Development of this release is approaching the point at +which it will be frozen, and no significant new features will be +added. + +In this release, the server and relay agent are currently fully +functional on NetBSD, Linux systems with kernel version 2.2 or later, +FreeBSD, OpenBSD, BSD/OS, Digital Tru64 Unix and Solaris. The +software will also run on HP-UX, but only supports a single network +interface. Ports also exist for QNX, SCO, NeXTStep, and MacOS X, but +are not in wide use, with all that implies. We are not aware of an +easy way to get this software running on HP-UX. + +The DHCP client currently only knows how to configure the network on +NetBSD, FreeBSD, OpenBSD, BSD/os, Linux, Solaris and NextStep. The +client depends on a system-dependent shell script to do network configuration - support for other operating systems is simply a matter -of porting this shell script to the new platform.</P> +of porting this shell script to the new platform. + +If you are running the DHCP distribution on a machine which is a +firewall, or if there is a firewall between your DHCP server(s) and +DHCP clients, please read the section on firewalls which appears later +in this document. -<P>If you wish to run the DHCP Distribution on Linux, please see the +If you wish to run the DHCP Distribution on Linux, please see the Linux-specific notes later in this document. If you wish to run on an SCO release, please see the SCO-specific notes later in this document. You particularly need to read these notes if you intend to support Windows 95 clients. If you are running a version of FreeBSD prior to 2.2, please read the note on FreeBSD. If you are running HP-UX or -Ultrix, please read the notes for those operating systems below. -If you are running NeXTSTEP, please see the notes on NeXTSTEP below.</P> +Ultrix, please read the notes for those operating systems below. If +you are running NeXTSTEP, please see the notes on NeXTSTEP below. -<P>If you start dhcpd and get a message, "no free bpf", that means you +If you start dhcpd and get a message, "no free bpf", that means you need to configure the Berkeley Packet Filter into your operating system kernel. On NetBSD, FreeBSD and BSD/os, type ``man bpf'' for -information. On Digital Unix, type ``man pfilt''.</P> +information. On Digital Unix, type ``man pfilt''. + + + BUILDING THE DHCP DISTRIBUTION -<H4 ID="3">Building the DHCP Distribution</H4> + UNPACKING IT -<P>To build the DHCP Distribution, unpack the compressed tar file using -the tar utility and the gzip command - type something like:</P> +To build the DHCP Distribution, unpack the compressed tar file using +the tar utility and the gzip command - type something like: -<BLOCKQUOTE> - zcat dhcp-2.0pl5.tar.gz |tar xvf - -</BLOCKQUOTE> + zcat dhcp-3.0.1rc6.tar.gz |tar xvf - -<P>On BSD/OS, you have to type gzcat, not zcat, and you may run into -similar problems on other operating systems.</P> +On BSD/OS, you have to type gzcat, not zcat, and you may run into +similar problems on other operating systems. -<P>Now, cd to the dhcp-2.0pl5 subdirectory that you've just created and -configure the source tree by typing:</P> + CONFIGURING IT + +Now, cd to the dhcp-3.0.1rc6 subdirectory that you've just +created and configure the source tree by typing: -<BLOCKQUOTE> ./configure -</BLOCKQUOTE> -<P>If the configure utility can figure out what sort of system you're +If the configure utility can figure out what sort of system you're running on, it will create a custom Makefile for you for that system; otherwise, it will complain. If it can't figure out what system you are using, that system is not supported - you are on -your own.</P> +your own. + + DYNAMIC DNS UPDATES + +A fully-featured implementation of dynamic DNS updates is included in +this release. There are no build dependencies with any BIND version +- this version can and should just use the resolver in your C library. + +There is documentation for the DDNS support in the dhcpd.conf manual +page - see the beginning of this document for information on finding +manual pages. -<P>Once you've run configure, just type ``make'', and after a while + LOCALLY DEFINED OPTIONS + +In previous versions of the DHCP server there was a mechanism whereby +options that were not known by the server could be configured using +a name made up of the option code number and an identifier: +"option-nnn" This is no longer supported, because it is not future- +proof. Instead, if you want to use an option that the server doesn't +know about, you must explicitly define it using the method described +in the dhcp-options man page under the DEFINING NEW OPTIONS heading. + + BUILDING IT + +Once you've run configure, just type ``make'', and after a while you should have a dhcp server. If you get compile errors on one of the supported systems mentioned earlier, please let us know. If you get warnings, it's not likely to be a problem - the DHCP @@ -162,56 +191,96 @@ server compiles completely warning-free on as many architectures as we can manage, but there are a few for which this is difficult. If you get errors on a system not mentioned above, you will need to do some programming or debugging on your own to get the DHCP -Distribution working.</P> +Distribution working. -<H4 ID="4">Installing the dhcp distribution</H4> + INSTALLING THE DHCP DISTRIBUTION -<P>Once you have successfully gotten the DHCP Distribution to build, you +Once you have successfully gotten the DHCP Distribution to build, you can install it by typing ``make install''. If you already have an old version of the DHCP Distribution installed, you may want to save it -before typing ``make install''.</P> - -<H4 ID="5">Using the dhcp distribution</H4> - -<H4 ID="5.1">Linux</H4> - -<P>There are three big LINUX issues: the all-ones broadcast address, +before typing ``make install''. + + USING THE DHCP DISTRIBUTION + + FIREWALL RULES + +If you are running the DHCP server or client on a computer that's also +acting as a firewall, you must be sure to allow DHCP packets through +the firewall. In particular, your firewall rules _must_ allow packets +from IP address 0.0.0.0 to IP address 255.255.255.255 from UDP port 68 +to UDP port 67 through. They must also allow packets from your local +firewall's IP address and UDP port 67 through to any address your DHCP +server might serve on UDP port 68. Finally, packets from relay agents +on port 67 to the DHCP server on port 67, and vice versa, must be +permitted. + +We have noticed that on some systems where we are using a packet +filter, if you set up a firewall that blocks UDP port 67 and 68 +entirely, packets sent through the packet filter will not be blocked. +However, unicast packets will be blocked. This can result in strange +behaviour, particularly on DHCP clients, where the initial packet +exchange is broadcast, but renewals are unicast - the client will +appear to be unable to renew until it starts broadcasting its +renewals, and then suddenly it'll work. The fix is to fix the +firewall rules as described above. + + PARTIAL SERVERS + +If you have a server that is connected to two networks, and you only +want to provide DHCP service on one of those networks (e.g., you are +using a cable modem and have set up a NAT router), if you don't write +any subnet declaration for the network you aren't supporting, the DHCP +server will ignore input on that network interface if it can. If it +can't, it will refuse to run - some operating systems do not have the +capability of supporting DHCP on machines with more than one +interface, and ironically this is the case even if you don't want to +provide DHCP service on one of those interfaces. + + LINUX + +There are three big LINUX issues: the all-ones broadcast address, Linux 2.1 ip_bootp_agent enabling, and operations with more than one network interface. There are also two potential compilation/runtime problems for Linux 2.1/2.2: the "SO_ATTACH_FILTER undeclared" problem -and the "protocol not configured" problem.</P> +and the "protocol not configured" problem. + + LINUX: IF_TR.H NOT FOUND -<H4 ID="5.1.1">So_attach_filter undeclared</H4> +When you compile the distribution on Linux, you may get an error +message indicating that the include file if_tr.h could not be found. +If this happens, go into includes/cf/linux.h and delete the line that +defined HAVE_TR_SUPPORT, or look into installing a new version of libc +that includes the if_tr.h file. We will be working on removing this +problem in the future, but for now, if you run into it, this should be +a viable workaround. -<P>In addition, there is a minor issue that we will mention here because + LINUX: SO_ATTACH_FILTER UNDECLARED + +In addition, there is a minor issue that we will mention here because this release is so close on the heels of the Linux 2.2 release: there is a symlink in /usr/include that points at the linux asm headers. It appears to be not uncommon that this link won't be updated correctly, -in which case you'll get the following error when you try to build:</P> +in which case you'll get the following error when you try to build: -<BLOCKQUOTE> lpf.c: In function `if_register_receive': lpf.c:152: `SO_ATTACH_FILTER' undeclared (first use this function) lpf.c:152: (Each undeclared identifier is reported only once lpf.c:152: for each function it appears in.) -</BLOCKQUOTE> -<P>The line numbers may be different, of course. If you see this +The line numbers may be different, of course. If you see this header, your linux asm header link is probably bad, and you should -make sure it's pointing to correct linux source directory.</P> +make sure it's pointing to correct linux source directory. -<H4 ID="5.1.2">Protocol not configured</H4> + LINUX: PROTOCOL NOT CONFIGURED -<P>One additional Linux 2.1/2.2 issue: if you get the following message, +One additional Linux 2.1/2.2 issue: if you get the following message, it's because your kernel doesn't have the linux packetfilter or raw -packet socket configured:</P> +packet socket configured: -<BLOCKQUOTE> Make sure CONFIG_PACKET (Packet socket) and CONFIG_FILTER (Socket Filtering) are enabled in your kernel configuration -</BLOCKQUOTE> -<P>If this happens, you need to configure your Linux kernel to support +If this happens, you need to configure your Linux kernel to support Socket Filtering and the Packet socket. You can do this by typing ``make config'', ``make menuconfig'' or ``make xconfig'', and then enabling the Packet socket and Socket Filtering options that you'll @@ -222,90 +291,75 @@ afterwards, so that the changes you've made are propogated to the kernel header files. After you've reconfigured, you need to type ``make'' to build a new Linux kernel, and then install it in the appropriate place (probably /linux). Make sure to save a copy of your -old /linux.</P> +old /linux. -<P>If the preceding paragraph made no sense to you, ask your Linux -vendor/guru for help - please don't ask us.</P> +If the preceding paragraph made no sense to you, ask your Linux +vendor/guru for help - please don't ask us. -<P>If you set CONFIG_PACKET=m or CONFIG_FILTER=m, then you must tell the +If you set CONFIG_PACKET=m or CONFIG_FILTER=m, then you must tell the kernel module loader to load the appropriate modules. If this doesn't make sense to you, don't use CONFIG_whatever=m - use CONFIG_whatever=y. Don't ask for help with this on the DHCP mailing list - it's a Linux kernel issue. This is probably not a problem with the most recent -Linux 2.2.x kernels.</P> +Linux 2.2.x kernels. + + LINUX: BROADCAST -<H4 ID="5.1.3">Broadcast</H4> +If you are running a recent version of Linux, this won't be a problem, +but on older versions of Linux (kernel versions prior to 2.2), there +is a potential problem with the broadcast address being sent +incorrectly. -<P>In order for dhcpd to work correctly with picky DHCP clients (e.g., +In order for dhcpd to work correctly with picky DHCP clients (e.g., Windows 95), it must be able to send packets with an IP destination address of 255.255.255.255. Unfortunately, Linux changes an IP destination of 255.255.255.255 into the local subnet broadcast address -(here, that's 192.5.5.223). This isn't a problem on Linux 2.2 and -later kernels, since we completely bypass the Linux IP stack, but on -old versions of Linux 2.1 and all versions of Linux prior to 2.1, it -is a problem - pickier DHCP clients connected to the same network as -the ISC DHCP server or ISC relay agent will not see messages from the -DHCP server.</P> - -<P>It is possible to work around this problem on some versions of Linux +(here, that's 192.5.5.223). + +This isn't generally a problem on Linux 2.2 and later kernels, since +we completely bypass the Linux IP stack, but on old versions of Linux +2.1 and all versions of Linux prior to 2.1, it is a problem - pickier +DHCP clients connected to the same network as the ISC DHCP server or +ISC relay agent will not see messages from the DHCP server. It *is* +possible to run into trouble with this on Linux 2.2 and later if you +are running a verson of the DHCP server that was compiled on a Linux +2.0 system, though. + +It is possible to work around this problem on some versions of Linux by creating a host route from your network interface address to 255.255.255.255. The command you need to use to do this on Linux -varies from version to version. The easiest version is:</P> +varies from version to version. The easiest version is: -<BLOCKQUOTE> route add -host 255.255.255.255 dev eth0 -</BLOCKQUOTE> -<P>On some older Linux systems, you will get an error if you try to do +On some older Linux systems, you will get an error if you try to do this. On those systems, try adding the following entry to your -/etc/hosts file:</P> +/etc/hosts file: -<BLOCKQUOTE> 255.255.255.255 all-ones -</BLOCKQUOTE> -<P>Then, try:</P> +Then, try: -<BLOCKQUOTE> route add -host all-ones dev eth0 -</BLOCKQUOTE> -<P>Another route that has worked for some users is:</P> +Another route that has worked for some users is: -<BLOCKQUOTE> route add -net 255.255.255.0 dev eth0 -</BLOCKQUOTE> - -<P>If you are not using eth0 as your network interface, you should -specify the network interface you *are* using in your route command.</P> - -<H4 ID="5.1.4">Firewall rules</H4> -<P>If you are running the DHCP server or client on a Linux system that's -also acting as a firewall, you must be sure to allow DHCP packets -through the firewall - Linux firewalls make filtering decisions before -they make the forwarding decision, so they will filter packets that -are intended for the firewall itself, as well as packets intended to -be forwarded. In particular, your firewall rules _must_ allow -packets from IP address 0.0.0.0 to IP address 255.255.255.255 from UDP -port 68 to UDP port 67 through. They must also allow packets from -your local firewall's IP address and UDP port 67 through to any -address your DHCP server might serve on UDP port 68. Finally, -packets from relay agents on port 67 to the DHCP server on port 67, -and vice versa, must be permitted.</P> +If you are not using eth0 as your network interface, you should +specify the network interface you *are* using in your route command. -<H4 ID="5.1.5">IP BOOTP agent</H4> + LINUX: IP BOOTP AGENT -<P>Some versions of the Linux 2.1 kernel apparently prevent dhcpd from -working unless you enable it by doing the following:</P> +Some versions of the Linux 2.1 kernel apparently prevent dhcpd from +working unless you enable it by doing the following: -<BLOCKQUOTE> echo 1 >/proc/sys/net/ipv4/ip_bootp_agent -</BLOCKQUOTE> -<H4 ID="5.1.6">Multiple interfaces</H4> -<P>Very old versions of the Linux kernel do not provide a networking API + LINUX: MULTIPLE INTERFACES + +Very old versions of the Linux kernel do not provide a networking API that allows dhcpd to operate correctly if the system has more than one broadcast network interface. However, Linux 2.0 kernels with version numbers greater than or equal to 2.0.31 add an API feature: the @@ -313,100 +367,104 @@ SO_BINDTODEVICE socket option. If SO_BINDTODEVICE is present, it is possible for dhcpd to operate on Linux with more than one network interface. In order to take advantage of this, you must be running a 2.0.31 or greater kernel, and you must have 2.0.31 or later system -headers installed *before* you build the DHCP Distribution.</P> +headers installed *before* you build the DHCP Distribution. -<P>We have heard reports that you must still add routes to 255.255.255.255 +We have heard reports that you must still add routes to 255.255.255.255 in order for the all-ones broadcast to work, even on 2.0.31 kernels. In fact, you now need to add a route for each interface. Hopefully -the Linux kernel gurus will get this straight eventually.</P> +the Linux kernel gurus will get this straight eventually. -<P>Linux 2.1 and later kernels do not use SO_BINDTODEVICE or require the +Linux 2.1 and later kernels do not use SO_BINDTODEVICE or require the broadcast address hack, but do support multiple interfaces, using the -Linux Packet Filter.</P> +Linux Packet Filter. -<H4 ID="5.2">SCO</H4> + SCO -<P>SCO has the same problem as Linux (described earlier). The thing is, +SCO has the same problem as Linux (described earlier). The thing is, SCO *really* doesn't want to let you add a host route to the all-ones -broadcast address. One technique that has been successful on some -versions of SCO is the very bizarre command:</P> +broadcast address. + +On more recent versions of SCO, you can do this: + + ifconfig net0 xxx.xxx.xxx.xxx netmask 0xNNNNNNNN broadcast 255.255.255.255 + +If this doesn't work, you can also try the following strange hack: -<BLOCKQUOTE> - ifconfig net0 alias 10.1.1.1 netmask 8.0.0.0 -</BLOCKQUOTE> + ifconfig net0 alias 10.1.1.1 netmask 8.0.0.0 -<P>Apparently this works because of an interaction between SCO's support +Apparently this works because of an interaction between SCO's support for network classes and the weird netmask. The 10.* network is just a dummy that can generally be assumed to be safe. Don't ask why this -works. Just try it. If it works for you, great. If not, SCO is -supposedly adding hooks to support real DHCP service in a future -release - I have this on good authority from the people at SCO who do -*their* DHCP server and client.</P> +works. Just try it. If it works for you, great. SCO has added +support for doing DHCP in a more sensible way, but I have not had the +time or cause to implement them. If you are interested in this, and +are able to hack your way out of a wet paper back without assistance, +we'd appreciate it if you'd give it a try, but don't expect too much +support from us (sorry!). -<H4 ID="5.3">HP-UX</H4> + HP-UX -<P>HP-UX has the same problem with the all-ones broadcast address that +HP-UX has the same problem with the all-ones broadcast address that SCO and Linux have. One user reported that adding the following to /etc/rc.config.d/netconf helped (you may have to modify this to suit -your local configuration):</P> +your local configuration): -<BLOCKQUOTE> INTERFACE_NAME[0]=lan0 IP_ADDRESS[0]=1.1.1.1 SUBNET_MASK[0]=255.255.255.0 BROADCAST_ADDRESS[0]="255.255.255.255" LANCONFIG_ARGS[0]="ether" DHCP_ENABLE[0]=0 -</BLOCKQUOTE> -<H4 ID="5.4">Ultrix</H4> + ULTRIX -<P>Now that we have Ultrix packet filter support, the DHCP Distribution +Now that we have Ultrix packet filter support, the DHCP Distribution on Ultrix should be pretty trouble-free. However, one thing you do need to be aware of is that it now requires that the pfilt device be configured into your kernel and present in /dev. If you type ``man packetfilter'', you will get some information on how to configure your kernel for the packet filter (if it isn't already) and how to make an -entry for it in /dev.</P> +entry for it in /dev. -<H4 ID="5.5">FreeBSD</H4> + FreeBSD -<P>Versions of FreeBSD prior to 2.2 have a bug in BPF support in that the +Versions of FreeBSD prior to 2.2 have a bug in BPF support in that the ethernet driver swaps the ethertype field in the ethernet header downstream from BPF, which corrupts the output packet. If you are running a version of FreeBSD prior to 2.2, and you find that dhcpd can't communicate with its clients, you should #define BROKEN_FREEBSD_BPF -in site.h and recompile.</P> +in site.h and recompile. -<H4 ID="5.6">NeXTStep</H4> + NeXTSTEP -<P>The NeXTSTEP support uses the NeXTSTEP Berkeley Packet Filter +The NeXTSTEP support uses the NeXTSTEP Berkeley Packet Filter extension, which is not included in the base NextStep system. You -must install this extension in order to get dhcpd or dhclient to work.</P> +must install this extension in order to get dhcpd or dhclient to work. -<H4 ID="5.7">Solaris</H4> + SOLARIS -<P>One problem which has been observed and is not fixed in this +One problem which has been observed and is not fixed in this patchlevel has to do with using DLPI on Solaris machines. The symptom of this problem is that the DHCP server never receives any requests. -If you are using Solaris 2.6, and you encounter this symptom, and -you are running the DHCP server on a machine with a single broadcast -network interface, you may wish to edit the includes/site.h file and -uncomment the #define USE_SOCKETS line. Then type ``make clean; -make''.</P> - -<P>The DHCP client on Solaris will only work with DLPI. If you run it +This has been observed with Solaris 2.6 and Solaris 7 on Intel x86 +systems, although it may occur with other systems as well. If you +encounter this symptom, and you are running the DHCP server on a +machine with a single broadcast network interface, you may wish to +edit the includes/site.h file and uncomment the #define USE_SOCKETS +line. Then type ``make clean; make''. + +The DHCP client on Solaris will only work with DLPI. If you run it and it just keeps saying it's sending DHCPREQUEST packets, but never gets a response, you may be having DLPI trouble as described above. -If so, you are SOL. Also, because Solaris requires you to "plumb" an -interface before it can be detected by the DHCP client, you must -either specify the name(s) of the interface(s) you want to configure -on the command line, or must plumb the interfaces prior to invoking -the DHCP client. This can be done with ``ifconfig iface plumb'', -where iface is the name of the interface (e.g., ``ifconfig hme0 -plumb'').</P> - -<P>It should be noted that Solaris versions from 2.6 onward include a +If so, we have no solution to offer at this time. Also, because +Solaris requires you to "plumb" an interface before it can be detected +by the DHCP client, you must either specify the name(s) of the +interface(s) you want to configure on the command line, or must plumb +the interfaces prior to invoking the DHCP client. This can be done +with ``ifconfig iface plumb'', where iface is the name of the +interface (e.g., ``ifconfig hme0 plumb''). + +It should be noted that Solaris versions from 2.6 onward include a DHCP client that you can run with ``/sbin/ifconfig iface dhcp start'' rather than using the ISC DHCP client. The feature set of the Solaris client is different (not necessarily better or worse) than that of the @@ -415,121 +473,177 @@ use that. Please do not ask for help in using the Solaris DHCP client on Internet Software Consortium mailing lists - that's why you're paying Sun the big bucks. If you're having a problem with the Solaris client interoperating with the ISC dhcp server, that's another -matter, but please check with Sun first.</P> +matter, but please check with Sun first. -<H4 ID="6">Support</H4> + SUPPORT -<P>The Internet Software Consortium DHCP server is not a commercial -product, and is not supported in that sense. However, it has -attracted a fairly sizable following on the Internet, which means that -there are a lot of knowledgable users who may be able to help you if -you get stuck. These people generally read the dhcp-server@fugue.com -mailing list.</P> +The Internet Software Consortium DHCP server is not a commercial +product, and is not supported by the ISC. However, it has attracted a +fairly sizable following on the Internet, which means that there are a +lot of knowledgable users who may be able to help you if you get +stuck. These people generally read the dhcp-server@isc.org mailing +list. -<P>If you are going to use dhcpd, you should probably subscribe to the +If you are going to use dhcpd, you should probably subscribe to the dhcp-server and dhcp-announce mailing lists. If you will be using -dhclient, you should subscribe to the dhcp-client mailing list.</P> - -<P>If you need help, you should ask on the dhcp-server or dhcp-client -mailing list (or both) - whichever is appropriate to your -application. This includes reporting bugs. Please do not report -bugs in old software releases - fetch the latest release and see if -the bug is still in that copy of the software, and if it's not, _then_ -report it. It's okay to report bugs in the latest patchlevel of a -major version that's not the most recent major version, though - for -example, if you're running 2.0, you don't have to upgrade to 3.0 -before you can report bugs.</P> - -<H4 ID="6.1">Please read this readme file carefully before reporting bugs!</H4> -<H4>How to report bugs</H4> - -<P>When you report bugs, please provide us complete information. A list -of information we need follows. Please read it carefully, and put -all the information you can into your initial bug report, so that we -don't have to ask you any questions in order to figure out your -problem.</P> - -<UL> -<LI>The specific operating system name and version of the -machine on which the DHCP server or client is running. -<LI>The specific operating system name and version of the -machine on which the client is running, if you are having -trouble getting a client working with the server. -<LI>If you're running Linux, the version number we care about is -the kernel version and maybe the library version, not the -distribution version - e.g., while we don't mind knowing -that you're running Redhat version mumble.foo, we must know -what kernel version you're running, and it helps if you can -tell us what version of the C library you're running, -although if you don't know that off the top of your head it -may be hard for you to figure it out, so don't go crazy -trying. -<LI>The specific version of the DHCP distribution you're -running, for example 2.0b1pl19, not 2.0. -<LI>Please explain the problem carefully, thinking through what -you're saying to ensure that you don't assume we know -something about your situation that we don't know. -<LI>Include your dhcpd.conf and dhcpd.leases file if they're not -huge (if they are huge, we may need them anyway, but don't -send them until you're asked). -<LI>Include a log of your server or client running until it -encounters the problem - for example, if you are having -trouble getting some client to get an address, restart the -server with the -d flag and then restart the client, and -send us what the server prints. Likewise, with the client, -include the output of the client as it fails to get an -address or otherwise does the wrong thing. Do not leave -out parts of the output that you think aren't interesting. -<LI>If the client or server is dumping core, please run the -debugger and get a stack trace, and include that in your -bug report. For example, if your debugger is gdb, do the -following: - -<BLOCKQUOTE> +dhclient, you should subscribe to the dhcp-client mailing list. + +If you need help, you should ask on the dhcp-server or dhcp-client +mailing list - whichever is appropriate to your application. Support +requests for the ISC DHCP client should go to dhcp-client@isc.org. +Support requests for the DHCP server should go to dhcp-server@isc.org. +If you are having trouble with a combination of the client and server, +send the request to dhcp-server@isc.org. Please do not cross-post to +both lists under any circumstances. + +WHERE TO REPORT BUGS: If you want the act of sending in a bug report +to result in you getting help in the form of a fixed piece of +software, you are asking for help. Your bug report is helpful to us, +but fundamentally you are making a support request, so please use the +addresses described in the previous paragraphs. If you are _sure_ that +your problem is a bug, and not user error, or if your bug report +includes a patch, you can send it to dhcp-bugs@isc.org without +subscribing. This mailing list goes into a bug tracking system, so +you don't need to check periodically to see if we still remember the +bug - if you haven't been notified that the bug has been closed, we +still consider it a bug, and still have it in the system. + +PLEASE DO NOT REPORT BUGS IN OLD SOFTWARE RELEASES! Fetch the latest +release and see if the bug is still in that version of the software, +and if it's not, _then_ report it. It's okay to report bugs in the +latest patchlevel of a major version that's not the most recent major +version, though - for example, if you're running 2.0, you don't have +to upgrade to 3.0 before you can report bugs. + +PLEASE DO NOT REPORT BUGS IF YOU ARE RUNNING A VERSION OF THE ISC +DHCP DISTRIBUTION THAT YOU DIDN'T GET FROM THE ISC! Free operating +system distributions are notorious for including outdated versions of +software, and also versions of software that were not compiled on your +particular version of the operating system. These versions +frequently do not work. Getting a source distribution from the ISC +and installing it frequently *does* work. Please try this *before* +asking for help. + +PLEASE READ THIS README FILE CAREFULLY BEFORE REPORTING BUGS, +PARTICULARLY THE SECTION BELOW ON WHAT TO INCLUDE IN A BUG REPORT OR +HELP REQUEST. + +PLEASE DO NOT SEND REQUESTS FOR SUPPORT DIRECTLY TO THE ENGINEERS WHO +WORK ON THE ISC DHCP DISTRIBUTION! *PARTICULARLY*, DO NOT SEND MAIL +TO THE ENGINEERS BECAUSE YOU AREN'T SURE TO WHOM YOU SHOULD SEND MAIL +- if you aren't sure, *ask* on the dhcp-server@isc.org or +dhcp-client@isc.org mailing list. + +The number of people using the DHCP Distribution is sufficiently large +that if we take interrupts every time any one of those people runs +into trouble, we will never get any more coding done. If you send a +support request directly to any ISC or Nominum engineer, we will +forward it to the mailing list, or possibly ignore it, depending on +how much stress we are under at the time. + +Please do not Cc: us on mail you send to these lists - we read both +mailing lists, so this just means we get two copies! + +If your question can only be answered by one of the engineers, send it +to the appropriate public mailing list anyway - we will answer it +there. When we have time. + +Please do not think "Oh, I don't want to bother the whole mailing list +with this question." If you are too embarrassed to ask publically, +get a support contract. + +If you are concerned about bothering everybody on the list, that's +great, but that's what the list is there for. When you send mail to +one of the engineers, you are taking resources away from everybody on +the mailing list *anyway* - they just don't know it. + +We're not writing this because we don't respect you - we really do +want to help you, and we appreciate your bug reports and comments. +But please use the mechanisms we have in place to provide you with +help, because otherwise you are almost certainly depriving someone +else of our help. + +PLEASE DO NOT CALL US ON THE PHONE FOR HELP! Answering the phone +takes a lot more of our time and attention than answering email. If +you do call us on the phone, we will tell you to send email to the +mailing list or buy a support contract, so please don't waste your +time or ours. If you have a support contract, please use the support +channel mentioned in the support contract - otherwise you probably +won't get timely support unless you happen to ask an interesting +question and we happen to have some time to kill, because we can't +tell you're a support customer if you send mail to the public mailing +lists. + + HOW TO REPORT BUGS OR REQUEST HELP + +When you report bugs or ask for help, please provide us complete +information. A list of information we need follows. Please read it +carefully, and put all the information you can into your initial bug +report, so that we don't have to ask you any questions in order to +figure out your problem. If you need handholding support, please +consider contacting a commercial provider of the ISC DHCP +Distribution. + + 1. The specific operating system name and version of the + machine on which the DHCP server or client is running. + 2. The specific operating system name and version of the + machine on which the client is running, if you are having + trouble getting a client working with the server. + 3. If you're running Linux, the version number we care about is + the kernel version and maybe the library version, not the + distribution version - e.g., while we don't mind knowing + that you're running Redhat version mumble.foo, we must know + what kernel version you're running, and it helps if you can + tell us what version of the C library you're running, + although if you don't know that off the top of your head it + may be hard for you to figure it out, so don't go crazy + trying. + 4. The specific version of the DHCP distribution you're + running, for example "2.0b1pl19", not "2.0". + 5. Please explain the problem carefully, thinking through what + you're saying to ensure that you don't assume we know + something about your situation that we don't know. + 6. Include your dhcpd.conf and dhcpd.leases file if they're not + huge (if they are huge, we may need them anyway, but don't + send them until you're asked). Huge means more than 100 + kilobytes each. + 7. Include a log of your server or client running until it + encounters the problem - for example, if you are having + trouble getting some client to get an address, restart the + server with the -d flag and then restart the client, and + send us what the server prints. Likewise, with the client, + include the output of the client as it fails to get an + address or otherwise does the wrong thing. Do not leave + out parts of the output that you think aren't interesting. + 8. If the client or server is dumping core, please run the + debugger and get a stack trace, and include that in your + bug report. For example, if your debugger is gdb, do the + following: + gdb dhcpd dhcpd.core (gdb) where [...] (gdb) quit -</BLOCKQUOTE> - -<P>This assumes that it's the dhcp server you're debugging, and -that the core file is in dhcpd.core.</P> -</UL> - -<P><EM>Please, <B>do not</B></EM> send queries about non-isc clients -to the dhcp-client mailing list. If you're asking about them on an -ISC mailing list, it's probably because you're using the ISC DHCP -server, so ask there. If you are having problems with a client whose -executable is called dhcpcd, this is <EM>not</EM> the ISC DHCP client, -and we probably can't help you with it.</P> - -<P>Please see <A HREF="http://www.fugue.com/dhcp/lists"> -http://www.fugue.com/dhcp/lists</A> for details on how to subscribe. -If you don't have WorldWide Web access, you can send mail to -dhcp-request@fugue.com and tell me which lists you want to subscribe -to, but please use the web interface if you can, since I have to -handle the -request mailing list manually, and I will give you the -third degree if you make me do your subscription manually.</P> - -<P><EM>Please do not send requests for help directly to the author!</EM> -The number of people using the DHCP Distribution is sufficiently large -that if we take an interrupt every time any one of those people runs into -trouble, we will never get any more coding done.</P> - -<P><EM>Please do not call the author on the phone for support!</EM> -Answering the phone takes a lot more time and attention than answering -email. If you do call on the phone, you will be told to send email to -the mailing list, so there's no point in doing it.</P> - -<P><B>Exception:</B> if you are a support customer, you already know -how to get in touch with us. To become a support customer, see our -<A HREF="/isc/ISC_HTML/services/support/index.phtml">Support web -page</A>. -<H4 ID="7">Known bugs</H4> + This assumes that it's the dhcp server you're debugging, and + that the core file is in dhcpd.core. + 9. If you know that the problem is an actual bug, and you can + reproduce the bug, you can skip steps 6 through 8 and instead + capture a trace file using the -tf flag (see the man page for + details). If you do this, and there is anything in your + dhcp configuration that you are not willing to make public, + please send the trace file to dhcp-bugs@isc.org and NOT to + dhcp-server@isc.org, because the tracefile contains your entire + dhcp configuration. + +PLEASE DO NOT send queries about non-isc clients to the dhcp-client +mailing list. If you're asking about them on an ISC mailing list, +it's probably because you're using the ISC DHCP server, so ask there. +If you are having problems with a client whose executable is called +dhcpcd, this is _not_ the ISC DHCP client, and we probably can't help +you with it. + +Please see http://www.isc.org/services/public/lists/dhcp-lists.html +for details on how to subscribe to the ISC DHCP mailing lists. -<P>This release of the DHCP Distribution does not yet contain support for -DHCPINFORM. The Vendor Specific Data option is not supported. Site- -specific options are not supported. All of these are supported in the -3.0 release of the DHCP distribution, which is now in beta testing.</P> diff --git a/contrib/isc-dhcp/RELNOTES b/contrib/isc-dhcp/RELNOTES index de029af..df58adc 100644 --- a/contrib/isc-dhcp/RELNOTES +++ b/contrib/isc-dhcp/RELNOTES @@ -1,766 +1,1003 @@ - Internet Software Consortium - Dynamic Host Configuration Protocol Distribution - Version 2 Patchlevel 5 - September 6, 2000 + Internet Software Consortium DHCP Distribution + Version 3.0.1 + Release Candidate 6 + January 17, 2002 Release Notes -Version 2 of the ISC DHCP Distribution includes the ISC DHCP server, -DHCP Client and DHCP/BOOTP Relay Agent. - -This version has been in a near feature freeze since January of 1998, -was in Beta test from that time to June of 1999, and has now been -released in its final form. It has a number of important features, -and is the release that we would expect most sites to run. + NEW FEATURES + +Version 3 of the ISC DHCP Distribution includes the following features +that are new since version 2.0: + + - DHCP Failover Protocol support + - OMAPI, an API for accessing and modifying the DHCP server and + client state. + - Conditional behaviour + - Storing arbitrary information on leases + - Address pools with access control + - Client classing + - Address allocation restriction by class + - Relay agent information option support + - Dynamic DNS updates + - Many bug fixes, performance enhancements, and minor new DHCP + protocol features. + +This is a release candidate for a minor bug fix release to follow ISC +DHCP 3.0. The main bug fixed here is a bug in the subclass allocation +code that could result in a memory smash. Any users of the ISC DHCP server +who are using subclasses should seriously consider upgrading to 3.0.1 +either now or when the final 3.0.1 release comes out. + +If you are running 3.0 beta 1 and are doing dynamic DNS updates, the +lease file is no longer forward-compatible to 3.0 final. A script +has been provided to convert 3.0b1 lease files. This is in +contrib/3.0b1-lease-convert. For information on how to install, configure and run this software, as well as how to find documentation and report bugs, please consult the README file. - CHANGELOG +The Dynamic DNS Update support is a descendent of an implementation +done by Lans Carstensen and Brian Dols at Rose-Hulman Institute of +Technology, Jim Watt at Applied Biosystems, Irina Goble at Integrated +Measurement Systems, Igor Sharfmesser at Kazakh Telecom, and Brian +Murrell at BC Tel Advanced Communications. I'd like to express my +thanks to all of these good people here, both for working on the code +and for prodding me into improving it. -This log describes the changes that have been made in version 2.0 -since June of 1997. + Changes since 3.0.1rc5 - CHANGES FROM VERSION 2.0 PATCHLEVEL 4 +- Include some new documentation and changes provided by Karl Auer. -- Fix a prototype mismatch that causes compiles to fail on some architectures. +- Add a workaround for some Lexmark printers that send a double-NUL- + terminated host-name option, which would break DNS updates. -- Two minor cosmetic changes to manual pages. +- Fix an off-by-one error in the MAC-address checking code for + DHCPRELEASE that was added in 3.0.1rc5. - CHANGES FROM VERSION 2.0 PATCHLEVEL 3 +- Fix a bug where client-specific information was not being discarded + from the lease when it expired or was released, resulting in + problems if the lease was reallocated to a different client. -- Fix a bug introduced in the client in the previous patchlevel where the - broadcast would be set to the subnet number instead of the broadcast - address. +- If more than one allocation pool is specified that has the same set + of constraints as another allocation pool on the same shared + network, merge the two pools. - CHANGES FROM VERSION 2.0 PATCHLEVEL 2 +- Don't print an error in fallback_discard, since this just causes + confusion and does not appear to be helping to encourage anyone to + fix this bug. -- Rather than calling a client environment setup script, set the - environment up directly, so as to avoid any possible exploit making - use of clever shell metacharacter hacks. This is a security fix - that applies to the DHCP client *only*. + Changes since 3.0.1rc4 - CHANGES FROM VERSION 2.0 PATCHLEVEL 1 +- Fix a bug that would cause the DHCP server to spin if asked to parse + a certain kind of incorrect statement. -- Fix a case where an unitialized pointer could result from an exceptional - case in DHCPRELEASE and cause a core dump. +- Fix a related bug that would prevent an error from being reported in + the same case. - CHANGES FROM VERSION 2.0 +- Additional documentation. -- Clean up DHCPRELEASE support. +- Make sure that the hardware address matches the lease when + processing a DHCPRELEASE message. -- Don't use the broadcast flag when doing BOOTP unless we need to. + Changes since 3.0.1rc3 -- Clean up the fallback mess. +- A minor bug fix in the arguments to a logging function call. +- Documentation update for dhcpd.conf. -- Quote all shell special characters in the client script. + Changes since 3.0.1rc2 -- Fix ethernet header alignment on arm32. +- Allow the primary to send a POOLREQ message. This isn't what the current + failover draft says to do, so we may have to back it out if I can't get the + authors to relent, but the scheme for balancing that's specified in the + current draft seems needlessly hairy, so I'm floating a trial balloon. + The rc1 code did not implement the method described in the draft either. -- Clarify the "no subnet declaration" message. + Changes since 3.0.1rc1 -- Correctly store the tftp server name in the lease file and the - client script file. +- Treat NXDOMAIN and NXRRSET as success when we are trying to delete a + domain or RRSET. This allows the DHCP server to forget about a name + it added to the DNS once it's been removed, even if the DHCP server + wasn't the one that removed it. -- Avoid a potential spin loop in client when script file creation - fails for reasons other than the presence of an existing file of the - same name. +- Install defaults for failover maximum outstanding updates and maximum + silent time. This prevents problems that might occur if these values + were not configured. -- Add support for Linux kernel versions greater than 2.2. +- Don't do DDNS deletes if ddns-update-style is none. -- Fix a problem in raw.c on Irix. Thanks to Don Badrak for the - patch. +- Return relay agent information options in DHCPNAK. This prevents DHCPNAK + messages from being dropped when the relay agent information option contains + routing information. - CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 29 +- Fix a problem where coming up in recover wouldn't result in an update + request being sent. -- Define BYTE_ORDER in includes/cf/hpux.h so that ip.h will compile - correctly on HP-UX. +- Add some more chatty messages when we start a recovery update and when it's + done. -- Fix a long-standing but minor bug in the way the program name for - syslog was derived. +- Fix a possible problem where some state might have been left around + after the peer lost contact and regained contact about how many updates + were pending. -- Fix a long-standing bug that prevented the DHCP server from broadcasting - responses to BOOTP clients that requested a broadcast response. +- Don't nix a lease update because of a lease conflict. This test has + never (as far as I know) prevented a mistake, and it appears to cause + problems with failover. -- In dhcprequest(), check to make sure that there's a lease before trying - to acknowledge it to the client. This fixes a potential core dump that - a few people observed. +- Add support in rc history code for keeping a selective history, rather + than a history of all references and dereferences. This code is only used + when extensive additional debugging is enabled. - CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 28 + Changes since 3.0 -- Fix some pastos I introduced when merging Andrew Chittenden's token - ring support. +- Make allocators for hash tables. As a side effect, this fixes a memory + smash in the subclass allocation code. -- Apply a patch to the token ring support from Andrew Chittenden. +- Fix a small bug in omshell where if you try to close an object when + no object is open, it dumps core. - CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 27 +- Fix an obscure coredump that could occur on shutdown. -- Add dependencies to makefiles. +- Fix a bug in the recording of host declaration rubouts in the lease file. -- Don't use ping -w 1 in freebsd client script. +- Fix two potential spins in the host deletion code. -- Token ring support for LPF, contributed by Andrew Chittenden. +- Fix a core dump that would happen if an application tried to update + a host object attribute with a null value. -- Fix a subtle bug that would cause the server to respond incorrectly - in some cases when the client sent duplicate DHCPREQUEST packets. + Changes since 3.0 Release Candidate 12 -- Fix option pretty printing for 'X' format. +- Fix a memory leak in the evaluation code. -- Add some special cases to deal with DHCPREQUEST packets from RFC1541 - clients. +- Fix an obscure core dump. -- Fix an obscure bug in nested subnet mask handling. +- Print a couple of new warnings when parsing the configuration file + when crucial information is left out. -- Fix a bug in abandoned lease reclamation. +- Log "no free leases" as an error. -- Allow maximum message size to be set in configuration file. +- Documentation updates. -- Allow parameter request list to be supplied in configuration file. + Changes since 3.0 Release Candidate 11 - CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 26 +- Always return a subnet selection option if one is sent. -- Fix UDP/IP checksum code +- Fix a warning that was being printed because an automatic data + structure wasn't zeroed. -- Fix UDP payload length computation to prevent logging of spurious - errors. +- Fix some failover state transitions that were being handled + incorrectly. -- Support compilation on MacOS X +- When supersede_lease is called on a lease whose end time has already + expired, but for which a state transition has not yet been done, do + a state transition. This fixes the case where if the secondary + allocated a lease to a client and the lease "expired" while the + secondary was in partner-down, no expiry event would actually + happen, so the lease would remain active until the primary was + restarted. -- Add support for some options that were added in RFC2132. + Changes since 3.0 Release Candidate 10 - CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 25 +- Fix a bug that was preventing released leases from changing state + in failover-enabled pools. -- Use the udp header's length rather than computing the length based - on the number of bytes received, because some broken relay agents - send packets with ip lengths that are longer than then sum of the ip - header size and the udp length. +- Fix a core dump in the client identifier finder code (for host + declarations). -- Do path keyword substitution on unformatted manual pages before - installing them. +- Finish fixing a bug where bogus data would sometimes get logged to + the dhclient.leases file because it was opened as descriptor 2. - CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 24 +- Fix the linux dhclient-script according to suggestions made by + several people on the dhcp-client mailing list. -- D'oh! Fix a really stupid mistake in hash.c. +- Log successful DNS updates at LOG_INFO, not LOG_ERROR. - CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 23 +- Print an error message and refuse to run if a failover peer is + defined but not referenced by any pools. -- Support an always-reply-rfc1048 flag, which says to reply with an - RFC1048-style vendor extensions buffer even if the client didn't - send an RFC1048-style magic number. +- Correct a confusing error message in failover. -- Fix a null pointer dereference. + Changes since 3.0 Release Candidate 9 -- Use netmask from subnet if no netmask option specified. +- Fix a bug in lease allocation for Dynamic BOOTP clients. -- IRIX support (thanks to Don Badrak). + Changes since 3.0 Release Candidate 8 Patchlevel 2 -- Install unformatted manual pages on Linux. +- Fix a bug that prevented update-static-leases from working. -- Add note in README about zcat vs. gzcat on BSD/os. +- Document failover-state OMAPI object. - CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 22 +- Fix a compilation error on SunOS 4. -- Test for lease before dereferencing it in dhcprequest. + Changes since 3.0 Release Candidate 8 Patchlevel 1 -- Free the client parameter request list in dhcpnak if there is one. +- Fix a parsing bug that broke dns updates (both interim and ad-hoc). + This was introduced in rc8pl1 as an unintended result of the memory + leakage fixes that were in pl1. - CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 21 +- Fix a long-standing bug where the server would record that an update + had been done for a client with no name, even though no update had + been done, and then when the client's lease expired the deletion of + that nonexistant record would time out because the name was the null + string. -- Fix a pasto in options.c that will cause a core dump whenever a - client sends in a request without a parameter request list. +- Clean up the omshell, dhcpctl and omapi man pages a bit. - CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 20 + Changes since 3.0 Release Candidate 8 -- Actually do the client fix mentioned below - Patchlevel 20 only contained - half of the fix. +- Fix a bug that could cause the DHCP server to spin if + one-lease-per-client was enabled. - CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 19 +- Fix a bug that was causing core dumps on BSD/os in the presence of + malformed packets. -- Removed arp table clearing code from solaris client script. +- In partner-down state, don't restrict lease lengths to MCLT. -- Document Linux "protocol not configured" error more thoroughly. +- On the failover secondary, record the MCLT received from the primary + so that if we come up without a connection to the primary we don't + wind up giving out zero-length leases. -- Clean up some unused variables. +- Fix some compilation problems on BSD/os. -- Add entry and exit hooks to all dhcp client scripts, along with a - make_resolv_conf function that can be redefined in the entry hooks. - Document this new feature set. +- Fix a bunch of memory leaks. -- Fix client to take advantage of network APIs that allow it to - receive a unicast instead of requesting that the DHCP server - broadcast its response. +- Fix a couple of bugs in the option printer. -- Add -pf flag to all daemons allowing user to specify PID file name - on command line. +- Fix an obscure error reporting bug in the dns update code, and also + make the message clearer when a key algorithm isn't supported. -- Undo a previous change that attempted to be clever about testing - interface flags but wound up being stupid instead. +- Fix a bug in the tracing code that prevented trace runs that used + tcp connections from being played back. -- Enforce access control on DHCPREQUEST messages as well as - DHCPDISCOVER messages. +- Add some additional debugging capability for catching memory leaks + on exit. - CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 18 +- Make the client release the lease correctly on shutdown. -- Support added for AIX 4.1.5.0 (and hopefully other versions). +- Add some configurability to the build system. -- Use /var/run instead of /etc on Digital Unix. +- Install omshell manual page in man1, not man8. -- Change DHCP client exponential backoff code to back off more slowly, - so that it is more robust in lossy environments, at the expense of - being a bit less polite to the server. +- Craig Gwydir sent in a patch that fixes a long-standing bug in the + DHCP client that could cause core dumps, but that for some reason + hadn't been noticed until now. -- Don't request a specific lease interval in the client unless the - user says to do so. + Changes since 3.0 Release Candidate 7 -- Don't print DHCPXXX in wrong xxx messages unless DEBUG is defined. +- Fix a bug in failover where we weren't sending updates after a + transition from communications-interrupted to normal. -- Fix handling of secs field. +- Handle expired/released/reset -> free transition according to the + protocol specification (this works - the other way not only wasn't + conformant, but also didn't work). -- Fix handling of append statement. +- Add a control object in both client and server that allows either + daemon to be shut down cleanly. -- Fix documentation for append and prepend statements. +- When writing a lease, if we run out of disk space, shut down the + output file and insist on writing a new one before proceeding. -- Fix server support for parameter request list and maximum message - size. +- In the server, if the OMAPI listener port is occupied, keep trying + to get it, rather than simply giving up and exiting. -- Parameterize more hardware types in discover_interfaces. Check for - IFF_BROADCAST instead of !IFF_POINTOPOINT +- Support fetching variables from leases and also updating and adding + variables to leases via OMAPI. -- Print kernel configuration warning message if we get EINVAL when - opening or configuring the Linux packet filter. +- If two failover peers have wildly different clocks, refuse to start + doing failover. -- Fix a bug in UDP checksum code (thanks to John Nemeth for figuring - this out) and re-enable UDP checksumming. This allows the client - to work with some buggy DHCP servers that can't handle zero - checksums in the UDP header - in particular, the one John's cable - modem ISP is using. +- Fix a bug in the DNS update code that could cause core dumps when + running on alpha processors. -- Don't report packet header checksum errors unless we see a lot of - them. It's perfectly normal for some number of checksum errors to - occur. +- Fixed a bug in ddns updates for static lease entries, thanks to a + patch from Andrey M Linkevitch. -- Refer to the dhcpd.leases man page when printing an error message - prior to exiting because there's no lease database. +- Add support for Darwin/MacOS X -- Add information to the README telling the reader how to get to the - manual pages. +- Install omshell (including new documentation). -- Fix the server packet transmission code to unicast when it can. +- Support DNS updates in the client (this is a very obscure feature + that most DHCP client users probably will not be able to use). -- Fix a typo in the dhcpd.conf manual page. +- Somewhat cleaner status logging in the client. - CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 17 +- Make OMAPI key naming syntax compatible with the way keys are + actually named (key names are domain names). -- Fix a bug in the relay agent where messages to the client would be - unicast in the IP header but broadcast in the link header. The - Microsoft DHCP client would reject such packets, preventing it from - being configured. This was only a problem on non-socket-API - platforms. +- Fix a bug in the lease file writer. -- Do not attempt to reclaim requested abandoned leases in response to - DHCPDISCOVER messages. +- Install DHCP ISC headers in a different place than BIND 9 ISC + headers, to avoid causing trouble in BIND 9 builds. -- Allow the maximum lease time parameter in a host declaration to - override the maximum lease time parameter in a subnet declaration. +- Don't send updates for attributes on an object when the attributes + haven't changed. Support deleting attributes on remote objects. -- Better document the -p flag for dhclient, dhcrelay and dhcpd. +- Fix a number of bugs in omshell, and add the unset and refresh + statements. -- Apply John Wehle's patch to fix the endianness bug in the dlpi - packet filter on Solaris. +- Handle disconnects in OMAPI a little bit more intelligently (so that + the caller gets ECONNRESET instead of EINVAL). - CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 16 +- Fix a bunch of bugs in the handling of clients that have existing + leases when the try to renew their leases while failover is + operating. -- Fix linux man page install location. + Changes since 3.0 Release Candidate 6 -- Fix some confusion in the dhclient-script man page. +- Fix a core dump that could happen when processing a DHCPREQUEST from + a client that had a host declaration that contained both a + fixed-address declaration and a dhcp-client-identifier option + declaration, if the client identifier was longer than nine bytes. -- Fix error in includes/cf/linux.h that would have made network API - selections in site.h work incorrectly. +- Fix a memory leak that could happen in certain obscure cases when + using omapi to manipulate leases. -- Fix some major stupidity in the code that figures out where or not a - client owns a particular lease. +- Fix some bugs and omissions in omshell. - CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 15 -- Fix Makefile.conf on Linux to refer to /var/state/dhcp instead of - /var/state/dhcpd. + Changes since 3.0 Release Candidate 5 -- Eliminate redundant #defines in includes/cf/linux.h (for neatness). +- Fix a bug in omapi_object_dereference that prevented objects in + chains from having their reference counts decreased on dereference. -- Fix an obscure case where dhcpd is started by the /etc/rc system - with exactly the same pid each time, dhcpd.pid is not erased on - reboot, and therefore dhcpd would detect a server (itself) with the - pid in dhcpd.pid and decide that another server was running and - exit. +- Fix a bug in omapi_object_dereference that would prevent object + chains from being freed upon removal of the last reference external + to the chain. + +- Fix a number of other memory leaks in the OMAPI protocol subsystem. - CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 14 +- Add code in the OMAPI protocol handler to trace memory leakage. -- Install the dhcp databases in /var/state/dhcp instead of /etc or - /var/dhcpd, as suggested in the Linux Filesystem Hierarchy - Standard. +- Clean up the memory allocation/reference history printer. -- Fix an endianness bug in dlpi.c. As a consequence, make the - Solaris/i386 use dlpi again. +- Support input of dotted quads and colon-seperated hex lists as + attribute values in omshell. -- Fix a bunch of bugs in the Solaris client script. +- Fix a typo in the linux interface discovery code. -- Add some more information about Solaris to the README file. +- Conditionalize a piece of trace code that wasn't conditional. -- Adjust startup message in interface probe so that the relay agent - and client's unattached status will not trigger questions. + Changes since 3.0 Release Candidate 4 -- Update some error messages to provide more help to new users for - some common mistakes. +- Fix a bug that would prevent leases from being abandoned properly on + DHCPDECLINE. -- Create an interface alias on Solaris when setting up IP aliases, - rather than trying to do things the *BSD way. +- Fix failover peer OMAPI support. -- Fix a null pointer dereference bug (this time I went through the - whole function and audited it for more null pointer dereferences, - and I didn't find any, for what that's worth). +- In failover, correctly handle expiration of leases. Previously, + leases would never be reclaimed because they couldn't make the + transition from EXPIRED to FREE. -- Don't ever release leases in response to a DHCPDISCOVER (I think - this was unlikely anyway, but why not be correct?). +- Fix some broken failover state transitions. -- Remove the shared-network example from the sample dhcpd.conf file. +- Documentation fixes. -- Make ``make install'' make all first. +- Take out an unnecessary check in DHCP relay agent information option + stashing code that was preventing REBINDING clients from rebinding. - CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 13 +- Prevent failover peers from allocating leases in DHCPREQUEST + processing if the lease belongs to the other server. -- Support DESTDIR on installs. +- Record server version in lease file introductory comment. -- Fix a bug in dhcp.c where a store through a null pointer would - be made under some reasonably common circumstances. +- Correctly report connection errors in OMAPI and failover. -- Add test for ARPHRD_TUNNEL so that client and server do not fail on - versions of Linux running IPsec implementations or the like. +- Make authentication signature algorithm name comparisons in OMAPI + case-insensitive. -- Move tests for constants defined in O.S. headers into osdep.h - test - for HAVE_whatever in .c files. Define relevant HAVE_whatevers in - linux.h, so that versions of linux that define these constants as - enums will still work. +- Fix compile problem on SunOS 4.x - CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 12 +- If a signature algorithm is not termined with '.', terminate it so + that comparisons between fully-qualified names will work + consistently. -- Initialize the "quiet" variable in dhclient.c to zero (it was used - without first having been initialized). +- Different SIOCGIFCONF probe code, may "fix" problem on some Linux + systems with the probe not working correctly. -- Fix the parser code for the authoritative keyword. +- Don't allow user to type omapi key on command line of omshell. -- Adjust lease discovery code to NAK more aggressively for addresses - the server knows it owns. + Changes since 3.0 Release Candidate 3 -- Add several new messages for DHCPNAK. +- Do lease billing on startup in a way that I *think* will finally do + the billing correctly - the previous method could overbill as a + result of duplicate leases. - CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 11 +- Document OMAPI server objects. -- Use DLPI only on sparcs running Solaris, since it seems not to work - on i386 boxes running Solaris for reasons yet to be determined. + Changes since 3.0 Release Candidate 2 Patchlevel 1 -- In the client, close standard I/O descriptors when forking a daemon. +- Fix some problems in the DDNS update code. Thanks to Albert + Herranz for figuring out the main problem. -- Don't let large lease lengths wrap lease expiry times - just use - what fits into a TIME value. +- Fix some reference counting errors on host entries that were causing + core dumps. -- Fix a bug in the SIOCGIFCONF interface scanning code. +- Fix a byte-swap bug in the token ring code, thanks to Jochen + Friedrich. -- Fix a core dump in the interface scanner that crops up on Linux when - an interface is specified on the command line. +- Fix a bug in lease billing, thanks to Jonas Bulow. -- Don't use %D in strftime because egcs complains about it. + Changes since 3.0 Release Candidate 2 -- Print the error message if SO_BINDTODEVICE fails. +- Change the conditions under which a DHCPRELEASE is actually + committed to be consistent with lease binding states rather than + using the lease end time. THis may fix some problems with the + billing class code. - CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 10 +- Fix a bug where lease updates would fail on Digital Unix (and maybe + others) because malloc was called with a size of zero. -- Update top-level Makefile so that it exits correctly on errors in - submakes under bash/gnu make (dunno which is the culprit, and don't - really care). +- Fix a core dump that happens when the DHCP server can't create its + trace file. -- Print a more helpful message if no free BPF devices are found. + Changes since 3.0 Release Candidate 1 Patchlevel 1 -- Add support for specifying that the server is or is not - authoritative for a particular network segment. +- Fix the dhcp_failover_put_message to not attempt to allocate a + zero-length buffer. Some versions of malloc() fail if you try to + allocate a zero-length buffer, and this was causing problems on, + e.g., Digital Unix. -- Fix two stupid typos in lpf.c. +- Fix a case where the failover code was printing an error message + when no error had occurred. -- Print a more helpful message if we can't create an LPF socket or - can't attach a filter to it. +- Fix a problem where when a server went down and back up again, the + peer would not see a state transition and so would stay in the + non-communicating state. - CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 9 +- Be smart about going into recover_wait. -- Correct the hopelessly outdated information about Linux at the top - of the README - many apologies to the Linux people who have had to - read that nonsense for the past couple of snapshots and have been - confused or annoyed by it. I simply hadn't read it recently, and - didn't realize how out-of-date it was. +- Fix a problem in the failover implementation where peers would fail + to come into sync if interrupted in the RECOVER state. This could + have been the cause of some problems people have reported recently. -- Print a message if the client finds no broadcast interfaces to - configure. +- Fix a problem with billing classes where they would not be unbilled + when the client lease expired. -- Add support for use-lease-addr-for-default-route flag in server, so - that Windows machines can be made to ARP for all addresses. +- If select fails, figure out which descriptor is bad, and cut it out + of the I/O loop. This prevents a potentially nasty spin. I + haven't heard any report it in a while, but it came up consistently + in testing. -- Update README file to mention new Linux gotchas. +- Fix a bug in the relay agent where if you specified interfaces on + the command line, it would fail. -- After finally understanding Brian Murrel's code (my fault, not his) - to get interface names from /proc/net/dev on Linux, fix what I broke - of his code and document it. +- Fix a couple of small bugs in the omapi connection object (no known + user impact). -- Use sendto rather than send for SOCK_PACKET sockets, because they - can't be connected, only bound. :'( +- Add the missing 3.0 Beta 1 lease conversion script. -- Fix up SOCK_PACKET creation so that the kernel doesn't complain - about it. +- Read dhcp client script hooks if they exist, rather than only if + they're executable. -- Fix incorrect tests in linux client script: - [ $relmajor == 2 ] -> [ $relmajor -eq 2 ] + Changes since 3.0 Release Candidate 1 -- Make typedefs for u8, u16 and u32 types. These are Linux kernel - internal data types which are unfortunately exposed in the linux - packetfilter header file. +- Fix a memory smash that happens when fixed-address leases are used. + ANY SITE AT WHICH FIXED-ADDRESS STATEMENTS ARE BEING USED SHOULD + UPGRADE IMMEDIATELY. This has been a long-standing bug - thanks to + Alvise Nobile for discovering it and helping me to find it! -- Don't include <net/ethernet.h> in lpf.c - it defines things we're - already correctly defining elsewhere, and doesn't define any useful - new stuff. +- Fix a small bug in binary-to-ascii, thanks to H. Peter Anvin of + Transmeta. -- Finally fix client PREINIT bug that causes interfaces not specified - on the command line to be preinitialized. If no interfaces are - specified on the command line, all interfaces are still - preinitialized. +- There is a known problem with the DHCP server doing failover on + Compaq Alpha systems. This patchlevel is not a release candidate + because of this bug. The bug should be straightforward to fix, so + a new release candidate is expected shortly. - CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 8 +- There is a known problem in the DDNS update code that is probably a + bug, and is not, as far as we know, fixed in this patchlevel. -- Fix socket API fallback setup code, which was causing Linux servers - and clients to loop endlessly on select when run as daemons. + Changes since 3.0 Beta 2 Patchlevel 24 -- Add support for Linux 2.2 version number (treated the same as Linux - 2.1, for now). +- Went over problematic failover state transitions and made them all + work, so that failover should now much less fragile. -- Correct apparent error in DHCPREQUEST destination address handling - when in INIT-REBOOT state. +- Add some dhcpctl and omapi documentation -- Do not set BROADCAST flag if we have a valid IP address. +- Fix compile errors when compiling with unusual predefines. -- Remove hard-coded filenames and use system-specific manifest - constants. +- Make Token Ring work on Linux 2.4 -- Add entry and exit hooks to Linux dhclient-script (should be added - to all operating systems once tested). +- Fix the Digital Unix BPF_WORDALIGN bug. -- Test for linux major and minor version so as to correctly invoke - network configuration programs. +- Fix some dhcp client documentation errors. -- Add support for Linux's gratuitous name change of bpf_insn structure - (can't pollute precious Linux sources with the "Berkeley" word, I - guess. +- Update some parts of the README file. -- Correct USE_BPF_{SEND,RECEIVE} ifdefs for if_reinitialize_* - functions. +- Support GCC on SCO. -- Ensure that we have ifreq structure before initializing interface - - if an interface was specified on the command line on Linux, this was - not the case. + Changes since 3.0 Beta 2 Patchlevel 23 -- Get rid of references to enstamp structure in lpf.c. Correctly - declare and initialize sock_fprog structure (aka bpf_filter - structure on non-Linux machines). +- Fix a bug in the DNS update code where a status code was not being + checked. This may have been causing core dumps. -- Define ssize_t on Ultrix. +- When parsing the lease file, if a lease declaration includes a + billing class statement, and the lease already has a billing class, + unbill the old class. - CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 7 +- When processing failover transactions, where acks will be deferred, + process the state transition immediately. -- Generalize FDDI support. +- Don't try to use the new SIOCGIFCONF buffer size detection code on + Linux 2.0, which doesn't provide this functionality. -- Fix potential core dump in interface discovery code. +- Apply a patch suggested by Tuan Uong for a problem in dlpi.c. -- Put explicit release versions on startup messages. +- Fix a problem in using the which command in the configure script. - CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 6 +- Fix a parse error in the client when setting up an omapi listener. -- Add support for Linux Packet Filter (thanks to Brian Murrell, Interlinx). +- Document the -n and -g flags to the client. -- Add support for FDDI hardware type. +- Make sure there is always a stdin and stdout on startup. This + prevents shell scripts from accidentally writing error messages into + configuration files that happen to be opened as stderr. -- Fix a long-standing bug in DLPI support where the ethertype was - being set incorrectly (thanks to Gong Wei, CCENet). +- If an interface is removed, the client will now notice that it is + gone rather than spinning. This has only been tested on NetBSD. -- Don't use DLPI RAW mode on Solaris. +- The client will attempt to get an address even if it can't create a + lease file. -- In the client, when a lease expires, the interface to which that - lease is attached is unconfigured. On systems that use the socket - API, the interface needs to then be reconfigured with the 0.0.0.0 - address so that it can be used to get a new address. +- Don't overwrite tracefiles. -- Add fallback support for Linux. This fixes a problem with the - relay agent when relaying over non-broadcast links, and may also fix - some obscure problems with unicasting DHCPACKs in both the server and - relay agent. +- Fix some memory allocation bugs in failover. -- When allocating leases, if the oldest lease is abandoned, try to - find a younger-but-still-expired lease rather than reclaiming the - abandoned lease. + Changes since 3.0 Beta 2 Patchlevel 22 -- Add more documentation to README. +- Apply some patches suggested by Cyrille Lefevre, who is maintaining + the FreeBSD ISC DHCP Distribution port. -- The absence of the /etc/dhclient.conf file is no longer considered - an error. +- Fix a core dump in DHCPRELEASE. -- The dhcp client's lease file name can be specified on the command - line. + Changes since 3.0 Beta 2 Patchlevel 21 -- The DHCP client should no longer zap interfaces that it has not been - directed to configure. +- This time for sure: fix the spin described in the changes for pl20. -- If a client starts up in the init-reboot state, the xid will be a - "random" number rather than always being zero, as was previously the - case. + Changes since 3.0 Beta 2 Patchlevel 20 -- In addition to comparing transaction IDs, compare hardware addresses - in response packets to verify that they are ours. +- Fix a problem with Linux detecting large numbers of interfaces (Ben) -- Rewrite the client lease database after 20 leases have been written. +- Fix a memory smash in the quotify code, which was introduced in + pl19. -- Fix the exponential backoff code. +- Actually fix the spin described in the changes for pl20. The + previous fix only partially fixed the problem - enough to get it + past the regression test. -- Add a Y2k comment to indicate that something suspicious-looking is - in fact _not_ a problem. + Changes since 3.0 Beta 2 Patchlevel 19 -- Use mkstemp if possible. +- Fix a bug that could cause the server to abort if compiled with + POINTER_DEBUG enabled. -- Add missing fi in various client scripts. +- Fix a bug that could cause the server to spin when responding to a + DHCPREQUEST. -- Use "search" instead of "domain" in linux resolv.conf files. +- Apply Joost Mulders' suggested patches for DLPI on x86. -- Specify a hop count in all route command on solaris. +- Support NUL characters in quoted strings. -- If an allocation fails, don't try to zero out the allocation buffer - we didn't get. +- Install unformatted man pages on SunOS. -- Support subnets that are subsets of other subnets - that is, for - example, 10.0.1.0/24 and 10.0.0.0/16. This is useful in fairly - obscure circumstances. + Changes since 3.0 Beta 2 Patchlevel 18 -- Don't set the lease end time if it's already expired. +- Allow the server to be placed in partner-down state using OMAPI. + (Damien Neil) -- Don't define INADDR_LOOPBACK on FreeBSD if it's already defined in a - system header. +- Implement omshell, which can be used to do arbitrary things to the + server (in theory). (Damien Neil) -- Use the broadcast address in the relay agent if we are using the BSD - socket API. +- Fix a case where if a client had two different leases the server could + actually dereference the second one when it hadn't been referenced, + leading to memory corruption and a core dump. (James Brister) -- Allow host declarations without names. +- Fix a case where a client could request the address of another client's + lease, but find_lease wouldn't detect that the other client had it, and + would attempt to allocate it to the client, resulting in a lease conflict + message. -- Allow the server identifier option to be specified. +- Fix a case where a client with more than one client identifier could be + given a lease where the hardware address was correct but the client + identifier was not, resulting in a lease conflict message. -- Don't dump hostnames into the lease file if they contain - non-printable characters. +- Fix a problem where the server could write out a colon-seperated + hex list as a value for a variable, which would then not parse. + The fix is to always write strings as quoted strings, with any + non-printable characters quoted as octal escape sequences. So + a file written the old way still won't work, but new files written + this way will work. -- Copy the entire client hardware address buffer that the client sends - to the output packet, not just the portion of it that's supposedly - significant according to the hardware address length field. This - is done for the benefit of certain Microsoft clients. +- Fix documentation for sending non-standard options. -- Don't send a second ICMP echo request if we receive two DHCPDISCOVER - messages in quick succession. This prevents a rather annoying - timing race in configuring some Win95 clients. +- Use unparsable names for unknown options. WARNING: this will + break any configuration files that use the option-nnn convention. + If you want to continue to use this convention for some options, + please be sure to write a definition, like this: -- Fix up dhcp-options man page to make it more readable. Note that - netbios-name-server is the same thing as WINS. + option option-nnn code nnn = string; - CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 5 + You can use a descriptive name instead of option-nnn if you like. -- Define some extra DLPI support flags that make DLPI work much better - on Solaris. +- Fix a problem where we would see a DHCPDISCOVER/DHCPOFFER/ + DHCPREQUEST/DHCPACK/DHCPREQUEST/DHCPNAK sequence. This was the + result of a deceptively silly bug in supersede_lease. -- Fix inet_aton prototype/declaration to match Internet Software - Consortium BIND distribution. +- Fix client script exit status check, according to a fix supplied by + Hermann Lauer. -- Document new server-identifier functionality. +- Fix an endianness bug in the tracefile support, regarding ICMP + messages. - CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 4 +- Fix a bug in the client where the medium would not work correctly if + it contained quoted strings. -- Do not use -Wstrict-prototypes on Solaris with gcc - if the Internet - Software Consortium BIND distribution is not installed, this produces - errors. + ** there was no pl17 ** -- Actually use the new DLPI support on Solaris - although the code was - added in Patchlevel 2, it wasn't enabled (blush). + Changes since 3.0 Beta 2 Patchlevel 16 -- Fix a prototype bug that's exposed when DLPI support is enabled on +- Add support for transaction tracing. This allows the state of the + DHCP server on startup, and all the subsequent transactions, to be + recorded in a file which can then be played back to reproduce the + behaviour of the DHCP server. This can be used to quickly + reproduce bugs that cause core dumps or corruption, and also for + tracking down memory leaks. + +- Incorporate some bug fixes provided by Joost Mulders for the DLPI + package which should clear up problems people have been seeing on Solaris. - CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 3 +- Fix bugs in the handling of options stored as linked lists (agent + options, fqdn options and nwip options) that could cause memory + corruption and core dumps. -- Fix a makefile botch that prevents the DHCP Distribution from - from compiling on Solaris with gcc. Sigh. +- Fix a bug in DHCPREQUEST handling that resulted in DHCPNAK messages + not being send in some cases when they were needed. - CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 2 +- Make the lease structure somewhat more compact. -- Allow server-identifier in any scope. Use in-scope server - identifier option rather than the default, if one exists. +- Make initial failover startup *much* faster. This was researched + and implemented by Damien Neil. -- Delete newlines from abandoned lease reclaimation warning. +- Add a --version flag to all executables, which prints the program + name and version to standard output. -- Only release other applicable leases held by a client when the - client sends a DHCPREQUEST. +- Don't rewrite the lease file every thousand leases. -- Fix core dump when find_lease didn't find a lease. +- A bug in nit.c for older SunOS machines was fixed by a patch sent in + by Takeshi Hagiwara. -- Update dhcpd.leases man page. +- Fix a memory corruption bug in the DHCP client. - CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 1 +- Lots of documentation updates. -- Use -Wno-char-subscript on Solaris to prevent bogus warnings from - gcc on Solaris 2.6. +- Add a feature allowing environment variables to be passed to the + DHCP client script on the DHCP client command line. -- Add support for Apple's new Rhapsody operating system. +- Fix client medium support, which had been broken for some time. -- Use DLPI on Solaris instead of using the BSD Sockets API. +- Fix a bug in the DHCP client initial startup backoff interval, which + would cause two DHCPDISCOVERS to be sent back-to-back on startup. -- Fix two network input buffer overflow problems which could allow an - attacker to pervert the stack. -- Fix an ancient typo that could theoretically cause memory - corruption. + Changes since 3.0 Beta 2 Patchlevel 15 -- Sort abandoned leases in at current time rather than end of time. - This allows abandoned leases to be reclaimed if there are no - available free leases. +- Some documentation tweaks. -- If a client explicitly requests a lease that's been abandoned, it's - probably the system that was answering pings on that address, so let it - have the lease. +- Maybe fix a problem in the DLPI code. -- Fix a bunch of type conversion errors that are flagged by the Solaris - C compiler. +- Fix some error code space inconsistencies in ddns update code. - CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 0 +- Support relay agents that intercept unicast DHCP messages to stuff + agent options into them. -- Fix two potential buffer overflow problems. +- Fix a small memory leak in the relay agent option support code. -- Differentiate between versions of Linux for better success in - compiling. +- Fix a core dump that would occur if a packet was sent with no + options. -- Fix bug in linux client script regarding routing setup. + Changes since 3.0 Beta 2 Patchlevel 14 -- Clarify socket API error message on multiple interfaces. +- Finish fixing a long-standing bug in the agent options code. This + was causing core dumps and failing to operate correctly - in + particular, agent option stashing wasn't working. Agent option + stashing should now be working, meaning that agent options can be + used in class statements to control address allocation. -- Fix broken comparison that was setting IP source address to zero. +- Fix up documentation. -- Reclaim abandoned leases if we run out of free leases. +- Fix a couple of small memory leaks that would have added up + significantly in a high-demand situation. - CHANGES FROM THE DECEMBER 2, 1997 SNAPSHOT +- Add a log-facility configuration parameter. -- Use %ld to print pid_t and cast pid_t values to long to avoid - inconsistent declarations between different POSIX flavours. +- Fix a compile error on some older operating systems. -- Add support for ARPHRD_IEEE802 (token ring) hardware type. +- Add the ability in the client to execute certain statements before + transmitting packets to the server. Handy for debugging; not much + practical use otherwise. -- If we own an address and a client requests it, but we can't assign - it to that client, we now NAK it so that the client doesn't try to - reuse it. +- Don't send faked-out giaddr when renewing or bound - again, useful + for debugging. - CHANGES FROM THE JUNE SNAPSHOT + Changes since 3.0 Beta 2 Patchlevel 13 -- Support for NeXTstep 3.x and 4.x +- Fixed a problem where the fqdn decoder would sometimes try to store + an option with an (unsigned) negative length, resulting in a core + dump on some systems. -- Added man pages for dhcpd.leases, dhclient-script, dhclient.leases - and dhclient.conf. Move general documentation of DHCP options into - a seperate man page which is referred to by the dhclient.conf and - dhcpd.conf man pages. +- Work around the Win98 DHCP client, which NUL-terminates the FQDN + option. -- Updated README to answer some frequently asked questions. +- Work around Win98 and Win2k clients that will claim they want to do + the update even when they don't have any way to do it. -- Fixed a bug in command-line interface specification in dhclient - it - was formerly not possible to specify that only certain interfaces be - configured. +- Fix some log messages that can be printed when failover is operating + that were not printing enough information. -- Do not leave client scripts lying around in /tmp after they've been - used unless the -D flag is specified. +- It was possible for a DHCPDISCOVER to get an allocation even when + the state machine said the server shouldn't be responding. -- Add a new, non-standard, not-guaranteed-to-stay-the-same system - configuration status message server which can be used to trigger the - client to recheck its address, e.g., after a laptop has been put to - sleep and then awakened (this has yet to be documented). +- Don't load balance DHCPREQUESTs from clients in RENEWING and + REBINDING, since in RENEWING, if we heard it, it's for us, and in + REBINDING, the client wouldn't have got to REBINDING if its primary + were answering. -- Fix handling of media selection in the REBOOT phase - previously the - media type would not be remembered, which could cause severe delays - in reacquiring an address if the default media type was wrong. +- When we get a bogus state lease binding state transition, don't do + the transition. + -- Allocate space for a NUL terminator on the end of client options - - this was previously overlooked, and could cause garbage characters - to be written to the temporary client script files. + Changes since 3.0 Beta 2 Patchlevel 12 -- Use mkstemp if it's available. +- Fixed a couple of silly compile errors. -- Supply network number and broadcast address to the client script so - that on systems that need these values, they don't need to be - computed with an awk script. + Changes since 3.0 Beta 2 Patchlevel 11 -- Keep a PID file for the client and the relay agent, and have the - relay agent background itself by default. +- Albert Herranz tracked down and fixed a subtle bug in the base64 + decoder that would prevent any key with an 'x' in its base64 + representation from working correctly. -- Add client script for bsd/os, fix many niggling bugs in existing - client scripts and add support for static routing tables to all bsd - scripts. +- Thanks to Chris Cheney and Michael Sanders, we have a fix for the + hang that they both spotted in the DHCP server - when + one-lease-per-client was set, the code to release the "other" lease + could spin. -- Add a -q option to the client, server and relay agent so that they - can be started from /etc/rc scripts without spewing a bunch of - garbage on the console. By default, all three daemons still print - startup messages, since these are helpful in bug reporting. +- Fix a problem with alignment of the input buffer in bpf in cases + where two packets arrive in the same bpf read. -- Don't print anything to stderr or stdout after going into - background. +- Fix a problem where the relay agent would crash if you specified an + interface name on the command line. -- Fix bug where hostname keyword was not being recognized in - dhcpd.leases file, resulting in the loss of lease database entries. +- Add the ability to conditionalize client behaviour based on the + client state. -- Fix problem on some operating systems where zero-length ifreq - structures were being offset incorrectly when scanning the interface - list on startup. +- Add support for the FQDN option, and added support for a new way of + doing ddns updates (ddns update style interim) that allows more than + one DHCP server to update the DNS for the same network(s). This + was implemented by Damien Neil with some additional functionality + added by Ted Lemon. -- Unless a BOOTP client requests it, never send more than 64 bytes of - options. +- Damien added a "log" statement, so that the configuration file can + be made to log debugging information and other information. + +- Fixed a bug that caused option buffers not to be terminated with an + end option. + +- Fixed a long-standing bug in the support for option spaces where the + options are stored as an ordered list rather than in a hash table, + which could theoretically result in memory pool corruption. + +- Prevent hardware declarations with no actual hardware address from + being written as something unparsable, and behave correctly in the + face of a null hardware address on input. + +- Allow key names to be FQDNs, and qualify the algorithm name if it is + specified unqualified. + +- Modify the DDNS update code so that it never prints the "resolver + failed" message, but instead says *why* the resolver failed. + +- Officially support the subnet selection option, which now has an + RFC. + +- Fix a build bug on MacOS X. + +- Allow administrator to disable ping checking. + +- Clean up dhcpd.conf documentation and add more information about how + it works. + + Changes since 3.0 Beta 2 Patchlevel 10 + +- Fix a bug introduced during debugging (!) and accidentally committed + to CVS. + + Changes since 3.0 Beta 2 Patchlevel 9 + +- Fix DHCP client handling of vendor encapsulated options. + +- Fix a bug in the handling of relay agent information options introduced + in patchlevel 9. + +- Stash agent options on client leases by default, and use the stashed + options at renewal time. + +- Add the ability to test the client's binding state in the client + configuration language. + +- Fix a core dump in the DNS update code. + +- Fix some expression evaluation bugs that were causing updates to be + done when no client hostname was received. + +- Fix expression evaluation debugging printfs. + +- Teach pretty_print_option to print options in option spaces other than + the DHCP option space. + +- Add a warning message if the RHS of a not is not boolean. + +- Never select for more than a day, because some implementations of + select will just fail if the timeout is too long (!). + +- Fix a case where a DHCPDISCOVER from an unknown network would be + silently dropped. + +- Fix a bug where if a client requested an IP address for which a different + client had the lease, the DHCP server would reallocate it anyway. + +- Fix the DNS update code so that if the client changes its name, the DNS + will be correctly updated. + + Changes since 3.0 Beta 2 Patchlevel 8 + +- Oops, there was another subtle math error in the header-length + bounds-checking. + + Changes since 3.0 Beta 2 Patchlevel 7 + +- Oops, forgot to byte-swap udp header length before bounds-checking it. + + Changes since 3.0 Beta 2 Patchlevel 6 -- Don't ping static leases, since we don't have a lease structure on - the heap to work with later. +- Fix a possible DoS attack where a client could cause the checksummer + to dump core. This was a read, not a write, so it shouldn't be + possible to exploit it any further than that. -- Fixed a compile problem on Solaris 2.6. +- Implement client- and server-side support for using the Client FQDN + option. -- Support interface aliases on Solaris. +- Support for other option spaces in the client has been added. This + means that it is now possible to define a vendor option space on the + client, request options in that space from the server (which must + define the same option space), and then use those options in the + client. This also allows NWIP and Client FQDN options to be used + meaningfully. -- Print day and month with leading zero in lease files if less than - ten, for easier parsing by perl/sed/awk scripts. +- Add object initializer support. This means that objects can now be + initialized to something other than all-zeros when allocated, which + makes, e.g., the interface object support code a little more robust. -- Never make the lease database world writable, even if dhcpd is - invoked with a bogus umask. +- Fix an off-by-one bug in the host stuffer. This was causing host + deletes not the work, and may also have been causing OMAPI + connections to get dropped. Thanks to James Brister for tracking + this one down! -- Fix DHCPRELEASE handling (before, addressed would never be - released.) +- Fixed a core dump in the interface discovery code that is triggered + when there is no subnet declaration for an interface, but the server + decides to continue running. Thanks to Shane Kerr for tracking + down and fixing this problem. -- If there is more than one lease for a particular client on a - particular network, find the lease the client is asking for so as to - avoid a cycle of NAKs. + Changes since 3.0 Beta 2 Patchlevel 5 -- If a BOOTP request is received from a particular client and that - client has previously received a DHCP address, make sure that we - still find a valid BOOTP lease so that we don't cycle through - addresses. +- Fix a bug in the recent enhancement to the interface discovery code + to support arbitrary-length interface lists. -- Remove server-identifier option from documentation, other than to - document that it has been deprecated. +- Support NUL-terminated DHCP options when initializing client-script + environment. -- Don't give up if we get an EINTR or EAGAIN while polling or - selecting - these return statuses can occur spuriously without - indicating a fatal problem. +- Fix suffix operator. + +- Fix NetWare/IP option parsing. + +- Better error/status checking in dhcpctl initialization and omapi + connection code. + +- Fix a potential memory smash in dhcpctl code. + +- Fix SunOS4 and (maybe) Ultrix builds. + +- Fix a bug where a certain sort of incoming packet could cause a core + dump on Solaris (and probably elsewhere). + +- Add some more safety checks in error logging code. + +- Add support for ISC_R_INCOMPLETE in OMAPI protocol connection code. + +- Fix relay agent so that if an interface is specified on the command + line, the relay agent does not dump core. + +- Fix class matching so that match if can be combined with match or + spawn with. + +- Do not allow spurious leases in the lease database to introduce + potentially bogus leases into the in-memory database. + +- Fix a byte-order problem in the client hardware address type code + for OMAPI. + +- Be slightly less picky about what sort of hardware addresses OMAPI + can install in host declarations. + + Changes since 3.0 Beta 2 Patchlevel 4 + +- Incorporated Peter Marschall's proposed change to array/record + parsing, which allows things like the slp-agent option to be encoded + correctly. Thanks very much to Peter for taking the initiative to + do this, and for doing such a careful job of it (e.g., updating the + comments)! + +- Added an encoding for the slp-agent option. :') + +- Fixed SunOS 4 build. Thanks to Robert Elz for responding to my + request for help on this with patches! + +- Incorporated a change that should fix a problem reported by Philippe + Jumelle where when the network connection between two servers is + lost, they never reconnect. + +- Fix client script files other than that for NetBSD to actually use + make_resolv_conf as documented in the manual page. + +- Fix a bug in the packet handling code that could result in a core + dump. + +- Fix a bug in the bootp code where responses on the local net would + be sent to the wrong MAC address. Thanks to Jerry Schave for + catching this one. + + Changes since 3.0 Beta 2 Patchlevel 3 + +- In the DHCP client, execute client statements prior to using the values + of options, so that the client configuration can overried, e.g., the + lease renewal time. + +- Fix a reference counting error that would result in very reproducible + failures in updates, as well as occasional core dumps, if a zone was + declared without a key. + +- Fix some Linux 2.0 compilation problems. + +- Fix a bug in scope evaluation during execution of "on" statements that + caused values not to be recorded on leases. + +- If the dhcp-max-message-size option is specified in scope, and the + client didn't send this option, use the one specified in scope to + determine the maximum size of the response. + + Changes since 3.0 Beta 2 Patchlevel 2 + +- Fix a case where spawning subclasses were being allocated + incorrectly, resulting in a core dump. + +- Fix a case where the DHCP server might inappropriately NAK a + RENEWING client. + +- Fix a place dhcprequest() where static leases could leak. + +- Include memory.h in omapip_p.h so that we don't get warnings about + using memcmp(). + + Changes since 3.0 Beta 2 Patchlevel 1 + +- Notice when SIOCFIGCONF returns more data than fit in the buffer - + allocate a larger buffer, and retry. Thanks to Greg Fausak for + pointing this out. + +- In the server, if no interfaces were configured, report an error and + exit. -- Do not select for exceptions, since we don't handle them. This was - causing massive CPU consumption on some systems. +- Don't ever record a state of 'startup'. -- When a DHCP client has been assigned a fixed address but had - previously had a lease, it will request the old leased address. In - such an event, send a DHCPNAK so that it will discover its new - static binding. +- Don't try to evaluate the local failover binding address if none was + specified. Thanks to Joseph Breu for finding this. diff --git a/contrib/isc-dhcp/client/Makefile.dist b/contrib/isc-dhcp/client/Makefile.dist index 2b261a7..a1f8a38 100644 --- a/contrib/isc-dhcp/client/Makefile.dist +++ b/contrib/isc-dhcp/client/Makefile.dist @@ -1,33 +1,20 @@ # Makefile.dist # -# Copyright (c) 1996, 1997, 1999 The Internet Software Consortium. -# All rights reserved. +# Copyright (c) 1996-1999 Internet Software Consortium. +# Use is subject to license terms which appear in the file named +# ISC-LICENSE that should have accompanied this file when you +# received it. If a file named ISC-LICENSE did not accompany this +# file, or you are not sure the one you have is correct, you may +# obtain an applicable copy of the license at: # -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: +# http://www.isc.org/isc-license-1.0.html. # -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# 3. Neither the name of The Internet Software Consortium nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. +# This file is part of the ISC DHCP distribution. The documentation +# associated with this file is listed in the file DOCUMENTATION, +# included in the top-level directory of this release. # -# THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND -# CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, -# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -# THE INTERNET SOFTWARE CONSORTIUM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED -# OF THE POSSIBILITY OF SUCH DAMAGE. +# Support and other services are available for ISC products - see +# http://www.isc.org for more information. # CATMANPAGES = dhclient.cat8 dhclient.conf.cat5 dhclient-script.cat8 \ @@ -39,9 +26,8 @@ OBJS = dhclient.o clparse.o PROG = dhclient MAN = dhclient.8 dhclient.conf.5 dhclient-script.8 dhclient.leases.5 -DEBUG = -g -INCLUDES = -I.. -I../includes -DHCPLIB = ../common/libdhcp.a +INCLUDES = -I$(TOP) $(BINDINC) -I$(TOP)/includes +DHCPLIB = ../common/libdhcp.a $(BINDLIB) ../omapip/libomapi.a ../dst/libdst.a CFLAGS = $(DEBUG) $(PREDEFINES) $(INCLUDES) $(COPTS) \ -DCLIENT_PATH=${CLIENT_PATH} @@ -64,8 +50,9 @@ install: all if [ x$(SCRIPT) = xnone ]; then \ echo "No client script available."; \ else \ - $(INSTALL) scripts/$(SCRIPT) $(DESTDIR)$(ETC)/dhclient-script; \ - $(CHMOD) 700 $(DESTDIR)$(ETC)/dhclient-script; \ + $(INSTALL) $(TOP)/client/scripts/$(SCRIPT)\ + $(DESTDIR)$(CLIENTBINDIR)/dhclient-script; \ + $(CHMOD) 700 $(DESTDIR)$(CLIENTBINDIR)/dhclient-script; \ fi $(MANINSTALL) $(MANFROM) dhclient.$(MANCAT)8 $(MANTO) \ $(DESTDIR)$(ADMMANDIR)/dhclient$(ADMMANEXT) @@ -76,15 +63,26 @@ install: all $(MANINSTALL) $(MANFROM) dhclient.leases.$(MANCAT)5 $(MANTO) \ $(DESTDIR)$(FFMANDIR)/dhclient.leases$(FFMANEXT) +depend: + $(MKDEP) $(INCLUDES) $(PREDEFINES) $(SRCS) + clean: -rm -f $(OBJS) - + realclean: clean -rm -f $(PROG) $(CATMANPAGES) $(SEDMANPAGES) *~ #* distclean: realclean -rm -f Makefile +links: + @for foo in $(SRCS) $(MAN); do \ + if [ ! -b $$foo ]; then \ + rm -f $$foo; \ + fi; \ + ln -s $(TOP)/client/$$foo $$foo; \ + done + # These should only be done on 4.4 BSD-based systems, since the mandoc # macros aren't available on older unices. Catted man pages are # provided in the distribution so that this doesn't become a problem. @@ -94,6 +92,7 @@ dhclient.cat8: dhclient.man8 dhclient.man8: dhclient.8 sed -e "s#ETCDIR#$(ETC)#g" -e "s#DBDIR#$(VARDB)#g" \ + -e "s#CLIENTBINDIR#$(CLIENTBINDIR)#g" \ -e "s#RUNDIR#$(VARRUN)#g" < dhclient.8 >dhclient.man8 dhclient-script.cat8: dhclient-script.man8 @@ -101,11 +100,13 @@ dhclient-script.cat8: dhclient-script.man8 dhclient-script.man8: dhclient-script.8 sed -e "s#ETCDIR#$(ETC)#g" -e "s#DBDIR#$(VARDB)#g" \ + -e "s#CLIENTBINDIR#$(CLIENTBINDIR)#g" \ -e "s#RUNDIR#$(VARRUN)#g" < dhclient-script.8 \ >dhclient-script.man8 dhclient.conf.man5: dhclient.conf.5 sed -e "s#ETCDIR#$(ETC)#g" -e "s#DBDIR#$(VARDB)#g" \ + -e "s#CLIENTBINDIR#$(CLIENTBINDIR)#g" \ -e "s#RUNDIR#$(VARRUN)#g" < dhclient.conf.5 \ >dhclient.conf.man5 @@ -114,24 +115,15 @@ dhclient.conf.cat5: dhclient.conf.man5 dhclient.leases.man5: dhclient.leases.5 sed -e "s#ETCDIR#$(ETC)#g" -e "s#DBDIR#$(VARDB)#g" \ + -e "s#CLIENTBINDIR#$(CLIENTBINDIR)#g" \ -e "s#RUNDIR#$(VARRUN)#g" < dhclient.leases.5 \ >dhclient.leases.man5 dhclient.leases.cat5: dhclient.leases.man5 nroff -man dhclient.leases.man5 >dhclient.leases.cat5 + dhclient: $(OBJS) $(DHCPLIB) $(CC) $(LFLAGS) -o $(PROG) $(OBJS) $(DHCPLIB) $(LIBS) # Dependencies (semi-automatically-generated) - -dhclient.o: dhclient.c ../includes/dhcpd.h \ - ../includes/cdefs.h ../includes/osdep.h ../includes/site.h \ - ../includes/cf/netbsd.h ../includes/dhcp.h \ - ../includes/tree.h ../includes/hash.h ../includes/inet.h \ - ../includes/sysconf.h ../includes/version.h -clparse.o: clparse.c ../includes/dhcpd.h \ - ../includes/cdefs.h ../includes/osdep.h ../includes/site.h \ - ../includes/cf/netbsd.h ../includes/dhcp.h \ - ../includes/tree.h ../includes/hash.h ../includes/inet.h \ - ../includes/sysconf.h ../includes/dhctoken.h diff --git a/contrib/isc-dhcp/client/clparse.c b/contrib/isc-dhcp/client/clparse.c index 9af7744..7cd8529 100644 --- a/contrib/isc-dhcp/client/clparse.c +++ b/contrib/isc-dhcp/client/clparse.c @@ -3,7 +3,7 @@ Parser for dhclient config and lease files... */ /* - * Copyright (c) 1997 The Internet Software Consortium. + * Copyright (c) 1996-2001 Internet Software Consortium. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,41 +34,49 @@ * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium - * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie - * Enterprises. To learn more about the Internet Software Consortium, - * see ``http://www.vix.com/isc''. To learn more about Vixie - * Enterprises, see ``http://www.vix.com''. + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. */ #ifndef lint static char copyright[] = -"$Id: clparse.c,v 1.13.2.5 2000/07/20 05:06:40 mellon Exp $ Copyright (c) 1997 The Internet Software Consortium. All rights reserved.\n"; +"$Id: clparse.c,v 1.62.2.1 2001/06/01 17:26:44 mellon Exp $ Copyright (c) 1996-2001 The Internet Software Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" -#include "dhctoken.h" -struct client_config top_level_config; +static TIME parsed_time; -char client_script_name [] = "/etc/dhclient-script"; +struct client_config top_level_config; -/* client-conf-file :== client-declarations EOF +u_int32_t default_requested_options [] = { + DHO_SUBNET_MASK, + DHO_BROADCAST_ADDRESS, + DHO_TIME_OFFSET, + DHO_ROUTERS, + DHO_DOMAIN_NAME, + DHO_DOMAIN_NAME_SERVERS, + DHO_HOST_NAME, + 0 +}; + +/* client-conf-file :== client-declarations END_OF_FILE client-declarations :== <nil> | client-declaration | client-declarations client-declaration */ -int read_client_conf () +isc_result_t read_client_conf () { - FILE *cfile; - char *val; - int token; struct client_config *config; + struct client_state *state; struct interface_info *ip; - - new_parse (path_dhclient_conf); + isc_result_t status; /* Set up the initial dhcp option universe. */ - initialize_universes (); + initialize_common_option_spaces (); /* Initialize the top level client configuration. */ memset (&top_level_config, 0, sizeof top_level_config); @@ -80,98 +88,138 @@ int read_client_conf () top_level_config.retry_interval = 300; top_level_config.backoff_cutoff = 15; top_level_config.initial_interval = 3; - top_level_config.bootp_policy = ACCEPT; - top_level_config.script_name = client_script_name; - top_level_config.requested_options - [top_level_config.requested_option_count++] = - DHO_SUBNET_MASK; - top_level_config.requested_options - [top_level_config.requested_option_count++] = - DHO_BROADCAST_ADDRESS; - top_level_config.requested_options - [top_level_config.requested_option_count++] = - DHO_TIME_OFFSET; - top_level_config.requested_options - [top_level_config.requested_option_count++] = - DHO_ROUTERS; - top_level_config.requested_options - [top_level_config.requested_option_count++] = - DHO_DOMAIN_NAME; - top_level_config.requested_options - [top_level_config.requested_option_count++] = - DHO_DOMAIN_NAME_SERVERS; - top_level_config.requested_options - [top_level_config.requested_option_count++] = - DHO_HOST_NAME; - - if ((cfile = fopen (path_dhclient_conf, "r")) != NULL) { + top_level_config.bootp_policy = P_ACCEPT; + top_level_config.script_name = path_dhclient_script; + top_level_config.requested_options = default_requested_options; + top_level_config.omapi_port = -1; + + group_allocate (&top_level_config.on_receipt, MDL); + if (!top_level_config.on_receipt) + log_fatal ("no memory for top-level on_receipt group"); + + group_allocate (&top_level_config.on_transmission, MDL); + if (!top_level_config.on_transmission) + log_fatal ("no memory for top-level on_transmission group"); + + status = read_client_conf_file (path_dhclient_conf, + (struct interface_info *)0, + &top_level_config); + if (status != ISC_R_SUCCESS) { + ; +#ifdef LATER + /* Set up the standard name service updater routine. */ + parse = (struct parse *)0; + status = new_parse (&parse, -1, default_client_config, + (sizeof default_client_config) - 1, + "default client configuration", 0); + if (status != ISC_R_SUCCESS) + log_fatal ("can't begin default client config!"); + do { - token = peek_token (&val, cfile); - if (token == EOF) + token = peek_token (&val, (unsigned *)0, cfile); + if (token == END_OF_FILE) break; parse_client_statement (cfile, (struct interface_info *)0, &top_level_config); } while (1); - token = next_token (&val, cfile); /* Clear the peek buffer */ - fclose (cfile); + end_parse (&parse); +#endif } /* Set up state and config structures for clients that don't - have per-interface configuration declarations. */ + have per-interface configuration statements. */ config = (struct client_config *)0; for (ip = interfaces; ip; ip = ip -> next) { if (!ip -> client) { ip -> client = (struct client_state *) - malloc (sizeof (struct client_state)); + dmalloc (sizeof (struct client_state), MDL); if (!ip -> client) - error ("no memory for client state."); + log_fatal ("no memory for client state."); memset (ip -> client, 0, sizeof *(ip -> client)); + ip -> client -> interface = ip; } + if (!ip -> client -> config) { if (!config) { config = (struct client_config *) - malloc (sizeof (struct client_config)); + dmalloc (sizeof (struct client_config), + MDL); if (!config) - error ("no memory for client config."); + log_fatal ("no memory for client config."); memcpy (config, &top_level_config, sizeof top_level_config); } ip -> client -> config = config; } } + return status; +} + +int read_client_conf_file (const char *name, struct interface_info *ip, + struct client_config *client) +{ + int file; + struct parse *cfile; + const char *val; + int token; + isc_result_t status; + + if ((file = open (name, O_RDONLY)) < 0) + return uerr2isc (errno); + + cfile = (struct parse *)0; + new_parse (&cfile, file, (char *)0, 0, path_dhclient_conf, 0); - return !warnings_occurred; + do { + token = peek_token (&val, (unsigned *)0, cfile); + if (token == END_OF_FILE) + break; + parse_client_statement (cfile, ip, client); + } while (1); + token = next_token (&val, (unsigned *)0, cfile); + status = (cfile -> warnings_occurred + ? ISC_R_BADPARSE + : ISC_R_SUCCESS); + close (file); + end_parse (&cfile); + return status; } -/* lease-file :== client-lease-statements EOF + +/* lease-file :== client-lease-statements END_OF_FILE client-lease-statements :== <nil> | client-lease-statements LEASE client-lease-statement */ void read_client_leases () { - FILE *cfile; - char *val; + int file; + struct parse *cfile; + const char *val; int token; - new_parse (path_dhclient_db); - /* Open the lease file. If we can't open it, just return - we can safely trust the server to remember our state. */ - if ((cfile = fopen (path_dhclient_db, "r")) == NULL) + if ((file = open (path_dhclient_db, O_RDONLY)) < 0) return; + cfile = (struct parse *)0; + new_parse (&cfile, file, (char *)0, 0, path_dhclient_db, 0); + do { - token = next_token (&val, cfile); - if (token == EOF) + token = next_token (&val, (unsigned *)0, cfile); + if (token == END_OF_FILE) break; if (token != LEASE) { - warn ("Corrupt lease file - possible data loss!"); + log_error ("Corrupt lease file - possible data loss!"); skip_to_semi (cfile); break; } else parse_client_lease_statement (cfile, 0); } while (1); + + close (file); + end_parse (&cfile); } /* client-declaration :== @@ -188,332 +236,569 @@ void read_client_leases () REBOOT number | SELECT_TIMEOUT number | SCRIPT string | + VENDOR_SPACE string | interface-declaration | LEASE client-lease-statement | - ALIAS client-lease-statement */ + ALIAS client-lease-statement | + KEY key-definition */ void parse_client_statement (cfile, ip, config) - FILE *cfile; + struct parse *cfile; struct interface_info *ip; struct client_config *config; { int token; - char *val; + const char *val; struct option *option; - - switch (next_token (&val, cfile)) { - case SEND: - parse_option_decl (cfile, &config -> send_options [0]); + struct executable_statement *stmt, **p; + enum statement_op op; + int lose; + char *name; + struct data_string key_id; + enum policy policy; + int known; + int tmp, i; + isc_result_t status; + + switch (peek_token (&val, (unsigned *)0, cfile)) { + case INCLUDE: + next_token (&val, (unsigned *)0, cfile); + token = next_token (&val, (unsigned *)0, cfile); + if (token != STRING) { + parse_warn (cfile, "filename string expected."); + skip_to_semi (cfile); + } else { + status = read_client_conf_file (val, ip, config); + if (status != ISC_R_SUCCESS) + parse_warn (cfile, "%s: bad parse.", val); + parse_semi (cfile); + } return; - - case DEFAULT: - option = parse_option_decl (cfile, &config -> defaults [0]); - if (option) - config -> default_actions [option -> code] = - ACTION_DEFAULT; + + case KEY: + next_token (&val, (unsigned *)0, cfile); + if (ip) { + /* This may seem arbitrary, but there's a reason for + doing it: the authentication key database is not + scoped. If we allow the user to declare a key other + than in the outer scope, the user is very likely to + believe that the key will only be used in that + scope. If the user only wants the key to be used on + one interface, because it's known that the other + interface may be connected to an insecure net and + the secret key is considered sensitive, we don't + want to lull them into believing they've gotten + their way. This is a bit contrived, but people + tend not to be entirely rational about security. */ + parse_warn (cfile, "key definition not allowed here."); + skip_to_semi (cfile); + break; + } + parse_key (cfile); return; - case SUPERSEDE: - option = parse_option_decl (cfile, &config -> defaults [0]); - if (option) - config -> default_actions [option -> code] = - ACTION_SUPERSEDE; + /* REQUIRE can either start a policy statement or a + comma-seperated list of names of required options. */ + case REQUIRE: + next_token (&val, (unsigned *)0, cfile); + token = peek_token (&val, (unsigned *)0, cfile); + if (token == AUTHENTICATION) { + policy = P_REQUIRE; + goto do_policy; + } + parse_option_list (cfile, &config -> required_options); return; - case APPEND: - option = parse_option_decl (cfile, &config -> defaults [0]); - if (option) - config -> default_actions [option -> code] = - ACTION_APPEND; - return; + case IGNORE: + next_token (&val, (unsigned *)0, cfile); + policy = P_IGNORE; + goto do_policy; + + case ACCEPT: + next_token (&val, (unsigned *)0, cfile); + policy = P_ACCEPT; + goto do_policy; + + case PREFER: + next_token (&val, (unsigned *)0, cfile); + policy = P_PREFER; + goto do_policy; + + case DONT: + next_token (&val, (unsigned *)0, cfile); + policy = P_DONT; + goto do_policy; + + do_policy: + token = next_token (&val, (unsigned *)0, cfile); + if (token == AUTHENTICATION) { + if (policy != P_PREFER && + policy != P_REQUIRE && + policy != P_DONT) { + parse_warn (cfile, + "invalid authentication policy."); + skip_to_semi (cfile); + return; + } + config -> auth_policy = policy; + } else if (token != TOKEN_BOOTP) { + if (policy != P_PREFER && + policy != P_IGNORE && + policy != P_ACCEPT) { + parse_warn (cfile, "invalid bootp policy."); + skip_to_semi (cfile); + return; + } + config -> bootp_policy = policy; + } else { + parse_warn (cfile, "expecting a policy type."); + skip_to_semi (cfile); + return; + } + break; + + case OPTION: + token = next_token (&val, (unsigned *)0, cfile); + + token = peek_token (&val, (unsigned *)0, cfile); + if (token == SPACE) { + if (ip) { + parse_warn (cfile, + "option space definitions %s", + " may not be scoped."); + skip_to_semi (cfile); + break; + } + parse_option_space_decl (cfile); + return; + } + + option = parse_option_name (cfile, 1, &known); + if (!option) + return; - case PREPEND: - option = parse_option_decl (cfile, &config -> defaults [0]); - if (option) - config -> default_actions [option -> code] = - ACTION_PREPEND; + token = next_token (&val, (unsigned *)0, cfile); + if (token != CODE) { + parse_warn (cfile, "expecting \"code\" keyword."); + skip_to_semi (cfile); + free_option (option, MDL); + return; + } + if (ip) { + parse_warn (cfile, + "option definitions may only appear in %s", + "the outermost scope."); + skip_to_semi (cfile); + free_option (option, MDL); + return; + } + if (!parse_option_code_definition (cfile, option)) + free_option (option, MDL); return; case MEDIA: + token = next_token (&val, (unsigned *)0, cfile); parse_string_list (cfile, &config -> media, 1); return; case HARDWARE: + token = next_token (&val, (unsigned *)0, cfile); if (ip) { parse_hardware_param (cfile, &ip -> hw_address); } else { - parse_warn ("hardware address parameter %s", + parse_warn (cfile, "hardware address parameter %s", "not allowed here."); skip_to_semi (cfile); } return; case REQUEST: - config -> requested_option_count = - parse_option_list (cfile, config -> requested_options); - return; - - case REQUIRE: - memset (config -> required_options, 0, - sizeof config -> required_options); - parse_option_list (cfile, config -> required_options); + token = next_token (&val, (unsigned *)0, cfile); + if (config -> requested_options == default_requested_options) + config -> requested_options = (u_int32_t *)0; + parse_option_list (cfile, &config -> requested_options); return; case TIMEOUT: + token = next_token (&val, (unsigned *)0, cfile); parse_lease_time (cfile, &config -> timeout); return; case RETRY: + token = next_token (&val, (unsigned *)0, cfile); parse_lease_time (cfile, &config -> retry_interval); return; case SELECT_TIMEOUT: + token = next_token (&val, (unsigned *)0, cfile); parse_lease_time (cfile, &config -> select_interval); return; + case OMAPI: + token = next_token (&val, (unsigned *)0, cfile); + token = next_token (&val, (unsigned *)0, cfile); + if (token != PORT) { + parse_warn (cfile, + "unexpected omapi subtype: %s", val); + skip_to_semi (cfile); + return; + } + token = next_token (&val, (unsigned *)0, cfile); + if (token != NUMBER) { + parse_warn (cfile, "invalid port number: `%s'", val); + skip_to_semi (cfile); + return; + } + tmp = atoi (val); + if (tmp < 0 || tmp > 65535) + parse_warn (cfile, "invalid omapi port %d.", tmp); + else if (config != &top_level_config) + parse_warn (cfile, + "omapi port only works at top level."); + else + config -> omapi_port = tmp; + parse_semi (cfile); + return; + case REBOOT: + token = next_token (&val, (unsigned *)0, cfile); parse_lease_time (cfile, &config -> reboot_timeout); return; case BACKOFF_CUTOFF: + token = next_token (&val, (unsigned *)0, cfile); parse_lease_time (cfile, &config -> backoff_cutoff); return; case INITIAL_INTERVAL: + token = next_token (&val, (unsigned *)0, cfile); parse_lease_time (cfile, &config -> initial_interval); return; case SCRIPT: - config -> script_name = parse_string (cfile); + token = next_token (&val, (unsigned *)0, cfile); + parse_string (cfile, &config -> script_name, (unsigned *)0); + return; + + case VENDOR: + token = next_token (&val, (unsigned *)0, cfile); + token = next_token (&val, (unsigned *)0, cfile); + if (token != OPTION) { + parse_warn (cfile, "expecting 'vendor option space'"); + skip_to_semi (cfile); + return; + } + token = next_token (&val, (unsigned *)0, cfile); + if (token != SPACE) { + parse_warn (cfile, "expecting 'vendor option space'"); + skip_to_semi (cfile); + return; + } + token = next_token (&val, (unsigned *)0, cfile); + if (!is_identifier (token)) { + parse_warn (cfile, "expecting an identifier."); + skip_to_semi (cfile); + return; + } + config -> vendor_space_name = dmalloc (strlen (val) + 1, MDL); + if (!config -> vendor_space_name) + log_fatal ("no memory for vendor option space name."); + strcpy (config -> vendor_space_name, val); + for (i = 0; i < universe_count; i++) + if (!strcmp (universes [i] -> name, + config -> vendor_space_name)) + break; + if (i == universe_count) { + log_error ("vendor option space %s not found.", + config -> vendor_space_name); + } + parse_semi (cfile); return; case INTERFACE: + token = next_token (&val, (unsigned *)0, cfile); if (ip) - parse_warn ("nested interface declaration."); - parse_interface_declaration (cfile, config); + parse_warn (cfile, "nested interface declaration."); + parse_interface_declaration (cfile, config, (char *)0); return; + case PSEUDO: + token = next_token (&val, (unsigned *)0, cfile); + token = next_token (&val, (unsigned *)0, cfile); + name = dmalloc (strlen (val) + 1, MDL); + if (!name) + log_fatal ("no memory for pseudo interface name"); + strcpy (name, val); + parse_interface_declaration (cfile, config, name); + return; + case LEASE: + token = next_token (&val, (unsigned *)0, cfile); parse_client_lease_statement (cfile, 1); return; case ALIAS: + token = next_token (&val, (unsigned *)0, cfile); parse_client_lease_statement (cfile, 2); return; case REJECT: + token = next_token (&val, (unsigned *)0, cfile); parse_reject_statement (cfile, config); return; default: - parse_warn ("expecting a statement."); - skip_to_semi (cfile); - break; - } - token = next_token (&val, cfile); - if (token != SEMI) { - parse_warn ("semicolon expected."); - skip_to_semi (cfile); - } -} - -int parse_X (cfile, buf, max) - FILE *cfile; - u_int8_t *buf; - int max; -{ - int token; - char *val; - int len; - - token = peek_token (&val, cfile); - if (token == NUMBER_OR_NAME || token == NUMBER) { - len = 0; - do { - token = next_token (&val, cfile); - if (token != NUMBER && token != NUMBER_OR_NAME) { - parse_warn ("expecting hexadecimal constant."); + lose = 0; + stmt = (struct executable_statement *)0; + if (!parse_executable_statement (&stmt, + cfile, &lose, context_any)) { + if (!lose) { + parse_warn (cfile, "expecting a statement."); skip_to_semi (cfile); - return 0; } - convert_num (&buf [len], val, 16, 8); - if (len++ > max) { - parse_warn ("hexadecimal constant too long."); - skip_to_semi (cfile); - return 0; + } else { + struct executable_statement **eptr, *sptr; + if (stmt && + (stmt -> op == send_option_statement || + (stmt -> op == on_statement && + (stmt -> data.on.evtypes & ON_TRANSMISSION)))) { + eptr = &config -> on_transmission -> statements; + if (stmt -> op == on_statement) { + sptr = (struct executable_statement *)0; + executable_statement_reference + (&sptr, + stmt -> data.on.statements, MDL); + executable_statement_dereference (&stmt, + MDL); + executable_statement_reference (&stmt, + sptr, + MDL); + executable_statement_dereference (&sptr, + MDL); + } + } else + eptr = &config -> on_receipt -> statements; + + if (stmt) { + for (; *eptr; eptr = &(*eptr) -> next) + ; + executable_statement_reference (eptr, + stmt, MDL); } - token = peek_token (&val, cfile); - if (token == COLON) - token = next_token (&val, cfile); - } while (token == COLON); - val = (char *)buf; - } else if (token == STRING) { - token = next_token (&val, cfile); - len = strlen (val); - if (len + 1 > max) { - parse_warn ("string constant too long."); - skip_to_semi (cfile); - return 0; + return; } - memcpy (buf, val, len + 1); - } else { - parse_warn ("expecting string or hexadecimal data"); - skip_to_semi (cfile); - return 0; + break; } - return len; + parse_semi (cfile); } /* option-list :== option_name | option_list COMMA option_name */ -int parse_option_list (cfile, list) - FILE *cfile; - u_int8_t *list; +void parse_option_list (cfile, list) + struct parse *cfile; + u_int32_t **list; { int ix, i; int token; - char *val; + const char *val; + pair p = (pair)0, q, r; ix = 0; do { - token = next_token (&val, cfile); + token = next_token (&val, (unsigned *)0, cfile); + if (token == SEMI) + break; if (!is_identifier (token)) { - parse_warn ("expected option name."); + parse_warn (cfile, "%s: expected option name.", val); skip_to_semi (cfile); - return 0; + return; } for (i = 0; i < 256; i++) { if (!strcasecmp (dhcp_options [i].name, val)) break; } if (i == 256) { - parse_warn ("%s: expected option name."); - skip_to_semi (cfile); - return 0; - } - list [ix++] = i; - if (ix == 256) { - parse_warn ("%s: too many options.", val); + parse_warn (cfile, "%s: expected option name.", val); skip_to_semi (cfile); - return 0; + return; } - token = next_token (&val, cfile); + r = new_pair (MDL); + if (!r) + log_fatal ("can't allocate pair for option code."); + r -> car = (caddr_t)(long)i; + r -> cdr = (pair)0; + if (p) + q -> cdr = r; + else + p = r; + q = r; + ++ix; + token = next_token (&val, (unsigned *)0, cfile); } while (token == COMMA); if (token != SEMI) { - parse_warn ("expecting semicolon."); + parse_warn (cfile, "expecting semicolon."); skip_to_semi (cfile); - return 0; + return; + } + /* XXX we can't free the list here, because we may have copied + XXX it from an outer config state. */ + *list = (u_int32_t *)0; + if (ix) { + *list = dmalloc ((ix + 1) * sizeof **list, MDL); + if (!*list) + log_error ("no memory for option list."); + else { + ix = 0; + for (q = p; q; q = q -> cdr) + (*list) [ix++] = (u_int32_t)(long)q -> car; + (*list) [ix] = 0; + } + while (p) { + q = p -> cdr; + free_pair (p, MDL); + p = q; + } } - return ix; } /* interface-declaration :== INTERFACE string LBRACE client-declarations RBRACE */ -void parse_interface_declaration (cfile, outer_config) - FILE *cfile; +void parse_interface_declaration (cfile, outer_config, name) + struct parse *cfile; struct client_config *outer_config; + char *name; { int token; - char *val; + const char *val; + struct client_state *client, **cp; + struct interface_info *ip = (struct interface_info *)0; - struct interface_info *ip; - - token = next_token (&val, cfile); + token = next_token (&val, (unsigned *)0, cfile); if (token != STRING) { - parse_warn ("expecting interface name (in quotes)."); + parse_warn (cfile, "expecting interface name (in quotes)."); skip_to_semi (cfile); return; } - ip = interface_or_dummy (val); + if (!interface_or_dummy (&ip, val)) + log_fatal ("Can't allocate interface %s.", val); - if (!ip -> client) - make_client_state (ip); + /* If we were given a name, this is a pseudo-interface. */ + if (name) { + make_client_state (&client); + client -> name = name; + client -> interface = ip; + for (cp = &ip -> client; *cp; cp = &((*cp) -> next)) + ; + *cp = client; + } else { + if (!ip -> client) { + make_client_state (&ip -> client); + ip -> client -> interface = ip; + } + client = ip -> client; + } - if (!ip -> client -> config) - make_client_config (ip, outer_config); + if (!client -> config) + make_client_config (client, outer_config); ip -> flags &= ~INTERFACE_AUTOMATIC; interfaces_requested = 1; - token = next_token (&val, cfile); + token = next_token (&val, (unsigned *)0, cfile); if (token != LBRACE) { - parse_warn ("expecting left brace."); + parse_warn (cfile, "expecting left brace."); skip_to_semi (cfile); return; } do { - token = peek_token (&val, cfile); - if (token == EOF) { - parse_warn ("unterminated interface declaration."); + token = peek_token (&val, (unsigned *)0, cfile); + if (token == END_OF_FILE) { + parse_warn (cfile, + "unterminated interface declaration."); return; } if (token == RBRACE) break; - parse_client_statement (cfile, ip, ip -> client -> config); + parse_client_statement (cfile, ip, client -> config); } while (1); - token = next_token (&val, cfile); + token = next_token (&val, (unsigned *)0, cfile); } -struct interface_info *interface_or_dummy (name) - char *name; +int interface_or_dummy (struct interface_info **pi, const char *name) { - struct interface_info *ip; + struct interface_info *i; + struct interface_info *ip = (struct interface_info *)0; + isc_result_t status; /* Find the interface (if any) that matches the name. */ - for (ip = interfaces; ip; ip = ip -> next) { - if (!strcmp (ip -> name, name)) + for (i = interfaces; i; i = i -> next) { + if (!strcmp (i -> name, name)) { + interface_reference (&ip, i, MDL); break; + } } /* If it's not a real interface, see if it's on the dummy list. */ if (!ip) { for (ip = dummy_interfaces; ip; ip = ip -> next) { - if (!strcmp (ip -> name, name)) + if (!strcmp (ip -> name, name)) { + interface_reference (&ip, i, MDL); break; + } } } /* If we didn't find an interface, make a dummy interface as a placeholder. */ if (!ip) { - ip = ((struct interface_info *)malloc (sizeof *ip)); - if (!ip) - error ("Insufficient memory to record interface %s", - name); - memset (ip, 0, sizeof *ip); + isc_result_t status; + status = interface_allocate (&ip, MDL); + if (status != ISC_R_SUCCESS) + log_fatal ("Can't record interface %s: %s", + name, isc_result_totext (status)); strcpy (ip -> name, name); - ip -> next = dummy_interfaces; - dummy_interfaces = ip; + if (dummy_interfaces) { + interface_reference (&ip -> next, + dummy_interfaces, MDL); + interface_dereference (&dummy_interfaces, MDL); + } + interface_reference (&dummy_interfaces, ip, MDL); } - return ip; + if (pi) + status = interface_reference (pi, ip, MDL); + interface_dereference (&ip, MDL); + if (status != ISC_R_SUCCESS) + return 0; + return 1; } -void make_client_state (ip) - struct interface_info *ip; +void make_client_state (state) + struct client_state **state; { - ip -> client = - ((struct client_state *)malloc (sizeof *(ip -> client))); - if (!ip -> client) - error ("no memory for state on %s\n", ip -> name); - memset (ip -> client, 0, sizeof *(ip -> client)); + *state = ((struct client_state *)dmalloc (sizeof **state, MDL)); + if (!*state) + log_fatal ("no memory for client state\n"); + memset (*state, 0, sizeof **state); } -void make_client_config (ip, config) - struct interface_info *ip; +void make_client_config (client, config) + struct client_state *client; struct client_config *config; { - ip -> client -> config = - ((struct client_config *) - malloc (sizeof (struct client_config))); - if (!ip -> client -> config) - error ("no memory for config for %s\n", ip -> name); - memset (ip -> client -> config, 0, - sizeof *(ip -> client -> config)); - memcpy (ip -> client -> config, config, sizeof *config); + client -> config = (((struct client_config *) + dmalloc (sizeof (struct client_config), MDL))); + if (!client -> config) + log_fatal ("no memory for client config\n"); + memcpy (client -> config, config, sizeof *config); + if (!clone_group (&client -> config -> on_receipt, + config -> on_receipt, MDL) || + !clone_group (&client -> config -> on_transmission, + config -> on_transmission, MDL)) + log_fatal ("no memory for client state groups."); } /* client-lease-statement :== @@ -526,51 +811,57 @@ void make_client_config (ip, config) void parse_client_lease_statement (cfile, is_static) - FILE *cfile; + struct parse *cfile; int is_static; { struct client_lease *lease, *lp, *pl; - struct interface_info *ip; + struct interface_info *ip = (struct interface_info *)0; int token; - char *val; + const char *val; + struct client_state *client = (struct client_state *)0; - token = next_token (&val, cfile); + token = next_token (&val, (unsigned *)0, cfile); if (token != LBRACE) { - parse_warn ("expecting left brace."); + parse_warn (cfile, "expecting left brace."); skip_to_semi (cfile); return; } - lease = (struct client_lease *)malloc (sizeof (struct client_lease)); + lease = ((struct client_lease *) + dmalloc (sizeof (struct client_lease), MDL)); if (!lease) - error ("no memory for lease.\n"); + log_fatal ("no memory for lease.\n"); memset (lease, 0, sizeof *lease); lease -> is_static = is_static; - - ip = (struct interface_info *)0; + if (!option_state_allocate (&lease -> options, MDL)) + log_fatal ("no memory for lease options.\n"); do { - token = peek_token (&val, cfile); - if (token == EOF) { - parse_warn ("unterminated lease declaration."); + token = peek_token (&val, (unsigned *)0, cfile); + if (token == END_OF_FILE) { + parse_warn (cfile, "unterminated lease declaration."); return; } if (token == RBRACE) break; - parse_client_lease_declaration (cfile, lease, &ip); + parse_client_lease_declaration (cfile, lease, &ip, &client); } while (1); - token = next_token (&val, cfile); + token = next_token (&val, (unsigned *)0, cfile); /* If the lease declaration didn't include an interface declaration that we recognized, it's of no use to us. */ if (!ip) { - free_client_lease (lease); + destroy_client_lease (lease); return; } /* Make sure there's a client state structure... */ - if (!ip -> client) - make_client_state (ip); + if (!ip -> client) { + make_client_state (&ip -> client); + ip -> client -> interface = ip; + } + if (!client) + client = ip -> client; /* If this is an alias lease, it doesn't need to be sorted in. */ if (is_static == 2) { @@ -583,15 +874,15 @@ void parse_client_lease_statement (cfile, is_static) lease list looking for a lease with the same address, and if we find it, toss it. */ pl = (struct client_lease *)0; - for (lp = ip -> client -> leases; lp; lp = lp -> next) { + for (lp = client -> leases; lp; lp = lp -> next) { if (lp -> address.len == lease -> address.len && !memcmp (lp -> address.iabuf, lease -> address.iabuf, lease -> address.len)) { if (pl) pl -> next = lp -> next; else - ip -> client -> leases = lp -> next; - free_client_lease (lp); + client -> leases = lp -> next; + destroy_client_lease (lp); break; } } @@ -599,8 +890,8 @@ void parse_client_lease_statement (cfile, is_static) /* If this is a preloaded lease, just put it on the list of recorded leases - don't make it the active lease. */ if (is_static) { - lease -> next = ip -> client -> leases; - ip -> client -> leases = lease; + lease -> next = client -> leases; + client -> leases = lease; return; } @@ -615,22 +906,21 @@ void parse_client_lease_statement (cfile, is_static) then if the old active lease has expired, we dump it; if not, we put it on the list of leases for this interface which are still valid but no longer active. */ - if (ip -> client -> active) { - if (ip -> client -> active -> expiry < cur_time) - free_client_lease (ip -> client -> active); - else if (ip -> client -> active -> address.len == + if (client -> active) { + if (client -> active -> expiry < cur_time) + destroy_client_lease (client -> active); + else if (client -> active -> address.len == lease -> address.len && - !memcmp (ip -> client -> active -> address.iabuf, + !memcmp (client -> active -> address.iabuf, lease -> address.iabuf, lease -> address.len)) - free_client_lease (ip -> client -> active); + destroy_client_lease (client -> active); else { - ip -> client -> active -> next = - ip -> client -> leases; - ip -> client -> leases = ip -> client -> active; + client -> active -> next = client -> leases; + client -> leases = client -> active; } } - ip -> client -> active = lease; + client -> active = lease; /* phew. */ } @@ -644,31 +934,65 @@ void parse_client_lease_statement (cfile, is_static) OPTION option-decl | RENEW time-decl | REBIND time-decl | - EXPIRE time-decl */ + EXPIRE time-decl | + KEY id */ -void parse_client_lease_declaration (cfile, lease, ipp) - FILE *cfile; +void parse_client_lease_declaration (cfile, lease, ipp, clientp) + struct parse *cfile; struct client_lease *lease; struct interface_info **ipp; + struct client_state **clientp; { int token; - char *val; + const char *val; + char *t, *n; struct interface_info *ip; - - switch (next_token (&val, cfile)) { - case BOOTP: + struct option_cache *oc; + struct client_state *client = (struct client_state *)0; + struct data_string key_id; + + switch (next_token (&val, (unsigned *)0, cfile)) { + case KEY: + token = next_token (&val, (unsigned *)0, cfile); + if (token != STRING && !is_identifier (token)) { + parse_warn (cfile, "expecting key name."); + skip_to_semi (cfile); + break; + } + if (omapi_auth_key_lookup_name (&lease -> key, val) != + ISC_R_SUCCESS) + parse_warn (cfile, "unknown key %s", val); + parse_semi (cfile); + break; + case TOKEN_BOOTP: lease -> is_bootp = 1; break; case INTERFACE: - token = next_token (&val, cfile); + token = next_token (&val, (unsigned *)0, cfile); if (token != STRING) { - parse_warn ("expecting interface name (in quotes)."); + parse_warn (cfile, + "expecting interface name (in quotes)."); skip_to_semi (cfile); break; } - ip = interface_or_dummy (val); - *ipp = ip; + interface_or_dummy (ipp, val); + break; + + case NAME: + token = next_token (&val, (unsigned *)0, cfile); + ip = *ipp; + if (!ip) { + parse_warn (cfile, "state name precedes interface."); + break; + } + for (client = ip -> client; client; client = client -> next) + if (client -> name && !strcmp (client -> name, val)) + break; + if (!client) + parse_warn (cfile, + "lease specified for unknown pseudo."); + *clientp = client; break; case FIXED_ADDR: @@ -681,11 +1005,11 @@ void parse_client_lease_declaration (cfile, lease, ipp) return; case FILENAME: - lease -> filename = parse_string (cfile); + parse_string (cfile, &lease -> filename, (unsigned *)0); return; case SERVER_NAME: - lease -> server_name = parse_string (cfile); + parse_string (cfile, &lease -> server_name, (unsigned *)0); return; case RENEW: @@ -701,239 +1025,33 @@ void parse_client_lease_declaration (cfile, lease, ipp) return; case OPTION: - parse_option_decl (cfile, lease -> options); + oc = (struct option_cache *)0; + if (parse_option_decl (&oc, cfile)) { + save_option (oc -> option -> universe, + lease -> options, oc); + option_cache_dereference (&oc, MDL); + } return; default: - parse_warn ("expecting lease declaration."); + parse_warn (cfile, "expecting lease declaration."); skip_to_semi (cfile); break; } - token = next_token (&val, cfile); + token = next_token (&val, (unsigned *)0, cfile); if (token != SEMI) { - parse_warn ("expecting semicolon."); + parse_warn (cfile, "expecting semicolon."); skip_to_semi (cfile); } } -struct option *parse_option_decl (cfile, options) - FILE *cfile; - struct option_data *options; -{ - char *val; - int token; - u_int8_t buf [4]; - u_int8_t hunkbuf [1024]; - int hunkix = 0; - char *vendor; - char *fmt; - struct universe *universe; - struct option *option; - struct iaddr ip_addr; - u_int8_t *dp; - int len; - int nul_term = 0; - - token = next_token (&val, cfile); - if (!is_identifier (token)) { - parse_warn ("expecting identifier after option keyword."); - if (token != SEMI) - skip_to_semi (cfile); - return (struct option *)0; - } - vendor = malloc (strlen (val) + 1); - if (!vendor) - error ("no memory for vendor information."); - strcpy (vendor, val); - token = peek_token (&val, cfile); - if (token == DOT) { - /* Go ahead and take the DOT token... */ - token = next_token (&val, cfile); - - /* The next token should be an identifier... */ - token = next_token (&val, cfile); - if (!is_identifier (token)) { - parse_warn ("expecting identifier after '.'"); - if (token != SEMI) - skip_to_semi (cfile); - return (struct option *)0; - } - - /* Look up the option name hash table for the specified - vendor. */ - universe = ((struct universe *) - hash_lookup (&universe_hash, - (unsigned char *)vendor, 0)); - /* If it's not there, we can't parse the rest of the - declaration. */ - if (!universe) { - parse_warn ("no vendor named %s.", vendor); - skip_to_semi (cfile); - return (struct option *)0; - } - } else { - /* Use the default hash table, which contains all the - standard dhcp option names. */ - val = vendor; - universe = &dhcp_universe; - } - - /* Look up the actual option info... */ - option = (struct option *)hash_lookup (universe -> hash, - (unsigned char *)val, 0); - - /* If we didn't get an option structure, it's an undefined option. */ - if (!option) { - if (val == vendor) - parse_warn ("no option named %s", val); - else - parse_warn ("no option named %s for vendor %s", - val, vendor); - skip_to_semi (cfile); - return (struct option *)0; - } - - /* Free the initial identifier token. */ - free (vendor); - - /* Parse the option data... */ - do { - for (fmt = option -> format; *fmt; fmt++) { - if (*fmt == 'A') - break; - switch (*fmt) { - case 'X': - len = parse_X (cfile, &hunkbuf [hunkix], - sizeof hunkbuf - hunkix); - hunkix += len; - break; - - case 't': /* Text string... */ - token = next_token (&val, cfile); - if (token != STRING) { - parse_warn ("expecting string."); - skip_to_semi (cfile); - return (struct option *)0; - } - len = strlen (val); - if (hunkix + len + 1 > sizeof hunkbuf) { - parse_warn ("option data buffer %s", - "overflow"); - skip_to_semi (cfile); - return (struct option *)0; - } - memcpy (&hunkbuf [hunkix], val, len + 1); - nul_term = 1; - hunkix += len; - break; - - case 'I': /* IP address. */ - if (!parse_ip_addr (cfile, &ip_addr)) - return (struct option *)0; - len = ip_addr.len; - dp = ip_addr.iabuf; - - alloc: - if (hunkix + len > sizeof hunkbuf) { - parse_warn ("option data buffer %s", - "overflow"); - skip_to_semi (cfile); - return (struct option *)0; - } - memcpy (&hunkbuf [hunkix], dp, len); - hunkix += len; - break; - - case 'L': /* Unsigned 32-bit integer... */ - case 'l': /* Signed 32-bit integer... */ - token = next_token (&val, cfile); - if (token != NUMBER) { - need_number: - parse_warn ("expecting number."); - if (token != SEMI) - skip_to_semi (cfile); - return (struct option *)0; - } - convert_num (buf, val, 0, 32); - len = 4; - dp = buf; - goto alloc; - - case 's': /* Signed 16-bit integer. */ - case 'S': /* Unsigned 16-bit integer. */ - token = next_token (&val, cfile); - if (token != NUMBER) - goto need_number; - convert_num (buf, val, 0, 16); - len = 2; - dp = buf; - goto alloc; - - case 'b': /* Signed 8-bit integer. */ - case 'B': /* Unsigned 8-bit integer. */ - token = next_token (&val, cfile); - if (token != NUMBER) - goto need_number; - convert_num (buf, val, 0, 8); - len = 1; - dp = buf; - goto alloc; - - case 'f': /* Boolean flag. */ - token = next_token (&val, cfile); - if (!is_identifier (token)) { - parse_warn ("expecting identifier."); - bad_flag: - if (token != SEMI) - skip_to_semi (cfile); - return (struct option *)0; - } - if (!strcasecmp (val, "true") - || !strcasecmp (val, "on")) - buf [0] = 1; - else if (!strcasecmp (val, "false") - || !strcasecmp (val, "off")) - buf [0] = 0; - else { - parse_warn ("expecting boolean."); - goto bad_flag; - } - len = 1; - dp = buf; - goto alloc; - - default: - warn ("Bad format %c in parse_option_param.", - *fmt); - skip_to_semi (cfile); - return (struct option *)0; - } - } - token = next_token (&val, cfile); - } while (*fmt == 'A' && token == COMMA); - - if (token != SEMI) { - parse_warn ("semicolon expected."); - skip_to_semi (cfile); - return (struct option *)0; - } - - options [option -> code].data = - (unsigned char *)malloc (hunkix + nul_term); - if (!options [option -> code].data) - error ("out of memory allocating option data."); - memcpy (options [option -> code].data, hunkbuf, hunkix + nul_term); - options [option -> code].len = hunkix; - return option; -} - void parse_string_list (cfile, lp, multiple) - FILE *cfile; + struct parse *cfile; struct string_list **lp; int multiple; { int token; - char *val; + const char *val; struct string_list *cur, *tmp; /* Find the last medium in the media list. */ @@ -945,18 +1063,18 @@ void parse_string_list (cfile, lp, multiple) } do { - token = next_token (&val, cfile); + token = next_token (&val, (unsigned *)0, cfile); if (token != STRING) { - parse_warn ("Expecting media options."); + parse_warn (cfile, "Expecting media options."); skip_to_semi (cfile); return; } - tmp = (struct string_list *)malloc (strlen (val) + 1 + - sizeof - (struct string_list *)); + tmp = ((struct string_list *) + dmalloc (strlen (val) + sizeof (struct string_list), + MDL)); if (!tmp) - error ("no memory for string list entry."); + log_fatal ("no memory for string list entry."); strcpy (tmp -> string, val); tmp -> next = (struct string_list *)0; @@ -968,44 +1086,67 @@ void parse_string_list (cfile, lp, multiple) *lp = tmp; cur = tmp; - token = next_token (&val, cfile); + token = next_token (&val, (unsigned *)0, cfile); } while (multiple && token == COMMA); if (token != SEMI) { - parse_warn ("expecting semicolon."); + parse_warn (cfile, "expecting semicolon."); skip_to_semi (cfile); } } void parse_reject_statement (cfile, config) - FILE *cfile; + struct parse *cfile; struct client_config *config; { int token; - char *val; + const char *val; struct iaddr addr; struct iaddrlist *list; do { if (!parse_ip_addr (cfile, &addr)) { - parse_warn ("expecting IP address."); + parse_warn (cfile, "expecting IP address."); skip_to_semi (cfile); return; } - list = (struct iaddrlist *)malloc (sizeof (struct iaddrlist)); + list = (struct iaddrlist *)dmalloc (sizeof (struct iaddrlist), + MDL); if (!list) - error ("no memory for reject list!"); + log_fatal ("no memory for reject list!"); list -> addr = addr; list -> next = config -> reject_list; config -> reject_list = list; - token = next_token (&val, cfile); + token = next_token (&val, (unsigned *)0, cfile); } while (token == COMMA); if (token != SEMI) { - parse_warn ("expecting semicolon."); + parse_warn (cfile, "expecting semicolon."); skip_to_semi (cfile); } } + +/* allow-deny-keyword :== BOOTP + | BOOTING + | DYNAMIC_BOOTP + | UNKNOWN_CLIENTS */ + +int parse_allow_deny (oc, cfile, flag) + struct option_cache **oc; + struct parse *cfile; + int flag; +{ + enum dhcp_token token; + const char *val; + unsigned char rf = flag; + struct expression *data = (struct expression *)0; + int status; + + parse_warn (cfile, "allow/deny/ignore not permitted here."); + skip_to_semi (cfile); + return 0; +} + diff --git a/contrib/isc-dhcp/client/dhclient-script.8 b/contrib/isc-dhcp/client/dhclient-script.8 index 82212db..02b2252 100644 --- a/contrib/isc-dhcp/client/dhclient-script.8 +++ b/contrib/isc-dhcp/client/dhclient-script.8 @@ -1,8 +1,6 @@ .\" dhclient-script.8 .\" -.\" Copyright (c) 1997 The Internet Software Consortium. -.\" All rights reserved. -.\" +.\" Copyright (c) 1996-2001 Internet Software Consortium. .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: @@ -31,10 +29,11 @@ .\" SUCH DAMAGE. .\" .\" This software has been written for the Internet Software Consortium -.\" by Ted Lemon <mellon@fugue.com> in cooperation with Vixie -.\" Enterprises. To learn more about the Internet Software Consortium, -.\" see ``http://www.isc.org/isc''. To learn more about Vixie -.\" Enterprises, see ``http://www.vix.com''. +.\" by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. +.\" To learn more about the Internet Software Consortium, see +.\" ``http://www.isc.org/''. To learn more about Vixie Enterprises, +.\" see ``http://www.vix.com''. To learn more about Nominum, Inc., see +.\" ``http://www.nominum.com''. .TH dhclient-script 8 .SH NAME dhclient-script - DHCP client network configuration script @@ -61,7 +60,7 @@ to a particular computer should be done in the .B ETCDIR/dhclient.conf file. If you find that you can't make such a customization without customizing -.B dhclient-script +.B ETCDIR/dhclient.conf or using the enter and exit hooks, please submit a bug report. .SH HOOKS When it starts, the client script first defines a shell function, @@ -80,23 +79,29 @@ is available to this script, which may modify the environment if needed to change the behaviour of the script. If an error occurs during the execution of the script, it can set the exit_status variable to a nonzero value, and -.B ETCDIR/dhclient-script +.B CLIENTBINDIR/dhclient-script will exit with that error code immediately after the client script exits. .PP After all processing has completed, -.B ETCDIR/dhclient-script +.B CLIENTBINDIR/dhclient-script checks for the presence of an executable .B ETCDIR/dhclient-exit-hooks -script, which if present is invoked using the '.' command. The exit status -is passed in the exit_status shell variable, and will always be zero if the -script succeeded at the task for which it was invoked. +script, which if present is invoked using the '.' command. The exit +status of dhclient-script will be passed to dhclient-exit-hooks in the +exit_status shell variable, and will always be zero if the script +succeeded at the task for which it was invoked. The rest of the +environment as described previously for dhclient-enter-hooks is also +present. The +.B ETCDIR/dhclient-exit-hooks +script can modify the valid of exit_status to change the exit status +of dhclient-script. .SH OPERATION When dhclient needs to invoke the client configuration script, it -writes a shell script into /tmp which defines a variety of variables. +defines a set of variables in the environment, and then invokes +.B CLIENTBINDIR/dhclient-script. In all cases, $reason is set to the name of the reason why the script has been invoked. The following reasons are currently defined: -MEDIUM, PREINIT, ARPCHECK, ARPSEND, BOUND, RENEW, REBIND, REBOOT, -EXPIRE, FAIL and TIMEOUT. +MEDIUM, PREINIT, BOUND, RENEW, REBIND, REBOOT, EXPIRE, FAIL and TIMEOUT. .PP .SH MEDIUM The DHCP client is requesting that an interface's media type @@ -115,18 +120,6 @@ and the media type in $medium. If an IP alias has been declared in dhclient.conf, its address will be passed in $alias_ip_address, and that ip alias should be deleted from the interface, along with any routes to it. -.SH ARPSEND -The DHCP client is requesting that an address that has been offered to -it be checked to see if somebody else is using it, by sending an ARP -request for that address. It's not clear how to implement this, so -no examples exist yet. The IP address to check is passed in -$new_ip_address, and the interface name is passed in $interface. -.SH ARPCHECK -The DHCP client wants to know if a response to the ARP request send -using ARPSEND has been received. If one has, the script should exit -with a nonzero status, indicating that the offered address has already -been requested and should be declined. $new_ip_address and -$interface are set as with ARPSEND. .SH BOUND The DHCP client has done an initial binding to a new address. The new ip address is passed in $new_ip_address, and the interface name is @@ -137,6 +130,13 @@ by underscores ('_') in order to make valid shell variables, and the variable names start with new_. So for example, the new subnet mask would be passed in $new_subnet_mask. .PP +Before actually configuring the address, dhclient-script should +somehow ARP for it and exit with a nonzero status if it receives a +reply. In this case, the client will send a DHCPDECLINE message to +the server and acquire a different address. This may also be done in +the RENEW, REBIND, or REBOOT states, but is not required, and indeed +may not be desirable. +.PP When a binding has been completed, a lot of network parameters are likely to need to be set up. A new /etc/resolv.conf needs to be created, using the values of $new_domain_name and @@ -216,10 +216,10 @@ dhclient.leases(5). .SH AUTHOR .B dhclient-script(8) has been written for the Internet Software Consortium -by Ted Lemon <mellon@fugue.com> in cooperation with Vixie +by Ted Lemon in cooperation with Vixie Enterprises. To learn more about the Internet Software Consortium, see -.B http://www.vix.com/isc. +.B http://www.isc.org. To learn more about Vixie Enterprises, see .B http://www.vix.com. diff --git a/contrib/isc-dhcp/client/dhclient.8 b/contrib/isc-dhcp/client/dhclient.8 index eae8437..b47a4fd 100644 --- a/contrib/isc-dhcp/client/dhclient.8 +++ b/contrib/isc-dhcp/client/dhclient.8 @@ -1,40 +1,20 @@ .\" dhclient.8 .\" -.\" Copyright (c) 1997 The Internet Software Consortium. -.\" All rights reserved. +.\" Copyright (c) 1996-1999 Internet Software Consortium. +.\" Use is subject to license terms which appear in the file named +.\" ISC-LICENSE that should have accompanied this file when you +.\" received it. If a file named ISC-LICENSE did not accompany this +.\" file, or you are not sure the one you have is correct, you may +.\" obtain an applicable copy of the license at: .\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: +.\" http://www.isc.org/isc-license-1.0.html. .\" -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. Neither the name of The Internet Software Consortium nor the names -.\" of its contributors may be used to endorse or promote products derived -.\" from this software without specific prior written permission. +.\" This file is part of the ISC DHCP distribution. The documentation +.\" associated with this file is listed in the file DOCUMENTATION, +.\" included in the top-level directory of this release. .\" -.\" THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND -.\" CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, -.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -.\" DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR -.\" CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF -.\" USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -.\" ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" This software has been written for the Internet Software Consortium -.\" by Ted Lemon <mellon@fugue.com> in cooperation with Vixie -.\" Enterprises. To learn more about the Internet Software Consortium, -.\" see ``http://www.isc.org/isc''. To learn more about Vixie -.\" Enterprises, see ``http://www.vix.com''. +.\" Support and other services are available for ISC products - see +.\" http://www.isc.org for more information. .TH dhclient 8 .SH NAME dhclient - Dynamic Host Configuration Protocol Client @@ -48,6 +28,48 @@ dhclient - Dynamic Host Configuration Protocol Client .B -d ] [ +.B -q +] +[ +.B -1 +] +[ +.B -r +] +[ +.B -lf +.I lease-file +] +[ +.B -pf +.I pid-file +] +[ +.B -cf +.I config-file +] +[ +.B -sf +.I script-file +] +[ +.B -s +server +] +[ +.B -g +relay +] +[ +.B -n +] +[ +.B -nw +] +[ +.B -w +] +[ .I if0 [ .I ...ifN @@ -87,7 +109,7 @@ dhclient.leases file. In order to prevent the file from becoming arbitrarily large, from time to time dhclient creates a new dhclient.leases file from its in-core lease database. The old version of the dhclient.leases file is retained under the name -.IR dhcpd.leases~ +.IR dhclient.leases~ until the next time dhclient rewrites the database. .PP Old leases are kept around in case the DHCP server is unavailable when @@ -112,49 +134,163 @@ than cycling through the list of old leases. .PP The names of the network interfaces that dhclient should attempt to configure may be specified on the command line. If no interface names -are specified on the command line dhclient will identify all network -interfaces, elimininating non-broadcast interfaces if possible, and -attempt to configure each interface. +are specified on the command line dhclient will normally identify all +network interfaces, elimininating non-broadcast interfaces if +possible, and attempt to configure each interface. .PP -If dhclient should listen and transmit on a port other than the +It is also possible to specify interfaces by name in the +.B dhclient.conf(5) +file. If interfaces are specified in this way, then the client will +only configure interfaces that are either specified in the +configuration file or on the command line, and will ignore all other +interfaces. +.PP +If the DHCP client should listen and transmit on a port other than the standard (port 68), the .B -p flag may used. It should be followed by the udp port number that dhclient should use. This is mostly useful for debugging purposes. -If the -.B -p -flag is specified, the client will transmit responses to servers at a -port number that is one less than the one specified - i.e., if you -specify -.B -p -68, then the client will listen on port 68 and transmit to port 67. -Datagrams that must go through relay agents are sent to the port -number specified with the -.B -p -flag - if you wish to use alternate port numbers, you must configure -any relay agents you are using to use the same alternate port numbers. +If a different port is specified for the client to listen on and +transmit on, the client will also use a different destination port - +one greater than the specified destination port. +.PP +The DHCP client normally transmits any protocol messages it sends +before acquiring an IP address to, 255.255.255.255, the IP limited +broadcast address. For debugging purposes, it may be useful to have +the server transmit these messages to some other address. This can +be specified with the +.B -s +flag, followed by the IP address or domain name of the destination. .PP -Dhclient will normally run in the foreground until it has configured -an interface, and then will revert to running in the background. -To run force dhclient to always run as a foreground process, the +For testing purposes, the giaddr field of all packets that the client +sends can be set using the +.B -g +flag, followed by the IP address to send. This is only useful for testing, +and should not be expected to work in any consistent or useful way. +.PP +The DHCP client will normally run in the foreground until it has +configured an interface, and then will revert to running in the +background. To run force dhclient to always run as a foreground +process, the .B -d -flag should be specified. This is useful when running dhclient under -a debugger, or when running it out of inittab on System V systems. +flag should be specified. This is useful when running the client +under a debugger, or when running it out of inittab on System V +systems. +.PP +The client normally prints a startup message and displays the +protocol sequence to the standard error descriptor until it has +acquired an address, and then only logs messages using the +.B syslog (3) +facility. The +.B -q +flag prevents any messages other than errors from being printed to the +standard error descriptor. +.PP +The client normally doesn't release the current lease as it is not +required by the DHCP protocol. Some cable ISPs require their clients +to notify the server if they wish to release an assigned IP address. +The +.B -r +flag explicitly releases the current lease, and once the lease has been +released, the client exits. +.PP +The +.B -1 +flag cause dhclient to try once to get a lease. If it fails, dhclient exits +with exit code two. +.PP +The DHCP client normally gets its configuration information from +.B ETCDIR/dhclient.conf, +its lease database from +.B DBDIR/dhclient.leases, +stores its process ID in a file called +.B RUNDIR/dhclient.pid, +and configures the network interface using +.B CLIENTBINDIR/dhclient-script +To specify different names and/or locations for these files, use the +.B -cf, +.B -lf, +.B -pf +and +.B -sf +flags, respectively, followed by the name of the file. This can be +particularly useful if, for example, +.B DBDIR +or +.B RUNDIR +has not yet been mounted when the DHCP client is started. .PP +The DHCP client normally exits if it isn't able to identify any +network interfaces to configure. On laptop computers and other +computers with hot-swappable I/O buses, it is possible that a +broadcast interface may be added after system startup. The +.B -w +flag can be used to cause the client not to exit when it doesn't find +any such interfaces. The +.B omshell (8) +program can then be used to notify the client when a network interface +has been added or removed, so that the client can attempt to configure an IP +address on that interface. +.PP +The DHCP client can be directed not to attempt to configure any interfaces +using the +.B -n +flag. This is most likely to be useful in combination with the +.B -w +flag. +.PP +The client can also be instructed to become a daemon immediately, rather +than waiting until it has acquired an IP address. This can be done by +supplying the +.B -nw +flag. .SH CONFIGURATION The syntax of the dhclient.conf(8) file is discussed seperately. +.SH OMAPI +The DHCP client provides some ability to control it while it is +running, without stopping it. This capability is provided using OMAPI, +an API for manipulating remote objects. OMAPI clients connect to the +client using TCP/IP, authenticate, and can then examine the client's +current status and make changes to it. +.PP +Rather than implementing the underlying OMAPI protocol directly, user +programs should use the dhcpctl API or OMAPI itself. Dhcpctl is a +wrapper that handles some of the housekeeping chores that OMAPI does +not do automatically. Dhcpctl and OMAPI are documented in \fBdhcpctl(3)\fR +and \fBomapi(3)\fR. Most things you'd want to do with the client can +be done directly using the \fBomshell(1)\fR command, rather than +having to write a special program. +.SH THE CONTROL OBJECT +The control object allows you to shut the client down, releasing all +leases that it holds and deleting any DNS records it may have added. +It also allows you to pause the client - this unconfigures any +interfaces the client is using. You can then restart it, which +causes it to reconfigure those interfaces. You would normally pause +the client prior to going into hibernation or sleep on a laptop +computer. You would then resume it after the power comes back. +This allows PC cards to be shut down while the computer is hibernating +or sleeping, and then reinitialized to their previous state once the +computer comes out of hibernation or sleep. +.PP +The control object has one attribute - the state attribute. To shut +the client down, set its state attribute to 2. It will automatically +do a DHCPRELEASE. To pause it, set its state attribute to 3. To +resume it, set its state attribute to 4. +.PP .SH FILES +.B CLIENTBINDIR/dhclient-script, .B ETCDIR/dhclient.conf, DBDIR/dhclient.leases, RUNDIR/dhclient.pid, .B DBDIR/dhclient.leases~. .SH SEE ALSO -dhcpd(8), dhcrelay(8), dhclient.conf(5), dhclient.leases(5) +dhcpd(8), dhcrelay(8), dhclient-script (8), dhclient.conf(5), +dhclient.leases(5). .SH AUTHOR .B dhclient(8) has been written for the Internet Software Consortium -by Ted Lemon <mellon@fugue.com> in cooperation with Vixie +by Ted Lemon in cooperation with Vixie Enterprises. To learn more about the Internet Software Consortium, see -.B http://www.vix.com/isc. +.B http://www.isc.org To learn more about Vixie Enterprises, see .B http://www.vix.com. diff --git a/contrib/isc-dhcp/client/dhclient.c b/contrib/isc-dhcp/client/dhclient.c index 129f99a..f1c0ddd 100644 --- a/contrib/isc-dhcp/client/dhclient.c +++ b/contrib/isc-dhcp/client/dhclient.c @@ -3,8 +3,8 @@ DHCP Client. */ /* - * Copyright (c) 1995, 1996, 1997, 1998, 1999 - * The Internet Software Consortium. All rights reserved. + * Copyright (c) 1995-2001 Internet Software Consortium. + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -15,7 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of The Internet Software Consortium nor the names + * 3. Neither the name of Internet Software Consortium nor the names * of its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -33,30 +33,15 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * This software has been written for the Internet Software Consortium - * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie - * Enterprises. To learn more about the Internet Software Consortium, - * see ``http://www.vix.com/isc''. To learn more about Vixie - * Enterprises, see ``http://www.vix.com''. - * - * This client was substantially modified and enhanced by Elliot Poger - * for use on Linux while he was working on the MosquitoNet project at - * Stanford. - * - * The current version owes much to Elliot's Linux enhancements, but - * was substantially reorganized and partially rewritten by Ted Lemon - * so as to use the same networking framework that the Internet Software - * Consortium DHCP server uses. Much system-specific configuration code - * was moved into a shell script so that as support for more operating - * systems is added, it will not be necessary to port and maintain - * system-specific configuration code to these operating systems - instead, - * the shell script can invoke the native tools to accomplish the same - * purpose. + * This code is based on the original client state machine that was + * written by Elliot Poger. The code has been extensively hacked on + * by Ted Lemon since then, so any mistakes you find are probably his + * fault and not Elliot's. */ #ifndef lint static char ocopyright[] = -"$Id: dhclient.c,v 1.44.2.47 2000/09/06 20:59:09 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium. All rights reserved.\n"; +"$Id: dhclient.c,v 1.129.2.7 2001/08/08 14:46:14 mellon Exp $ Copyright (c) 1995-2001 Internet Software Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -65,39 +50,44 @@ static char ocopyright[] = TIME cur_time; TIME default_lease_time = 43200; /* 12 hours... */ TIME max_lease_time = 86400; /* 24 hours... */ -struct tree_cache *global_options [256]; -char *path_dhclient_conf = _PATH_DHCLIENT_CONF; -char *path_dhclient_db = _PATH_DHCLIENT_DB; -char *path_dhclient_pid = _PATH_DHCLIENT_PID; +const char *path_dhclient_conf = _PATH_DHCLIENT_CONF; +const char *path_dhclient_db = _PATH_DHCLIENT_DB; +const char *path_dhclient_pid = _PATH_DHCLIENT_PID; +static char path_dhclient_script_array [] = _PATH_DHCLIENT_SCRIPT; +char *path_dhclient_script = path_dhclient_script_array; -int interfaces_requested = 0; +int dhcp_max_agent_option_packet_length = 0; -int log_perror = 1; +int interfaces_requested = 0; struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } }; struct iaddr iaddr_any = { 4, { 0, 0, 0, 0 } }; struct in_addr inaddr_any; struct sockaddr_in sockaddr_broadcast; +struct in_addr giaddr; /* ASSERT_STATE() does nothing now; it used to be assert (state_is == state_shouldbe). */ #define ASSERT_STATE(state_is, state_shouldbe) {} +static char copyright[] = "Copyright 1995-2001 Internet Software Consortium."; +static char arr [] = "All rights reserved."; +static char message [] = "Internet Software Consortium DHCP Client"; +static char url [] = "For info, please visit http://www.isc.org/products/DHCP"; + u_int16_t local_port; u_int16_t remote_port; -int log_priority; int no_daemon; -int save_scripts; +struct string_list *client_env; +int client_env_count; +int onetry; +int quiet; +int nowait; -static char copyright[] = -"Copyright 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium."; -static char arr [] = "All rights reserved."; -static char message [] = "Internet Software Consortium DHCP Client"; -static char contrib [] = "Please contribute if you find this software useful."; -static char url [] = "For info, please visit http://www.isc.org/dhcp-contrib.html"; +static void usage PROTO ((void)); -static void usage PROTO ((char *)); +void do_release(struct client_state *); int main (argc, argv, envp) int argc; @@ -106,105 +96,242 @@ int main (argc, argv, envp) int i; struct servent *ent; struct interface_info *ip; - int seed; - int quiet = 0; + struct client_state *client; + unsigned seed; + char *server = (char *)0; + char *relay = (char *)0; + isc_result_t status; + int release_mode = 0; + omapi_object_t *listener; + isc_result_t result; + int persist = 0; + int omapi_port; + int no_dhclient_conf = 0; + int no_dhclient_db = 0; + int no_dhclient_pid = 0; + int no_dhclient_script = 0; char *s; - s = strrchr (argv [0], '/'); - if (!s) - s = argv [0]; - else - s++; + /* Make sure we have stdin, stdout and stderr. */ + i = open ("/dev/null", O_RDWR); + if (i == 0) + i = open ("/dev/null", O_RDWR); + if (i == 1) { + i = open ("/dev/null", O_RDWR); + log_perror = 0; /* No sense logging to /dev/null. */ + } else if (i != -1) + close (i); - /* Initially, log errors to stderr as well as to syslogd. */ #ifdef SYSLOG_4_2 - openlog (s, LOG_NDELAY); - log_priority = DHCPD_LOG_FACILITY; + openlog ("dhclient", LOG_NDELAY); + log_priority = LOG_DAEMON; #else - openlog (s, LOG_NDELAY, DHCPD_LOG_FACILITY); + openlog ("dhclient", LOG_NDELAY, LOG_DAEMON); #endif #if !(defined (DEBUG) || defined (SYSLOG_4_2) || defined (__CYGWIN32__)) setlogmask (LOG_UPTO (LOG_INFO)); #endif + /* Set up the OMAPI. */ + status = omapi_init (); + if (status != ISC_R_SUCCESS) + log_fatal ("Can't initialize OMAPI: %s", + isc_result_totext (status)); + + /* Set up the OMAPI wrappers for various server database internal + objects. */ + dhcp_common_objects_setup (); + + dhcp_interface_discovery_hook = dhclient_interface_discovery_hook; + dhcp_interface_shutdown_hook = dhclient_interface_shutdown_hook; + dhcp_interface_startup_hook = dhclient_interface_startup_hook; + for (i = 1; i < argc; i++) { - if (!strcmp (argv [i], "-p")) { + if (!strcmp (argv [i], "-r")) { + release_mode = 1; + no_daemon = 1; + } else if (!strcmp (argv [i], "-p")) { if (++i == argc) - usage (s); + usage (); local_port = htons (atoi (argv [i])); - debug ("binding to user-specified port %d", + log_debug ("binding to user-specified port %d", ntohs (local_port)); } else if (!strcmp (argv [i], "-d")) { no_daemon = 1; - } else if (!strcmp (argv [i], "-D")) { - save_scripts = 1; - } else if (!strcmp (argv [i], "-cf")) { + } else if (!strcmp (argv [i], "-pf")) { + if (++i == argc) + usage (); + path_dhclient_pid = argv [i]; + no_dhclient_pid = 1; + } else if (!strcmp (argv [i], "-cf")) { + if (++i == argc) + usage (); + path_dhclient_conf = argv [i]; + no_dhclient_conf = 1; + } else if (!strcmp (argv [i], "-lf")) { + if (++i == argc) + usage (); + path_dhclient_db = argv [i]; + no_dhclient_db = 1; + } else if (!strcmp (argv [i], "-sf")) { if (++i == argc) - usage (s); - path_dhclient_conf = argv [i]; - } else if (!strcmp (argv [i], "-pf")) { - if (++i == argc) - usage (s); - path_dhclient_pid = argv [i]; - } else if (!strcmp (argv [i], "-lf")) { - if (++i == argc) - usage (s); - path_dhclient_db = argv [i]; + usage (); + path_dhclient_script = argv [i]; + no_dhclient_script = 1; + } else if (!strcmp (argv [i], "-1")) { + onetry = 1; } else if (!strcmp (argv [i], "-q")) { quiet = 1; quiet_interface_discovery = 1; + } else if (!strcmp (argv [i], "-s")) { + if (++i == argc) + usage (); + server = argv [i]; + } else if (!strcmp (argv [i], "-g")) { + if (++i == argc) + usage (); + relay = argv [i]; + } else if (!strcmp (argv [i], "-n")) { + /* do not start up any interfaces */ + interfaces_requested = 1; + } else if (!strcmp (argv [i], "-w")) { + /* do not exit if there are no broadcast interfaces. */ + persist = 1; } else if (argv [i][0] == '-') { - usage (s); + usage (); + } else if (!strcmp (argv [i], "-e")) { + struct string_list *tmp; + if (++i == argc) + usage (); + tmp = dmalloc (strlen (argv [i]) + sizeof *tmp, MDL); + if (!tmp) + log_fatal ("No memory for %s", argv [i]); + strcpy (tmp -> string, argv [i]); + tmp -> next = client_env; + client_env = tmp; + client_env_count++; + } else if (!strcmp (argv [i], "--version")) { + log_info ("isc-dhclient-%s", DHCP_VERSION); + exit (0); + } else if (!strcmp (argv [i], "-nw")) { + nowait = 1; } else { - struct interface_info *tmp = - ((struct interface_info *) - dmalloc (sizeof *tmp, "specified_interface")); - if (!tmp) - error ("Insufficient memory to %s %s", - "record interface", argv [i]); - memset (tmp, 0, sizeof *tmp); + struct interface_info *tmp = (struct interface_info *)0; + status = interface_allocate (&tmp, MDL); + if (status != ISC_R_SUCCESS) + log_fatal ("Can't record interface %s:%s", + argv [i], isc_result_totext (status)); + if (strlen (argv [i]) > sizeof tmp -> name) + log_fatal ("%s: interface name too long (max %ld)", + argv [i], (long)strlen (argv [i])); strcpy (tmp -> name, argv [i]); - tmp -> next = interfaces; + if (interfaces) { + interface_reference (&tmp -> next, + interfaces, MDL); + interface_dereference (&interfaces, MDL); + } + interface_reference (&interfaces, tmp, MDL); tmp -> flags = INTERFACE_REQUESTED; interfaces_requested = 1; - interfaces = tmp; } } + if (!no_dhclient_conf && (s = getenv ("PATH_DHCLIENT_CONF"))) { + path_dhclient_conf = s; + } + if (!no_dhclient_db && (s = getenv ("PATH_DHCLIENT_DB"))) { + path_dhclient_db = s; + } + if (!no_dhclient_pid && (s = getenv ("PATH_DHCLIENT_PID"))) { + path_dhclient_pid = s; + } + if (!no_dhclient_script && (s = getenv ("PATH_DHCLIENT_SCRIPT"))) { + path_dhclient_script = s; + } + + /* first kill of any currently running client */ + if (release_mode) { + /* XXX inelegant hack to prove concept */ + char command[1024]; + +#if !defined (NO_SNPRINTF) + snprintf (command, 1024, "kill `cat %s`", path_dhclient_pid); +#else + sprintf (command, "kill `cat %s`", path_dhclient_pid); +#endif + system (command); + } + if (!quiet) { - note ("%s %s", message, DHCP_VERSION); - note (copyright); - note (arr); - note (""); - note (contrib); - note (url); - note (""); + log_info ("%s %s", message, DHCP_VERSION); + log_info (copyright); + log_info (arr); + log_info (url); + log_info ("%s", ""); } else log_perror = 0; + /* If we're given a relay agent address to insert, for testing + purposes, figure out what it is. */ + if (relay) { + if (!inet_aton (relay, &giaddr)) { + struct hostent *he; + he = gethostbyname (relay); + if (he) { + memcpy (&giaddr, he -> h_addr_list [0], + sizeof giaddr); + } else { + log_fatal ("%s: no such host", relay); + } + } + } + /* Default to the DHCP/BOOTP port. */ if (!local_port) { - ent = getservbyname ("dhcpc", "udp"); - if (!ent) - local_port = htons (68); - else - local_port = ent -> s_port; + if (relay && giaddr.s_addr != htonl (INADDR_LOOPBACK)) { + local_port = htons (67); + } else { + ent = getservbyname ("dhcpc", "udp"); + if (!ent) + local_port = htons (68); + else + local_port = ent -> s_port; #ifndef __CYGWIN32__ - endservent (); + endservent (); #endif + } } - remote_port = htons (ntohs (local_port) - 1); /* XXX */ + + /* If we're faking a relay agent, and we're not using loopback, + use the server port, not the client port. */ + if (relay && giaddr.s_addr != htonl (INADDR_LOOPBACK)) { + local_port = htons (ntohs (local_port) - 1); + remote_port = local_port; + } else + remote_port = htons (ntohs (local_port) - 1); /* XXX */ /* Get the current time... */ GET_TIME (&cur_time); sockaddr_broadcast.sin_family = AF_INET; sockaddr_broadcast.sin_port = remote_port; - sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST; -#ifdef HAVE_SA_LEN - sockaddr_broadcast.sin_len = sizeof sockaddr_broadcast; -#endif + if (server) { + if (!inet_aton (server, &sockaddr_broadcast.sin_addr)) { + struct hostent *he; + he = gethostbyname (server); + if (he) { + memcpy (&sockaddr_broadcast.sin_addr, + he -> h_addr_list [0], + sizeof sockaddr_broadcast.sin_addr); + } else + sockaddr_broadcast.sin_addr.s_addr = + INADDR_BROADCAST; + } + } else { + sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST; + } + inaddr_any.s_addr = INADDR_ANY; /* Discover all the network interfaces. */ @@ -219,17 +346,26 @@ int main (argc, argv, envp) /* Rewrite the lease database... */ rewrite_client_leases (); + /* XXX */ +/* config_counter(&snd_counter, &rcv_counter); */ + /* If no broadcast interfaces were discovered, call the script and tell it so. */ if (!interfaces) { - script_init ((struct interface_info *)0, "NBI", + /* Call dhclient-script with the NBI flag, in case somebody + cares. */ + script_init ((struct client_state *)0, "NBI", (struct string_list *)0); - script_go ((struct interface_info *)0); - - note ("No broadcast interfaces found - exiting."); - /* Nothing more to do. */ - exit (0); - } else { + script_go ((struct client_state *)0); + + /* If we haven't been asked to persist, waiting for new + interfaces, then just exit. */ + if (!persist) { + /* Nothing more to do. */ + log_info ("No broadcast interfaces found - exiting."); + exit (0); + } + } else if (!release_mode) { /* Call the script with the list of interfaces. */ for (ip = interfaces; ip; ip = ip -> next) { /* If interfaces were specified, don't configure @@ -239,11 +375,12 @@ int main (argc, argv, envp) INTERFACE_AUTOMATIC)) != INTERFACE_REQUESTED)) continue; - script_init (ip, "PREINIT", (struct string_list *)0); + script_init (ip -> client, + "PREINIT", (struct string_list *)0); if (ip -> client -> alias) - script_write_params (ip, "alias_", + script_write_params (ip -> client, "alias_", ip -> client -> alias); - script_go (ip); + script_go (ip -> client); } } @@ -260,25 +397,71 @@ int main (argc, argv, envp) interface's hardware address interpreted as an integer. Not much entropy, but we're booting, so we're not likely to find anything better. */ - seed = 0; /* Unfortunately, what's on the stack isn't random. :') */ + seed = 0; for (ip = interfaces; ip; ip = ip -> next) { int junk; memcpy (&junk, - &ip -> hw_address.haddr [ip -> hw_address.hlen - - sizeof seed], sizeof seed); + &ip -> hw_address.hbuf [ip -> hw_address.hlen - + sizeof seed], sizeof seed); seed += junk; } srandom (seed + cur_time); /* Start a configuration state machine for each interface. */ for (ip = interfaces; ip; ip = ip -> next) { - ip -> client -> state = S_INIT; - state_reboot (ip); + ip -> flags |= INTERFACE_RUNNING; + for (client = ip -> client; client; client = client -> next) { + if (release_mode) + do_release (client); + else { + client -> state = S_INIT; + /* Set up a timeout to start the initialization + process. */ + add_timeout (cur_time + random () % 5, + state_reboot, client, 0, 0); + } + } + } + + if (release_mode) + return 0; + + /* Start up a listener for the object management API protocol. */ + if (top_level_config.omapi_port != -1) { + listener = (omapi_object_t *)0; + result = omapi_generic_new (&listener, MDL); + if (result != ISC_R_SUCCESS) + log_fatal ("Can't allocate new generic object: %s\n", + isc_result_totext (result)); + result = omapi_protocol_listen (listener, + (unsigned) + top_level_config.omapi_port, + 1); + if (result != ISC_R_SUCCESS) + log_fatal ("Can't start OMAPI protocol: %s", + isc_result_totext (result)); } /* Set up the bootp packet handler... */ bootp_packet_handler = do_packet; +#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \ + defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) + dmalloc_cutoff_generation = dmalloc_generation; + dmalloc_longterm = dmalloc_outstanding; + dmalloc_outstanding = 0; +#endif + + /* If we're not supposed to wait before getting the address, + don't. */ + if (nowait) + go_daemon (); + + /* If we're not going to daemonize, write the pid file + now. */ + if (no_daemon || nowait) + write_client_pid_file (); + /* Start dispatching packets and timeouts... */ dispatch (); @@ -286,23 +469,51 @@ int main (argc, argv, envp) return 0; } -static void usage (appname) - char *appname; +static void usage () +{ + log_info ("%s %s", message, DHCP_VERSION); + log_info (copyright); + log_info (arr); + log_info (url); + + log_error ("Usage: dhclient [-1dqr] [-nw] [-p <port>] %s", + "[-s server]"); + log_error (" [-cf config-file] [-lf lease-file]%s", + "[-pf pid-file] [-e VAR=val]"); + log_fatal (" [-sf script-file] [interface]"); +} + +isc_result_t find_class (struct class **c, + const char *s, const char *file, int line) { - note (message); - note (copyright); - note (arr); - note (""); - note (contrib); - note (url); - note (""); - - warn ("Usage: %s [-c] [-p <port>] [-lf lease-file]", appname); - error (" [-pf pidfile] [interface]"); + return 0; } -void cleanup () +int check_collection (packet, lease, collection) + struct packet *packet; + struct lease *lease; + struct collection *collection; { + return 0; +} + +void classify (packet, class) + struct packet *packet; + struct class *class; +{ +} + +int unbill_class (lease, class) + struct lease *lease; + struct class *class; +{ + return 0; +} + +int find_subnet (struct subnet **sp, + struct iaddr addr, const char *file, int line) +{ + return 0; } /* Individual States: @@ -334,152 +545,141 @@ void cleanup () * can no longer legitimately use the lease. */ -void state_reboot (ipp) - void *ipp; +void state_reboot (cpp) + void *cpp; { - struct interface_info *ip = ipp; + struct client_state *client = cpp; /* If we don't remember an active lease, go straight to INIT. */ - if (!ip -> client -> active || - ip -> client -> active -> is_bootp) { - state_init (ip); + if (!client -> active || + client -> active -> is_bootp || + client -> active -> expiry <= cur_time) { + state_init (client); return; } /* We are in the rebooting state. */ - ip -> client -> state = S_REBOOTING; + client -> state = S_REBOOTING; /* make_request doesn't initialize xid because it normally comes from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER, so pick an xid now. */ - ip -> client -> xid = random (); + client -> xid = random (); /* Make a DHCPREQUEST packet, and set appropriate per-interface flags. */ - make_request (ip, ip -> client -> active); - ip -> client -> destination = iaddr_broadcast; - ip -> client -> first_sending = cur_time; - ip -> client -> interval = ip -> client -> config -> initial_interval; + make_request (client, client -> active); + client -> destination = iaddr_broadcast; + client -> first_sending = cur_time; + client -> interval = client -> config -> initial_interval; /* Zap the medium list... */ - ip -> client -> medium = (struct string_list *)0; + client -> medium = (struct string_list *)0; /* Send out the first DHCPREQUEST packet. */ - send_request (ip); + send_request (client); } /* Called when a lease has completely expired and we've been unable to renew it. */ -void state_init (ipp) - void *ipp; +void state_init (cpp) + void *cpp; { - struct interface_info *ip = ipp; + struct client_state *client = cpp; ASSERT_STATE(state, S_INIT); /* Make a DHCPDISCOVER packet, and set appropriate per-interface flags. */ - make_discover (ip, ip -> client -> active); - ip -> client -> xid = ip -> client -> packet.xid; - ip -> client -> destination = iaddr_broadcast; - ip -> client -> state = S_SELECTING; - ip -> client -> first_sending = cur_time; - ip -> client -> interval = ip -> client -> config -> initial_interval; + make_discover (client, client -> active); + client -> xid = client -> packet.xid; + client -> destination = iaddr_broadcast; + client -> state = S_SELECTING; + client -> first_sending = cur_time; + client -> interval = client -> config -> initial_interval; /* Add an immediate timeout to cause the first DHCPDISCOVER packet to go out. */ - send_discover (ip); + send_discover (client); } /* state_selecting is called when one or more DHCPOFFER packets have been received and a configurable period of time has passed. */ -void state_selecting (ipp) - void *ipp; +void state_selecting (cpp) + void *cpp; { - struct interface_info *ip = ipp; - + struct client_state *client = cpp; struct client_lease *lp, *next, *picked; + ASSERT_STATE(state, S_SELECTING); /* Cancel state_selecting and send_discover timeouts, since either one could have got us here. */ - cancel_timeout (state_selecting, ip); - cancel_timeout (send_discover, ip); + cancel_timeout (state_selecting, client); + cancel_timeout (send_discover, client); /* We have received one or more DHCPOFFER packets. Currently, the only criterion by which we judge leases is whether or not we get a response when we arp for them. */ picked = (struct client_lease *)0; - for (lp = ip -> client -> offered_leases; lp; lp = next) { + for (lp = client -> offered_leases; lp; lp = next) { next = lp -> next; /* Check to see if we got an ARPREPLY for the address in this particular lease. */ if (!picked) { - script_init (ip, "ARPCHECK", lp -> medium); - script_write_params (ip, "check_", lp); - - /* If the ARPCHECK code detects another - machine using the offered address, it exits - nonzero. We need to send a DHCPDECLINE and - toss the lease. */ - if (script_go (ip)) { - make_decline (ip, lp); - send_decline (ip); - goto freeit; - } picked = lp; picked -> next = (struct client_lease *)0; } else { freeit: - free_client_lease (lp); + destroy_client_lease (lp); } } - ip -> client -> offered_leases = (struct client_lease *)0; + client -> offered_leases = (struct client_lease *)0; /* If we just tossed all the leases we were offered, go back to square one. */ if (!picked) { - ip -> client -> state = S_INIT; - state_init (ip); + client -> state = S_INIT; + state_init (client); return; } /* If it was a BOOTREPLY, we can just take the address right now. */ - if (!picked -> options [DHO_DHCP_MESSAGE_TYPE].len) { - ip -> client -> new = picked; + if (picked -> is_bootp) { + client -> new = picked; /* Make up some lease expiry times XXX these should be configurable. */ - ip -> client -> new -> expiry = cur_time + 12000; - ip -> client -> new -> renewal += cur_time + 8000; - ip -> client -> new -> rebind += cur_time + 10000; + client -> new -> expiry = cur_time + 12000; + client -> new -> renewal += cur_time + 8000; + client -> new -> rebind += cur_time + 10000; - ip -> client -> state = S_REQUESTING; + client -> state = S_REQUESTING; /* Bind to the address we received. */ - bind_lease (ip); + bind_lease (client); return; } /* Go to the REQUESTING state. */ - ip -> client -> destination = iaddr_broadcast; - ip -> client -> state = S_REQUESTING; - ip -> client -> first_sending = cur_time; - ip -> client -> interval = ip -> client -> config -> initial_interval; + client -> destination = iaddr_broadcast; + client -> state = S_REQUESTING; + client -> first_sending = cur_time; + client -> interval = client -> config -> initial_interval; /* Make a DHCPREQUEST packet from the lease we picked. */ - make_request (ip, picked); - ip -> client -> xid = ip -> client -> packet.xid; + make_request (client, picked); + client -> xid = client -> packet.xid; /* Toss the lease we picked - we'll get it back in a DHCPACK. */ - free_client_lease (picked); + destroy_client_lease (picked); /* Add an immediate timeout to send the first DHCPREQUEST packet. */ - send_request (ip); + send_request (client); } /* state_requesting is called when we receive a DHCPACK message after @@ -489,128 +689,200 @@ void dhcpack (packet) struct packet *packet; { struct interface_info *ip = packet -> interface; + struct client_state *client; struct client_lease *lease; + struct option_cache *oc; + struct data_string ds; + int i; /* If we're not receptive to an offer right now, or if the offer has an unrecognizable transaction id, then just drop it. */ - if (packet -> interface -> client -> xid != packet -> raw -> xid || - (packet -> interface -> hw_address.hlen != + for (client = ip -> client; client; client = client -> next) { + if (client -> xid == packet -> raw -> xid) + break; + } + if (!client || + (packet -> interface -> hw_address.hlen - 1 != packet -> raw -> hlen) || - (memcmp (packet -> interface -> hw_address.haddr, + (memcmp (&packet -> interface -> hw_address.hbuf [1], packet -> raw -> chaddr, packet -> raw -> hlen))) { #if defined (DEBUG) - debug ("DHCPACK in wrong transaction."); + log_debug ("DHCPACK in wrong transaction."); #endif return; } - if (ip -> client -> state != S_REBOOTING && - ip -> client -> state != S_REQUESTING && - ip -> client -> state != S_RENEWING && - ip -> client -> state != S_REBINDING) { + if (client -> state != S_REBOOTING && + client -> state != S_REQUESTING && + client -> state != S_RENEWING && + client -> state != S_REBINDING) { #if defined (DEBUG) - debug ("DHCPACK in wrong state."); + log_debug ("DHCPACK in wrong state."); #endif return; } - note ("DHCPACK from %s", piaddr (packet -> client_addr)); + log_info ("DHCPACK from %s", piaddr (packet -> client_addr)); - lease = packet_to_lease (packet); + lease = packet_to_lease (packet, client); if (!lease) { - note ("packet_to_lease failed."); + log_info ("packet_to_lease failed."); return; } - ip -> client -> new = lease; + client -> new = lease; /* Stop resending DHCPREQUEST. */ - cancel_timeout (send_request, ip); + cancel_timeout (send_request, client); /* Figure out the lease time. */ - ip -> client -> new -> expiry = - getULong (ip -> client -> - new -> options [DHO_DHCP_LEASE_TIME].data); + oc = lookup_option (&dhcp_universe, client -> new -> options, + DHO_DHCP_LEASE_TIME); + memset (&ds, 0, sizeof ds); + if (oc && + evaluate_option_cache (&ds, packet, (struct lease *)0, client, + packet -> options, client -> new -> options, + &global_scope, oc, MDL)) { + if (ds.len > 3) + client -> new -> expiry = getULong (ds.data); + else + client -> new -> expiry = 0; + data_string_forget (&ds, MDL); + } else + client -> new -> expiry = 0; + + if (!client -> new -> expiry) { + log_error ("no expiry time on offered lease."); + /* XXX this is going to be bad - if this _does_ + XXX happen, we should probably dynamically + XXX disqualify the DHCP server that gave us the + XXX bad packet from future selections and + XXX then go back into the init state. */ + state_init (client); + return; + } + /* A number that looks negative here is really just very large, because the lease expiry offset is unsigned. */ - if (ip -> client -> new -> expiry < 0) - ip -> client -> new -> expiry = TIME_MAX; - - /* Take the server-provided renewal time if there is one; - otherwise figure it out according to the spec. */ - if (ip -> client -> new -> options [DHO_DHCP_RENEWAL_TIME].len) - ip -> client -> new -> renewal = - getULong (ip -> client -> - new -> options [DHO_DHCP_RENEWAL_TIME].data); - else - ip -> client -> new -> renewal = - ip -> client -> new -> expiry / 2; + if (client -> new -> expiry < 0) + client -> new -> expiry = TIME_MAX; + /* Take the server-provided renewal time if there is one. */ + oc = lookup_option (&dhcp_universe, client -> new -> options, + DHO_DHCP_RENEWAL_TIME); + if (oc && + evaluate_option_cache (&ds, packet, (struct lease *)0, client, + packet -> options, client -> new -> options, + &global_scope, oc, MDL)) { + if (ds.len > 3) + client -> new -> renewal = getULong (ds.data); + else + client -> new -> renewal = 0; + data_string_forget (&ds, MDL); + } else + client -> new -> renewal = 0; + + /* If it wasn't specified by the server, calculate it. */ + if (!client -> new -> renewal) + client -> new -> renewal = + client -> new -> expiry / 2; + + /* Now introduce some randomness to the renewal time: */ + client -> new -> renewal = (((client -> new -> renewal + 3) * 3 / 4) + + (random () % /* XXX NUMS */ + ((client -> new -> renewal + 3) / 4))); /* Same deal with the rebind time. */ - if (ip -> client -> new -> options [DHO_DHCP_REBINDING_TIME].len) - ip -> client -> new -> rebind = - getULong (ip -> client -> new -> - options [DHO_DHCP_REBINDING_TIME].data); - else - ip -> client -> new -> rebind = - ip -> client -> new -> renewal + - ip -> client -> new -> renewal / 2 + - ip -> client -> new -> renewal / 4; + oc = lookup_option (&dhcp_universe, client -> new -> options, + DHO_DHCP_REBINDING_TIME); + if (oc && + evaluate_option_cache (&ds, packet, (struct lease *)0, client, + packet -> options, client -> new -> options, + &global_scope, oc, MDL)) { + if (ds.len > 3) + client -> new -> rebind = getULong (ds.data); + else + client -> new -> rebind = 0; + data_string_forget (&ds, MDL); + } else + client -> new -> rebind = 0; + + if (!client -> new -> rebind) + client -> new -> rebind = + (client -> new -> expiry * 7) / 8; /* XXX NUMS */ + + /* Make sure our randomness didn't run the renewal time past the + rebind time. */ + if (client -> new -> renewal > client -> new -> rebind) + client -> new -> renewal = (client -> new -> rebind * 3) / 4; - ip -> client -> new -> expiry += cur_time; + client -> new -> expiry += cur_time; /* Lease lengths can never be negative. */ - if (ip -> client -> new -> expiry < cur_time) - ip -> client -> new -> expiry = TIME_MAX; - ip -> client -> new -> renewal += cur_time; - if (ip -> client -> new -> renewal < cur_time) - ip -> client -> new -> renewal = TIME_MAX; - ip -> client -> new -> rebind += cur_time; - if (ip -> client -> new -> rebind < cur_time) - ip -> client -> new -> rebind = TIME_MAX; - - bind_lease (ip); + if (client -> new -> expiry < cur_time) + client -> new -> expiry = TIME_MAX; + client -> new -> renewal += cur_time; + if (client -> new -> renewal < cur_time) + client -> new -> renewal = TIME_MAX; + client -> new -> rebind += cur_time; + if (client -> new -> rebind < cur_time) + client -> new -> rebind = TIME_MAX; + + bind_lease (client); } -void bind_lease (ip) - struct interface_info *ip; +void bind_lease (client) + struct client_state *client; { - /* Remember the medium. */ - ip -> client -> new -> medium = ip -> client -> medium; + struct interface_info *ip = client -> interface; - /* Write out the new lease. */ - write_client_lease (ip, ip -> client -> new, 0); + /* Remember the medium. */ + client -> new -> medium = client -> medium; /* Run the client script with the new parameters. */ - script_init (ip, (ip -> client -> state == S_REQUESTING + script_init (client, (client -> state == S_REQUESTING ? "BOUND" - : (ip -> client -> state == S_RENEWING + : (client -> state == S_RENEWING ? "RENEW" - : (ip -> client -> state == S_REBOOTING + : (client -> state == S_REBOOTING ? "REBOOT" : "REBIND"))), - ip -> client -> new -> medium); - if (ip -> client -> active && ip -> client -> state != S_REBOOTING) - script_write_params (ip, "old_", ip -> client -> active); - script_write_params (ip, "new_", ip -> client -> new); - if (ip -> client -> alias) - script_write_params (ip, "alias_", ip -> client -> alias); - script_go (ip); + client -> new -> medium); + if (client -> active && client -> state != S_REBOOTING) + script_write_params (client, "old_", client -> active); + script_write_params (client, "new_", client -> new); + if (client -> alias) + script_write_params (client, "alias_", client -> alias); + + /* If the BOUND/RENEW code detects another machine using the + offered address, it exits nonzero. We need to send a + DHCPDECLINE and toss the lease. */ + if (script_go (client)) { + make_decline (client, client -> new); + send_decline (client); + destroy_client_lease (client -> new); + client -> new = (struct client_lease *)0; + state_init (client); + return; + } + + /* Write out the new lease. */ + write_client_lease (client, client -> new, 0, 0); /* Replace the old active lease with the new one. */ - if (ip -> client -> active) - free_client_lease (ip -> client -> active); - ip -> client -> active = ip -> client -> new; - ip -> client -> new = (struct client_lease *)0; + if (client -> active) + destroy_client_lease (client -> active); + client -> active = client -> new; + client -> new = (struct client_lease *)0; /* Set up a timeout to start the renewal process. */ - add_timeout (ip -> client -> active -> renewal, - state_bound, ip); + add_timeout (client -> active -> renewal, + state_bound, client, 0, 0); - note ("bound to %s -- renewal in %d seconds.", - piaddr (ip -> client -> active -> address), - ip -> client -> active -> renewal - cur_time); - ip -> client -> state = S_BOUND; + log_info ("bound to %s -- renewal in %ld seconds.", + piaddr (client -> active -> address), + (long)(client -> active -> renewal - cur_time)); + client -> state = S_BOUND; reinitialize_interfaces (); go_daemon (); + client_dns_update (client, 1); } /* state_bound is called when we've successfully bound to a particular @@ -618,32 +890,68 @@ void bind_lease (ip) expected to unicast a DHCPREQUEST to the server that gave us our original lease. */ -void state_bound (ipp) - void *ipp; +void state_bound (cpp) + void *cpp; { - struct interface_info *ip = ipp; + struct client_state *client = cpp; + int i; + struct option_cache *oc; + struct data_string ds; ASSERT_STATE(state, S_BOUND); /* T1 has expired. */ - make_request (ip, ip -> client -> active); - ip -> client -> xid = ip -> client -> packet.xid; - - if (ip -> client -> active -> - options [DHO_DHCP_SERVER_IDENTIFIER].len == 4) { - memcpy (ip -> client -> destination.iabuf, - ip -> client -> active -> - options [DHO_DHCP_SERVER_IDENTIFIER].data, 4); - ip -> client -> destination.len = 4; + make_request (client, client -> active); + client -> xid = client -> packet.xid; + + memset (&ds, 0, sizeof ds); + oc = lookup_option (&dhcp_universe, client -> active -> options, + DHO_DHCP_SERVER_IDENTIFIER); + if (oc && + evaluate_option_cache (&ds, (struct packet *)0, (struct lease *)0, + client, (struct option_state *)0, + client -> active -> options, + &global_scope, oc, MDL)) { + if (ds.len > 3) { + memcpy (client -> destination.iabuf, ds.data, 4); + client -> destination.len = 4; + } else + client -> destination = iaddr_broadcast; } else - ip -> client -> destination = iaddr_broadcast; + client -> destination = iaddr_broadcast; - ip -> client -> first_sending = cur_time; - ip -> client -> interval = ip -> client -> config -> initial_interval; - ip -> client -> state = S_RENEWING; + client -> first_sending = cur_time; + client -> interval = client -> config -> initial_interval; + client -> state = S_RENEWING; /* Send the first packet immediately. */ - send_request (ip); + send_request (client); +} + +/* state_stop is called when we've been told to shut down. We unconfigure + the interfaces, and then stop operating until told otherwise. */ + +void state_stop (cpp) + void *cpp; +{ + struct client_state *client = cpp; + int i; + + /* Cancel all timeouts. */ + cancel_timeout (state_selecting, client); + cancel_timeout (send_discover, client); + cancel_timeout (send_request, client); + cancel_timeout (state_bound, client); + + /* If we have an address, unconfigure it. */ + if (client -> active) { + script_init (client, "STOP", client -> active -> medium); + script_write_params (client, "old_", client -> active); + if (client -> alias) + script_write_params (client, "alias_", + client -> alias); + script_go (client); + } } int commit_leases () @@ -657,7 +965,14 @@ int write_lease (lease) return 0; } -void db_startup () +int write_host (host) + struct host_decl *host; +{ + return 0; +} + +void db_startup (testp) + int testp; { } @@ -674,7 +989,7 @@ void bootp (packet) for (ap = packet -> interface -> client -> config -> reject_list; ap; ap = ap -> next) { if (addr_eq (packet -> client_addr, ap -> addr)) { - note ("BOOTREPLY from %s rejected.", + log_info ("BOOTREPLY from %s rejected.", piaddr (ap -> addr)); return; } @@ -689,7 +1004,7 @@ void dhcp (packet) { struct iaddrlist *ap; void (*handler) PROTO ((struct packet *)); - char *type; + const char *type; switch (packet -> packet_type) { case DHCPOFFER: @@ -716,7 +1031,7 @@ void dhcp (packet) for (ap = packet -> interface -> client -> config -> reject_list; ap; ap = ap -> next) { if (addr_eq (packet -> client_addr, ap -> addr)) { - note ("%s from %s rejected.", + log_info ("%s from %s rejected.", type, piaddr (ap -> addr)); return; } @@ -728,186 +1043,196 @@ void dhcpoffer (packet) struct packet *packet; { struct interface_info *ip = packet -> interface; + struct client_state *client; struct client_lease *lease, *lp; int i; - int arp_timeout_needed, stop_selecting; - char *name = (packet -> options [DHO_DHCP_MESSAGE_TYPE].len - ? "DHCPOFFER" : "BOOTREPLY"); + int stop_selecting; + const char *name = packet -> packet_type ? "DHCPOFFER" : "BOOTREPLY"; + struct iaddrlist *ap; + struct option_cache *oc; + char obuf [1024]; #ifdef DEBUG_PACKET dump_packet (packet); #endif + /* Find a client state that matches the xid... */ + for (client = ip -> client; client; client = client -> next) + if (client -> xid == packet -> raw -> xid) + break; + /* If we're not receptive to an offer right now, or if the offer has an unrecognizable transaction id, then just drop it. */ - if (ip -> client -> state != S_SELECTING || - packet -> interface -> client -> xid != packet -> raw -> xid || - (packet -> interface -> hw_address.hlen != + if (!client || + client -> state != S_SELECTING || + (packet -> interface -> hw_address.hlen - 1 != packet -> raw -> hlen) || - (memcmp (packet -> interface -> hw_address.haddr, + (memcmp (&packet -> interface -> hw_address.hbuf [1], packet -> raw -> chaddr, packet -> raw -> hlen))) { #if defined (DEBUG) - debug ("%s in wrong transaction.", name); + log_debug ("%s in wrong transaction.", name); #endif return; } - note ("%s from %s", name, piaddr (packet -> client_addr)); + sprintf (obuf, "%s from %s", name, piaddr (packet -> client_addr)); /* If this lease doesn't supply the minimum required parameters, blow it off. */ - for (i = 0; ip -> client -> config -> required_options [i]; i++) { - if (!packet -> options [ip -> client -> config -> - required_options [i]].len) { - note ("%s isn't satisfactory.", name); - return; + if (client -> config -> required_options) { + for (i = 0; client -> config -> required_options [i]; i++) { + if (!lookup_option + (&dhcp_universe, packet -> options, + client -> config -> required_options [i])) { + log_info ("%s: no %s option.", + obuf, (dhcp_universe.options + [client -> config -> required_options [i]] + -> name)); + return; + } } } /* If we've already seen this lease, don't record it again. */ - for (lease = ip -> client -> offered_leases; - lease; lease = lease -> next) { + for (lease = client -> offered_leases; lease; lease = lease -> next) { if (lease -> address.len == sizeof packet -> raw -> yiaddr && !memcmp (lease -> address.iabuf, &packet -> raw -> yiaddr, lease -> address.len)) { - debug ("%s already seen.", name); + log_debug ("%s: already seen.", obuf); return; } } - lease = packet_to_lease (packet); + lease = packet_to_lease (packet, client); if (!lease) { - note ("packet_to_lease failed."); + log_info ("%s: packet_to_lease failed.", obuf); return; } /* If this lease was acquired through a BOOTREPLY, record that fact. */ - if (!packet -> options [DHO_DHCP_MESSAGE_TYPE].len) + if (!packet -> options_valid || !packet -> packet_type) lease -> is_bootp = 1; /* Record the medium under which this lease was offered. */ - lease -> medium = ip -> client -> medium; - - /* Send out an ARP Request for the offered IP address. */ - script_init (ip, "ARPSEND", lease -> medium); - script_write_params (ip, "check_", lease); - /* If the script can't send an ARP request without waiting, - we'll be waiting when we do the ARPCHECK, so don't wait now. */ - if (script_go (ip)) - arp_timeout_needed = 0; - else - arp_timeout_needed = 2; + lease -> medium = client -> medium; /* Figure out when we're supposed to stop selecting. */ - stop_selecting = (ip -> client -> first_sending + - ip -> client -> config -> select_interval); + stop_selecting = (client -> first_sending + + client -> config -> select_interval); /* If this is the lease we asked for, put it at the head of the list, and don't mess with the arp request timeout. */ - if (lease -> address.len == ip -> client -> requested_address.len && + if (lease -> address.len == client -> requested_address.len && !memcmp (lease -> address.iabuf, - ip -> client -> requested_address.iabuf, - ip -> client -> requested_address.len)) { - lease -> next = ip -> client -> offered_leases; - ip -> client -> offered_leases = lease; + client -> requested_address.iabuf, + client -> requested_address.len)) { + lease -> next = client -> offered_leases; + client -> offered_leases = lease; } else { - /* If we already have an offer, and arping for this - offer would take us past the selection timeout, - then don't extend the timeout - just hope for the - best. */ - if (ip -> client -> offered_leases && - (cur_time + arp_timeout_needed) > stop_selecting) - arp_timeout_needed = 0; - /* Put the lease at the end of the list. */ lease -> next = (struct client_lease *)0; - if (!ip -> client -> offered_leases) - ip -> client -> offered_leases = lease; + if (!client -> offered_leases) + client -> offered_leases = lease; else { - for (lp = ip -> client -> offered_leases; lp -> next; + for (lp = client -> offered_leases; lp -> next; lp = lp -> next) ; lp -> next = lease; } } - /* If we're supposed to stop selecting before we've had time - to wait for the ARPREPLY, add some delay to wait for - the ARPREPLY. */ - if (stop_selecting - cur_time < arp_timeout_needed) - stop_selecting = cur_time + arp_timeout_needed; - /* If the selecting interval has expired, go immediately to state_selecting(). Otherwise, time out into state_selecting at the select interval. */ if (stop_selecting <= 0) - state_selecting (ip); + state_selecting (client); else { - add_timeout (stop_selecting, state_selecting, ip); - cancel_timeout (send_discover, ip); + add_timeout (stop_selecting, state_selecting, client, 0, 0); + cancel_timeout (send_discover, client); } + log_info ("%s", obuf); } /* Allocate a client_lease structure and initialize it from the parameters in the specified packet. */ -struct client_lease *packet_to_lease (packet) +struct client_lease *packet_to_lease (packet, client) struct packet *packet; + struct client_state *client; { struct client_lease *lease; - int i; + unsigned i; + struct option_cache *oc; + struct data_string data; - lease = (struct client_lease *)malloc (sizeof (struct client_lease)); + lease = (struct client_lease *)new_client_lease (MDL); if (!lease) { - warn ("dhcpoffer: no memory to record lease.\n"); + log_error ("packet_to_lease: no memory to record lease.\n"); return (struct client_lease *)0; } memset (lease, 0, sizeof *lease); /* Copy the lease options. */ - for (i = 0; i < 256; i++) { - if (packet -> options [i].len) { - lease -> options [i].data = - (unsigned char *) - malloc (packet -> options [i].len + 1); - if (!lease -> options [i].data) { - warn ("dhcpoffer: no memory for option %d\n", - i); - free_client_lease (lease); - return (struct client_lease *)0; - } else { - memcpy (lease -> options [i].data, - packet -> options [i].data, - packet -> options [i].len); - lease -> options [i].len = - packet -> options [i].len; - lease -> options [i].data - [lease -> options [i].len] = 0; - } - } - } + option_state_reference (&lease -> options, packet -> options, MDL); lease -> address.len = sizeof (packet -> raw -> yiaddr); memcpy (lease -> address.iabuf, &packet -> raw -> yiaddr, lease -> address.len); + if (client -> config -> vendor_space_name) { + i = DHO_VENDOR_ENCAPSULATED_OPTIONS; + + /* See if there was a vendor encapsulation option. */ + oc = lookup_option (&dhcp_universe, lease -> options, i); + memset (&data, 0, sizeof data); + if (oc && + client -> config -> vendor_space_name && + evaluate_option_cache (&data, packet, + (struct lease *)0, client, + packet -> options, lease -> options, + &global_scope, oc, MDL)) { + if (data.len) { + parse_encapsulated_suboptions + (packet -> options, &dhcp_options [i], + data.data, data.len, &dhcp_universe, + client -> config -> vendor_space_name + ); + } + data_string_forget (&data, MDL); + } + } else + i = 0; + + /* Figure out the overload flag. */ + oc = lookup_option (&dhcp_universe, lease -> options, + DHO_DHCP_OPTION_OVERLOAD); + if (oc && + evaluate_option_cache (&data, packet, (struct lease *)0, client, + packet -> options, lease -> options, + &global_scope, oc, MDL)) { + if (data.len > 0) + i = data.data [0]; + else + i = 0; + data_string_forget (&data, MDL); + } else + i = 0; + /* If the server name was filled out, copy it. */ - if ((!packet -> options [DHO_DHCP_OPTION_OVERLOAD].len || - !(packet -> options [DHO_DHCP_OPTION_OVERLOAD].data [0] & 2)) && - packet -> raw -> sname [0]) { - int len; + if (!(i & 2) && packet -> raw -> sname [0]) { + unsigned len; /* Don't count on the NUL terminator. */ for (len = 0; len < 64; len++) if (!packet -> raw -> sname [len]) break; - lease -> server_name = malloc (len + 1); + lease -> server_name = dmalloc (len + 1, MDL); if (!lease -> server_name) { - warn ("dhcpoffer: no memory for filename.\n"); - free_client_lease (lease); + log_error ("dhcpoffer: no memory for filename.\n"); + destroy_client_lease (lease); return (struct client_lease *)0; } else { memcpy (lease -> server_name, @@ -917,18 +1242,16 @@ struct client_lease *packet_to_lease (packet) } /* Ditto for the filename. */ - if ((!packet -> options [DHO_DHCP_OPTION_OVERLOAD].len || - !(packet -> options [DHO_DHCP_OPTION_OVERLOAD].data [0] & 1)) && - packet -> raw -> file [0]) { - int len; + if (!(i & 1) && packet -> raw -> file [0]) { + unsigned len; /* Don't count on the NUL terminator. */ for (len = 0; len < 64; len++) if (!packet -> raw -> file [len]) break; - lease -> filename = malloc (len + 1); + lease -> filename = dmalloc (len + 1, MDL); if (!lease -> filename) { - warn ("dhcpoffer: no memory for filename.\n"); - free_client_lease (lease); + log_error ("dhcpoffer: no memory for filename.\n"); + destroy_client_lease (lease); return (struct client_lease *)0; } else { memcpy (lease -> filename, @@ -936,6 +1259,15 @@ struct client_lease *packet_to_lease (packet) lease -> filename [len] = 0; } } + + execute_statements_in_scope ((struct binding_value **)0, + (struct packet *)packet, + (struct lease *)0, client, + lease -> options, lease -> options, + &global_scope, + client -> config -> on_receipt, + (struct group *)0); + return lease; } @@ -943,95 +1275,103 @@ void dhcpnak (packet) struct packet *packet; { struct interface_info *ip = packet -> interface; + struct client_state *client; + + /* Find a client state that matches the xid... */ + for (client = ip -> client; client; client = client -> next) + if (client -> xid == packet -> raw -> xid) + break; /* If we're not receptive to an offer right now, or if the offer has an unrecognizable transaction id, then just drop it. */ - if (packet -> interface -> client -> xid != packet -> raw -> xid || - (packet -> interface -> hw_address.hlen != + if (!client || + (packet -> interface -> hw_address.hlen - 1 != packet -> raw -> hlen) || - (memcmp (packet -> interface -> hw_address.haddr, + (memcmp (&packet -> interface -> hw_address.hbuf [1], packet -> raw -> chaddr, packet -> raw -> hlen))) { #if defined (DEBUG) - debug ("DHCPNAK in wrong transaction."); + log_debug ("DHCPNAK in wrong transaction."); #endif return; } - if (ip -> client -> state != S_REBOOTING && - ip -> client -> state != S_REQUESTING && - ip -> client -> state != S_RENEWING && - ip -> client -> state != S_REBINDING) { + if (client -> state != S_REBOOTING && + client -> state != S_REQUESTING && + client -> state != S_RENEWING && + client -> state != S_REBINDING) { #if defined (DEBUG) - debug ("DHCPNAK in wrong state."); + log_debug ("DHCPNAK in wrong state."); #endif return; } - note ("DHCPNAK from %s", piaddr (packet -> client_addr)); + log_info ("DHCPNAK from %s", piaddr (packet -> client_addr)); - if (!ip -> client -> active) { - note ("DHCPNAK with no active lease.\n"); + if (!client -> active) { +#if defined (DEBUG) + log_info ("DHCPNAK with no active lease.\n"); +#endif return; } - free_client_lease (ip -> client -> active); - ip -> client -> active = (struct client_lease *)0; + destroy_client_lease (client -> active); + client -> active = (struct client_lease *)0; /* Stop sending DHCPREQUEST packets... */ - cancel_timeout (send_request, ip); + cancel_timeout (send_request, client); - ip -> client -> state = S_INIT; - state_init (ip); + client -> state = S_INIT; + state_init (client); } /* Send out a DHCPDISCOVER packet, and set a timeout to send out another one after the right interval has expired. If we don't get an offer by the time we reach the panic interval, call the panic function. */ -void send_discover (ipp) - void *ipp; +void send_discover (cpp) + void *cpp; { - struct interface_info *ip = ipp; + struct client_state *client = cpp; int result; int interval; int increase = 1; /* Figure out how long it's been since we started transmitting. */ - interval = cur_time - ip -> client -> first_sending; + interval = cur_time - client -> first_sending; /* If we're past the panic timeout, call the script and tell it we haven't found anything for this interface yet. */ - if (interval > ip -> client -> config -> timeout) { - state_panic (ip); + if (interval > client -> config -> timeout) { + state_panic (client); return; } /* If we're selecting media, try the whole list before doing the exponential backoff, but if we've already received an offer, stop looping, because we obviously have it right. */ - if (!ip -> client -> offered_leases && - ip -> client -> config -> media) { + if (!client -> offered_leases && + client -> config -> media) { int fail = 0; again: - if (ip -> client -> medium) { - ip -> client -> medium = - ip -> client -> medium -> next; + if (client -> medium) { + client -> medium = client -> medium -> next; increase = 0; } - if (!ip -> client -> medium) { + if (!client -> medium) { if (fail) - error ("No valid media types for %s!", - ip -> name); - ip -> client -> medium = - ip -> client -> config -> media; + log_fatal ("No valid media types for %s!", + client -> interface -> name); + client -> medium = + client -> config -> media; increase = 1; } - note ("Trying medium \"%s\" %d", - ip -> client -> medium -> string, increase); - script_init (ip, "MEDIUM", ip -> client -> medium); - if (script_go (ip)) { + log_info ("Trying medium \"%s\" %d", + client -> medium -> string, increase); + script_init (client, "MEDIUM", client -> medium); + if (script_go (client)) { + fail = 1; goto again; } } @@ -1042,54 +1382,52 @@ void send_discover (ipp) zero and two times itself. On average, this means that it will double with every transmission. */ if (increase) { - if (!ip -> client -> interval) - ip -> client -> interval = - ip -> client -> config -> initial_interval; - else { - ip -> client -> interval += - ((random () >> 2) % - (2 * ip -> client -> interval)); - } + if (!client -> interval) + client -> interval = + client -> config -> initial_interval; + else + client -> interval += ((random () >> 2) % + (2 * client -> interval)); /* Don't backoff past cutoff. */ - if (ip -> client -> interval > - ip -> client -> config -> backoff_cutoff) - ip -> client -> interval = - ((ip -> client -> config -> backoff_cutoff / 2) + if (client -> interval > + client -> config -> backoff_cutoff) + client -> interval = + ((client -> config -> backoff_cutoff / 2) + ((random () >> 2) % - ip -> client -> config -> backoff_cutoff)); - } else if (!ip -> client -> interval) - ip -> client -> interval = - ip -> client -> config -> initial_interval; + client -> config -> backoff_cutoff)); + } else if (!client -> interval) + client -> interval = client -> config -> initial_interval; /* If the backoff would take us to the panic timeout, just use that as the interval. */ - if (cur_time + ip -> client -> interval > - ip -> client -> first_sending + ip -> client -> config -> timeout) - ip -> client -> interval = - (ip -> client -> first_sending + - ip -> client -> config -> timeout) - cur_time + 1; + if (cur_time + client -> interval > + client -> first_sending + client -> config -> timeout) + client -> interval = + (client -> first_sending + + client -> config -> timeout) - cur_time + 1; /* Record the number of seconds since we started sending. */ if (interval < 65536) - ip -> client -> packet.secs = htons (interval); + client -> packet.secs = htons (interval); else - ip -> client -> packet.secs = htons (65535); - ip -> client -> secs = ip -> client -> packet.secs; + client -> packet.secs = htons (65535); + client -> secs = client -> packet.secs; - note ("DHCPDISCOVER on %s to %s port %d interval %ld", - ip -> name, + log_info ("DHCPDISCOVER on %s to %s port %d interval %ld", + client -> name ? client -> name : client -> interface -> name, inet_ntoa (sockaddr_broadcast.sin_addr), - ntohs (sockaddr_broadcast.sin_port), ip -> client -> interval); + ntohs (sockaddr_broadcast.sin_port), (long)(client -> interval)); /* Send out a packet. */ - result = send_packet (ip, (struct packet *)0, - &ip -> client -> packet, - ip -> client -> packet_length, + result = send_packet (client -> interface, (struct packet *)0, + &client -> packet, + client -> packet_length, inaddr_any, &sockaddr_broadcast, (struct hardware *)0); - add_timeout (cur_time + ip -> client -> interval, send_discover, ip); + add_timeout (cur_time + client -> interval, + send_discover, client, 0, 0); } /* state_panic gets called if we haven't received any offers in a preset @@ -1097,106 +1435,113 @@ void send_discover (ipp) haven't yet expired, and failing that, we call the client script and hope it can do something. */ -void state_panic (ipp) - void *ipp; +void state_panic (cpp) + void *cpp; { - struct interface_info *ip = ipp; - - struct client_lease *loop = ip -> client -> active; + struct client_state *client = cpp; + struct client_lease *loop; struct client_lease *lp; - note ("No DHCPOFFERS received."); + loop = lp = client -> active; + + log_info ("No DHCPOFFERS received."); /* We may not have an active lease, but we may have some predefined leases that we can try. */ - if (!ip -> client -> active && ip -> client -> leases) + if (!client -> active && client -> leases) goto activate_next; /* Run through the list of leases and see if one can be used. */ - while (ip -> client -> active) { - if (ip -> client -> active -> expiry > cur_time) { - note ("Trying recorded lease %s", - piaddr (ip -> client -> active -> address)); + while (client -> active) { + if (client -> active -> expiry > cur_time) { + log_info ("Trying recorded lease %s", + piaddr (client -> active -> address)); /* Run the client script with the existing parameters. */ - script_init (ip, "TIMEOUT", - ip -> client -> active -> medium); - script_write_params (ip, "new_", - ip -> client -> active); - if (ip -> client -> alias) - script_write_params (ip, "alias_", - ip -> client -> alias); + script_init (client, "TIMEOUT", + client -> active -> medium); + script_write_params (client, "new_", client -> active); + if (client -> alias) + script_write_params (client, "alias_", + client -> alias); /* If the old lease is still good and doesn't yet need renewal, go into BOUND state and timeout at the renewal time. */ - if (!script_go (ip)) { - if (cur_time < - ip -> client -> active -> renewal) { - ip -> client -> state = S_BOUND; - note ("bound: renewal in %d seconds.", - ip -> client -> active -> renewal - - cur_time); - add_timeout ((ip -> client -> - active -> renewal), - state_bound, ip); - } else { - ip -> client -> state = S_BOUND; - note ("bound: immediate renewal."); - state_bound (ip); - } - reinitialize_interfaces (); - go_daemon (); - return; + if (!script_go (client)) { + if (cur_time < client -> active -> renewal) { + client -> state = S_BOUND; + log_info ("bound: renewal in %ld %s.", + (long)(client -> active -> renewal - + cur_time), "seconds"); + add_timeout (client -> active -> renewal, + state_bound, client, 0, 0); + } else { + client -> state = S_BOUND; + log_info ("bound: immediate renewal."); + state_bound (client); + } + reinitialize_interfaces (); + go_daemon (); + return; } } /* If there are no other leases, give up. */ - if (!ip -> client -> leases) { - ip -> client -> leases = ip -> client -> active; - ip -> client -> active = (struct client_lease *)0; + if (!client -> leases) { + client -> leases = client -> active; + client -> active = (struct client_lease *)0; break; } activate_next: /* Otherwise, put the active lease at the end of the lease list, and try another lease.. */ - for (lp = ip -> client -> leases; lp -> next; lp = lp -> next) + for (lp = client -> leases; lp -> next; lp = lp -> next) ; - lp -> next = ip -> client -> active; + lp -> next = client -> active; if (lp -> next) { lp -> next -> next = (struct client_lease *)0; } - ip -> client -> active = ip -> client -> leases; - ip -> client -> leases = ip -> client -> leases -> next; + client -> active = client -> leases; + client -> leases = client -> leases -> next; /* If we already tried this lease, we've exhausted the set of leases, so we might as well give up for now. */ - if (ip -> client -> active == loop) + if (client -> active == loop) break; else if (!loop) - loop = ip -> client -> active; + loop = client -> active; } /* No leases were available, or what was available didn't work, so tell the shell script that we failed to allocate an address, and try again later. */ - note ("No working leases in persistent database - sleeping.\n"); - script_init (ip, "FAIL", (struct string_list *)0); - if (ip -> client -> alias) - script_write_params (ip, "alias_", ip -> client -> alias); - script_go (ip); - ip -> client -> state = S_INIT; - add_timeout (cur_time + ip -> client -> config -> retry_interval, - state_init, ip); + if (onetry) { + if (!quiet) + log_info ("Unable to obtain a lease on first try.%s", + " Exiting."); + exit (2); + } + + log_info ("No working leases in persistent database - sleeping."); + script_init (client, "FAIL", (struct string_list *)0); + if (client -> alias) + script_write_params (client, "alias_", client -> alias); + script_go (client); + client -> state = S_INIT; + add_timeout (cur_time + + ((client -> config -> retry_interval + 1) / 2 + + (random () % client -> config -> retry_interval)), + state_init, client, 0, 0); go_daemon (); } -void send_request (ipp) - void *ipp; +void send_request (cpp) + void *cpp; { - struct interface_info *ip = ipp; + struct client_state *client = cpp; int result; int interval; @@ -1204,7 +1549,7 @@ void send_request (ipp) struct in_addr from; /* Figure out how long it's been since we started transmitting. */ - interval = cur_time - ip -> client -> first_sending; + interval = cur_time - client -> first_sending; /* If we're in the INIT-REBOOT or REQUESTING state and we're past the reboot timeout, go to INIT and see if we can @@ -1216,91 +1561,87 @@ void send_request (ipp) us a new address, but we could also have successfully reused our old address. In the former case, we're hosed anyway. This is not a win-prone situation. */ - if ((ip -> client -> state == S_REBOOTING || - ip -> client -> state == S_REQUESTING) && - interval > ip -> client -> config -> reboot_timeout) { + if ((client -> state == S_REBOOTING || + client -> state == S_REQUESTING) && + interval > client -> config -> reboot_timeout) { cancel: - ip -> client -> state = S_INIT; - cancel_timeout (send_request, ip); - state_init (ip); + client -> state = S_INIT; + cancel_timeout (send_request, client); + state_init (client); return; } /* If we're in the reboot state, make sure the media is set up correctly. */ - if (ip -> client -> state == S_REBOOTING && - !ip -> client -> medium && - ip -> client -> active -> medium ) { - script_init (ip, "MEDIUM", ip -> client -> active -> medium); + if (client -> state == S_REBOOTING && + !client -> medium && + client -> active -> medium ) { + script_init (client, "MEDIUM", client -> active -> medium); /* If the medium we chose won't fly, go to INIT state. */ - if (script_go (ip)) + if (script_go (client)) goto cancel; /* Record the medium. */ - ip -> client -> medium = ip -> client -> active -> medium; + client -> medium = client -> active -> medium; } /* If the lease has expired, relinquish the address and go back to the INIT state. */ - if (ip -> client -> state != S_REQUESTING && - cur_time > ip -> client -> active -> expiry) { + if (client -> state != S_REQUESTING && + cur_time > client -> active -> expiry) { /* Run the client script with the new parameters. */ - script_init (ip, "EXPIRE", (struct string_list *)0); - script_write_params (ip, "old_", ip -> client -> active); - if (ip -> client -> alias) - script_write_params (ip, "alias_", - ip -> client -> alias); - script_go (ip); + script_init (client, "EXPIRE", (struct string_list *)0); + script_write_params (client, "old_", client -> active); + if (client -> alias) + script_write_params (client, "alias_", + client -> alias); + script_go (client); /* Now do a preinit on the interface so that we can discover a new address. */ - script_init (ip, "PREINIT", (struct string_list *)0); - if (ip -> client -> alias) - script_write_params (ip, "alias_", - ip -> client -> alias); - script_go (ip); - - ip -> client -> state = S_INIT; - state_init (ip); + script_init (client, "PREINIT", (struct string_list *)0); + if (client -> alias) + script_write_params (client, "alias_", + client -> alias); + script_go (client); + + client -> state = S_INIT; + state_init (client); return; } /* Do the exponential backoff... */ - if (!ip -> client -> interval) - ip -> client -> interval = - ip -> client -> config -> initial_interval; + if (!client -> interval) + client -> interval = client -> config -> initial_interval; else { - ip -> client -> interval += - ((random () >> 2) % - (2 * ip -> client -> interval)); + client -> interval += ((random () >> 2) % + (2 * client -> interval)); } /* Don't backoff past cutoff. */ - if (ip -> client -> interval > - ip -> client -> config -> backoff_cutoff) - ip -> client -> interval = - ((ip -> client -> config -> backoff_cutoff / 2) - + ((random () >> 2) - % ip -> client -> interval)); + if (client -> interval > + client -> config -> backoff_cutoff) + client -> interval = + ((client -> config -> backoff_cutoff / 2) + + ((random () >> 2) % client -> interval)); /* If the backoff would take us to the expiry time, just set the timeout to the expiry time. */ - if (ip -> client -> state != S_REQUESTING && - cur_time + ip -> client -> interval > - ip -> client -> active -> expiry) - ip -> client -> interval = - ip -> client -> active -> expiry - cur_time + 1; + if (client -> state != S_REQUESTING && + cur_time + client -> interval > client -> active -> expiry) + client -> interval = + client -> active -> expiry - cur_time + 1; /* If the lease T2 time has elapsed, or if we're not yet bound, broadcast the DHCPREQUEST rather than unicasting. */ - if (ip -> client -> state == S_REQUESTING || - ip -> client -> state == S_REBOOTING || - cur_time > ip -> client -> active -> rebind) - destination.sin_addr.s_addr = INADDR_BROADCAST; + if (client -> state == S_REQUESTING || + client -> state == S_REBOOTING || + cur_time > client -> active -> rebind) + destination.sin_addr = sockaddr_broadcast.sin_addr; else memcpy (&destination.sin_addr.s_addr, - ip -> client -> destination.iabuf, + client -> destination.iabuf, sizeof destination.sin_addr.s_addr); destination.sin_port = remote_port; destination.sin_family = AF_INET; @@ -1308,23 +1649,25 @@ void send_request (ipp) destination.sin_len = sizeof destination; #endif - if (ip -> client -> state != S_REQUESTING) - memcpy (&from, ip -> client -> active -> address.iabuf, + if (client -> state == S_RENEWING || + client -> state == S_REBINDING) + memcpy (&from, client -> active -> address.iabuf, sizeof from); else from.s_addr = INADDR_ANY; /* Record the number of seconds since we started sending. */ - if (ip -> client -> state == S_REQUESTING) - ip -> client -> packet.secs = ip -> client -> secs; + if (client -> state == S_REQUESTING) + client -> packet.secs = client -> secs; else { if (interval < 65536) - ip -> client -> packet.secs = htons (interval); + client -> packet.secs = htons (interval); else - ip -> client -> packet.secs = htons (65535); + client -> packet.secs = htons (65535); } - note ("DHCPREQUEST on %s to %s port %d", ip -> name, + log_info ("DHCPREQUEST on %s to %s port %d", + client -> name ? client -> name : client -> interface -> name, inet_ntoa (destination.sin_addr), ntohs (destination.sin_port)); @@ -1332,451 +1675,429 @@ void send_request (ipp) fallback_interface) result = send_packet (fallback_interface, (struct packet *)0, - &ip -> client -> packet, - ip -> client -> packet_length, + &client -> packet, + client -> packet_length, from, &destination, (struct hardware *)0); else /* Send out a packet. */ - result = send_packet (ip, (struct packet *)0, - &ip -> client -> packet, - ip -> client -> packet_length, + result = send_packet (client -> interface, (struct packet *)0, + &client -> packet, + client -> packet_length, from, &destination, (struct hardware *)0); - add_timeout (cur_time + ip -> client -> interval, - send_request, ip); + add_timeout (cur_time + client -> interval, + send_request, client, 0, 0); } -void send_decline (ipp) - void *ipp; +void send_decline (cpp) + void *cpp; { - struct interface_info *ip = ipp; + struct client_state *client = cpp; int result; - note ("DHCPDECLINE on %s to %s port %d", ip -> name, + log_info ("DHCPDECLINE on %s to %s port %d", + client -> name ? client -> name : client -> interface -> name, inet_ntoa (sockaddr_broadcast.sin_addr), ntohs (sockaddr_broadcast.sin_port)); /* Send out a packet. */ - result = send_packet (ip, (struct packet *)0, - &ip -> client -> packet, - ip -> client -> packet_length, + result = send_packet (client -> interface, (struct packet *)0, + &client -> packet, + client -> packet_length, inaddr_any, &sockaddr_broadcast, (struct hardware *)0); } -void send_release (ipp) - void *ipp; +void send_release (cpp) + void *cpp; { - struct interface_info *ip = ipp; + struct client_state *client = cpp; int result; + struct sockaddr_in destination; + struct in_addr from; - note ("DHCPRELEASE on %s to %s port %d", ip -> name, - inet_ntoa (sockaddr_broadcast.sin_addr), - ntohs (sockaddr_broadcast.sin_port)); + memcpy (&from, client -> active -> address.iabuf, + sizeof from); + memcpy (&destination.sin_addr.s_addr, + client -> destination.iabuf, + sizeof destination.sin_addr.s_addr); + destination.sin_port = remote_port; + destination.sin_family = AF_INET; +#ifdef HAVE_SA_LEN + destination.sin_len = sizeof destination; +#endif - /* Send out a packet. */ - result = send_packet (ip, (struct packet *)0, - &ip -> client -> packet, - ip -> client -> packet_length, - inaddr_any, &sockaddr_broadcast, - (struct hardware *)0); + /* Set the lease to end now, so that we don't accidentally + reuse it if we restart before the old expiry time. */ + client -> active -> expiry = + client -> active -> renewal = + client -> active -> rebind = cur_time; + if (!write_client_lease (client, client -> active, 1, 1)) { + log_error ("Can't release lease: lease write failed."); + return; + } + + log_info ("DHCPRELEASE on %s to %s port %d", + client -> name ? client -> name : client -> interface -> name, + inet_ntoa (destination.sin_addr), + ntohs (destination.sin_port)); + + if (fallback_interface) + result = send_packet (fallback_interface, + (struct packet *)0, + &client -> packet, + client -> packet_length, + from, &destination, + (struct hardware *)0); + else + /* Send out a packet. */ + result = send_packet (client -> interface, (struct packet *)0, + &client -> packet, + client -> packet_length, + from, &destination, + (struct hardware *)0); } -void make_discover (ip, lease) - struct interface_info *ip; +void make_client_options (client, lease, type, sid, rip, prl, op) + struct client_state *client; struct client_lease *lease; + u_int8_t *type; + struct option_cache *sid; + struct iaddr *rip; + u_int32_t *prl; + struct option_state **op; { - unsigned char discover = DHCPDISCOVER; - int i; - - struct tree_cache *options [256]; - struct tree_cache option_elements [256]; - - memset (option_elements, 0, sizeof option_elements); - memset (options, 0, sizeof options); - memset (&ip -> client -> packet, 0, sizeof (ip -> client -> packet)); - - /* Set DHCP_MESSAGE_TYPE to DHCPDISCOVER */ - i = DHO_DHCP_MESSAGE_TYPE; - options [i] = &option_elements [i]; - options [i] -> value = &discover; - options [i] -> len = sizeof discover; - options [i] -> buf_size = sizeof discover; - options [i] -> timeout = 0xFFFFFFFF; - options [i] -> tree = (struct tree *)0; - - /* Request the options we want */ - i = DHO_DHCP_PARAMETER_REQUEST_LIST; - options [i] = &option_elements [i]; - options [i] -> value = ip -> client -> config -> requested_options; - options [i] -> len = ip -> client -> config -> requested_option_count; - options [i] -> buf_size = - ip -> client -> config -> requested_option_count; - options [i] -> timeout = 0xFFFFFFFF; - options [i] -> tree = (struct tree *)0; - - /* If we had an address, try to get it again. */ - if (lease) { - ip -> client -> requested_address = lease -> address; - i = DHO_DHCP_REQUESTED_ADDRESS; - options [i] = &option_elements [i]; - options [i] -> value = lease -> address.iabuf; - options [i] -> len = lease -> address.len; - options [i] -> buf_size = lease -> address.len; - options [i] -> timeout = 0xFFFFFFFF; - options [i] -> tree = (struct tree *)0; + unsigned i; + struct option_cache *oc; + struct buffer *bp = (struct buffer *)0; + + /* If there are any leftover options, get rid of them. */ + if (*op) + option_state_dereference (op, MDL); + + /* Allocate space for options. */ + option_state_allocate (op, MDL); + + /* Send the server identifier if provided. */ + if (sid) + save_option (&dhcp_universe, *op, sid); + + oc = (struct option_cache *)0; + + /* Send the requested address if provided. */ + if (rip) { + client -> requested_address = *rip; + if (!(make_const_option_cache + (&oc, (struct buffer **)0, rip -> iabuf, rip -> len, + &dhcp_options [DHO_DHCP_REQUESTED_ADDRESS], MDL))) + log_error ("can't make requested address cache."); + else { + save_option (&dhcp_universe, *op, oc); + option_cache_dereference (&oc, MDL); + } } else { - ip -> client -> requested_address.len = 0; - } - - /* Send any options requested in the config file. */ - for (i = 0; i < 256; i++) { - if (!options [i] && - ip -> client -> config -> send_options [i].data) { - options [i] = &option_elements [i]; - options [i] -> value = ip -> client -> config -> - send_options [i].data; - options [i] -> len = ip -> client -> config -> - send_options [i].len; - options [i] -> buf_size = ip -> client -> config -> - send_options [i].len; - options [i] -> timeout = 0xFFFFFFFF; - options [i] -> tree = (struct tree *)0; + client -> requested_address.len = 0; + } + + if (!(make_const_option_cache + (&oc, (struct buffer **)0, + type, 1, &dhcp_options [DHO_DHCP_MESSAGE_TYPE], MDL))) + log_error ("can't make message type."); + else { + save_option (&dhcp_universe, *op, oc); + option_cache_dereference (&oc, MDL); + } + + if (prl) { + /* Figure out how many parameters were requested. */ + for (i = 0; prl [i]; i++) + ; + if (!buffer_allocate (&bp, i, MDL)) + log_error ("can't make parameter list buffer."); + else { + for (i = 0; prl [i]; i++) + bp -> data [i] = prl [i]; + if (!(make_const_option_cache + (&oc, &bp, (u_int8_t *)0, i, + &dhcp_options [DHO_DHCP_PARAMETER_REQUEST_LIST], + MDL))) + log_error ("can't make option cache"); + else { + save_option (&dhcp_universe, *op, oc); + option_cache_dereference (&oc, MDL); + } } } + /* Run statements that need to be run on transmission. */ + if (client -> config -> on_transmission) + execute_statements_in_scope + ((struct binding_value **)0, + (struct packet *)0, (struct lease *)0, client, + (lease ? lease -> options : (struct option_state *)0), + *op, &global_scope, + client -> config -> on_transmission, + (struct group *)0); +} + +void make_discover (client, lease) + struct client_state *client; + struct client_lease *lease; +{ + unsigned char discover = DHCPDISCOVER; + int i; + struct option_state *options = (struct option_state *)0; + + memset (&client -> packet, 0, sizeof (client -> packet)); + + make_client_options (client, + lease, &discover, (struct option_cache *)0, + lease ? &lease -> address : (struct iaddr *)0, + client -> config -> requested_options, + &options); + /* Set up the option buffer... */ - ip -> client -> packet_length = - cons_options ((struct packet *)0, &ip -> client -> packet, 0, - options, 0, 0, 0, (u_int8_t *)0, 0); - if (ip -> client -> packet_length < BOOTP_MIN_LEN) - ip -> client -> packet_length = BOOTP_MIN_LEN; - - ip -> client -> packet.op = BOOTREQUEST; - ip -> client -> packet.htype = ip -> hw_address.htype; - ip -> client -> packet.hlen = ip -> hw_address.hlen; - ip -> client -> packet.hops = 0; - ip -> client -> packet.xid = random (); - ip -> client -> packet.secs = 0; /* filled in by send_discover. */ - - if (can_receive_unicast_unconfigured (ip)) - ip -> client -> packet.flags = 0; + client -> packet_length = + cons_options ((struct packet *)0, &client -> packet, + (struct lease *)0, client, 0, + (struct option_state *)0, options, + &global_scope, 0, 0, 0, (struct data_string *)0, + client -> config -> vendor_space_name); + if (client -> packet_length < BOOTP_MIN_LEN) + client -> packet_length = BOOTP_MIN_LEN; + + client -> packet.op = BOOTREQUEST; + client -> packet.htype = client -> interface -> hw_address.hbuf [0]; + client -> packet.hlen = client -> interface -> hw_address.hlen - 1; + client -> packet.hops = 0; + client -> packet.xid = random (); + client -> packet.secs = 0; /* filled in by send_discover. */ + + if (can_receive_unicast_unconfigured (client -> interface)) + client -> packet.flags = 0; else - ip -> client -> packet.flags = htons (BOOTP_BROADCAST); - - memset (&(ip -> client -> packet.ciaddr), - 0, sizeof ip -> client -> packet.ciaddr); - memset (&(ip -> client -> packet.yiaddr), - 0, sizeof ip -> client -> packet.yiaddr); - memset (&(ip -> client -> packet.siaddr), - 0, sizeof ip -> client -> packet.siaddr); - memset (&(ip -> client -> packet.giaddr), - 0, sizeof ip -> client -> packet.giaddr); - memcpy (ip -> client -> packet.chaddr, - ip -> hw_address.haddr, ip -> hw_address.hlen); + client -> packet.flags = htons (BOOTP_BROADCAST); + + memset (&(client -> packet.ciaddr), + 0, sizeof client -> packet.ciaddr); + memset (&(client -> packet.yiaddr), + 0, sizeof client -> packet.yiaddr); + memset (&(client -> packet.siaddr), + 0, sizeof client -> packet.siaddr); + client -> packet.giaddr = giaddr; + if (client -> interface -> hw_address.hlen > 0) + memcpy (client -> packet.chaddr, + &client -> interface -> hw_address.hbuf [1], + (unsigned)(client -> interface -> hw_address.hlen - 1)); #ifdef DEBUG_PACKET - dump_packet (sendpkt); - dump_raw ((unsigned char *)ip -> client -> packet, - sendpkt->packet_length); + dump_raw ((unsigned char *)&client -> packet, client -> packet_length); #endif } -void make_request (ip, lease) - struct interface_info *ip; +void make_request (client, lease) + struct client_state *client; struct client_lease *lease; { unsigned char request = DHCPREQUEST; - int i; + int i, j; + unsigned char *tmp, *digest; + unsigned char *old_digest_loc; + struct option_cache *oc; - struct tree_cache *options [256]; - struct tree_cache option_elements [256]; - - memset (options, 0, sizeof options); - memset (&ip -> client -> packet, 0, sizeof (ip -> client -> packet)); - - /* Set DHCP_MESSAGE_TYPE to DHCPREQUEST */ - i = DHO_DHCP_MESSAGE_TYPE; - options [i] = &option_elements [i]; - options [i] -> value = &request; - options [i] -> len = sizeof request; - options [i] -> buf_size = sizeof request; - options [i] -> timeout = 0xFFFFFFFF; - options [i] -> tree = (struct tree *)0; - - /* Request the options we want */ - i = DHO_DHCP_PARAMETER_REQUEST_LIST; - options [i] = &option_elements [i]; - options [i] -> value = ip -> client -> config -> requested_options; - options [i] -> len = ip -> client -> config -> requested_option_count; - options [i] -> buf_size = - ip -> client -> config -> requested_option_count; - options [i] -> timeout = 0xFFFFFFFF; - options [i] -> tree = (struct tree *)0; - - /* If we are requesting an address that hasn't yet been assigned - to us, use the DHCP Requested Address option. */ - if (ip -> client -> state == S_REQUESTING) { - /* Send back the server identifier... */ - i = DHO_DHCP_SERVER_IDENTIFIER; - options [i] = &option_elements [i]; - options [i] -> value = lease -> options [i].data; - options [i] -> len = lease -> options [i].len; - options [i] -> buf_size = lease -> options [i].len; - options [i] -> timeout = 0xFFFFFFFF; - options [i] -> tree = (struct tree *)0; - } - if (ip -> client -> state == S_REQUESTING || - ip -> client -> state == S_REBOOTING) { - ip -> client -> requested_address = lease -> address; - i = DHO_DHCP_REQUESTED_ADDRESS; - options [i] = &option_elements [i]; - options [i] -> value = lease -> address.iabuf; - options [i] -> len = lease -> address.len; - options [i] -> buf_size = lease -> address.len; - options [i] -> timeout = 0xFFFFFFFF; - options [i] -> tree = (struct tree *)0; - } else { - ip -> client -> requested_address.len = 0; - } - - /* Send any options requested in the config file. */ - for (i = 0; i < 256; i++) { - if (!options [i] && - ip -> client -> config -> send_options [i].data) { - options [i] = &option_elements [i]; - options [i] -> value = ip -> client -> config -> - send_options [i].data; - options [i] -> len = ip -> client -> config -> - send_options [i].len; - options [i] -> buf_size = ip -> client -> config -> - send_options [i].len; - options [i] -> timeout = 0xFFFFFFFF; - options [i] -> tree = (struct tree *)0; - } - } + memset (&client -> packet, 0, sizeof (client -> packet)); + + if (client -> state == S_REQUESTING) + oc = lookup_option (&dhcp_universe, lease -> options, + DHO_DHCP_SERVER_IDENTIFIER); + else + oc = (struct option_cache *)0; + + make_client_options (client, lease, &request, oc, + ((client -> state == S_REQUESTING || + client -> state == S_REBOOTING) + ? &lease -> address + : (struct iaddr *)0), + client -> config -> requested_options, + &client -> sent_options); /* Set up the option buffer... */ - ip -> client -> packet_length = - cons_options ((struct packet *)0, &ip -> client -> packet, 0, - options, 0, 0, 0, (u_int8_t *)0, 0); - if (ip -> client -> packet_length < BOOTP_MIN_LEN) - ip -> client -> packet_length = BOOTP_MIN_LEN; - - ip -> client -> packet.op = BOOTREQUEST; - ip -> client -> packet.htype = ip -> hw_address.htype; - ip -> client -> packet.hlen = ip -> hw_address.hlen; - ip -> client -> packet.hops = 0; - ip -> client -> packet.xid = ip -> client -> xid; - ip -> client -> packet.secs = 0; /* Filled in by send_request. */ + client -> packet_length = + cons_options ((struct packet *)0, &client -> packet, + (struct lease *)0, client, 0, + (struct option_state *)0, client -> sent_options, + &global_scope, 0, 0, 0, (struct data_string *)0, + client -> config -> vendor_space_name); + if (client -> packet_length < BOOTP_MIN_LEN) + client -> packet_length = BOOTP_MIN_LEN; + + client -> packet.op = BOOTREQUEST; + client -> packet.htype = client -> interface -> hw_address.hbuf [0]; + client -> packet.hlen = client -> interface -> hw_address.hlen - 1; + client -> packet.hops = 0; + client -> packet.xid = client -> xid; + client -> packet.secs = 0; /* Filled in by send_request. */ /* If we own the address we're requesting, put it in ciaddr; otherwise set ciaddr to zero. */ - if (ip -> client -> state == S_BOUND || - ip -> client -> state == S_RENEWING || - ip -> client -> state == S_REBINDING) { - memcpy (&ip -> client -> packet.ciaddr, + if (client -> state == S_BOUND || + client -> state == S_RENEWING || + client -> state == S_REBINDING) { + memcpy (&client -> packet.ciaddr, lease -> address.iabuf, lease -> address.len); - ip -> client -> packet.flags = 0; + client -> packet.flags = 0; } else { - memset (&ip -> client -> packet.ciaddr, 0, - sizeof ip -> client -> packet.ciaddr); - if (can_receive_unicast_unconfigured (ip)) - ip -> client -> packet.flags = 0; + memset (&client -> packet.ciaddr, 0, + sizeof client -> packet.ciaddr); + if (can_receive_unicast_unconfigured (client -> interface)) + client -> packet.flags = 0; else - ip -> client -> packet.flags = htons (BOOTP_BROADCAST); + client -> packet.flags = htons (BOOTP_BROADCAST); } - memset (&ip -> client -> packet.yiaddr, 0, - sizeof ip -> client -> packet.yiaddr); - memset (&ip -> client -> packet.siaddr, 0, - sizeof ip -> client -> packet.siaddr); - memset (&ip -> client -> packet.giaddr, 0, - sizeof ip -> client -> packet.giaddr); - memcpy (ip -> client -> packet.chaddr, - ip -> hw_address.haddr, ip -> hw_address.hlen); + memset (&client -> packet.yiaddr, 0, + sizeof client -> packet.yiaddr); + memset (&client -> packet.siaddr, 0, + sizeof client -> packet.siaddr); + if (client -> state != S_BOUND && + client -> state != S_RENEWING) + client -> packet.giaddr = giaddr; + else + memset (&client -> packet.giaddr, 0, + sizeof client -> packet.giaddr); + if (client -> interface -> hw_address.hlen > 0) + memcpy (client -> packet.chaddr, + &client -> interface -> hw_address.hbuf [1], + (unsigned)(client -> interface -> hw_address.hlen - 1)); #ifdef DEBUG_PACKET - dump_packet (sendpkt); - dump_raw ((unsigned char *)ip -> client -> packet, sendpkt->packet_length); + dump_raw ((unsigned char *)&client -> packet, client -> packet_length); #endif } -void make_decline (ip, lease) - struct interface_info *ip; +void make_decline (client, lease) + struct client_state *client; struct client_lease *lease; { unsigned char decline = DHCPDECLINE; int i; + struct option_cache *oc; - struct tree_cache *options [256]; - struct tree_cache message_type_tree; - struct tree_cache requested_address_tree; - struct tree_cache server_id_tree; - struct tree_cache client_id_tree; - - memset (options, 0, sizeof options); - memset (&ip -> client -> packet, 0, sizeof (ip -> client -> packet)); - - /* Set DHCP_MESSAGE_TYPE to DHCPDECLINE */ - i = DHO_DHCP_MESSAGE_TYPE; - options [i] = &message_type_tree; - options [i] -> value = &decline; - options [i] -> len = sizeof decline; - options [i] -> buf_size = sizeof decline; - options [i] -> timeout = 0xFFFFFFFF; - options [i] -> tree = (struct tree *)0; - - /* Send back the server identifier... */ - i = DHO_DHCP_SERVER_IDENTIFIER; - options [i] = &server_id_tree; - options [i] -> value = lease -> options [i].data; - options [i] -> len = lease -> options [i].len; - options [i] -> buf_size = lease -> options [i].len; - options [i] -> timeout = 0xFFFFFFFF; - options [i] -> tree = (struct tree *)0; - - /* Send back the address we're declining. */ - i = DHO_DHCP_REQUESTED_ADDRESS; - options [i] = &requested_address_tree; - options [i] -> value = lease -> address.iabuf; - options [i] -> len = lease -> address.len; - options [i] -> buf_size = lease -> address.len; - options [i] -> timeout = 0xFFFFFFFF; - options [i] -> tree = (struct tree *)0; - - /* Send the uid if the user supplied one. */ - i = DHO_DHCP_CLIENT_IDENTIFIER; - if (ip -> client -> config -> send_options [i].len) { - options [i] = &client_id_tree; - options [i] -> value = ip -> client -> config -> - send_options [i].data; - options [i] -> len = ip -> client -> config -> - send_options [i].len; - options [i] -> buf_size = ip -> client -> config -> - send_options [i].len; - options [i] -> timeout = 0xFFFFFFFF; - options [i] -> tree = (struct tree *)0; - } + struct option_state *options = (struct option_state *)0; + oc = lookup_option (&dhcp_universe, lease -> options, + DHO_DHCP_SERVER_IDENTIFIER); + make_client_options (client, lease, &decline, oc, + &lease -> address, (u_int32_t *)0, &options); /* Set up the option buffer... */ - ip -> client -> packet_length = - cons_options ((struct packet *)0, &ip -> client -> packet, 0, - options, 0, 0, 0, (u_int8_t *)0, 0); - if (ip -> client -> packet_length < BOOTP_MIN_LEN) - ip -> client -> packet_length = BOOTP_MIN_LEN; - - ip -> client -> packet.op = BOOTREQUEST; - ip -> client -> packet.htype = ip -> hw_address.htype; - ip -> client -> packet.hlen = ip -> hw_address.hlen; - ip -> client -> packet.hops = 0; - ip -> client -> packet.xid = ip -> client -> xid; - ip -> client -> packet.secs = 0; /* Filled in by send_request. */ - ip -> client -> packet.flags = 0; + memset (&client -> packet, 0, sizeof (client -> packet)); + client -> packet_length = + cons_options ((struct packet *)0, &client -> packet, + (struct lease *)0, client, 0, + (struct option_state *)0, options, + &global_scope, 0, 0, 0, (struct data_string *)0, + client -> config -> vendor_space_name); + if (client -> packet_length < BOOTP_MIN_LEN) + client -> packet_length = BOOTP_MIN_LEN; + option_state_dereference (&options, MDL); + + client -> packet.op = BOOTREQUEST; + client -> packet.htype = client -> interface -> hw_address.hbuf [0]; + client -> packet.hlen = client -> interface -> hw_address.hlen - 1; + client -> packet.hops = 0; + client -> packet.xid = client -> xid; + client -> packet.secs = 0; /* Filled in by send_request. */ + if (can_receive_unicast_unconfigured (client -> interface)) + client -> packet.flags = 0; + else + client -> packet.flags = htons (BOOTP_BROADCAST); /* ciaddr must always be zero. */ - memset (&ip -> client -> packet.ciaddr, 0, - sizeof ip -> client -> packet.ciaddr); - memset (&ip -> client -> packet.yiaddr, 0, - sizeof ip -> client -> packet.yiaddr); - memset (&ip -> client -> packet.siaddr, 0, - sizeof ip -> client -> packet.siaddr); - memset (&ip -> client -> packet.giaddr, 0, - sizeof ip -> client -> packet.giaddr); - memcpy (ip -> client -> packet.chaddr, - ip -> hw_address.haddr, ip -> hw_address.hlen); + memset (&client -> packet.ciaddr, 0, + sizeof client -> packet.ciaddr); + memset (&client -> packet.yiaddr, 0, + sizeof client -> packet.yiaddr); + memset (&client -> packet.siaddr, 0, + sizeof client -> packet.siaddr); + client -> packet.giaddr = giaddr; + memcpy (client -> packet.chaddr, + &client -> interface -> hw_address.hbuf [1], + client -> interface -> hw_address.hlen); #ifdef DEBUG_PACKET - dump_packet (sendpkt); - dump_raw ((unsigned char *)ip -> client -> packet, sendpkt->packet_length); + dump_raw ((unsigned char *)&client -> packet, client -> packet_length); #endif } -void make_release (ip, lease) - struct interface_info *ip; +void make_release (client, lease) + struct client_state *client; struct client_lease *lease; { unsigned char request = DHCPRELEASE; int i; + struct option_cache *oc; + + struct option_state *options = (struct option_state *)0; - struct tree_cache *options [256]; - struct tree_cache message_type_tree; - struct tree_cache server_id_tree; - - memset (options, 0, sizeof options); - memset (&ip -> client -> packet, 0, sizeof (ip -> client -> packet)); - - /* Set DHCP_MESSAGE_TYPE to DHCPRELEASE */ - i = DHO_DHCP_MESSAGE_TYPE; - options [i] = &message_type_tree; - options [i] -> value = &request; - options [i] -> len = sizeof request; - options [i] -> buf_size = sizeof request; - options [i] -> timeout = 0xFFFFFFFF; - options [i] -> tree = (struct tree *)0; - - /* Send back the server identifier... */ - i = DHO_DHCP_SERVER_IDENTIFIER; - options [i] = &server_id_tree; - options [i] -> value = lease -> options [i].data; - options [i] -> len = lease -> options [i].len; - options [i] -> buf_size = lease -> options [i].len; - options [i] -> timeout = 0xFFFFFFFF; - options [i] -> tree = (struct tree *)0; + memset (&client -> packet, 0, sizeof (client -> packet)); + + oc = lookup_option (&dhcp_universe, lease -> options, + DHO_DHCP_SERVER_IDENTIFIER); + make_client_options (client, lease, &request, oc, + (struct iaddr *)0, (u_int32_t *)0, + &options); /* Set up the option buffer... */ - ip -> client -> packet_length = - cons_options ((struct packet *)0, &ip -> client -> packet, 0, - options, 0, 0, 0, (u_int8_t *)0, 0); - if (ip -> client -> packet_length < BOOTP_MIN_LEN) - ip -> client -> packet_length = BOOTP_MIN_LEN; - - ip -> client -> packet.op = BOOTREQUEST; - ip -> client -> packet.htype = ip -> hw_address.htype; - ip -> client -> packet.hlen = ip -> hw_address.hlen; - ip -> client -> packet.hops = 0; - ip -> client -> packet.xid = random (); - ip -> client -> packet.secs = 0; - ip -> client -> packet.flags = 0; - - memset (&ip -> client -> packet.ciaddr, 0, - sizeof ip -> client -> packet.ciaddr); - memset (&ip -> client -> packet.yiaddr, 0, - sizeof ip -> client -> packet.yiaddr); - memset (&ip -> client -> packet.siaddr, 0, - sizeof ip -> client -> packet.siaddr); - memset (&ip -> client -> packet.giaddr, 0, - sizeof ip -> client -> packet.giaddr); - memcpy (ip -> client -> packet.chaddr, - ip -> hw_address.haddr, ip -> hw_address.hlen); + client -> packet_length = + cons_options ((struct packet *)0, &client -> packet, + (struct lease *)0, client, 0, + (struct option_state *)0, options, + &global_scope, 0, 0, 0, (struct data_string *)0, + client -> config -> vendor_space_name); + if (client -> packet_length < BOOTP_MIN_LEN) + client -> packet_length = BOOTP_MIN_LEN; + option_state_dereference (&options, MDL); + + client -> packet.op = BOOTREQUEST; + client -> packet.htype = client -> interface -> hw_address.hbuf [0]; + client -> packet.hlen = client -> interface -> hw_address.hlen - 1; + client -> packet.hops = 0; + client -> packet.xid = random (); + client -> packet.secs = 0; + client -> packet.flags = 0; + memcpy (&client -> packet.ciaddr, + lease -> address.iabuf, lease -> address.len); + memset (&client -> packet.yiaddr, 0, + sizeof client -> packet.yiaddr); + memset (&client -> packet.siaddr, 0, + sizeof client -> packet.siaddr); + client -> packet.giaddr = giaddr; + memcpy (client -> packet.chaddr, + &client -> interface -> hw_address.hbuf [1], + client -> interface -> hw_address.hlen); #ifdef DEBUG_PACKET - dump_packet (sendpkt); - dump_raw ((unsigned char *)ip -> client -> packet, - ip -> client -> packet_length); + dump_raw ((unsigned char *)&client -> packet, client -> packet_length); #endif } -void free_client_lease (lease) +void destroy_client_lease (lease) struct client_lease *lease; { int i; if (lease -> server_name) - free (lease -> server_name); + dfree (lease -> server_name, MDL); if (lease -> filename) - free (lease -> filename); - for (i = 0; i < 256; i++) { - if (lease -> options [i].len) - free (lease -> options [i].data); - } - free (lease); + dfree (lease -> filename, MDL); + option_state_dereference (&lease -> options, MDL); + free_client_lease (lease, MDL); } FILE *leaseFile; @@ -1784,44 +2105,92 @@ FILE *leaseFile; void rewrite_client_leases () { struct interface_info *ip; + struct client_state *client; struct client_lease *lp; if (leaseFile) fclose (leaseFile); leaseFile = fopen (path_dhclient_db, "w"); - if (!leaseFile) - error ("can't create %s: %m", path_dhclient_db); + if (!leaseFile) { + log_error ("can't create %s: %m", path_dhclient_db); + return; + } /* Write out all the leases attached to configured interfaces that we know about. */ for (ip = interfaces; ip; ip = ip -> next) { - for (lp = ip -> client -> leases; lp; lp = lp -> next) { - write_client_lease (ip, lp, 1); + for (client = ip -> client; client; client = client -> next) { + for (lp = client -> leases; lp; lp = lp -> next) { + write_client_lease (client, lp, 1, 0); + } + if (client -> active) + write_client_lease (client, + client -> active, 1, 0); } - if (ip -> client -> active) - write_client_lease (ip, ip -> client -> active, 1); } /* Write out any leases that are attached to interfaces that aren't currently configured. */ for (ip = dummy_interfaces; ip; ip = ip -> next) { - for (lp = ip -> client -> leases; lp; lp = lp -> next) { - write_client_lease (ip, lp, 1); + for (client = ip -> client; client; client = client -> next) { + for (lp = client -> leases; lp; lp = lp -> next) { + write_client_lease (client, lp, 1, 0); + } + if (client -> active) + write_client_lease (client, + client -> active, 1, 0); } - if (ip -> client -> active) - write_client_lease (ip, ip -> client -> active, 1); } fflush (leaseFile); } -void write_client_lease (ip, lease, rewrite) - struct interface_info *ip; +void write_lease_option (struct option_cache *oc, + struct packet *packet, struct lease *lease, + struct client_state *client_state, + struct option_state *in_options, + struct option_state *cfg_options, + struct binding_scope **scope, + struct universe *u, void *stuff) +{ + const char *name, *dot; + struct data_string ds; + int status; + struct client_state *client; + + memset (&ds, 0, sizeof ds); + + if (u != &dhcp_universe) { + name = u -> name; + dot = "."; + } else { + name = ""; + dot = ""; + } + if (evaluate_option_cache (&ds, packet, lease, client_state, + in_options, cfg_options, scope, oc, MDL)) { + fprintf (leaseFile, + " option %s%s%s %s;\n", + name, dot, oc -> option -> name, + pretty_print_option (oc -> option, + ds.data, ds.len, 1, 1)); + data_string_forget (&ds, MDL); + } +} + +int write_client_lease (client, lease, rewrite, makesure) + struct client_state *client; struct client_lease *lease; int rewrite; + int makesure; { int i; struct tm *t; static int leases_written; + struct option_cache *oc; + struct data_string ds; + pair *hash; + int errors = 0; + char *s; if (!rewrite) { if (leases_written++ > 20) { @@ -1833,38 +2202,94 @@ void write_client_lease (ip, lease, rewrite) /* If the lease came from the config file, we don't need to stash a copy in the lease database. */ if (lease -> is_static) - return; + return 1; if (!leaseFile) { /* XXX */ leaseFile = fopen (path_dhclient_db, "w"); - if (!leaseFile) - error ("can't create %s: %m", path_dhclient_db); + if (!leaseFile) { + log_error ("can't create %s: %m", path_dhclient_db); + return 0; + } } + errno = 0; fprintf (leaseFile, "lease {\n"); - if (lease -> is_bootp) + if (lease -> is_bootp) { fprintf (leaseFile, " bootp;\n"); - fprintf (leaseFile, " interface \"%s\";\n", ip -> name); + if (errno) { + ++errors; + errno = 0; + } + } + fprintf (leaseFile, " interface \"%s\";\n", + client -> interface -> name); + if (errno) { + ++errors; + errno = 0; + } + if (client -> name) { + fprintf (leaseFile, " name \"%s\";\n", client -> name); + if (errno) { + ++errors; + errno = 0; + } + } fprintf (leaseFile, " fixed-address %s;\n", piaddr (lease -> address)); - if (lease -> filename) - fprintf (leaseFile, " filename \"%s\";\n", - lease -> filename); - if (lease -> server_name) - fprintf (leaseFile, " server-name \"%s\";\n", - lease -> server_name); - if (lease -> medium) - fprintf (leaseFile, " medium \"%s\";\n", - lease -> medium -> string); - for (i = 0; i < 256; i++) { - if (lease -> options [i].len) { - fprintf (leaseFile, - " option %s %s;\n", - dhcp_options [i].name, - pretty_print_option - (i, lease -> options [i].data, - lease -> options [i].len, 1, 1)); - } + if (errno) { + ++errors; + errno = 0; + } + if (lease -> filename) { + s = quotify_string (lease -> filename, MDL); + if (s) { + fprintf (leaseFile, " filename \"%s\";\n", s); + if (errno) { + ++errors; + errno = 0; + } + dfree (s, MDL); + } else + errors++; + + } + if (lease -> server_name) { + s = quotify_string (lease -> filename, MDL); + if (s) { + fprintf (leaseFile, " server-name \"%s\";\n", s); + if (errno) { + ++errors; + errno = 0; + } + dfree (s, MDL); + } else + ++errors; + } + if (lease -> medium) { + s = quotify_string (lease -> medium -> string, MDL); + if (s) { + fprintf (leaseFile, " medium \"%s\";\n", s); + if (errno) { + ++errors; + errno = 0; + } + dfree (s, MDL); + } else + errors++; + } + if (errno != 0) { + errors++; + errno = 0; + } + + memset (&ds, 0, sizeof ds); + + for (i = 0; i < lease -> options -> universe_count; i++) { + option_space_foreach ((struct packet *)0, (struct lease *)0, + client, (struct option_state *)0, + lease -> options, &global_scope, + universes [i], + client, write_lease_option); } /* Note: the following is not a Y2K bug - it's a Y1.9K bug. Until @@ -1876,20 +2301,47 @@ void write_client_lease (ip, lease, rewrite) t -> tm_wday, t -> tm_year + 1900, t -> tm_mon + 1, t -> tm_mday, t -> tm_hour, t -> tm_min, t -> tm_sec); + if (errno != 0) { + errors++; + errno = 0; + } t = gmtime (&lease -> rebind); fprintf (leaseFile, " rebind %d %d/%d/%d %02d:%02d:%02d;\n", t -> tm_wday, t -> tm_year + 1900, t -> tm_mon + 1, t -> tm_mday, t -> tm_hour, t -> tm_min, t -> tm_sec); + if (errno != 0) { + errors++; + errno = 0; + } t = gmtime (&lease -> expiry); fprintf (leaseFile, " expire %d %d/%d/%d %02d:%02d:%02d;\n", t -> tm_wday, t -> tm_year + 1900, t -> tm_mon + 1, t -> tm_mday, t -> tm_hour, t -> tm_min, t -> tm_sec); + if (errno != 0) { + errors++; + errno = 0; + } fprintf (leaseFile, "}\n"); + if (errno != 0) { + errors++; + errno = 0; + } fflush (leaseFile); + if (errno != 0) { + errors++; + errno = 0; + } + if (!errors && makesure) { + if (fsync (fileno (leaseFile)) < 0) { + log_info ("write_client_lease: %m"); + return 0; + } + } + return errors ? 0 : 1; } /* Variables holding name of script and file pointer for writing to @@ -1898,41 +2350,88 @@ void write_client_lease (ip, lease, rewrite) char scriptName [256]; FILE *scriptFile; -void script_init (ip, reason, medium) - struct interface_info *ip; - char *reason; +void script_init (client, reason, medium) + struct client_state *client; + const char *reason; struct string_list *medium; { struct string_list *sl, *next; - if (ip) { - for (sl = ip -> client -> env; sl; sl = next) { + if (client) { + for (sl = client -> env; sl; sl = next) { next = sl -> next; - dfree (sl, "script_init"); + dfree (sl, MDL); } - ip -> client -> env = (struct string_list *)0; - ip -> client -> envc = 0; + client -> env = (struct string_list *)0; + client -> envc = 0; - client_envadd (ip -> client, "", "interface", "%s", - ip -> name); + if (client -> interface) { + client_envadd (client, "", "interface", "%s", + client -> interface -> name); + } + if (client -> name) + client_envadd (client, + "", "client", "%s", client -> name); if (medium) - client_envadd (ip -> client, + client_envadd (client, "", "medium", "%s", medium -> string); - client_envadd (ip -> client, "", "reason", "%s", reason); + client_envadd (client, "", "reason", "%s", reason); + client_envadd (client, "", "pid", "%ld", (long int)getpid ()); } } -void script_write_params (ip, prefix, lease) - struct interface_info *ip; - char *prefix; +struct envadd_state { + struct client_state *client; + const char *prefix; +}; + +void client_option_envadd (struct option_cache *oc, + struct packet *packet, struct lease *lease, + struct client_state *client_state, + struct option_state *in_options, + struct option_state *cfg_options, + struct binding_scope **scope, + struct universe *u, void *stuff) +{ + struct envadd_state *es = stuff; + struct data_string data; + memset (&data, 0, sizeof data); + + if (evaluate_option_cache (&data, packet, lease, client_state, + in_options, cfg_options, scope, oc, MDL)) { + if (data.len) { + char name [256]; + if (dhcp_option_ev_name (name, sizeof name, + oc -> option)) { + client_envadd (es -> client, es -> prefix, + name, "%s", + (pretty_print_option + (oc -> option, + data.data, data.len, + 0, 0))); + data_string_forget (&data, MDL); + } + } + } +} + +void script_write_params (client, prefix, lease) + struct client_state *client; + const char *prefix; struct client_lease *lease; { int i; - u_int8_t dbuf [1500]; - int len; + struct data_string data; + struct option_cache *oc; + pair *hash; + char *s, *t; + struct envadd_state es; - client_envadd (ip -> client, + es.client = client; + es.prefix = prefix; + + client_envadd (client, prefix, "ip_address", "%s", piaddr (lease -> address)); /* For the benefit of Linux (and operating systems which may @@ -1942,125 +2441,66 @@ void script_write_params (ip, prefix, lease) broadcast address, not the host address all zeroes broadcast address). */ - if (lease -> options [DHO_SUBNET_MASK].len && - (lease -> options [DHO_SUBNET_MASK].len < - sizeof lease -> address.iabuf)) { - struct iaddr netmask, subnet, broadcast; - - memcpy (netmask.iabuf, - lease -> options [DHO_SUBNET_MASK].data, - lease -> options [DHO_SUBNET_MASK].len); - netmask.len = lease -> options [DHO_SUBNET_MASK].len; - - subnet = subnet_number (lease -> address, netmask); - if (subnet.len) { - client_envadd (ip -> client, prefix, "network_number", - "%s", piaddr (subnet)); - - if (!lease -> options [DHO_BROADCAST_ADDRESS].len) { + memset (&data, 0, sizeof data); + oc = lookup_option (&dhcp_universe, lease -> options, DHO_SUBNET_MASK); + if (oc && evaluate_option_cache (&data, (struct packet *)0, + (struct lease *)0, client, + (struct option_state *)0, + lease -> options, + &global_scope, oc, MDL)) { + if (data.len > 3) { + struct iaddr netmask, subnet, broadcast; + + memcpy (netmask.iabuf, data.data, data.len); + netmask.len = data.len; + data_string_forget (&data, MDL); + + subnet = subnet_number (lease -> address, netmask); + if (subnet.len) { + client_envadd (client, prefix, "network_number", + "%s", piaddr (subnet)); + + oc = lookup_option (&dhcp_universe, + lease -> options, + DHO_BROADCAST_ADDRESS); + if (!oc || + !(evaluate_option_cache + (&data, (struct packet *)0, + (struct lease *)0, client, + (struct option_state *)0, + lease -> options, + &global_scope, oc, MDL))) { broadcast = broadcast_addr (subnet, netmask); if (broadcast.len) { - client_envadd (ip -> client, + client_envadd (client, prefix, "broadcast_address", "%s", piaddr (broadcast)); } + } } } + data_string_forget (&data, MDL); } if (lease -> filename) - client_envadd (ip -> client, + client_envadd (client, prefix, "filename", "%s", lease -> filename); if (lease -> server_name) - client_envadd (ip -> client, prefix, "server_name", + client_envadd (client, prefix, "server_name", "%s", lease -> server_name); - for (i = 0; i < 256; i++) { - u_int8_t *dp; - - if (ip -> client -> config -> defaults [i].len) { - if (lease -> options [i].len) { - switch (ip -> client -> - config -> default_actions [i]) { - case ACTION_DEFAULT: - dp = lease -> options [i].data; - len = lease -> options [i].len; - break; - case ACTION_SUPERSEDE: - supersede: - dp = ip -> client -> - config -> defaults [i].data; - len = ip -> client -> - config -> defaults [i].len; - break; - case ACTION_PREPEND: - len = (ip -> client -> - config -> defaults [i].len + - lease -> options [i].len); - if (len > sizeof dbuf) { - warn ("no space to %s %s", - "prepend option", - dhcp_options [i].name); - goto supersede; - } - dp = dbuf; - memcpy (dp, - ip -> client -> - config -> defaults [i].data, - ip -> client -> - config -> defaults [i].len); - memcpy (dp + ip -> client -> - config -> defaults [i].len, - lease -> options [i].data, - lease -> options [i].len); - break; - case ACTION_APPEND: - len = (ip -> client -> - config -> defaults [i].len + - lease -> options [i].len); - if (len > sizeof dbuf) { - warn ("no space to %s %s", - "append option", - dhcp_options [i].name); - goto supersede; - } - dp = dbuf; - memcpy (dp, - lease -> options [i].data, - lease -> options [i].len); - memcpy (dp + lease -> options [i].len, - ip -> client -> - config -> defaults [i].data, - ip -> client -> - config -> defaults [i].len); - } - } else { - dp = ip -> client -> - config -> defaults [i].data; - len = ip -> client -> - config -> defaults [i].len; - } - } else if (lease -> options [i].len) { - len = lease -> options [i].len; - dp = lease -> options [i].data; - } else { - len = 0; - } - if (len) { - char name [256]; - if (dhcp_option_ev_name (name, sizeof name, - &dhcp_options [i])) { - client_envadd (ip -> client, prefix, name, "%s", - (pretty_print_option (i, dp, - len, 0, 0))); - } - } + + for (i = 0; i < lease -> options -> universe_count; i++) { + option_space_foreach ((struct packet *)0, (struct lease *)0, + client, (struct option_state *)0, + lease -> options, &global_scope, + universes [i], + &es, client_option_envadd); } - client_envadd (ip -> client, - prefix, "expiry", "%d", (int)(lease -> expiry)); + client_envadd (client, prefix, "expiry", "%d", (int)(lease -> expiry)); } -int script_go (ip) - struct interface_info *ip; +int script_go (client) + struct client_state *client; { int rval; char *scriptName; @@ -2073,59 +2513,68 @@ int script_go (ip) struct string_list *sp, *next; int pid, wpid, wstatus; - if (ip) { - scriptName = ip -> client -> config -> script_name; - envp = dmalloc ((ip -> client -> envc + 2) * sizeof (char *), - "script_go"); - if (!envp) { - error ("No memory for client script environment."); - return 0; - } - i = 0; - for (sp = ip -> client -> env; sp; sp = sp -> next) { + if (client) + scriptName = client -> config -> script_name; + else + scriptName = top_level_config.script_name; + + envp = dmalloc (((client ? client -> envc : 2) + + client_env_count + 2) * sizeof (char *), MDL); + if (!envp) { + log_error ("No memory for client script environment."); + return 0; + } + i = 0; + /* Copy out the environment specified on the command line, + if any. */ + for (sp = client_env; sp; sp = sp -> next) { + envp [i++] = sp -> string; + } + /* Copy out the environment specified by dhclient. */ + if (client) { + for (sp = client -> env; sp; sp = sp -> next) { envp [i++] = sp -> string; } - envp [i++] = client_path; - envp [i] = (char *)0; } else { - scriptName = top_level_config.script_name; - epp [0] = reason; - epp [1] = client_path; - epp [2] = (char *)0; - envp = epp; + envp [i++] = reason; } + /* Set $PATH. */ + envp [i++] = client_path; + envp [i] = (char *)0; argv [0] = scriptName; argv [1] = (char *)0; pid = fork (); if (pid < 0) { - error ("fork: %m"); + log_error ("fork: %m"); wstatus = 0; } else if (pid) { do { wpid = wait (&wstatus); } while (wpid != pid && wpid > 0); if (wpid < 0) { - error ("wait: %m"); + log_error ("wait: %m"); wstatus = 0; } } else { execve (scriptName, argv, envp); - error ("execve (%s, ...): %m", scriptName); + log_error ("execve (%s, ...): %m", scriptName); exit (0); } - if (ip) { - for (sp = ip -> client -> env; sp; sp = next) { + if (client) { + for (sp = client -> env; sp; sp = next) { next = sp -> next; - dfree (sp, "script_go"); + dfree (sp, MDL); } - ip -> client -> env = (struct string_list *)0; - ip -> client -> envc = 0; - dfree (envp, "script_go"); + client -> env = (struct string_list *)0; + client -> envc = 0; } - return wstatus & 0xff; + dfree (envp, MDL); + GET_TIME (&cur_time); + return (WIFEXITED (wstatus) ? + WEXITSTATUS (wstatus) : -WTERMSIG (wstatus)); } void client_envadd (struct client_state *client, @@ -2142,7 +2591,7 @@ void client_envadd (struct client_state *client, va_end (list); val = dmalloc (strlen (prefix) + strlen (name) + 1 /* = */ + - len + sizeof *val, "client_envadd"); + len + sizeof *val, MDL); if (!val) return; s = val -> string; @@ -2166,25 +2615,46 @@ int dhcp_option_ev_name (buf, buflen, option) size_t buflen; struct option *option; { - int i; + int i, j; + const char *s; - for (i = 0; option -> name [i]; i++) { - if (i + 1 == buflen) - return 0; - if (option -> name [i] == '-') - buf [i] = '_'; - else - buf [i] = option -> name [i]; + j = 0; + if (option -> universe != &dhcp_universe) { + s = option -> universe -> name; + i = 0; + } else { + s = option -> name; + i = 1; } - buf [i] = 0; + do { + while (*s) { + if (j + 1 == buflen) + return 0; + if (*s == '-') + buf [j++] = '_'; + else + buf [j++] = *s; + ++s; + } + if (!i) { + s = option -> name; + if (j + 1 == buflen) + return 0; + buf [j++] = '_'; + } + ++i; + } while (i != 2); + + buf [j] = 0; return 1; } - + void go_daemon () { static int state = 0; int pid; + int i; /* Don't become a daemon if the user requested otherwise. */ if (no_daemon) { @@ -2202,7 +2672,7 @@ void go_daemon () /* Become a daemon... */ if ((pid = fork ()) < 0) - error ("Can't fork daemon: %m"); + log_fatal ("Can't fork daemon: %m"); else if (pid) exit (0); /* Become session leader and get pid... */ @@ -2213,6 +2683,16 @@ void go_daemon () close(1); close(2); + /* Reopen them on /dev/null. */ + i = open ("/dev/null", O_RDWR); + if (i == 0) + i = open ("/dev/null", O_RDWR); + if (i == 1) { + i = open ("/dev/null", O_RDWR); + log_perror = 0; /* No sense logging to /dev/null. */ + } else if (i != -1) + close (i); + write_client_pid_file (); } @@ -2224,15 +2704,384 @@ void write_client_pid_file () pfdesc = open (path_dhclient_pid, O_CREAT | O_TRUNC | O_WRONLY, 0644); if (pfdesc < 0) { - warn ("Can't create %s: %m", path_dhclient_pid); + log_error ("Can't create %s: %m", path_dhclient_pid); return; } pf = fdopen (pfdesc, "w"); if (!pf) - warn ("Can't fdopen %s: %m", path_dhclient_pid); + log_error ("Can't fdopen %s: %m", path_dhclient_pid); else { fprintf (pf, "%ld\n", (long)getpid ()); fclose (pf); } } + +void client_location_changed () +{ + struct interface_info *ip; + struct client_state *client; + + for (ip = interfaces; ip; ip = ip -> next) { + for (client = ip -> client; client; client = client -> next) { + switch (client -> state) { + case S_SELECTING: + cancel_timeout (send_discover, client); + break; + + case S_BOUND: + cancel_timeout (state_bound, client); + break; + + case S_REBOOTING: + case S_REQUESTING: + case S_RENEWING: + cancel_timeout (send_request, client); + break; + + case S_INIT: + case S_REBINDING: + case S_STOPPED: + break; + } + client -> state = S_INIT; + state_reboot (client); + } + } +} + +void do_release(client) + struct client_state *client; +{ + struct data_string ds; + struct option_cache *oc; + + /* Pick a random xid. */ + client -> xid = random (); + + /* is there even a lease to release? */ + if (client -> active) { + /* Make a DHCPRELEASE packet, and set appropriate per-interface + flags. */ + make_release (client, client -> active); + + memset (&ds, 0, sizeof ds); + oc = lookup_option (&dhcp_universe, + client -> active -> options, + DHO_DHCP_SERVER_IDENTIFIER); + if (oc && + evaluate_option_cache (&ds, (struct packet *)0, + (struct lease *)0, client, + (struct option_state *)0, + client -> active -> options, + &global_scope, oc, MDL)) { + if (ds.len > 3) { + memcpy (client -> destination.iabuf, + ds.data, 4); + client -> destination.len = 4; + } else + client -> destination = iaddr_broadcast; + } else + client -> destination = iaddr_broadcast; + client -> first_sending = cur_time; + client -> interval = client -> config -> initial_interval; + + /* Zap the medium list... */ + client -> medium = (struct string_list *)0; + + /* Send out the first and only DHCPRELEASE packet. */ + send_release (client); + + /* Do the client script RELEASE operation. */ + script_init (client, + "RELEASE", (struct string_list *)0); + if (client -> alias) + script_write_params (client, "alias_", + client -> alias); + script_write_params (client, "old_", client -> active); + script_go (client); + } + + /* Cancel any timeouts. */ + cancel_timeout (state_bound, client); + cancel_timeout (send_discover, client); + cancel_timeout (state_init, client); + cancel_timeout (send_request, client); + cancel_timeout (state_reboot, client); + client -> state = S_STOPPED; +} + +int dhclient_interface_shutdown_hook (struct interface_info *interface) +{ + do_release (interface -> client); + + return 1; +} + +int dhclient_interface_discovery_hook (struct interface_info *tmp) +{ + struct interface_info *last, *ip; + /* See if we can find the client from dummy_interfaces */ + last = 0; + for (ip = dummy_interfaces; ip; ip = ip -> next) { + if (!strcmp (ip -> name, tmp -> name)) { + /* Remove from dummy_interfaces */ + if (last) { + ip = (struct interface_info *)0; + interface_reference (&ip, last -> next, MDL); + interface_dereference (&last -> next, MDL); + if (ip -> next) { + interface_reference (&last -> next, + ip -> next, MDL); + interface_dereference (&ip -> next, + MDL); + } + } else { + ip = (struct interface_info *)0; + interface_reference (&ip, + dummy_interfaces, MDL); + interface_dereference (&dummy_interfaces, MDL); + if (ip -> next) { + interface_reference (&dummy_interfaces, + ip -> next, MDL); + interface_dereference (&ip -> next, + MDL); + } + } + /* Copy "client" to tmp */ + if (ip -> client) { + tmp -> client = ip -> client; + tmp -> client -> interface = tmp; + } + interface_dereference (&ip, MDL); + break; + } + last = ip; + } + return 1; +} + +isc_result_t dhclient_interface_startup_hook (struct interface_info *interface) +{ + struct interface_info *ip; + struct client_state *client; + + /* This code needs some rethinking. It doesn't test against + a signal name, and it just kind of bulls into doing something + that may or may not be appropriate. */ + + if (interfaces) { + interface_reference (&interface -> next, interfaces, MDL); + interface_dereference (&interfaces, MDL); + } + interface_reference (&interfaces, interface, MDL); + + discover_interfaces (DISCOVER_UNCONFIGURED); + + for (ip = interfaces; ip; ip = ip -> next) { + /* If interfaces were specified, don't configure + interfaces that weren't specified! */ + if (ip -> flags & INTERFACE_RUNNING || + (ip -> flags & (INTERFACE_REQUESTED | + INTERFACE_AUTOMATIC)) != + INTERFACE_REQUESTED) + continue; + script_init (ip -> client, + "PREINIT", (struct string_list *)0); + if (ip -> client -> alias) + script_write_params (ip -> client, "alias_", + ip -> client -> alias); + script_go (ip -> client); + } + + discover_interfaces (interfaces_requested + ? DISCOVER_REQUESTED + : DISCOVER_RUNNING); + + for (ip = interfaces; ip; ip = ip -> next) { + if (ip -> flags & INTERFACE_RUNNING) + continue; + ip -> flags |= INTERFACE_RUNNING; + for (client = ip -> client; client; client = client -> next) { + client -> state = S_INIT; + /* Set up a timeout to start the initialization + process. */ + add_timeout (cur_time + random () % 5, + state_reboot, client, 0, 0); + } + } + return ISC_R_SUCCESS; +} + +/* The client should never receive a relay agent information option, + so if it does, log it and discard it. */ + +int parse_agent_information_option (packet, len, data) + struct packet *packet; + int len; + u_int8_t *data; +{ + return 1; +} + +/* The client never sends relay agent information options. */ + +unsigned cons_agent_information_options (cfg_options, outpacket, + agentix, length) + struct option_state *cfg_options; + struct dhcp_packet *outpacket; + unsigned agentix; + unsigned length; +{ + return length; +} + +static void shutdown_exit (void *foo) +{ + exit (0); +} + +isc_result_t dhcp_set_control_state (control_object_state_t oldstate, + control_object_state_t newstate) +{ + struct interface_info *ip; + struct client_state *client; + + /* Do the right thing for each interface. */ + for (ip = interfaces; ip; ip = ip -> next) { + for (client = ip -> client; client; client = client -> next) { + switch (newstate) { + case server_startup: + return ISC_R_SUCCESS; + + case server_running: + return ISC_R_SUCCESS; + + case server_shutdown: + if (client -> active && + client -> active -> expiry > cur_time) { + client_dns_update (client, 0); + do_release (client); + } + break; + + case server_hibernate: + state_stop (client); + break; + + case server_awaken: + state_reboot (client); + break; + } + } + } + if (newstate == server_shutdown) + add_timeout (cur_time + 1, shutdown_exit, 0, 0, 0); + return ISC_R_SUCCESS; +} + +/* See if we should do a DNS update, and if so, do it. */ + +void client_dns_update (struct client_state *client, int addp) +{ + struct data_string ddns_fqdn, ddns_fwd_name, + ddns_dhcid, client_identifier; + struct option_cache *oc; + int ignorep; + int result; + isc_result_t rcode; + + /* If we didn't send an FQDN option, we certainly aren't going to + be doing an update. */ + if (!client -> sent_options) + return; + + /* If we don't have a lease, we can't do an update. */ + if (!client -> active) + return; + + /* If we set the no client update flag, don't do the update. */ + if ((oc = lookup_option (&fqdn_universe, client -> sent_options, + FQDN_NO_CLIENT_UPDATE)) && + evaluate_boolean_option_cache (&ignorep, (struct packet *)0, + (struct lease *)0, client, + client -> sent_options, + (struct option_state *)0, + &global_scope, oc, MDL)) + return; + + /* If we set the "server, please update" flag, or didn't set it + to false, don't do the update. */ + if (!(oc = lookup_option (&fqdn_universe, client -> sent_options, + FQDN_SERVER_UPDATE)) || + evaluate_boolean_option_cache (&ignorep, (struct packet *)0, + (struct lease *)0, client, + client -> sent_options, + (struct option_state *)0, + &global_scope, oc, MDL)) + return; + + /* If no FQDN option was supplied, don't do the update. */ + memset (&ddns_fwd_name, 0, sizeof ddns_fwd_name); + if (!(oc = lookup_option (&fqdn_universe, client -> sent_options, + FQDN_FQDN)) || + !evaluate_option_cache (&ddns_fwd_name, (struct packet *)0, + (struct lease *)0, client, + client -> sent_options, + (struct option_state *)0, + &global_scope, oc, MDL)) + return; + + /* Make a dhcid string out of either the client identifier, + if we are sending one, or the interface's MAC address, + otherwise. */ + memset (&ddns_dhcid, 0, sizeof ddns_dhcid); + + memset (&client_identifier, 0, sizeof client_identifier); + if ((oc = lookup_option (&dhcp_universe, client -> sent_options, + DHO_DHCP_CLIENT_IDENTIFIER)) && + evaluate_option_cache (&client_identifier, (struct packet *)0, + (struct lease *)0, client, + client -> sent_options, + (struct option_state *)0, + &global_scope, oc, MDL)) { + result = get_dhcid (&ddns_dhcid, + DHO_DHCP_CLIENT_IDENTIFIER, + client_identifier.data, + client_identifier.len); + data_string_forget (&client_identifier, MDL); + } else + result = get_dhcid (&ddns_dhcid, 0, + client -> interface -> hw_address.hbuf, + client -> interface -> hw_address.hlen); + if (!result) { + data_string_forget (&ddns_fwd_name, MDL); + return; + } + + /* Start the resolver, if necessary. */ + if (!resolver_inited) { + minires_ninit (&resolver_state); + resolver_inited = 1; + resolver_state.retrans = 1; + resolver_state.retry = 1; + } + + /* + * Perform updates. + */ + if (ddns_fwd_name.len && ddns_dhcid.len) { + if (addp) + rcode = ddns_update_a (&ddns_fwd_name, + client -> active -> address, + &ddns_dhcid, DEFAULT_DDNS_TTL, + 1); + else + rcode = ddns_remove_a (&ddns_fwd_name, + client -> active -> address, + &ddns_dhcid); + } + + data_string_forget (&ddns_fwd_name, MDL); + data_string_forget (&ddns_dhcid, MDL); +} diff --git a/contrib/isc-dhcp/client/dhclient.conf.5 b/contrib/isc-dhcp/client/dhclient.conf.5 index 6919081..ecdd4eb 100644 --- a/contrib/isc-dhcp/client/dhclient.conf.5 +++ b/contrib/isc-dhcp/client/dhclient.conf.5 @@ -1,8 +1,6 @@ .\" dhclient.conf.5 .\" -.\" Copyright (c) 1997 The Internet Software Consortium. -.\" All rights reserved. -.\" +.\" Copyright (c) 1996-2001 Internet Software Consortium. .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: @@ -31,10 +29,11 @@ .\" SUCH DAMAGE. .\" .\" This software has been written for the Internet Software Consortium -.\" by Ted Lemon <mellon@fugue.com> in cooperation with Vixie -.\" Enterprises. To learn more about the Internet Software Consortium, -.\" see ``http://www.isc.org/isc''. To learn more about Vixie -.\" Enterprises, see ``http://www.vix.com''. +.\" by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. +.\" To learn more about the Internet Software Consortium, see +.\" ``http://www.isc.org/''. To learn more about Vixie Enterprises, +.\" see ``http://www.vix.com''. To learn more about Nominum, Inc., see +.\" ``http://www.nominum.com''. .TH dhclient.conf 5 .SH NAME dhclient.conf - DHCP client configuration file @@ -190,7 +189,17 @@ are called \fIDHCP Options\fR. DHCP Options are defined in The request statement causes the client to request that any server responding to the client send the client its values for the specified options. Only the option names should be specified in the request -statement - not option parameters. +statement - not option parameters. By default, the DHCP server +requests the subnet-mask, broadcast-address, time-offset, routers, +domain-name, domain-name-servers and host-name options. +.PP +In some cases, it may be desirable to send no parameter request list +at all. To do this, simply write the request statement but specify +no parameters: +.PP +.nf + request; +.fi .PP .I The .B require @@ -218,6 +227,26 @@ than the default requested lease time, which is two hours. The other obvious use for this statement is to send information to the server that will allow it to differentiate between this client and other clients or kinds of clients. +.SH DYNAMIC DNS +The client now has some very limited support for doing DNS updates +when a lease is acquired. This is prototypical, and probably doesn't +do what you want. It also only works if you happen to have control +over your DNS server, which isn't very likely. +.PP +To make it work, you have to declare a key and zone as in the DHCP +server (see \fBdhcpd.conf\fR(5) for details). You also need to +configure the fqdn option on the client, as follows: +.PP +.nf + send fqdn.fqdn "grosse.fugue.com."; + send fqdn.encoded on; + send fqdn.server-update off; +.fi +.PP +The \fIfqdn.fqdn\fR option \fBMUST\fR be a fully-qualified domain +name. You \fBMUST\fR define a zone statement for the zone to be +updated. The \fIfqdn.encoded\fR option may need to be set to +\fIon\fR or \fIoff\fR, depending on the DHCP server you are using. .SH OPTION MODIFIERS In some cases, a client may receive option data from the server which is not really appropriate for that client, or may not receive @@ -230,10 +259,9 @@ needs, several option modifiers are available. .B default .I statement .PP - \fBdefault { [ \fIoption declaration\fR ] -[\fB,\fI ... \fIoption declaration\fR ]\fB}\fR + \fBdefault [ \fIoption declaration\fR ] \fB;\fR .PP -If for some set of options the client should use the value supplied by +If for some option the client should use the value supplied by the server, but needs to use some default value if no value was supplied by the server, these values can be defined in the .B default @@ -243,12 +271,11 @@ statement. .B supersede .I statement .PP - \fBsupersede { [ \fIoption declaration\fR ] -[\fB,\fI ... \fIoption declaration\fR ]\fB}\fR + \fBsupersede [ \fIoption declaration\fR ] \fB;\fR .PP -If for some set of options the client should always use its own value -rather than any value supplied by the server, these values can be -defined in the +If for some option the client should always use a locally-configured +value or values rather than whatever is supplied by the server, these +values can be defined in the .B supersede statement. .PP @@ -256,8 +283,7 @@ statement. .B prepend .I statement .PP - \fBprepend { [ \fIoption declaration\fR ] -[\fB,\fI ... \fIoption declaration\fR ]\fB}\fR + \fBprepend [ \fIoption declaration\fR ] \fB;\fR .PP If for some set of options the client should use a value you supply, and then use the values supplied by @@ -267,14 +293,13 @@ statement. The .B prepend statement can only be used for options which allow more than one value to be given. This restriction is not -enforced - if violated, the results are unpredictable. +enforced - if you ignore it, the behaviour will be unpredictable. .PP .I The .B append .I statement .PP - \fBappend { [ \fIoption declaration\fR ] -[\fB,\fI ... \fIoption declaration\fR ]\fB}\fR + \fBappend [ \fIoption declaration\fR ] \fB;\fR .PP If for some set of options the client should first use the values supplied by the server, if any, and then use values you supply, these @@ -380,7 +405,18 @@ interface's final configuration once a lease has been acquired. If no lease is acquired, the script is used to test predefined leases, if any, and also called once if no valid lease can be identified. For more information, see -.B dhclient-lease(8). +.B dhclient-script(8). +.PP + \fBvendor option space "\fIname\fB";\fR +.PP +The +.B vendor option space +statement is used to specify which option space should be used for +decoding the vendor-encapsulate-options option if one is received. +The \fIdhcp-vendor-identifier\fR can be used to request a specific +class of vendor options from the server. See +.B dhcp-options(5) +for details. .PP \fBmedium "\fImedia setup\fB";\fR .PP @@ -432,8 +468,8 @@ specified as zero. The year is specified with the century, so it should generally be four digits except for really long leases. The month is specified as a number starting with 1 for January. The day of the month is likewise specified starting with 1. The hour is a -number between 0 and 23, the minute a number between 0 and 69, and the -second also a number between 0 and 69. +number between 0 and 23, the minute a number between 0 and 59, and the +second also a number between 0 and 59. .SH ALIAS DECLARATIONS \fBalias { \fI declarations ... \fB}\fR .PP @@ -474,6 +510,36 @@ specified name. Interfaces for which there is no interface declaration will use the parameters declared outside of any interface declaration, or the default settings. .PP + \fBpseudo "\fIname\fR" "\fIreal-name\fB" { \fIdeclarations ... \fB } +.PP +Under some circumstances it can be useful to declare a pseudo-interface +and have the DHCP client acquire a configuration for that interface. +Each interface that the DHCP client is supporting normally has a DHCP +client state machine running on it to acquire and maintain its lease. +A pseudo-interface is just another state machine running on the +interface named \fIreal-name\fR, with its own lease and its own +state. If you use this feature, you must provide a client identifier +for both the pseudo-interface and the actual interface, and the two +identifiers must be different. You must also provide a seperate +client script for the pseudo-interface to do what you want with the IP +address. For example: +.PP +.nf + interface "ep0" { + send dhcp-client-identifier "my-client-ep0"; + } + pseudo "secondary" "ep0" { + send dhcp-client-identifier "my-client-ep0-secondary"; + script "/etc/dhclient-secondary"; + } +.fi +.PP +The client script for the pseudo-interface should not configure the +interface up or down - essentially, all it needs to handle are the +states where a lease has been acquired or renewed, and the states +where a lease has expired. See \fBdhclient-script(8)\fR for more +information. +.PP \fBmedia "\fImedia setup\fB"\fI [ \fB, "\fImedia setup\fB", \fI... ]\fB;\fR .PP The @@ -538,8 +604,8 @@ dhcp-options(5), dhclient.leases(5), dhcpd(8), dhcpd.conf(5), RFC2132, RFC2131. .SH AUTHOR .B dhclient(8) -was written by Ted Lemon <mellon@vix.com> +was written by Ted Lemon under a contract with Vixie Labs. Funding -for this project was provided by the Internet Software Corporation. +for this project was provided by the Internet Software Consortium. Information about the Internet Software Consortium can be found at -.B http://www.isc.org/isc. +.B http://www.isc.org. diff --git a/contrib/isc-dhcp/client/dhclient.leases.5 b/contrib/isc-dhcp/client/dhclient.leases.5 index e0da360..5f1418e 100644 --- a/contrib/isc-dhcp/client/dhclient.leases.5 +++ b/contrib/isc-dhcp/client/dhclient.leases.5 @@ -31,7 +31,7 @@ .\" SUCH DAMAGE. .\" .\" This software has been written for the Internet Software Consortium -.\" by Ted Lemon <mellon@fugue.com> in cooperation with Vixie +.\" by Ted Lemon in cooperation with Vixie .\" Enterprises. To learn more about the Internet Software Consortium, .\" see ``http://www.isc.org/isc''. To learn more about Vixie .\" Enterprises, see ``http://www.vix.com''. @@ -55,8 +55,8 @@ dhclient(8), dhcp-options(5), dhclient.conf(5), dhcpd(8), dhcpd.conf(5), RFC2132, RFC2131. .SH AUTHOR .B dhclient(8) -was written by Ted Lemon <mellon@vix.com> +was written by Ted Lemon under a contract with Vixie Labs. Funding -for this project was provided by the Internet Software Corporation. +for this project was provided by the Internet Software Consortium. Information about the Internet Software Consortium can be found at -.B http://www.isc.org/isc. +.B http://www.isc.org. diff --git a/contrib/isc-dhcp/client/scripts/freebsd b/contrib/isc-dhcp/client/scripts/freebsd index ce7a1bf..652d0d0 100755 --- a/contrib/isc-dhcp/client/scripts/freebsd +++ b/contrib/isc-dhcp/client/scripts/freebsd @@ -1,16 +1,24 @@ #!/bin/sh +if [ -x /usr/bin/logger ]; then + LOGGER="/usr/bin/logger -s -p user.notice -t dhclient" +else + LOGGER=echo +fi + make_resolv_conf() { - echo search $new_domain_name >/etc/resolv.conf - for nameserver in $new_domain_name_servers; do - echo nameserver $nameserver >>/etc/resolv.conf - done + if [ "x$new_domain_name" != x ] && [ x"$new_domain_name_servers" != x ]; then + echo search $new_domain_name >/etc/resolv.conf + for nameserver in $new_domain_name_servers; do + echo nameserver $nameserver >>/etc/resolv.conf + done + fi } # Must be used on exit. Invokes the local dhcp client exit hooks, if any. exit_with_hooks() { exit_status=$1 - if [ -x /etc/dhclient-exit-hooks ]; then + if [ -f /etc/dhclient-exit-hooks ]; then . /etc/dhclient-exit-hooks fi # probably should do something with exit status of the local script @@ -18,7 +26,7 @@ exit_with_hooks() { } # Invoke the local dhcp client enter hooks, if they exist. -if [ -x /etc/dhclient-enter-hooks ]; then +if [ -f /etc/dhclient-enter-hooks ]; then exit_status=0 . /etc/dhclient-enter-hooks # allow the local script to abort processing of this state @@ -29,11 +37,11 @@ if [ -x /etc/dhclient-enter-hooks ]; then fi if [ x$new_network_number != x ]; then - echo New Network Number: $new_network_number + $LOGGER New Network Number: $new_network_number fi if [ x$new_broadcast_address != x ]; then - echo New Broadcast Address: $new_broadcast_address + $LOGGER New Broadcast Address: $new_broadcast_address new_broadcast_arg="broadcast $new_broadcast_address" fi if [ x$old_broadcast_address != x ]; then @@ -50,8 +58,8 @@ if [ x$alias_subnet_mask != x ]; then fi if [ x$reason = xMEDIUM ]; then - ifconfig $interface $medium - ifconfig $interface inet -alias 0.0.0.0 $medium >/dev/null 2>&1 + eval "ifconfig $interface $medium" + eval "ifconfig $interface inet -alias 0.0.0.0 $medium" >/dev/null 2>&1 sleep 1 exit_with_hooks 0 fi @@ -72,36 +80,53 @@ fi if [ x$reason = xBOUND ] || [ x$reason = xRENEW ] || \ [ x$reason = xREBIND ] || [ x$reason = xREBOOT ]; then + current_hostname=`hostname` + if [ x$current_hostname = x ] || \ + [ x$current_hostname = x$old_host_name ]; then + if [ x$current_hostname = x ] || \ + [ x$new_host_name != x$old_host_name ]; then + $LOGGER "New Hostname: $new_host_name" + hostname $new_host_name + fi + fi if [ x$old_ip_address != x ] && [ x$alias_ip_address != x ] && \ [ x$alias_ip_address != x$old_ip_address ]; then ifconfig $interface inet -alias $alias_ip_address > /dev/null 2>&1 route delete $alias_ip_address 127.0.0.1 > /dev/null 2>&1 fi - if [ x$old_ip_address != x ] && [ x$old_ip_address != x$new_ip_address ]; then - ifconfig $interface inet -alias $old_ip_address $medium + if [ x$old_ip_address != x ] && [ x$old_ip_address != x$new_ip_address ] + then + eval "ifconfig $interface inet -alias $old_ip_address $medium" route delete $old_ip_address 127.1 >/dev/null 2>&1 for router in $old_routers; do route delete default $router >/dev/null 2>&1 done if [ "$old_static_routes" != "" ]; then - set $old_static_routes + set -- $old_static_routes while [ $# -gt 1 ]; do route delete $1 $2 shift; shift done fi - arp -n -a | sed -n -e 's/^.*(\(.*\)) at .*$/arp -n -d \1/p' |sh + arp -n -a | sed -n -e 's/^.*(\(.*\)) at .*$/arp -d \1/p' |sh fi if [ x$old_ip_address = x ] || [ x$old_ip_address != x$new_ip_address ] || \ [ x$reason = xBOUND ] || [ x$reason = xREBOOT ]; then - ifconfig $interface inet $new_ip_address $new_netmask_arg \ - $new_broadcast_arg $medium + eval "ifconfig $interface inet $new_ip_address $new_netmask_arg \ + $new_broadcast_arg $medium" + $LOGGER "New IP Address($interface): $new_ip_address" + $LOGGER "New Subnet Mask($interface): $new_subnet_mask" + $LOGGER "New Broadcast Address($interface): $new_broadcast_address" + if [ "$new_routers" != "" ]; then + $LOGGER "New Routers: $new_routers" + fi route add $new_ip_address 127.1 >/dev/null 2>&1 for router in $new_routers; do route add default $router >/dev/null 2>&1 done if [ "$new_static_routes" != "" ]; then - set $new_static_routes + $LOGGER "New Static Routes: $new_static_routes" + set -- $new_static_routes while [ $# -gt 1 ]; do route add $1 $2 shift; shift @@ -113,26 +138,24 @@ if [ x$reason = xBOUND ] || [ x$reason = xRENEW ] || \ ifconfig $interface inet alias $alias_ip_address $alias_subnet_arg route add $alias_ip_address 127.0.0.1 fi - echo search $new_domain_name >/etc/resolv.conf - for nameserver in $new_domain_name_servers; do - echo nameserver $nameserver >>/etc/resolv.conf - done + make_resolv_conf exit_with_hooks 0 fi -if [ x$reason = xEXPIRE ] || [ x$reason = xFAIL ]; then +if [ x$reason = xEXPIRE ] || [ x$reason = xFAIL ] || [ x$reason = xRELEASE ] \ + || [ x$reason = xSTOP ]; then if [ x$alias_ip_address != x ]; then ifconfig $interface inet -alias $alias_ip_address > /dev/null 2>&1 route delete $alias_ip_address 127.0.0.1 > /dev/null 2>&1 fi if [ x$old_ip_address != x ]; then - ifconfig $interface inet -alias $old_ip_address $medium + eval "ifconfig $interface inet -alias $old_ip_address $medium" route delete $old_ip_address 127.1 >/dev/null 2>&1 for router in $old_routers; do route delete default $router >/dev/null 2>&1 done if [ "$old_static_routes" != "" ]; then - set $old_static_routes + set -- $old_static_routes while [ $# -gt 1 ]; do route delete $1 $2 shift; shift @@ -153,11 +176,15 @@ if [ x$reason = xTIMEOUT ]; then ifconfig $interface inet -alias $alias_ip_address > /dev/null 2>&1 route delete $alias_ip_address 127.0.0.1 > /dev/null 2>&1 fi - ifconfig $interface inet $new_ip_address $new_netmask_arg \ - $new_broadcast_arg $medium + eval "ifconfig $interface inet $new_ip_address $new_netmask_arg \ + $new_broadcast_arg $medium" + $LOGGER "New IP Address($interface): $new_ip_address" + $LOGGER "New Subnet Mask($interface): $new_subnet_mask" + $LOGGER "New Broadcast Address($interface): $new_broadcast_address" sleep 1 if [ "$new_routers" != "" ]; then - set $new_routers + $LOGGER "New Routers: $new_routers" + set -- $new_routers if ping -q -c 1 $1; then if [ x$new_ip_address != x$alias_ip_address ] && \ [ x$alias_ip_address != x ]; then @@ -168,34 +195,27 @@ if [ x$reason = xTIMEOUT ]; then for router in $new_routers; do route add default $router >/dev/null 2>&1 done - set $new_static_routes + set -- $new_static_routes while [ $# -gt 1 ]; do - route add $0 $1 + route add $1 $2 shift; shift done - echo search $new_domain_name >/etc/resolv.conf.std - for nameserver in $new_domain_name_servers; do - echo nameserver $nameserver >>/etc/resolv.conf.std - done - if [ -f /etc/resolv.conf ]; then - rm -f /etc/resolv.conf - fi - mv /etc/resolv.conf.std /etc/resolv.conf + make_resolv_conf exit_with_hooks 0 fi fi - ifconfig $interface inet -alias $new_ip_address $medium + eval "ifconfig $interface inet -alias $new_ip_address $medium" for router in $old_routers; do route delete default $router >/dev/null 2>&1 done if [ "$old_static_routes" != "" ]; then - set $old_static_routes + set -- $old_static_routes while [ $# -gt 1 ]; do route delete $1 $2 shift; shift done fi - arp -n -a | sed -n -e 's/^.*(\(.*\)) at .*$/arp -n -d \1/p' \ + arp -n -a | sed -n -e 's/^.*(\(.*\)) at .*$/arp -d \1/p' \ |sh >/dev/null 2>&1 exit_with_hooks 1 fi diff --git a/contrib/isc-dhcp/common/Makefile.dist b/contrib/isc-dhcp/common/Makefile.dist index 1e3e062..3efa120 100644 --- a/contrib/isc-dhcp/common/Makefile.dist +++ b/contrib/isc-dhcp/common/Makefile.dist @@ -1,49 +1,18 @@ # Makefile.dist -# -# Copyright (c) 1996, 1999 The Internet Software Consortium. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# 3. Neither the name of The Internet Software Consortium nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND -# CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, -# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -# THE INTERNET SOFTWARE CONSORTIUM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED -# OF THE POSSIBILITY OF SUCH DAMAGE. -# -CATMANPAGES = dhcp-options.cat5 -SEDMANPAGES = dhcp-options.man5 +CATMANPAGES = dhcp-options.cat5 dhcp-eval.cat5 +SEDMANPAGES = dhcp-options.man5 dhcp-eval.man5 SRC = raw.c parse.c nit.c icmp.c dispatch.c conflex.c upf.c bpf.c socket.c \ - lpf.c packet.c memory.c print.c options.c inet.c convert.c \ - tree.c tables.c hash.c alloc.c errwarn.c inet_addr.c dlpi.c \ - tr.c ethernet.c + lpf.c dlpi.c packet.c tr.c ethernet.c memory.c print.c options.c \ + inet.c tree.c tables.c alloc.c fddi.c ctrace.c \ + dns.c resolv.c execute.c discover.c comapi.c OBJ = raw.o parse.o nit.o icmp.o dispatch.o conflex.o upf.o bpf.o socket.o \ - lpf.o packet.o memory.o print.o options.o inet.o convert.o \ - tree.o tables.o hash.o alloc.o errwarn.o inet_addr.o dlpi.o \ - tr.o ethernet.o -MAN = dhcp-options.5 + lpf.o dlpi.o packet.o tr.o ethernet.o memory.o print.o options.o \ + inet.o tree.o tables.o alloc.o fddi.o ctrace.o \ + dns.o resolv.o execute.o discover.o comapi.o +MAN = dhcp-options.5 dhcp-eval.5 -DEBUG = -g -INCLUDES = -I.. -I../includes +INCLUDES = -I$(TOP) $(BINDINC) -I$(TOP)/includes CFLAGS = $(DEBUG) $(PREDEFINES) $(INCLUDES) $(COPTS) all: libdhcp.a $(CATMANPAGES) @@ -51,7 +20,7 @@ all: libdhcp.a $(CATMANPAGES) libdhcp.a: $(OBJ) rm -f libdhcp.a ar cruv libdhcp.a $(OBJ) - ranlib libdhcp.a + $(RANLIB) libdhcp.a install: all for dir in $(FFMANDIR); do \ @@ -66,17 +35,29 @@ install: all done $(MANINSTALL) $(MANFROM) dhcp-options.$(MANCAT)5 $(MANTO) \ $(DESTDIR)$(FFMANDIR)/dhcp-options$(FFMANEXT) + $(MANINSTALL) $(MANFROM) dhcp-eval.$(MANCAT)5 $(MANTO) \ + $(DESTDIR)$(FFMANDIR)/dhcp-eval$(FFMANEXT) +depend: + $(MKDEP) $(INCLUDES) $(PREDEFINES) $(SRC) clean: -rm -f $(OBJ) - + realclean: clean - -rm -f libdhcp.a *~ #* $(CATMANPAGES) $(SEDMANPAGES) + -rm -f libdhcp.a $(CATMANPAGES) $(SEDMANPAGES) *~ #* distclean: realclean -rm -f Makefile +links: + @for foo in $(SRC) $(MAN); do \ + if [ ! -b $$foo ]; then \ + rm -f $$foo; \ + fi; \ + ln -s $(TOP)/common/$$foo $$foo; \ + done + dhcp-options.cat5: dhcp-options.man5 nroff -man dhcp-options.man5 >dhcp-options.cat5 @@ -84,123 +65,11 @@ dhcp-options.man5: dhcp-options.5 sed -e "s#ETCDIR#$(ETC)#g" -e "s#DBDIR#$(VARDB)#g" \ -e "s#RUNDIR#$(VARRUN)#g" < dhcp-options.5 >dhcp-options.man5 -# Dependencies (semi-automatically-generated) +dhcp-eval.cat5: dhcp-eval.man5 + nroff -man dhcp-eval.man5 >dhcp-eval.cat5 -raw.o: raw.c ../includes/dhcpd.h \ - ../includes/cdefs.h ../includes/osdep.h ../includes/site.h \ - ../includes/cf/netbsd.h ../includes/dhcp.h \ - ../includes/tree.h ../includes/hash.h ../includes/inet.h \ - ../includes/sysconf.h -parse.o: parse.c ../includes/dhcpd.h \ - ../includes/cdefs.h ../includes/osdep.h ../includes/site.h \ - ../includes/cf/netbsd.h \ - ../includes/dhcp.h ../includes/tree.h ../includes/hash.h ../includes/inet.h \ - ../includes/sysconf.h ../includes/dhctoken.h -nit.o: nit.c ../includes/dhcpd.h \ - ../includes/cdefs.h ../includes/osdep.h ../includes/site.h \ - ../includes/cf/netbsd.h ../includes/dhcp.h \ - ../includes/tree.h ../includes/hash.h ../includes/inet.h \ - ../includes/sysconf.h -icmp.o: icmp.c ../includes/dhcpd.h \ - ../includes/cdefs.h ../includes/osdep.h ../includes/site.h \ - ../includes/cf/netbsd.h ../includes/dhcp.h \ - ../includes/tree.h ../includes/hash.h ../includes/inet.h \ - ../includes/sysconf.h ../includes/netinet/ip.h \ - ../includes/netinet/ip_icmp.h -dispatch.o: dispatch.c ../includes/dhcpd.h \ - ../includes/cdefs.h ../includes/osdep.h ../includes/site.h \ - ../includes/cf/netbsd.h ../includes/dhcp.h \ - ../includes/tree.h ../includes/hash.h ../includes/inet.h \ - ../includes/sysconf.h \ - conflex.c ../includes/dhcpd.h \ - ../includes/cdefs.h ../includes/osdep.h ../includes/site.h \ - ../includes/cf/netbsd.h ../includes/dhcp.h \ - ../includes/tree.h ../includes/hash.h ../includes/inet.h \ - ../includes/sysconf.h ../includes/dhctoken.h -upf.o: upf.c ../includes/dhcpd.h \ - ../includes/cdefs.h ../includes/osdep.h ../includes/site.h \ - ../includes/cf/netbsd.h ../includes/dhcp.h \ - ../includes/tree.h ../includes/hash.h ../includes/inet.h \ - ../includes/sysconf.h -bpf.o: bpf.c ../includes/dhcpd.h \ - ../includes/cdefs.h ../includes/osdep.h ../includes/site.h \ - ../includes/cf/netbsd.h ../includes/dhcp.h \ - ../includes/tree.h ../includes/hash.h ../includes/inet.h \ - ../includes/sysconf.h ../includes/netinet/ip.h ../includes/netinet/udp.h \ - ../includes/netinet/if_ether.h -socket.o: socket.c ../includes/dhcpd.h \ - ../includes/cdefs.h ../includes/osdep.h ../includes/site.h \ - ../includes/cf/netbsd.h ../includes/dhcp.h \ - ../includes/tree.h ../includes/hash.h ../includes/inet.h \ - ../includes/sysconf.h -lpf.o: lpf.c ../includes/dhcpd.h \ - ../includes/cdefs.h ../includes/osdep.h ../includes/site.h \ - ../includes/cf/netbsd.h ../includes/dhcp.h \ - ../includes/tree.h ../includes/hash.h ../includes/inet.h \ - ../includes/sysconf.h -packet.o: packet.c ../includes/dhcpd.h \ - ../includes/cdefs.h ../includes/osdep.h ../includes/site.h \ - ../includes/cf/netbsd.h ../includes/dhcp.h \ - ../includes/tree.h ../includes/hash.h ../includes/inet.h \ - ../includes/sysconf.h ../includes/netinet/ip.h \ - ../includes/netinet/udp.h ../includes/netinet/if_ether.h -memory.o: memory.c ../includes/dhcpd.h \ - ../includes/cdefs.h ../includes/osdep.h ../includes/site.h \ - ../includes/cf/netbsd.h ../includes/dhcp.h \ - ../includes/tree.h ../includes/hash.h ../includes/inet.h \ - ../includes/sysconf.h -print.o: print.c ../includes/dhcpd.h \ - ../includes/cdefs.h ../includes/osdep.h ../includes/site.h \ - ../includes/cf/netbsd.h ../includes/dhcp.h \ - ../includes/tree.h ../includes/hash.h ../includes/inet.h \ - ../includes/sysconf.h -options.o: options.c ../includes/dhcpd.h \ - ../includes/cdefs.h ../includes/osdep.h ../includes/site.h \ - ../includes/cf/netbsd.h ../includes/dhcp.h \ - ../includes/tree.h ../includes/hash.h ../includes/inet.h \ - ../includes/sysconf.h -inet.o: inet.c ../includes/dhcpd.h \ - ../includes/cdefs.h ../includes/osdep.h ../includes/site.h \ - ../includes/cf/netbsd.h ../includes/dhcp.h \ - ../includes/tree.h ../includes/hash.h ../includes/inet.h \ - ../includes/sysconf.h -convert.o: convert.c ../includes/dhcpd.h \ - ../includes/cdefs.h ../includes/osdep.h ../includes/site.h \ - ../includes/cf/netbsd.h ../includes/dhcp.h \ - ../includes/tree.h ../includes/hash.h ../includes/inet.h \ - ../includes/sysconf.h -tree.o: tree.c ../includes/dhcpd.h \ - ../includes/cdefs.h ../includes/osdep.h ../includes/site.h \ - ../includes/cf/netbsd.h ../includes/dhcp.h \ - ../includes/tree.h ../includes/hash.h ../includes/inet.h \ - ../includes/sysconf.h -tables.o: tables.c ../includes/dhcpd.h \ - ../includes/cdefs.h ../includes/osdep.h ../includes/site.h \ - ../includes/cf/netbsd.h ../includes/dhcp.h \ - ../includes/tree.h ../includes/hash.h ../includes/inet.h \ - ../includes/sysconf.h -hash.o: hash.c ../includes/dhcpd.h \ - ../includes/cdefs.h ../includes/osdep.h ../includes/site.h \ - ../includes/cf/netbsd.h ../includes/dhcp.h \ - ../includes/tree.h ../includes/hash.h ../includes/inet.h \ - ../includes/sysconf.h -alloc.o: alloc.c ../includes/dhcpd.h \ - ../includes/cdefs.h ../includes/osdep.h ../includes/site.h \ - ../includes/cf/netbsd.h ../includes/dhcp.h \ - ../includes/tree.h ../includes/hash.h ../includes/inet.h \ - ../includes/sysconf.h -errwarn.o: errwarn.c ../includes/dhcpd.h \ - ../includes/cdefs.h ../includes/osdep.h ../includes/site.h \ - ../includes/cf/netbsd.h ../includes/dhcp.h \ - ../includes/tree.h ../includes/hash.h ../includes/inet.h \ - ../includes/sysconf.h -inet_addr.o: inet_addr.c ../includes/dhcpd.h \ - ../includes/cdefs.h ../includes/osdep.h ../includes/site.h \ - ../includes/cf/netbsd.h ../includes/dhcp.h \ - ../includes/tree.h ../includes/hash.h ../includes/inet.h \ - ../includes/sysconf.h -dlpi.o: dlpi.c ../includes/dhcpd.h \ - ../includes/cdefs.h ../includes/osdep.h ../includes/site.h \ - ../includes/cf/netbsd.h ../includes/dhcp.h \ - ../includes/tree.h ../includes/hash.h ../includes/inet.h \ - ../includes/sysconf.h +dhcp-eval.man5: dhcp-eval.5 + sed -e "s#ETCDIR#$(ETC)#g" -e "s#DBDIR#$(VARDB)#g" \ + -e "s#RUNDIR#$(VARRUN)#g" < dhcp-eval.5 >dhcp-eval.man5 + +# Dependencies (semi-automatically-generated) diff --git a/contrib/isc-dhcp/common/alloc.c b/contrib/isc-dhcp/common/alloc.c index 61d7572..5ed0204 100644 --- a/contrib/isc-dhcp/common/alloc.c +++ b/contrib/isc-dhcp/common/alloc.c @@ -3,7 +3,7 @@ Memory allocation... */ /* - * Copyright (c) 1995, 1996, 1998 The Internet Software Consortium. + * Copyright (c) 1996-2001 Internet Software Consortium. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,299 +34,1293 @@ * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium - * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie - * Enterprises. To learn more about the Internet Software Consortium, - * see ``http://www.vix.com/isc''. To learn more about Vixie - * Enterprises, see ``http://www.vix.com''. + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. */ #ifndef lint static char copyright[] = -"$Id: alloc.c,v 1.13.2.2 1999/03/26 16:39:36 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n"; +"$Id: alloc.c,v 1.53.2.8 2001/10/18 20:30:02 mellon Exp $ Copyright (c) 1996-2000 The Internet Software Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" +#include <omapip/omapip_p.h> struct dhcp_packet *dhcp_free_list; struct packet *packet_free_list; -VOIDPTR dmalloc (size, name) +int option_chain_head_allocate (ptr, file, line) + struct option_chain_head **ptr; + const char *file; + int line; +{ int size; - char *name; + struct option_chain_head *h; + + if (!ptr) { + log_error ("%s(%d): null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + if (*ptr) { + log_error ("%s(%d): non-null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + *ptr = (struct option_chain_head *)0; +#endif + } + + h = dmalloc (sizeof *h, file, line); + if (h) { + memset (h, 0, sizeof *h); + return option_chain_head_reference (ptr, h, file, line); + } + return 0; +} + +int option_chain_head_reference (ptr, bp, file, line) + struct option_chain_head **ptr; + struct option_chain_head *bp; + const char *file; + int line; { - VOIDPTR foo = (VOIDPTR)malloc (size); - if (!foo) - warn ("No memory for %s.", name); - else - memset (foo, 0, size); - return foo; + if (!ptr) { + log_error ("%s(%d): null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + if (*ptr) { + log_error ("%s(%d): non-null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + *ptr = (struct option_chain_head *)0; +#endif + } + *ptr = bp; + bp -> refcnt++; + rc_register (file, line, ptr, bp, bp -> refcnt, 0, RC_MISC); + return 1; +} + +int option_chain_head_dereference (ptr, file, line) + struct option_chain_head **ptr; + const char *file; + int line; +{ + int i; + struct option_chain_head *option_chain_head; + pair car, cdr; + + if (!ptr || !*ptr) { + log_error ("%s(%d): null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + + option_chain_head = *ptr; + *ptr = (struct option_chain_head *)0; + --option_chain_head -> refcnt; + rc_register (file, line, ptr, option_chain_head, + option_chain_head -> refcnt, 1, RC_MISC); + if (option_chain_head -> refcnt > 0) + return 1; + + if (option_chain_head -> refcnt < 0) { + log_error ("%s(%d): negative refcnt!", file, line); +#if defined (DEBUG_RC_HISTORY) + dump_rc_history (option_chain_head); +#endif +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + + /* If there are any options on this head, free them. */ + for (car = option_chain_head -> first; car; car = cdr) { + cdr = car -> cdr; + if (car -> car) + option_cache_dereference ((struct option_cache **) + (&car -> car), MDL); + dfree (car, MDL); + car = cdr; + } + + dfree (option_chain_head, file, line); + return 1; } -void dfree (ptr, name) - VOIDPTR ptr; - char *name; +int group_allocate (ptr, file, line) + struct group **ptr; + const char *file; + int line; { + int size; + struct group *g; + if (!ptr) { - warn ("dfree %s: free on null pointer.", name); - return; + log_error ("%s(%d): null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + if (*ptr) { + log_error ("%s(%d): non-null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + *ptr = (struct group *)0; +#endif } - free (ptr); + + g = dmalloc (sizeof *g, file, line); + if (g) { + memset (g, 0, sizeof *g); + return group_reference (ptr, g, file, line); + } + return 0; } -struct packet *new_packet (name) - char *name; +int group_reference (ptr, bp, file, line) + struct group **ptr; + struct group *bp; + const char *file; + int line; { - struct packet *rval; - rval = (struct packet *)dmalloc (sizeof (struct packet), name); - return rval; + if (!ptr) { + log_error ("%s(%d): null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + if (*ptr) { + log_error ("%s(%d): non-null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + *ptr = (struct group *)0; +#endif + } + *ptr = bp; + bp -> refcnt++; + rc_register (file, line, ptr, bp, bp -> refcnt, 0, RC_MISC); + return 1; +} + +int group_dereference (ptr, file, line) + struct group **ptr; + const char *file; + int line; +{ + int i; + struct group *group; + + if (!ptr || !*ptr) { + log_error ("%s(%d): null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + + group = *ptr; + *ptr = (struct group *)0; + --group -> refcnt; + rc_register (file, line, ptr, group, group -> refcnt, 1, RC_MISC); + if (group -> refcnt > 0) + return 1; + + if (group -> refcnt < 0) { + log_error ("%s(%d): negative refcnt!", file, line); +#if defined (DEBUG_RC_HISTORY) + dump_rc_history (group); +#endif +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + + if (group -> object) + group_object_dereference (&group -> object, file, line); + if (group -> subnet) + subnet_dereference (&group -> subnet, file, line); + if (group -> shared_network) + shared_network_dereference (&group -> shared_network, + file, line); + if (group -> statements) + executable_statement_dereference (&group -> statements, + file, line); + if (group -> next) + group_dereference (&group -> next, file, line); + dfree (group, file, line); + return 1; } -struct dhcp_packet *new_dhcp_packet (name) - char *name; +struct dhcp_packet *new_dhcp_packet (file, line) + const char *file; + int line; { struct dhcp_packet *rval; rval = (struct dhcp_packet *)dmalloc (sizeof (struct dhcp_packet), - name); + file, line); + return rval; +} + +struct protocol *new_protocol (file, line) + const char *file; + int line; +{ + struct protocol *rval = dmalloc (sizeof (struct protocol), file, line); + return rval; +} + +struct domain_search_list *new_domain_search_list (file, line) + const char *file; + int line; +{ + struct domain_search_list *rval = + dmalloc (sizeof (struct domain_search_list), file, line); + return rval; +} + +struct name_server *new_name_server (file, line) + const char *file; + int line; +{ + struct name_server *rval = + dmalloc (sizeof (struct name_server), file, line); + return rval; +} + +void free_name_server (ptr, file, line) + struct name_server *ptr; + const char *file; + int line; +{ + dfree ((VOIDPTR)ptr, file, line); +} + +struct option *new_option (file, line) + const char *file; + int line; +{ + struct option *rval = + dmalloc (sizeof (struct option), file, line); + if (rval) + memset (rval, 0, sizeof *rval); return rval; } -struct tree *new_tree (name) - char *name; +void free_option (ptr, file, line) + struct option *ptr; + const char *file; + int line; +{ +/* XXX have to put all options on heap before this is possible. */ +#if 0 + if (ptr -> name) + dfree ((VOIDPTR)option -> name, file, line); + dfree ((VOIDPTR)ptr, file, line); +#endif +} + +struct universe *new_universe (file, line) + const char *file; + int line; { - struct tree *rval = dmalloc (sizeof (struct tree), name); + struct universe *rval = + dmalloc (sizeof (struct universe), file, line); return rval; } -struct tree_cache *free_tree_caches; +void free_universe (ptr, file, line) + struct universe *ptr; + const char *file; + int line; +{ + dfree ((VOIDPTR)ptr, file, line); +} + +void free_domain_search_list (ptr, file, line) + struct domain_search_list *ptr; + const char *file; + int line; +{ + dfree ((VOIDPTR)ptr, file, line); +} + +void free_protocol (ptr, file, line) + struct protocol *ptr; + const char *file; + int line; +{ + dfree ((VOIDPTR)ptr, file, line); +} + +void free_dhcp_packet (ptr, file, line) + struct dhcp_packet *ptr; + const char *file; + int line; +{ + dfree ((VOIDPTR)ptr, file, line); +} + +struct client_lease *new_client_lease (file, line) + const char *file; + int line; +{ + return (struct client_lease *)dmalloc (sizeof (struct client_lease), + file, line); +} + +void free_client_lease (lease, file, line) + struct client_lease *lease; + const char *file; + int line; +{ + dfree (lease, file, line); +} + +pair free_pairs; -struct tree_cache *new_tree_cache (name) - char *name; +pair new_pair (file, line) + const char *file; + int line; { - struct tree_cache *rval; + pair foo; + + if (free_pairs) { + foo = free_pairs; + free_pairs = foo -> cdr; + memset (foo, 0, sizeof *foo); + dmalloc_reuse (foo, file, line, 0); + return foo; + } + + foo = dmalloc (sizeof *foo, file, line); + if (!foo) + return foo; + memset (foo, 0, sizeof *foo); + return foo; +} - if (free_tree_caches) { - rval = free_tree_caches; - free_tree_caches = - (struct tree_cache *)(rval -> value); +void free_pair (foo, file, line) + pair foo; + const char *file; + int line; +{ + foo -> cdr = free_pairs; + free_pairs = foo; + dmalloc_reuse (free_pairs, (char *)0, 0, 0); +} + +#if defined (DEBUG_MEMORY_LEAKAGE) || \ + defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) +void relinquish_free_pairs () +{ + pair pf, pc; + + for (pf = free_pairs; pf; pf = pc) { + pc = pf -> cdr; + dfree (pf, MDL); + } + free_pairs = (pair)0; +} +#endif + +struct expression *free_expressions; + +int expression_allocate (cptr, file, line) + struct expression **cptr; + const char *file; + int line; +{ + struct expression *rval; + + if (free_expressions) { + rval = free_expressions; + free_expressions = rval -> data.not; + dmalloc_reuse (rval, file, line, 1); } else { - rval = dmalloc (sizeof (struct tree_cache), name); + rval = dmalloc (sizeof (struct expression), file, line); if (!rval) - error ("unable to allocate tree cache for %s.", name); + return 0; } - return rval; + memset (rval, 0, sizeof *rval); + return expression_reference (cptr, rval, file, line); } -struct hash_table *new_hash_table (count, name) - int count; - char *name; +int expression_reference (ptr, src, file, line) + struct expression **ptr; + struct expression *src; + const char *file; + int line; { - struct hash_table *rval = dmalloc (sizeof (struct hash_table) - - (DEFAULT_HASH_SIZE - * sizeof (struct hash_bucket *)) - + (count - * sizeof (struct hash_bucket *)), - name); - rval -> hash_count = count; - return rval; + if (!ptr) { + log_error ("%s(%d): null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + if (*ptr) { + log_error ("%s(%d): non-null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + *ptr = (struct expression *)0; +#endif + } + *ptr = src; + src -> refcnt++; + rc_register (file, line, ptr, src, src -> refcnt, 0, RC_MISC); + return 1; } -struct hash_bucket *new_hash_bucket (name) - char *name; +void free_expression (expr, file, line) + struct expression *expr; + const char *file; + int line; { - struct hash_bucket *rval = dmalloc (sizeof (struct hash_bucket), name); - return rval; + expr -> data.not = free_expressions; + free_expressions = expr; + dmalloc_reuse (free_expressions, (char *)0, 0, 0); } -struct lease *new_leases (n, name) - int n; - char *name; +#if defined (DEBUG_MEMORY_LEAKAGE) || \ + defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) +void relinquish_free_expressions () { - struct lease *rval = dmalloc (n * sizeof (struct lease), name); - return rval; + struct expression *e, *n; + + for (e = free_expressions; e; e = n) { + n = e -> data.not; + dfree (e, MDL); + } + free_expressions = (struct expression *)0; } +#endif -struct lease *new_lease (name) - char *name; +struct binding_value *free_binding_values; + +int binding_value_allocate (cptr, file, line) + struct binding_value **cptr; + const char *file; + int line; { - struct lease *rval = dmalloc (sizeof (struct lease), name); - return rval; + struct binding_value *rval; + + if (free_binding_values) { + rval = free_binding_values; + free_binding_values = rval -> value.bv; + dmalloc_reuse (rval, file, line, 1); + } else { + rval = dmalloc (sizeof (struct binding_value), file, line); + if (!rval) + return 0; + } + memset (rval, 0, sizeof *rval); + return binding_value_reference (cptr, rval, file, line); } -struct subnet *new_subnet (name) - char *name; +int binding_value_reference (ptr, src, file, line) + struct binding_value **ptr; + struct binding_value *src; + const char *file; + int line; { - struct subnet *rval = dmalloc (sizeof (struct subnet), name); - return rval; + if (!ptr) { + log_error ("%s(%d): null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + if (*ptr) { + log_error ("%s(%d): non-null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + *ptr = (struct binding_value *)0; +#endif + } + *ptr = src; + src -> refcnt++; + rc_register (file, line, ptr, src, src -> refcnt, 0, RC_MISC); + return 1; } -struct class *new_class (name) - char *name; +void free_binding_value (bv, file, line) + struct binding_value *bv; + const char *file; + int line; { - struct class *rval = dmalloc (sizeof (struct class), name); - return rval; + bv -> value.bv = free_binding_values; + free_binding_values = bv; + dmalloc_reuse (free_binding_values, (char *)0, 0, 0); } -struct shared_network *new_shared_network (name) - char *name; +#if defined (DEBUG_MEMORY_LEAKAGE) || \ + defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) +void relinquish_free_binding_values () { - struct shared_network *rval = - dmalloc (sizeof (struct shared_network), name); - return rval; + struct binding_value *b, *n; + + for (b = free_binding_values; b; b = n) { + n = b -> value.bv; + dfree (b, MDL); + } + free_binding_values = (struct binding_value *)0; } +#endif -struct group *new_group (name) - char *name; +int fundef_allocate (cptr, file, line) + struct fundef **cptr; + const char *file; + int line; { - struct group *rval = - dmalloc (sizeof (struct group), name); - return rval; + struct fundef *rval; + + rval = dmalloc (sizeof (struct fundef), file, line); + if (!rval) + return 0; + memset (rval, 0, sizeof *rval); + return fundef_reference (cptr, rval, file, line); } -struct protocol *new_protocol (name) - char *name; +int fundef_reference (ptr, src, file, line) + struct fundef **ptr; + struct fundef *src; + const char *file; + int line; { - struct protocol *rval = dmalloc (sizeof (struct protocol), name); - return rval; + if (!ptr) { + log_error ("%s(%d): null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + if (*ptr) { + log_error ("%s(%d): non-null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + *ptr = (struct fundef *)0; +#endif + } + *ptr = src; + src -> refcnt++; + rc_register (file, line, ptr, src, src -> refcnt, 0, RC_MISC); + return 1; } -struct lease_state *free_lease_states; +struct option_cache *free_option_caches; -struct lease_state *new_lease_state (name) - char *name; +#if defined (DEBUG_MEMORY_LEAKAGE) || \ + defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) +void relinquish_free_option_caches () { - struct lease_state *rval; + struct option_cache *o, *n; - if (free_lease_states) { - rval = free_lease_states; - free_lease_states = - (struct lease_state *)(free_lease_states -> next); + for (o = free_option_caches; o; o = n) { + n = (struct option_cache *)(o -> expression); + dfree (o, MDL); + } + free_option_caches = (struct option_cache *)0; +} +#endif + +int option_cache_allocate (cptr, file, line) + struct option_cache **cptr; + const char *file; + int line; +{ + struct option_cache *rval; + + if (free_option_caches) { + rval = free_option_caches; + free_option_caches = + (struct option_cache *)(rval -> expression); + dmalloc_reuse (rval, file, line, 0); } else { - rval = dmalloc (sizeof (struct lease_state), name); + rval = dmalloc (sizeof (struct option_cache), file, line); + if (!rval) + return 0; } - return rval; + memset (rval, 0, sizeof *rval); + return option_cache_reference (cptr, rval, file, line); } -struct domain_search_list *new_domain_search_list (name) - char *name; +int option_cache_reference (ptr, src, file, line) + struct option_cache **ptr; + struct option_cache *src; + const char *file; + int line; { - struct domain_search_list *rval = - dmalloc (sizeof (struct domain_search_list), name); - return rval; + if (!ptr) { + log_error ("%s(%d): null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + if (*ptr) { + log_error ("%s(%d): non-null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + *ptr = (struct option_cache *)0; +#endif + } + *ptr = src; + src -> refcnt++; + rc_register (file, line, ptr, src, src -> refcnt, 0, RC_MISC); + return 1; } -struct name_server *new_name_server (name) - char *name; +int buffer_allocate (ptr, len, file, line) + struct buffer **ptr; + unsigned len; + const char *file; + int line; { - struct name_server *rval = - dmalloc (sizeof (struct name_server), name); - return rval; + struct buffer *bp; + + bp = dmalloc (len + sizeof *bp, file, line); + if (!bp) + return 0; + memset (bp, 0, sizeof *bp); + bp -> refcnt = 0; + return buffer_reference (ptr, bp, file, line); } -void free_name_server (ptr, name) - struct name_server *ptr; - char *name; +int buffer_reference (ptr, bp, file, line) + struct buffer **ptr; + struct buffer *bp; + const char *file; + int line; { - dfree ((VOIDPTR)ptr, name); + if (!ptr) { + log_error ("%s(%d): null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + if (*ptr) { + log_error ("%s(%d): non-null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + *ptr = (struct buffer *)0; +#endif + } + *ptr = bp; + bp -> refcnt++; + rc_register (file, line, ptr, bp, bp -> refcnt, 0, RC_MISC); + return 1; } -void free_domain_search_list (ptr, name) - struct domain_search_list *ptr; - char *name; +int buffer_dereference (ptr, file, line) + struct buffer **ptr; + const char *file; + int line; { - dfree ((VOIDPTR)ptr, name); + struct buffer *bp; + + if (!ptr) { + log_error ("%s(%d): null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + + if (!*ptr) { + log_error ("%s(%d): null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + + (*ptr) -> refcnt--; + rc_register (file, line, ptr, *ptr, (*ptr) -> refcnt, 1, RC_MISC); + if (!(*ptr) -> refcnt) { + dfree ((*ptr), file, line); + } else if ((*ptr) -> refcnt < 0) { + log_error ("%s(%d): negative refcnt!", file, line); +#if defined (DEBUG_RC_HISTORY) + dump_rc_history (*ptr); +#endif +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + *ptr = (struct buffer *)0; + return 1; } -void free_lease_state (ptr, name) - struct lease_state *ptr; - char *name; +int dns_host_entry_allocate (ptr, hostname, file, line) + struct dns_host_entry **ptr; + const char *hostname; + const char *file; + int line; { - if (ptr -> prl) - dfree (ptr -> prl, name); - ptr -> next = free_lease_states; - free_lease_states = ptr; + struct dns_host_entry *bp; + + bp = dmalloc (strlen (hostname) + sizeof *bp, file, line); + if (!bp) + return 0; + memset (bp, 0, sizeof *bp); + bp -> refcnt = 0; + strcpy (bp -> hostname, hostname); + return dns_host_entry_reference (ptr, bp, file, line); } -void free_protocol (ptr, name) - struct protocol *ptr; - char *name; +int dns_host_entry_reference (ptr, bp, file, line) + struct dns_host_entry **ptr; + struct dns_host_entry *bp; + const char *file; + int line; +{ + if (!ptr) { + log_error ("%s(%d): null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + if (*ptr) { + log_error ("%s(%d): non-null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + *ptr = (struct dns_host_entry *)0; +#endif + } + *ptr = bp; + bp -> refcnt++; + rc_register (file, line, ptr, bp, bp -> refcnt, 0, RC_MISC); + return 1; +} + +int dns_host_entry_dereference (ptr, file, line) + struct dns_host_entry **ptr; + const char *file; + int line; +{ + struct dns_host_entry *bp; + + if (!ptr || !*ptr) { + log_error ("%s(%d): null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + + (*ptr) -> refcnt--; + rc_register (file, line, ptr, *ptr, (*ptr) -> refcnt, 1, RC_MISC); + if (!(*ptr) -> refcnt) + dfree ((*ptr), file, line); + if ((*ptr) -> refcnt < 0) { + log_error ("%s(%d): negative refcnt!", file, line); +#if defined (DEBUG_RC_HISTORY) + dump_rc_history (*ptr); +#endif +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + *ptr = (struct dns_host_entry *)0; + return 1; +} + +int option_state_allocate (ptr, file, line) + struct option_state **ptr; + const char *file; + int line; +{ + unsigned size; + + if (!ptr) { + log_error ("%s(%d): null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + if (*ptr) { + log_error ("%s(%d): non-null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + *ptr = (struct option_state *)0; +#endif + } + + size = sizeof **ptr + (universe_count - 1) * sizeof (VOIDPTR); + *ptr = dmalloc (size, file, line); + if (*ptr) { + memset (*ptr, 0, size); + (*ptr) -> universe_count = universe_count; + (*ptr) -> refcnt = 1; + rc_register (file, line, + ptr, *ptr, (*ptr) -> refcnt, 0, RC_MISC); + return 1; + } + return 0; +} + +int option_state_reference (ptr, bp, file, line) + struct option_state **ptr; + struct option_state *bp; + const char *file; + int line; +{ + if (!ptr) { + log_error ("%s(%d): null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + if (*ptr) { + log_error ("%s(%d): non-null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + *ptr = (struct option_state *)0; +#endif + } + *ptr = bp; + bp -> refcnt++; + rc_register (file, line, ptr, bp, bp -> refcnt, 0, RC_MISC); + return 1; +} + +int option_state_dereference (ptr, file, line) + struct option_state **ptr; + const char *file; + int line; { - dfree ((VOIDPTR)ptr, name); + int i; + struct option_state *options; + + if (!ptr || !*ptr) { + log_error ("%s(%d): null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + + options = *ptr; + *ptr = (struct option_state *)0; + --options -> refcnt; + rc_register (file, line, ptr, options, options -> refcnt, 1, RC_MISC); + if (options -> refcnt > 0) + return 1; + + if (options -> refcnt < 0) { + log_error ("%s(%d): negative refcnt!", file, line); +#if defined (DEBUG_RC_HISTORY) + dump_rc_history (options); +#endif +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + + /* Loop through the per-universe state. */ + for (i = 0; i < options -> universe_count; i++) + if (options -> universes [i] && + universes [i] -> option_state_dereference) + ((*(universes [i] -> option_state_dereference)) + (universes [i], options, file, line)); + dfree (options, file, line); + return 1; } -void free_group (ptr, name) - struct group *ptr; - char *name; +int executable_statement_allocate (ptr, file, line) + struct executable_statement **ptr; + const char *file; + int line; { - dfree ((VOIDPTR)ptr, name); + struct executable_statement *bp; + + bp = dmalloc (sizeof *bp, file, line); + if (!bp) + return 0; + memset (bp, 0, sizeof *bp); + return executable_statement_reference (ptr, bp, file, line); } -void free_shared_network (ptr, name) - struct shared_network *ptr; - char *name; +int executable_statement_reference (ptr, bp, file, line) + struct executable_statement **ptr; + struct executable_statement *bp; + const char *file; + int line; { - dfree ((VOIDPTR)ptr, name); + if (!ptr) { + log_error ("%s(%d): null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + if (*ptr) { + log_error ("%s(%d): non-null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + *ptr = (struct executable_statement *)0; +#endif + } + *ptr = bp; + bp -> refcnt++; + rc_register (file, line, ptr, bp, bp -> refcnt, 0, RC_MISC); + return 1; } -void free_class (ptr, name) - struct class *ptr; - char *name; +static struct packet *free_packets; + +#if defined (DEBUG_MEMORY_LEAKAGE) || \ + defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) +void relinquish_free_packets () { - dfree ((VOIDPTR)ptr, name); + struct packet *p, *n; + for (p = free_packets; p; p = n) { + n = (struct packet *)(p -> raw); + dfree (p, MDL); + } + free_packets = (struct packet *)0; } +#endif -void free_subnet (ptr, name) - struct subnet *ptr; - char *name; +int packet_allocate (ptr, file, line) + struct packet **ptr; + const char *file; + int line; { - dfree ((VOIDPTR)ptr, name); + int size; + struct packet *p; + + if (!ptr) { + log_error ("%s(%d): null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + if (*ptr) { + log_error ("%s(%d): non-null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + *ptr = (struct packet *)0; +#endif + } + + if (free_packets) { + p = free_packets; + free_packets = (struct packet *)(p -> raw); + dmalloc_reuse (p, file, line, 1); + } else { + p = dmalloc (sizeof *p, file, line); + } + if (p) { + memset (p, 0, sizeof *p); + return packet_reference (ptr, p, file, line); + } + return 0; } -void free_lease (ptr, name) - struct lease *ptr; - char *name; +int packet_reference (ptr, bp, file, line) + struct packet **ptr; + struct packet *bp; + const char *file; + int line; { - dfree ((VOIDPTR)ptr, name); + if (!ptr) { + log_error ("%s(%d): null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + if (*ptr) { + log_error ("%s(%d): non-null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + *ptr = (struct packet *)0; +#endif + } + *ptr = bp; + bp -> refcnt++; + rc_register (file, line, ptr, bp, bp -> refcnt, 0, RC_MISC); + return 1; } -void free_hash_bucket (ptr, name) - struct hash_bucket *ptr; - char *name; +int packet_dereference (ptr, file, line) + struct packet **ptr; + const char *file; + int line; { - dfree ((VOIDPTR)ptr, name); + int i; + struct packet *packet; + + if (!ptr || !*ptr) { + log_error ("%s(%d): null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + + packet = *ptr; + *ptr = (struct packet *)0; + --packet -> refcnt; + rc_register (file, line, ptr, packet, packet -> refcnt, 1, RC_MISC); + if (packet -> refcnt > 0) + return 1; + + if (packet -> refcnt < 0) { + log_error ("%s(%d): negative refcnt!", file, line); +#if defined (DEBUG_RC_HISTORY) + dump_rc_history (packet); +#endif +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + + if (packet -> options) + option_state_dereference (&packet -> options, file, line); + if (packet -> interface) + interface_dereference (&packet -> interface, MDL); + if (packet -> shared_network) + shared_network_dereference (&packet -> shared_network, MDL); + for (i = 0; i < packet -> class_count && i < PACKET_MAX_CLASSES; i++) { + if (packet -> classes [i]) + omapi_object_dereference ((omapi_object_t **) + &packet -> classes [i], MDL); + } + packet -> raw = (struct dhcp_packet *)free_packets; + free_packets = packet; + dmalloc_reuse (free_packets, (char *)0, 0, 0); + return 1; } -void free_hash_table (ptr, name) - struct hash_table *ptr; - char *name; +int dns_zone_allocate (ptr, file, line) + struct dns_zone **ptr; + const char *file; + int line; { - dfree ((VOIDPTR)ptr, name); + int size; + struct dns_zone *d; + + if (!ptr) { + log_error ("%s(%d): null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + if (*ptr) { + log_error ("%s(%d): non-null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + *ptr = (struct dns_zone *)0; +#endif + } + + d = dmalloc (sizeof *d, file, line); + if (d) { + memset (d, 0, sizeof *d); + return dns_zone_reference (ptr, d, file, line); + } + return 0; } -void free_tree_cache (ptr, name) - struct tree_cache *ptr; - char *name; +int dns_zone_reference (ptr, bp, file, line) + struct dns_zone **ptr; + struct dns_zone *bp; + const char *file; + int line; { - ptr -> value = (unsigned char *)free_tree_caches; - free_tree_caches = ptr; + if (!ptr) { + log_error ("%s(%d): null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + if (*ptr) { + log_error ("%s(%d): non-null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + *ptr = (struct dns_zone *)0; +#endif + } + *ptr = bp; + bp -> refcnt++; + rc_register (file, line, ptr, bp, bp -> refcnt, 0, RC_MISC); + return 1; } -void free_packet (ptr, name) - struct packet *ptr; - char *name; +int binding_scope_allocate (ptr, file, line) + struct binding_scope **ptr; + const char *file; + int line; { - dfree ((VOIDPTR)ptr, name); + struct binding_scope *bp; + + if (!ptr) { + log_error ("%s(%d): null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + + if (*ptr) { + log_error ("%s(%d): non-null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + + bp = dmalloc (sizeof *bp, file, line); + if (!bp) + return 0; + memset (bp, 0, sizeof *bp); + binding_scope_reference (ptr, bp, file, line); + return 1; } -void free_dhcp_packet (ptr, name) - struct dhcp_packet *ptr; - char *name; +int binding_scope_reference (ptr, bp, file, line) + struct binding_scope **ptr; + struct binding_scope *bp; + const char *file; + int line; { - dfree ((VOIDPTR)ptr, name); + if (!ptr) { + log_error ("%s(%d): null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + if (*ptr) { + log_error ("%s(%d): non-null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + *ptr = (struct binding_scope *)0; +#endif + } + *ptr = bp; + bp -> refcnt++; + rc_register (file, line, ptr, bp, bp -> refcnt, 0, RC_MISC); + return 1; } -void free_tree (ptr, name) - struct tree *ptr; - char *name; +/* Make a copy of the data in data_string, upping the buffer reference + count if there's a buffer. */ + +void data_string_copy (dest, src, file, line) + struct data_string *dest; + struct data_string *src; + const char *file; + int line; { - dfree ((VOIDPTR)ptr, name); + if (src -> buffer) + buffer_reference (&dest -> buffer, src -> buffer, file, line); + dest -> data = src -> data; + dest -> terminated = src -> terminated; + dest -> len = src -> len; +} + +/* Release the reference count to a data string's buffer (if any) and + zero out the other information, yielding the null data string. */ + +void data_string_forget (data, file, line) + struct data_string *data; + const char *file; + int line; +{ + if (data -> buffer) + buffer_dereference (&data -> buffer, file, line); + memset (data, 0, sizeof *data); +} + +/* Make a copy of the data in data_string, upping the buffer reference + count if there's a buffer. */ + +void data_string_truncate (dp, len) + struct data_string *dp; + int len; +{ + if (len < dp -> len) { + dp -> terminated = 0; + dp -> len = len; + } } diff --git a/contrib/isc-dhcp/common/bpf.c b/contrib/isc-dhcp/common/bpf.c index e204dfe..49af907 100644 --- a/contrib/isc-dhcp/common/bpf.c +++ b/contrib/isc-dhcp/common/bpf.c @@ -3,8 +3,8 @@ BPF socket interface code, originally contributed by Archie Cobbs. */ /* - * Copyright (c) 1995, 1996, 1998, 1999 - * The Internet Software Consortium. All rights reserved. + * Copyright (c) 1996-2000 Internet Software Consortium. + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,16 +33,21 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * This software has been written for the Internet Software Consortium - * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie - * Enterprises. To learn more about the Internet Software Consortium, - * see ``http://www.vix.com/isc''. To learn more about Vixie - * Enterprises, see ``http://www.vix.com''. + * This software was contributed to the Internet Software Consortium + * by Archie Cobbs, and is now maintained by Ted Lemon in cooperation + * with Nominum, Inc. To learn more about the Internet Software + * Consortium, see ``http://www.isc.org/''. To learn more about Vixie + * Enterprises, see ``http://www.vix.com''. To learn more about + * Nominum, Inc., see ``http://www.nominum.com''. + * + * Patches for FDDI support on Digital Unix were written by Bill + * Stapleton, and maintained for a while by Mike Meredith before he + * managed to get me to integrate them. */ #ifndef lint static char copyright[] = -"$Id: bpf.c,v 1.19.2.10 1999/05/27 17:44:51 mellon Exp $ Copyright (c) 1995, 1996, 1998, 1999 The Internet Software Consortium. All rights reserved.\n"; +"$Id: bpf.c,v 1.48 2001/04/08 21:12:49 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -55,7 +60,6 @@ static char copyright[] = # else # include <sys/ioctl.h> # include <sys/uio.h> - # include <net/bpf.h> # if defined (NEED_OSF_PFILT_HACKS) # include <net/pfilt.h> @@ -110,11 +114,11 @@ int if_register_bpf (info) continue; } else { if (!b) - error ("No bpf devices.%s%s%s", + log_fatal ("No bpf devices.%s%s%s", " Please read the README", " section for your operating", " system."); - error ("Can't find free bpf: %m"); + log_fatal ("Can't find free bpf: %m"); } } else { break; @@ -123,7 +127,7 @@ int if_register_bpf (info) /* Set the BPF device to point at this interface. */ if (ioctl (sock, BIOCSETIF, info -> ifp) < 0) - error ("Can't attach interface %s to bpf device %s: %m", + log_fatal ("Can't attach interface %s to bpf device %s: %m", info -> name, filename); return sock; @@ -142,11 +146,32 @@ void if_register_send (info) info -> wfdesc = info -> rfdesc; #endif if (!quiet_interface_discovery) - note ("Sending on BPF/%s/%s%s%s", + log_info ("Sending on BPF/%s/%s%s%s", + info -> name, + print_hw_addr (info -> hw_address.hbuf [0], + info -> hw_address.hlen - 1, + &info -> hw_address.hbuf [1]), + (info -> shared_network ? "/" : ""), + (info -> shared_network ? + info -> shared_network -> name : "")); +} + +void if_deregister_send (info) + struct interface_info *info; +{ + /* If we're using the bpf API for sending and receiving, + we don't need to register this interface twice. */ +#ifndef USE_BPF_RECEIVE + close (info -> wfdesc); +#endif + info -> wfdesc = -1; + + if (!quiet_interface_discovery) + log_info ("Disabling output on BPF/%s/%s%s%s", info -> name, - print_hw_addr (info -> hw_address.htype, - info -> hw_address.hlen, - info -> hw_address.haddr), + print_hw_addr (info -> hw_address.hbuf [0], + info -> hw_address.hlen - 1, + &info -> hw_address.hbuf [1]), (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : "")); @@ -185,8 +210,12 @@ struct bpf_insn dhcp_bpf_filter [] = { BPF_STMT(BPF_RET+BPF_K, 0), }; -int dhcp_bpf_filter_len = sizeof dhcp_bpf_filter / sizeof (struct bpf_insn); +#if defined (DEC_FDDI) +struct bpf_insn *bpf_fddi_filter; +#endif +int dhcp_bpf_filter_len = sizeof dhcp_bpf_filter / sizeof (struct bpf_insn); +#if defined (HAVE_TR_SUPPORT) struct bpf_insn dhcp_bpf_tr_filter [] = { /* accept all token ring packets due to variable length header */ /* if we want to get clever, insert the program here */ @@ -200,7 +229,8 @@ struct bpf_insn dhcp_bpf_tr_filter [] = { int dhcp_bpf_tr_filter_len = (sizeof dhcp_bpf_tr_filter / sizeof (struct bpf_insn)); -#endif +#endif /* HAVE_TR_SUPPORT */ +#endif /* USE_LPF_RECEIVE || USE_BPF_RECEIVE */ #if defined (USE_BPF_RECEIVE) void if_register_receive (info) @@ -211,50 +241,80 @@ void if_register_receive (info) u_int32_t addr; struct bpf_program p; u_int32_t bits; +#ifdef DEC_FDDI + int link_layer; +#endif /* DEC_FDDI */ /* Open a BPF device and hang it on this interface... */ info -> rfdesc = if_register_bpf (info); /* Make sure the BPF version is in range... */ if (ioctl (info -> rfdesc, BIOCVERSION, &v) < 0) - error ("Can't get BPF version: %m"); + log_fatal ("Can't get BPF version: %m"); if (v.bv_major != BPF_MAJOR_VERSION || v.bv_minor < BPF_MINOR_VERSION) - error ("Kernel BPF version out of range - recompile dhcpd!"); + log_fatal ("BPF version mismatch - recompile DHCP!"); /* Set immediate mode so that reads return as soon as a packet comes in, rather than waiting for the input buffer to fill with packets. */ if (ioctl (info -> rfdesc, BIOCIMMEDIATE, &flag) < 0) - error ("Can't set immediate mode on bpf device: %m"); + log_fatal ("Can't set immediate mode on bpf device: %m"); #ifdef NEED_OSF_PFILT_HACKS /* Allow the copyall flag to be set... */ if (ioctl(info -> rfdesc, EIOCALLOWCOPYALL, &flag) < 0) - error ("Can't set ALLOWCOPYALL: %m"); + log_fatal ("Can't set ALLOWCOPYALL: %m"); /* Clear all the packet filter mode bits first... */ bits = 0; if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0) - error ("Can't clear pfilt bits: %m"); + log_fatal ("Can't clear pfilt bits: %m"); /* Set the ENBATCH, ENCOPYALL, ENBPFHDR bits... */ bits = ENBATCH | ENCOPYALL | ENBPFHDR; if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0) - error ("Can't set ENBATCH|ENCOPYALL|ENBPFHDR: %m"); + log_fatal ("Can't set ENBATCH|ENCOPYALL|ENBPFHDR: %m"); #endif /* Get the required BPF buffer length from the kernel. */ if (ioctl (info -> rfdesc, BIOCGBLEN, &info -> rbuf_max) < 0) - error ("Can't get bpf buffer length: %m"); - info -> rbuf = malloc (info -> rbuf_max); + log_fatal ("Can't get bpf buffer length: %m"); + info -> rbuf = dmalloc (info -> rbuf_max, MDL); if (!info -> rbuf) - error ("Can't allocate %d bytes for bpf input buffer."); + log_fatal ("Can't allocate %ld bytes for bpf input buffer.", + (long)(info -> rbuf_max)); info -> rbuf_offset = 0; info -> rbuf_len = 0; /* Set up the bpf filter program structure. */ p.bf_len = dhcp_bpf_filter_len; + +#ifdef DEC_FDDI + /* See if this is an FDDI interface, flag it for later. */ + if (ioctl(info -> rfdesc, BIOCGDLT, &link_layer) >= 0 && + link_layer == DLT_FDDI) { + if (!bpf_fddi_filter) { + bpf_fddi_filter = dmalloc (sizeof bpf_fddi_filter, + MDL); + if (!bpf_fddi_filter) + log_fatal ("No memory for FDDI filter."); + memcpy (bpf_fddi_filter, + dhcp_bpf_filter, sizeof dhcp_bpf_filter); + /* Patch the BPF program to account for the difference + in length between ethernet headers (14), FDDI and + 802.2 headers (16 +8=24, +10). + XXX changes to filter program may require changes to + XXX the insn number(s) used below! */ + bpf_fddi_filter[0].k += 10; + bpf_fddi_filter[2].k += 10; + bpf_fddi_filter[4].k += 10; + bpf_fddi_filter[6].k += 10; + bpf_fddi_filter[7].k += 10; + } + p.bf_insns = bpf_fddi_filter; + } else +#endif /* DEC_FDDI */ p.bf_insns = dhcp_bpf_filter; /* Patch the server port into the BPF program... @@ -263,13 +323,30 @@ void if_register_receive (info) dhcp_bpf_filter [8].k = ntohs (local_port); if (ioctl (info -> rfdesc, BIOCSETF, &p) < 0) - error ("Can't install packet filter program: %m"); + log_fatal ("Can't install packet filter program: %m"); if (!quiet_interface_discovery) - note ("Listening on BPF/%s/%s%s%s", + log_info ("Listening on BPF/%s/%s%s%s", info -> name, - print_hw_addr (info -> hw_address.htype, - info -> hw_address.hlen, - info -> hw_address.haddr), + print_hw_addr (info -> hw_address.hbuf [0], + info -> hw_address.hlen - 1, + &info -> hw_address.hbuf [1]), + (info -> shared_network ? "/" : ""), + (info -> shared_network ? + info -> shared_network -> name : "")); +} + +void if_deregister_receive (info) + struct interface_info *info; +{ + close (info -> rfdesc); + info -> rfdesc = -1; + + if (!quiet_interface_discovery) + log_info ("Disabling input on BPF/%s/%s%s%s", + info -> name, + print_hw_addr (info -> hw_address.hbuf [0], + info -> hw_address.hlen - 1, + &info -> hw_address.hbuf [1]), (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : "")); @@ -286,30 +363,35 @@ ssize_t send_packet (interface, packet, raw, len, from, to, hto) struct sockaddr_in *to; struct hardware *hto; { - int bufp = 0; - unsigned char buf [256]; - struct iovec iov [2]; + unsigned hbufp = 0, ibufp = 0; + double hw [4]; + double ip [32]; + struct iovec iov [3]; int result; + int fudge; if (!strcmp (interface -> name, "fallback")) return send_fallback (interface, packet, raw, len, from, to, hto); /* Assemble the headers... */ - assemble_hw_header (interface, buf, &bufp, hto); - assemble_udp_ip_header (interface, buf, &bufp, from.s_addr, + assemble_hw_header (interface, (unsigned char *)hw, &hbufp, hto); + assemble_udp_ip_header (interface, + (unsigned char *)ip, &ibufp, from.s_addr, to -> sin_addr.s_addr, to -> sin_port, (unsigned char *)raw, len); /* Fire it off */ - iov [0].iov_base = (char *)buf; - iov [0].iov_len = bufp; - iov [1].iov_base = (char *)raw; - iov [1].iov_len = len; - - result = writev(interface -> wfdesc, iov, 2); + iov [0].iov_base = ((char *)hw); + iov [0].iov_len = hbufp; + iov [1].iov_base = ((char *)ip); + iov [1].iov_len = ibufp; + iov [2].iov_base = (char *)raw; + iov [2].iov_len = len; + + result = writev(interface -> wfdesc, iov, 3); if (result < 0) - warn ("send_packet: %m"); + log_error ("send_packet: %m"); return result; } #endif /* USE_BPF_SEND */ @@ -340,10 +422,16 @@ ssize_t receive_packet (interface, buf, len, from, hfrom) length = read (interface -> rfdesc, interface -> rbuf, interface -> rbuf_max); - if (length <= 0) + if (length <= 0) { + if (errno == EIO) { + dhcp_interface_remove + ((omapi_object_t *)interface, + (omapi_object_t *)0); + } return length; + } interface -> rbuf_offset = 0; - interface -> rbuf_len = length; + interface -> rbuf_len = BPF_WORDALIGN (length); } /* If there isn't room for a whole bpf header, something went @@ -370,8 +458,9 @@ ssize_t receive_packet (interface, buf, len, from, hfrom) the packet won't fit in the input buffer, all we can do is drop it. */ if (hdr.bh_caplen != hdr.bh_datalen) { - interface -> rbuf_offset += - hdr.bh_hdrlen = hdr.bh_caplen; + interface -> rbuf_offset = + BPF_WORDALIGN (interface -> rbuf_offset + + hdr.bh_hdrlen + hdr.bh_caplen); continue; } @@ -388,7 +477,9 @@ ssize_t receive_packet (interface, buf, len, from, hfrom) physical layer that supports this, but WTH), skip this packet. */ if (offset < 0) { - interface -> rbuf_offset += hdr.bh_caplen; + interface -> rbuf_offset = + BPF_WORDALIGN (interface -> rbuf_offset + + hdr.bh_caplen); continue; } interface -> rbuf_offset += offset; @@ -404,30 +495,37 @@ ssize_t receive_packet (interface, buf, len, from, hfrom) /* If the IP or UDP checksum was bad, skip the packet... */ if (offset < 0) { - interface -> rbuf_offset += hdr.bh_caplen; + interface -> rbuf_offset = + BPF_WORDALIGN (interface -> rbuf_offset + + hdr.bh_caplen); continue; } - interface -> rbuf_offset += offset; + interface -> rbuf_offset = interface -> rbuf_offset + offset; hdr.bh_caplen -= offset; /* If there's not enough room to stash the packet data, we have to skip it (this shouldn't happen in real life, though). */ if (hdr.bh_caplen > len) { - interface -> rbuf_offset += hdr.bh_caplen; + interface -> rbuf_offset = + BPF_WORDALIGN (interface -> rbuf_offset + + hdr.bh_caplen); continue; } /* Copy out the data in the packet... */ memcpy (buf, interface -> rbuf + interface -> rbuf_offset, hdr.bh_caplen); - interface -> rbuf_offset += hdr.bh_caplen; + interface -> rbuf_offset = + BPF_WORDALIGN (interface -> rbuf_offset + + hdr.bh_caplen); return hdr.bh_caplen; } while (!length); return 0; } -int can_unicast_without_arp () +int can_unicast_without_arp (ip) + struct interface_info *ip; { return 1; } @@ -438,14 +536,25 @@ int can_receive_unicast_unconfigured (ip) return 1; } +int supports_multiple_interfaces (ip) + struct interface_info *ip; +{ + return 1; +} + void maybe_setup_fallback () { - struct interface_info *fbi; - fbi = setup_fallback (); - if (fbi) { + isc_result_t status; + struct interface_info *fbi = (struct interface_info *)0; + if (setup_fallback (&fbi, MDL)) { if_register_fallback (fbi); - add_protocol ("fallback", fallback_interface -> wfdesc, - fallback_discard, fallback_interface); + status = omapi_register_io_object ((omapi_object_t *)fbi, + if_readsocket, 0, + fallback_discard, 0, 0); + if (status != ISC_R_SUCCESS) + log_fatal ("Can't register I/O handle for %s: %s", + fbi -> name, isc_result_totext (status)); + interface_dereference (&fbi, MDL); } } #endif diff --git a/contrib/isc-dhcp/common/comapi.c b/contrib/isc-dhcp/common/comapi.c new file mode 100644 index 0000000..a038903 --- /dev/null +++ b/contrib/isc-dhcp/common/comapi.c @@ -0,0 +1,958 @@ +/* omapi.c + + OMAPI object interfaces for the DHCP server. */ + +/* + * Copyright (c) 1999-2001 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. + */ + +/* Many, many thanks to Brian Murrell and BCtel for this code - BCtel + provided the funding that resulted in this code and the entire + OMAPI support library being written, and Brian helped brainstorm + and refine the requirements. To the extent that this code is + useful, you have Brian and BCtel to thank. Any limitations in the + code are a result of mistakes on my part. -- Ted Lemon */ + +#ifndef lint +static char copyright[] = +"$Id: comapi.c,v 1.9.2.5 2001/10/18 20:09:59 mellon Exp $ Copyright (c) 1999-2001 The Internet Software Consortium. All rights reserved.\n"; +#endif /* not lint */ + +#include "dhcpd.h" +#include <omapip/omapip_p.h> + +OMAPI_OBJECT_ALLOC (subnet, struct subnet, dhcp_type_subnet) +OMAPI_OBJECT_ALLOC (shared_network, struct shared_network, + dhcp_type_shared_network) +OMAPI_OBJECT_ALLOC (group_object, struct group_object, dhcp_type_group) +OMAPI_OBJECT_ALLOC (dhcp_control, dhcp_control_object_t, dhcp_type_control) + +omapi_object_type_t *dhcp_type_interface; +omapi_object_type_t *dhcp_type_group; +omapi_object_type_t *dhcp_type_shared_network; +omapi_object_type_t *dhcp_type_subnet; +omapi_object_type_t *dhcp_type_control; +dhcp_control_object_t *dhcp_control_object; + +void dhcp_common_objects_setup () +{ + isc_result_t status; + + status = omapi_object_type_register (&dhcp_type_control, + "control", + dhcp_control_set_value, + dhcp_control_get_value, + dhcp_control_destroy, + dhcp_control_signal_handler, + dhcp_control_stuff_values, + dhcp_control_lookup, + dhcp_control_create, + dhcp_control_remove, 0, 0, 0, + sizeof (dhcp_control_object_t), + 0, RC_MISC); + if (status != ISC_R_SUCCESS) + log_fatal ("Can't register control object type: %s", + isc_result_totext (status)); + status = dhcp_control_allocate (&dhcp_control_object, MDL); + if (status != ISC_R_SUCCESS) + log_fatal ("Can't make initial control object: %s", + isc_result_totext (status)); + dhcp_control_object -> state = server_startup; + + status = omapi_object_type_register (&dhcp_type_group, + "group", + dhcp_group_set_value, + dhcp_group_get_value, + dhcp_group_destroy, + dhcp_group_signal_handler, + dhcp_group_stuff_values, + dhcp_group_lookup, + dhcp_group_create, + dhcp_group_remove, 0, 0, 0, + sizeof (struct group_object), 0, + RC_MISC); + if (status != ISC_R_SUCCESS) + log_fatal ("Can't register group object type: %s", + isc_result_totext (status)); + + status = omapi_object_type_register (&dhcp_type_subnet, + "subnet", + dhcp_subnet_set_value, + dhcp_subnet_get_value, + dhcp_subnet_destroy, + dhcp_subnet_signal_handler, + dhcp_subnet_stuff_values, + dhcp_subnet_lookup, + dhcp_subnet_create, + dhcp_subnet_remove, 0, 0, 0, + sizeof (struct subnet), 0, + RC_MISC); + if (status != ISC_R_SUCCESS) + log_fatal ("Can't register subnet object type: %s", + isc_result_totext (status)); + + status = omapi_object_type_register + (&dhcp_type_shared_network, + "shared-network", + dhcp_shared_network_set_value, + dhcp_shared_network_get_value, + dhcp_shared_network_destroy, + dhcp_shared_network_signal_handler, + dhcp_shared_network_stuff_values, + dhcp_shared_network_lookup, + dhcp_shared_network_create, + dhcp_shared_network_remove, 0, 0, 0, + sizeof (struct shared_network), 0, RC_MISC); + if (status != ISC_R_SUCCESS) + log_fatal ("Can't register shared network object type: %s", + isc_result_totext (status)); + + interface_setup (); +} + +isc_result_t dhcp_group_set_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_typed_data_t *value) +{ + struct group_object *group; + isc_result_t status; + int foo; + + if (h -> type != dhcp_type_group) + return ISC_R_INVALIDARG; + group = (struct group_object *)h; + + /* XXX For now, we can only set these values on new group objects. + XXX Soon, we need to be able to update group objects. */ + if (!omapi_ds_strcmp (name, "name")) { + if (group -> name) + return ISC_R_EXISTS; + if (value -> type == omapi_datatype_data || + value -> type == omapi_datatype_string) { + group -> name = dmalloc (value -> u.buffer.len + 1, + MDL); + if (!group -> name) + return ISC_R_NOMEMORY; + memcpy (group -> name, + value -> u.buffer.value, + value -> u.buffer.len); + group -> name [value -> u.buffer.len] = 0; + } else + return ISC_R_INVALIDARG; + return ISC_R_SUCCESS; + } + + if (!omapi_ds_strcmp (name, "statements")) { + if (group -> group && group -> group -> statements) + return ISC_R_EXISTS; + if (!group -> group) { + if (!clone_group (&group -> group, root_group, MDL)) + return ISC_R_NOMEMORY; + } + if (value -> type == omapi_datatype_data || + value -> type == omapi_datatype_string) { + struct parse *parse; + int lose = 0; + parse = (struct parse *)0; + status = new_parse (&parse, -1, + (char *)value -> u.buffer.value, + value -> u.buffer.len, + "network client", 0); + if (status != ISC_R_SUCCESS) + return status; + if (!(parse_executable_statements + (&group -> group -> statements, parse, &lose, + context_any))) { + end_parse (&parse); + return ISC_R_BADPARSE; + } + end_parse (&parse); + return ISC_R_SUCCESS; + } else + return ISC_R_INVALIDARG; + } + + /* Try to find some inner object that can take the value. */ + if (h -> inner && h -> inner -> type -> set_value) { + status = ((*(h -> inner -> type -> set_value)) + (h -> inner, id, name, value)); + if (status == ISC_R_SUCCESS || status == ISC_R_UNCHANGED) + return status; + } + + return ISC_R_NOTFOUND; +} + + +isc_result_t dhcp_group_get_value (omapi_object_t *h, omapi_object_t *id, + omapi_data_string_t *name, + omapi_value_t **value) +{ + struct group_object *group; + isc_result_t status; + struct data_string ip_addrs; + + if (h -> type != dhcp_type_group) + return ISC_R_INVALIDARG; + group = (struct group_object *)h; + + if (!omapi_ds_strcmp (name, "name")) + return omapi_make_string_value (value, + name, group -> name, MDL); + + /* Try to find some inner object that can take the value. */ + if (h -> inner && h -> inner -> type -> get_value) { + status = ((*(h -> inner -> type -> get_value)) + (h -> inner, id, name, value)); + if (status == ISC_R_SUCCESS) + return status; + } + return ISC_R_NOTFOUND; +} + +isc_result_t dhcp_group_destroy (omapi_object_t *h, const char *file, int line) +{ + struct group_object *group, *t; + isc_result_t status; + + if (h -> type != dhcp_type_group) + return ISC_R_INVALIDARG; + group = (struct group_object *)h; + + if (group -> name) { + if (group_name_hash) { + t = (struct group_object *)0; + if (group_hash_lookup (&t, group_name_hash, + group -> name, + strlen (group -> name), MDL)) { + group_hash_delete (group_name_hash, + group -> name, + strlen (group -> name), + MDL); + group_object_dereference (&t, MDL); + } + } + dfree (group -> name, file, line); + group -> name = (char *)0; + } + if (group -> group) + group_dereference (&group -> group, MDL); + + return ISC_R_SUCCESS; +} + +isc_result_t dhcp_group_signal_handler (omapi_object_t *h, + const char *name, va_list ap) +{ + struct group_object *group, *t; + isc_result_t status; + int updatep = 0; + + if (h -> type != dhcp_type_group) + return ISC_R_INVALIDARG; + group = (struct group_object *)h; + + if (!strcmp (name, "updated")) { + /* A group object isn't valid if a subgroup hasn't yet been + associated with it. */ + if (!group -> group) + return ISC_R_INVALIDARG; + + /* Group objects always have to have names. */ + if (!group -> name) { + char hnbuf [64]; + sprintf (hnbuf, "ng%08lx%08lx", + (unsigned long)cur_time, + (unsigned long)group); + group -> name = dmalloc (strlen (hnbuf) + 1, MDL); + if (!group -> name) + return ISC_R_NOMEMORY; + strcpy (group -> name, hnbuf); + } + + supersede_group (group, 1); + updatep = 1; + } + + /* Try to find some inner object that can take the value. */ + if (h -> inner && h -> inner -> type -> get_value) { + status = ((*(h -> inner -> type -> signal_handler)) + (h -> inner, name, ap)); + if (status == ISC_R_SUCCESS) + return status; + } + if (updatep) + return ISC_R_SUCCESS; + return ISC_R_NOTFOUND; +} + +isc_result_t dhcp_group_stuff_values (omapi_object_t *c, + omapi_object_t *id, + omapi_object_t *h) +{ + struct group_object *group; + isc_result_t status; + + if (h -> type != dhcp_type_group) + return ISC_R_INVALIDARG; + group = (struct group_object *)h; + + /* Write out all the values. */ + if (group -> name) { + status = omapi_connection_put_name (c, "name"); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_put_string (c, group -> name); + if (status != ISC_R_SUCCESS) + return status; + } + + /* Write out the inner object, if any. */ + if (h -> inner && h -> inner -> type -> stuff_values) { + status = ((*(h -> inner -> type -> stuff_values)) + (c, id, h -> inner)); + if (status == ISC_R_SUCCESS) + return status; + } + + return ISC_R_SUCCESS; +} + +isc_result_t dhcp_group_lookup (omapi_object_t **lp, + omapi_object_t *id, omapi_object_t *ref) +{ + omapi_value_t *tv = (omapi_value_t *)0; + isc_result_t status; + struct group_object *group; + + if (!ref) + return ISC_R_NOKEYS; + + /* First see if we were sent a handle. */ + status = omapi_get_value_str (ref, id, "handle", &tv); + if (status == ISC_R_SUCCESS) { + status = omapi_handle_td_lookup (lp, tv -> value); + + omapi_value_dereference (&tv, MDL); + if (status != ISC_R_SUCCESS) + return status; + + /* Don't return the object if the type is wrong. */ + if ((*lp) -> type != dhcp_type_group) { + omapi_object_dereference (lp, MDL); + return ISC_R_INVALIDARG; + } + } + + /* Now look for a name. */ + status = omapi_get_value_str (ref, id, "name", &tv); + if (status == ISC_R_SUCCESS) { + group = (struct group_object *)0; + if (group_name_hash && + group_hash_lookup (&group, group_name_hash, + (const char *) + tv -> value -> u.buffer.value, + tv -> value -> u.buffer.len, MDL)) { + omapi_value_dereference (&tv, MDL); + + if (*lp && *lp != (omapi_object_t *)group) { + group_object_dereference (&group, MDL); + omapi_object_dereference (lp, MDL); + return ISC_R_KEYCONFLICT; + } else if (!*lp) { + /* XXX fix so that hash lookup itself creates + XXX the reference. */ + omapi_object_reference (lp, + (omapi_object_t *)group, + MDL); + group_object_dereference (&group, MDL); + } + } else if (!*lp) + return ISC_R_NOTFOUND; + } + + /* If we get to here without finding a group, no valid key was + specified. */ + if (!*lp) + return ISC_R_NOKEYS; + + if (((struct group_object *)(*lp)) -> flags & GROUP_OBJECT_DELETED) { + omapi_object_dereference (lp, MDL); + return ISC_R_NOTFOUND; + } + return ISC_R_SUCCESS; +} + +isc_result_t dhcp_group_create (omapi_object_t **lp, + omapi_object_t *id) +{ + struct group_object *group; + isc_result_t status; + group = (struct group_object *)0; + + status = group_object_allocate (&group, MDL); + if (status != ISC_R_SUCCESS) + return status; + group -> flags = GROUP_OBJECT_DYNAMIC; + status = omapi_object_reference (lp, (omapi_object_t *)group, MDL); + group_object_dereference (&group, MDL); + return status; +} + +isc_result_t dhcp_group_remove (omapi_object_t *lp, + omapi_object_t *id) +{ + struct group_object *group; + isc_result_t status; + if (lp -> type != dhcp_type_group) + return ISC_R_INVALIDARG; + group = (struct group_object *)lp; + + group -> flags |= GROUP_OBJECT_DELETED; + if (group_write_hook) { + if (!(*group_write_hook) (group)) + return ISC_R_IOERROR; + } + + status = dhcp_group_destroy ((omapi_object_t *)group, MDL); + + return ISC_R_SUCCESS; +} + +isc_result_t dhcp_control_set_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_typed_data_t *value) +{ + dhcp_control_object_t *control; + isc_result_t status; + int foo; + unsigned long newstate; + + if (h -> type != dhcp_type_control) + return ISC_R_INVALIDARG; + control = (dhcp_control_object_t *)h; + + if (!omapi_ds_strcmp (name, "state")) { + status = omapi_get_int_value (&newstate, value); + if (status != ISC_R_SUCCESS) + return status; + status = dhcp_set_control_state (control -> state, newstate); + if (status == ISC_R_SUCCESS) + control -> state = value -> u.integer; + return status; + } + + /* Try to find some inner object that can take the value. */ + if (h -> inner && h -> inner -> type -> set_value) { + status = ((*(h -> inner -> type -> set_value)) + (h -> inner, id, name, value)); + if (status == ISC_R_SUCCESS || status == ISC_R_UNCHANGED) + return status; + } + + return ISC_R_NOTFOUND; +} + + +isc_result_t dhcp_control_get_value (omapi_object_t *h, omapi_object_t *id, + omapi_data_string_t *name, + omapi_value_t **value) +{ + dhcp_control_object_t *control; + isc_result_t status; + struct data_string ip_addrs; + + if (h -> type != dhcp_type_control) + return ISC_R_INVALIDARG; + control = (dhcp_control_object_t *)h; + + if (!omapi_ds_strcmp (name, "state")) + return omapi_make_int_value (value, + name, (int)control -> state, MDL); + + /* Try to find some inner object that can take the value. */ + if (h -> inner && h -> inner -> type -> get_value) { + status = ((*(h -> inner -> type -> get_value)) + (h -> inner, id, name, value)); + if (status == ISC_R_SUCCESS) + return status; + } + return ISC_R_NOTFOUND; +} + +isc_result_t dhcp_control_destroy (omapi_object_t *h, + const char *file, int line) +{ + dhcp_control_object_t *control, *t; + isc_result_t status; + + if (h -> type != dhcp_type_control) + return ISC_R_INVALIDARG; + + /* Can't destroy the control object. */ + return ISC_R_NOPERM; +} + +isc_result_t dhcp_control_signal_handler (omapi_object_t *h, + const char *name, va_list ap) +{ + dhcp_control_object_t *control, *t; + isc_result_t status; + int updatep = 0; + + if (h -> type != dhcp_type_control) + return ISC_R_INVALIDARG; + control = (dhcp_control_object_t *)h; + + /* Try to find some inner object that can take the value. */ + if (h -> inner && h -> inner -> type -> get_value) { + status = ((*(h -> inner -> type -> signal_handler)) + (h -> inner, name, ap)); + if (status == ISC_R_SUCCESS) + return status; + } + return ISC_R_NOTFOUND; +} + +isc_result_t dhcp_control_stuff_values (omapi_object_t *c, + omapi_object_t *id, + omapi_object_t *h) +{ + dhcp_control_object_t *control; + isc_result_t status; + + if (h -> type != dhcp_type_control) + return ISC_R_INVALIDARG; + control = (dhcp_control_object_t *)h; + + /* Write out all the values. */ + status = omapi_connection_put_name (c, "state"); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_put_uint32 (c, sizeof (u_int32_t)); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_put_uint32 (c, control -> state); + if (status != ISC_R_SUCCESS) + return status; + + /* Write out the inner object, if any. */ + if (h -> inner && h -> inner -> type -> stuff_values) { + status = ((*(h -> inner -> type -> stuff_values)) + (c, id, h -> inner)); + if (status == ISC_R_SUCCESS) + return status; + } + + return ISC_R_SUCCESS; +} + +isc_result_t dhcp_control_lookup (omapi_object_t **lp, + omapi_object_t *id, omapi_object_t *ref) +{ + omapi_value_t *tv = (omapi_value_t *)0; + isc_result_t status; + dhcp_control_object_t *control; + + /* First see if we were sent a handle. */ + if (ref) { + status = omapi_get_value_str (ref, id, "handle", &tv); + if (status == ISC_R_SUCCESS) { + status = omapi_handle_td_lookup (lp, tv -> value); + + omapi_value_dereference (&tv, MDL); + if (status != ISC_R_SUCCESS) + return status; + + /* Don't return the object if the type is wrong. */ + if ((*lp) -> type != dhcp_type_control) { + omapi_object_dereference (lp, MDL); + return ISC_R_INVALIDARG; + } + } + } + + /* Otherwise, stop playing coy - there's only one control object, + so we can just return it. */ + dhcp_control_reference ((dhcp_control_object_t **)lp, + dhcp_control_object, MDL); + return ISC_R_SUCCESS; +} + +isc_result_t dhcp_control_create (omapi_object_t **lp, + omapi_object_t *id) +{ + /* Can't create a control object - there can be only one. */ + return ISC_R_NOPERM; +} + +isc_result_t dhcp_control_remove (omapi_object_t *lp, + omapi_object_t *id) +{ + /* Form is emptiness; emptiness form. The control object + cannot go out of existance. */ + return ISC_R_NOPERM; +} + +isc_result_t dhcp_subnet_set_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_typed_data_t *value) +{ + struct subnet *subnet; + isc_result_t status; + int foo; + + if (h -> type != dhcp_type_subnet) + return ISC_R_INVALIDARG; + subnet = (struct subnet *)h; + + /* No values to set yet. */ + + /* Try to find some inner object that can take the value. */ + if (h -> inner && h -> inner -> type -> set_value) { + status = ((*(h -> inner -> type -> set_value)) + (h -> inner, id, name, value)); + if (status == ISC_R_SUCCESS || status == ISC_R_UNCHANGED) + return status; + } + + return ISC_R_NOTFOUND; +} + + +isc_result_t dhcp_subnet_get_value (omapi_object_t *h, omapi_object_t *id, + omapi_data_string_t *name, + omapi_value_t **value) +{ + struct subnet *subnet; + isc_result_t status; + + if (h -> type != dhcp_type_subnet) + return ISC_R_INVALIDARG; + subnet = (struct subnet *)h; + + /* No values to get yet. */ + + /* Try to find some inner object that can provide the value. */ + if (h -> inner && h -> inner -> type -> get_value) { + status = ((*(h -> inner -> type -> get_value)) + (h -> inner, id, name, value)); + if (status == ISC_R_SUCCESS) + return status; + } + return ISC_R_NOTFOUND; +} + +isc_result_t dhcp_subnet_destroy (omapi_object_t *h, const char *file, int line) +{ + struct subnet *subnet; + isc_result_t status; + + if (h -> type != dhcp_type_subnet) + return ISC_R_INVALIDARG; + subnet = (struct subnet *)h; + +#if defined (DEBUG_MEMORY_LEAKAGE) || \ + defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) + if (subnet -> next_subnet) + subnet_dereference (&subnet -> next_subnet, file, line); + if (subnet -> next_sibling) + subnet_dereference (&subnet -> next_sibling, file, line); + if (subnet -> shared_network) + shared_network_dereference (&subnet -> shared_network, + file, line); + if (subnet -> interface) + interface_dereference (&subnet -> interface, file, line); + if (subnet -> group) + group_dereference (&subnet -> group, file, line); +#endif + + return ISC_R_SUCCESS; +} + +isc_result_t dhcp_subnet_signal_handler (omapi_object_t *h, + const char *name, va_list ap) +{ + struct subnet *subnet; + isc_result_t status; + int updatep = 0; + + if (h -> type != dhcp_type_subnet) + return ISC_R_INVALIDARG; + subnet = (struct subnet *)h; + + /* Can't write subnets yet. */ + + /* Try to find some inner object that can take the value. */ + if (h -> inner && h -> inner -> type -> get_value) { + status = ((*(h -> inner -> type -> signal_handler)) + (h -> inner, name, ap)); + if (status == ISC_R_SUCCESS) + return status; + } + if (updatep) + return ISC_R_SUCCESS; + return ISC_R_NOTFOUND; +} + +isc_result_t dhcp_subnet_stuff_values (omapi_object_t *c, + omapi_object_t *id, + omapi_object_t *h) +{ + struct subnet *subnet; + isc_result_t status; + + if (h -> type != dhcp_type_subnet) + return ISC_R_INVALIDARG; + subnet = (struct subnet *)h; + + /* Can't stuff subnet values yet. */ + + /* Write out the inner object, if any. */ + if (h -> inner && h -> inner -> type -> stuff_values) { + status = ((*(h -> inner -> type -> stuff_values)) + (c, id, h -> inner)); + if (status == ISC_R_SUCCESS) + return status; + } + + return ISC_R_SUCCESS; +} + +isc_result_t dhcp_subnet_lookup (omapi_object_t **lp, + omapi_object_t *id, + omapi_object_t *ref) +{ + omapi_value_t *tv = (omapi_value_t *)0; + isc_result_t status; + struct subnet *subnet; + + /* Can't look up subnets yet. */ + + /* If we get to here without finding a subnet, no valid key was + specified. */ + if (!*lp) + return ISC_R_NOKEYS; + return ISC_R_SUCCESS; +} + +isc_result_t dhcp_subnet_create (omapi_object_t **lp, + omapi_object_t *id) +{ + return ISC_R_NOTIMPLEMENTED; +} + +isc_result_t dhcp_subnet_remove (omapi_object_t *lp, + omapi_object_t *id) +{ + return ISC_R_NOTIMPLEMENTED; +} + +isc_result_t dhcp_shared_network_set_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_typed_data_t *value) +{ + struct shared_network *shared_network; + isc_result_t status; + int foo; + + if (h -> type != dhcp_type_shared_network) + return ISC_R_INVALIDARG; + shared_network = (struct shared_network *)h; + + /* No values to set yet. */ + + /* Try to find some inner object that can take the value. */ + if (h -> inner && h -> inner -> type -> set_value) { + status = ((*(h -> inner -> type -> set_value)) + (h -> inner, id, name, value)); + if (status == ISC_R_SUCCESS || status == ISC_R_UNCHANGED) + return status; + } + + return ISC_R_NOTFOUND; +} + + +isc_result_t dhcp_shared_network_get_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_value_t **value) +{ + struct shared_network *shared_network; + isc_result_t status; + + if (h -> type != dhcp_type_shared_network) + return ISC_R_INVALIDARG; + shared_network = (struct shared_network *)h; + + /* No values to get yet. */ + + /* Try to find some inner object that can provide the value. */ + if (h -> inner && h -> inner -> type -> get_value) { + status = ((*(h -> inner -> type -> get_value)) + (h -> inner, id, name, value)); + if (status == ISC_R_SUCCESS) + return status; + } + return ISC_R_NOTFOUND; +} + +isc_result_t dhcp_shared_network_destroy (omapi_object_t *h, + const char *file, int line) +{ + struct shared_network *shared_network; + isc_result_t status; + + if (h -> type != dhcp_type_shared_network) + return ISC_R_INVALIDARG; + shared_network = (struct shared_network *)h; + +#if defined (DEBUG_MEMORY_LEAKAGE) || \ + defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) + if (shared_network -> next) + shared_network_dereference (&shared_network -> next, + file, line); + if (shared_network -> name) { + dfree (shared_network -> name, file, line); + shared_network -> name = 0; + } + if (shared_network -> subnets) + subnet_dereference (&shared_network -> subnets, file, line); + if (shared_network -> interface) + interface_dereference (&shared_network -> interface, + file, line); + if (shared_network -> pools) + omapi_object_dereference ((omapi_object_t **) + &shared_network -> pools, file, line); + if (shared_network -> group) + group_dereference (&shared_network -> group, file, line); +#if defined (FAILOVER_PROTOCOL) + if (shared_network -> failover_peer) + omapi_object_dereference ((omapi_object_t **) + &shared_network -> failover_peer, + file, line); +#endif +#endif /* DEBUG_MEMORY_LEAKAGE */ + + return ISC_R_SUCCESS; +} + +isc_result_t dhcp_shared_network_signal_handler (omapi_object_t *h, + const char *name, + va_list ap) +{ + struct shared_network *shared_network; + isc_result_t status; + int updatep = 0; + + if (h -> type != dhcp_type_shared_network) + return ISC_R_INVALIDARG; + shared_network = (struct shared_network *)h; + + /* Can't write shared_networks yet. */ + + /* Try to find some inner object that can take the value. */ + if (h -> inner && h -> inner -> type -> get_value) { + status = ((*(h -> inner -> type -> signal_handler)) + (h -> inner, name, ap)); + if (status == ISC_R_SUCCESS) + return status; + } + if (updatep) + return ISC_R_SUCCESS; + return ISC_R_NOTFOUND; +} + +isc_result_t dhcp_shared_network_stuff_values (omapi_object_t *c, + omapi_object_t *id, + omapi_object_t *h) +{ + struct shared_network *shared_network; + isc_result_t status; + + if (h -> type != dhcp_type_shared_network) + return ISC_R_INVALIDARG; + shared_network = (struct shared_network *)h; + + /* Can't stuff shared_network values yet. */ + + /* Write out the inner object, if any. */ + if (h -> inner && h -> inner -> type -> stuff_values) { + status = ((*(h -> inner -> type -> stuff_values)) + (c, id, h -> inner)); + if (status == ISC_R_SUCCESS) + return status; + } + + return ISC_R_SUCCESS; +} + +isc_result_t dhcp_shared_network_lookup (omapi_object_t **lp, + omapi_object_t *id, + omapi_object_t *ref) +{ + omapi_value_t *tv = (omapi_value_t *)0; + isc_result_t status; + struct shared_network *shared_network; + + /* Can't look up shared_networks yet. */ + + /* If we get to here without finding a shared_network, no valid key was + specified. */ + if (!*lp) + return ISC_R_NOKEYS; + return ISC_R_SUCCESS; +} + +isc_result_t dhcp_shared_network_create (omapi_object_t **lp, + omapi_object_t *id) +{ + return ISC_R_NOTIMPLEMENTED; +} + +isc_result_t dhcp_shared_network_remove (omapi_object_t *lp, + omapi_object_t *id) +{ + return ISC_R_NOTIMPLEMENTED; +} + diff --git a/contrib/isc-dhcp/common/conflex.c b/contrib/isc-dhcp/common/conflex.c index ddb78e6..ac73de5 100644 --- a/contrib/isc-dhcp/common/conflex.c +++ b/contrib/isc-dhcp/common/conflex.c @@ -3,7 +3,7 @@ Lexical scanner for dhcpd config file... */ /* - * Copyright (c) 1995, 1996, 1997 The Internet Software Consortium. + * Copyright (c) 1995-2001 Internet Software Consortium. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,146 +34,193 @@ * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium - * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie - * Enterprises. To learn more about the Internet Software Consortium, - * see ``http://www.vix.com/isc''. To learn more about Vixie - * Enterprises, see ``http://www.vix.com''. + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. */ #ifndef lint static char copyright[] = -"$Id: conflex.c,v 1.29.2.4 1999/04/06 14:58:55 mellon Exp $ Copyright (c) 1995, 1996, 1997 The Internet Software Consortium. All rights reserved.\n"; +"$Id: conflex.c,v 1.92.2.4 2002/01/10 19:35:59 mellon Exp $ Copyright (c) 1995-2001 The Internet Software Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" -#include "dhctoken.h" #include <ctype.h> -int lexline; -int lexchar; -char *token_line; -char *prev_line; -char *cur_line; -char *tlname; -int eol_token; - -static char line1 [81]; -static char line2 [81]; -static int lpos; -static int line; -static int tlpos; -static int tline; -static int token; -static int ugflag; -static char *tval; -static char tokbuf [1500]; +static int get_char PROTO ((struct parse *)); +static enum dhcp_token get_token PROTO ((struct parse *)); +static void skip_to_eol PROTO ((struct parse *)); +static enum dhcp_token read_string PROTO ((struct parse *)); +static enum dhcp_token read_number PROTO ((int, struct parse *)); +static enum dhcp_token read_num_or_name PROTO ((int, struct parse *)); +static enum dhcp_token intern PROTO ((char *, enum dhcp_token)); -#ifdef OLD_LEXER -char comments [4096]; -int comment_index; -#endif +isc_result_t new_parse (cfile, file, inbuf, buflen, name, eolp) + struct parse **cfile; + int file; + char *inbuf; + unsigned buflen; + const char *name; + int eolp; +{ + struct parse *tmp; + + tmp = dmalloc (sizeof (struct parse), MDL); + if (!tmp) + return ISC_R_NOMEMORY; + memset (tmp, 0, sizeof *tmp); + tmp -> token = 0; + tmp -> tlname = name; + tmp -> lpos = tmp -> line = 1; + tmp -> cur_line = tmp -> line1; + tmp -> prev_line = tmp -> line2; + tmp -> token_line = tmp -> cur_line; + tmp -> cur_line [0] = tmp -> prev_line [0] = 0; + tmp -> warnings_occurred = 0; + tmp -> file = file; + tmp -> eol_token = eolp; -static int get_char PROTO ((FILE *)); -static int get_token PROTO ((FILE *)); -static void skip_to_eol PROTO ((FILE *)); -static int read_string PROTO ((FILE *)); -static int read_number PROTO ((int, FILE *)); -static int read_num_or_name PROTO ((int, FILE *)); -static int intern PROTO ((char *, int)); + tmp -> bufix = 0; + tmp -> buflen = buflen; + if (inbuf) { + tmp -> bufsiz = 0; + tmp -> inbuf = inbuf; + } else { + tmp -> inbuf = dmalloc (8192, MDL); + if (!tmp -> inbuf) { + dfree (tmp, MDL); + return ISC_R_NOMEMORY; + } + tmp -> bufsiz = 8192; + } -void new_parse (name) - char *name; + *cfile = tmp; + return ISC_R_SUCCESS; +} + +isc_result_t end_parse (cfile) + struct parse **cfile; { - tlname = name; - lpos = line = 1; - cur_line = line1; - prev_line = line2; - token_line = cur_line; - cur_line [0] = prev_line [0] = 0; - warnings_occurred = 0; + if ((*cfile) -> bufsiz) + dfree ((*cfile) -> inbuf, MDL); + dfree (*cfile, MDL); + *cfile = (struct parse *)0; + return ISC_R_SUCCESS; } static int get_char (cfile) - FILE *cfile; + struct parse *cfile; { - int c = getc (cfile); - if (!ugflag) { + /* My kingdom for WITH... */ + int c; + + if (cfile -> bufix == cfile -> buflen) { + if (cfile -> file != -1) { + cfile -> buflen = + read (cfile -> file, + cfile -> inbuf, cfile -> bufsiz); + if (cfile -> buflen == 0) { + c = EOF; + cfile -> bufix = 0; + } else if (cfile -> buflen < 0) { + c = EOF; + cfile -> bufix = cfile -> buflen = 0; + } else { + c = cfile -> inbuf [0]; + cfile -> bufix = 1; + } + } else + c = EOF; + } else { + c = cfile -> inbuf [cfile -> bufix]; + cfile -> bufix++; + } + + if (!cfile -> ugflag) { if (c == EOL) { - if (cur_line == line1) { - cur_line = line2; - prev_line = line1; + if (cfile -> cur_line == cfile -> line1) { + cfile -> cur_line = cfile -> line2; + cfile -> prev_line = cfile -> line1; } else { - cur_line = line2; - prev_line = line1; + cfile -> cur_line = cfile -> line1; + cfile -> prev_line = cfile -> line2; } - line++; - lpos = 1; - cur_line [0] = 0; + cfile -> line++; + cfile -> lpos = 1; + cfile -> cur_line [0] = 0; } else if (c != EOF) { - if (lpos <= 81) { - cur_line [lpos - 1] = c; - cur_line [lpos] = 0; + if (cfile -> lpos <= 80) { + cfile -> cur_line [cfile -> lpos - 1] = c; + cfile -> cur_line [cfile -> lpos] = 0; } - lpos++; + cfile -> lpos++; } } else - ugflag = 0; + cfile -> ugflag = 0; return c; } -static int get_token (cfile) - FILE *cfile; +static enum dhcp_token get_token (cfile) + struct parse *cfile; { int c; - int ttok; + enum dhcp_token ttok; static char tb [2]; int l, p, u; do { - l = line; - p = lpos; - u = ugflag; + l = cfile -> line; + p = cfile -> lpos; + u = cfile -> ugflag; c = get_char (cfile); #ifdef OLD_LEXER if (c == '\n' && p == 1 && !u - && comment_index < sizeof comments) - comments [comment_index++] = '\n'; + && cfile -> comment_index < sizeof cfile -> comments) + cfile -> comments [cfile -> comment_index++] = '\n'; #endif - if (!(c == '\n' && eol_token) && isascii (c) && isspace (c)) + if (!(c == '\n' && cfile -> eol_token) + && isascii (c) && isspace (c)) continue; if (c == '#') { #ifdef OLD_LEXER - if (comment_index < sizeof comments) - comments [comment_index++] = '#'; + if (cfile -> comment_index < sizeof cfile -> comments) + cfile -> comments [cfile -> comment_index++] = '#'; #endif skip_to_eol (cfile); continue; } if (c == '"') { - lexline = l; - lexchar = p; + cfile -> lexline = l; + cfile -> lexchar = p; ttok = read_string (cfile); break; } if ((isascii (c) && isdigit (c)) || c == '-') { - lexline = l; - lexchar = p; + cfile -> lexline = l; + cfile -> lexchar = p; ttok = read_number (c, cfile); break; } else if (isascii (c) && isalpha (c)) { - lexline = l; - lexchar = p; + cfile -> lexline = l; + cfile -> lexchar = p; ttok = read_num_or_name (c, cfile); break; + } else if (c == EOF) { + ttok = END_OF_FILE; + cfile -> tlen = 0; + break; } else { - lexline = l; - lexchar = p; + cfile -> lexline = l; + cfile -> lexchar = p; tb [0] = c; tb [1] = 0; - tval = tb; + cfile -> tval = tb; + cfile -> tlen = 1; ttok = c; break; } @@ -181,56 +228,68 @@ static int get_token (cfile) return ttok; } -int next_token (rval, cfile) - char **rval; - FILE *cfile; +enum dhcp_token next_token (rval, rlen, cfile) + const char **rval; + unsigned *rlen; + struct parse *cfile; { int rv; - if (token) { - if (lexline != tline) - token_line = cur_line; - lexchar = tlpos; - lexline = tline; - rv = token; - token = 0; + if (cfile -> token) { + if (cfile -> lexline != cfile -> tline) + cfile -> token_line = cfile -> cur_line; + cfile -> lexchar = cfile -> tlpos; + cfile -> lexline = cfile -> tline; + rv = cfile -> token; + cfile -> token = 0; } else { rv = get_token (cfile); - token_line = cur_line; + cfile -> token_line = cfile -> cur_line; } if (rval) - *rval = tval; + *rval = cfile -> tval; + if (rlen) + *rlen = cfile -> tlen; #ifdef DEBUG_TOKENS - fprintf (stderr, "%s:%d ", tval, rv); + fprintf (stderr, "%s:%d ", cfile -> tval, rv); #endif return rv; } -int peek_token (rval, cfile) - char **rval; - FILE *cfile; +enum dhcp_token peek_token (rval, rlen, cfile) + const char **rval; + unsigned int *rlen; + struct parse *cfile; { int x; - if (!token) { - tlpos = lexchar; - tline = lexline; - token = get_token (cfile); - if (lexline != tline) - token_line = prev_line; - x = lexchar; lexchar = tlpos; tlpos = x; - x = lexline; lexline = tline; tline = x; + if (!cfile -> token) { + cfile -> tlpos = cfile -> lexchar; + cfile -> tline = cfile -> lexline; + cfile -> token = get_token (cfile); + if (cfile -> lexline != cfile -> tline) + cfile -> token_line = cfile -> prev_line; + + x = cfile -> lexchar; + cfile -> lexchar = cfile -> tlpos; + cfile -> tlpos = x; + + x = cfile -> lexline; + cfile -> lexline = cfile -> tline; + cfile -> tline = x; } if (rval) - *rval = tval; + *rval = cfile -> tval; + if (rlen) + *rlen = cfile -> tlen; #ifdef DEBUG_TOKENS - fprintf (stderr, "(%s:%d) ", tval, token); + fprintf (stderr, "(%s:%d) ", cfile -> tval, cfile -> token); #endif - return token; + return cfile -> token; } static void skip_to_eol (cfile) - FILE *cfile; + struct parse *cfile; { int c; do { @@ -238,8 +297,8 @@ static void skip_to_eol (cfile) if (c == EOF) return; #ifdef OLD_LEXER - if (comment_index < sizeof (comments)) - comments [comment_index++] = c; + if (cfile -> comment_index < sizeof (cfile -> comments)) + comments [cfile -> comment_index++] = c; #endif if (c == EOL) { return; @@ -247,50 +306,125 @@ static void skip_to_eol (cfile) } while (1); } -static int read_string (cfile) - FILE *cfile; +static enum dhcp_token read_string (cfile) + struct parse *cfile; { int i; int bs = 0; int c; + int value; + int hex; - for (i = 0; i < sizeof tokbuf; i++) { + for (i = 0; i < sizeof cfile -> tokbuf; i++) { + again: c = get_char (cfile); if (c == EOF) { - parse_warn ("eof in string constant"); + parse_warn (cfile, "eof in string constant"); break; } - if (bs) { + if (bs == 1) { + switch (c) { + case 't': + cfile -> tokbuf [i] = '\t'; + break; + case 'r': + cfile -> tokbuf [i] = '\r'; + break; + case 'n': + cfile -> tokbuf [i] = '\n'; + break; + case 'b': + cfile -> tokbuf [i] = '\b'; + break; + case '0': + case '1': + case '2': + case '3': + hex = 0; + value = c - '0'; + ++bs; + goto again; + case 'x': + hex = 1; + value = 0; + ++bs; + goto again; + default: + cfile -> tokbuf [i] = c; + bs = 0; + break; + } bs = 0; - tokbuf [i] = c; - } else if (c == '\\') + } else if (bs > 1) { + if (hex) { + if (c >= '0' && c <= '9') { + value = value * 16 + (c - '0'); + } else if (c >= 'a' && c <= 'f') { + value = value * 16 + (c - 'a' + 10); + } else if (c >= 'A' && c <= 'F') { + value = value * 16 + (c - 'A' + 10); + } else { + parse_warn (cfile, + "invalid hex digit: %x", + c); + bs = 0; + continue; + } + if (++bs == 4) { + cfile -> tokbuf [i] = value; + bs = 0; + } else + goto again; + } else { + if (c >= '0' && c <= '9') { + value = value * 8 + (c - '0'); + } else { + if (value != 0) { + parse_warn (cfile, + "invalid octal digit %x", + c); + continue; + } else + cfile -> tokbuf [i] = 0; + bs = 0; + } + if (++bs == 4) { + cfile -> tokbuf [i] = value; + bs = 0; + } else + goto again; + } + } else if (c == '\\') { bs = 1; - else if (c == '"') + goto again; + } else if (c == '"') break; else - tokbuf [i] = c; + cfile -> tokbuf [i] = c; } /* Normally, I'd feel guilty about this, but we're talking about strings that'll fit in a DHCP packet here... */ - if (i == sizeof tokbuf) { - parse_warn ("string constant larger than internal buffer"); + if (i == sizeof cfile -> tokbuf) { + parse_warn (cfile, + "string constant larger than internal buffer"); --i; } - tokbuf [i] = 0; - tval = tokbuf; + cfile -> tokbuf [i] = 0; + cfile -> tlen = i; + cfile -> tval = cfile -> tokbuf; return STRING; } -static int read_number (c, cfile) +static enum dhcp_token read_number (c, cfile) int c; - FILE *cfile; + struct parse *cfile; { int seenx = 0; int i = 0; int token = NUMBER; - tokbuf [i++] = c; - for (; i < sizeof tokbuf; i++) { + cfile -> tokbuf [i++] = c; + for (; i < sizeof cfile -> tokbuf; i++) { c = get_char (cfile); if (!seenx && c == 'x') { seenx = 1; @@ -302,95 +436,190 @@ static int read_number (c, cfile) token = NUMBER_OR_NAME; #endif } else if (!isascii (c) || !isxdigit (c)) { - ungetc (c, cfile); - ugflag = 1; + if (c != EOF) { + cfile -> bufix--; + cfile -> ugflag = 1; + } break; } - tokbuf [i] = c; + cfile -> tokbuf [i] = c; } - if (i == sizeof tokbuf) { - parse_warn ("numeric token larger than internal buffer"); + if (i == sizeof cfile -> tokbuf) { + parse_warn (cfile, + "numeric token larger than internal buffer"); --i; } - tokbuf [i] = 0; - tval = tokbuf; + cfile -> tokbuf [i] = 0; + cfile -> tlen = i; + cfile -> tval = cfile -> tokbuf; return token; } -static int read_num_or_name (c, cfile) +static enum dhcp_token read_num_or_name (c, cfile) int c; - FILE *cfile; + struct parse *cfile; { int i = 0; - int rv = NUMBER_OR_NAME; - tokbuf [i++] = c; - for (; i < sizeof tokbuf; i++) { + enum dhcp_token rv = NUMBER_OR_NAME; + cfile -> tokbuf [i++] = c; + for (; i < sizeof cfile -> tokbuf; i++) { c = get_char (cfile); if (!isascii (c) || (c != '-' && c != '_' && !isalnum (c))) { - ungetc (c, cfile); - ugflag = 1; + if (c != EOF) { + cfile -> bufix--; + cfile -> ugflag = 1; + } break; } if (!isxdigit (c)) rv = NAME; - tokbuf [i] = c; + cfile -> tokbuf [i] = c; } - if (i == sizeof tokbuf) { - parse_warn ("token larger than internal buffer"); + if (i == sizeof cfile -> tokbuf) { + parse_warn (cfile, "token larger than internal buffer"); --i; } - tokbuf [i] = 0; - tval = tokbuf; - return intern (tval, rv); + cfile -> tokbuf [i] = 0; + cfile -> tlen = i; + cfile -> tval = cfile -> tokbuf; + return intern (cfile -> tval, rv); } -static int intern (atom, dfv) +static enum dhcp_token intern (atom, dfv) char *atom; - int dfv; + enum dhcp_token dfv; { if (!isascii (atom [0])) return dfv; switch (tolower (atom [0])) { + case '-': + if (atom [1] == 0) + return MINUS; + break; + case 'a': - if (!strcasecmp (atom + 1, "lways-reply-rfc1048")) - return ALWAYS_REPLY_RFC1048; + if (!strncasecmp (atom + 1, "uth", 3)) { + if (!strncasecmp (atom + 3, "uthenticat", 10)) { + if (!strcasecmp (atom + 13, "ed")) + return AUTHENTICATED; + if (!strcasecmp (atom + 13, "ion")) + return AUTHENTICATION; + break; + } + if (!strcasecmp (atom + 1, "uthoritative")) + return AUTHORITATIVE; + break; + } + if (!strcasecmp (atom + 1, "nd")) + return AND; if (!strcasecmp (atom + 1, "ppend")) return APPEND; if (!strcasecmp (atom + 1, "llow")) return ALLOW; if (!strcasecmp (atom + 1, "lias")) return ALIAS; + if (!strcasecmp (atom + 1, "lgorithm")) + return ALGORITHM; if (!strcasecmp (atom + 1, "bandoned")) - return ABANDONED; - if (!strcasecmp (atom + 1, "uthoritative")) - return AUTHORITATIVE; + return TOKEN_ABANDONED; + if (!strcasecmp (atom + 1, "dd")) + return TOKEN_ADD; + if (!strcasecmp (atom + 1, "ll")) + return ALL; + if (!strcasecmp (atom + 1, "t")) + return AT; + if (!strcasecmp (atom + 1, "rray")) + return ARRAY; + if (!strcasecmp (atom + 1, "ddress")) + return ADDRESS; + if (!strcasecmp (atom + 1, "ctive")) + return TOKEN_ACTIVE; break; case 'b': + if (!strcasecmp (atom + 1, "ackup")) + return TOKEN_BACKUP; + if (!strcasecmp (atom + 1, "ootp")) + return TOKEN_BOOTP; + if (!strcasecmp (atom + 1, "inding")) + return BINDING; + if (!strcasecmp (atom + 1, "inary-to-ascii")) + return BINARY_TO_ASCII; if (!strcasecmp (atom + 1, "ackoff-cutoff")) return BACKOFF_CUTOFF; - if (!strcasecmp (atom + 1, "ootp")) - return BOOTP; if (!strcasecmp (atom + 1, "ooting")) return BOOTING; if (!strcasecmp (atom + 1, "oot-unknown-clients")) return BOOT_UNKNOWN_CLIENTS; + if (!strcasecmp (atom + 1, "reak")) + return BREAK; + if (!strcasecmp (atom + 1, "illing")) + return BILLING; + if (!strcasecmp (atom + 1, "oolean")) + return BOOLEAN; + if (!strcasecmp (atom + 1, "alance")) + return BALANCE; + if (!strcasecmp (atom + 1, "ound")) + return BOUND; + break; case 'c': + if (!strcasecmp (atom + 1, "ase")) + return CASE; + if (!strcasecmp (atom + 1, "ommit")) + return COMMIT; + if (!strcasecmp (atom + 1, "ode")) + return CODE; + if (!strcasecmp (atom + 1, "onfig-option")) + return CONFIG_OPTION; + if (!strcasecmp (atom + 1, "heck")) + return CHECK; if (!strcasecmp (atom + 1, "lass")) return CLASS; + if (!strcasecmp (atom + 1, "lose")) + return TOKEN_CLOSE; + if (!strcasecmp (atom + 1, "reate")) + return TOKEN_CREATE; if (!strcasecmp (atom + 1, "iaddr")) return CIADDR; - if (!strcasecmp (atom + 1, "lient-identifier")) - return CLIENT_IDENTIFIER; - if (!strcasecmp (atom + 1, "lient-hostname")) - return CLIENT_HOSTNAME; + if (!strncasecmp (atom + 1, "lient", 5)) { + if (!strcasecmp (atom + 6, "-identifier")) + return CLIENT_IDENTIFIER; + if (!strcasecmp (atom + 6, "-hostname")) + return CLIENT_HOSTNAME; + if (!strcasecmp (atom + 6, "-state")) + return CLIENT_STATE; + if (!strcasecmp (atom + 6, "-updates")) + return CLIENT_UPDATES; + if (!strcasecmp (atom + 6, "s")) + return CLIENTS; + } + if (!strcasecmp (atom + 1, "oncat")) + return CONCAT; + if (!strcasecmp (atom + 1, "onnect")) + return CONNECT; + if (!strcasecmp (atom + 1, "ommunications-interrupted")) + return COMMUNICATIONS_INTERRUPTED; + if (!strcasecmp (atom + 1, "ltt")) + return CLTT; break; case 'd': + if (!strcasecmp (atom + 1, "ns-update")) + return DNS_UPDATE; + if (!strcasecmp (atom + 1, "ns-delete")) + return DNS_DELETE; if (!strcasecmp (atom + 1, "omain")) return DOMAIN; + if (!strcasecmp (atom + 1, "omain-name")) + return DOMAIN_NAME; + if (!strcasecmp (atom + 1, "ebug")) + return TOKEN_DEBUG; if (!strcasecmp (atom + 1, "eny")) return DENY; + if (!strcasecmp (atom + 1, "eleted")) + return TOKEN_DELETED; + if (!strcasecmp (atom + 1, "elete")) + return TOKEN_DELETE; if (!strncasecmp (atom + 1, "efault", 6)) { if (!atom [7]) return DEFAULT; @@ -398,31 +627,80 @@ static int intern (atom, dfv) return DEFAULT_LEASE_TIME; break; } - if (!strncasecmp (atom + 1, "ynamic-bootp", 12)) { - if (!atom [13]) - return DYNAMIC_BOOTP; - if (!strcasecmp (atom + 13, "-lease-cutoff")) - return DYNAMIC_BOOTP_LEASE_CUTOFF; - if (!strcasecmp (atom + 13, "-lease-length")) - return DYNAMIC_BOOTP_LEASE_LENGTH; - break; + if (!strncasecmp (atom + 1, "ynamic", 6)) { + if (!atom [7]) + return DYNAMIC; + if (!strncasecmp (atom + 7, "-bootp", 6)) { + if (!atom [13]) + return DYNAMIC_BOOTP; + if (!strcasecmp (atom + 13, "-lease-cutoff")) + return DYNAMIC_BOOTP_LEASE_CUTOFF; + if (!strcasecmp (atom + 13, "-lease-length")) + return DYNAMIC_BOOTP_LEASE_LENGTH; + break; + } + } + if (!strcasecmp (atom + 1, "uplicates")) + return DUPLICATES; + if (!strcasecmp (atom + 1, "eclines")) + return DECLINES; + if (!strncasecmp (atom + 1, "efine", 5)) { + if (!strcasecmp (atom + 6, "d")) + return DEFINED; + if (!atom [6]) + return DEFINE; } break; case 'e': + if (isascii (atom [1]) && tolower (atom [1]) == 'x') { + if (!strcasecmp (atom + 2, "tract-int")) + return EXTRACT_INT; + if (!strcasecmp (atom + 2, "ists")) + return EXISTS; + if (!strcasecmp (atom + 2, "piry")) + return EXPIRY; + if (!strcasecmp (atom + 2, "pire")) + return EXPIRE; + if (!strcasecmp (atom + 2, "pired")) + return TOKEN_EXPIRED; + } + if (!strcasecmp (atom + 1, "ncode-int")) + return ENCODE_INT; if (!strcasecmp (atom + 1, "thernet")) return ETHERNET; if (!strcasecmp (atom + 1, "nds")) return ENDS; - if (!strcasecmp (atom + 1, "xpire")) - return EXPIRE; + if (!strncasecmp (atom + 1, "ls", 2)) { + if (!strcasecmp (atom + 3, "e")) + return ELSE; + if (!strcasecmp (atom + 3, "if")) + return ELSIF; + break; + } + if (!strcasecmp (atom + 1, "rror")) + return ERROR; + if (!strcasecmp (atom + 1, "val")) + return EVAL; + if (!strcasecmp (atom + 1, "ncapsulate")) + return ENCAPSULATE; break; case 'f': + if (!strcasecmp (atom + 1, "atal")) + return FATAL; if (!strcasecmp (atom + 1, "ilename")) return FILENAME; if (!strcasecmp (atom + 1, "ixed-address")) return FIXED_ADDR; if (!strcasecmp (atom + 1, "ddi")) return FDDI; + if (!strcasecmp (atom + 1, "ormerr")) + return NS_FORMERR; + if (!strcasecmp (atom + 1, "unction")) + return FUNCTION; + if (!strcasecmp (atom + 1, "ailover")) + return FAILOVER; + if (!strcasecmp (atom + 1, "ree")) + return TOKEN_FREE; break; case 'g': if (!strcasecmp (atom + 1, "iaddr")) @@ -433,26 +711,85 @@ static int intern (atom, dfv) return GET_LEASE_HOSTNAMES; break; case 'h': + if (!strcasecmp (atom + 1, "ba")) + return HBA; if (!strcasecmp (atom + 1, "ost")) return HOST; + if (!strcasecmp (atom + 1, "ost-decl-name")) + return HOST_DECL_NAME; if (!strcasecmp (atom + 1, "ardware")) return HARDWARE; if (!strcasecmp (atom + 1, "ostname")) return HOSTNAME; + if (!strcasecmp (atom + 1, "elp")) + return TOKEN_HELP; break; case 'i': + if (!strcasecmp (atom + 1, "nclude")) + return INCLUDE; + if (!strcasecmp (atom + 1, "nteger")) + return INTEGER; + if (!strcasecmp (atom + 1, "nfinite")) + return INFINITE; + if (!strcasecmp (atom + 1, "nfo")) + return INFO; + if (!strcasecmp (atom + 1, "p-address")) + return IP_ADDRESS; if (!strcasecmp (atom + 1, "nitial-interval")) return INITIAL_INTERVAL; if (!strcasecmp (atom + 1, "nterface")) return INTERFACE; + if (!strcasecmp (atom + 1, "dentifier")) + return IDENTIFIER; + if (!strcasecmp (atom + 1, "f")) + return IF; + if (!strcasecmp (atom + 1, "s")) + return IS; + if (!strcasecmp (atom + 1, "gnore")) + return IGNORE; + break; + case 'k': + if (!strcasecmp (atom + 1, "nown")) + return KNOWN; + if (!strcasecmp (atom + 1, "ey")) + return KEY; break; case 'l': if (!strcasecmp (atom + 1, "ease")) return LEASE; + if (!strcasecmp (atom + 1, "eased-address")) + return LEASED_ADDRESS; + if (!strcasecmp (atom + 1, "ease-time")) + return LEASE_TIME; + if (!strcasecmp (atom + 1, "imit")) + return LIMIT; + if (!strcasecmp (atom + 1, "et")) + return LET; + if (!strcasecmp (atom + 1, "oad")) + return LOAD; + if (!strcasecmp (atom + 1, "og")) + return LOG; break; case 'm': - if (!strcasecmp (atom + 1, "ax-lease-time")) - return MAX_LEASE_TIME; + if (!strncasecmp (atom + 1, "ax", 2)) { + if (!atom [3]) + return TOKEN_MAX; + if (!strcasecmp (atom + 3, "-lease-time")) + return MAX_LEASE_TIME; + if (!strcasecmp (atom + 3, "-transmit-idle")) + return MAX_TRANSMIT_IDLE; + if (!strcasecmp (atom + 3, "-response-delay")) + return MAX_RESPONSE_DELAY; + if (!strcasecmp (atom + 3, "-unacked-updates")) + return MAX_UNACKED_UPDATES; + } + if (!strncasecmp (atom + 1, "in-", 3)) { + if (!strcasecmp (atom + 4, "lease-time")) + return MIN_LEASE_TIME; + if (!strcasecmp (atom + 4, "secs")) + return MIN_SECS; + break; + } if (!strncasecmp (atom + 1, "edi", 3)) { if (!strcasecmp (atom + 4, "a")) return MEDIA; @@ -460,38 +797,121 @@ static int intern (atom, dfv) return MEDIUM; break; } + if (!strcasecmp (atom + 1, "atch")) + return MATCH; + if (!strcasecmp (atom + 1, "embers")) + return MEMBERS; + if (!strcasecmp (atom + 1, "y")) + return MY; + if (!strcasecmp (atom + 1, "clt")) + return MCLT; break; case 'n': + if (!strcasecmp (atom + 1, "ormal")) + return NORMAL; if (!strcasecmp (atom + 1, "ameserver")) return NAMESERVER; if (!strcasecmp (atom + 1, "etmask")) return NETMASK; + if (!strcasecmp (atom + 1, "ever")) + return NEVER; if (!strcasecmp (atom + 1, "ext-server")) return NEXT_SERVER; if (!strcasecmp (atom + 1, "ot")) return TOKEN_NOT; + if (!strcasecmp (atom + 1, "o")) + return NO; + if (!strcasecmp (atom + 1, "s-update")) + return NS_UPDATE; + if (!strcasecmp (atom + 1, "oerror")) + return NS_NOERROR; + if (!strcasecmp (atom + 1, "otauth")) + return NS_NOTAUTH; + if (!strcasecmp (atom + 1, "otimp")) + return NS_NOTIMP; + if (!strcasecmp (atom + 1, "otzone")) + return NS_NOTZONE; + if (!strcasecmp (atom + 1, "xdomain")) + return NS_NXDOMAIN; + if (!strcasecmp (atom + 1, "xrrset")) + return NS_NXRRSET; + if (!strcasecmp (atom + 1, "ull")) + return TOKEN_NULL; + if (!strcasecmp (atom + 1, "ext")) + return TOKEN_NEXT; + if (!strcasecmp (atom + 1, "ew")) + return TOKEN_NEW; break; case 'o': + if (!strcasecmp (atom + 1, "mapi")) + return OMAPI; + if (!strcasecmp (atom + 1, "r")) + return OR; + if (!strcasecmp (atom + 1, "n")) + return ON; + if (!strcasecmp (atom + 1, "pen")) + return TOKEN_OPEN; if (!strcasecmp (atom + 1, "ption")) return OPTION; if (!strcasecmp (atom + 1, "ne-lease-per-client")) return ONE_LEASE_PER_CLIENT; + if (!strcasecmp (atom + 1, "f")) + return OF; + if (!strcasecmp (atom + 1, "wner")) + return OWNER; break; case 'p': if (!strcasecmp (atom + 1, "repend")) return PREPEND; if (!strcasecmp (atom + 1, "acket")) return PACKET; + if (!strcasecmp (atom + 1, "ool")) + return POOL; + if (!strcasecmp (atom + 1, "seudo")) + return PSEUDO; + if (!strcasecmp (atom + 1, "eer")) + return PEER; + if (!strcasecmp (atom + 1, "rimary")) + return PRIMARY; + if (!strncasecmp (atom + 1, "artner", 6)) { + if (!atom [7]) + return PARTNER; + if (!strcasecmp (atom + 7, "-down")) + return PARTNER_DOWN; + } + if (!strcasecmp (atom + 1, "ort")) + return PORT; + if (!strcasecmp (atom + 1, "otential-conflict")) + return POTENTIAL_CONFLICT; + if (!strcasecmp (atom + 1, "ick-first-value") || + !strcasecmp (atom + 1, "ick")) + return PICK; + if (!strcasecmp (atom + 1, "aused")) + return PAUSED; break; case 'r': + if (!strcasecmp (atom + 1, "esolution-interrupted")) + return RESOLUTION_INTERRUPTED; if (!strcasecmp (atom + 1, "ange")) return RANGE; + if (!strcasecmp (atom + 1, "ecover")) + return RECOVER; + if (!strcasecmp (atom + 1, "ecover-done")) + return RECOVER_DONE; + if (!strcasecmp (atom + 1, "ecover-wait")) + return RECOVER_WAIT; + if (!strcasecmp (atom + 1, "econtact-interval")) + return RECONTACT_INTERVAL; if (!strcasecmp (atom + 1, "equest")) return REQUEST; if (!strcasecmp (atom + 1, "equire")) return REQUIRE; + if (!strcasecmp (atom + 1, "equire")) + return REQUIRE; if (!strcasecmp (atom + 1, "etry")) return RETRY; + if (!strcasecmp (atom + 1, "eturn")) + return RETURN; if (!strcasecmp (atom + 1, "enew")) return RENEW; if (!strcasecmp (atom + 1, "ebind")) @@ -500,30 +920,89 @@ static int intern (atom, dfv) return REBOOT; if (!strcasecmp (atom + 1, "eject")) return REJECT; + if (!strcasecmp (atom + 1, "everse")) + return REVERSE; + if (!strcasecmp (atom + 1, "elease")) + return RELEASE; + if (!strcasecmp (atom + 1, "efused")) + return NS_REFUSED; + if (!strcasecmp (atom + 1, "eleased")) + return TOKEN_RELEASED; + if (!strcasecmp (atom + 1, "eset")) + return TOKEN_RESET; + if (!strcasecmp (atom + 1, "eserved")) + return TOKEN_RESERVED; + if (!strcasecmp (atom + 1, "emove")) + return REMOVE; + if (!strcasecmp (atom + 1, "efresh")) + return REFRESH; break; case 's': + if (!strcasecmp (atom + 1, "tate")) + return STATE; + if (!strcasecmp (atom + 1, "ecret")) + return SECRET; + if (!strcasecmp (atom + 1, "ervfail")) + return NS_SERVFAIL; + if (!strcasecmp (atom + 1, "witch")) + return SWITCH; + if (!strcasecmp (atom + 1, "igned")) + return SIGNED; + if (!strcasecmp (atom + 1, "tring")) + return STRING_TOKEN; + if (!strcasecmp (atom + 1, "uffix")) + return SUFFIX; if (!strcasecmp (atom + 1, "earch")) return SEARCH; if (!strcasecmp (atom + 1, "tarts")) return STARTS; if (!strcasecmp (atom + 1, "iaddr")) return SIADDR; - if (!strcasecmp (atom + 1, "ubnet")) - return SUBNET; if (!strcasecmp (atom + 1, "hared-network")) return SHARED_NETWORK; + if (!strcasecmp (atom + 1, "econdary")) + return SECONDARY; if (!strcasecmp (atom + 1, "erver-name")) return SERVER_NAME; if (!strcasecmp (atom + 1, "erver-identifier")) return SERVER_IDENTIFIER; + if (!strcasecmp (atom + 1, "erver")) + return SERVER; if (!strcasecmp (atom + 1, "elect-timeout")) return SELECT_TIMEOUT; + if (!strcasecmp (atom + 1, "elect")) + return SELECT; if (!strcasecmp (atom + 1, "end")) return SEND; if (!strcasecmp (atom + 1, "cript")) return SCRIPT; if (!strcasecmp (atom + 1, "upersede")) return SUPERSEDE; + if (!strncasecmp (atom + 1, "ub", 2)) { + if (!strcasecmp (atom + 3, "string")) + return SUBSTRING; + if (!strcasecmp (atom + 3, "net")) + return SUBNET; + if (!strcasecmp (atom + 3, "class")) + return SUBCLASS; + break; + } + if (!strcasecmp (atom + 1, "pawn")) + return SPAWN; + if (!strcasecmp (atom + 1, "pace")) + return SPACE; + if (!strcasecmp (atom + 1, "tatic")) + return STATIC; + if (!strcasecmp (atom + 1, "plit")) + return SPLIT; + if (!strcasecmp (atom + 1, "et")) + return TOKEN_SET; + if (!strcasecmp (atom + 1, "econds")) + return SECONDS; + if (!strcasecmp (atom + 1, "hutdown")) + return SHUTDOWN; + if (!strcasecmp (atom + 1, "tartup")) + return STARTUP; break; case 't': if (!strcasecmp (atom + 1, "imestamp")) @@ -532,8 +1011,22 @@ static int intern (atom, dfv) return TIMEOUT; if (!strcasecmp (atom + 1, "oken-ring")) return TOKEN_RING; + if (!strcasecmp (atom + 1, "ext")) + return TEXT; + if (!strcasecmp (atom + 1, "stp")) + return TSTP; + if (!strcasecmp (atom + 1, "sfp")) + return TSFP; + if (!strcasecmp (atom + 1, "ransmission")) + return TRANSMISSION; break; case 'u': + if (!strcasecmp (atom + 1, "nset")) + return UNSET; + if (!strcasecmp (atom + 1, "nsigned")) + return UNSIGNED; + if (!strcasecmp (atom + 1, "id")) + return UID; if (!strncasecmp (atom + 1, "se", 2)) { if (!strcasecmp (atom + 3, "r-class")) return USER_CLASS; @@ -544,18 +1037,43 @@ static int intern (atom, dfv) return USE_LEASE_ADDR_FOR_DEFAULT_ROUTE; break; } - if (!strcasecmp (atom + 1, "id")) - return UID; - if (!strcasecmp (atom + 1, "nknown-clients")) - return UNKNOWN_CLIENTS; + if (!strncasecmp (atom + 1, "nknown", 6)) { + if (!strcasecmp (atom + 7, "-clients")) + return UNKNOWN_CLIENTS; + if (!strcasecmp (atom + 7, "-state")) + return UNKNOWN_STATE; + if (!atom [7]) + return UNKNOWN; + break; + } + if (!strcasecmp (atom + 1, "nauthenticated")) + return AUTHENTICATED; + if (!strcasecmp (atom + 1, "pdated-dns-rr")) + return UPDATED_DNS_RR; + if (!strcasecmp (atom + 1, "pdate")) + return UPDATE; break; case 'v': if (!strcasecmp (atom + 1, "endor-class")) return VENDOR_CLASS; + if (!strcasecmp (atom + 1, "endor")) + return VENDOR; + break; + case 'w': + if (!strcasecmp (atom + 1, "ith")) + return WITH; break; case 'y': if (!strcasecmp (atom + 1, "iaddr")) return YIADDR; + if (!strcasecmp (atom + 1, "xdomain")) + return NS_YXDOMAIN; + if (!strcasecmp (atom + 1, "xrrset")) + return NS_YXRRSET; + break; + case 'z': + if (!strcasecmp (atom + 1, "one")) + return ZONE; break; } return dfv; diff --git a/contrib/isc-dhcp/common/ctrace.c b/contrib/isc-dhcp/common/ctrace.c new file mode 100644 index 0000000..bea933c --- /dev/null +++ b/contrib/isc-dhcp/common/ctrace.c @@ -0,0 +1,297 @@ +/* trace.c + + Subroutines that support dhcp tracing... */ + +/* + * Copyright (c) 2001 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon, as part of a project for Nominum, Inc. To learn more + * about the Internet Software Consortium, see http://www.isc.org/. To + * learn more about Nominum, Inc., see ``http://www.nominum.com''. + */ + +#include "dhcpd.h" + +#if defined (TRACING) +void trace_interface_register (trace_type_t *ttype, struct interface_info *ip) +{ + trace_interface_packet_t tipkt; + + if (trace_record ()) { + memset (&tipkt, 0, sizeof tipkt); + memcpy (&tipkt.hw_address, + &ip -> hw_address, sizeof ip -> hw_address); + memcpy (&tipkt.primary_address, + &ip -> primary_address, sizeof ip -> primary_address); + memcpy (tipkt.name, ip -> name, sizeof ip -> name); + tipkt.index = htonl (ip -> index); + + trace_write_packet (ttype, sizeof tipkt, (char *)&tipkt, MDL); + } +} + +void trace_interface_input (trace_type_t *ttype, unsigned len, char *buf) +{ + trace_interface_packet_t *tipkt; + struct interface_info *ip; + struct sockaddr_in *sin; + struct iaddr addr; + isc_result_t status; + + if (len != sizeof *tipkt) { + log_error ("trace interface packet size mismatch: %ld != %d", + (long)(sizeof *tipkt), len); + return; + } + tipkt = (trace_interface_packet_t *)buf; + + ip = (struct interface_info *)0; + status = interface_allocate (&ip, MDL); + if (status != ISC_R_SUCCESS) { + foo: + log_error ("trace_interface_input: %s.", + isc_result_totext (status)); + return; + } + ip -> ifp = dmalloc (sizeof *(ip -> ifp), MDL); + if (!ip -> ifp) { + interface_dereference (&ip, MDL); + status = ISC_R_NOMEMORY; + goto foo; + } + + memcpy (&ip -> hw_address, &tipkt -> hw_address, + sizeof ip -> hw_address); + memcpy (&ip -> primary_address, &tipkt -> primary_address, + sizeof ip -> primary_address); + memcpy (ip -> name, tipkt -> name, sizeof ip -> name); + ip -> index = ntohl (tipkt -> index); + + interface_snorf (ip, 0); + if (dhcp_interface_discovery_hook) + (*dhcp_interface_discovery_hook) (ip); + + /* Fake up an ifp. */ + memcpy (ip -> ifp -> ifr_name, ip -> name, sizeof ip -> name); +#ifdef HAVE_SA_LEN + ip -> ifp -> ifr_addr.sa_len = sizeof (struct sockaddr_in); +#endif + sin = (struct sockaddr_in *)&ip -> ifp -> ifr_addr; + sin -> sin_addr = ip -> primary_address; + + addr.len = 4; + memcpy (addr.iabuf, &sin -> sin_addr.s_addr, addr.len); + if (dhcp_interface_setup_hook) + (*dhcp_interface_setup_hook) (ip, &addr); + interface_stash (ip); + + if (!quiet_interface_discovery) { + log_info ("Listening on Trace/%s/%s%s%s", + ip -> name, + print_hw_addr (ip -> hw_address.hbuf [0], + ip -> hw_address.hlen - 1, + &ip -> hw_address.hbuf [1]), + (ip -> shared_network ? "/" : ""), + (ip -> shared_network ? + ip -> shared_network -> name : "")); + if (strcmp (ip -> name, "fallback")) { + log_info ("Sending on Trace/%s/%s%s%s", + ip -> name, + print_hw_addr (ip -> hw_address.hbuf [0], + ip -> hw_address.hlen - 1, + &ip -> hw_address.hbuf [1]), + (ip -> shared_network ? "/" : ""), + (ip -> shared_network ? + ip -> shared_network -> name : "")); + } + } + interface_dereference (&ip, MDL); +} + +void trace_interface_stop (trace_type_t *ttype) { + /* XXX */ +} + +void trace_inpacket_stash (struct interface_info *interface, + struct dhcp_packet *packet, + unsigned len, + unsigned int from_port, + struct iaddr from, + struct hardware *hfrom) +{ + trace_inpacket_t tip; + trace_iov_t iov [2]; + + if (!trace_record ()) + return; + tip.from_port = from_port; + tip.from = from; + if (hfrom) { + tip.hfrom = *hfrom; + tip.havehfrom = 1; + } else { + memset (&tip.hfrom, 0, sizeof tip.hfrom); + tip.havehfrom = 0; + } + tip.index = htonl (interface -> index); + + iov [0].buf = (char *)&tip; + iov [0].len = sizeof tip; + iov [1].buf = (char *)packet; + iov [1].len = len; + trace_write_packet_iov (inpacket_trace, 2, iov, MDL); +} + +void trace_inpacket_input (trace_type_t *ttype, unsigned len, char *buf) +{ + trace_inpacket_t *tip; + int index; + + if (len < sizeof *tip) { + log_error ("trace_input_packet: too short - %d", len); + return; + } + tip = (trace_inpacket_t *)buf; + index = ntohl (tip -> index); + + if (index > interface_count || + index < 0 || + !interface_vector [index]) { + log_error ("trace_input_packet: unknown interface index %d", + index); + return; + } + + if (!bootp_packet_handler) { + log_error ("trace_input_packet: no bootp packet handler."); + return; + } + + (*bootp_packet_handler) (interface_vector [index], + (struct dhcp_packet *)(tip + 1), + len - sizeof *tip, + tip -> from_port, + tip -> from, + (tip -> havehfrom ? + &tip -> hfrom + : (struct hardware *)0)); +} + +void trace_inpacket_stop (trace_type_t *ttype) { } + +ssize_t trace_packet_send (struct interface_info *interface, + struct packet *packet, + struct dhcp_packet *raw, + size_t len, + struct in_addr from, + struct sockaddr_in *to, + struct hardware *hto) +{ + trace_outpacket_t tip; + trace_iov_t iov [2]; + + if (trace_record ()) { + if (hto) { + tip.hto = *hto; + tip.havehto = 1; + } else { + memset (&tip.hto, 0, sizeof tip.hto); + tip.havehto = 0; + } + tip.from.len = 4; + memcpy (tip.from.iabuf, &from, 4); + tip.to.len = 4; + memcpy (tip.to.iabuf, &to -> sin_addr, 4); + tip.to_port = to -> sin_port; + tip.index = htonl (interface -> index); + + iov [0].buf = (char *)&tip; + iov [0].len = sizeof tip; + iov [1].buf = (char *)raw; + iov [1].len = len; + trace_write_packet_iov (outpacket_trace, 2, iov, MDL); + } + if (!trace_playback ()) { + return send_packet (interface, packet, raw, len, + from, to, hto); + } + return len; +} + +void trace_outpacket_input (trace_type_t *ttype, unsigned len, char *buf) +{ + trace_outpacket_t *tip; + int index; + + if (len < sizeof *tip) { + log_error ("trace_input_packet: too short - %d", len); + return; + } + tip = (trace_outpacket_t *)buf; + index = ntohl (tip -> index); + + if (index > interface_count || + index < 0 || + !interface_vector [index]) { + log_error ("trace_input_packet: unknown interface index %d", + index); + return; + } + + /* XXX would be nice to somehow take notice of these. */ +} + +void trace_outpacket_stop (trace_type_t *ttype) { } + +void trace_seed_stash (trace_type_t *ttype, unsigned seed) +{ + u_int32_t outseed; + if (!trace_record ()) + return; + outseed = htonl (seed); + trace_write_packet (ttype, sizeof outseed, (char *)&outseed, MDL); + return; +} + +void trace_seed_input (trace_type_t *ttype, unsigned length, char *buf) +{ + u_int32_t *seed; + + if (length != sizeof seed) { + log_error ("trace_seed_input: wrong size (%d)", length); + } + seed = (u_int32_t *)buf; + srandom (ntohl (*seed)); +} + +void trace_seed_stop (trace_type_t *ttype) { } +#endif /* TRACING */ diff --git a/contrib/isc-dhcp/common/dhcp-eval.5 b/contrib/isc-dhcp/common/dhcp-eval.5 new file mode 100644 index 0000000..cbb7745 --- /dev/null +++ b/contrib/isc-dhcp/common/dhcp-eval.5 @@ -0,0 +1,484 @@ +.\" dhcp-eval.5 +.\" +.\" Copyright (c) 1996-2001 Internet Software Consortium. +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of The Internet Software Consortium nor the names +.\" of its contributors may be used to endorse or promote products derived +.\" from this software without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND +.\" CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, +.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +.\" DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR +.\" CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +.\" USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +.\" ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" This software has been written for the Internet Software Consortium +.\" by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. +.\" To learn more about the Internet Software Consortium, see +.\" ``http://www.isc.org/''. To learn more about Vixie Enterprises, +.\" see ``http://www.vix.com''. To learn more about Nominum, Inc., see +.\" ``http://www.nominum.com''. +.TH dhcp-eval 5 +.SH NAME +dhcp-eval - ISC DHCP conditional evaluation +.SH DESCRIPTION +The Internet Software Consortium DHCP client and server both provide +the ability to perform conditional behavior depending on the contents +of packets they receive. The syntax for specifying this conditional +behaviour is documented here. +.SH REFERENCE: CONDITIONAL BEHAVIOUR +Conditional behaviour is specified using the if statement and the else +or elsif statements. A conditional statement can appear anywhere +that a regular statement (e.g., an option statement) can appear, and +can enclose one or more such statements. A typical conditional +statement in a server might be: +.PP +.nf +if option dhcp-user-class = "accounting" { + max-lease-time 17600; + option domain-name "accounting.example.org"; + option domain-name-servers ns1.accounting.example.org, + ns2.accounting.example.org; +} elsif option dhcp-user-class = "sales" { + max-lease-time 17600; + option domain-name "sales.example.org"; + option domain-name-servers ns1.sales.example.org, + ns2.sales.example.org; +} elsif option dhcp-user-class = "engineering" { + max-lease-time 17600; + option domain-name "engineering.example.org"; + option domain-name-servers ns1.engineering.example.org, + ns2.engineering.example.org; +} else { + max-lease-time 600; + option domain-name "misc.example.org"; + option domain-name-servers ns1.misc.example.org, + ns2.misc.example.org; +} +.fi +.PP +On the client side, an example of conditional evaluation might be: +.PP +.nf +# example.org filters DNS at its firewall, so we have to use their DNS +# servers when we connect to their network. If we are not at +# example.org, prefer our own DNS server. +if not option domain-name = "example.org" { + prepend domain-name-servers 127.0.0.1; +} +.fi +.PP +The +.B if +statement and the +.B elsif +continuation statement both take boolean expressions as their +arguments. That is, they take expressions that, when evaluated, +produce a boolean result. If the expression evaluates to true, then +the statements enclosed in braces following the +.B if +statement are executed, and all subsequent +.B elsif +and +.B else +clauses are skipped. Otherwise, each subsequent +.B elsif +clause's expression is checked, until an elsif clause is encountered +whose test evaluates to true. If such a clause is found, the +statements in braces following it are executed, and then any +subsequent +.B elsif +and +.B else +clauses are skipped. If all the +.B if +and +.B elsif +clauses are checked but none +of their expressions evaluate true, then if there is an +.B else +clause, the statements enclosed in braces following the +.B else +are evaluated. Boolean expressions that evaluate to null are +treated as false in conditionals. +.SH BOOLEAN EXPRESSIONS +The following is the current list of boolean expressions that are +supported by the DHCP distribution. +.PP +.I data-expression-1 \fB=\fI data-expression-2\fR +.RS 0.25i +.PP +The \fB=\fR operator compares the values of two data expressions, +returning true if they are the same, false if they are not. If +either the left-hand side or the right-hand side are null, the +result is also null. +.RE +.PP +.I boolean-expression-1 \fBand\fI boolean-expression-2\fR +.PP +.RS 0.25i +The \fBand\fR operator evaluates to true if the boolean expression on +the left-hand side and the boolean expression on the right-hand side +both evaluate to true. Otherwise, it evaluates to false. If either +the expression on the left-hand side or the expression on the +right-hand side are null, the result is null. +.RE +.PP +.I boolean-expression-1 \fBor\fI boolean-expression-2\fR +.PP +.RS 0.25i +The \fBor\fR operator evaluates to true if either the boolean +expression on the left-hand side or the boolean expression on the +right-hand side evaluate to true. Otherwise, it evaluates to false. +If either the expression on the left-hand side or the expression on +the right-hand side are null, the result is null. +.RE +.PP +.B not \fIboolean-expression +.PP +.RS 0.25i +The \fBnot\fR operator evaluates to true if \fIboolean-expression\fR +evaluates to false, and returns false if \fIboolean-expression\fR evaluates +to true. If \fIboolean-expression\fR evaluates to null, the result +is also null. +.RE +.PP +.B exists \fIoption-name\fR +.PP +.RS 0.25i +The \fBexists\fR expression returns true if the specified option +exists in the incoming DHCP packet being processed. +.RE +.B known +.PP +.RS 0.25i +The \fBknown\fR expression returns true if the client whose request is +currently being processed is known - that is, if there's a host +declaration for it. +.RE +.B static +.PP +.RS 0.25i +The \fBstatic\fR expression returns true if the lease assigned to the +client whose request is currently being processed is derived from a static +address assignment. +.RE +.SH DATA EXPRESSIONS +Several of the boolean expressions above depend on the results of +evaluating data expressions. A list of these expressions is provided +here. +.PP +.B substring (\fIdata-expr\fB, \fIoffset\fB, \fIlength\fB)\fR +.PP +.RS 0.25i +The \fBsubstring\fR operator evaluates the data expression and returns +the substring of the result of that evaluation that starts +\fIoffset\fR bytes from the beginning, continuing for \fIlength\fR +bytes. \fIOffset\fR and \fIlength\fR are both numeric expressions. +If \fIdata-expr\fR, \fIoffset\fR or \fIlength\fR evaluate to null, +then the result is also null. If \fIoffset\fR is greater than or +equal to the length of the evaluated data, then a zero-length data +string is returned. If \fIlength\fI is greater then the remaining +length of the evaluated data after \fIoffset\fR, then a data string +containing all data from \fIoffset\fR to the end of the evaluated data +is returned. +.RE +.PP +.B suffix (\fIdata-expr\fB, \fIlength\fB)\fR +.PP +.RS 0.25i +The \fBsuffix\fR operator evaluates \fIdata-expr\fR and returns the +last \fIlength\fR bytes of the result of that evaluation. \fILength\fR +is a numeric expression. If \fIdata-expr\fR or \fIlength\fR evaluate +to null, then the result is also null. If \fIsuffix\fR evaluates to a +number greater than the length of the evaluated data, then the +evaluated data is returned. +.RE +.PP +.B option \fIoption-name\fR +.PP +.RS 0.25i +The \fBoption\fR operator returns the contents of the specified option in +the packet to which the server is responding. +.RE +.PP +.B config-option \fIoption-name\fR +.PP +.RS 0.25i +The \fBconfig-option\fR operator returns the value for the specified option +that the DHCP client or server has been configured to send. +.RE +.PP +.B hardware +.PP +.RS 0.25i +The \fBhardware\fR operator returns a data string whose first element +is the type of network interface indicated in packet being considered, +and whose subsequent elements are client's link-layer address. If +there is no packet, or if the RFC2131 \fIhlen\fR field is invalid, +then the result is null. Hardware types include ethernet (1), +token-ring (6), and fddi (8). Hardware types are specified by the +IETF, and details on how the type numbers are defined can be found in +RFC2131 (in the ISC DHCP distribution, this is included in the doc/ +subdirectory). +.RE +.PP +.B packet (\fIoffset\fB, \fIlength\fB)\fR +.PP +.RS 0.25i +The \fBpacket\fR operator returns the specified portion of the packet +being considered, or null in contexts where no packet is being +considered. \fIOffset\fR and \fIlength\fR are applied to the +contents packet as in the \fBsubstring\fR operator. +.RE +.PP +.I string +.PP +.RS 0.25i +A string, enclosed in quotes, may be specified as a data expression, +and returns the text between the quotes, encoded in ASCII. The +backslash ('\\') character is treated specially, as in C programming: +'\\t' means TAB, '\\r' means carriage return, '\\n' means newline, and +'\\b' means bell. Any octal value can be specified with '\\nnn', +where nnn is any positive octal number less than 0400. Any +hexadecimal value can be specified with '\xnn', where nn is any +positive hexadecimal number less than 0xff. +.RE +.PP +.I colon-seperated hexadecimal list +.PP +.RS 0.25i +A list of hexadecimal octet values, seperated by colons, may be +specified as a data expression. +.RE +.PP +.B concat (\fIdata-expr1\fB, ..., \fIdata-exprN\fB)\fR +.RS 0.25i +The expressions are evaluated, and the results of each evaluation are +concatenated in the sequence that the subexpressions are listed. If +any subexpression evaluates to null, the result of the concatenation +is null. +.RE +.PP +.B reverse (\fInumeric-expr1\fB, \fIdata-expr2\fB)\fR +.RS 0.25i +The two expressions are evaluated, and then the result of evaluating +the data expression is reversed in place, using hunks of the size +specified in the numeric expression. For example, if the numeric +expression evaluates to four, and the data expression evaluates to +twelve bytes of data, then the reverse expression will evaluate to +twelve bytes of data, consisting of the last four bytes of the the +input data, followed by the middle four bytes, followed by the first +four bytes. +.RE +.PP +.B leased-address +.RS 0.25i +In any context where the client whose request is being processed has +been assigned an IP address, this data expression returns that IP +address. +.RE +.PP +.B binary-to-ascii (\fInumeric-expr1\fB, \fInumeric-expr2\fB, +.B \fIdata-expr1\fB,\fR \fIdata-expr2\fB)\fR +.RS 0.25i +Converts the result of evaluating data-expr2 into a text string +containing one number for each element of the result of evaluating +data-expr2. Each number is seperated from the other by the result of +evaluating data-expr1. The result of evaluating numeric-expr1 +specifies the base (2 through 16) into which the numbers should be +converted. The result of evaluating numeric-expr2 specifies the +width in bits of each number, which may be either 8, 16 or 32. +.PP +As an example of the preceding three types of expressions, to produce +the name of a PTR record for the IP address being assigned to a +client, one could write the following expression: +.RE +.PP +.nf + concat (binary-to-ascii (10, 8, ".", + reverse (1, leased-address)), + ".in-addr.arpa."); + +.fi +.PP +.B encode-int (\fInumeric-expr\fB, \fIwidth\fB)\fR +.RS 0.25i +Numeric-expr is evaluated and encoded as a data string of the +specified width, in network byte order (most significant byte first). +If the numeric expression evaluates to the null value, the result is +also null. +.PP +.B pick-first-value (\fIdata-expr1\fR [ ... \fIexpr\fRn ] \fB)\fR +.RS 0.25i +The pick-first-value function takes any number of data expressions as +its arguments. Each expression is evaluated, starting with the first +in the list, until an expression is found that does not evaluate to a +null value. That expression is returned, and none of the subsequent +expressions are evaluated. If all expressions evaluate to a null +value, the null value is returned. +.RE +.PP +.B host-decl-name +.RS 0.25i +The host-decl-name function returns the name of the host declaration +that matched the client whose request is currently being processed, if +any. If no host declaration matched, the result is the null value. +.RE +.SH NUMERIC EXPRESSIONS +Numeric expressions are expressions that evaluate to an integer. In +general, the maximum size of such an integer should not be assumed to +be representable in fewer than 32 bits, but the precision of such +integers may be more than 32 bits. +.PP +.B extract-int (\fIdata-expr\fB, \fIwidth\fB)\fR +.PP +.RS 0.25i +The \fBextract-int\fR operator extracts an integer value in network +byte order from the result of evaluating the specified data +expression. Width is the width in bits of the integer to extract. +Currently, the only supported widths are 8, 16 and 32. If the +evaluation of the data expression doesn't provide sufficient bits to +extract an integer of the specified size, the null value is returned. +.RE +.PP +.B lease-time +.PP +.RS 0.25i +The duration of the current lease - that is, the difference between +the current time and the time that the lease expires. +.RE +.PP +.I number +.PP +.RS 0.25i +Any number between zero and the maximum representable size may be +specified as a numeric expression. +.RE +.PP +.B client-state +.PP +.RS 0.25i +The current state of the client instance being processed. This is +only useful in DHCP client configuration files. Possible values are: +.TP 2 +.I \(bu +Booting - DHCP client is in the INIT state, and does not yet have an +IP address. The next message transmitted will be a DHCPDISCOVER, +which will be broadcast. +.TP +.I \(bu +Reboot - DHCP client is in the INIT-REBOOT state. It has an IP +address, but is not yet using it. The next message to be transmitted +will be a DHCPREQUEST, which will be broadcast. If no response is +heard, the client will bind to its address and move to the BOUND state. +.TP +.I \(bu +Select - DHCP client is in the SELECTING state - it has received at +least one DHCPOFFER message, but is waiting to see if it may receive +other DHCPOFFER messages from other servers. No messages are sent in +the SELECTING state. +.TP +.I \(bu +Request - DHCP client is in the REQUESTING state - it has received at +least one DHCPOFFER message, and has chosen which one it will +request. The next message to be sent will be a DHCPREQUEST message, +which will be broadcast. +.TP +.I \(bu +Bound - DHCP client is in the BOUND state - it has an IP address. No +messages are transmitted in this state. +.TP +.I \(bu +Renew - DHCP client is in the RENEWING state - it has an IP address, +and is trying to contact the server to renew it. The next message to +be sent will be a DHCPREQUEST message, which will be unicast directly +to the server. +.TP +.I \(bu +Rebind - DHCP client is in the REBINDING state - it has an IP address, +and is trying to contact any server to renew it. The next message to +be sent will be a DHCPREQUEST, which will be broadcast. +.RE +.SH REFERENCE: LOGGING +Logging statements may be used to send information to the standard logging +channels. A logging statement includes an optional priority (\fBfatal\fR, +\fBerror\fR, \fBinfo\fR, or \fBdebug\fR), and a data expression. +.PP +.B log (\fIpriority\fB, \fIdata-expr\FB)\fR +.PP +Logging statements take only a single data expression argument, so if you +want to output multiple data values, you will need to use the \fBconcat\fR +operator to concatenate them. +.RE +.SH REFERENCE: DYNAMIC DNS UPDATES +.PP +The DHCP client and server have the ability to dynamically update the +Domain Name System. Within the configuration files, you can define +how you want the Domain Name System to be updated. These updates are +RFC 2136 compliant so any DNS server supporting RFC 2136 should be +able to accept updates from the DHCP server. +.SH SECURITY +Support for TSIG and DNSSEC is not yet available. When you set your +DNS server up to allow updates from the DHCP server or client, you may +be exposing it to unauthorized updates. To avoid this, the best you +can do right now is to use IP address-based packet filtering to +prevent unauthorized hosts from submitting update requests. +Obviously, there is currently no way to provide security for client +updates - this will require TSIG or DNSSEC, neither of which is yet +available in the DHCP distribution. +.PP +Dynamic DNS (DDNS) updates are performed by using the \fBdns-update\fR +expression. The \fBdns-update\fR expression is a boolean expression +that takes four parameters. If the update succeeds, the result is +true. If it fails, the result is false. The four parameters that the +are the resource record type (RR), the left hand side of the RR, the +right hand side of the RR and the ttl that should be applied to the +record. The simplest example of the use of the function can be found +in the reference section of the dhcpd.conf file, where events are +described. In this example several statements are being used to make +the arguments to the \fBdns-update\f\R. +.PP +In the example, the first argument to the first \f\Bdns-update\fR +expression is a data expression that evaluates to the A RR type. The +second argument is constructed by concatenating the DHCP host-name +option with a text string containing the local domain, in this case +"ssd.example.net". The third argument is constructed by converting +the address the client has been assigned from a 32-bit number into an +ascii string with each byte separated by a ".". The fourth argument, +the TTL, specifies the amount of time remaining in the lease (note +that this isn't really correct, since the DNS server will pass this +TTL out whenever a request comes in, even if that is only a few +seconds before the lease expires). +.PP +If the first \fBdns-update\fR statement succeeds, it is followed up +with a second update to install a PTR RR. The installation of a PTR +record is similar to installing an A RR except that the left hand side +of the record is the leased address, reversed, with ".in-addr.arpa" +concatenated. The right hand side is the fully qualified domain name +of the client to which the address is being leased. +.SH SEE ALSO +dhcpd.conf(5), dhcpd.leases(5), dhclient.conf(5), dhcp-eval(5), dhcpd(8), +dhclient(8), RFC2132, RFC2131. +.SH AUTHOR +The Internet Software Consortium DHCP Distribution was written by Ted +Lemon under a contract with Vixie Labs. Funding for +this project was provided through the Internet Software Consortium. +Information about the Internet Software Consortium can be found at +.B http://www.isc.org. diff --git a/contrib/isc-dhcp/common/dhcp-options.5 b/contrib/isc-dhcp/common/dhcp-options.5 index 5e7ca00..6f5d6f7 100644 --- a/contrib/isc-dhcp/common/dhcp-options.5 +++ b/contrib/isc-dhcp/common/dhcp-options.5 @@ -1,8 +1,6 @@ .\" dhcp-options.5 .\" -.\" Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium. -.\" All rights reserved. -.\" +.\" Copyright (c) 1996-2001 Internet Software Consortium. .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: @@ -31,10 +29,11 @@ .\" SUCH DAMAGE. .\" .\" This software has been written for the Internet Software Consortium -.\" by Ted Lemon <mellon@fugue.com> in cooperation with Vixie -.\" Enterprises. To learn more about the Internet Software Consortium, -.\" see ``http://www.isc.org/isc''. To learn more about Vixie -.\" Enterprises, see ``http://www.vix.com''. +.\" by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. +.\" To learn more about the Internet Software Consortium, see +.\" ``http://www.isc.org/''. To learn more about Vixie Enterprises, +.\" see ``http://www.vix.com''. To learn more about Nominum, Inc., see +.\" ``http://www.nominum.com''. .TH dhcpd-options 5 .SH NAME dhcp-options - Dynamic Host Configuration Protocol options @@ -82,94 +81,310 @@ data types specify signed and unsigned 8-bit integers. Unsigned 8-bit integers are also sometimes referred to as octets. .PP The -.B string +.B text data type specifies an NVT ASCII string, which must be -enclosed in double quotes - for example, to specify a domain-name +enclosed in double quotes - for example, to specify a root-path option, the syntax would be .nf .sp 1 - option domain-name "isc.org"; +option root-path "10.0.1.4:/var/tmp/rootfs"; .fi .PP The +.B domain-name +data type specifies a domain name, which must not +enclosed in double quotes. This data type is not used for any +existing DHCP options. The domain name is stored just as if it were +a text option. +.PP +The .B flag data type specifies a boolean value. Booleans can be either true or false (or on or off, if that makes more sense to you). .PP The -.B data-string +.B string data type specifies either an NVT ASCII string enclosed in double quotes, or a series of octets specified in hexadecimal, seperated by colons. For example: .nf .sp 1 - option dhcp-client-identifier "CLIENT-FOO"; + option dhcp-client-identifier "CLIENT-FOO"; or - option dhcp-client-identifier 43:4c:49:45:54:2d:46:4f:4f; + option dhcp-client-identifier 43:4c:49:45:54:2d:46:4f:4f; +.fi +.SH SETTING OPTION VALUES USING EXPRESSIONS +Sometimes it's helpful to be able to set the value of a DHCP option +based on some value that the client has sent. To do this, you can +use expression evaluation. The +.B dhcp-eval(5) +manual page describes how to write expressions. To assign the result +of an evaluation to an option, define the option as follows: +.nf +.sp 1 + \fBoption \fImy-option \fB= \fIexpression \fB;\fR .fi .PP +For example: +.nf +.sp 1 + option hostname = binary-to-ascii (16, 8, "-", + substring (hardware, 1, 6)); +.fi +.SH STANDARD DHCP OPTIONS The documentation for the various options mentioned below is taken -from the latest IETF draft document on DHCP options. Options which -are not listed by name may be defined by the name option-\fInnn\fR, -where \fInnn\fI is the decimal number of the option code. These -options may be followed either by a string, enclosed in quotes, or by -a series of octets, expressed as two-digit hexadecimal numbers seperated -by colons. For example: +from the latest IETF draft document on DHCP options. Options not +listed below may not yet be implemented, but it is possible to use +such options by defining them in the configuration file. Please see +the DEFINING NEW OPTIONS heading later in this document for more +information. +.PP +Some of the options documented here are automatically generated by +the DHCP server or by clients, and cannot be configured by the user. +The value of such an option can be used in the configuration file of +the receiving DHCP protocol agent (server or client), for example in +conditional expressions. However, the value of the option cannot be +used in the configuration file of the sending agent, because the value +is determined only \fIafter\fR the configuration file has been +processed. In the following documentation, such options will be shown +as "not user configurable" +.PP +The standard options are: +.PP +.B option \fBall-subnets-local\fR \fIflag\fR\fB;\fR +.RS 0.25i +.PP +This option specifies whether or not the client may assume that all +subnets of the IP network to which the client is connected use the +same MTU as the subnet of that network to which the client is +directly connected. A value of true indicates that all subnets share +the same MTU. A value of false means that the client should assume that +some subnets of the directly connected network may have smaller MTUs. +.RE +.PP +.B option \fBarp-cache-timeout\fR \fIuint32\fR\fB;\fR +.RS 0.25i +.PP +This option specifies the timeout in seconds for ARP cache entries. +.RE +.PP +.B option \fBbootfile-name\fR \fItext\fR\fB;\fR +.RS 0.25i +.PP +This option is used to identify a bootstrap file. If supported by the +client, it should have the same effect as the \fBfilename\fR +declaration. BOOTP clients are unlikely to support this option. Some +DHCP clients will support it, and others actually require it. +.RE +.PP +.B option \fBboot-size\fR \fIuint16\fR\fB;\fR +.RS 0.25i +.PP +This option specifies the length in 512-octet blocks of the default +boot image for the client. +.RE +.PP +.B option \fBbroadcast-address\fR \fIip-address\fR\fB;\fR +.RS 0.25i +.PP +This option specifies the broadcast address in use on the client's +subnet. Legal values for broadcast addresses are specified in +section 3.2.1.3 of STD 3 (RFC1122). +.RE +.PP +.B option \fBcookie-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... +]\fB;\fR +.RS 0.25i +.PP +The cookie server option specifies a list of RFC 865 cookie +servers available to the client. Servers should be listed in order +of preference. +.RE +.PP +.B option \fBdefault-ip-ttl\fR \fIuint8;\fR +.RS 0.25i .PP +This option specifies the default time-to-live that the client should +use on outgoing datagrams. +.RE +.PP +.B option \fBdefault-tcp-ttl\fR \fIuint8\fR\fB;\fR +.RS 0.25i +.PP +This option specifies the default TTL that the client should use when +sending TCP segments. The minimum value is 1. +.RE +.PP +.B option \fBdhcp-client-identifier\fR \fIstring\fR\fB;\fR +.RS 0.25i +.PP +This option can be used to specify the a DHCP client identifier in a +host declaration, so that dhcpd can find the host record by matching +against the client identifier. +.PP +Please be aware that some DHCP clients, when configured with client +identifiers that are ASCII text, will prepend a zero to the ASCII +text. So you may need to write: .nf - option option-133 "my-option-133-text"; - option option-129 1:54:c9:2b:47; + + option dhcp-client-identifier "\\0foo"; + +rather than: + + option dhcp-client-identifier "foo"; .fi +.RE .PP -Because dhcpd does not know the format of these undefined option codes, -no checking is done to ensure the correctness of the entered data. +.B option \fBdhcp-lease-time\fR \fIuint32\fR\fB;\fR +.RS 0.25i .PP -The standard options are: +This option is used in a client request (DHCPDISCOVER or DHCPREQUEST) +to allow the client to request a lease time for the IP address. In a +server reply (DHCPOFFER), a DHCP server uses this option to specify +the lease time it is willing to offer. .PP -.B option subnet-mask \fIip-address\fR\fB;\fR +This option is not directly user configurable in the server; refer to the +\fImax-lease-time\fR and \fidefault-lease-time\fR server options in +.B dhcpd.conf(5). +.RE +.PP +.B option \fBdhcp-max-message-size\fR \fIuint16\fR\fB;\fR .RS 0.25i .PP -The subnet mask option specifies the client's subnet mask as per RFC -950. If no subnet mask option is provided anywhere in scope, as a -last resort dhcpd will use the subnet mask from the subnet declaration -for the network on which an address is being assigned. However, -.I any -subnet-mask option declaration that is in scope for the address being -assigned will override the subnet mask specified in the subnet -declaration. +This option, when sent by the client, specifies the maximum size of +any response that the server sends to the client. When specified on +the server, if the client did not send a dhcp-max-message-size option, +the size specified on the server is used. This works for BOOTP as +well as DHCP responses. .RE .PP -.B option time-offset \fIint32\fR\fB;\fR +.B option \fBdhcp-message\fR \fItext\fR\fB;\fR .RS 0.25i .PP -The time-offset option specifies the offset of the client's subnet in -seconds from Coordinated Universal Time (UTC). +This option is used by a DHCP server to provide an error message to a +DHCP client in a DHCPNAK message in the event of a failure. A client +may use this option in a DHCPDECLINE message to indicate why the +client declined the offered parameters. +.PP +This option is not user configurable. .RE .PP -.B option routers \fIip-address\fR [\fB,\fR \fIip-address\fR... -]\fB;\fR +.B option \fBdhcp-message-type\fR \fIuint8\fR\fB;\fR .RS 0.25i .PP -The routers option specifies a list of IP addresses for routers on the -client's subnet. Routers should be listed in order of preference. +This option, sent by both client and server, specifies the type of DHCP +message contained in the DHCP packet. Possible values (taken directly from +RFC2132) are: +.PP +.nf + 1 DHCPDISCOVER + 2 DHCPOFFER + 3 DHCPREQUEST + 4 DHCPDECLINE + 5 DHCPACK + 6 DHCPNAK + 7 DHCPRELEASE + 8 DHCPINFORM +.fi +.PP +This option is not user configurable. +.PP .RE +.B option \fBdhcp-option-overload\fR \fIuint8\fR\fB;\fR +.RS 0.25i .PP -.B option time-servers \fIip-address\fR [, \fIip-address\fR... -]\fB;\fR +This option is used to indicate that the DHCP 'sname' or 'file' +fields are being overloaded by using them to carry DHCP options. A +DHCP server inserts this option if the returned parameters will +exceed the usual space allotted for options. +.PP +If this option is present, the client interprets the specified +additional fields after it concludes interpretation of the standard +option fields. +.PP +Legal values for this option are: +.PP +.nf + 1 the 'file' field is used to hold options + 2 the 'sname' field is used to hold options + 3 both fields are used to hold options +.fi +.PP +This option is not user configurable. +.PP +.RE +.PP +.B option \fBdhcp-parameter-request-list\fR \fIuint16\fR\fB;\fR .RS 0.25i .PP -The time-server option specifies a list of RFC 868 time servers -available to the client. Servers should be listed in order of -preference. +This option, when sent by the client, specifies which options the +client wishes the server to return. Normally, in the ISC DHCP +client, this is done using the \fIrequest\fR statement. If this +option is not specified by the client, the DHCP server will normally +return every option that is valid in scope and that fits into the +reply. When this option is specified on the server, the server +returns the specified options. This can be used to force a client to +take options that it hasn't requested, and it can also be used to +tailor the response of the DHCP server for clients that may need a +more limited set of options than those the server would normally +return. .RE .PP -.B option \fBien116-name-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... -]; +.B option \fBdhcp-rebinding-time\fR \fIuint32\fR\fB;\fR .RS 0.25i .PP -The ien116-name-servers option specifies a list of IEN 116 name servers -available to the client. Servers should be listed in order of -preference. +This option specifies the number of seconds from the time a client gets +an address until the client transitions to the REBINDING state. +.PP +This option is not user configurable. +.PP +.RE +.PP +.B option \fBdhcp-renewal-time\fR \fIuint32\fR\fB;\fR +.RS 0.25i +.PP +This option specifies the number of seconds from the time a client gets +an address until the client transitions to the RENEWING state. +.PP +This option is not user configurable. +.PP +.RE +.PP +.B option \fBdhcp-requested-address\fR \fIip-address\fR\fB;\fR +.RS 0.25i +.PP +This option is used by the client in a DHCPDISCOVER to +request that a particular IP address be assigned. +.PP +This option is not user configurable. +.PP +.RE +.PP +.B option \fBdhcp-server-identifier\fR \fIip-address\fR\fB;\fR +.RS 0.25i +.PP +This option is used in DHCPOFFER and DHCPREQUEST messages, and may +optionally be included in the DHCPACK and DHCPNAK messages. DHCP +servers include this option in the DHCPOFFER in order to allow the +client to distinguish between lease offers. DHCP clients use the +contents of the 'server identifier' field as the destination address +for any DHCP messages unicast to the DHCP server. DHCP clients also +indicate which of several lease offers is being accepted by including +this option in a DHCPREQUEST message. +.PP +The value of this option is the IP address of the server. +.PP +This option is not directly user configurable. See the +\fIserver-identifier\fR server option in +.B \fIdhcpd.conf(5). +.PP +.RE +.PP +.B option \fBdomain-name\fR \fItext\fR\fB;\fR +.RS 0.25i +.PP +This option specifies the domain name that client should use when +resolving hostnames via the Domain Name System. .RE .PP .B option \fBdomain-name-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... @@ -181,68 +396,126 @@ The domain-name-servers option specifies a list of Domain Name System should be listed in order of preference. .RE .PP -.B option \fBlog-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... +.B option \fBextensions-path\fR \fItext\fR\fB;\fR +.RS 0.25i +.PP +This option specifies the name of a file containing additional options +to be interpreted according to the DHCP option format as specified in +RFC2132. +.RE +.PP +.B option \fBfinger-server\fR \fIip-address\fR [\fB,\fR +\fIip-address\fR... ]\fB;\fR +.RS 0.25i +.PP +The Finger server option specifies a list of Finger available to the +client. Servers should be listed in order of preference. +.RE +.PP +.B option \fBfont-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP -The log-server option specifies a list of MIT-LCS UDP log servers +This option specifies a list of X Window System Font servers available +to the client. Servers should be listed in order of preference. +.RE +.PP +.B option \fBhost-name\fR \fIstring\fR\fB;\fR +.RS 0.25i +.PP +This option specifies the name of the client. The name may or may +not be qualified with the local domain name (it is preferable to use +the domain-name option to specify the domain name). See RFC 1035 for +character set restrictions. +.RE +.PP +.B option \fBieee802-3-encapsulation\fR \fIflag\fR\fB;\fR +.RS 0.25i +.PP +This option specifies whether or not the client should use Ethernet +Version 2 (RFC 894) or IEEE 802.3 (RFC 1042) encapsulation if the +interface is an Ethernet. A value of false indicates that the client +should use RFC 894 encapsulation. A value of true means that the client +should use RFC 1042 encapsulation. +.RE +.PP +.B option \fBien116-name-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... +]; +.RS 0.25i +.PP +The ien116-name-servers option specifies a list of IEN 116 name servers available to the client. Servers should be listed in order of preference. .RE .PP -.B option \fBcookie-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... +.B option \fBimpress-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP -The cookie server option specifies a list of RFC 865 cookie -servers available to the client. Servers should be listed in order -of preference. +The impress-server option specifies a list of Imagen Impress servers +available to the client. Servers should be listed in order of +preference. .RE .PP -.B option \fBlpr-servers\fR \fIip-address \fR [\fB,\fR \fIip-address\fR... -]\fB;\fR +.B option \fBinterface-mtu\fR \fIuint16\fR\fB;\fR .RS 0.25i .PP -The LPR server option specifies a list of RFC 1179 line printer -servers available to the client. Servers should be listed in order -of preference. +This option specifies the MTU to use on this interface. The minimum +legal value for the MTU is 68. .RE .PP -.B option \fBimpress-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... +.B option \fBip-forwarding\fR \fIflag\fR\fB;\fR +.RS 0.25i +.PP +This option specifies whether the client should configure its IP +layer for packet forwarding. A value of false means disable IP +forwarding, and a value of true means enable IP forwarding. +.RE +.PP +.B option \fBirc-server\fR \fIip-address\fR [\fB,\fR +\fIip-address\fR... ]\fB;\fR +.RS 0.25i +.PP +The IRC server option specifies a list of IRC available to the +client. Servers should be listed in order of preference. +.RE +.PP +.B option \fBlog-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP -The impress-server option specifies a list of Imagen Impress servers +The log-server option specifies a list of MIT-LCS UDP log servers available to the client. Servers should be listed in order of preference. .RE .PP -.B option \fBresource-location-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... +.B option \fBlpr-servers\fR \fIip-address \fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP -This option specifies a list of RFC 887 Resource Location +The LPR server option specifies a list of RFC 1179 line printer servers available to the client. Servers should be listed in order of preference. .RE .PP -.B option \fBhost-name\fR \fIstring\fR\fB;\fR +.B option \fBmask-supplier\fR \fIflag\fR\fB;\fR .RS 0.25i .PP -This option specifies the name of the client. The name may or may -not be qualified with the local domain name (it is preferable to use -the domain-name option to specify the domain name). See RFC 1035 for -character set restrictions. +This option specifies whether or not the client should respond to +subnet mask requests using ICMP. A value of false indicates that the +client should not respond. A value of true means that the client should +respond. .RE .PP -.B option \fBboot-size\fR \fIuint16\fR\fB;\fR +.B option \fBmax-dgram-reassembly\fR \fIuint16\fR\fB;\fR .RS 0.25i .PP -This option specifies the length in 512-octet blocks of the default -boot image for the client. +This option specifies the maximum size datagram that the client +should be prepared to reassemble. The minimum value legal value is +576. .RE .PP -.B option \fBmerit-dump\fR \fIstring\fR\fB;\fR +.B option \fBmerit-dump\fR \fItext\fR\fB;\fR .RS 0.25i .PP This option specifies the path-name of a file to which the client's @@ -251,33 +524,123 @@ path is formatted as a character string consisting of characters from the NVT ASCII character set. .RE .PP -.B option \fBdomain-name\fR \fIstring\fR\fB;\fR +.B option \fBmobile-ip-home-agent\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP -This option specifies the domain name that client should use when -resolving hostnames via the Domain Name System. +This option specifies a list of IP addresses indicating mobile IP +home agents available to the client. Agents should be listed in +order of preference, although normally there will be only one such +agent. .RE .PP -.B option \fBswap-server\fR \fIip-address\fR\fB;\fR +.B option \fBnds-context\fR \fIstring\fR\fB;\fR .RS 0.25i .PP -This specifies the IP address of the client's swap server. +The nds-context option specifies the name of the initial Netware +Directory Service for an NDS client. .RE .PP -.B option \fBroot-path\fR \fIstring\fB;\fR\fR +.B option \fBnds-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP -This option specifies the path-name that contains the client's root -disk. The path is formatted as a character string consisting of -characters from the NVT ASCII character set. +The nds-servers option specifies a list of IP addresses of NDS servers. .RE .PP -.B option \fBip-forwarding\fR \fIflag\fR\fB;\fR +.B option \fBnds-tree-name\fR \fIstring\fR\fB;\fR .RS 0.25i .PP -This option specifies whether the client should configure its IP -layer for packet forwarding. A value of 0 means disable IP -forwarding, and a value of 1 means enable IP forwarding. +The nds-context option specifies NDS tree name that the NDS client +should use. +.RE +.PP +.B option \fBnetbios-dd-server\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... +]\fB;\fR +.RS 0.25i +.PP +The NetBIOS datagram distribution server (NBDD) option specifies a +list of RFC 1001/1002 NBDD servers listed in order of preference. +.RE +.PP +.B option \fBnetbios-name-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR...]\fB;\fR +.RS 0.25i +.PP +The NetBIOS name server (NBNS) option specifies a list of RFC +1001/1002 NBNS name servers listed in order of preference. NetBIOS +Name Service is currently more commonly referred to as WINS. WINS +servers can be specified using the netbios-name-servers option. +.RE +.PP +.B option \fBnetbios-node-type\fR \fIuint8\fR\fB;\fR +.RS 0.25i +.PP +The NetBIOS node type option allows NetBIOS over TCP/IP clients which +are configurable to be configured as described in RFC 1001/1002. The +value is specified as a single octet which identifies the client type. +.PP +Possible node types are: +.PP +.TP 5 +.I 1 +B-node: Broadcast - no WINS +.TP +.I 2 +P-node: Peer - WINS only. +.TP +.I 4 +M-node: Mixed - broadcast, then WINS +.TP +.I 8 +H-node: Hybrid - WINS, then broadcast +.RE +.PP +.B option \fBnetbios-scope\fR \fIstring\fR\fB;\fR +.RS 0.25i +.PP +The NetBIOS scope option specifies the NetBIOS over TCP/IP scope +parameter for the client as specified in RFC 1001/1002. See RFC1001, +RFC1002, and RFC1035 for character-set restrictions. +.RE +.PP +.B option \fBnis-domain\fR \fItext\fR\fB;\fR +.RS 0.25i +.PP +This option specifies the name of the client's NIS (Sun Network +Information Services) domain. The domain is formatted as a character +string consisting of characters from the NVT ASCII character set. +.RE +.PP +.B option \fBnis-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... +]\fB;\fR +.RS 0.25i +.PP +This option specifies a list of IP addresses indicating NIS servers +available to the client. Servers should be listed in order of +preference. +.RE +.PP +.B option \fBnisplus-domain\fR \fItext\fR\fB;\fR +.RS 0.25i +.PP +This option specifies the name of the client's NIS+ domain. The +domain is formatted as a character string consisting of characters +from the NVT ASCII character set. +.RE +.PP +.B option \fBnisplus-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... +]\fB;\fR +.RS 0.25i +.PP +This option specifies a list of IP addresses indicating NIS+ servers +available to the client. Servers should be listed in order of +preference. +.RE +.PP +.B option \fBnntp-server\fR \fIip-address\fR [\fB,\fR +\fIip-address\fR... ]\fB;\fR +.RS 0.25i +.PP +The NNTP server option specifies a list of NNTP available to the +client. Servers should be listed in order of preference. .RE .PP .B option \fBnon-local-source-routing\fR \fIflag\fR\fB;\fR @@ -286,37 +649,33 @@ forwarding, and a value of 1 means enable IP forwarding. This option specifies whether the client should configure its IP layer to allow forwarding of datagrams with non-local source routes (see Section 3.3.5 of [4] for a discussion of this topic). A value -of 0 means disallow forwarding of such datagrams, and a value of 1 +of 0 means disallow forwarding of such datagrams, and a value of true means allow forwarding. .RE .PP -.B option \fBpolicy-filter\fR \fIip-address ip-address\fR [\fB,\fR \fIip-address ip-address\fR... +.B option \fBntp-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP -This option specifies policy filters for non-local source routing. -The filters consist of a list of IP addresses and masks which specify -destination/mask pairs with which to filter incoming source routes. -.PP -Any source routed datagram whose next-hop address does not match one -of the filters should be discarded by the client. -.PP -See STD 3 (RFC1122) for further information. +This option specifies a list of IP addresses indicating NTP (RFC 1035) +servers available to the client. Servers should be listed in order +of preference. .RE .PP -.B option \fBmax-dgram-reassembly\fR \fIuint16\fR\fB;\fR +.B option \fBnwip-domain\fR \fIstring\fR\fB;\fR .RS 0.25i .PP -This option specifies the maximum size datagram that the client -should be prepared to reassemble. The minimum value legal value is -576. +The name of the NetWare/IP domain that a NetWare/IP client should +use. .RE .PP -.B option \fBdefault-ip-ttl\fR \fIuint8;\fR +.B option \fBnwip-suboptions\fR \fIstring\fR\fB;\fR .RS 0.25i .PP -This option specifies the default time-to-live that the client should -use on outgoing datagrams. +A sequence of suboptions for NetWare/IP clients - see RFC2242 for +details. Normally this option is set by specifying specific +NetWare/IP suboptions - see the NETWARE/IP SUBOPTIONS section for more +information. .RE .PP .B option \fBpath-mtu-aging-timeout\fR \fIuint32\fR\fB;\fR @@ -336,48 +695,55 @@ a list of 16-bit unsigned integers, ordered from smallest to largest. The minimum MTU value cannot be smaller than 68. .RE .PP -.B option \fBinterface-mtu\fR \fIuint16\fR\fB;\fR +.B option \fBperform-mask-discovery\fR \fIflag\fR\fB;\fR .RS 0.25i .PP -This option specifies the MTU to use on this interface. The minimum -legal value for the MTU is 68. +This option specifies whether or not the client should perform subnet +mask discovery using ICMP. A value of false indicates that the client +should not perform mask discovery. A value of true means that the +client should perform mask discovery. .RE .PP -.B option \fBall-subnets-local\fR \fIflag\fR\fB;\fR +.nf +.B option \fBpolicy-filter\fR \fIip-address ip-address\fR + [\fB,\fR \fIip-address ip-address\fR...]\fB;\fR +.RE +.fi .RS 0.25i .PP -This option specifies whether or not the client may assume that all -subnets of the IP network to which the client is connected use the -same MTU as the subnet of that network to which the client is -directly connected. A value of 1 indicates that all subnets share -the same MTU. A value of 0 means that the client should assume that -some subnets of the directly connected network may have smaller MTUs. +This option specifies policy filters for non-local source routing. +The filters consist of a list of IP addresses and masks which specify +destination/mask pairs with which to filter incoming source routes. +.PP +Any source routed datagram whose next-hop address does not match one +of the filters should be discarded by the client. +.PP +See STD 3 (RFC1122) for further information. .RE .PP -.B option \fBbroadcast-address\fR \fIip-address\fR\fB;\fR +.B option \fBpop-server\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP -This option specifies the broadcast address in use on the client's -subnet. Legal values for broadcast addresses are specified in -section 3.2.1.3 of STD 3 (RFC1122). +The POP3 server option specifies a list of POP3 available to the +client. Servers should be listed in order of preference. .RE .PP -.B option \fBperform-mask-discovery\fR \fIflag\fR\fB;\fR +.B option \fBresource-location-servers\fR \fIip-address\fR + [\fB, \fR\fIip-address\fR...]\fB;\fR +.fi .RS 0.25i .PP -This option specifies whether or not the client should perform subnet -mask discovery using ICMP. A value of 0 indicates that the client -should not perform mask discovery. A value of 1 means that the -client should perform mask discovery. +This option specifies a list of RFC 887 Resource Location +servers available to the client. Servers should be listed in order +of preference. .RE .PP -.B option \fBmask-supplier\fR \fIflag\fR\fB;\fR +.B option \fBroot-path\fR \fItext\fB;\fR\fR .RS 0.25i .PP -This option specifies whether or not the client should respond to -subnet mask requests using ICMP. A value of 0 indicates that the -client should not respond. A value of 1 means that the client should -respond. +This option specifies the path-name that contains the client's root +disk. The path is formatted as a character string consisting of +characters from the NVT ASCII character set. .RE .PP .B option \fBrouter-discovery\fR \fIflag\fR\fB;\fR @@ -385,8 +751,8 @@ respond. .PP This option specifies whether or not the client should solicit routers using the Router Discovery mechanism defined in RFC 1256. -A value of 0 indicates that the client should not perform -router discovery. A value of 1 means that the client should perform +A value of false indicates that the client should not perform +router discovery. A value of true means that the client should perform router discovery. .RE .PP @@ -397,10 +763,65 @@ This option specifies the address to which the client should transmit router solicitation requests. .RE .PP -.B option \fBstatic-routes\fR \fIip-address ip-address\fR [\fB,\fR \fIip-address ip-address\fR... +.B option routers \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP +The routers option specifies a list of IP addresses for routers on the +client's subnet. Routers should be listed in order of preference. +.RE +.PP +.B option slp-directory-agent \fIboolean ip-address +[\fB,\fR \fIip-address\fR... ]\fB;\fR +.RS 0.25i +.PP +This option specifies two things: the IP addresses of one or more +Service Location Protocol Directory Agents, and whether the use of +these addresses is mandatory. If the initial boolean value is true, +the SLP agent should just use the IP addresses given. If the value +is false, the SLP agent may additionally do active or passive +multicast discovery of SLP agents (see RFC2165 for details). +.PP +Please note that in this option and the slp-service-scope option, the +term "SLP Agent" is being used to refer to a Service Location Protocol +agent running on a machine that is being configured using the DHCP +protocol. +.PP +Also, please be aware that some companies may refer to SLP as NDS. +If you have an NDS directory agent whose address you need to +configure, the slp-directory-agent option should work. +.RE +.PP +.B option slp-service-scope \fIboolean text\fR\fB;\fR +.RS 0.25i +.PP +The Service Location Protocol Service Scope Option specifies two +things: a list of service scopes for SLP, and whether the use of this +list is mandatory. If the initial boolean value is true, the SLP +agent should only use the list of scopes provided in this option; +otherwise, it may use its own static configuration in preference to +the list provided in this option. +.PP +The text string should be a comma-seperated list of scopes that the +SLP agent should use. It may be omitted, in which case the SLP Agent +will use the aggregated list of scopes of all directory agents known +to the SLP agent. +.RE +.PP +.B option \fBsmtp-server\fR \fIip-address\fR [\fB,\fR +\fIip-address\fR... ]\fB;\fR +.RS 0.25i +.PP +The SMTP server option specifies a list of SMTP servers available to +the client. Servers should be listed in order of preference. +.RE +.PP +.nf +.B option \fBstatic-routes\fR \fIip-address ip-address\fR + [\fB,\fR \fIip-address ip-address\fR...]\fB;\fR +.fi +.RS 0.25i +.PP This option specifies a list of static routes that the client should install in its routing cache. If multiple routes to the same destination are specified, they are listed in descending order of @@ -413,39 +834,73 @@ the destination. The default route (0.0.0.0) is an illegal destination for a static route. To specify the default route, use the .B routers -option. +option. Also, please note that this option is not intended for +classless IP routing - it does not include a subnet mask. Since +classless IP routing is now the most widely deployed routing standard, +this option is virtually useless, and is not implemented by any of the +popular DHCP clients, for example the Microsoft DHCP client. .RE .PP -.B option \fBtrailer-encapsulation\fR \fIflag\fR\fB;\fR +.nf +.B option \fBstreettalk-directory-assistance-server\fR \fIip-address\fR + [\fB,\fR \fIip-address\fR...]\fB;\fR +.fi .RS 0.25i .PP -This option specifies whether or not the client should negotiate the -use of trailers (RFC 893 [14]) when using the ARP protocol. A value -of 0 indicates that the client should not attempt to use trailers. A -value of 1 means that the client should attempt to use trailers. +The StreetTalk Directory Assistance (STDA) server option specifies a +list of STDA servers available to the client. Servers should be +listed in order of preference. .RE .PP -.B option \fBarp-cache-timeout\fR \fIuint32\fR\fB;\fR +.B option \fBstreettalk-server\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP -This option specifies the timeout in seconds for ARP cache entries. +The StreetTalk server option specifies a list of StreetTalk servers +available to the client. Servers should be listed in order of +preference. .RE .PP -.B option \fBieee802-3-encapsulation\fR \fIflag\fR\fB;\fR +.B option subnet-mask \fIip-address\fR\fB;\fR .RS 0.25i .PP -This option specifies whether or not the client should use Ethernet -Version 2 (RFC 894) or IEEE 802.3 (RFC 1042) encapsulation if the -interface is an Ethernet. A value of 0 indicates that the client -should use RFC 894 encapsulation. A value of 1 means that the client -should use RFC 1042 encapsulation. +The subnet mask option specifies the client's subnet mask as per RFC +950. If no subnet mask option is provided anywhere in scope, as a +last resort dhcpd will use the subnet mask from the subnet declaration +for the network on which an address is being assigned. However, +.I any +subnet-mask option declaration that is in scope for the address being +assigned will override the subnet mask specified in the subnet +declaration. .RE .PP -.B option \fBdefault-tcp-ttl\fR \fIuint8\fR\fB;\fR +.B option \fBsubnet-selection\fR \fIstring\fR\fB;\fR .RS 0.25i .PP -This option specifies the default TTL that the client should use when -sending TCP segments. The minimum value is 1. +Sent by the client if an address is required in a subnet other than the one +that would normally be selected (based on the relaying address of the +connected subnet the request is obtained from). See RFC3011. Note that the +option number used by this server is 118; this has not always been the +defined number, and some clients may use a different value. Use of this +option should be regarded as slightly experimental! +.RE +.PP +This option is not user configurable in the server. +.PP +.PP +.B option \fBswap-server\fR \fIip-address\fR\fB;\fR +.RS 0.25i +.PP +This specifies the IP address of the client's swap server. +.RE +.PP +.B option \fBtcp-keepalive-garbage\fR \fIflag\fR\fB;\fR +.RS 0.25i +.PP +This option specifies the whether or not the client should send TCP +keepalive messages with a octet of garbage for compatibility with +older implementations. A value of false indicates that a garbage octet +should not be sent. A value of true indicates that a garbage octet +should be sent. .RE .PP .B option \fBtcp-keepalive-interval\fR \fIuint32\fR\fB;\fR @@ -458,99 +913,117 @@ indicates that the client should not generate keepalive messages on connections unless specifically requested by an application. .RE .PP -.B option \fBtcp-keepalive-garbage\fR \fIflag\fR\fB;\fR +.B option \fBtftp-server-name\fR \fItext\fR\fB;\fR .RS 0.25i .PP -This option specifies the whether or not the client should send TCP -keepalive messages with a octet of garbage for compatibility with -older implementations. A value of 0 indicates that a garbage octet -should not be sent. A value of 1 indicates that a garbage octet -should be sent. +This option is used to identify a TFTP server and, if supported by the +client, should have the same effect as the \fBserver-name\fR +declaration. BOOTP clients are unlikely to support this option. +Some DHCP clients will support it, and others actually require it. .RE .PP -.B option \fBnis-domain\fR \fIstring\fR\fB;\fR +.B option time-offset \fIint32\fR\fB;\fR .RS 0.25i .PP -This option specifies the name of the client's NIS (Sun Network -Information Services) domain. The domain is formatted as a character -string consisting of characters from the NVT ASCII character set. +The time-offset option specifies the offset of the client's subnet in +seconds from Coordinated Universal Time (UTC). .RE .PP -.B option \fBnis-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... +.B option time-servers \fIip-address\fR [, \fIip-address\fR... ]\fB;\fR .RS 0.25i .PP -This option specifies a list of IP addresses indicating NIS servers +The time-server option specifies a list of RFC 868 time servers available to the client. Servers should be listed in order of preference. .RE .PP -.B option \fBntp-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... -]\fB;\fR +.B option \fBtrailer-encapsulation\fR \fIflag\fR\fB;\fR .RS 0.25i .PP -This option specifies a list of IP addresses indicating NTP (RFC 1035) -servers available to the client. Servers should be listed in order -of preference. +This option specifies whether or not the client should negotiate the +use of trailers (RFC 893 [14]) when using the ARP protocol. A value +of 0 indicates that the client should not attempt to use trailers. A +value of true means that the client should attempt to use trailers. .RE .PP -.B option \fBnetbios-name-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... -]\fB;\fR +.B option \fBuap-servers\fR \fItext\fR\fB;\fR .RS 0.25i .PP -The NetBIOS name server (NBNS) option specifies a list of RFC -1001/1002 NBNS name servers listed in order of preference. NetBIOS -Name Service is currently more commonly referred to as WINS. WINS -servers can be specified using the netbios-name-servers option. +This option specifies a list of URLs, each pointing to a user +authentication service that is capable of processing authentication +requests encapsulated in the User Authentication Protocol (UAP). UAP +servers can accept either HTTP 1.1 or SSLv3 connections. If the list +includes a URL that does not contain a port component, the normal +default port is assumed (i.e., port 80 for http and port 443 for +https). If the list includes a URL that does not contain a path +component, the path /uap is assumed. If more than one URL is +specified in this list, the URLs are seperated by spaces. .RE .PP -.B option \fBnetbios-dd-server\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... -]\fB;\fR +.B option \fBuser-class\fR \fIstring\fR\fB;\fR .RS 0.25i .PP -The NetBIOS datagram distribution server (NBDD) option specifies a -list of RFC 1001/1002 NBDD servers listed in order of preference. -.RE +This option is used by some DHCP clients as a way for users to +specify identifying information to the client. This can be used in a +similar way to the vendor-class-identifier option, but the value of +the option is specified by the user, not the vendor. Most recent +DHCP clients have a way in the user interface to specify the value for +this identifier, usually as a text string. .PP -.B option \fBnetbios-node-type\fR \fIuint8\fR\fB;\fR +.B option \fBvendor-class-identifier\fR \fIstring\fR\fB;\fR .RS 0.25i .PP -The NetBIOS node type option allows NetBIOS over TCP/IP clients which -are configurable to be configured as described in RFC 1001/1002. The -value is specified as a single octet which identifies the client type. +This option is used by some DHCP clients to identify the vendor +type and possibly the configuration of a DHCP client. The information +is a string of bytes whose contents are specific to the vendor and are +not specified in a standard. To see what vendor class identifier a +clients are sending, you can write the following in your DHCP server +configuration file: +.nf .PP -Possible node types are: +set vendor-class option vendor-class-identifier; +.fi .PP -.TP 5 -.I 1 -B-node: Broadcast - no WINS -.TP -.I 2 -P-node: Peer - WINS only. -.TP -.I 4 -M-node: Mixed - broadcast, then WINS -.TP -.I 8 -H-node: Hybrid - WINS, then broadcast +This will result in all entries in the DHCP server lease database file +for clients that sent vendor-class-identifier options having a set +statement that looks something like this: +.nf +.PP +set vendor-class "SUNW.Ultra-5_10"; +.fi +.PP +The vendor-class-identifier option is normally used by the DHCP server +to determine the options that are returned in the +.B vendor-encapsulated-options +option. Please see the VENDOR ENCAPSULATED OPTIONS section of the +dhcpd.conf manual page for further information. .RE .PP -.B option -.B netbios-scope -.I string\fB;\fR +.B option \fBvendor-encapsulated-options\fR \fIstring\fR\fB;\fR .RS 0.25i .PP -The NetBIOS scope option specifies the NetBIOS over TCP/IP scope -parameter for the client as specified in RFC 1001/1002. See RFC1001, -RFC1002, and RFC1035 for character-set restrictions. +The \fBvendor-encapsulated-options\fR option can contain either a +single vendor-specific value or one or more vendor-specific +suboptions. This option is not normally specified in the DHCP server +configuration file - instead, a vendor class is defined for each +vendor, vendor class suboptions are defined, values for those +suboptions are defined, and the DHCP server makes up a response on +that basis. +.PP +Some default behaviours for well-known DHCP client vendors (currently, +the Microsoft Windows 2000 DHCP client) are configured automatically, +but otherwise this must be configured manually - see the VENDOR +ENCAPSULATED OPTIONS section of the \fIdhcpd.conf\fI manual page for +details. .RE .PP -.B option \fBfont-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... -]\fB;\fR +.B option \fBwww-server\fR \fIip-address\fR [\fB,\fR +\fIip-address\fR... ]\fB;\fR .RS 0.25i .PP -This option specifies a list of X Window System Font servers available -to the client. Servers should be listed in order of preference. +The WWW server option specifies a list of WWW available to the +client. Servers should be listed in order of preference. .RE .PP .B option \fBx-display-manager\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... @@ -561,130 +1034,466 @@ This option specifies a list of systems that are running the X Window System Display Manager and are available to the client. Addresses should be listed in order of preference. .RE -.PP -.B option \fBdhcp-client-identifier\fR \fIdata-string\fR\fB;\fR +.SH RELAY AGENT INFORMATION OPTION +An IETF draft, draft-ietf-dhc-agent-options-11.txt, defines a series +of encapsulated options that a relay agent can add to a DHCP packet +when relaying it to the DHCP server. The server can then make +address allocation decisions (or whatever other decisions it wants) +based on these options. The server also returns these options in any +replies it sends through the relay agent, so that the relay agent can +use the information in these options for delivery or accounting +purposes. +.PP +The current draft defines two options. To reference +these options in the dhcp server, specify the option space name, +"agent", followed by a period, followed by the option name. It is +not normally useful to define values for these options in the server, +although it is permissible. These options are not supported in the +client. +.PP +.B option \fBagent.circuit-id\fR \fIstring\fR\fB;\fR .RS 0.25i .PP -This option can be used to specify the a DHCP client identifier in a -host declaration, so that dhcpd can find the host record by matching -against the client identifier. +The circuit-id suboption encodes an agent-local identifier of the +circuit from which a DHCP client-to-server packet was received. It is +intended for use by agents in relaying DHCP responses back to the +proper circuit. The format of this option is currently defined to be +vendor-dependent, and will probably remain that way, although the +current draft allows for for the possibility of standardizing the +format in the future. .RE -.B option \fBnisplus-domain\fR \fIstring\fR\fB;\fR +.PP +.B option \fBagent.remote-id\fR \fIstring\fR\fB;\fR .RS 0.25i .PP -This option specifies the name of the client's NIS+ domain. The -domain is formatted as a character string consisting of characters -from the NVT ASCII character set. +The remote-id suboption encodes information about the remote host end +of a circuit. Examples of what it might contain include caller ID +information, username information, remote ATM address, cable modem ID, +and similar things. In principal, the meaning is not well-specified, +and it should generally be assumed to be an opaque object that is +administratively guaranteed to be unique to a particular remote end of +a circuit. .RE -.B option \fBnisplus-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... -]\fB;\fR +.SH THE CLIENT FQDN SUBOPTIONS +The Client FQDN option, currently defined in the Internet Draft +draft-ietf-dhc-fqdn-option-00.txt is not a standard yet, but is in +sufficiently wide use already that we have implemented it. Due to +the complexity of the option format, we have implemented it as a +suboption space rather than a single option. In general this +option should not be configured by the user - instead it should be +used as part of an automatic DNS update system. +.PP +.B option fqdn.no-client-update \fIflag\fB; .RS 0.25i .PP -This option specifies a list of IP addresses indicating NIS+ servers -available to the client. Servers should be listed in order of -preference. +When the client sends this, if it is true, it means the client will not +attempt to update its A record. When sent by the server to the client, +it means that the client \fIshould not\fR update its own A record. .RE .PP -.B option \fBtftp-server-name\fR \fIstring\fR\fB;\fR +.B option fqdn.server-update \fIflag\fB; .RS 0.25i .PP -This option is used to identify a TFTP server and, if supported by the -client, should have the same effect as the \fBserver-name\fR -declaration. BOOTP clients are unlikely to support this option. -Some DHCP clients will support it, and others actually require it. +When the client sends this to the server, it is requesting that the server +update its A record. When sent by the server, it means that the server +has updated (or is about to update) the client's A record. .RE .PP -.B option \fBbootfile-name\fR \fIstring\fR\fB;\fR +.B option fqdn.encoded \fIflag\fB; .RS 0.25i .PP -This option is used to identify a bootstrap file. If supported by the -client, it should have the same effect as the \fBfilename\fR -declaration. BOOTP clients are unlikely to support this option. Some -DHCP clients will support it, and others actually require it. +If true, this indicates that the domain name included in the option is +encoded in DNS wire format, rather than as plain ASCII text. The client +normally sets this to false if it doesn't support DNS wire format in the +FQDN option. The server should always send back the same value that the +client sent. When this value is set on the configuration side, it controls +the format in which the \fIfqdn.fqdn\fR suboption is encoded. .RE .PP -.B option \fBmobile-ip-home-agent\fR \fIip-address\fR [\fB,\fR -\fIip-address\fR... ]\fB;\fR +.B option fqdn.rcode1 \fIflag\fB; +.PP +.B option fqdn.rcode1 \fIflag\fB; .RS 0.25i .PP -This option specifies a list of IP addresses indicating mobile IP -home agents available to the client. Agents should be listed in -order of preference, although normally there will be only one such -agent. +These options specify the result of the updates of the A and PTR records, +respectively, and are only sent by the DHCP server to the DHCP client. +The values of these fields are those defined in the DNS protocol specification. .RE .PP -.B option \fBsmtp-server\fR \fIip-address\fR [\fB,\fR -\fIip-address\fR... ]\fB;\fR +.B option fqdn.fqdn \fItext\fB; .RS 0.25i .PP -The SMTP server option specifies a list of SMTP servers available to -the client. Servers should be listed in order of preference. +Specifies the domain name that the client wishes to use. This can be a +fully-qualified domain name, or a single label. If there is no trailing +'.' character in the name, it is not fully-qualified, and the server will +generally update that name in some locally-defined domain. .RE .PP -.B option \fBpop-server\fR \fIip-address\fR [\fB,\fR -\fIip-address\fR... ]\fB;\fR +If you wish to use any of these suboptions, we strongly recommend that you +refer to the Client FQDN option draft (or standard, when it becomes a +standard) - the documentation here is sketchy and incomplete in comparison, +and is just intended for reference by people who already understand the +Client FQDN option specification. +.SH THE NETWARE/IP SUBOPTIONS +RFC2242 defines a set of encapsulated options for Novell NetWare/IP +clients. To use these options in the dhcp server, specify the option +space name, "nwip", followed by a period, followed by the option name. +The following options can be specified: +.PP +.B option \fBnwip.nsq-broadcast\fR \fIflag\fR\fB;\fR .RS 0.25i .PP -The POP3 server option specifies a list of POP3 available to the -client. Servers should be listed in order of preference. -.RE +If true, the client should use the NetWare Nearest Server Query to +locate a NetWare/IP server. The behaviour of the Novell client if +this suboption is false, or is not present, is not specified. .PP -.B option \fBnntp-server\fR \fIip-address\fR [\fB,\fR -\fIip-address\fR... ]\fB;\fR +.RE +.B option \fBnwip.preferred-dss\fR \fIip-address\fR [\fB,\fR \fIip-address\fR... ]\fR\fB;\fR .RS 0.25i .PP -The NNTP server option specifies a list of NNTP available to the -client. Servers should be listed in order of preference. +This suboption specifies a list of up to five IP addresses, each of +which should be the IP address of a NetWare Domain SAP/RIP server +(DSS). .RE .PP -.B option \fBwww-server\fR \fIip-address\fR [\fB,\fR -\fIip-address\fR... ]\fB;\fR +.B option \fBnwip.nearest-nwip-server\fR \fI\fIip-address\fR + [\fB,\fR \fIip-address\fR...]\fR\fB;\fR .RS 0.25i .PP -The WWW server option specifies a list of WWW available to the -client. Servers should be listed in order of preference. +This suboption specifies a list of up to five IP addresses, each of +which should be the IP address of a Nearest NetWare IP server. .RE .PP -.B option \fBfinger-server\fR \fIip-address\fR [\fB,\fR -\fIip-address\fR... ]\fB;\fR +.B option \fBnwip.autoretries\fR \fIuint8\fR\fB;\fR .RS 0.25i .PP -The Finger server option specifies a list of Finger available to the -client. Servers should be listed in order of preference. +Specifies the number of times that a NetWare/IP client should attempt +to communicate with a given DSS server at startup. .RE .PP -.B option \fBirc-server\fR \fIip-address\fR [\fB,\fR -\fIip-address\fR... ]\fB;\fR +.B option \fBnwip.autoretry-secs\fR \fIuint8\fR\fB;\fR .RS 0.25i .PP -The IRC server option specifies a list of IRC available to the -client. Servers should be listed in order of preference. +Specifies the number of seconds that a Netware/IP client should wait +between retries when attempting to establish communications with a DSS +server at startup. .RE .PP -.B option \fBstreettalk-server\fR \fIip-address\fR [\fB,\fR -\fIip-address\fR... ]\fB;\fR +.B option \fBnwip.nwip-1-1\fR \fIuint8\fR\fB;\fR .RS 0.25i .PP -The StreetTalk server option specifies a list of StreetTalk servers -available to the client. Servers should be listed in order of -preference. +If true, the NetWare/IP client should support NetWare/IP version 1.1 +compatibility. This is only needed if the client will be contacting +Netware/IP version 1.1 servers. .RE .PP -.B option \fBstreetalk-directory-assistance-server\fR \fIip-address\fR [\fB,\fR -\fIip-address\fR... ]\fB;\fR +.B option \fBnwip.primary-dss\fR \fIip-address\fR\fB;\fR .RS 0.25i .PP -The StreetTalk Directory Assistance (STDA) server option specifies a -list of STDA servers available to the client. Servers should be -listed in order of preference. +Specifies the IP address of the Primary Domain SAP/RIP Service server +(DSS) for this NetWare/IP domain. The NetWare/IP administration +utility uses this value as Primary DSS server when configuring a +secondary DSS server. .RE +.SH DEFINING NEW OPTIONS +The Internet Software Consortium DHCP client and server provide the +capability to define new options. Each DHCP option has a name, a +code, and a structure. The name is used by you to refer to the +option. The code is a number, used by the DHCP server and client to +refer to an option. The structure describes what the contents of an +option looks like. +.PP +To define a new option, you need to choose a name for it that is not +in use for some other option - for example, you can't use "host-name" +because the DHCP protocol already defines a host-name option, which is +documented earlier in this manual page. If an option name doesn't +appear in this manual page, you can use it, but it's probably a good +idea to put some kind of unique string at the beginning so you can be +sure that future options don't take your name. For example, you +might define an option, "local-host-name", feeling some confidence +that no official DHCP option name will ever start with "local". +.PP +Once you have chosen a name, you must choose a code. For site-local +options, all codes between 128 and 254 are reserved for DHCP options, +so you can pick any one of these. In practice, some vendors have +interpreted the protocol rather loosely and have used option code +values greater than 128 themselves. There's no real way to avoid +this problem, but it's not likely to cause too much trouble in +practice. +.PP +The structure of an option is simply the format in which the option +data appears. The ISC DHCP server currently supports a few simple +types, like integers, booleans, strings and IP addresses, and it also +supports the ability to define arrays of single types or arrays of +fixed sequences of types. +.PP +New options are declared as follows: +.PP +.B option +.I new-name +.B code +.I new-code +.B = +.I definition +.B ; +.PP +The values of +.I new-name +and +.I new-code +should be the name you have chosen for the new option and the code you +have chosen. The +.I definition +should be the definition of the structure of the option. +.PP +The following simple option type definitions are supported: +.PP +.B BOOLEAN +.PP +.B option +.I new-name +.B code +.I new-code +.B = +.B boolean +.B ; +.PP +An option of type boolean is a flag with a value of either on or off +(or true or false). So an example use of the boolean type would be: +.nf + +option use-zephyr code 180 = boolean; +option use-zephyr on; + +.fi +.B INTEGER +.PP +.B option +.I new-name +.B code +.I new-code +.B = +.I sign +.B integer +.I width +.B ; +.PP +The \fIsign\fR token should either be blank, \fIunsigned\fR +or \fIsigned\fR. The width can be either 8, 16 or 32, and refers to +the number of bits in the integer. So for example, the following two +lines show a definition of the sql-connection-max option and its use: +.nf + +option sql-connection-max code 192 = unsigned integer 16; +option sql-connection-max 1536; + +.fi +.B IP-ADDRESS +.PP +.B option +.I new-name +.B code +.I new-code +.B = +.B ip-address +.B ; +.PP +An option whose structure is an IP address can be expressed either as +a domain name or as a dotted quad. So the following is an example use +of the ip-address type: +.nf + +option sql-server-address code 193 = ip-address; +option sql-server-address sql.example.com; + +.fi +.PP +.B TEXT +.PP +.B option +.I new-name +.B code +.I new-code +.B = +.B text +.B ; +.PP +An option whose type is text will encode an ASCII text string. For +example: +.nf + +option sql-default-connection-name code 194 = text; +option sql-default-connection-name "PRODZA"; + +.fi +.PP +.B DATA STRING +.PP +.B option +.I new-name +.B code +.I new-code +.B = +.B string +.B ; +.PP +An option whose type is a data string is essentially just a collection +of bytes, and can be specified either as quoted text, like the text +type, or as a list of hexadecimal contents seperated by colons whose +values must be between 0 and FF. For example: +.nf + +option sql-identification-token code 195 = string; +option sql-identification-token 17:23:19:a6:42:ea:99:7c:22; + +.fi +.PP +.B ENCAPSULATION +.PP +.B option +.I new-name +.B code +.I new-code +.B = +.B encapsulate +.I identifier +.B ; +.PP +An option whose type is \fBencapsulate\fR will encapsulate the +contents of the option space specified in \fIidentifier\fR. Examples +of encapsulated options in the DHCP protocol as it currently exists +include the vendor-encapsulated-options option, the netware-suboptions +option and the relay-agent-information option. +.nf + +option space local; +option local.demo code 1 = text; +option local-encapsulation code 197 = encapsulate local; +option local.demo "demo"; + +.fi +.PP +.B ARRAYS +.PP +Options can contain arrays of any of the above types except for the +text and data string types, which aren't currently supported in +arrays. An example of an array definition is as follows: +.nf + +option kerberos-servers code 200 = array of ip-address; +option kerberos-servers 10.20.10.1, 10.20.11.1; + +.fi +.B RECORDS +.PP +Options can also contain data structures consisting of a sequence of +data types, which is sometimes called a record type. For example: +.nf + +option contrived-001 code 201 = { boolean, integer 32, text }; +option contrived-001 on 1772 "contrivance"; + +.fi +It's also possible to have options that are arrays of records, for +example: +.nf + +option new-static-routes code 201 = array of { + ip-address, ip-address, ip-address, integer 8 }; +option static-routes + 10.0.0.0 255.255.255.0 net-0-rtr.example.com 1, + 10.0.1.0 255.255.255.0 net-1-rtr.example.com 1, + 10.2.0.0 255.255.224.0 net-2-0-rtr.example.com 3; + +.fi +.SH VENDOR ENCAPSULATED OPTIONS +The DHCP protocol defines the \fB vendor-encapsulated-options\fR +option, which allows vendors to define their own options that will be +sent encapsulated in a standard DHCP option. The format of the +.B vendor-encapsulated-options +option is either a series of bytes whose format is not specified, or +a sequence of options, each of which consists of a single-byte +vendor-specific option code, followed by a single-byte length, +followed by as many bytes of data as are specified in the length (the +length does not include itself or the option code). +.PP +The value of this option can be set in one of two ways. The first +way is to simply specify the data directly, using a text string or a +colon-seperated list of hexadecimal values. For example: +.PP +.nf +option vendor-encapsulated-options + 2:4:AC:11:41:1: + 3:12:73:75:6e:64:68:63:70:2d:73:65:72:76:65:72:31:37:2d:31: + 4:12:2f:65:78:70:6f:72:74:2f:72:6f:6f:74:2f:69:38:36:70:63; +.fi +.PP +The second way of setting the value of this option is to have the DHCP +server generate a vendor-specific option buffer. To do this, you +must do four things: define an option space, define some options in +that option space, provide values for them, and specify that that +option space should be used to generate the +.B vendor-encapsulated-options +option. +.PP +To define a new option space in which vendor options can be stored, +use the \fRoption space\fP statement: +.PP +.B option +.B space +.I name +.B ; +.PP +The name can then be used in option definitions, as described earlier in +this document. For example: +.nf + +option space SUNW; +option SUNW.server-address code 2 = ip-address; +option SUNW.server-name code 3 = text; +option SUNW.root-path code 4 = text; + +.fi +Once you have defined an option space and the format of some options, +you can set up scopes that define values for those options, and you +can say when to use them. For example, suppose you want to handle +two different classes of clients. Using the option space definition +shown in the previous example, you can send different option values to +different clients based on the vendor-class-identifier option that the +clients send, as follows: +.PP +.nf +class "vendor-classes" { + match option vendor-class-identifier; +} + +option SUNW.server-address 172.17.65.1; +option SUNW.server-name "sundhcp-server17-1"; + +subclass "vendor-classes" "SUNW.Ultra-5_10" { + vendor-option-space SUNW; + option SUNW.root-path "/export/root/sparc"; +} + +subclass "vendor-classes" "SUNW.i86pc" { + vendor-option-space SUNW; + option SUNW.root-path "/export/root/i86pc"; +} +.fi +.PP +As you can see in the preceding example, regular scoping rules apply, +so you can define values that are global in the global scope, and only +define values that are specific to a particular class in the local +scope. The \fBvendor-option-space\fR declaration tells the DHCP +server to use options in the SUNW option space to construct the +.B vendor-encapsulated-options +option. .SH SEE ALSO -dhcpd.conf(5), dhcpd.leases(5), dhclient.conf(5), dhcpd(8), -dhclient(8), RFC2132, RFC2131. +dhcpd.conf(5), dhcpd.leases(5), dhclient.conf(5), dhcp-eval(5), dhcpd(8), +dhclient(8), RFC2132, RFC2131, draft-ietf-dhc-agent-options-??.txt. .SH AUTHOR -.B dhcpd(8) -was written by Ted Lemon <mellon@vix.com> -under a contract with Vixie Labs. Funding -for this project was provided by the Internet Software Corporation. +The Internet Software Consortium DHCP Distribution was written by Ted +Lemon under a contract with Vixie Labs. Funding for +this project was provided through the Internet Software Consortium. Information about the Internet Software Consortium can be found at -.B http://www.isc.org/isc. +.B http://www.isc.org. diff --git a/contrib/isc-dhcp/common/discover.c b/contrib/isc-dhcp/common/discover.c new file mode 100644 index 0000000..953bab0 --- /dev/null +++ b/contrib/isc-dhcp/common/discover.c @@ -0,0 +1,1138 @@ +/* dispatch.c + + Network input dispatcher... */ + +/* + * Copyright (c) 1995-2001 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. + */ + +#ifndef lint +static char copyright[] = +"$Id: discover.c,v 1.42.2.8 2001/10/18 20:10:26 mellon Exp $ Copyright (c) 1995-2001 The Internet Software Consortium. All rights reserved.\n"; +#endif /* not lint */ + +#include "dhcpd.h" +#include <sys/ioctl.h> + +struct interface_info *interfaces, *dummy_interfaces, *fallback_interface; +int interfaces_invalidated; +int quiet_interface_discovery; +u_int16_t local_port; +u_int16_t remote_port; +int (*dhcp_interface_setup_hook) (struct interface_info *, struct iaddr *); +int (*dhcp_interface_discovery_hook) (struct interface_info *); +isc_result_t (*dhcp_interface_startup_hook) (struct interface_info *); +int (*dhcp_interface_shutdown_hook) (struct interface_info *); + +struct in_addr limited_broadcast; +struct in_addr local_address; + +void (*bootp_packet_handler) PROTO ((struct interface_info *, + struct dhcp_packet *, unsigned, + unsigned int, + struct iaddr, struct hardware *)); + +omapi_object_type_t *dhcp_type_interface; +#if defined (TRACING) +trace_type_t *interface_trace; +trace_type_t *inpacket_trace; +trace_type_t *outpacket_trace; +#endif +struct interface_info **interface_vector; +int interface_count; +int interface_max; + +OMAPI_OBJECT_ALLOC (interface, struct interface_info, dhcp_type_interface) + +isc_result_t interface_setup () +{ + isc_result_t status; + status = omapi_object_type_register (&dhcp_type_interface, + "interface", + dhcp_interface_set_value, + dhcp_interface_get_value, + dhcp_interface_destroy, + dhcp_interface_signal_handler, + dhcp_interface_stuff_values, + dhcp_interface_lookup, + dhcp_interface_create, + dhcp_interface_remove, + 0, 0, 0, + sizeof (struct interface_info), + interface_initialize, RC_MISC); + if (status != ISC_R_SUCCESS) + log_fatal ("Can't register interface object type: %s", + isc_result_totext (status)); + + return status; +} + +#if defined (TRACING) +void interface_trace_setup () +{ + interface_trace = trace_type_register ("interface", (void *)0, + trace_interface_input, + trace_interface_stop, MDL); + inpacket_trace = trace_type_register ("inpacket", (void *)0, + trace_inpacket_input, + trace_inpacket_stop, MDL); + outpacket_trace = trace_type_register ("outpacket", (void *)0, + trace_outpacket_input, + trace_outpacket_stop, MDL); +} +#endif + +isc_result_t interface_initialize (omapi_object_t *ipo, + const char *file, int line) +{ + struct interface_info *ip = (struct interface_info *)ipo; + ip -> rfdesc = ip -> wfdesc = -1; + return ISC_R_SUCCESS; +} + +/* Use the SIOCGIFCONF ioctl to get a list of all the attached interfaces. + For each interface that's of type INET and not the loopback interface, + register that interface with the network I/O software, figure out what + subnet it's on, and add it to the list of interfaces. */ + +void discover_interfaces (state) + int state; +{ + struct interface_info *tmp, *ip; + struct interface_info *last, *next; + char buf [2048]; + struct ifconf ic; + struct ifreq ifr; + int i; + int sock; + int address_count = 0; + struct subnet *subnet; + struct shared_network *share; + struct sockaddr_in foo; + int ir; + struct ifreq *tif; +#ifdef ALIAS_NAMES_PERMUTED + char *s; +#endif + isc_result_t status; + static int setup_fallback = 0; + int wifcount = 0; + + /* Create an unbound datagram socket to do the SIOCGIFADDR ioctl on. */ + if ((sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) + log_fatal ("Can't create addrlist socket"); + + /* Get the interface configuration information... */ + +#ifdef SIOCGIFCONF_ZERO_PROBE + /* linux will only tell us how long a buffer it wants if we give it + * a null buffer first. So, do a dry run to figure out the length. + * + * XXX this code is duplicated from below because trying to fold + * the logic into the if statement and goto resulted in excesssive + * obfuscation. The intent is that unless you run Linux you shouldn't + * have to deal with this. */ + + ic.ifc_len = 0; + ic.ifc_ifcu.ifcu_buf = (caddr_t)NULL; +#else + /* otherwise, we just feed it a starting size, and it'll tell us if + * it needs more */ + + ic.ifc_len = sizeof buf; + ic.ifc_ifcu.ifcu_buf = (caddr_t)buf; +#endif + + gifconf_again: + i = ioctl(sock, SIOCGIFCONF, &ic); + + if (i < 0) + log_fatal ("ioctl: SIOCGIFCONF: %m"); + +#ifdef SIOCGIFCONF_ZERO_PROBE + /* Workaround for SIOCGIFCONF bug on some Linux versions. */ + if (ic.ifc_ifcu.ifcu_buf == 0 && ic.ifc_len == 0) { + ic.ifc_len = sizeof buf; + ic.ifc_ifcu.ifcu_buf = (caddr_t)buf; + goto gifconf_again; + } +#endif + + /* If the SIOCGIFCONF resulted in more data than would fit in + a buffer, allocate a bigger buffer. */ + if ((ic.ifc_ifcu.ifcu_buf == buf +#ifdef SIOCGIFCONF_ZERO_PROBE + || ic.ifc_ifcu.ifcu_buf == 0 +#endif + ) && ic.ifc_len > sizeof buf) { + ic.ifc_ifcu.ifcu_buf = dmalloc ((size_t)ic.ifc_len, MDL); + if (!ic.ifc_ifcu.ifcu_buf) + log_fatal ("Can't allocate SIOCGIFCONF buffer."); + goto gifconf_again; +#ifdef SIOCGIFCONF_ZERO_PROBE + } else if (ic.ifc_ifcu.ifcu_buf == 0) { + ic.ifc_ifcu.ifcu_buf = (caddr_t)buf; + ic.ifc_len = sizeof buf; + goto gifconf_again; +#endif + } + + + /* If we already have a list of interfaces, and we're running as + a DHCP server, the interfaces were requested. */ + if (interfaces && (state == DISCOVER_SERVER || + state == DISCOVER_RELAY || + state == DISCOVER_REQUESTED)) + ir = 0; + else if (state == DISCOVER_UNCONFIGURED) + ir = INTERFACE_REQUESTED | INTERFACE_AUTOMATIC; + else + ir = INTERFACE_REQUESTED; + + /* Cycle through the list of interfaces looking for IP addresses. */ + for (i = 0; i < ic.ifc_len;) { + struct ifreq *ifp = (struct ifreq *)((caddr_t)ic.ifc_req + i); +#ifdef HAVE_SA_LEN + if (ifp -> ifr_addr.sa_len > sizeof (struct sockaddr)) + i += (sizeof ifp -> ifr_name) + ifp -> ifr_addr.sa_len; + else +#endif + i += sizeof *ifp; + +#ifdef ALIAS_NAMES_PERMUTED + if ((s = strrchr (ifp -> ifr_name, ':'))) { + *s = 0; + } +#endif + +#ifdef SKIP_DUMMY_INTERFACES + if (!strncmp (ifp -> ifr_name, "dummy", 5)) + continue; +#endif + + + /* See if this is the sort of interface we want to + deal with. */ + strcpy (ifr.ifr_name, ifp -> ifr_name); + if (ioctl (sock, SIOCGIFFLAGS, &ifr) < 0) + log_fatal ("Can't get interface flags for %s: %m", + ifr.ifr_name); + + /* See if we've seen an interface that matches this one. */ + for (tmp = interfaces; tmp; tmp = tmp -> next) + if (!strcmp (tmp -> name, ifp -> ifr_name)) + break; + + /* Skip loopback, point-to-point and down interfaces, + except don't skip down interfaces if we're trying to + get a list of configurable interfaces. */ + if (((ifr.ifr_flags & IFF_LOOPBACK || + ifr.ifr_flags & IFF_POINTOPOINT) && !tmp) || + (!(ifr.ifr_flags & IFF_UP) && + state != DISCOVER_UNCONFIGURED)) + continue; + + /* If there isn't already an interface by this name, + allocate one. */ + if (!tmp) { + tmp = (struct interface_info *)0; + status = interface_allocate (&tmp, MDL); + if (status != ISC_R_SUCCESS) + log_fatal ("Error allocating interface %s: %s", + ifp -> ifr_name, + isc_result_totext (status)); + strcpy (tmp -> name, ifp -> ifr_name); + interface_snorf (tmp, ir); + interface_dereference (&tmp, MDL); + tmp = interfaces; /* XXX */ + } + + if (dhcp_interface_discovery_hook) + (*dhcp_interface_discovery_hook) (tmp); + + /* If we have the capability, extract link information + and record it in a linked list. */ +#ifdef HAVE_AF_LINK + if (ifp -> ifr_addr.sa_family == AF_LINK) { + struct sockaddr_dl *foo = ((struct sockaddr_dl *) + (&ifp -> ifr_addr)); +#if defined (HAVE_SIN_LEN) + tmp -> hw_address.hlen = foo -> sdl_alen; +#else + tmp -> hw_address.hlen = 6; /* XXX!!! */ +#endif + tmp -> hw_address.hbuf [0] = HTYPE_ETHER; /* XXX */ + memcpy (&tmp -> hw_address.hbuf [1], + LLADDR (foo), tmp -> hw_address.hlen); + tmp -> hw_address.hlen++; /* for type. */ + } else +#endif /* AF_LINK */ + + if (ifp -> ifr_addr.sa_family == AF_INET) { + struct iaddr addr; + + /* Get a pointer to the address... */ + memcpy (&foo, &ifp -> ifr_addr, + sizeof ifp -> ifr_addr); + + /* We don't want the loopback interface. */ + if (foo.sin_addr.s_addr == htonl (INADDR_LOOPBACK) && + ((tmp -> flags & INTERFACE_AUTOMATIC) && + state == DISCOVER_SERVER)) + continue; + + + /* If this is the first real IP address we've + found, keep a pointer to ifreq structure in + which we found it. */ + if (!tmp -> ifp) { +#ifdef HAVE_SA_LEN + unsigned len = ((sizeof ifp -> ifr_name) + + ifp -> ifr_addr.sa_len); +#else + unsigned len = sizeof *ifp; +#endif + tif = (struct ifreq *)dmalloc (len, MDL); + if (!tif) + log_fatal ("no space for ifp."); + memcpy (tif, ifp, len); + tmp -> ifp = tif; + tmp -> primary_address = foo.sin_addr; + } + + /* Grab the address... */ + addr.len = 4; + memcpy (addr.iabuf, &foo.sin_addr.s_addr, + addr.len); + if (dhcp_interface_setup_hook) + (*dhcp_interface_setup_hook) (tmp, &addr); + } + } + + /* If we allocated a buffer, free it. */ + if (ic.ifc_ifcu.ifcu_buf != buf) + dfree (ic.ifc_ifcu.ifcu_buf, MDL); + +#if defined (LINUX_SLASHPROC_DISCOVERY) + /* On Linux, interfaces that don't have IP addresses don't + show up in the SIOCGIFCONF syscall. This only matters for + the DHCP client, of course - the relay agent and server + should only care about interfaces that are configured with + IP addresses anyway. + + The PROCDEV_DEVICE (/proc/net/dev) is a kernel-supplied file + that, when read, prints a human readable network status. We + extract the names of the network devices by skipping the first + two lines (which are header) and then parsing off everything + up to the colon in each subsequent line - these lines start + with the interface name, then a colon, then a bunch of + statistics. */ + + if (state == DISCOVER_UNCONFIGURED) { + FILE *proc_dev; + char buffer [256]; + int skip = 2; + + proc_dev = fopen (PROCDEV_DEVICE, "r"); + if (!proc_dev) + log_fatal ("%s: %m", PROCDEV_DEVICE); + + while (fgets (buffer, sizeof buffer, proc_dev)) { + char *name = buffer; + char *sep; + + /* Skip the first two blocks, which are header + lines. */ + if (skip) { + --skip; + continue; + } + + sep = strrchr (buffer, ':'); + if (sep) + *sep = '\0'; + while (*name == ' ') + name++; + + /* See if we've seen an interface that matches + this one. */ + for (tmp = interfaces; tmp; tmp = tmp -> next) + if (!strcmp (tmp -> name, name)) + break; + + /* If we found one, nothing more to do.. */ + if (tmp) + continue; + + /* Otherwise, allocate one. */ + tmp = (struct interface_info *)0; + status = interface_allocate (&tmp, MDL); + if (status != ISC_R_SUCCESS) + log_fatal ("Can't allocate interface %s: %s", + name, isc_result_totext (status)); + tmp -> flags = ir; + strncpy (tmp -> name, name, IFNAMSIZ); + interface_reference (&tmp -> next, interfaces, MDL); + interface_dereference (&interfaces, MDL); + interface_reference (&interfaces, tmp, MDL); + interface_dereference (&tmp, MDL); + tmp = interfaces; + + if (dhcp_interface_discovery_hook) + (*dhcp_interface_discovery_hook) (tmp); + + } + fclose (proc_dev); + } +#endif + + /* Now cycle through all the interfaces we found, looking for + hardware addresses. */ +#if defined (HAVE_SIOCGIFHWADDR) && !defined (HAVE_AF_LINK) + for (tmp = interfaces; tmp; tmp = tmp -> next) { + struct ifreq ifr; + struct sockaddr sa; + int b, sk; + + if (!tmp -> ifp) { + /* Make up an ifreq structure. */ + tif = (struct ifreq *)dmalloc (sizeof (struct ifreq), + MDL); + if (!tif) + log_fatal ("no space to remember ifp."); + memset (tif, 0, sizeof (struct ifreq)); + strcpy (tif -> ifr_name, tmp -> name); + tmp -> ifp = tif; + } + + /* Read the hardware address from this interface. */ + ifr = *tmp -> ifp; + if (ioctl (sock, SIOCGIFHWADDR, &ifr) < 0) + continue; + + sa = *(struct sockaddr *)&ifr.ifr_hwaddr; + + switch (sa.sa_family) { +#ifdef HAVE_ARPHRD_TUNNEL + case ARPHRD_TUNNEL: + /* ignore tunnel interfaces. */ +#endif +#ifdef HAVE_ARPHRD_ROSE + case ARPHRD_ROSE: +#endif +#ifdef HAVE_ARPHRD_LOOPBACK + case ARPHRD_LOOPBACK: + /* ignore loopback interface */ + break; +#endif + + case ARPHRD_ETHER: + tmp -> hw_address.hlen = 7; + tmp -> hw_address.hbuf [0] = ARPHRD_ETHER; + memcpy (&tmp -> hw_address.hbuf [1], sa.sa_data, 6); + break; + +#ifndef HAVE_ARPHRD_IEEE802 +# define ARPHRD_IEEE802 HTYPE_IEEE802 +#endif +#if defined (HAVE_ARPHRD_IEEE802_TR) + case ARPHRD_IEEE802_TR: +#endif + case ARPHRD_IEEE802: + tmp -> hw_address.hlen = 7; + tmp -> hw_address.hbuf [0] = ARPHRD_IEEE802; + memcpy (&tmp -> hw_address.hbuf [1], sa.sa_data, 6); + break; + +#ifndef HAVE_ARPHRD_FDDI +# define ARPHRD_FDDI HTYPE_FDDI +#endif + case ARPHRD_FDDI: + tmp -> hw_address.hlen = 17; + tmp -> hw_address.hbuf [0] = HTYPE_FDDI; /* XXX */ + memcpy (&tmp -> hw_address.hbuf [1], sa.sa_data, 16); + break; + +#ifdef HAVE_ARPHRD_METRICOM + case ARPHRD_METRICOM: + tmp -> hw_address.hlen = 7; + tmp -> hw_address.hbuf [0] = ARPHRD_METRICOM; + memcpy (&tmp -> hw_address.hbuf [0], sa.sa_data, 6); + break; +#endif + +#ifdef HAVE_ARPHRD_AX25 + case ARPHRD_AX25: + tmp -> hw_address.hlen = 7; + tmp -> hw_address.hbuf [0] = ARPHRD_AX25; + memcpy (&tmp -> hw_address.hbuf [1], sa.sa_data, 6); + break; +#endif + +#ifdef HAVE_ARPHRD_NETROM + case ARPHRD_NETROM: + tmp -> hw_address.hlen = 7; + tmp -> hw_address.hbuf [0] = ARPHRD_NETROM; + memcpy (&tmp -> hw_address.hbuf [1], sa.sa_data, 6); + break; +#endif + + default: + log_error ("%s: unknown hardware address type %d", + ifr.ifr_name, sa.sa_family); + break; + } + } +#endif /* defined (HAVE_SIOCGIFHWADDR) && !defined (HAVE_AF_LINK) */ + + /* If we're just trying to get a list of interfaces that we might + be able to configure, we can quit now. */ + if (state == DISCOVER_UNCONFIGURED) { + close (sock); + return; + } + + /* Weed out the interfaces that did not have IP addresses. */ + tmp = last = next = (struct interface_info *)0; + if (interfaces) + interface_reference (&tmp, interfaces, MDL); + while (tmp) { + if (next) + interface_dereference (&next, MDL); + if (tmp -> next) + interface_reference (&next, tmp -> next, MDL); + /* skip interfaces that are running already */ + if (tmp -> flags & INTERFACE_RUNNING) + continue; + if ((tmp -> flags & INTERFACE_AUTOMATIC) && + state == DISCOVER_REQUESTED) + tmp -> flags &= ~(INTERFACE_AUTOMATIC | + INTERFACE_REQUESTED); + if (!tmp -> ifp || !(tmp -> flags & INTERFACE_REQUESTED)) { + if ((tmp -> flags & INTERFACE_REQUESTED) != ir) + log_fatal ("%s: not found", tmp -> name); + if (!last) { + if (interfaces) + interface_dereference (&interfaces, + MDL); + if (next) + interface_reference (&interfaces, next, MDL); + } else { + interface_dereference (&last -> next, MDL); + if (next) + interface_reference (&last -> next, + next, MDL); + } + if (tmp -> next) + interface_dereference (&tmp -> next, MDL); + + /* Remember the interface in case we need to know + about it later. */ + if (dummy_interfaces) { + interface_reference (&tmp -> next, + dummy_interfaces, MDL); + interface_dereference (&dummy_interfaces, MDL); + } + interface_reference (&dummy_interfaces, tmp, MDL); + interface_dereference (&tmp, MDL); + if (next) + interface_reference (&tmp, next, MDL); + continue; + } + last = tmp; + + memcpy (&foo, &tmp -> ifp -> ifr_addr, + sizeof tmp -> ifp -> ifr_addr); + + /* We must have a subnet declaration for each interface. */ + if (!tmp -> shared_network && (state == DISCOVER_SERVER)) { + log_error ("%s", ""); + log_error ("No subnet declaration for %s (%s).", + tmp -> name, inet_ntoa (foo.sin_addr)); + if (supports_multiple_interfaces (tmp)) { + log_error ("** Ignoring requests on %s. %s", + tmp -> name, "If this is not what"); + log_error (" you want, please write %s", + "a subnet declaration"); + log_error (" in your dhcpd.conf file %s", + "for the network segment"); + log_error (" to %s %s %s", + "which interface", + tmp -> name, "is attached. **"); + log_error ("%s", ""); + goto next; + } else { + log_error ("You must write a subnet %s", + " declaration for this"); + log_error ("subnet. You cannot prevent %s", + "the DHCP server"); + log_error ("from listening on this subnet %s", + "because your"); + log_fatal ("operating system does not %s.", + "support this capability"); + } + } + + /* Find subnets that don't have valid interface + addresses... */ + for (subnet = (tmp -> shared_network + ? tmp -> shared_network -> subnets + : (struct subnet *)0); + subnet; subnet = subnet -> next_sibling) { + if (!subnet -> interface_address.len) { + /* Set the interface address for this subnet + to the first address we found. */ + subnet -> interface_address.len = 4; + memcpy (subnet -> interface_address.iabuf, + &foo.sin_addr.s_addr, 4); + } + } + + /* Flag the index as not having been set, so that the + interface registerer can set it or not as it chooses. */ + tmp -> index = -1; + + /* Register the interface... */ + if_register_receive (tmp); + if_register_send (tmp); + + interface_stash (tmp); + wifcount++; +#if defined (HAVE_SETFD) + if (fcntl (tmp -> rfdesc, F_SETFD, 1) < 0) + log_error ("Can't set close-on-exec on %s: %m", + tmp -> name); + if (tmp -> rfdesc != tmp -> wfdesc) { + if (fcntl (tmp -> wfdesc, F_SETFD, 1) < 0) + log_error ("Can't set close-on-exec on %s: %m", + tmp -> name); + } +#endif + next: + interface_dereference (&tmp, MDL); + if (next) + interface_reference (&tmp, next, MDL); + } + + /* Now register all the remaining interfaces as protocols. */ + for (tmp = interfaces; tmp; tmp = tmp -> next) { + /* not if it's been registered before */ + if (tmp -> flags & INTERFACE_RUNNING) + continue; + if (tmp -> rfdesc == -1) + continue; + status = omapi_register_io_object ((omapi_object_t *)tmp, + if_readsocket, 0, + got_one, 0, 0); + if (status != ISC_R_SUCCESS) + log_fatal ("Can't register I/O handle for %s: %s", + tmp -> name, isc_result_totext (status)); + } + + close (sock); + + if (state == DISCOVER_SERVER && wifcount == 0) { + log_info ("%s", ""); + log_fatal ("Not configured to listen on any interfaces!"); + } + + if (!setup_fallback) { + setup_fallback = 1; + maybe_setup_fallback (); + } + +#if defined (HAVE_SETFD) + if (fallback_interface) { + if (fcntl (fallback_interface -> rfdesc, F_SETFD, 1) < 0) + log_error ("Can't set close-on-exec on fallback: %m"); + if (fallback_interface -> rfdesc != fallback_interface -> wfdesc) { + if (fcntl (fallback_interface -> wfdesc, F_SETFD, 1) < 0) + log_error ("Can't set close-on-exec on fallback: %m"); + } + } +#endif +} + +int if_readsocket (h) + omapi_object_t *h; +{ + struct interface_info *ip; + + if (h -> type != dhcp_type_interface) + return -1; + ip = (struct interface_info *)h; + return ip -> rfdesc; +} + +int setup_fallback (struct interface_info **fp, const char *file, int line) +{ + isc_result_t status; + + status = interface_allocate (&fallback_interface, file, line); + if (status != ISC_R_SUCCESS) + log_fatal ("Error allocating fallback interface: %s", + isc_result_totext (status)); + strcpy (fallback_interface -> name, "fallback"); + if (dhcp_interface_setup_hook) + (*dhcp_interface_setup_hook) (fallback_interface, + (struct iaddr *)0); + status = interface_reference (fp, fallback_interface, file, line); + + fallback_interface -> index = -1; + interface_stash (fallback_interface); + return status == ISC_R_SUCCESS; +} + +void reinitialize_interfaces () +{ + struct interface_info *ip; + + for (ip = interfaces; ip; ip = ip -> next) { + if_reinitialize_receive (ip); + if_reinitialize_send (ip); + } + + if (fallback_interface) + if_reinitialize_send (fallback_interface); + + interfaces_invalidated = 1; +} + +isc_result_t got_one (h) + omapi_object_t *h; +{ + struct sockaddr_in from; + struct hardware hfrom; + struct iaddr ifrom; + int result; + union { + unsigned char packbuf [4095]; /* Packet input buffer. + Must be as large as largest + possible MTU. */ + struct dhcp_packet packet; + } u; + struct interface_info *ip; + + if (h -> type != dhcp_type_interface) + return ISC_R_INVALIDARG; + ip = (struct interface_info *)h; + + again: + if ((result = + receive_packet (ip, u.packbuf, sizeof u, &from, &hfrom)) < 0) { + log_error ("receive_packet failed on %s: %m", ip -> name); + return ISC_R_UNEXPECTED; + } + if (result == 0) + return ISC_R_UNEXPECTED; + + /* If we didn't at least get the fixed portion of the BOOTP + packet, drop the packet. We're allowing packets with no + sname or filename, because we're aware of at least one + client that sends such packets, but this definitely falls + into the category of being forgiving. */ + if (result < DHCP_FIXED_NON_UDP - DHCP_SNAME_LEN - DHCP_FILE_LEN) + return ISC_R_UNEXPECTED; + + if (bootp_packet_handler) { + ifrom.len = 4; + memcpy (ifrom.iabuf, &from.sin_addr, ifrom.len); + + (*bootp_packet_handler) (ip, &u.packet, (unsigned)result, + from.sin_port, ifrom, &hfrom); + } + + /* If there is buffered data, read again. This is for, e.g., + bpf, which may return two packets at once. */ + if (ip -> rbuf_offset != ip -> rbuf_len) + goto again; + return ISC_R_SUCCESS; +} + +isc_result_t dhcp_interface_set_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_typed_data_t *value) +{ + struct interface_info *interface; + isc_result_t status; + int foo; + + if (h -> type != dhcp_type_interface) + return ISC_R_INVALIDARG; + interface = (struct interface_info *)h; + + if (!omapi_ds_strcmp (name, "name")) { + if ((value -> type == omapi_datatype_data || + value -> type == omapi_datatype_string) && + value -> u.buffer.len < sizeof interface -> name) { + memcpy (interface -> name, + value -> u.buffer.value, + value -> u.buffer.len); + interface -> name [value -> u.buffer.len] = 0; + } else + return ISC_R_INVALIDARG; + return ISC_R_SUCCESS; + } + + /* Try to find some inner object that can take the value. */ + if (h -> inner && h -> inner -> type -> set_value) { + status = ((*(h -> inner -> type -> set_value)) + (h -> inner, id, name, value)); + if (status == ISC_R_SUCCESS || status == ISC_R_UNCHANGED) + return status; + } + + return ISC_R_NOTFOUND; +} + + +isc_result_t dhcp_interface_get_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_value_t **value) +{ + return ISC_R_NOTIMPLEMENTED; +} + +isc_result_t dhcp_interface_destroy (omapi_object_t *h, + const char *file, int line) +{ + struct interface_info *interface; + isc_result_t status; + + if (h -> type != dhcp_type_interface) + return ISC_R_INVALIDARG; + interface = (struct interface_info *)h; + + if (interface -> ifp) { + dfree (interface -> ifp, file, line); + interface -> ifp = 0; + } + if (interface -> next) + interface_dereference (&interface -> next, file, line); + if (interface -> rbuf) { + dfree (interface -> rbuf, file, line); + interface -> rbuf = (unsigned char *)0; + } + if (interface -> client) + interface -> client = (struct client_state *)0; + + if (interface -> shared_network) + omapi_object_dereference ((omapi_object_t **) + &interface -> shared_network, MDL); + + return ISC_R_SUCCESS; +} + +isc_result_t dhcp_interface_signal_handler (omapi_object_t *h, + const char *name, va_list ap) +{ + struct interface_info *ip, *interface; + struct client_config *config; + struct client_state *client; + isc_result_t status; + + if (h -> type != dhcp_type_interface) + return ISC_R_INVALIDARG; + interface = (struct interface_info *)h; + + /* If it's an update signal, see if the interface is dead right + now, or isn't known at all, and if that's the case, revive it. */ + if (!strcmp (name, "update")) { + for (ip = dummy_interfaces; ip; ip = ip -> next) + if (ip == interface) + break; + if (ip && dhcp_interface_startup_hook) + return (*dhcp_interface_startup_hook) (ip); + + for (ip = interfaces; ip; ip = ip -> next) + if (ip == interface) + break; + if (!ip && dhcp_interface_startup_hook) + return (*dhcp_interface_startup_hook) (ip); + } + + /* Try to find some inner object that can take the value. */ + if (h -> inner && h -> inner -> type -> get_value) { + status = ((*(h -> inner -> type -> signal_handler)) + (h -> inner, name, ap)); + if (status == ISC_R_SUCCESS) + return status; + } + return ISC_R_NOTFOUND; +} + +isc_result_t dhcp_interface_stuff_values (omapi_object_t *c, + omapi_object_t *id, + omapi_object_t *h) +{ + struct interface_info *interface; + isc_result_t status; + + if (h -> type != dhcp_type_interface) + return ISC_R_INVALIDARG; + interface = (struct interface_info *)h; + + /* Write out all the values. */ + + status = omapi_connection_put_name (c, "state"); + if (status != ISC_R_SUCCESS) + return status; + if (interface -> flags && INTERFACE_REQUESTED) + status = omapi_connection_put_string (c, "up"); + else + status = omapi_connection_put_string (c, "down"); + if (status != ISC_R_SUCCESS) + return status; + + /* Write out the inner object, if any. */ + if (h -> inner && h -> inner -> type -> stuff_values) { + status = ((*(h -> inner -> type -> stuff_values)) + (c, id, h -> inner)); + if (status == ISC_R_SUCCESS) + return status; + } + + return ISC_R_SUCCESS; +} + +isc_result_t dhcp_interface_lookup (omapi_object_t **ip, + omapi_object_t *id, + omapi_object_t *ref) +{ + omapi_value_t *tv = (omapi_value_t *)0; + isc_result_t status; + struct interface_info *interface; + + if (!ref) + return ISC_R_NOKEYS; + + /* First see if we were sent a handle. */ + status = omapi_get_value_str (ref, id, "handle", &tv); + if (status == ISC_R_SUCCESS) { + status = omapi_handle_td_lookup (ip, tv -> value); + + omapi_value_dereference (&tv, MDL); + if (status != ISC_R_SUCCESS) + return status; + + /* Don't return the object if the type is wrong. */ + if ((*ip) -> type != dhcp_type_interface) { + omapi_object_dereference (ip, MDL); + return ISC_R_INVALIDARG; + } + } + + /* Now look for an interface name. */ + status = omapi_get_value_str (ref, id, "name", &tv); + if (status == ISC_R_SUCCESS) { + char *s; + unsigned len; + for (interface = interfaces; interface; + interface = interface -> next) { + s = memchr (interface -> name, 0, IFNAMSIZ); + if (s) + len = s - &interface -> name [0]; + else + len = IFNAMSIZ; + if ((tv -> value -> u.buffer.len == len && + !memcmp (interface -> name, + (char *)tv -> value -> u.buffer.value, + len))) + break; + } + if (!interface) { + for (interface = dummy_interfaces; + interface; interface = interface -> next) { + s = memchr (interface -> name, 0, IFNAMSIZ); + if (s) + len = s - &interface -> name [0]; + else + len = IFNAMSIZ; + if ((tv -> value -> u.buffer.len == len && + !memcmp (interface -> name, + (char *) + tv -> value -> u.buffer.value, + len))) + break; + } + } + + omapi_value_dereference (&tv, MDL); + if (*ip && *ip != (omapi_object_t *)interface) { + omapi_object_dereference (ip, MDL); + return ISC_R_KEYCONFLICT; + } else if (!interface) { + if (*ip) + omapi_object_dereference (ip, MDL); + return ISC_R_NOTFOUND; + } else if (!*ip) + omapi_object_reference (ip, + (omapi_object_t *)interface, + MDL); + } + + /* If we get to here without finding an interface, no valid key was + specified. */ + if (!*ip) + return ISC_R_NOKEYS; + return ISC_R_SUCCESS; +} + +/* actually just go discover the interface */ +isc_result_t dhcp_interface_create (omapi_object_t **lp, + omapi_object_t *id) +{ + struct interface_info *hp; + isc_result_t status; + + hp = (struct interface_info *)0; + status = interface_allocate (&hp, MDL); + if (status != ISC_R_SUCCESS) + return status; + hp -> flags = INTERFACE_REQUESTED; + status = interface_reference ((struct interface_info **)lp, hp, MDL); + interface_dereference (&hp, MDL); + return status; +} + +isc_result_t dhcp_interface_remove (omapi_object_t *lp, + omapi_object_t *id) +{ + struct interface_info *interface, *ip, *last; + + interface = (struct interface_info *)lp; + + /* remove from interfaces */ + last = 0; + for (ip = interfaces; ip; ip = ip -> next) { + if (ip == interface) { + if (last) { + interface_dereference (&last -> next, MDL); + if (ip -> next) + interface_reference (&last -> next, + ip -> next, MDL); + } else { + interface_dereference (&interfaces, MDL); + if (ip -> next) + interface_reference (&interfaces, + ip -> next, MDL); + } + if (ip -> next) + interface_dereference (&ip -> next, MDL); + break; + } + last = ip; + } + if (!ip) + return ISC_R_NOTFOUND; + + /* add the interface to the dummy_interface list */ + if (dummy_interfaces) { + interface_reference (&interface -> next, + dummy_interfaces, MDL); + interface_dereference (&dummy_interfaces, MDL); + } + interface_reference (&dummy_interfaces, interface, MDL); + + /* do a DHCPRELEASE */ + if (dhcp_interface_shutdown_hook) + (*dhcp_interface_shutdown_hook) (interface); + + /* remove the io object */ + omapi_unregister_io_object ((omapi_object_t *)interface); + + if_deregister_send (interface); + if_deregister_receive (interface); + + return ISC_R_SUCCESS; +} + +void interface_stash (struct interface_info *tptr) +{ + struct interface_info **vec; + int delta; + + /* If the registerer didn't assign an index, assign one now. */ + if (tptr -> index == -1) { + tptr -> index = interface_count++; + while (tptr -> index < interface_max && + interface_vector [tptr -> index]) + tptr -> index = interface_count++; + } + + if (interface_max <= tptr -> index) { + delta = tptr -> index - interface_max + 10; + vec = dmalloc ((interface_max + delta) * + sizeof (struct interface_info *), MDL); + if (!vec) + return; + memset (&vec [interface_max], 0, + (sizeof (struct interface_info *)) * delta); + interface_max += delta; + if (interface_vector) { + memcpy (vec, interface_vector, + (interface_count * + sizeof (struct interface_info *))); + dfree (interface_vector, MDL); + } + interface_vector = vec; + } + interface_reference (&interface_vector [tptr -> index], tptr, MDL); + if (tptr -> index >= interface_count) + interface_count = tptr -> index + 1; +#if defined (TRACING) + trace_interface_register (interface_trace, tptr); +#endif +} + +void interface_snorf (struct interface_info *tmp, int ir) +{ + tmp -> circuit_id = (u_int8_t *)tmp -> name; + tmp -> circuit_id_len = strlen (tmp -> name); + tmp -> remote_id = 0; + tmp -> remote_id_len = 0; + tmp -> flags = ir; + if (interfaces) { + interface_reference (&tmp -> next, + interfaces, MDL); + interface_dereference (&interfaces, MDL); + } + interface_reference (&interfaces, tmp, MDL); +} diff --git a/contrib/isc-dhcp/common/dispatch.c b/contrib/isc-dhcp/common/dispatch.c index d44a987..7c8545b 100644 --- a/contrib/isc-dhcp/common/dispatch.c +++ b/contrib/isc-dhcp/common/dispatch.c @@ -3,8 +3,8 @@ Network input dispatcher... */ /* - * Copyright (c) 1995, 1996, 1997, 1998, 1999 - * The Internet Software Consortium. All rights reserved. + * Copyright (c) 1995-2001 Internet Software Consortium. + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -34,587 +34,59 @@ * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium - * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie - * Enterprises. To learn more about the Internet Software Consortium, - * see ``http://www.vix.com/isc''. To learn more about Vixie - * Enterprises, see ``http://www.vix.com''. + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. */ #ifndef lint static char copyright[] = -"$Id: dispatch.c,v 1.47.2.15 1999/07/13 12:51:55 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium. All rights reserved.\n"; +"$Id: dispatch.c,v 1.63.2.2 2001/06/21 16:47:15 mellon Exp $ Copyright (c) 1995-2001 The Internet Software Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" -#include <sys/ioctl.h> -struct interface_info *interfaces, *dummy_interfaces, *fallback_interface; -struct protocol *protocols; struct timeout *timeouts; static struct timeout *free_timeouts; -static int interfaces_invalidated; -void (*bootp_packet_handler) PROTO ((struct interface_info *, - struct dhcp_packet *, int, unsigned int, - struct iaddr, struct hardware *)); -int quiet_interface_discovery; - -/* Use the SIOCGIFCONF ioctl to get a list of all the attached interfaces. - For each interface that's of type INET and not the loopback interface, - register that interface with the network I/O software, figure out what - subnet it's on, and add it to the list of interfaces. */ - -void discover_interfaces (state) - int state; +void set_time (u_int32_t t) { - struct interface_info *tmp; - struct interface_info *last, *next; - char buf [8192]; - struct ifconf ic; - struct ifreq ifr; - int i; - int sock; - struct subnet *subnet; - struct shared_network *share; - struct sockaddr_in foo; - int ir; - struct ifreq *tif; -#ifdef ALIAS_NAMES_PERMUTED - char *s; -#endif - - /* Create an unbound datagram socket to do the SIOCGIFADDR ioctl on. */ - if ((sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) - error ("Can't create addrlist socket"); - - /* Get the interface configuration information... */ - ic.ifc_len = sizeof buf; - ic.ifc_ifcu.ifcu_buf = (caddr_t)buf; - i = ioctl(sock, SIOCGIFCONF, &ic); - - if (i < 0) - error ("ioctl: SIOCGIFCONF: %m"); - - /* If we already have a list of interfaces, and we're running as - a DHCP server, the interfaces were requested. */ - if (interfaces && (state == DISCOVER_SERVER || - state == DISCOVER_RELAY || - state == DISCOVER_REQUESTED)) - ir = 0; - else if (state == DISCOVER_UNCONFIGURED) - ir = INTERFACE_REQUESTED | INTERFACE_AUTOMATIC; - else - ir = INTERFACE_REQUESTED; - - /* Cycle through the list of interfaces looking for IP addresses. */ - for (i = 0; i < ic.ifc_len;) { - struct ifreq *ifp = (struct ifreq *)((caddr_t)ic.ifc_req + i); -#ifdef HAVE_SA_LEN - if (ifp -> ifr_addr.sa_len > sizeof (struct sockaddr)) - i += (sizeof ifp -> ifr_name) + ifp -> ifr_addr.sa_len; - else -#endif - i += sizeof *ifp; - -#ifdef ALIAS_NAMES_PERMUTED - if ((s = strrchr (ifp -> ifr_name, ':'))) { - *s = 0; - } -#endif - -#ifdef SKIP_DUMMY_INTERFACES - if (!strncmp (ifp -> ifr_name, "dummy", 5)) - continue; -#endif - - - /* See if this is the sort of interface we want to - deal with. */ - strcpy (ifr.ifr_name, ifp -> ifr_name); - if (ioctl (sock, SIOCGIFFLAGS, &ifr) < 0) - error ("Can't get interface flags for %s: %m", - ifr.ifr_name); - - /* Skip loopback, point-to-point and down interfaces, - except don't skip down interfaces if we're trying to - get a list of configurable interfaces. */ - if ((ifr.ifr_flags & IFF_LOOPBACK) || -#ifdef HAVE_IFF_POINTOPOINT - (ifr.ifr_flags & IFF_POINTOPOINT) || -#endif - (!(ifr.ifr_flags & IFF_UP) && - state != DISCOVER_UNCONFIGURED)) - continue; - - /* See if we've seen an interface that matches this one. */ - for (tmp = interfaces; tmp; tmp = tmp -> next) - if (!strcmp (tmp -> name, ifp -> ifr_name)) - break; - - /* If there isn't already an interface by this name, - allocate one. */ - if (!tmp) { - tmp = ((struct interface_info *) - dmalloc (sizeof *tmp, "discover_interfaces")); - if (!tmp) - error ("Insufficient memory to %s %s", - "record interface", ifp -> ifr_name); - strcpy (tmp -> name, ifp -> ifr_name); - tmp -> next = interfaces; - tmp -> flags = ir; - interfaces = tmp; - } - - /* If we have the capability, extract link information - and record it in a linked list. */ -#ifdef HAVE_AF_LINK - if (ifp -> ifr_addr.sa_family == AF_LINK) { - struct sockaddr_dl *foo = ((struct sockaddr_dl *) - (&ifp -> ifr_addr)); - tmp -> hw_address.hlen = foo -> sdl_alen; - tmp -> hw_address.htype = HTYPE_ETHER; /* XXX */ - memcpy (tmp -> hw_address.haddr, - LLADDR (foo), foo -> sdl_alen); - } else -#endif /* AF_LINK */ - - if (ifp -> ifr_addr.sa_family == AF_INET) { - struct iaddr addr; - - /* Get a pointer to the address... */ - memcpy (&foo, &ifp -> ifr_addr, - sizeof ifp -> ifr_addr); - - /* We don't want the loopback interface. */ - if (foo.sin_addr.s_addr == htonl (INADDR_LOOPBACK)) - continue; - - - /* If this is the first real IP address we've - found, keep a pointer to ifreq structure in - which we found it. */ - if (!tmp -> ifp) { -#ifdef HAVE_SA_LEN - int len = ((sizeof ifp -> ifr_name) + - ifp -> ifr_addr.sa_len); -#else - int len = sizeof *ifp; -#endif - tif = (struct ifreq *)malloc (len); - if (!tif) - error ("no space to remember ifp."); - memcpy (tif, ifp, len); - tmp -> ifp = tif; - tmp -> primary_address = foo.sin_addr; - } - - /* Grab the address... */ - addr.len = 4; - memcpy (addr.iabuf, &foo.sin_addr.s_addr, - addr.len); - - /* If there's a registered subnet for this address, - connect it together... */ - if ((subnet = find_subnet (addr))) { - /* If this interface has multiple aliases - on the same subnet, ignore all but the - first we encounter. */ - if (!subnet -> interface) { - subnet -> interface = tmp; - subnet -> interface_address = addr; - } else if (subnet -> interface != tmp) { - warn ("Multiple %s %s: %s %s", - "interfaces match the", - "same subnet", - subnet -> interface -> name, - tmp -> name); - } - share = subnet -> shared_network; - if (tmp -> shared_network && - tmp -> shared_network != share) { - warn ("Interface %s matches %s", - tmp -> name, - "multiple shared networks"); - } else { - tmp -> shared_network = share; - } - - if (!share -> interface) { - share -> interface = tmp; - } else if (share -> interface != tmp) { - warn ("Multiple %s %s: %s %s", - "interfaces match the", - "same shared network", - share -> interface -> name, - tmp -> name); - } - } - } + /* Do any outstanding timeouts. */ + if (cur_time != t) { + cur_time = t; + process_outstanding_timeouts ((struct timeval *)0); } - -#if defined (LINUX_SLASHPROC_DISCOVERY) - /* On Linux, interfaces that don't have IP addresses don't show up - in the SIOCGIFCONF syscall. We got away with this prior to - Linux 2.1 because we would give each interface an IP address of - 0.0.0.0 before trying to boot, but that doesn't work after 2.1 - because we're using LPF, because we can't configure interfaces - with IP addresses of 0.0.0.0 anymore (grumble). This only - matters for the DHCP client, of course - the relay agent and - server should only care about interfaces that are configured - with IP addresses anyway. - - The PROCDEV_DEVICE (/proc/net/dev) is a kernel-supplied file - that, when read, prints a human readable network status. We - extract the names of the network devices by skipping the first - two lines (which are header) and then parsing off everything - up to the colon in each subsequent line - these lines start - with the interface name, then a colon, then a bunch of - statistics. Yes, Virgina, this is a kludge, but you work - with what you have. */ - - if (state == DISCOVER_UNCONFIGURED) { - FILE *proc_dev; - char buffer [256]; - int skip = 2; - - proc_dev = fopen (PROCDEV_DEVICE, "r"); - if (!proc_dev) - error ("%s: %m", PROCDEV_DEVICE); - - while (fgets (buffer, sizeof buffer, proc_dev)) { - char *name = buffer; - char *sep; - - /* Skip the first two blocks, which are header - lines. */ - if (skip) { - --skip; - continue; - } - - sep = strrchr (buffer, ':'); - if (sep) - *sep = '\0'; - while (*name == ' ') - name++; - - /* See if we've seen an interface that matches - this one. */ - for (tmp = interfaces; tmp; tmp = tmp -> next) - if (!strcmp (tmp -> name, name)) - break; - - /* If we found one, nothing more to do.. */ - if (tmp) - continue; - - /* Otherwise, allocate one. */ - tmp = ((struct interface_info *) - dmalloc (sizeof *tmp, "discover_interfaces")); - if (!tmp) - error ("Insufficient memory to %s %s", - "record interface", name); - memset (tmp, 0, sizeof *tmp); - strcpy (tmp -> name, name); - - tmp -> flags = ir; - tmp -> next = interfaces; - interfaces = tmp; - } - fclose (proc_dev); - } -#endif - - /* Now cycle through all the interfaces we found, looking for - hardware addresses. */ -#if defined (HAVE_SIOCGIFHWADDR) && !defined (HAVE_AF_LINK) - for (tmp = interfaces; tmp; tmp = tmp -> next) { - struct ifreq ifr; - struct sockaddr sa; - int b, sk; - - if (!tmp -> ifp) { - /* Make up an ifreq structure. */ - tif = (struct ifreq *)malloc (sizeof (struct ifreq)); - if (!tif) - error ("no space to remember ifp."); - memset (tif, 0, sizeof (struct ifreq)); - strcpy (tif -> ifr_name, tmp -> name); - tmp -> ifp = tif; - } - - /* Read the hardware address from this interface. */ - ifr = *tmp -> ifp; - if (ioctl (sock, SIOCGIFHWADDR, &ifr) < 0) - continue; - - sa = *(struct sockaddr *)&ifr.ifr_hwaddr; - - switch (sa.sa_family) { -#ifdef HAVE_ARPHRD_TUNNEL - case ARPHRD_TUNNEL: - /* ignore tunnel interfaces. */ -#endif -#ifdef HAVE_ARPHRD_ROSE - case ARPHRD_ROSE: -#endif -#ifdef HAVE_ARPHRD_LOOPBACK - case ARPHRD_LOOPBACK: - /* ignore loopback interface */ - break; -#endif - - case ARPHRD_ETHER: - tmp -> hw_address.hlen = 6; - tmp -> hw_address.htype = ARPHRD_ETHER; - memcpy (tmp -> hw_address.haddr, sa.sa_data, 6); - break; - -#ifndef HAVE_ARPHRD_IEEE802 -# define ARPHRD_IEEE802 HTYPE_IEEE802 -#endif - case ARPHRD_IEEE802: - tmp -> hw_address.hlen = 6; - tmp -> hw_address.htype = ARPHRD_IEEE802; - memcpy (tmp -> hw_address.haddr, sa.sa_data, 6); - break; - -#ifndef HAVE_ARPHRD_FDDI -# define ARPHRD_FDDI HTYPE_FDDI -#endif - case ARPHRD_FDDI: - tmp -> hw_address.hlen = 16; - tmp -> hw_address.htype = HTYPE_FDDI; /* XXX */ - memcpy (tmp -> hw_address.haddr, sa.sa_data, 16); - break; - -#ifdef HAVE_ARPHRD_METRICOM - case ARPHRD_METRICOM: - tmp -> hw_address.hlen = 6; - tmp -> hw_address.htype = ARPHRD_METRICOM; - memcpy (tmp -> hw_address.haddr, sa.sa_data, 6); - break; -#endif - -#ifdef HAVE_ARPHRD_AX25 - case ARPHRD_AX25: - tmp -> hw_address.hlen = 6; - tmp -> hw_address.htype = ARPHRD_AX25; - memcpy (tmp -> hw_address.haddr, sa.sa_data, 6); - break; -#endif - -#ifdef HAVE_ARPHRD_NETROM - case ARPHRD_NETROM: - tmp -> hw_address.hlen = 6; - tmp -> hw_address.htype = ARPHRD_NETROM; - memcpy (tmp -> hw_address.haddr, sa.sa_data, 6); - break; -#endif - - default: - warn ("%s: unknown hardware address type %d", - ifr.ifr_name, sa.sa_family); - break; - } - } -#endif /* defined (HAVE_SIOCGIFHWADDR) && !defined (HAVE_AF_LINK) */ - - /* If we're just trying to get a list of interfaces that we might - be able to configure, we can quit now. */ - if (state == DISCOVER_UNCONFIGURED) - return; - - /* Weed out the interfaces that did not have IP addresses. */ - last = (struct interface_info *)0; - for (tmp = interfaces; tmp; tmp = next) { - next = tmp -> next; - if ((tmp -> flags & INTERFACE_AUTOMATIC) && - state == DISCOVER_REQUESTED) - tmp -> flags &= ~(INTERFACE_AUTOMATIC | - INTERFACE_REQUESTED); - if (!tmp -> ifp || !(tmp -> flags & INTERFACE_REQUESTED)) { - if ((tmp -> flags & INTERFACE_REQUESTED) != ir) - error ("%s: not found", tmp -> name); - if (!last) - interfaces = interfaces -> next; - else - last -> next = tmp -> next; - - /* Remember the interface in case we need to know - about it later. */ - tmp -> next = dummy_interfaces; - dummy_interfaces = tmp; - continue; - } - last = tmp; - - memcpy (&foo, &tmp -> ifp -> ifr_addr, - sizeof tmp -> ifp -> ifr_addr); - - /* We must have a subnet declaration for each interface. */ - if (!tmp -> shared_network && (state == DISCOVER_SERVER)) { - warn ("No subnet declaration for %s (%s).", - tmp -> name, inet_ntoa (foo.sin_addr)); - warn ("Please write a subnet declaration in your %s", - "dhcpd.conf file for the"); - error ("network segment to which interface %s %s", - tmp -> name, "is attached."); - } - - /* Find subnets that don't have valid interface - addresses... */ - for (subnet = (tmp -> shared_network - ? tmp -> shared_network -> subnets - : (struct subnet *)0); - subnet; subnet = subnet -> next_sibling) { - if (!subnet -> interface_address.len) { - /* Set the interface address for this subnet - to the first address we found. */ - subnet -> interface_address.len = 4; - memcpy (subnet -> interface_address.iabuf, - &foo.sin_addr.s_addr, 4); - } - } - - /* Register the interface... */ - if_register_receive (tmp); - if_register_send (tmp); - } - - /* Now register all the remaining interfaces as protocols. */ - for (tmp = interfaces; tmp; tmp = tmp -> next) - add_protocol (tmp -> name, tmp -> rfdesc, got_one, tmp); - - close (sock); - - maybe_setup_fallback (); } -struct interface_info *setup_fallback () +struct timeval *process_outstanding_timeouts (struct timeval *tvp) { - fallback_interface = - ((struct interface_info *) - dmalloc (sizeof *fallback_interface, "discover_interfaces")); - if (!fallback_interface) - error ("Insufficient memory to record fallback interface."); - memset (fallback_interface, 0, sizeof *fallback_interface); - strcpy (fallback_interface -> name, "fallback"); - fallback_interface -> shared_network = - new_shared_network ("parse_statement"); - if (!fallback_interface -> shared_network) - error ("No memory for shared subnet"); - memset (fallback_interface -> shared_network, 0, - sizeof (struct shared_network)); - fallback_interface -> shared_network -> name = "fallback-net"; - return fallback_interface; -} - -void reinitialize_interfaces () -{ - struct interface_info *ip; - - for (ip = interfaces; ip; ip = ip -> next) { - if_reinitialize_receive (ip); - if_reinitialize_send (ip); - } - - if (fallback_interface) - if_reinitialize_send (fallback_interface); - - interfaces_invalidated = 1; + /* Call any expired timeouts, and then if there's + still a timeout registered, time out the select + call then. */ + another: + if (timeouts) { + struct timeout *t; + if (timeouts -> when <= cur_time) { + t = timeouts; + timeouts = timeouts -> next; + (*(t -> func)) (t -> what); + if (t -> unref) + (*t -> unref) (&t -> what, MDL); + t -> next = free_timeouts; + free_timeouts = t; + goto another; + } + if (tvp) { + tvp -> tv_sec = timeouts -> when; + tvp -> tv_usec = 0; + } + return tvp; + } else + return (struct timeval *)0; } -#ifdef USE_POLL -/* Wait for packets to come in using poll(). When a packet comes in, - call receive_packet to receive the packet and possibly strip hardware - addressing information from it, and then call through the - bootp_packet_handler hook to try to do something with it. */ - -void dispatch () -{ - struct protocol *l; - int nfds = 0; - struct pollfd *fds; - int count; - int i; - int to_msec; - - nfds = 0; - for (l = protocols; l; l = l -> next) { - ++nfds; - } - fds = (struct pollfd *)malloc ((nfds) * sizeof (struct pollfd)); - if (!fds) - error ("Can't allocate poll structures."); - - do { - /* Call any expired timeouts, and then if there's - still a timeout registered, time out the select - call then. */ - another: - if (timeouts) { - struct timeout *t; - if (timeouts -> when <= cur_time) { - t = timeouts; - timeouts = timeouts -> next; - (*(t -> func)) (t -> what); - t -> next = free_timeouts; - free_timeouts = t; - goto another; - } - /* Figure timeout in milliseconds, and check for - potential overflow. We assume that integers - are 32 bits, which is harmless if they're 64 - bits - we'll just get extra timeouts in that - case. Lease times would have to be quite - long in order for a 32-bit integer to overflow, - anyway. */ - to_msec = timeouts -> when - cur_time; - if (to_msec > 2147483) - to_msec = 2147483; - to_msec *= 1000; - } else - to_msec = -1; - - /* Set up the descriptors to be polled. */ - i = 0; - for (l = protocols; l; l = l -> next) { - fds [i].fd = l -> fd; - fds [i].events = POLLIN; - fds [i].revents = 0; - ++i; - } - - /* Wait for a packet or a timeout... XXX */ - count = poll (fds, nfds, to_msec); - - /* Get the current time... */ - GET_TIME (&cur_time); - - /* Not likely to be transitory... */ - if (count < 0) { - if (errno == EAGAIN || errno == EINTR) - continue; - else - error ("poll: %m"); - } - - i = 0; - for (l = protocols; l; l = l -> next) { - if ((fds [i].revents & POLLIN)) { - fds [i].revents = 0; - if (l -> handler) - (*(l -> handler)) (l); - if (interfaces_invalidated) - break; - } - ++i; - } - interfaces_invalidated = 0; - } while (1); -} -#else /* Wait for packets to come in using select(). When one does, call receive_packet to receive the packet and possibly strip hardware addressing information from it, and then call through the @@ -622,135 +94,32 @@ void dispatch () void dispatch () { - fd_set r, w, x; - struct protocol *l; - int max = 0; - int count; struct timeval tv, *tvp; + isc_result_t status; - FD_ZERO (&w); - FD_ZERO (&x); - + /* Wait for a packet or a timeout... XXX */ do { - /* Call any expired timeouts, and then if there's - still a timeout registered, time out the select - call then. */ - another: - if (timeouts) { - struct timeout *t; - if (timeouts -> when <= cur_time) { - t = timeouts; - timeouts = timeouts -> next; - (*(t -> func)) (t -> what); - t -> next = free_timeouts; - free_timeouts = t; - goto another; - } - tv.tv_sec = timeouts -> when - cur_time; - tv.tv_usec = 0; - tvp = &tv; - } else - tvp = (struct timeval *)0; - - /* Set up the read mask. */ - FD_ZERO (&r); - - for (l = protocols; l; l = l -> next) { - FD_SET (l -> fd, &r); - if (l -> fd > max) - max = l -> fd; - } - - /* Wait for a packet or a timeout... XXX */ - count = select (max + 1, &r, &w, &x, tvp); - - /* Get the current time... */ - GET_TIME (&cur_time); - - /* Not likely to be transitory... */ - if (count < 0) - error ("select: %m"); - - for (l = protocols; l; l = l -> next) { - if (!FD_ISSET (l -> fd, &r)) - continue; - if (l -> handler) - (*(l -> handler)) (l); - if (interfaces_invalidated) - break; - } - interfaces_invalidated = 0; - } while (1); -} -#endif /* USE_POLL */ - -void got_one (l) - struct protocol *l; -{ - struct sockaddr_in from; - struct hardware hfrom; - struct iaddr ifrom; - int result; - union { - unsigned char packbuf [4095]; /* Packet input buffer. - Must be as large as largest - possible MTU. */ - struct dhcp_packet packet; - } u; - struct interface_info *ip = l -> local; - - if ((result = - receive_packet (ip, u.packbuf, sizeof u, &from, &hfrom)) < 0) { - warn ("receive_packet failed on %s: %m", ip -> name); - return; - } - if (result == 0) - return; - - if (bootp_packet_handler) { - ifrom.len = 4; - memcpy (ifrom.iabuf, &from.sin_addr, ifrom.len); - - (*bootp_packet_handler) (ip, &u.packet, result, - from.sin_port, ifrom, &hfrom); - } -} - -int locate_network (packet) - struct packet *packet; -{ - struct iaddr ia; - - /* If this came through a gateway, find the corresponding subnet... */ - if (packet -> raw -> giaddr.s_addr) { - struct subnet *subnet; - ia.len = 4; - memcpy (ia.iabuf, &packet -> raw -> giaddr, 4); - subnet = find_subnet (ia); - if (subnet) - packet -> shared_network = subnet -> shared_network; - else - packet -> shared_network = (struct shared_network *)0; - } else { - packet -> shared_network = - packet -> interface -> shared_network; - } - if (packet -> shared_network) - return 1; - return 0; + tvp = process_outstanding_timeouts (&tv); + status = omapi_one_dispatch (0, tvp); + } while (status == ISC_R_TIMEDOUT || status == ISC_R_SUCCESS); + log_fatal ("omapi_one_dispatch failed: %s -- exiting.", + isc_result_totext (status)); } -void add_timeout (when, where, what) +void add_timeout (when, where, what, ref, unref) TIME when; void (*where) PROTO ((void *)); void *what; + tvref_t ref; + tvunref_t unref; { struct timeout *t, *q; /* See if this timeout supersedes an existing timeout. */ t = (struct timeout *)0; for (q = timeouts; q; q = q -> next) { - if (q -> func == where && q -> what == what) { + if ((where == NULL || q -> func == where) && + q -> what == what) { if (t) t -> next = q -> next; else @@ -766,15 +135,20 @@ void add_timeout (when, where, what) if (free_timeouts) { q = free_timeouts; free_timeouts = q -> next; - q -> func = where; - q -> what = what; } else { - q = (struct timeout *)malloc (sizeof (struct timeout)); + q = ((struct timeout *) + dmalloc (sizeof (struct timeout), MDL)); if (!q) - error ("Can't allocate timeout structure!"); - q -> func = where; + log_fatal ("add_timeout: no memory!"); + } + memset (q, 0, sizeof *q); + q -> func = where; + q -> ref = ref; + q -> unref = unref; + if (q -> ref) + (*q -> ref)(&q -> what, what, MDL); + else q -> what = what; - } } q -> when = when; @@ -823,46 +197,32 @@ void cancel_timeout (where, what) /* If we found the timeout, put it on the free list. */ if (q) { + if (q -> unref) + (*q -> unref) (&q -> what, MDL); q -> next = free_timeouts; free_timeouts = q; } } -/* Add a protocol to the list of protocols... */ -void add_protocol (name, fd, handler, local) - char *name; - int fd; - void (*handler) PROTO ((struct protocol *)); - void *local; +#if defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) +void cancel_all_timeouts () { - struct protocol *p; - - p = (struct protocol *)malloc (sizeof *p); - if (!p) - error ("can't allocate protocol struct for %s", name); - - p -> fd = fd; - p -> handler = handler; - p -> local = local; - - p -> next = protocols; - protocols = p; + struct timeout *t, *n; + for (t = timeouts; t; t = n) { + n = t -> next; + if (t -> unref && t -> what) + (*t -> unref) (&t -> what, MDL); + t -> next = free_timeouts; + free_timeouts = t; + } } -void remove_protocol (proto) - struct protocol *proto; +void relinquish_timeouts () { - struct protocol *p, *next, *prev; - - prev = (struct protocol *)0; - for (p = protocols; p; p = next) { - next = p -> next; - if (p == proto) { - if (prev) - prev -> next = p -> next; - else - protocols = p -> next; - free (p); - } + struct timeout *t, *n; + for (t = free_timeouts; t; t = n) { + n = t -> next; + dfree (t, MDL); } } +#endif diff --git a/contrib/isc-dhcp/common/dlpi.c b/contrib/isc-dhcp/common/dlpi.c new file mode 100644 index 0000000..4cbc332 --- /dev/null +++ b/contrib/isc-dhcp/common/dlpi.c @@ -0,0 +1,1345 @@ +/* dlpi.c + + Data Link Provider Interface (DLPI) network interface code. */ + +/* + * Copyright (c) 1996-2001 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software was written for the Internet Software Consortium + * by Eric James Negaard, <lmdejn@lmd.ericsson.se>. To learn more about + * the Internet Software Consortium, see ``http://www.isc.org''. + * + * Joost Mulders has also done considerable work in debugging the DLPI API + * support on Solaris and getting this code to work properly on a variety + * of different Solaris platforms. + */ + +/* + * Based largely in part to the existing NIT code in nit.c. + * + * This code has been developed and tested on sparc-based machines running + * SunOS 5.5.1, with le and hme network interfaces. It should be pretty + * generic, though. + */ + +/* + * Implementation notes: + * + * I first tried to write this code to the "vanilla" DLPI 2.0 API. + * It worked on a Sun Ultra-1 with a hme interface, but didn't work + * on Sun SparcStation 5's with "le" interfaces (the packets sent out + * via dlpiunitdatareq contained an Ethernet type of 0x0000 instead + * of the expected 0x0800). + * + * Therefore I added the "DLPI_RAW" code which is a Sun extension to + * the DLPI standard. This code works on both of the above machines. + * This is configurable in the OS-dependent include file by defining + * USE_DLPI_RAW. + * + * It quickly became apparant that I should also use the "pfmod" + * STREAMS module to cut down on the amount of user level packet + * processing. I don't know how widely available "pfmod" is, so it's + * use is conditionally included. This is configurable in the + * OS-dependent include file by defining USE_DLPI_PFMOD. + * + * A major quirk on the Sun's at least, is that no packets seem to get + * sent out the interface until six seconds after the interface is + * first "attached" to [per system reboot] (it's actually from when + * the interface is attached, not when it is plumbed, so putting a + * sleep into the dhclient-script at PREINIT time doesn't help). I + * HAVE tried, without success to poll the fd to see when it is ready + * for writing. This doesn't help at all. If the sleeps are not done, + * the initial DHCPREQUEST or DHCPDISCOVER never gets sent out, so + * I've put them here, when register_send and register_receive are + * called (split up into two three-second sleeps between the notices, + * so that it doesn't seem like so long when you're watching :-). The + * amount of time to sleep is configurable in the OS-dependent include + * file by defining DLPI_FIRST_SEND_WAIT to be the number of seconds + * to sleep. + */ + +#ifndef lint +static char copyright[] = +"$Id: dlpi.c,v 1.28 2001/04/05 20:53:01 mellon Exp $ Copyright (c) 1996-2000 The Internet Software Consortium. All rights reserved.\n"; +#endif /* not lint */ + +#include "dhcpd.h" + +#if defined (USE_DLPI_SEND) || defined (USE_DLPI_RECEIVE) + +# include <sys/ioctl.h> +# include <sys/time.h> +# include <sys/dlpi.h> +# include <stropts.h> +# ifdef USE_DLPI_PFMOD +# include <sys/pfmod.h> +# endif +# ifdef USE_POLL +# include <poll.h> +# endif + +# include <netinet/in_systm.h> +# include "includes/netinet/ip.h" +# include "includes/netinet/udp.h" +# include "includes/netinet/if_ether.h" + +# ifdef USE_DLPI_PFMOD +# ifdef USE_DLPI_RAW +# define DLPI_MODNAME "DLPI+RAW+PFMOD" +# else +# define DLPI_MODNAME "DLPI+PFMOD" +# endif +# else +# ifdef USE_DLPI_RAW +# define DLPI_MODNAME "DLPI+RAW" +# else +# define DLPI_MODNAME "DLPI" +# endif +# endif + +# ifndef ABS +# define ABS(x) ((x) >= 0 ? (x) : 0-(x)) +# endif + +static int strioctl PROTO ((int fd, int cmd, int timeout, int len, char *dp)); + +#define DLPI_MAXDLBUF 8192 /* Buffer size */ +#define DLPI_MAXDLADDR 1024 /* Max address size */ +#define DLPI_DEVDIR "/dev/" /* Device directory */ + +static int dlpiopen PROTO ((char *ifname)); +static int dlpiunit PROTO ((char *ifname)); +static int dlpiinforeq PROTO ((int fd)); +static int dlpiphysaddrreq PROTO ((int fd, unsigned long addrtype)); +static int dlpiattachreq PROTO ((int fd, unsigned long ppa)); +static int dlpibindreq PROTO ((int fd, unsigned long sap, unsigned long max_conind, + unsigned long service_mode, unsigned long conn_mgmt, + unsigned long xidtest)); +static int dlpidetachreq PROTO ((int fd)); +static int dlpiunbindreq PROTO ((int fd)); +static int dlpiokack PROTO ((int fd, char *bufp)); +static int dlpiinfoack PROTO ((int fd, char *bufp)); +static int dlpiphysaddrack PROTO ((int fd, char *bufp)); +static int dlpibindack PROTO ((int fd, char *bufp)); +static int dlpiunitdatareq PROTO ((int fd, unsigned char *addr, + int addrlen, unsigned long minpri, + unsigned long maxpri, unsigned char *data, + int datalen)); +static int dlpiunitdataind PROTO ((int fd, + unsigned char *dstaddr, + unsigned long *dstaddrlen, + unsigned char *srcaddr, + unsigned long *srcaddrlen, + unsigned long *grpaddr, + unsigned char *data, + int datalen)); + +# ifndef USE_POLL +static void sigalrm PROTO ((int sig)); +# endif +static int expected PROTO ((unsigned long prim, union DL_primitives *dlp, + int msgflags)); +static int strgetmsg PROTO ((int fd, struct strbuf *ctlp, + struct strbuf *datap, int *flagsp, + char *caller)); + +/* Reinitializes the specified interface after an address change. This + is not required for packet-filter APIs. */ + +#ifdef USE_DLPI_SEND +void if_reinitialize_send (info) + struct interface_info *info; +{ +} +#endif + +#ifdef USE_DLPI_RECEIVE +void if_reinitialize_receive (info) + struct interface_info *info; +{ +} +#endif + +/* Called by get_interface_list for each interface that's discovered. + Opens a packet filter for each interface and adds it to the select + mask. */ + +int if_register_dlpi (info) + struct interface_info *info; +{ + int sock; + int unit; + long buf [DLPI_MAXDLBUF]; + union DL_primitives *dlp; + + dlp = (union DL_primitives *)buf; + + /* Open a DLPI device */ + if ((sock = dlpiopen (info -> name)) < 0) { + log_fatal ("Can't open DLPI device for %s: %m", info -> name); + } + + + /* + * Submit a DL_INFO_REQ request, to find the dl_mac_type and + * dl_provider_style + */ + if (dlpiinforeq(sock) < 0 || dlpiinfoack(sock, (char *)buf) < 0) { + log_fatal ("Can't get DLPI MAC type for %s: %m", info -> name); + } else { + switch (dlp -> info_ack.dl_mac_type) { + case DL_CSMACD: /* IEEE 802.3 */ + case DL_ETHER: + info -> hw_address.hbuf [0] = HTYPE_ETHER; + break; + /* adding token ring 5/1999 - mayer@ping.at */ + case DL_TPR: + info -> hw_address.hbuf [0] = HTYPE_IEEE802; + break; + case DL_FDDI: + info -> hw_address.hbuf [0] = HTYPE_FDDI; + break; + default: + log_fatal ("%s: unsupported DLPI MAC type %ld", + info -> name, dlp -> info_ack.dl_mac_type); + break; + } + /* + * copy the sap length and broadcast address of this interface + * to interface_info. This fixes nothing but seemed nicer than to + * assume -2 and ffffff. + */ + info -> dlpi_sap_length = dlp -> info_ack.dl_sap_length; + info -> dlpi_broadcast_addr.hlen = + dlp -> info_ack.dl_brdcst_addr_length; + memcpy (info -> dlpi_broadcast_addr.hbuf, + (char *)dlp + dlp -> info_ack.dl_brdcst_addr_offset, + dlp -> info_ack.dl_brdcst_addr_length); + } + + if (dlp -> info_ack.dl_provider_style == DL_STYLE2) { + /* + * Attach to the device. If this fails, the device + * does not exist. + */ + unit = dlpiunit (info -> name); + + if (dlpiattachreq (sock, unit) < 0 + || dlpiokack (sock, (char *)buf) < 0) { + log_fatal ("Can't attach DLPI device for %s: %m", info -> name); + } + } + + /* + * Bind to the IP service access point (SAP), connectionless (CLDLS). + */ + if (dlpibindreq (sock, ETHERTYPE_IP, 0, DL_CLDLS, 0, 0) < 0 + || dlpibindack (sock, (char *)buf) < 0) { + log_fatal ("Can't bind DLPI device for %s: %m", info -> name); + } + + /* + * Submit a DL_PHYS_ADDR_REQ request, to find + * the hardware address + */ + if (dlpiphysaddrreq (sock, DL_CURR_PHYS_ADDR) < 0 + || dlpiphysaddrack (sock, (char *)buf) < 0) { + log_fatal ("Can't get DLPI hardware address for %s: %m", + info -> name); + } + + info -> hw_address.hlen = dlp -> physaddr_ack.dl_addr_length + 1; + memcpy (&info -> hw_address.hbuf [1], + (char *)buf + dlp -> physaddr_ack.dl_addr_offset, + dlp -> physaddr_ack.dl_addr_length); + +#ifdef USE_DLPI_RAW + if (strioctl (sock, DLIOCRAW, INFTIM, 0, 0) < 0) { + log_fatal ("Can't set DLPI RAW mode for %s: %m", + info -> name); + } +#endif + +#ifdef USE_DLPI_PFMOD + if (ioctl (sock, I_PUSH, "pfmod") < 0) { + log_fatal ("Can't push packet filter onto DLPI for %s: %m", + info -> name); + } +#endif + + return sock; +} + +static int +strioctl (fd, cmd, timeout, len, dp) +int fd; +int cmd; +int timeout; +int len; +char *dp; +{ + struct strioctl sio; + int rslt; + + sio.ic_cmd = cmd; + sio.ic_timout = timeout; + sio.ic_len = len; + sio.ic_dp = dp; + + if ((rslt = ioctl (fd, I_STR, &sio)) < 0) { + return rslt; + } else { + return sio.ic_len; + } +} + +#ifdef USE_DLPI_SEND +void if_register_send (info) + struct interface_info *info; +{ + /* If we're using the DLPI API for sending and receiving, + we don't need to register this interface twice. */ +#ifndef USE_DLPI_RECEIVE +# ifdef USE_DLPI_PFMOD + struct packetfilt pf; +# endif + + info -> wfdesc = if_register_dlpi (info); + +# ifdef USE_DLPI_PFMOD + /* Set up an PFMOD filter that rejects everything... */ + pf.Pf_Priority = 0; + pf.Pf_FilterLen = 1; + pf.Pf_Filter [0] = ENF_PUSHZERO; + + /* Install the filter */ + if (strioctl (info -> wfdesc, PFIOCSETF, INFTIM, + sizeof (pf), (char *)&pf) < 0) { + log_fatal ("Can't set PFMOD send filter on %s: %m", info -> name); + } + +# endif /* USE_DLPI_PFMOD */ +#else /* !defined (USE_DLPI_RECEIVE) */ + /* + * If using DLPI for both send and receive, simply re-use + * the read file descriptor that was set up earlier. + */ + info -> wfdesc = info -> rfdesc; +#endif + + if (!quiet_interface_discovery) + log_info ("Sending on DLPI/%s/%s%s%s", + info -> name, + print_hw_addr (info -> hw_address.hbuf [0], + info -> hw_address.hlen - 1, + &info -> hw_address.hbuf [1]), + (info -> shared_network ? "/" : ""), + (info -> shared_network ? + info -> shared_network -> name : "")); + +#ifdef DLPI_FIRST_SEND_WAIT +/* See the implementation notes at the beginning of this file */ +# ifdef USE_DLPI_RECEIVE + sleep (DLPI_FIRST_SEND_WAIT - (DLPI_FIRST_SEND_WAIT / 2)); +# else + sleep (DLPI_FIRST_SEND_WAIT); +# endif +#endif +} + +void if_deregister_send (info) + struct interface_info *info; +{ + /* If we're using the DLPI API for sending and receiving, + we don't need to register this interface twice. */ +#ifndef USE_DLPI_RECEIVE + close (info -> wfdesc); +#endif + info -> wfdesc = -1; + + if (!quiet_interface_discovery) + log_info ("Disabling output on DLPI/%s/%s%s%s", + info -> name, + print_hw_addr (info -> hw_address.hbuf [0], + info -> hw_address.hlen - 1, + &info -> hw_address.hbuf [1]), + (info -> shared_network ? "/" : ""), + (info -> shared_network ? + info -> shared_network -> name : "")); +} +#endif /* USE_DLPI_SEND */ + +#ifdef USE_DLPI_RECEIVE +/* Packet filter program... + XXX Changes to the filter program may require changes to the constant + offsets used in if_register_send to patch the NIT program! XXX */ + +void if_register_receive (info) + struct interface_info *info; +{ +#ifdef USE_DLPI_PFMOD + struct packetfilt pf; + struct ip iphdr; + u_int16_t offset; +#endif + + /* Open a DLPI device and hang it on this interface... */ + info -> rfdesc = if_register_dlpi (info); + +#ifdef USE_DLPI_PFMOD + /* Set up the PFMOD filter program. */ + /* XXX Unlike the BPF filter program, this one won't work if the + XXX IP packet is fragmented or if there are options on the IP + XXX header. */ + pf.Pf_Priority = 0; + pf.Pf_FilterLen = 0; + +#if defined (USE_DLPI_RAW) +# define ETHER_H_PREFIX (14) /* sizeof (ethernet_header) */ + /* + * ethertype == ETHERTYPE_IP + */ + offset = 12; + pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + (offset / 2); + pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_CAND; + pf.Pf_Filter [pf.Pf_FilterLen++] = htons (ETHERTYPE_IP); +# else +# define ETHER_H_PREFIX (0) +# endif /* USE_DLPI_RAW */ + /* + * The packets that will be received on this file descriptor + * will be IP packets (due to the SAP that was specified in + * the dlbind call). There will be no ethernet header. + * Therefore, setup the packet filter to check the protocol + * field for UDP, and the destination port number equal + * to the local port. All offsets are relative to the start + * of an IP packet. + */ + + /* + * BOOTPS destination port + */ + offset = ETHER_H_PREFIX + sizeof (iphdr) + sizeof (u_int16_t); + pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + (offset / 2); + pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_CAND; + pf.Pf_Filter [pf.Pf_FilterLen++] = local_port; + + /* + * protocol should be udp. this is a byte compare, test for + * endianess. + */ + offset = ETHER_H_PREFIX + ((u_int8_t *)&(iphdr.ip_p) - (u_int8_t *)&iphdr); + pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + (offset / 2); + pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_AND; + pf.Pf_Filter [pf.Pf_FilterLen++] = htons (0x00FF); + pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT | ENF_CAND; + pf.Pf_Filter [pf.Pf_FilterLen++] = htons (IPPROTO_UDP); + + /* Install the filter... */ + if (strioctl (info -> rfdesc, PFIOCSETF, INFTIM, + sizeof (pf), (char *)&pf) < 0) { + log_fatal ("Can't set PFMOD receive filter on %s: %m", info -> name); + } +#endif /* USE_DLPI_PFMOD */ + + if (!quiet_interface_discovery) + log_info ("Listening on DLPI/%s/%s%s%s", + info -> name, + print_hw_addr (info -> hw_address.hbuf [0], + info -> hw_address.hlen - 1, + &info -> hw_address.hbuf [1]), + (info -> shared_network ? "/" : ""), + (info -> shared_network ? + info -> shared_network -> name : "")); + +#ifdef DLPI_FIRST_SEND_WAIT +/* See the implementation notes at the beginning of this file */ +# ifdef USE_DLPI_SEND + sleep (DLPI_FIRST_SEND_WAIT / 2); +# else + sleep (DLPI_FIRST_SEND_WAIT); +# endif +#endif +} + +void if_deregister_receive (info) + struct interface_info *info; +{ + /* If we're using the DLPI API for sending and receiving, + we don't need to register this interface twice. */ +#ifndef USE_DLPI_SEND + close (info -> rfdesc); +#endif + info -> rfdesc = -1; + + if (!quiet_interface_discovery) + log_info ("Disabling input on DLPI/%s/%s%s%s", + info -> name, + print_hw_addr (info -> hw_address.hbuf [0], + info -> hw_address.hlen - 1, + &info -> hw_address.hbuf [1]), + (info -> shared_network ? "/" : ""), + (info -> shared_network ? + info -> shared_network -> name : "")); +} +#endif /* USE_DLPI_RECEIVE */ + +#ifdef USE_DLPI_SEND +ssize_t send_packet (interface, packet, raw, len, from, to, hto) + struct interface_info *interface; + struct packet *packet; + struct dhcp_packet *raw; + size_t len; + struct in_addr from; + struct sockaddr_in *to; + struct hardware *hto; +{ + unsigned hbufp = 0; + double hh [32]; + double ih [1536 / sizeof (double)]; + unsigned char *dbuf = (unsigned char *)ih; + unsigned dbuflen; + unsigned char dstaddr [DLPI_MAXDLADDR]; + unsigned addrlen; + int result; + int fudge; + + if (!strcmp (interface -> name, "fallback")) + return send_fallback (interface, packet, raw, + len, from, to, hto); + + dbuflen = 0; + + /* Assemble the headers... */ +#ifdef USE_DLPI_RAW + assemble_hw_header (interface, (unsigned char *)hh, &dbuflen, hto); + if (dbuflen > sizeof hh) + log_fatal ("send_packet: hh buffer too small.\n"); + fudge = dbuflen % 4; /* IP header must be word-aligned. */ + memcpy (dbuf + fudge, (unsigned char *)hh, dbuflen); + dbuflen += fudge; +#else + fudge = 0; +#endif + assemble_udp_ip_header (interface, dbuf, &dbuflen, from.s_addr, + to -> sin_addr.s_addr, to -> sin_port, + (unsigned char *)raw, len); + + /* Copy the data into the buffer (yuk). */ + memcpy (dbuf + dbuflen, raw, len); + dbuflen += len; + +#ifdef USE_DLPI_RAW + result = write (interface -> wfdesc, dbuf + fudge, dbuflen - fudge); +#else + + /* + * Setup the destination address (DLSAP) in dstaddr + * + * If sap_length < 0 we must deliver the DLSAP as phys+sap. + * If sap_length > 0 we must deliver the DLSAP as sap+phys. + * + * sap = Service Access Point == ETHERTYPE_IP + * sap + datalink address is called DLSAP in dlpi speak. + */ + { /* ENCODE DLSAP */ + unsigned char phys [DLPI_MAXDLADDR]; + unsigned char sap [4]; + int sap_len = interface -> dlpi_sap_length; + int phys_len = interface -> hw_address.hlen - 1; + + /* sap = htons (ETHERTYPE_IP) kludge */ + memset (sap, 0, sizeof (sap)); +# if (BYTE_ORDER == LITTLE_ENDIAN) + sap [0] = 0x00; + sap [1] = 0x08; +# else + sap [0] = 0x08; + sap [1] = 0x00; +# endif + + if (hto && hto -> hlen == interface -> hw_address.hlen) + memcpy ( phys, (char *) &hto -> hbuf [1], phys_len); + else + memcpy ( phys, interface -> dlpi_broadcast_addr.hbuf, + interface -> dlpi_broadcast_addr.hlen); + + if (sap_len < 0) { + memcpy ( dstaddr, phys, phys_len); + memcpy ( (char *) &dstaddr [phys_len], sap, ABS (sap_len)); + } + else { + memcpy ( dstaddr, (void *) sap, sap_len); + memcpy ( (char *) &dstaddr [sap_len], phys, phys_len); + } + addrlen = phys_len + ABS (sap_len); + } /* ENCODE DLSAP */ + + result = dlpiunitdatareq (interface -> wfdesc, dstaddr, addrlen, + 0, 0, dbuf, dbuflen); +#endif /* USE_DLPI_RAW */ + if (result < 0) + log_error ("send_packet: %m"); + return result; +} +#endif /* USE_DLPI_SEND */ + +#ifdef USE_DLPI_RECEIVE +ssize_t receive_packet (interface, buf, len, from, hfrom) + struct interface_info *interface; + unsigned char *buf; + size_t len; + struct sockaddr_in *from; + struct hardware *hfrom; +{ + unsigned char dbuf [1536]; + unsigned char srcaddr [DLPI_MAXDLADDR]; + unsigned long srcaddrlen; + int flags = 0; + int length = 0; + int offset = 0; + int rslt; + int bufix = 0; + +#ifdef USE_DLPI_RAW + length = read (interface -> rfdesc, dbuf, sizeof (dbuf)); +#else + length = dlpiunitdataind (interface -> rfdesc, (unsigned char *)NULL, + (unsigned long *)NULL, srcaddr, &srcaddrlen, + (unsigned long *)NULL, dbuf, sizeof (dbuf)); +#endif + + if (length <= 0) { + return length; + } + +# if !defined (USE_DLPI_RAW) + /* + * Copy the sender's hw address into hfrom + * If sap_len < 0 the DLSAP is as phys+sap. + * If sap_len > 0 the DLSAP is as sap+phys. + * + * sap is discarded here. + */ + { /* DECODE DLSAP */ + int sap_len = interface -> dlpi_sap_length; + int phys_len = interface -> hw_address.hlen - 1; + + if (hfrom && (srcaddrlen == ABS (sap_len) + phys_len )) { + hfrom -> hbuf [0] = interface -> hw_address.hbuf [0]; + hfrom -> hlen = interface -> hw_address.hlen; + + if (sap_len < 0) { + memcpy ((char *) &hfrom -> hbuf [1], srcaddr, phys_len); + } + else { + memcpy ((char *) &hfrom -> hbuf [1], (char *) &srcaddr [phys_len], + phys_len); + } + } + else if (hfrom) { + memset (hfrom, '\0', sizeof *hfrom); + } + } /* DECODE_DLSAP */ + +# endif /* !defined (USE_DLPI_RAW) */ + + /* Decode the IP and UDP headers... */ + bufix = 0; +#ifdef USE_DLPI_RAW + /* Decode the physical header... */ + offset = decode_hw_header (interface, dbuf, bufix, hfrom); + + /* If a physical layer checksum failed (dunno of any + physical layer that supports this, but WTH), skip this + packet. */ + if (offset < 0) { + return 0; + } + bufix += offset; + length -= offset; +#endif + offset = decode_udp_ip_header (interface, dbuf, bufix, + from, (unsigned char *)0, length); + + /* If the IP or UDP checksum was bad, skip the packet... */ + if (offset < 0) { + return 0; + } + + bufix += offset; + length -= offset; + + /* Copy out the data in the packet... */ + memcpy (buf, &dbuf [bufix], length); + return length; +} +#endif + +/* Common DLPI routines ... + * + * Written by Eric James Negaard, <lmdejn@lmd.ericsson.se> + * + * Based largely in part to the example code contained in the document + * "How to Use the STREAMS Data Link Provider Interface (DLPI)", written + * by Neal Nuckolls of SunSoft Internet Engineering. + * + * This code has been developed and tested on sparc-based machines running + * SunOS 5.5.1, with le and hme network interfaces. It should be pretty + * generic, though. + * + * The usual disclaimers apply. This code works for me. Don't blame me + * if it makes your machine or network go down in flames. That taken + * into consideration, use this code as you wish. If you make usefull + * modifications I'd appreciate hearing about it. + */ + +#define DLPI_MAXWAIT 15 /* Max timeout */ + + +/* + * Parse an interface name and extract the unit number + */ + +static int dlpiunit (ifname) + char *ifname; +{ + int fd; + char *cp, *dp, *ep; + int unit; + + if (!ifname) { + return 0; + } + + /* Advance to the end of the name */ + cp = ifname; + while (*cp) cp++; + /* Back up to the start of the first digit */ + while ((*(cp-1) >= '0' && *(cp-1) <= '9') || *(cp - 1) == ':') cp--; + + /* Convert the unit number */ + unit = 0; + while (*cp >= '0' && *cp <= '9') { + unit *= 10; + unit += (*cp++ - '0'); + } + + return unit; +} + +/* + * dlpiopen - open the DLPI device for a given interface name + */ +static int dlpiopen (ifname) + char *ifname; +{ + char devname [50]; + char *cp, *dp, *ep; + + if (!ifname) { + return -1; + } + + /* Open a DLPI device */ + if (*ifname == '/') { + dp = devname; + } else { + /* Prepend the device directory */ + memcpy (devname, DLPI_DEVDIR, strlen (DLPI_DEVDIR)); + dp = &devname [strlen (DLPI_DEVDIR)]; + } + + /* Find the end of the interface name */ + ep = cp = ifname; + while (*ep) + ep++; + /* And back up to the first digit (unit number) */ + while ((*(ep - 1) >= '0' && *(ep - 1) <= '9') || *(ep - 1) == ':') + ep--; + + /* Copy everything up to the unit number */ + while (cp < ep) { + *dp++ = *cp++; + } + *dp = '\0'; + + return open (devname, O_RDWR, 0); +} + +/* + * dlpiinforeq - request information about the data link provider. + */ + +static int dlpiinforeq (fd) + int fd; +{ + dl_info_req_t info_req; + struct strbuf ctl; + int flags; + + info_req.dl_primitive = DL_INFO_REQ; + + ctl.maxlen = 0; + ctl.len = sizeof (info_req); + ctl.buf = (char *)&info_req; + + flags = RS_HIPRI; + + return putmsg (fd, &ctl, (struct strbuf *)NULL, flags); +} + +/* + * dlpiphysaddrreq - request the current physical address. + */ +static int dlpiphysaddrreq (fd, addrtype) + int fd; + unsigned long addrtype; +{ + dl_phys_addr_req_t physaddr_req; + struct strbuf ctl; + int flags; + + physaddr_req.dl_primitive = DL_PHYS_ADDR_REQ; + physaddr_req.dl_addr_type = addrtype; + + ctl.maxlen = 0; + ctl.len = sizeof (physaddr_req); + ctl.buf = (char *)&physaddr_req; + + flags = RS_HIPRI; + + return putmsg (fd, &ctl, (struct strbuf *)NULL, flags); +} + +/* + * dlpiattachreq - send a request to attach to a specific unit. + */ +static int dlpiattachreq (fd, ppa) + unsigned long ppa; + int fd; +{ + dl_attach_req_t attach_req; + struct strbuf ctl; + int flags; + + attach_req.dl_primitive = DL_ATTACH_REQ; + attach_req.dl_ppa = ppa; + + ctl.maxlen = 0; + ctl.len = sizeof (attach_req); + ctl.buf = (char *)&attach_req; + + flags = 0; + + return putmsg (fd, &ctl, (struct strbuf*)NULL, flags); +} + +/* + * dlpibindreq - send a request to bind to a specific SAP address. + */ +static int dlpibindreq (fd, sap, max_conind, service_mode, conn_mgmt, xidtest) + unsigned long sap; + unsigned long max_conind; + unsigned long service_mode; + unsigned long conn_mgmt; + unsigned long xidtest; + int fd; +{ + dl_bind_req_t bind_req; + struct strbuf ctl; + int flags; + + bind_req.dl_primitive = DL_BIND_REQ; + bind_req.dl_sap = sap; + bind_req.dl_max_conind = max_conind; + bind_req.dl_service_mode = service_mode; + bind_req.dl_conn_mgmt = conn_mgmt; + bind_req.dl_xidtest_flg = xidtest; + + ctl.maxlen = 0; + ctl.len = sizeof (bind_req); + ctl.buf = (char *)&bind_req; + + flags = 0; + + return putmsg (fd, &ctl, (struct strbuf*)NULL, flags); +} + +/* + * dlpiunbindreq - send a request to unbind. + */ +static int dlpiunbindreq (fd) + int fd; +{ + dl_unbind_req_t unbind_req; + struct strbuf ctl; + int flags; + + unbind_req.dl_primitive = DL_UNBIND_REQ; + + ctl.maxlen = 0; + ctl.len = sizeof (unbind_req); + ctl.buf = (char *)&unbind_req; + + flags = 0; + + return putmsg (fd, &ctl, (struct strbuf*)NULL, flags); +} + + +/* + * dlpidetachreq - send a request to detach. + */ +static int dlpidetachreq (fd) + int fd; +{ + dl_detach_req_t detach_req; + struct strbuf ctl; + int flags; + + detach_req.dl_primitive = DL_DETACH_REQ; + + ctl.maxlen = 0; + ctl.len = sizeof (detach_req); + ctl.buf = (char *)&detach_req; + + flags = 0; + + return putmsg (fd, &ctl, (struct strbuf*)NULL, flags); +} + + +/* + * dlpibindack - receive an ack to a dlbindreq. + */ +static int dlpibindack (fd, bufp) + char *bufp; + int fd; +{ + union DL_primitives *dlp; + struct strbuf ctl; + int flags; + + ctl.maxlen = DLPI_MAXDLBUF; + ctl.len = 0; + ctl.buf = bufp; + + if (strgetmsg (fd, &ctl, + (struct strbuf*)NULL, &flags, "dlpibindack") < 0) { + return -1; + } + + dlp = (union DL_primitives *)ctl.buf; + + if (!expected (DL_BIND_ACK, dlp, flags) < 0) { + return -1; + } + + if (ctl.len < sizeof (dl_bind_ack_t)) { + /* Returned structure is too short */ + return -1; + } + + return 0; +} + +/* + * dlpiokack - general acknowledgement reception. + */ +static int dlpiokack (fd, bufp) + char *bufp; + int fd; +{ + union DL_primitives *dlp; + struct strbuf ctl; + int flags; + + ctl.maxlen = DLPI_MAXDLBUF; + ctl.len = 0; + ctl.buf = bufp; + + if (strgetmsg (fd, &ctl, + (struct strbuf*)NULL, &flags, "dlpiokack") < 0) { + return -1; + } + + dlp = (union DL_primitives *)ctl.buf; + + if (!expected (DL_OK_ACK, dlp, flags) < 0) { + return -1; + } + + if (ctl.len < sizeof (dl_ok_ack_t)) { + /* Returned structure is too short */ + return -1; + } + + return 0; +} + +/* + * dlpiinfoack - receive an ack to a dlinforeq. + */ +static int dlpiinfoack (fd, bufp) + char *bufp; + int fd; +{ + union DL_primitives *dlp; + struct strbuf ctl; + int flags; + + ctl.maxlen = DLPI_MAXDLBUF; + ctl.len = 0; + ctl.buf = bufp; + + if (strgetmsg (fd, &ctl, (struct strbuf *)NULL, &flags, + "dlpiinfoack") < 0) { + return -1; + } + + dlp = (union DL_primitives *) ctl.buf; + + if (!expected (DL_INFO_ACK, dlp, flags) < 0) { + return -1; + } + + if (ctl.len < sizeof (dl_info_ack_t)) { + /* Returned structure is too short */ + return -1; + } + + return 0; +} + +/* + * dlpiphysaddrack - receive an ack to a dlpiphysaddrreq. + */ +int dlpiphysaddrack (fd, bufp) + char *bufp; + int fd; +{ + union DL_primitives *dlp; + struct strbuf ctl; + int flags; + + ctl.maxlen = DLPI_MAXDLBUF; + ctl.len = 0; + ctl.buf = bufp; + + if (strgetmsg (fd, &ctl, (struct strbuf *)NULL, &flags, + "dlpiphysaddrack") < 0) { + return -1; + } + + dlp = (union DL_primitives *)ctl.buf; + + if (!expected (DL_PHYS_ADDR_ACK, dlp, flags) < 0) { + return -1; + } + + if (ctl.len < sizeof (dl_phys_addr_ack_t)) { + /* Returned structure is too short */ + return -1; + } + + return 0; +} + +int dlpiunitdatareq (fd, addr, addrlen, minpri, maxpri, dbuf, dbuflen) + int fd; + unsigned char *addr; + int addrlen; + unsigned long minpri; + unsigned long maxpri; + unsigned char *dbuf; + int dbuflen; +{ + long buf [DLPI_MAXDLBUF]; + union DL_primitives *dlp; + struct strbuf ctl, data; + + /* Set up the control information... */ + dlp = (union DL_primitives *)buf; + dlp -> unitdata_req.dl_primitive = DL_UNITDATA_REQ; + dlp -> unitdata_req.dl_dest_addr_length = addrlen; + dlp -> unitdata_req.dl_dest_addr_offset = sizeof (dl_unitdata_req_t); + dlp -> unitdata_req.dl_priority.dl_min = minpri; + dlp -> unitdata_req.dl_priority.dl_max = maxpri; + + /* Append the destination address */ + memcpy ((char *)buf + dlp -> unitdata_req.dl_dest_addr_offset, + addr, addrlen); + + ctl.maxlen = 0; + ctl.len = dlp -> unitdata_req.dl_dest_addr_offset + addrlen; + ctl.buf = (char *)buf; + + data.maxlen = 0; + data.buf = (char *)dbuf; + data.len = dbuflen; + + /* Send the packet down the wire... */ + return putmsg (fd, &ctl, &data, 0); +} + +static int dlpiunitdataind (fd, daddr, daddrlen, + saddr, saddrlen, grpaddr, dbuf, dlen) + int fd; + unsigned char *daddr; + unsigned long *daddrlen; + unsigned char *saddr; + unsigned long *saddrlen; + unsigned long *grpaddr; + unsigned char *dbuf; + int dlen; +{ + long buf [DLPI_MAXDLBUF]; + union DL_primitives *dlp; + struct strbuf ctl, data; + int flags = 0; + int result; + + /* Set up the msg_buf structure... */ + dlp = (union DL_primitives *)buf; + dlp -> unitdata_ind.dl_primitive = DL_UNITDATA_IND; + + ctl.maxlen = DLPI_MAXDLBUF; + ctl.len = 0; + ctl.buf = (char *)buf; + + data.maxlen = dlen; + data.len = 0; + data.buf = (char *)dbuf; + + result = getmsg (fd, &ctl, &data, &flags); + + if (result != 0) { + return -1; + } + + if (ctl.len < sizeof (dl_unitdata_ind_t) || + dlp -> unitdata_ind.dl_primitive != DL_UNITDATA_IND) { + return -1; + } + + if (data.len <= 0) { + return data.len; + } + + /* Copy sender info */ + if (saddr) { + memcpy (saddr, + (char *)buf + dlp -> unitdata_ind.dl_src_addr_offset, + dlp -> unitdata_ind.dl_src_addr_length); + } + if (saddrlen) { + *saddrlen = dlp -> unitdata_ind.dl_src_addr_length; + } + + /* Copy destination info */ + if (daddr) { + memcpy (daddr, + (char *)buf + dlp -> unitdata_ind.dl_dest_addr_offset, + dlp -> unitdata_ind.dl_dest_addr_length); + } + if (daddrlen) { + *daddrlen = dlp -> unitdata_ind.dl_dest_addr_length; + } + + if (grpaddr) { + *grpaddr = dlp -> unitdata_ind.dl_group_address; + } + + return data.len; +} + +/* + * expected - see if we got what we wanted. + */ +static int expected (prim, dlp, msgflags) + unsigned long prim; + union DL_primitives *dlp; + int msgflags; +{ + if (msgflags != RS_HIPRI) { + /* Message was not M_PCPROTO */ + return 0; + } + + if (dlp -> dl_primitive != prim) { + /* Incorrect/unexpected return message */ + return 0; + } + + return 1; +} + +/* + * strgetmsg - get a message from a stream, with timeout. + */ +static int strgetmsg (fd, ctlp, datap, flagsp, caller) + struct strbuf *ctlp, *datap; + char *caller; + int *flagsp; + int fd; +{ + int result; +#ifdef USE_POLL + struct pollfd pfd; + int count; + time_t now; + time_t starttime; + int to_msec; +#endif + +#ifdef USE_POLL + pfd.fd = fd; + pfd.events = POLLPRI; /* We're only interested in knowing + * when we can receive the next high + * priority message. + */ + pfd.revents = 0; + + now = time (&starttime); + while (now <= starttime + DLPI_MAXWAIT) { + to_msec = ((starttime + DLPI_MAXWAIT) - now) * 1000; + count = poll (&pfd, 1, to_msec); + + if (count == 0) { + /* log_fatal ("strgetmsg: timeout"); */ + return -1; + } else if (count < 0) { + if (errno == EAGAIN || errno == EINTR) { + time (&now); + continue; + } else { + /* log_fatal ("poll: %m"); */ + return -1; + } + } else { + break; + } + } +#else /* defined (USE_POLL) */ + /* + * Start timer. Can't use select, since it might return true if there + * were non High-Priority data available on the stream. + */ + (void) sigset (SIGALRM, sigalrm); + + if (alarm (DLPI_MAXWAIT) < 0) { + /* log_fatal ("alarm: %m"); */ + return -1; + } +#endif /* !defined (USE_POLL) */ + + /* + * Set flags argument and issue getmsg (). + */ + *flagsp = 0; + if ((result = getmsg (fd, ctlp, datap, flagsp)) < 0) { + return result; + } + +#ifndef USE_POLL + /* + * Stop timer. + */ + if (alarm (0) < 0) { + /* log_fatal ("alarm: %m"); */ + return -1; + } +#endif + + /* + * Check for MOREDATA and/or MORECTL. + */ + if (result & (MORECTL|MOREDATA)) { + return -1; + } + + /* + * Check for at least sizeof (long) control data portion. + */ + if (ctlp -> len < sizeof (long)) { + return -1; + } + + return 0; +} + +#ifndef USE_POLL +/* + * sigalrm - handle alarms. + */ +static void sigalrm (sig) + int sig; +{ + fprintf (stderr, "strgetmsg: timeout"); + exit (1); +} +#endif /* !defined (USE_POLL) */ + +int can_unicast_without_arp (ip) + struct interface_info *ip; +{ + return 1; +} + +int can_receive_unicast_unconfigured (ip) + struct interface_info *ip; +{ + return 1; +} + +int supports_multiple_interfaces (ip) + struct interface_info *ip; +{ + return 1; +} + +void maybe_setup_fallback () +{ + isc_result_t status; + struct interface_info *fbi = (struct interface_info *)0; + if (setup_fallback (&fbi, MDL)) { + if_register_fallback (fbi); + status = omapi_register_io_object ((omapi_object_t *)fbi, + if_readsocket, 0, + fallback_discard, 0, 0); + if (status != ISC_R_SUCCESS) + log_fatal ("Can't register I/O handle for %s: %s", + fbi -> name, isc_result_totext (status)); + interface_dereference (&fbi, MDL); + } +} +#endif /* USE_DLPI */ diff --git a/contrib/isc-dhcp/common/dns.c b/contrib/isc-dhcp/common/dns.c new file mode 100644 index 0000000..d529652 --- /dev/null +++ b/contrib/isc-dhcp/common/dns.c @@ -0,0 +1,943 @@ +/* dns.c + + Domain Name Service subroutines. */ + +/* + * Copyright (c) 2001 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon in cooperation with Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. + */ + +#ifndef lint +static char copyright[] = +"$Id: dns.c,v 1.35.2.10 2001/10/26 21:26:39 mellon Exp $ Copyright (c) 2001 The Internet Software Consortium. All rights reserved.\n"; +#endif /* not lint */ + +#include "dhcpd.h" +#include "arpa/nameser.h" +#include "dst/md5.h" + +/* This file is kind of a crutch for the BIND 8 nsupdate code, which has + * itself been cruelly hacked from its original state. What this code + * does is twofold: first, it maintains a database of zone cuts that can + * be used to figure out which server should be contacted to update any + * given domain name. Secondly, it maintains a set of named TSIG keys, + * and associates those keys with zones. When an update is requested for + * a particular zone, the key associated with that zone is used for the + * update. + * + * The way this works is that you define the domain name to which an + * SOA corresponds, and the addresses of some primaries for that domain name: + * + * zone FOO.COM { + * primary 10.0.17.1; + * secondary 10.0.22.1, 10.0.23.1; + * key "FOO.COM Key"; + * } + * + * If an update is requested for GAZANGA.TOPANGA.FOO.COM, then the name + * server looks in its database for a zone record for "GAZANGA.TOPANGA.FOO.COM", + * doesn't find it, looks for one for "TOPANGA.FOO.COM", doesn't find *that*, + * looks for "FOO.COM", finds it. So it + * attempts the update to the primary for FOO.COM. If that times out, it + * tries the secondaries. You can list multiple primaries if you have some + * kind of magic name server that supports that. You shouldn't list + * secondaries that don't know how to forward updates (e.g., BIND 8 doesn't + * support update forwarding, AFAIK). If no TSIG key is listed, the update + * is attempted without TSIG. + * + * The DHCP server tries to find an existing zone for any given name by + * trying to look up a local zone structure for each domain containing + * that name, all the way up to '.'. If it finds one cached, it tries + * to use that one to do the update. That's why it tries to update + * "FOO.COM" above, even though theoretically it should try GAZANGA... + * and TOPANGA... first. + * + * If the update fails with a predefined or cached zone (we'll get to + * those in a second), then it tries to find a more specific zone. This + * is done by looking first for an SOA for GAZANGA.TOPANGA.FOO.COM. Then + * an SOA for TOPANGA.FOO.COM is sought. If during this search a predefined + * or cached zone is found, the update fails - there's something wrong + * somewhere. + * + * If a more specific zone _is_ found, that zone is cached for the length of + * its TTL in the same database as that described above. TSIG updates are + * never done for cached zones - if you want TSIG updates you _must_ + * write a zone definition linking the key to the zone. In cases where you + * know for sure what the key is but do not want to hardcode the IP addresses + * of the primary or secondaries, a zone declaration can be made that doesn't + * include any primary or secondary declarations. When the DHCP server + * encounters this while hunting up a matching zone for a name, it looks up + * the SOA, fills in the IP addresses, and uses that record for the update. + * If the SOA lookup returns NXRRSET, a warning is printed and the zone is + * discarded, TSIG key and all. The search for the zone then continues as if + * the zone record hadn't been found. Zones without IP addresses don't + * match when initially hunting for a predefined or cached zone to update. + * + * When an update is attempted and no predefined or cached zone is found + * that matches any enclosing domain of the domain being updated, the DHCP + * server goes through the same process that is done when the update to a + * predefined or cached zone fails - starting with the most specific domain + * name (GAZANGA.TOPANGA.FOO.COM) and moving to the least specific (the root), + * it tries to look up an SOA record. When it finds one, it creates a cached + * zone and attempts an update, and gives up if the update fails. + * + * TSIG keys are defined like this: + * + * key "FOO.COM Key" { + * algorithm HMAC-MD5.SIG-ALG.REG.INT; + * secret <Base64>; + * } + * + * <Base64> is a number expressed in base64 that represents the key. + * It's also permissible to use a quoted string here - this will be + * translated as the ASCII bytes making up the string, and will not + * include any NUL termination. The key name can be any text string, + * and the key type must be one of the key types defined in the draft + * or by the IANA. Currently only the HMAC-MD5... key type is + * supported. + */ + +dns_zone_hash_t *dns_zone_hash; + +#if defined (NSUPDATE) +isc_result_t find_tsig_key (ns_tsig_key **key, const char *zname, + struct dns_zone *zone) +{ + isc_result_t status; + ns_tsig_key *tkey; + + if (!zone) + return ISC_R_NOTFOUND; + + if (!zone -> key) { + return ISC_R_KEY_UNKNOWN; + } + + if ((!zone -> key -> name || + strlen (zone -> key -> name) > NS_MAXDNAME) || + (!zone -> key -> algorithm || + strlen (zone -> key -> algorithm) > NS_MAXDNAME) || + (!zone -> key) || + (!zone -> key -> key) || + (zone -> key -> key -> len == 0)) { + return ISC_R_INVALIDKEY; + } + tkey = dmalloc (sizeof *tkey, MDL); + if (!tkey) { + nomem: + return ISC_R_NOMEMORY; + } + memset (tkey, 0, sizeof *tkey); + tkey -> data = dmalloc (zone -> key -> key -> len, MDL); + if (!tkey -> data) { + dfree (tkey, MDL); + goto nomem; + } + strcpy (tkey -> name, zone -> key -> name); + strcpy (tkey -> alg, zone -> key -> algorithm); + memcpy (tkey -> data, + zone -> key -> key -> value, zone -> key -> key -> len); + tkey -> len = zone -> key -> key -> len; + *key = tkey; + return ISC_R_SUCCESS; +} + +void tkey_free (ns_tsig_key **key) +{ + if ((*key) -> data) + dfree ((*key) -> data, MDL); + dfree ((*key), MDL); + *key = (ns_tsig_key *)0; +} +#endif + +isc_result_t enter_dns_zone (struct dns_zone *zone) +{ + struct dns_zone *tz = (struct dns_zone *)0; + + if (dns_zone_hash) { + dns_zone_hash_lookup (&tz, + dns_zone_hash, zone -> name, 0, MDL); + if (tz == zone) { + dns_zone_dereference (&tz, MDL); + return ISC_R_SUCCESS; + } + if (tz) { + dns_zone_hash_delete (dns_zone_hash, + zone -> name, 0, MDL); + dns_zone_dereference (&tz, MDL); + } + } else { + if (!dns_zone_new_hash (&dns_zone_hash, 1, MDL)) + return ISC_R_NOMEMORY; + } + dns_zone_hash_add (dns_zone_hash, zone -> name, 0, zone, MDL); + return ISC_R_SUCCESS; +} + +isc_result_t dns_zone_lookup (struct dns_zone **zone, const char *name) +{ + struct dns_zone *tz = (struct dns_zone *)0; + int len; + char *tname = (char *)0; + isc_result_t status; + + if (!dns_zone_hash) + return ISC_R_NOTFOUND; + + len = strlen (name); + if (name [len - 1] != '.') { + tname = dmalloc ((unsigned)len + 2, MDL); + if (!tname) + return ISC_R_NOMEMORY;; + strcpy (tname, name); + tname [len] = '.'; + tname [len + 1] = 0; + name = tname; + } + if (!dns_zone_hash_lookup (zone, dns_zone_hash, name, 0, MDL)) + status = ISC_R_NOTFOUND; + else + status = ISC_R_SUCCESS; + + if (tname) + dfree (tname, MDL); + return status; +} + +int dns_zone_dereference (ptr, file, line) + struct dns_zone **ptr; + const char *file; + int line; +{ + int i; + struct dns_zone *dns_zone; + + if (!ptr || !*ptr) { + log_error ("%s(%d): null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + + dns_zone = *ptr; + *ptr = (struct dns_zone *)0; + --dns_zone -> refcnt; + rc_register (file, line, ptr, dns_zone, dns_zone -> refcnt, 1, RC_MISC); + if (dns_zone -> refcnt > 0) + return 1; + + if (dns_zone -> refcnt < 0) { + log_error ("%s(%d): negative refcnt!", file, line); +#if defined (DEBUG_RC_HISTORY) + dump_rc_history (dns_zone); +#endif +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + + if (dns_zone -> name) + dfree (dns_zone -> name, file, line); + if (dns_zone -> key) + omapi_auth_key_dereference (&dns_zone -> key, file, line); + if (dns_zone -> primary) + option_cache_dereference (&dns_zone -> primary, file, line); + if (dns_zone -> secondary) + option_cache_dereference (&dns_zone -> secondary, file, line); + dfree (dns_zone, file, line); + return 1; +} + +#if defined (NSUPDATE) +isc_result_t find_cached_zone (const char *dname, ns_class class, + char *zname, size_t zsize, + struct in_addr *addrs, + int naddrs, int *naddrout, + struct dns_zone **zcookie) +{ + isc_result_t status = ISC_R_NOTFOUND; + const char *np; + struct dns_zone *zone = (struct dns_zone *)0; + struct data_string nsaddrs; + int ix; + + /* The absence of the zcookie pointer indicates that we + succeeded previously, but the update itself failed, meaning + that we shouldn't use the cached zone. */ + if (!zcookie) + return ISC_R_NOTFOUND; + + /* We can't look up a null zone. */ + if (!dname || !*dname) + return ISC_R_INVALIDARG; + + /* For each subzone, try to find a cached zone. */ + for (np = dname; np; np = strchr (np, '.')) { + np++; + status = dns_zone_lookup (&zone, np); + if (status == ISC_R_SUCCESS) + break; + } + + if (status != ISC_R_SUCCESS) + return status; + + /* Make sure the zone is valid. */ + if (zone -> timeout && zone -> timeout < cur_time) { + dns_zone_dereference (&zone, MDL); + return ISC_R_CANCELED; + } + + /* Make sure the zone name will fit. */ + if (strlen (zone -> name) > zsize) { + dns_zone_dereference (&zone, MDL); + return ISC_R_NOSPACE; + } + strcpy (zname, zone -> name); + + memset (&nsaddrs, 0, sizeof nsaddrs); + ix = 0; + + if (zone -> primary) { + if (evaluate_option_cache (&nsaddrs, (struct packet *)0, + (struct lease *)0, + (struct client_state *)0, + (struct option_state *)0, + (struct option_state *)0, + &global_scope, + zone -> primary, MDL)) { + int ip = 0; + while (ix < naddrs) { + if (ip + 4 > nsaddrs.len) + break; + memcpy (&addrs [ix], &nsaddrs.data [ip], 4); + ip += 4; + ix++; + } + data_string_forget (&nsaddrs, MDL); + } + } + if (zone -> secondary) { + if (evaluate_option_cache (&nsaddrs, (struct packet *)0, + (struct lease *)0, + (struct client_state *)0, + (struct option_state *)0, + (struct option_state *)0, + &global_scope, + zone -> secondary, MDL)) { + int ip = 0; + while (ix < naddrs) { + if (ip + 4 > nsaddrs.len) + break; + memcpy (&addrs [ix], &nsaddrs.data [ip], 4); + ip += 4; + ix++; + } + data_string_forget (&nsaddrs, MDL); + } + } + + /* It's not an error for zcookie to have a value here - actually, + it's quite likely, because res_nupdate cycles through all the + names in the update looking for their zones. */ + if (!*zcookie) + dns_zone_reference (zcookie, zone, MDL); + dns_zone_dereference (&zone, MDL); + if (naddrout) + *naddrout = ix; + return ISC_R_SUCCESS; +} + +void forget_zone (struct dns_zone **zone) +{ + dns_zone_dereference (zone, MDL); +} + +void repudiate_zone (struct dns_zone **zone) +{ + /* XXX Currently we're not differentiating between a cached + XXX zone and a zone that's been repudiated, which means + XXX that if we reap cached zones, we blow away repudiated + XXX zones. This isn't a big problem since we're not yet + XXX caching zones... :'} */ + + (*zone) -> timeout = cur_time - 1; + dns_zone_dereference (zone, MDL); +} + +void cache_found_zone (ns_class class, + char *zname, struct in_addr *addrs, int naddrs) +{ + isc_result_t status = ISC_R_NOTFOUND; + struct dns_zone *zone = (struct dns_zone *)0; + struct data_string nsaddrs; + int ix = strlen (zname); + + if (zname [ix - 1] == '.') + ix = 0; + + /* See if there's already such a zone. */ + if (dns_zone_lookup (&zone, zname) == ISC_R_SUCCESS) { + /* If it's not a dynamic zone, leave it alone. */ + if (!zone -> timeout) + return; + /* Address may have changed, so just blow it away. */ + if (zone -> primary) + option_cache_dereference (&zone -> primary, MDL); + if (zone -> secondary) + option_cache_dereference (&zone -> secondary, MDL); + } else if (!dns_zone_allocate (&zone, MDL)) + return; + + if (!zone -> name) { + zone -> name = + dmalloc (strlen (zname) + 1 + (ix != 0), MDL); + if (!zone -> name) { + dns_zone_dereference (&zone, MDL); + return; + } + strcpy (zone -> name, zname); + /* Add a trailing '.' if it was missing. */ + if (ix) { + zone -> name [ix] = '.'; + zone -> name [ix + 1] = 0; + } + } + + /* XXX Need to get the lower-level code to push the actual zone + XXX TTL up to us. */ + zone -> timeout = cur_time + 1800; + + if (!option_cache_allocate (&zone -> primary, MDL)) { + dns_zone_dereference (&zone, MDL); + return; + } + if (!buffer_allocate (&zone -> primary -> data.buffer, + naddrs * sizeof (struct in_addr), MDL)) { + dns_zone_dereference (&zone, MDL); + return; + } + memcpy (zone -> primary -> data.buffer -> data, + addrs, naddrs * sizeof *addrs); + zone -> primary -> data.data = + &zone -> primary -> data.buffer -> data [0]; + zone -> primary -> data.len = naddrs * sizeof *addrs; + + enter_dns_zone (zone); +} + +/* Have to use TXT records for now. */ +#define T_DHCID T_TXT + +int get_dhcid (struct data_string *id, + int type, const u_int8_t *data, unsigned len) +{ + unsigned char buf[MD5_DIGEST_LENGTH]; + MD5_CTX md5; + int i; + + /* Types can only be 0..(2^16)-1. */ + if (type < 0 || type > 65535) + return 0; + + /* Hexadecimal MD5 digest plus two byte type and NUL. */ + if (!buffer_allocate (&id -> buffer, + (MD5_DIGEST_LENGTH * 2) + 3, MDL)) + return 0; + id -> data = id -> buffer -> data; + + /* + * DHCP clients and servers should use the following forms of client + * identification, starting with the most preferable, and finishing + * with the least preferable. If the client does not send any of these + * forms of identification, the DHCP/DDNS interaction is not defined by + * this specification. The most preferable form of identification is + * the Globally Unique Identifier Option [TBD]. Next is the DHCP + * Client Identifier option. Last is the client's link-layer address, + * as conveyed in its DHCPREQUEST message. Implementors should note + * that the link-layer address cannot be used if there are no + * significant bytes in the chaddr field of the DHCP client's request, + * because this does not constitute a unique identifier. + * -- "Interaction between DHCP and DNS" + * <draft-ietf-dhc-dhcp-dns-12.txt> + * M. Stapp, Y. Rekhter + */ + + /* Put the type in the first two bytes. */ + id -> buffer -> data [0] = "0123456789abcdef" [type >> 4]; + id -> buffer -> data [1] = "0123456789abcdef" [type % 15]; + + /* Mash together an MD5 hash of the identifier. */ + MD5_Init (&md5); + MD5_Update (&md5, data, len); + MD5_Final (buf, &md5); + + /* Convert into ASCII. */ + for (i = 0; i < MD5_DIGEST_LENGTH; i++) { + id -> buffer -> data [i * 2 + 2] = + "0123456789abcdef" [(buf [i] >> 4) & 0xf]; + id -> buffer -> data [i * 2 + 3] = + "0123456789abcdef" [buf [i] & 0xf]; + } + id -> len = MD5_DIGEST_LENGTH * 2 + 2; + id -> buffer -> data [id -> len] = 0; + id -> terminated = 1; + + return 1; +} + +/* Now for the DDNS update code that is shared between client and + server... */ + +isc_result_t ddns_update_a (struct data_string *ddns_fwd_name, + struct iaddr ddns_addr, + struct data_string *ddns_dhcid, + unsigned long ttl, int rrsetp) +{ + ns_updque updqueue; + ns_updrec *updrec; + isc_result_t result; + char ddns_address [16]; + + if (ddns_addr.len != 4) + return ISC_R_INVALIDARG; +#ifndef NO_SNPRINTF + snprintf (ddns_address, 16, "%d.%d.%d.%d", + ddns_addr.iabuf[0], ddns_addr.iabuf[1], + ddns_addr.iabuf[2], ddns_addr.iabuf[3]); +#else + sprintf (ddns_address, "%d.%d.%d.%d", + ddns_addr.iabuf[0], ddns_addr.iabuf[1], + ddns_addr.iabuf[2], ddns_addr.iabuf[3]); +#endif + + /* + * When a DHCP client or server intends to update an A RR, it first + * prepares a DNS UPDATE query which includes as a prerequisite the + * assertion that the name does not exist. The update section of the + * query attempts to add the new name and its IP address mapping (an A + * RR), and the DHCID RR with its unique client-identity. + * -- "Interaction between DHCP and DNS" + */ + + ISC_LIST_INIT (updqueue); + + /* + * A RR does not exist. + */ + updrec = minires_mkupdrec (S_PREREQ, + (const char *)ddns_fwd_name -> data, + C_IN, T_A, 0); + if (!updrec) { + result = ISC_R_NOMEMORY; + goto error; + } + + updrec -> r_data = (unsigned char *)0; + updrec -> r_size = 0; + updrec -> r_opcode = rrsetp ? NXRRSET : NXDOMAIN; + + ISC_LIST_APPEND (updqueue, updrec, r_link); + + + /* + * Add A RR. + */ + updrec = minires_mkupdrec (S_UPDATE, + (const char *)ddns_fwd_name -> data, + C_IN, T_A, ttl); + if (!updrec) { + result = ISC_R_NOMEMORY; + goto error; + } + + updrec -> r_data = (unsigned char *)ddns_address; + updrec -> r_size = strlen (ddns_address); + updrec -> r_opcode = ADD; + + ISC_LIST_APPEND (updqueue, updrec, r_link); + + + /* + * Add DHCID RR. + */ + updrec = minires_mkupdrec (S_UPDATE, + (const char *)ddns_fwd_name -> data, + C_IN, T_DHCID, ttl); + if (!updrec) { + result = ISC_R_NOMEMORY; + goto error; + } + + updrec -> r_data = ddns_dhcid -> data; + updrec -> r_size = ddns_dhcid -> len; + updrec -> r_opcode = ADD; + + ISC_LIST_APPEND (updqueue, updrec, r_link); + + + /* + * Attempt to perform the update. + */ + result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updqueue)); + + print_dns_status ((int)result, &updqueue); + + while (!ISC_LIST_EMPTY (updqueue)) { + updrec = ISC_LIST_HEAD (updqueue); + ISC_LIST_UNLINK (updqueue, updrec, r_link); + minires_freeupdrec (updrec); + } + + + /* + * If this update operation succeeds, the updater can conclude that it + * has added a new name whose only RRs are the A and DHCID RR records. + * The A RR update is now complete (and a client updater is finished, + * while a server might proceed to perform a PTR RR update). + * -- "Interaction between DHCP and DNS" + */ + + if (result == ISC_R_SUCCESS) + return result; + + + /* + * If the first update operation fails with YXDOMAIN, the updater can + * conclude that the intended name is in use. The updater then + * attempts to confirm that the DNS name is not being used by some + * other host. The updater prepares a second UPDATE query in which the + * prerequisite is that the desired name has attached to it a DHCID RR + * whose contents match the client identity. The update section of + * this query deletes the existing A records on the name, and adds the + * A record that matches the DHCP binding and the DHCID RR with the + * client identity. + * -- "Interaction between DHCP and DNS" + */ + + if (result != (rrsetp ? ISC_R_YXRRSET : ISC_R_YXDOMAIN)) + return result; + + + /* + * DHCID RR exists, and matches client identity. + */ + updrec = minires_mkupdrec (S_PREREQ, + (const char *)ddns_fwd_name -> data, + C_IN, T_DHCID, 0); + if (!updrec) { + result = ISC_R_NOMEMORY; + goto error; + } + + updrec -> r_data = ddns_dhcid -> data; + updrec -> r_size = ddns_dhcid -> len; + updrec -> r_opcode = YXRRSET; + + ISC_LIST_APPEND (updqueue, updrec, r_link); + + + /* + * Delete A RRset. + */ + updrec = minires_mkupdrec (S_UPDATE, + (const char *)ddns_fwd_name -> data, + C_IN, T_A, 0); + if (!updrec) { + result = ISC_R_NOMEMORY; + goto error; + } + + updrec -> r_data = (unsigned char *)0; + updrec -> r_size = 0; + updrec -> r_opcode = DELETE; + + ISC_LIST_APPEND (updqueue, updrec, r_link); + + + /* + * Add A RR. + */ + updrec = minires_mkupdrec (S_UPDATE, + (const char *)ddns_fwd_name -> data, + C_IN, T_A, ttl); + if (!updrec) { + result = ISC_R_NOMEMORY; + goto error; + } + + updrec -> r_data = (unsigned char *)ddns_address; + updrec -> r_size = strlen (ddns_address); + updrec -> r_opcode = ADD; + + ISC_LIST_APPEND (updqueue, updrec, r_link); + + + /* + * Attempt to perform the update. + */ + result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updqueue)); + + print_dns_status ((int)result, &updqueue); + + /* + * If this query succeeds, the updater can conclude that the current + * client was the last client associated with the domain name, and that + * the name now contains the updated A RR. The A RR update is now + * complete (and a client updater is finished, while a server would + * then proceed to perform a PTR RR update). + * -- "Interaction between DHCP and DNS" + */ + + /* + * If the second query fails with NXRRSET, the updater must conclude + * that the client's desired name is in use by another host. At this + * juncture, the updater can decide (based on some administrative + * configuration outside of the scope of this document) whether to let + * the existing owner of the name keep that name, and to (possibly) + * perform some name disambiguation operation on behalf of the current + * client, or to replace the RRs on the name with RRs that represent + * the current client. If the configured policy allows replacement of + * existing records, the updater submits a query that deletes the + * existing A RR and the existing DHCID RR, adding A and DHCID RRs that + * represent the IP address and client-identity of the new client. + * -- "Interaction between DHCP and DNS" + */ + + error: + while (!ISC_LIST_EMPTY (updqueue)) { + updrec = ISC_LIST_HEAD (updqueue); + ISC_LIST_UNLINK (updqueue, updrec, r_link); + minires_freeupdrec (updrec); + } + + return result; +} + +isc_result_t ddns_remove_a (struct data_string *ddns_fwd_name, + struct iaddr ddns_addr, + struct data_string *ddns_dhcid) +{ + ns_updque updqueue; + ns_updrec *updrec; + isc_result_t result = SERVFAIL; + char ddns_address [16]; + + if (ddns_addr.len != 4) + return ISC_R_INVALIDARG; + +#ifndef NO_SNPRINTF + snprintf (ddns_address, 16, "%d.%d.%d.%d", + ddns_addr.iabuf[0], ddns_addr.iabuf[1], + ddns_addr.iabuf[2], ddns_addr.iabuf[3]); +#else + sprintf (ddns_address, "%d.%d.%d.%d", + ddns_addr.iabuf[0], ddns_addr.iabuf[1], + ddns_addr.iabuf[2], ddns_addr.iabuf[3]); +#endif + + + /* + * The entity chosen to handle the A record for this client (either the + * client or the server) SHOULD delete the A record that was added when + * the lease was made to the client. + * + * In order to perform this delete, the updater prepares an UPDATE + * query which contains two prerequisites. The first prerequisite + * asserts that the DHCID RR exists whose data is the client identity + * described in Section 4.3. The second prerequisite asserts that the + * data in the A RR contains the IP address of the lease that has + * expired or been released. + * -- "Interaction between DHCP and DNS" + */ + + ISC_LIST_INIT (updqueue); + + /* + * DHCID RR exists, and matches client identity. + */ + updrec = minires_mkupdrec (S_PREREQ, + (const char *)ddns_fwd_name -> data, + C_IN, T_DHCID,0); + if (!updrec) { + result = ISC_R_NOMEMORY; + goto error; + } + + updrec -> r_data = ddns_dhcid -> data; + updrec -> r_size = ddns_dhcid -> len; + updrec -> r_opcode = YXRRSET; + + ISC_LIST_APPEND (updqueue, updrec, r_link); + + + /* + * A RR matches the expiring lease. + */ + updrec = minires_mkupdrec (S_PREREQ, + (const char *)ddns_fwd_name -> data, + C_IN, T_A, 0); + if (!updrec) { + result = ISC_R_NOMEMORY; + goto error; + } + + updrec -> r_data = (unsigned char *)ddns_address; + updrec -> r_size = strlen (ddns_address); + updrec -> r_opcode = YXRRSET; + + ISC_LIST_APPEND (updqueue, updrec, r_link); + + + /* + * Delete appropriate A RR. + */ + updrec = minires_mkupdrec (S_UPDATE, + (const char *)ddns_fwd_name -> data, + C_IN, T_A, 0); + if (!updrec) { + result = ISC_R_NOMEMORY; + goto error; + } + + updrec -> r_data = (unsigned char *)ddns_address; + updrec -> r_size = strlen (ddns_address); + updrec -> r_opcode = DELETE; + + ISC_LIST_APPEND (updqueue, updrec, r_link); + + /* + * Attempt to perform the update. + */ + result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updqueue)); + print_dns_status ((int)result, &updqueue); + + /* + * If the query fails, the updater MUST NOT delete the DNS name. It + * may be that the host whose lease on the server has expired has moved + * to another network and obtained a lease from a different server, + * which has caused the client's A RR to be replaced. It may also be + * that some other client has been configured with a name that matches + * the name of the DHCP client, and the policy was that the last client + * to specify the name would get the name. In this case, the DHCID RR + * will no longer match the updater's notion of the client-identity of + * the host pointed to by the DNS name. + * -- "Interaction between DHCP and DNS" + */ + + if (result != ISC_R_SUCCESS) { + /* If the rrset isn't there, we didn't need to do the + delete, which is success. */ + if (result == ISC_R_NXRRSET || result == ISC_R_NXDOMAIN) + result = ISC_R_SUCCESS; + goto error; + } + + while (!ISC_LIST_EMPTY (updqueue)) { + updrec = ISC_LIST_HEAD (updqueue); + ISC_LIST_UNLINK (updqueue, updrec, r_link); + minires_freeupdrec (updrec); + } + + /* If the deletion of the A succeeded, and there are no A records + left for this domain, then we can blow away the DHCID record + as well. We can't blow away the DHCID record above because + it's possible that more than one A has been added to this + domain name. */ + ISC_LIST_INIT (updqueue); + + /* + * A RR does not exist. + */ + updrec = minires_mkupdrec (S_PREREQ, + (const char *)ddns_fwd_name -> data, + C_IN, T_A, 0); + if (!updrec) { + result = ISC_R_NOMEMORY; + goto error; + } + + updrec -> r_data = (unsigned char *)0; + updrec -> r_size = 0; + updrec -> r_opcode = NXRRSET; + + ISC_LIST_APPEND (updqueue, updrec, r_link); + + /* + * Delete appropriate DHCID RR. + */ + updrec = minires_mkupdrec (S_UPDATE, + (const char *)ddns_fwd_name -> data, + C_IN, T_DHCID, 0); + if (!updrec) { + result = ISC_R_NOMEMORY; + goto error; + } + + updrec -> r_data = ddns_dhcid -> data; + updrec -> r_size = ddns_dhcid -> len; + updrec -> r_opcode = DELETE; + + ISC_LIST_APPEND (updqueue, updrec, r_link); + + /* + * Attempt to perform the update. + */ + result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updqueue)); + print_dns_status ((int)result, &updqueue); + + /* Fall through. */ + error: + + while (!ISC_LIST_EMPTY (updqueue)) { + updrec = ISC_LIST_HEAD (updqueue); + ISC_LIST_UNLINK (updqueue, updrec, r_link); + minires_freeupdrec (updrec); + } + + return result; +} + + +#endif /* NSUPDATE */ + +HASH_FUNCTIONS (dns_zone, const char *, struct dns_zone, dns_zone_hash_t, + dns_zone_reference, dns_zone_dereference) diff --git a/contrib/isc-dhcp/common/ethernet.c b/contrib/isc-dhcp/common/ethernet.c index 41c0a30..309084a 100644 --- a/contrib/isc-dhcp/common/ethernet.c +++ b/contrib/isc-dhcp/common/ethernet.c @@ -1,9 +1,9 @@ -/* packet.c +/* ethernet.c Packet assembly code, originally contributed by Archie Cobbs. */ /* - * Copyright (c) 1995, 1996 The Internet Software Consortium. + * Copyright (c) 1996-2000 Internet Software Consortium. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,15 +34,16 @@ * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium - * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie - * Enterprises. To learn more about the Internet Software Consortium, - * see ``http://www.vix.com/isc''. To learn more about Vixie - * Enterprises, see ``http://www.vix.com''. + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. */ #ifndef lint static char copyright[] = -"$Id: ethernet.c,v 1.1.2.2 1999/11/11 16:10:41 mellon Exp $ Copyright (c) 1996 The Internet Software Consortium. All rights reserved.\n"; +"$Id: ethernet.c,v 1.6.2.1 2001/06/14 19:15:27 mellon Exp $ Copyright (c) 1996-2000 The Internet Software Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -53,31 +54,27 @@ static char copyright[] = #if defined (PACKET_ASSEMBLY) /* Assemble an hardware header... */ -/* XXX currently only supports ethernet; doesn't check for other types. */ void assemble_ethernet_header (interface, buf, bufix, to) struct interface_info *interface; unsigned char *buf; - int *bufix; + unsigned *bufix; struct hardware *to; { - struct ether_header eh; + struct isc_ether_header eh; - if (to && to -> hlen == 6) /* XXX */ - memcpy (eh.ether_dhost, to -> haddr, sizeof eh.ether_dhost); + if (to && to -> hlen == 7) /* XXX */ + memcpy (eh.ether_dhost, &to -> hbuf [1], + sizeof eh.ether_dhost); else memset (eh.ether_dhost, 0xff, sizeof (eh.ether_dhost)); - if (interface -> hw_address.hlen == sizeof (eh.ether_shost)) - memcpy (eh.ether_shost, interface -> hw_address.haddr, + if (interface -> hw_address.hlen - 1 == sizeof (eh.ether_shost)) + memcpy (eh.ether_shost, &interface -> hw_address.hbuf [1], sizeof (eh.ether_shost)); else memset (eh.ether_shost, 0x00, sizeof (eh.ether_shost)); -#ifdef BROKEN_FREEBSD_BPF /* Fixed in FreeBSD 2.2 */ - eh.ether_type = ETHERTYPE_IP; -#else eh.ether_type = htons (ETHERTYPE_IP); -#endif memcpy (&buf [*bufix], &eh, ETHER_HEADER_SIZE); *bufix += ETHER_HEADER_SIZE; @@ -90,10 +87,10 @@ void assemble_ethernet_header (interface, buf, bufix, to) ssize_t decode_ethernet_header (interface, buf, bufix, from) struct interface_info *interface; unsigned char *buf; - int bufix; + unsigned bufix; struct hardware *from; { - struct ether_header eh; + struct isc_ether_header eh; memcpy (&eh, buf + bufix, ETHER_HEADER_SIZE); @@ -101,10 +98,10 @@ ssize_t decode_ethernet_header (interface, buf, bufix, from) if (ntohs (eh.ether_type) != ETHERTYPE_IP) return -1; #endif - memcpy (from -> haddr, eh.ether_shost, sizeof (eh.ether_shost)); - from -> htype = ARPHRD_ETHER; - from -> hlen = sizeof eh.ether_shost; + memcpy (&from -> hbuf [1], eh.ether_shost, sizeof (eh.ether_shost)); + from -> hbuf [0] = ARPHRD_ETHER; + from -> hlen = (sizeof eh.ether_shost) + 1; - return sizeof eh; + return ETHER_HEADER_SIZE; } #endif /* PACKET_DECODING */ diff --git a/contrib/isc-dhcp/common/execute.c b/contrib/isc-dhcp/common/execute.c new file mode 100644 index 0000000..ec4b22e --- /dev/null +++ b/contrib/isc-dhcp/common/execute.c @@ -0,0 +1,1061 @@ +/* execute.c + + Support for executable statements. */ + +/* + * Copyright (c) 1998-2001 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. + */ + +#ifndef lint +static char copyright[] = +"$Id: execute.c,v 1.44.2.8 2001/10/18 20:10:58 mellon Exp $ Copyright (c) 1998-2000 The Internet Software Consortium. All rights reserved.\n"; +#endif /* not lint */ + +#include "dhcpd.h" +#include <omapip/omapip_p.h> + +int execute_statements (result, packet, lease, client_state, + in_options, out_options, scope, statements) + struct binding_value **result; + struct packet *packet; + struct lease *lease; + struct client_state *client_state; + struct option_state *in_options; + struct option_state *out_options; + struct binding_scope **scope; + struct executable_statement *statements; +{ + struct executable_statement *r, *e, *next; + int rc; + int status; + unsigned long num; + struct binding_scope *outer; + struct binding *binding; + struct data_string ds; + struct binding_scope *ns; + + if (!statements) + return 1; + + r = (struct executable_statement *)0; + next = (struct executable_statement *)0; + e = (struct executable_statement *)0; + executable_statement_reference (&r, statements, MDL); + while (r && !(result && *result)) { + if (r -> next) + executable_statement_reference (&next, r -> next, MDL); + switch (r -> op) { + case statements_statement: +#if defined (DEBUG_EXPRESSIONS) + log_debug ("exec: statements"); +#endif + status = execute_statements (result, packet, lease, + client_state, in_options, + out_options, scope, + r -> data.statements); +#if defined (DEBUG_EXPRESSIONS) + log_debug ("exec: statements returns %d", status); +#endif + if (!status) + return 0; + break; + + case on_statement: + if (lease) { + if (r -> data.on.evtypes & ON_EXPIRY) { +#if defined (DEBUG_EXPRESSIONS) + log_debug ("exec: on expiry"); +#endif + if (lease -> on_expiry) + executable_statement_dereference + (&lease -> on_expiry, MDL); + if (r -> data.on.statements) + executable_statement_reference + (&lease -> on_expiry, + r -> data.on.statements, MDL); + } + if (r -> data.on.evtypes & ON_RELEASE) { +#if defined (DEBUG_EXPRESSIONS) + log_debug ("exec: on release"); +#endif + if (lease -> on_release) + executable_statement_dereference + (&lease -> on_release, MDL); + if (r -> data.on.statements) + executable_statement_reference + (&lease -> on_release, + r -> data.on.statements, MDL); + } + if (r -> data.on.evtypes & ON_COMMIT) { +#if defined (DEBUG_EXPRESSIONS) + log_debug ("exec: on commit"); +#endif + if (lease -> on_commit) + executable_statement_dereference + (&lease -> on_commit, MDL); + if (r -> data.on.statements) + executable_statement_reference + (&lease -> on_commit, + r -> data.on.statements, MDL); + } + } + break; + + case switch_statement: +#if defined (DEBUG_EXPRESSIONS) + log_debug ("exec: switch"); +#endif + status = (find_matching_case + (&e, packet, lease, client_state, + in_options, out_options, scope, + r -> data.s_switch.expr, + r -> data.s_switch.statements)); +#if defined (DEBUG_EXPRESSIONS) + log_debug ("exec: switch: case %lx", (unsigned long)e); +#endif + if (status) { + if (!(execute_statements + (result, packet, lease, client_state, + in_options, out_options, scope, e))) { + executable_statement_dereference + (&e, MDL); + return 0; + } + executable_statement_dereference (&e, MDL); + } + break; + + /* These have no effect when executed. */ + case case_statement: + case default_statement: + break; + + case if_statement: + status = (evaluate_boolean_expression + (&rc, packet, + lease, client_state, in_options, + out_options, scope, r -> data.ie.expr)); + +#if defined (DEBUG_EXPRESSIONS) + log_debug ("exec: if %s", (status + ? (rc ? "true" : "false") + : "NULL")); +#endif + /* XXX Treat NULL as false */ + if (!status) + rc = 0; + if (!execute_statements + (result, packet, lease, client_state, + in_options, out_options, scope, + rc ? r -> data.ie.tc : r -> data.ie.fc)) + return 0; + break; + + case eval_statement: + status = evaluate_expression + ((struct binding_value **)0, + packet, lease, client_state, in_options, + out_options, scope, r -> data.eval, MDL); +#if defined (DEBUG_EXPRESSIONS) + log_debug ("exec: evaluate: %s", + (status ? "succeeded" : "failed")); +#endif + break; + + case return_statement: + status = evaluate_expression + (result, packet, + lease, client_state, in_options, + out_options, scope, r -> data.retval, MDL); +#if defined (DEBUG_EXPRESSIONS) + log_debug ("exec: return: %s", + (status ? "succeeded" : "failed")); +#endif + break; + + case add_statement: +#if defined (DEBUG_EXPRESSIONS) + log_debug ("exec: add %s", (r -> data.add -> name + ? r -> data.add -> name + : "<unnamed class>")); +#endif + classify (packet, r -> data.add); + break; + + case break_statement: +#if defined (DEBUG_EXPRESSIONS) + log_debug ("exec: break"); +#endif + return 1; + + case supersede_option_statement: + case send_option_statement: +#if defined (DEBUG_EXPRESSIONS) + log_debug ("exec: %s option %s.%s", + (r -> op == supersede_option_statement + ? "supersede" : "send"), + r -> data.option -> option -> universe -> name, + r -> data.option -> option -> name); + goto option_statement; +#endif + case default_option_statement: +#if defined (DEBUG_EXPRESSIONS) + log_debug ("exec: default option %s.%s", + r -> data.option -> option -> universe -> name, + r -> data.option -> option -> name); + goto option_statement; +#endif + case append_option_statement: +#if defined (DEBUG_EXPRESSIONS) + log_debug ("exec: append option %s.%s", + r -> data.option -> option -> universe -> name, + r -> data.option -> option -> name); + goto option_statement; +#endif + case prepend_option_statement: +#if defined (DEBUG_EXPRESSIONS) + log_debug ("exec: prepend option %s.%s", + r -> data.option -> option -> universe -> name, + r -> data.option -> option -> name); + option_statement: +#endif + set_option (r -> data.option -> option -> universe, + out_options, r -> data.option, r -> op); + break; + + case set_statement: + case define_statement: + if (!scope) { + log_error ("set %s: no scope", + r -> data.set.name); + status = 0; + break; + } + if (!*scope) { + if (!binding_scope_allocate (scope, MDL)) { + log_error ("set %s: can't allocate scope", + r -> data.set.name); + status = 0; + break; + } + } + binding = find_binding (*scope, r -> data.set.name); +#if defined (DEBUG_EXPRESSIONS) + log_debug ("exec: set %s", r -> data.set.name); +#endif + if (!binding) { + binding = dmalloc (sizeof *binding, MDL); + if (binding) { + memset (binding, 0, sizeof *binding); + binding -> name = + dmalloc (strlen + (r -> data.set.name) + 1, + MDL); + if (binding -> name) { + strcpy (binding -> name, + r -> data.set.name); + binding -> next = (*scope) -> bindings; + (*scope) -> bindings = binding; + } else { + badalloc: + dfree (binding, MDL); + binding = (struct binding *)0; + } + } + } + if (binding) { + if (binding -> value) + binding_value_dereference + (&binding -> value, MDL); + if (r -> op == set_statement) { + status = (evaluate_expression + (&binding -> value, packet, + lease, client_state, + in_options, out_options, + scope, r -> data.set.expr, + MDL)); + } else { + if (!(binding_value_allocate + (&binding -> value, MDL))) { + dfree (binding, MDL); + binding = (struct binding *)0; + } + if (binding -> value) { + binding -> value -> type = + binding_function; + (fundef_reference + (&binding -> value -> value.fundef, + r -> data.set.expr -> data.func, + MDL)); + } + } + } +#if defined (DEBUG_EXPRESSIONS) + log_debug ("exec: set %s%s", r -> data.set.name, + (binding && status ? "" : " (failed)")); +#endif + break; + + case unset_statement: + if (!scope || !*scope) { + status = 0; + break; + } + binding = find_binding (*scope, r -> data.unset); + if (binding) { + if (binding -> value) + binding_value_dereference + (&binding -> value, MDL); + status = 1; + } else + status = 0; +#if defined (DEBUG_EXPRESSIONS) + log_debug ("exec: unset %s: %s", r -> data.unset, + (status ? "found" : "not found")); +#endif + break; + + case let_statement: +#if defined (DEBUG_EXPRESSIONS) + log_debug ("exec: let %s", r -> data.let.name); +#endif + ns = (struct binding_scope *)0; + binding_scope_allocate (&ns, MDL); + e = r; + + next_let: + if (ns) { + binding = dmalloc (sizeof *binding, MDL); + memset (binding, 0, sizeof *binding); + if (!binding) { + blb: + binding_scope_dereference (&ns, MDL); + } else { + binding -> name = + dmalloc (strlen + (e -> data.let.name + 1), + MDL); + if (binding -> name) + strcpy (binding -> name, + e -> data.let.name); + else { + dfree (binding, MDL); + binding = (struct binding *)0; + goto blb; + } + } + } + if (ns && binding) { + status = (evaluate_expression + (&binding -> value, packet, lease, + client_state, + in_options, out_options, + scope, e -> data.set.expr, MDL)); + binding -> next = ns -> bindings; + ns -> bindings = binding; + } + +#if defined (DEBUG_EXPRESSIONS) + log_debug ("exec: let %s%s", e -> data.let.name, + (binding && status ? "" : "failed")); +#endif + if (!e -> data.let.statements) { + } else if (e -> data.let.statements -> op == + let_statement) { + e = e -> data.let.statements; + goto next_let; + } else if (ns) { + if (scope && *scope) + binding_scope_reference (&ns -> outer, + *scope, MDL); + execute_statements + (result, packet, lease, + client_state, + in_options, out_options, + &ns, e -> data.let.statements); + } + if (ns) + binding_scope_dereference (&ns, MDL); + break; + + case log_statement: + memset (&ds, 0, sizeof ds); + status = (evaluate_data_expression + (&ds, packet, + lease, client_state, in_options, + out_options, scope, r -> data.log.expr, + MDL)); + +#if defined (DEBUG_EXPRESSIONS) + log_debug ("exec: log"); +#endif + + if (status) { + switch (r -> data.log.priority) { + case log_priority_fatal: + log_fatal ("%.*s", (int)ds.len, + ds.buffer -> data); + break; + case log_priority_error: + log_error ("%.*s", (int)ds.len, + ds.buffer -> data); + break; + case log_priority_debug: + log_debug ("%.*s", (int)ds.len, + ds.buffer -> data); + break; + case log_priority_info: + log_info ("%.*s", (int)ds.len, + ds.buffer -> data); + break; + } + data_string_forget (&ds, MDL); + } + + break; + + default: + log_error ("bogus statement type %d", r -> op); + break; + } + executable_statement_dereference (&r, MDL); + if (next) { + executable_statement_reference (&r, next, MDL); + executable_statement_dereference (&next, MDL); + } + } + + return 1; +} + +/* Execute all the statements in a particular scope, and all statements in + scopes outer from that scope, but if a particular limiting scope is + reached, do not execute statements in that scope or in scopes outer + from it. More specific scopes need to take precedence over less + specific scopes, so we recursively traverse the scope list, executing + the most outer scope first. */ + +void execute_statements_in_scope (result, packet, + lease, client_state, in_options, out_options, + scope, group, limiting_group) + struct binding_value **result; + struct packet *packet; + struct lease *lease; + struct client_state *client_state; + struct option_state *in_options; + struct option_state *out_options; + struct binding_scope **scope; + struct group *group; + struct group *limiting_group; +{ + struct group *limit; + + /* If we've recursed as far as we can, return. */ + if (!group) + return; + + /* As soon as we get to a scope that is outer than the limiting + scope, we are done. This is so that if somebody does something + like this, it does the expected thing: + + domain-name "fugue.com"; + shared-network FOO { + host bar { + domain-name "othello.fugue.com"; + fixed-address 10.20.30.40; + } + subnet 10.20.30.0 netmask 255.255.255.0 { + domain-name "manhattan.fugue.com"; + } + } + + The problem with the above arrangement is that the host's + group nesting will be host -> shared-network -> top-level, + and the limiting scope when we evaluate the host's scope + will be the subnet -> shared-network -> top-level, so we need + to know when we evaluate the host's scope to stop before we + evaluate the shared-networks scope, because it's outer than + the limiting scope, which means we've already evaluated it. */ + + for (limit = limiting_group; limit; limit = limit -> next) { + if (group == limit) + return; + } + + if (group -> next) + execute_statements_in_scope (result, packet, + lease, client_state, + in_options, out_options, scope, + group -> next, limiting_group); + execute_statements (result, packet, lease, client_state, in_options, + out_options, scope, group -> statements); +} + +/* Dereference or free any subexpressions of a statement being freed. */ + +int executable_statement_dereference (ptr, file, line) + struct executable_statement **ptr; + const char *file; + int line; +{ + struct executable_statement *bp; + + if (!ptr || !*ptr) { + log_error ("%s(%d): null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + + (*ptr) -> refcnt--; + rc_register (file, line, ptr, *ptr, (*ptr) -> refcnt, 1, RC_MISC); + if ((*ptr) -> refcnt > 0) { + *ptr = (struct executable_statement *)0; + return 1; + } + + if ((*ptr) -> refcnt < 0) { + log_error ("%s(%d): negative refcnt!", file, line); +#if defined (DEBUG_RC_HISTORY) + dump_rc_history (*ptr); +#endif +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + + if ((*ptr) -> next) + executable_statement_dereference (&(*ptr) -> next, file, line); + + switch ((*ptr) -> op) { + case statements_statement: + if ((*ptr) -> data.statements) + executable_statement_dereference + (&(*ptr) -> data.statements, file, line); + break; + + case on_statement: + if ((*ptr) -> data.on.statements) + executable_statement_dereference + (&(*ptr) -> data.on.statements, file, line); + break; + + case switch_statement: + if ((*ptr) -> data.s_switch.statements) + executable_statement_dereference + (&(*ptr) -> data.on.statements, file, line); + if ((*ptr) -> data.s_switch.expr) + expression_dereference (&(*ptr) -> data.s_switch.expr, + file, line); + break; + + case case_statement: + if ((*ptr) -> data.s_switch.expr) + expression_dereference (&(*ptr) -> data.c_case, + file, line); + break; + + case if_statement: + if ((*ptr) -> data.ie.expr) + expression_dereference (&(*ptr) -> data.ie.expr, + file, line); + if ((*ptr) -> data.ie.tc) + executable_statement_dereference + (&(*ptr) -> data.ie.tc, file, line); + if ((*ptr) -> data.ie.fc) + executable_statement_dereference + (&(*ptr) -> data.ie.fc, file, line); + break; + + case eval_statement: + if ((*ptr) -> data.eval) + expression_dereference (&(*ptr) -> data.eval, + file, line); + break; + + case return_statement: + if ((*ptr) -> data.eval) + expression_dereference (&(*ptr) -> data.eval, + file, line); + break; + + case set_statement: + if ((*ptr)->data.set.name) + dfree ((*ptr)->data.set.name, file, line); + if ((*ptr)->data.set.expr) + expression_dereference (&(*ptr) -> data.set.expr, + file, line); + break; + + case unset_statement: + if ((*ptr)->data.unset) + dfree ((*ptr)->data.unset, file, line); + break; + + case supersede_option_statement: + case send_option_statement: + case default_option_statement: + case append_option_statement: + case prepend_option_statement: + if ((*ptr) -> data.option) + option_cache_dereference (&(*ptr) -> data.option, + file, line); + break; + + default: + /* Nothing to do. */ + break; + } + + dfree ((*ptr), file, line); + *ptr = (struct executable_statement *)0; + return 1; +} + +void write_statements (file, statements, indent) + FILE *file; + struct executable_statement *statements; + int indent; +{ + struct executable_statement *r, *x; + int result; + int status; + const char *s, *t, *dot; + int col; + + if (!statements) + return; + + for (r = statements; r; r = r -> next) { + switch (r -> op) { + case statements_statement: + write_statements (file, r -> data.statements, indent); + break; + + case on_statement: + indent_spaces (file, indent); + fprintf (file, "on "); + s = ""; + if (r -> data.on.evtypes & ON_EXPIRY) { + fprintf (file, "%sexpiry", s); + s = " or "; + } + if (r -> data.on.evtypes & ON_COMMIT) { + fprintf (file, "%scommit", s); + s = "or"; + } + if (r -> data.on.evtypes & ON_RELEASE) { + fprintf (file, "%srelease", s); + s = "or"; + } + if (r -> data.on.statements) { + fprintf (file, " {"); + write_statements (file, + r -> data.on.statements, + indent + 2); + indent_spaces (file, indent); + fprintf (file, "}"); + } else { + fprintf (file, ";"); + } + break; + + case switch_statement: + indent_spaces (file, indent); + fprintf (file, "switch ("); + col = write_expression (file, + r -> data.s_switch.expr, + indent + 7, indent + 7, 1); + col = token_print_indent (file, col, indent + 7, + "", "", ")"); + token_print_indent (file, + col, indent, " ", "", "{"); + write_statements (file, r -> data.s_switch.statements, + indent + 2); + indent_spaces (file, indent); + fprintf (file, "}"); + break; + + case case_statement: + indent_spaces (file, indent - 1); + fprintf (file, "case "); + col = write_expression (file, + r -> data.s_switch.expr, + indent + 5, indent + 5, 1); + token_print_indent (file, col, indent + 5, + "", "", ":"); + break; + + case default_statement: + indent_spaces (file, indent - 1); + fprintf (file, "default: "); + break; + + case if_statement: + indent_spaces (file, indent); + fprintf (file, "if "); + x = r; + col = write_expression (file, + x -> data.ie.expr, + indent + 3, indent + 3, 1); + else_if: + token_print_indent (file, col, indent, " ", "", "{"); + write_statements (file, x -> data.ie.tc, indent + 2); + if (x -> data.ie.fc && + x -> data.ie.fc -> op == if_statement && + !x -> data.ie.fc -> next) { + indent_spaces (file, indent); + fprintf (file, "} elsif "); + x = x -> data.ie.fc; + col = write_expression (file, + x -> data.ie.expr, + indent + 6, + indent + 6, 1); + goto else_if; + } + if (x -> data.ie.fc) { + indent_spaces (file, indent); + fprintf (file, "} else {"); + write_statements (file, x -> data.ie.fc, + indent + 2); + } + indent_spaces (file, indent); + fprintf (file, "}"); + break; + + case eval_statement: + indent_spaces (file, indent); + fprintf (file, "eval "); + col = write_expression (file, r -> data.eval, + indent + 5, indent + 5, 1); + fprintf (file, ";"); + break; + + case return_statement: + indent_spaces (file, indent); + fprintf (file, "return;"); + break; + + case add_statement: + indent_spaces (file, indent); + fprintf (file, "add \"%s\"", r -> data.add -> name); + break; + + case break_statement: + indent_spaces (file, indent); + fprintf (file, "break;"); + break; + + case supersede_option_statement: + case send_option_statement: + s = "supersede"; + goto option_statement; + + case default_option_statement: + s = "default"; + goto option_statement; + + case append_option_statement: + s = "append"; + goto option_statement; + + case prepend_option_statement: + s = "prepend"; + option_statement: + /* Note: the reason we don't try to pretty print + the option here is that the format of the option + may change in dhcpd.conf, and then when this + statement was read back, it would cause a syntax + error. */ + if (r -> data.option -> option -> universe == + &dhcp_universe) { + t = ""; + dot = ""; + } else { + t = (r -> data.option -> option -> + universe -> name); + dot = "."; + } + indent_spaces (file, indent); + fprintf (file, "%s %s%s%s = ", s, t, dot, + r -> data.option -> option -> name); + col = (indent + strlen (s) + strlen (t) + + strlen (dot) + strlen (r -> data.option -> + option -> name) + 4); + if (r -> data.option -> expression) + write_expression + (file, + r -> data.option -> expression, + col, indent + 8, 1); + else + token_indent_data_string + (file, col, indent + 8, "", "", + &r -> data.option -> data); + + fprintf (file, ";"); /* XXX */ + break; + + case set_statement: + indent_spaces (file, indent); + fprintf (file, "set "); + col = token_print_indent (file, indent + 4, indent + 4, + "", "", r -> data.set.name); + col = token_print_indent (file, col, indent + 4, + " ", " ", "="); + col = write_expression (file, r -> data.set.expr, + indent + 3, indent + 3, 0); + col = token_print_indent (file, col, indent + 4, + " ", "", ";"); + break; + + case unset_statement: + indent_spaces (file, indent); + fprintf (file, "unset "); + col = token_print_indent (file, indent + 6, indent + 6, + "", "", r -> data.set.name); + col = token_print_indent (file, col, indent + 6, + " ", "", ";"); + break; + + case log_statement: + indent_spaces (file, indent); + fprintf (file, "log "); + col = token_print_indent (file, col, indent + 4, + "", "", "("); + switch (r -> data.log.priority) { + case log_priority_fatal: + col = token_print_indent + (file, col, indent + 4, "", + " ", "fatal,"); + break; + case log_priority_error: + col = token_print_indent + (file, col, indent + 4, "", + " ", "error,"); + break; + case log_priority_debug: + col = token_print_indent + (file, col, indent + 4, "", + " ", "debug,"); + break; + case log_priority_info: + col = token_print_indent + (file, col, indent + 4, "", + " ", "info,"); + break; + } + col = write_expression (file, r -> data.log.expr, + indent + 4, indent + 4, 0); + col = token_print_indent (file, col, indent + 4, + "", "", ");"); + + break; + + default: + log_fatal ("bogus statement type %d\n", r -> op); + } + } +} + +/* Find a case statement in the sequence of executable statements that + matches the expression, and if found, return the following statement. + If no case statement matches, try to find a default statement and + return that (the default statement can precede all the case statements). + Otherwise, return the null statement. */ + +int find_matching_case (struct executable_statement **ep, + struct packet *packet, struct lease *lease, + struct client_state *client_state, + struct option_state *in_options, + struct option_state *out_options, + struct binding_scope **scope, + struct expression *expr, + struct executable_statement *stmt) +{ + int status, sub; + struct executable_statement *s; + unsigned long foo; + + if (is_data_expression (expr)) { + struct executable_statement *e; + struct data_string cd, ds; + memset (&ds, 0, sizeof ds); + memset (&cd, 0, sizeof cd); + + status = (evaluate_data_expression (&ds, packet, lease, + client_state, in_options, + out_options, scope, expr, + MDL)); + if (status) { + for (s = stmt; s; s = s -> next) { + if (s -> op == case_statement) { + sub = (evaluate_data_expression + (&cd, packet, lease, client_state, + in_options, out_options, + scope, s -> data.c_case, MDL)); + if (sub && cd.len == ds.len && + !memcmp (cd.data, ds.data, cd.len)) + { + data_string_forget (&cd, MDL); + data_string_forget (&ds, MDL); + executable_statement_reference + (ep, s -> next, MDL); + return 1; + } + data_string_forget (&cd, MDL); + } + } + data_string_forget (&ds, MDL); + } + } else { + unsigned long n, c; + status = evaluate_numeric_expression (&n, packet, lease, + client_state, + in_options, out_options, + scope, expr); + + if (status) { + for (s = stmt; s; s = s -> next) { + if (s -> op == case_statement) { + sub = (evaluate_numeric_expression + (&c, packet, lease, client_state, + in_options, out_options, + scope, s -> data.c_case)); + if (sub && n == c) { + executable_statement_reference + (ep, s -> next, MDL); + return 1; + } + } + } + } + } + + /* If we didn't find a matching case statement, look for a default + statement and return the statement following it. */ + for (s = stmt; s; s = s -> next) + if (s -> op == default_statement) + break; + if (s) { + executable_statement_reference (ep, s -> next, MDL); + return 1; + } + return 0; +} + +int executable_statement_foreach (struct executable_statement *stmt, + int (*callback) (struct + executable_statement *, + void *, int), + void *vp, int condp) +{ + struct executable_statement *foo; + int ok = 0; + int result; + + for (foo = stmt; foo; foo = foo -> next) { + if ((*callback) (foo, vp, condp) != 0) + ok = 1; + switch (foo -> op) { + case null_statement: + break; + case if_statement: + if (executable_statement_foreach (foo -> data.ie.tc, + callback, vp, 1)) + ok = 1; + if (executable_statement_foreach (foo -> data.ie.fc, + callback, vp, 1)) + ok = 1; + break; + case add_statement: + break; + case eval_statement: + break; + case break_statement: + break; + case default_option_statement: + break; + case supersede_option_statement: + break; + case append_option_statement: + break; + case prepend_option_statement: + break; + case send_option_statement: + break; + case statements_statement: + if ((executable_statement_foreach + (foo -> data.statements, callback, vp, condp))) + ok = 1; + break; + case on_statement: + if ((executable_statement_foreach + (foo -> data.on.statements, callback, vp, 1))) + ok = 1; + break; + case switch_statement: + if ((executable_statement_foreach + (foo -> data.s_switch.statements, callback, vp, 1))) + ok = 1; + break; + case case_statement: + break; + case default_statement: + break; + case set_statement: + break; + case unset_statement: + break; + case let_statement: + if ((executable_statement_foreach + (foo -> data.let.statements, callback, vp, 0))) + ok = 1; + break; + case define_statement: + break; + case log_statement: + case return_statement: + break; + } + } + return ok; +} diff --git a/contrib/isc-dhcp/common/fddi.c b/contrib/isc-dhcp/common/fddi.c new file mode 100644 index 0000000..d73d450 --- /dev/null +++ b/contrib/isc-dhcp/common/fddi.c @@ -0,0 +1,106 @@ +/* fddi.c + + Packet assembly code, originally contributed by Archie Cobbs. */ + +/* + * Copyright (c) 1996-2000 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. + */ + +#ifndef lint +static char copyright[] = +"$Id: fddi.c,v 1.3 2000/04/18 23:02:09 mellon Exp $ Copyright (c) 1996-2000 The Internet Software Consortium. All rights reserved.\n"; +#endif /* not lint */ + +#include "dhcpd.h" + +#if defined (DEC_FDDI) +#include <netinet/if_fddi.h> +#include <net/if_llc.h> + +#if defined (PACKET_ASSEMBLY) || defined (PACKET_DECODING) +#include "includes/netinet/if_ether.h" +#endif /* PACKET_ASSEMBLY || PACKET_DECODING */ + +#if defined (PACKET_ASSEMBLY) +/* Assemble an hardware header... */ + +void assemble_fddi_header (interface, buf, bufix, to) + struct interface_info *interface; + unsigned char *buf; + unsigned *bufix; + struct hardware *to; +{ + struct fddi_header fh; + struct llc lh; + + if (to && to -> hlen == 7) + memcpy (fh.fddi_dhost, &to -> hbuf [1], + sizeof (fh.fddi_dhost)); + memcpy (fh.fddi_shost, + &interface -> hw_address.hbuf [1], sizeof (fh.fddi_shost)); + fh.fddi_fc = FDDIFC_LLC_ASYNC; + memcpy (&buf [*bufix], &fh, sizeof fh); + *bufix += sizeof fh; + + lh.llc_dsap = LLC_SNAP_LSAP; + lh.llc_ssap = LLC_SNAP_LSAP; + lh.llc_un.type_snap.control = LLC_UI; + lh.llc_un.type_snap.ether_type = htons (ETHERTYPE_IP); + memcpy (&buf [*bufix], &lh, LLC_SNAP_LEN); + *bufix += LLC_SNAP_LEN; +} +#endif /* PACKET_ASSEMBLY */ + +#ifdef PACKET_DECODING +/* Decode a hardware header... */ + +ssize_t decode_fddi_header (interface, buf, bufix, from) + struct interface_info *interface; + unsigned char *buf; + unsigned bufix; + struct hardware *from; +{ + struct fddi_header fh; + struct llc lh; + + from -> hbuf [0] = HTYPE_FDDI; + memcpy (&from -> hbuf [1], fh.fddi_shost, sizeof fh.fddi_shost); + return FDDI_HEADER_SIZE + LLC_SNAP_LEN; +} +#endif /* PACKET_DECODING */ +#endif /* DEC_FDDI */ diff --git a/contrib/isc-dhcp/common/icmp.c b/contrib/isc-dhcp/common/icmp.c index a9d7ec4..299e030 100644 --- a/contrib/isc-dhcp/common/icmp.c +++ b/contrib/isc-dhcp/common/icmp.c @@ -1,10 +1,10 @@ -/* icmp.c +/* dhcp.c ICMP Protocol engine - for sending out pings and receiving responses. */ /* - * Copyright (c) 1997, 1998 The Internet Software Consortium. + * Copyright (c) 1996-2001 Internet Software Consortium. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -35,23 +35,32 @@ * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium - * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie - * Enterprises. To learn more about the Internet Software Consortium, - * see ``http://www.vix.com/isc''. To learn more about Vixie - * Enterprises, see ``http://www.vix.com''. + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. */ #ifndef lint static char copyright[] = -"$Id: icmp.c,v 1.7.2.2 1999/03/29 23:20:00 mellon Exp $ Copyright (c) 1997, 1998 The Internet Software Consortium. All rights reserved.\n"; +"$Id: icmp.c,v 1.30.2.3 2001/10/18 20:11:24 mellon Exp $ Copyright (c) 1996-2001 The Internet Software Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" #include "netinet/ip.h" #include "netinet/ip_icmp.h" -static int icmp_protocol_initialized; -static int icmp_protocol_fd; +struct icmp_state *icmp_state; +static omapi_object_type_t *dhcp_type_icmp; +static int no_icmp; + +OMAPI_OBJECT_ALLOC (icmp_state, struct icmp_state, dhcp_type_icmp) + +#if defined (TRACING) +trace_type_t *trace_icmp_input; +trace_type_t *trace_icmp_output; +#endif /* Initialize the ICMP protocol. */ @@ -61,31 +70,83 @@ void icmp_startup (routep, handler) { struct protoent *proto; int protocol = 1; + struct sockaddr_in from; + int fd; int state; + struct icmp_state *new; + omapi_object_t *h; + isc_result_t result; /* Only initialize icmp once. */ - if (icmp_protocol_initialized) - error ("attempted to reinitialize icmp protocol"); - icmp_protocol_initialized = 1; - - /* Get the protocol number (should be 1). */ - proto = getprotobyname ("icmp"); - if (proto) - protocol = proto -> p_proto; - - /* Get a raw socket for the ICMP protocol. */ - icmp_protocol_fd = socket (AF_INET, SOCK_RAW, protocol); - if (icmp_protocol_fd < 0) - error ("unable to create icmp socket: %m"); - - /* Make sure it does routing... */ - state = 0; - if (setsockopt (icmp_protocol_fd, SOL_SOCKET, SO_DONTROUTE, - (char *)&state, sizeof state) < 0) - error ("Unable to disable SO_DONTROUTE on ICMP socket: %m"); - - add_protocol ("icmp", icmp_protocol_fd, icmp_echoreply, - (void *)handler); + if (dhcp_type_icmp) + log_fatal ("attempted to reinitialize icmp protocol"); + + result = omapi_object_type_register (&dhcp_type_icmp, "icmp", + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + sizeof (struct icmp_state), + 0, RC_MISC); + + if (result != ISC_R_SUCCESS) + log_fatal ("Can't register icmp object type: %s", + isc_result_totext (result)); + + icmp_state_allocate (&icmp_state, MDL); + icmp_state -> icmp_handler = handler; + +#if defined (TRACING) + trace_icmp_input = trace_type_register ("icmp-input", (void *)0, + trace_icmp_input_input, + trace_icmp_input_stop, MDL); + trace_icmp_output = trace_type_register ("icmp-output", (void *)0, + trace_icmp_output_input, + trace_icmp_output_stop, MDL); + + /* If we're playing back a trace file, don't create the socket + or set up the callback. */ + if (!trace_playback ()) { +#endif + /* Get the protocol number (should be 1). */ + proto = getprotobyname ("icmp"); + if (proto) + protocol = proto -> p_proto; + + /* Get a raw socket for the ICMP protocol. */ + icmp_state -> socket = socket (AF_INET, SOCK_RAW, protocol); + if (icmp_state -> socket < 0) { + no_icmp = 1; + log_error ("unable to create icmp socket: %m"); + return; + } + +#if defined (HAVE_SETFD) + if (fcntl (icmp_state -> socket, F_SETFD, 1) < 0) + log_error ("Can't set close-on-exec on icmp: %m"); +#endif + + /* Make sure it does routing... */ + state = 0; + if (setsockopt (icmp_state -> socket, SOL_SOCKET, SO_DONTROUTE, + (char *)&state, sizeof state) < 0) + log_fatal ("Can't disable SO_DONTROUTE on ICMP: %m"); + + result = (omapi_register_io_object + ((omapi_object_t *)icmp_state, + icmp_readsocket, 0, icmp_echoreply, 0, 0)); + if (result != ISC_R_SUCCESS) + log_fatal ("Can't register icmp handle: %s", + isc_result_totext (result)); +#if defined (TRACING) + } +#endif +} + +int icmp_readsocket (h) + omapi_object_t *h; +{ + struct icmp_state *state; + + state = (struct icmp_state *)h; + return state -> socket; } int icmp_echorequest (addr) @@ -94,9 +155,14 @@ int icmp_echorequest (addr) struct sockaddr_in to; struct icmp icmp; int status; +#if defined (TRACING) + trace_iov_t iov [2]; +#endif - if (!icmp_protocol_initialized) - error ("attempt to use ICMP protocol before initialization."); + if (no_icmp) + return 1; + if (!icmp_state) + log_fatal ("ICMP protocol used before initialization."); #ifdef HAVE_SA_LEN to.sin_len = sizeof to; @@ -115,61 +181,145 @@ int icmp_echorequest (addr) #else icmp.icmp_id = (u_int32_t)addr; #endif + memset (&icmp.icmp_dun, 0, sizeof icmp.icmp_dun); icmp.icmp_cksum = wrapsum (checksum ((unsigned char *)&icmp, sizeof icmp, 0)); - /* Send the ICMP packet... */ - status = sendto (icmp_protocol_fd, (char *)&icmp, sizeof icmp, 0, - (struct sockaddr *)&to, sizeof to); - if (status < 0) - warn ("icmp_echorequest %s: %m", inet_ntoa(to.sin_addr)); +#if defined (TRACING) + if (trace_playback ()) { + char *buf = (char *)0; + unsigned buflen = 0; + + /* Consume the ICMP event. */ + status = trace_get_packet (&trace_icmp_output, &buflen, &buf); + if (status != ISC_R_SUCCESS) + log_error ("icmp_echorequest: %s", + isc_result_totext (status)); + if (buf) + dfree (buf, MDL); + } else { + if (trace_record ()) { + iov [0].buf = (char *)addr; + iov [0].len = sizeof *addr; + iov [1].buf = (char *)&icmp; + iov [1].len = sizeof icmp; + trace_write_packet_iov (trace_icmp_output, + 2, iov, MDL); + } +#endif + /* Send the ICMP packet... */ + status = sendto (icmp_state -> socket, + (char *)&icmp, sizeof icmp, 0, + (struct sockaddr *)&to, sizeof to); + if (status < 0) + log_error ("icmp_echorequest %s: %m", + inet_ntoa(to.sin_addr)); - if (status != sizeof icmp) - return 0; + if (status != sizeof icmp) + return 0; +#if defined (TRACING) + } +#endif return 1; } -void icmp_echoreply (protocol) - struct protocol *protocol; +isc_result_t icmp_echoreply (h) + omapi_object_t *h; { struct icmp *icfrom; + struct ip *ip; struct sockaddr_in from; u_int8_t icbuf [1500]; int status; - int len; + SOCKLEN_T sl; + int hlen, len; struct iaddr ia; - void (*handler) PROTO ((struct iaddr, u_int8_t *, int)); + struct icmp_state *state; +#if defined (TRACING) + trace_iov_t iov [2]; +#endif + + state = (struct icmp_state *)h; - len = sizeof from; - status = recvfrom (protocol -> fd, (char *)icbuf, sizeof icbuf, 0, - (struct sockaddr *)&from, &len); + sl = sizeof from; + status = recvfrom (state -> socket, (char *)icbuf, sizeof icbuf, 0, + (struct sockaddr *)&from, &sl); if (status < 0) { - warn ("icmp_echoreply: %m"); - return; + log_error ("icmp_echoreply: %m"); + return ISC_R_UNEXPECTED; } - /* Probably not for us. */ - if (status < (sizeof (struct ip)) + (sizeof *icfrom)) { - return; + /* Find the IP header length... */ + ip = (struct ip *)icbuf; + hlen = IP_HL (ip); + + /* Short packet? */ + if (status < hlen + (sizeof *icfrom)) { + return ISC_R_SUCCESS; } - len = status - sizeof (struct ip); - icfrom = (struct icmp *)(icbuf + sizeof (struct ip)); + len = status - hlen; + icfrom = (struct icmp *)(icbuf + hlen); /* Silently discard ICMP packets that aren't echoreplies. */ if (icfrom -> icmp_type != ICMP_ECHOREPLY) { - return; + return ISC_R_SUCCESS; } /* If we were given a second-stage handler, call it. */ - if (protocol -> local) { - handler = ((void (*) PROTO ((struct iaddr, - u_int8_t *, int))) - protocol -> local); + if (state -> icmp_handler) { memcpy (ia.iabuf, &from.sin_addr, sizeof from.sin_addr); ia.len = sizeof from.sin_addr; - (*handler) (ia, icbuf, len); +#if defined (TRACING) + if (trace_record ()) { + ia.len = htonl(ia.len); + iov [0].buf = (char *)&ia; + iov [0].len = sizeof ia; + iov [1].buf = (char *)icbuf; + iov [1].len = len; + trace_write_packet_iov (trace_icmp_input, 2, iov, MDL); + ia.len = ntohl(ia.len); + } +#endif + (*state -> icmp_handler) (ia, icbuf, len); } + return ISC_R_SUCCESS; } + +#if defined (TRACING) +void trace_icmp_input_input (trace_type_t *ttype, unsigned length, char *buf) +{ + struct iaddr *ia; + unsigned len; + u_int8_t *icbuf; + ia = (struct iaddr *)buf; + ia->len = ntohl(ia->len); + icbuf = (u_int8_t *)(ia + 1); + if (icmp_state -> icmp_handler) + (*icmp_state -> icmp_handler) (*ia, icbuf, + (int)(length - sizeof ia)); +} + +void trace_icmp_input_stop (trace_type_t *ttype) { } + +void trace_icmp_output_input (trace_type_t *ttype, unsigned length, char *buf) +{ + struct icmp *icmp; + struct iaddr ia; + + if (length != (sizeof (*icmp) + (sizeof ia))) { + log_error ("trace_icmp_output_input: data size mismatch %d:%d", + length, (int)((sizeof (*icmp)) + (sizeof ia))); + return; + } + ia.len = 4; + memcpy (ia.iabuf, buf, 4); + icmp = (struct icmp *)(buf + 1); + + log_error ("trace_icmp_output_input: unsent ping to %s", piaddr (ia)); +} + +void trace_icmp_output_stop (trace_type_t *ttype) { } +#endif /* TRACING */ diff --git a/contrib/isc-dhcp/common/inet.c b/contrib/isc-dhcp/common/inet.c index 527afbb..158440e 100644 --- a/contrib/isc-dhcp/common/inet.c +++ b/contrib/isc-dhcp/common/inet.c @@ -4,7 +4,8 @@ way... */ /* - * Copyright (c) 1996 The Internet Software Consortium. All rights reserved. + * Copyright (c) 1995-2001 Internet Software Consortium. + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -34,15 +35,16 @@ * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium - * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie - * Enterprises. To learn more about the Internet Software Consortium, - * see ``http://www.vix.com/isc''. To learn more about Vixie - * Enterprises, see ``http://www.vix.com''. + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. */ #ifndef lint static char copyright[] = -"$Id: inet.c,v 1.5.2.2 1999/04/24 16:48:10 mellon Exp $ Copyright (c) 1995, 1996, 1998, 1999 The Internet Software Consortium. All rights reserved.\n"; +"$Id: inet.c,v 1.8.2.3 2001/06/21 16:59:00 mellon Exp $ Copyright (c) 1995-1999 The Internet Software Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -119,7 +121,7 @@ struct iaddr broadcast_addr (subnet, mask) struct iaddr subnet; struct iaddr mask; { - int i; + int i, j, k; struct iaddr rv; if (subnet.len != mask.len) { @@ -181,3 +183,60 @@ char *piaddr (addr) } return pbuf; } + +char *piaddr1 (addr) + struct iaddr addr; +{ + static char pbuf [4 * 16]; + char *s = pbuf; + int i; + + if (addr.len == 0) { + strcpy (s, "<null address>"); + } + for (i = 0; i < addr.len; i++) { + sprintf (s, "%s%d", i ? "." : "", addr.iabuf [i]); + s += strlen (s); + } + return pbuf; +} + +char *piaddrmask (struct iaddr addr, struct iaddr mask, + const char *file, int line) +{ + char *s, *t; + int i, mw; + unsigned len; + + for (i = 0; i < 32; i++) { + if (!mask.iabuf [3 - i / 8]) + i += 7; + else if (mask.iabuf [3 - i / 8] & (1 << (i % 8))) + break; + } + mw = 32 - i; + len = mw > 9 ? 2 : 1; + len += 4; /* three dots and a slash. */ + for (i = 0; i < (mw / 8) + 1; i++) { + if (addr.iabuf [i] > 99) + len += 3; + else if (addr.iabuf [i] > 9) + len += 2; + else + len++; + } + s = dmalloc (len + 1, file, line); + if (!s) + return s; + t = s; + sprintf (t, "%d", addr.iabuf [0]); + t += strlen (t); + for (i = 1; i < (mw / 8) + 1; i++) { + sprintf (t, ".%d", addr.iabuf [i]); + t += strlen (t); + } + *t++ = '/'; + sprintf (t, "%d", mw); + return s; +} + diff --git a/contrib/isc-dhcp/common/lpf.c b/contrib/isc-dhcp/common/lpf.c index 14dd21a..da03c31 100644 --- a/contrib/isc-dhcp/common/lpf.c +++ b/contrib/isc-dhcp/common/lpf.c @@ -4,8 +4,8 @@ Support Services in Vancouver, B.C. */ /* - * Copyright (c) 1995, 1996, 1998, 1999 - * The Internet Software Consortium. All rights reserved. + * Copyright (c) 1996-2000 Internet Software Consortium. + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,17 +33,11 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * This software has been written for the Internet Software Consortium - * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie - * Enterprises. To learn more about the Internet Software Consortium, - * see ``http://www.vix.com/isc''. To learn more about Vixie - * Enterprises, see ``http://www.vix.com''. */ #ifndef lint static char copyright[] = -"$Id: lpf.c,v 1.1.2.10 1999/10/25 15:39:02 mellon Exp $ Copyright (c) 1995, 1996, 1998, 1999 The Internet Software Consortium. All rights reserved.\n"; +"$Id: lpf.c,v 1.29 2001/04/24 00:36:00 mellon Exp $ Copyright (c) 1996-2000 The Internet Software Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -59,9 +53,6 @@ static char copyright[] = #include "includes/netinet/udp.h" #include "includes/netinet/if_ether.h" -static void lpf_gen_filter_setup PROTO ((struct interface_info *)); -static void lpf_tr_filter_setup PROTO ((struct interface_info *)); - /* Reinitializes the specified interface after an address change. This is not required for packet-filter APIs. */ @@ -92,16 +83,19 @@ int if_register_lpf (info) struct sockaddr sa; /* Make an LPF socket. */ - if ((sock = socket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ALL))) < 0) { + if ((sock = socket(PF_PACKET, SOCK_PACKET, + htons((short)ETH_P_ALL))) < 0) { if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT || errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT || errno == EAFNOSUPPORT || errno == EINVAL) { - warn ("socket: %m"); - error ("Make sure to set %s %s!", - "CONFIG_PACKET=y and CONFIG_FILTER=y", - "in your kernel configuration"); + log_error ("socket: %m - make sure"); + log_error ("CONFIG_PACKET (Packet socket) %s", + "and CONFIG_FILTER"); + log_error ("(Socket Filtering) are enabled %s", + "in your kernel"); + log_fatal ("configuration!"); } - error("Open a socket for LPF: %m"); + log_fatal ("Open a socket for LPF: %m"); } /* Bind to the interface name */ @@ -112,12 +106,14 @@ int if_register_lpf (info) if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT || errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT || errno == EAFNOSUPPORT || errno == EINVAL) { - warn ("bind: %m"); - error ("Set %s %s!", - "CONFIG_PACKET=y and CONFIG_FILTER=y", - "in your kernel configuration"); + log_error ("socket: %m - make sure"); + log_error ("CONFIG_PACKET (Packet socket) %s", + "and CONFIG_FILTER"); + log_error ("(Socket Filtering) are enabled %s", + "in your kernel"); + log_fatal ("configuration!"); } - error("Bind socket to interface: %m"); + log_fatal ("Bind socket to interface: %m"); } return sock; @@ -131,16 +127,38 @@ void if_register_send (info) /* If we're using the lpf API for sending and receiving, we don't need to register this interface twice. */ #ifndef USE_LPF_RECEIVE - info -> wfdesc = if_register_lpf (info, interface); + info -> wfdesc = if_register_lpf (info); #else info -> wfdesc = info -> rfdesc; #endif if (!quiet_interface_discovery) - note ("Sending on LPF/%s/%s%s%s", + log_info ("Sending on LPF/%s/%s%s%s", + info -> name, + print_hw_addr (info -> hw_address.hbuf [0], + info -> hw_address.hlen - 1, + &info -> hw_address.hbuf [1]), + (info -> shared_network ? "/" : ""), + (info -> shared_network ? + info -> shared_network -> name : "")); +} + +void if_deregister_send (info) + struct interface_info *info; +{ + /* don't need to close twice if we are using lpf for sending and + receiving */ +#ifndef USE_LPF_RECEIVE + /* for LPF this is simple, packet filters are removed when sockets + are closed */ + close (info -> wfdesc); +#endif + info -> wfdesc = -1; + if (!quiet_interface_discovery) + log_info ("Disabling output on LPF/%s/%s%s%s", info -> name, - print_hw_addr (info -> hw_address.htype, - info -> hw_address.hlen, - info -> hw_address.haddr), + print_hw_addr (info -> hw_address.hbuf [0], + info -> hw_address.hlen - 1, + &info -> hw_address.hbuf [1]), (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : "")); @@ -152,11 +170,14 @@ void if_register_send (info) in bpf includes... */ extern struct sock_filter dhcp_bpf_filter []; extern int dhcp_bpf_filter_len; + +#if defined (HAVE_TR_SUPPORT) extern struct sock_filter dhcp_bpf_tr_filter []; extern int dhcp_bpf_tr_filter_len; +static void lpf_tr_filter_setup (struct interface_info *); +#endif static void lpf_gen_filter_setup (struct interface_info *); -static void lpf_tr_filter_setup (struct interface_info *); void if_register_receive (info) struct interface_info *info; @@ -164,20 +185,40 @@ void if_register_receive (info) /* Open a LPF device and hang it on this interface... */ info -> rfdesc = if_register_lpf (info); - if (info -> hw_address.htype == HTYPE_IEEE802) +#if defined (HAVE_TR_SUPPORT) + if (info -> hw_address.hbuf [0] == HTYPE_IEEE802) lpf_tr_filter_setup (info); else +#endif lpf_gen_filter_setup (info); if (!quiet_interface_discovery) - note ("Listening on LPF/%s/%s%s%s", - info -> name, - print_hw_addr (info -> hw_address.htype, - info -> hw_address.hlen, - info -> hw_address.haddr), - (info -> shared_network ? "/" : ""), - (info -> shared_network ? - info -> shared_network -> name : "")); + log_info ("Listening on LPF/%s/%s%s%s", + info -> name, + print_hw_addr (info -> hw_address.hbuf [0], + info -> hw_address.hlen - 1, + &info -> hw_address.hbuf [1]), + (info -> shared_network ? "/" : ""), + (info -> shared_network ? + info -> shared_network -> name : "")); +} + +void if_deregister_receive (info) + struct interface_info *info; +{ + /* for LPF this is simple, packet filters are removed when sockets + are closed */ + close (info -> rfdesc); + info -> rfdesc = -1; + if (!quiet_interface_discovery) + log_info ("Disabling input on LPF/%s/%s%s%s", + info -> name, + print_hw_addr (info -> hw_address.hbuf [0], + info -> hw_address.hlen - 1, + &info -> hw_address.hbuf [1]), + (info -> shared_network ? "/" : ""), + (info -> shared_network ? + info -> shared_network -> name : "")); } static void lpf_gen_filter_setup (info) @@ -193,20 +234,25 @@ static void lpf_gen_filter_setup (info) /* Patch the server port into the LPF program... XXX changes to filter program may require changes to the insn number(s) used below! XXX */ - dhcp_bpf_filter [8].k = ntohs (local_port); + dhcp_bpf_filter [8].k = ntohs ((short)local_port); if (setsockopt (info -> rfdesc, SOL_SOCKET, SO_ATTACH_FILTER, &p, sizeof p) < 0) { if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT || errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT || - errno == EAFNOSUPPORT) - error ("socket: %m - make sure %s %s!", - "CONFIG_PACKET and CONFIG_FILTER are defined", - "in your kernel configuration"); - error ("Can't install packet filter program: %m"); + errno == EAFNOSUPPORT) { + log_error ("socket: %m - make sure"); + log_error ("CONFIG_PACKET (Packet socket) %s", + "and CONFIG_FILTER"); + log_error ("(Socket Filtering) are enabled %s", + "in your kernel"); + log_fatal ("configuration!"); + } + log_fatal ("Can't install packet filter program: %m"); } } +#if defined (HAVE_TR_SUPPORT) static void lpf_tr_filter_setup (info) struct interface_info *info; { @@ -228,13 +274,18 @@ static void lpf_tr_filter_setup (info) sizeof p) < 0) { if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT || errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT || - errno == EAFNOSUPPORT) - error ("socket: %m - make sure %s %s!", - "CONFIG_PACKET and CONFIG_FILTER are defined", - "in your kernel configuration"); - error ("Can't install packet filter program: %m"); + errno == EAFNOSUPPORT) { + log_error ("socket: %m - make sure"); + log_error ("CONFIG_PACKET (Packet socket) %s", + "and CONFIG_FILTER"); + log_error ("(Socket Filtering) are enabled %s", + "in your kernel"); + log_fatal ("configuration!"); + } + log_fatal ("Can't install packet filter program: %m"); } } +#endif /* HAVE_TR_SUPPORT */ #endif /* USE_LPF_RECEIVE */ #ifdef USE_LPF_SEND @@ -247,21 +298,27 @@ ssize_t send_packet (interface, packet, raw, len, from, to, hto) struct sockaddr_in *to; struct hardware *hto; { - int bufp = 0; - unsigned char buf [1500]; + unsigned hbufp = 0, ibufp = 0; + double hh [16]; + double ih [1536 / sizeof (double)]; + unsigned char *buf = (unsigned char *)ih; struct sockaddr sa; int result; + int fudge; if (!strcmp (interface -> name, "fallback")) return send_fallback (interface, packet, raw, len, from, to, hto); /* Assemble the headers... */ - assemble_hw_header (interface, buf, &bufp, hto); - assemble_udp_ip_header (interface, buf, &bufp, from.s_addr, + assemble_hw_header (interface, (unsigned char *)hh, &hbufp, hto); + fudge = hbufp % 4; /* IP header must be word-aligned. */ + memcpy (buf + fudge, (unsigned char *)hh, hbufp); + ibufp = hbufp + fudge; + assemble_udp_ip_header (interface, buf, &ibufp, from.s_addr, to -> sin_addr.s_addr, to -> sin_port, (unsigned char *)raw, len); - memcpy (buf + bufp, raw, len); + memcpy (buf + ibufp, raw, len); /* For some reason, SOCK_PACKET sockets can't be connected, so we have to do a sentdo every time. */ @@ -270,10 +327,10 @@ ssize_t send_packet (interface, packet, raw, len, from, to, hto) strncpy (sa.sa_data, (const char *)interface -> ifp, sizeof sa.sa_data); - result = sendto (interface -> wfdesc, buf, bufp + len, 0, - &sa, sizeof sa); + result = sendto (interface -> wfdesc, + buf + fudge, ibufp + len - fudge, 0, &sa, sizeof sa); if (result < 0) - warn ("send_packet: %m"); + log_error ("send_packet: %m"); return result; } #endif /* USE_LPF_SEND */ @@ -289,8 +346,8 @@ ssize_t receive_packet (interface, buf, len, from, hfrom) int nread; int length = 0; int offset = 0; - unsigned char ibuf [1500]; - int bufix = 0; + unsigned char ibuf [1536]; + unsigned bufix = 0; length = read (interface -> rfdesc, ibuf, sizeof ibuf); if (length <= 0) @@ -311,8 +368,8 @@ ssize_t receive_packet (interface, buf, len, from, hfrom) length -= offset; /* Decode the IP and UDP headers... */ - offset = decode_udp_ip_header (interface, ibuf, bufix, - from, (unsigned char *)0, length); + offset = decode_udp_ip_header (interface, ibuf, bufix, from, + (unsigned char *)0, (unsigned)length); /* If the IP or UDP checksum was bad, skip the packet... */ if (offset < 0) @@ -326,7 +383,8 @@ ssize_t receive_packet (interface, buf, len, from, hfrom) return length; } -int can_unicast_without_arp () +int can_unicast_without_arp (ip) + struct interface_info *ip; { return 1; } @@ -337,14 +395,25 @@ int can_receive_unicast_unconfigured (ip) return 1; } +int supports_multiple_interfaces (ip) + struct interface_info *ip; +{ + return 1; +} + void maybe_setup_fallback () { - struct interface_info *fbi; - fbi = setup_fallback (); - if (fbi) { + isc_result_t status; + struct interface_info *fbi = (struct interface_info *)0; + if (setup_fallback (&fbi, MDL)) { if_register_fallback (fbi); - add_protocol ("fallback", fallback_interface -> wfdesc, - fallback_discard, fallback_interface); + status = omapi_register_io_object ((omapi_object_t *)fbi, + if_readsocket, 0, + fallback_discard, 0, 0); + if (status != ISC_R_SUCCESS) + log_fatal ("Can't register I/O handle for %s: %s", + fbi -> name, isc_result_totext (status)); + interface_dereference (&fbi, MDL); } } #endif diff --git a/contrib/isc-dhcp/common/memory.c b/contrib/isc-dhcp/common/memory.c index c293217..3c6d913 100644 --- a/contrib/isc-dhcp/common/memory.c +++ b/contrib/isc-dhcp/common/memory.c @@ -3,7 +3,7 @@ Memory-resident database... */ /* - * Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium. + * Copyright (c) 1995-2001 Internet Software Consortium. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,907 +34,137 @@ * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium - * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie - * Enterprises. To learn more about the Internet Software Consortium, - * see ``http://www.vix.com/isc''. To learn more about Vixie - * Enterprises, see ``http://www.vix.com''. + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. */ #ifndef lint static char copyright[] = -"$Id: memory.c,v 1.35.2.4 1999/05/27 17:47:43 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium. All rights reserved.\n"; +"$Id: memory.c,v 1.66.2.3 2001/10/17 03:25:10 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" -static struct subnet *subnets; -static struct shared_network *shared_networks; -static struct hash_table *host_hw_addr_hash; -static struct hash_table *host_uid_hash; -static struct hash_table *lease_uid_hash; -static struct hash_table *lease_ip_addr_hash; -static struct hash_table *lease_hw_addr_hash; -static struct lease *dangling_leases; - -static struct hash_table *vendor_class_hash; -static struct hash_table *user_class_hash; - -void enter_host (hd) - struct host_decl *hd; -{ - struct host_decl *hp = (struct host_decl *)0; - struct host_decl *np = (struct host_decl *)0; - - hd -> n_ipaddr = (struct host_decl *)0; - - if (hd -> interface.hlen) { - if (!host_hw_addr_hash) - host_hw_addr_hash = new_hash (); - else - hp = (struct host_decl *) - hash_lookup (host_hw_addr_hash, - hd -> interface.haddr, - hd -> interface.hlen); - - /* If there isn't already a host decl matching this - address, add it to the hash table. */ - if (!hp) - add_hash (host_hw_addr_hash, - hd -> interface.haddr, hd -> interface.hlen, - (unsigned char *)hd); - } - - /* If there was already a host declaration for this hardware - address, add this one to the end of the list. */ - - if (hp) { - for (np = hp; np -> n_ipaddr; np = np -> n_ipaddr) - ; - np -> n_ipaddr = hd; - } - - if (hd -> group -> options [DHO_DHCP_CLIENT_IDENTIFIER]) { - if (!tree_evaluate (hd -> group -> options - [DHO_DHCP_CLIENT_IDENTIFIER])) - return; - - /* If there's no uid hash, make one; otherwise, see if - there's already an entry in the hash for this host. */ - if (!host_uid_hash) { - host_uid_hash = new_hash (); - hp = (struct host_decl *)0; - } else - hp = (struct host_decl *) hash_lookup - (host_uid_hash, - hd -> group -> options - [DHO_DHCP_CLIENT_IDENTIFIER] -> value, - hd -> group -> options - [DHO_DHCP_CLIENT_IDENTIFIER] -> len); - - /* If there's already a host declaration for this - client identifier, add this one to the end of the - list. Otherwise, add it to the hash table. */ - if (hp) { - /* Don't link it in twice... */ - if (!np) { - for (np = hp; np -> n_ipaddr; - np = np -> n_ipaddr) - ; - np -> n_ipaddr = hd; - } - } else { - add_hash (host_uid_hash, - hd -> group -> options - [DHO_DHCP_CLIENT_IDENTIFIER] -> value, - hd -> group -> options - [DHO_DHCP_CLIENT_IDENTIFIER] -> len, - (unsigned char *)hd); - } - } -} - -struct host_decl *find_hosts_by_haddr (htype, haddr, hlen) - int htype; - unsigned char *haddr; - int hlen; -{ - struct host_decl *foo; - - foo = (struct host_decl *)hash_lookup (host_hw_addr_hash, - haddr, hlen); - return foo; -} - -struct host_decl *find_hosts_by_uid (data, len) - unsigned char *data; - int len; -{ - struct host_decl *foo; - - foo = (struct host_decl *)hash_lookup (host_uid_hash, data, len); - return foo; -} - -/* More than one host_decl can be returned by find_hosts_by_haddr or - find_hosts_by_uid, and each host_decl can have multiple addresses. - Loop through the list of hosts, and then for each host, through the - list of addresses, looking for an address that's in the same shared - network as the one specified. Store the matching address through - the addr pointer, update the host pointer to point at the host_decl - that matched, and return the subnet that matched. */ - -struct subnet *find_host_for_network (host, addr, share) - struct host_decl **host; - struct iaddr *addr; - struct shared_network *share; -{ - int i; - struct subnet *subnet; - struct iaddr ip_address; - struct host_decl *hp; - - for (hp = *host; hp; hp = hp -> n_ipaddr) { - if (!hp -> fixed_addr || !tree_evaluate (hp -> fixed_addr)) - continue; - for (i = 0; i < hp -> fixed_addr -> len; i += 4) { - ip_address.len = 4; - memcpy (ip_address.iabuf, - hp -> fixed_addr -> value + i, 4); - subnet = find_grouped_subnet (share, ip_address); - if (subnet) { - *addr = ip_address; - *host = hp; - return subnet; - } - } - } - return (struct subnet *)0; -} - -void new_address_range (low, high, subnet, dynamic) - struct iaddr low, high; - struct subnet *subnet; - int dynamic; -{ - struct lease *address_range, *lp, *plp; - struct iaddr net; - int min, max, i; - char lowbuf [16], highbuf [16], netbuf [16]; - struct shared_network *share = subnet -> shared_network; - struct hostent *h; - struct in_addr ia; - - /* All subnets should have attached shared network structures. */ - if (!share) { - strcpy (netbuf, piaddr (subnet -> net)); - error ("No shared network for network %s (%s)", - netbuf, piaddr (subnet -> netmask)); - } - - /* Initialize the hash table if it hasn't been done yet. */ - if (!lease_uid_hash) - lease_uid_hash = new_hash (); - if (!lease_ip_addr_hash) - lease_ip_addr_hash = new_hash (); - if (!lease_hw_addr_hash) - lease_hw_addr_hash = new_hash (); - - /* Make sure that high and low addresses are in same subnet. */ - net = subnet_number (low, subnet -> netmask); - if (!addr_eq (net, subnet_number (high, subnet -> netmask))) { - strcpy (lowbuf, piaddr (low)); - strcpy (highbuf, piaddr (high)); - strcpy (netbuf, piaddr (subnet -> netmask)); - error ("Address range %s to %s, netmask %s spans %s!", - lowbuf, highbuf, netbuf, "multiple subnets"); - } - - /* Make sure that the addresses are on the correct subnet. */ - if (!addr_eq (net, subnet -> net)) { - strcpy (lowbuf, piaddr (low)); - strcpy (highbuf, piaddr (high)); - strcpy (netbuf, piaddr (subnet -> netmask)); - error ("Address range %s to %s not on net %s/%s!", - lowbuf, highbuf, piaddr (subnet -> net), netbuf); - } - - /* Get the high and low host addresses... */ - max = host_addr (high, subnet -> netmask); - min = host_addr (low, subnet -> netmask); - - /* Allow range to be specified high-to-low as well as low-to-high. */ - if (min > max) { - max = min; - min = host_addr (high, subnet -> netmask); - } - - /* Get a lease structure for each address in the range. */ - address_range = new_leases (max - min + 1, "new_address_range"); - if (!address_range) { - strcpy (lowbuf, piaddr (low)); - strcpy (highbuf, piaddr (high)); - error ("No memory for address range %s-%s.", lowbuf, highbuf); - } - memset (address_range, 0, (sizeof *address_range) * (max - min + 1)); - - /* Fill in the last lease if it hasn't been already... */ - if (!share -> last_lease) { - share -> last_lease = &address_range [0]; - } - - /* Fill out the lease structures with some minimal information. */ - for (i = 0; i < max - min + 1; i++) { - address_range [i].ip_addr = - ip_addr (subnet -> net, subnet -> netmask, i + min); - address_range [i].starts = - address_range [i].timestamp = MIN_TIME; - address_range [i].ends = MIN_TIME; - address_range [i].subnet = subnet; - address_range [i].shared_network = share; - address_range [i].flags = dynamic ? DYNAMIC_BOOTP_OK : 0; - - memcpy (&ia, address_range [i].ip_addr.iabuf, 4); - - if (subnet -> group -> get_lease_hostnames) { - h = gethostbyaddr ((char *)&ia, sizeof ia, AF_INET); - if (!h) - warn ("No hostname for %s", inet_ntoa (ia)); - else { - address_range [i].hostname = - malloc (strlen (h -> h_name) + 1); - if (!address_range [i].hostname) - error ("no memory for hostname %s.", - h -> h_name); - strcpy (address_range [i].hostname, - h -> h_name); - } - } - - /* Link this entry into the list. */ - address_range [i].next = share -> leases; - address_range [i].prev = (struct lease *)0; - share -> leases = &address_range [i]; - if (address_range [i].next) - address_range [i].next -> prev = share -> leases; - add_hash (lease_ip_addr_hash, - address_range [i].ip_addr.iabuf, - address_range [i].ip_addr.len, - (unsigned char *)&address_range [i]); - } - - /* Find out if any dangling leases are in range... */ - plp = (struct lease *)0; - for (lp = dangling_leases; lp; lp = lp -> next) { - struct iaddr lnet; - int lhost; - - lnet = subnet_number (lp -> ip_addr, subnet -> netmask); - lhost = host_addr (lp -> ip_addr, subnet -> netmask); - - /* If it's in range, fill in the real lease structure with - the dangling lease's values, and remove the lease from - the list of dangling leases. */ - if (addr_eq (lnet, subnet -> net) && - lhost >= i && lhost <= max) { - if (plp) { - plp -> next = lp -> next; - } else { - dangling_leases = lp -> next; - } - lp -> next = (struct lease *)0; - address_range [lhost - i].hostname = lp -> hostname; - address_range [lhost - i].client_hostname = - lp -> client_hostname; - supersede_lease (&address_range [lhost - i], lp, 0); - free_lease (lp, "new_address_range"); - } else - plp = lp; - } -} - -struct subnet *find_subnet (addr) - struct iaddr addr; -{ - struct subnet *rv; - - for (rv = subnets; rv; rv = rv -> next_subnet) { - if (addr_eq (subnet_number (addr, rv -> netmask), rv -> net)) - return rv; - } - return (struct subnet *)0; -} - -struct subnet *find_grouped_subnet (share, addr) - struct shared_network *share; - struct iaddr addr; -{ - struct subnet *rv; - - for (rv = share -> subnets; rv; rv = rv -> next_sibling) { - if (addr_eq (subnet_number (addr, rv -> netmask), rv -> net)) - return rv; - } - return (struct subnet *)0; -} - -int subnet_inner_than (subnet, scan, warnp) - struct subnet *subnet, *scan; - int warnp; -{ - if (addr_eq (subnet_number (subnet -> net, scan -> netmask), - scan -> net) || - addr_eq (subnet_number (scan -> net, subnet -> netmask), - subnet -> net)) { - char n1buf [16]; - int i, j; - for (i = 0; i < 32; i++) - if (subnet -> netmask.iabuf [3 - (i >> 3)] - & (1 << (i & 7))) - break; - for (j = 0; j < 32; j++) - if (scan -> netmask.iabuf [3 - (j >> 3)] & - (1 << (j & 7))) - break; - strcpy (n1buf, piaddr (subnet -> net)); - if (warnp) - warn ("%ssubnet %s/%d conflicts with subnet %s/%d", - "Warning: ", n1buf, 32 - i, - piaddr (scan -> net), 32 - j); - if (i < j) - return 1; - } - return 0; -} - -/* Enter a new subnet into the subnet list. */ - -void enter_subnet (subnet) - struct subnet *subnet; -{ - struct subnet *scan, *prev = (struct subnet *)0; - - /* Check for duplicates... */ - for (scan = subnets; scan; scan = scan -> next_subnet) { - /* When we find a conflict, make sure that the - subnet with the narrowest subnet mask comes - first. */ - if (subnet_inner_than (subnet, scan, 1)) { - if (prev) { - prev -> next_subnet = subnet; - } else - subnets = subnet; - subnet -> next_subnet = scan; - return; - } - prev = scan; - } - - /* XXX use the BSD radix tree code instead of a linked list. */ - subnet -> next_subnet = subnets; - subnets = subnet; -} - -/* Enter a new shared network into the shared network list. */ - -void enter_shared_network (share) - struct shared_network *share; -{ - /* XXX Sort the nets into a balanced tree to make searching quicker. */ - share -> next = shared_networks; - shared_networks = share; -} - -/* Enter a lease into the system. This is called by the parser each - time it reads in a new lease. If the subnet for that lease has - already been read in (usually the case), just update that lease; - otherwise, allocate temporary storage for the lease and keep it around - until we're done reading in the config file. */ - -void enter_lease (lease) - struct lease *lease; -{ - struct lease *comp = find_lease_by_ip_addr (lease -> ip_addr); - - /* If we don't have a place for this lease yet, save it for - later. */ - if (!comp) { - comp = new_lease ("enter_lease"); - if (!comp) { - error ("No memory for lease %s\n", - piaddr (lease -> ip_addr)); - } - *comp = *lease; - comp -> next = dangling_leases; - comp -> prev = (struct lease *)0; - dangling_leases = comp; +struct group *root_group; +group_hash_t *group_name_hash; +int (*group_write_hook) (struct group_object *); + +isc_result_t delete_group (struct group_object *group, int writep) +{ + struct group_object *d; + + /* The group should exist and be hashed - if not, it's invalid. */ + if (group_name_hash) { + d = (struct group_object *)0; + group_hash_lookup (&d, group_name_hash, group -> name, + strlen (group -> name), MDL); + } else + return ISC_R_INVALIDARG; + if (!d) + return ISC_R_INVALIDARG; + + /* Also not okay to delete a group that's not the one in + the hash table. */ + if (d != group) + return ISC_R_INVALIDARG; + + /* If it's dynamic, and we're deleting it, we can just blow away the + hash table entry. */ + if ((group -> flags & GROUP_OBJECT_DYNAMIC) && + !(group -> flags & GROUP_OBJECT_STATIC)) { + group_hash_delete (group_name_hash, + group -> name, strlen (group -> name), MDL); } else { - /* Record the hostname information in the lease. */ - comp -> hostname = lease -> hostname; - comp -> client_hostname = lease -> client_hostname; - supersede_lease (comp, lease, 0); - } -} - -/* Replace the data in an existing lease with the data in a new lease; - adjust hash tables to suit, and insertion sort the lease into the - list of leases by expiry time so that we can always find the oldest - lease. */ - -int supersede_lease (comp, lease, commit) - struct lease *comp, *lease; - int commit; -{ - int enter_uid = 0; - int enter_hwaddr = 0; - struct lease *lp; - - /* Static leases are not currently kept in the database... */ - if (lease -> flags & STATIC_LEASE) - return 1; - - /* If the existing lease hasn't expired and has a different - unique identifier or, if it doesn't have a unique - identifier, a different hardware address, then the two - leases are in conflict. If the existing lease has a uid - and the new one doesn't, but they both have the same - hardware address, and dynamic bootp is allowed on this - lease, then we allow that, in case a dynamic BOOTP lease is - requested *after* a DHCP lease has been assigned. */ - - if (!(lease -> flags & ABANDONED_LEASE) && - comp -> ends > cur_time && - (((comp -> uid && lease -> uid) && - (comp -> uid_len != lease -> uid_len || - memcmp (comp -> uid, lease -> uid, comp -> uid_len))) || - (!comp -> uid && - ((comp -> hardware_addr.htype != - lease -> hardware_addr.htype) || - (comp -> hardware_addr.hlen != - lease -> hardware_addr.hlen) || - memcmp (comp -> hardware_addr.haddr, - lease -> hardware_addr.haddr, - comp -> hardware_addr.hlen))))) { - warn ("Lease conflict at %s", - piaddr (comp -> ip_addr)); - return 0; - } else { - /* If there's a Unique ID, dissociate it from the hash - table and free it if necessary. */ - if (comp -> uid) { - uid_hash_delete (comp); - enter_uid = 1; - if (comp -> uid != &comp -> uid_buf [0]) { - free (comp -> uid); - comp -> uid_max = 0; - comp -> uid_len = 0; - } - comp -> uid = (unsigned char *)0; - } else - enter_uid = 1; - - if (comp -> hardware_addr.htype && - ((comp -> hardware_addr.hlen != - lease -> hardware_addr.hlen) || - (comp -> hardware_addr.htype != - lease -> hardware_addr.htype) || - memcmp (comp -> hardware_addr.haddr, - lease -> hardware_addr.haddr, - comp -> hardware_addr.hlen))) { - hw_hash_delete (comp); - enter_hwaddr = 1; - } else if (!comp -> hardware_addr.htype) - enter_hwaddr = 1; - - /* Copy the data files, but not the linkages. */ - comp -> starts = lease -> starts; - if (lease -> uid) { - if (lease -> uid_len < sizeof (lease -> uid_buf)) { - memcpy (comp -> uid_buf, - lease -> uid, lease -> uid_len); - comp -> uid = &comp -> uid_buf [0]; - comp -> uid_max = sizeof comp -> uid_buf; - } else if (lease -> uid != &lease -> uid_buf [0]) { - comp -> uid = lease -> uid; - comp -> uid_max = lease -> uid_max; - lease -> uid = (unsigned char *)0; - lease -> uid_max = 0; - } else { - error ("corrupt lease uid."); /* XXX */ - } - } else { - comp -> uid = (unsigned char *)0; - comp -> uid_max = 0; - } - comp -> uid_len = lease -> uid_len; - comp -> host = lease -> host; - comp -> hardware_addr = lease -> hardware_addr; - comp -> flags = ((lease -> flags & ~PERSISTENT_FLAGS) | - (comp -> flags & ~EPHEMERAL_FLAGS)); - - /* Record the lease in the uid hash if necessary. */ - if (enter_uid && lease -> uid) { - uid_hash_add (comp); - } - - /* Record it in the hardware address hash if necessary. */ - if (enter_hwaddr && lease -> hardware_addr.htype) { - hw_hash_add (comp); - } - - /* Remove the lease from its current place in the - timeout sequence. */ - if (comp -> prev) { - comp -> prev -> next = comp -> next; - } else { - comp -> shared_network -> leases = comp -> next; - } - if (comp -> next) { - comp -> next -> prev = comp -> prev; - } - if (comp -> shared_network -> last_lease == comp) { - comp -> shared_network -> last_lease = comp -> prev; - } - - /* Find the last insertion point... */ - if (comp == comp -> shared_network -> insertion_point || - !comp -> shared_network -> insertion_point) { - lp = comp -> shared_network -> leases; - } else { - lp = comp -> shared_network -> insertion_point; - } - - if (!lp) { - /* Nothing on the list yet? Just make comp the - head of the list. */ - comp -> shared_network -> leases = comp; - comp -> shared_network -> last_lease = comp; - } else if (lp -> ends > lease -> ends) { - /* Skip down the list until we run out of list - or find a place for comp. */ - while (lp -> next && lp -> ends > lease -> ends) { - lp = lp -> next; - } - if (lp -> ends > lease -> ends) { - /* If we ran out of list, put comp - at the end. */ - lp -> next = comp; - comp -> prev = lp; - comp -> next = (struct lease *)0; - comp -> shared_network -> last_lease = comp; - } else { - /* If we didn't, put it between lp and - the previous item on the list. */ - if ((comp -> prev = lp -> prev)) - comp -> prev -> next = comp; - comp -> next = lp; - lp -> prev = comp; - } - } else { - /* Skip up the list until we run out of list - or find a place for comp. */ - while (lp -> prev && lp -> ends < lease -> ends) { - lp = lp -> prev; - } - if (lp -> ends < lease -> ends) { - /* If we ran out of list, put comp - at the beginning. */ - lp -> prev = comp; - comp -> next = lp; - comp -> prev = (struct lease *)0; - comp -> shared_network -> leases = comp; - } else { - /* If we didn't, put it between lp and - the next item on the list. */ - if ((comp -> next = lp -> next)) - comp -> next -> prev = comp; - comp -> prev = lp; - lp -> next = comp; + group -> flags |= GROUP_OBJECT_DELETED; + if (group -> group) + group_dereference (&group -> group, MDL); + } + + /* Store the group declaration in the lease file. */ + if (writep && group_write_hook) { + if (!(*group_write_hook) (group)) + return ISC_R_IOERROR; + } + return ISC_R_SUCCESS; +} + +isc_result_t supersede_group (struct group_object *group, int writep) +{ + struct group_object *t, *u; + isc_result_t status; + + /* Register the group in the group name hash table, + so we can look it up later. */ + if (group_name_hash) { + t = (struct group_object *)0; + group_hash_lookup (&t, group_name_hash, + group -> name, + strlen (group -> name), MDL); + if (t && t != group) { + /* If this isn't a dynamic entry, then we need to flag + the replacement as not dynamic either - otherwise, + if the dynamic entry is deleted later, the static + entry will come back next time the server is stopped + and restarted. */ + if (!(t -> flags & GROUP_OBJECT_DYNAMIC)) + group -> flags |= GROUP_OBJECT_STATIC; + + /* Delete the old object if it hasn't already been + deleted. If it has already been deleted, get rid of + the hash table entry. This is a legitimate + situation - a deleted static object needs to be kept + around so we remember it's deleted. */ + if (!(t -> flags & GROUP_OBJECT_DELETED)) + delete_group (t, 0); + else { + group_hash_delete (group_name_hash, + group -> name, + strlen (group -> name), + MDL); + group_object_dereference (&t, MDL); } } - comp -> shared_network -> insertion_point = comp; - comp -> ends = lease -> ends; - } - - /* Return zero if we didn't commit the lease to permanent storage; - nonzero if we did. */ - return commit && write_lease (comp) && commit_leases (); -} - -/* Release the specified lease and re-hash it as appropriate. */ - -void release_lease (lease) - struct lease *lease; -{ - struct lease lt; - - lt = *lease; - if (lt.ends > cur_time) { - lt.ends = cur_time; - supersede_lease (lease, <, 1); - } -} - -/* Abandon the specified lease (set its timeout to infinity and its - particulars to zero, and re-hash it as appropriate. */ - -void abandon_lease (lease, message) - struct lease *lease; - char *message; -{ - struct lease lt; - - lease -> flags |= ABANDONED_LEASE; - lt = *lease; - lt.ends = cur_time; - warn ("Abandoning IP address %s: %s", - piaddr (lease -> ip_addr), message); - lt.hardware_addr.htype = 0; - lt.hardware_addr.hlen = 0; - lt.uid = (unsigned char *)0; - lt.uid_len = 0; - supersede_lease (lease, <, 1); -} - -/* Locate the lease associated with a given IP address... */ - -struct lease *find_lease_by_ip_addr (addr) - struct iaddr addr; -{ - struct lease *lease = (struct lease *)hash_lookup (lease_ip_addr_hash, - addr.iabuf, - addr.len); - return lease; -} - -struct lease *find_lease_by_uid (uid, len) - unsigned char *uid; - int len; -{ - struct lease *lease = (struct lease *)hash_lookup (lease_uid_hash, - uid, len); - return lease; -} - -struct lease *find_lease_by_hw_addr (hwaddr, hwlen) - unsigned char *hwaddr; - int hwlen; -{ - struct lease *lease = (struct lease *)hash_lookup (lease_hw_addr_hash, - hwaddr, hwlen); - return lease; -} - -/* Add the specified lease to the uid hash. */ - -void uid_hash_add (lease) - struct lease *lease; -{ - struct lease *head = - find_lease_by_uid (lease -> uid, lease -> uid_len); - struct lease *scan; - -#ifdef DEBUG - if (lease -> n_uid) - abort (); -#endif - - /* If it's not in the hash, just add it. */ - if (!head) - add_hash (lease_uid_hash, lease -> uid, - lease -> uid_len, (unsigned char *)lease); - else { - /* Otherwise, attach it to the end of the list. */ - for (scan = head; scan -> n_uid; scan = scan -> n_uid) -#ifdef DEBUG - if (scan == lease) - abort () -#endif - ; - scan -> n_uid = lease; - } -} - -/* Delete the specified lease from the uid hash. */ - -void uid_hash_delete (lease) - struct lease *lease; -{ - struct lease *head = - find_lease_by_uid (lease -> uid, lease -> uid_len); - struct lease *scan; - - /* If it's not in the hash, we have no work to do. */ - if (!head) { - lease -> n_uid = (struct lease *)0; - return; - } - - /* If the lease we're freeing is at the head of the list, - remove the hash table entry and add a new one with the - next lease on the list (if there is one). */ - if (head == lease) { - delete_hash_entry (lease_uid_hash, - lease -> uid, lease -> uid_len); - if (lease -> n_uid) - add_hash (lease_uid_hash, - lease -> n_uid -> uid, - lease -> n_uid -> uid_len, - (unsigned char *)(lease -> n_uid)); } else { - /* Otherwise, look for the lease in the list of leases - attached to the hash table entry, and remove it if - we find it. */ - for (scan = head; scan -> n_uid; scan = scan -> n_uid) { - if (scan -> n_uid == lease) { - scan -> n_uid = scan -> n_uid -> n_uid; - break; - } - } + group_new_hash (&group_name_hash, 0, MDL); + t = (struct group_object *)0; } - lease -> n_uid = (struct lease *)0; -} - -/* Add the specified lease to the hardware address hash. */ -void hw_hash_add (lease) - struct lease *lease; -{ - struct lease *head = - find_lease_by_hw_addr (lease -> hardware_addr.haddr, - lease -> hardware_addr.hlen); - struct lease *scan; - - /* If it's not in the hash, just add it. */ - if (!head) - add_hash (lease_hw_addr_hash, - lease -> hardware_addr.haddr, - lease -> hardware_addr.hlen, - (unsigned char *)lease); - else { - /* Otherwise, attach it to the end of the list. */ - for (scan = head; scan -> n_hw; scan = scan -> n_hw) - ; - scan -> n_hw = lease; - } -} - -/* Delete the specified lease from the hardware address hash. */ - -void hw_hash_delete (lease) - struct lease *lease; -{ - struct lease *head = - find_lease_by_hw_addr (lease -> hardware_addr.haddr, - lease -> hardware_addr.hlen); - struct lease *scan; - - /* If it's not in the hash, we have no work to do. */ - if (!head) { - lease -> n_hw = (struct lease *)0; - return; + /* Add the group to the group name hash if it's not + already there, and also thread it into the list of + dynamic groups if appropriate. */ + if (!t) { + group_hash_add (group_name_hash, group -> name, + strlen (group -> name), group, MDL); } - /* If the lease we're freeing is at the head of the list, - remove the hash table entry and add a new one with the - next lease on the list (if there is one). */ - if (head == lease) { - delete_hash_entry (lease_hw_addr_hash, - lease -> hardware_addr.haddr, - lease -> hardware_addr.hlen); - if (lease -> n_hw) - add_hash (lease_hw_addr_hash, - lease -> n_hw -> hardware_addr.haddr, - lease -> n_hw -> hardware_addr.hlen, - (unsigned char *)(lease -> n_hw)); - } else { - /* Otherwise, look for the lease in the list of leases - attached to the hash table entry, and remove it if - we find it. */ - for (scan = head; scan -> n_hw; scan = scan -> n_hw) { - if (scan -> n_hw == lease) { - scan -> n_hw = scan -> n_hw -> n_hw; - break; - } - } + /* Store the group declaration in the lease file. */ + if (writep && group_write_hook) { + if (!(*group_write_hook) (group)) + return ISC_R_IOERROR; } - lease -> n_hw = (struct lease *)0; + return ISC_R_SUCCESS; } - -struct class *add_class (type, name) - int type; - char *name; +int clone_group (struct group **gp, struct group *group, + const char *file, int line) { - struct class *class = new_class ("add_class"); - char *tname = (char *)malloc (strlen (name) + 1); - - if (!vendor_class_hash) - vendor_class_hash = new_hash (); - if (!user_class_hash) - user_class_hash = new_hash (); + isc_result_t status; + struct group *g = (struct group *)0; - if (!tname || !class || !vendor_class_hash || !user_class_hash) - return (struct class *)0; - - memset (class, 0, sizeof *class); - strcpy (tname, name); - class -> name = tname; - - if (type) - add_hash (user_class_hash, - (unsigned char *)tname, strlen (tname), - (unsigned char *)class); - else - add_hash (vendor_class_hash, - (unsigned char *)tname, strlen (tname), - (unsigned char *)class); - return class; -} - -struct class *find_class (type, name, len) - int type; - unsigned char *name; - int len; -{ - struct class *class = - (struct class *)hash_lookup (type - ? user_class_hash - : vendor_class_hash, name, len); - return class; -} - -struct group *clone_group (group, caller) - struct group *group; - char *caller; -{ - struct group *g = new_group (caller); - if (!g) - error ("%s: can't allocate new group", caller); - *g = *group; - return g; -} - -/* Write all interesting leases to permanent storage. */ - -void write_leases () -{ - struct lease *l; - struct shared_network *s; - - for (s = shared_networks; s; s = s -> next) { - for (l = s -> leases; l; l = l -> next) { - if (l -> hardware_addr.hlen || - l -> uid_len || - (l -> flags & ABANDONED_LEASE)) - if (!write_lease (l)) - error ("Can't rewrite lease database"); - } - } - if (!commit_leases ()) - error ("Can't commit leases to new database: %m"); -} - -void dump_subnets () -{ - struct lease *l; - struct shared_network *s; - struct subnet *n; - - note ("Subnets:"); - for (n = subnets; n; n = n -> next_subnet) { - debug (" Subnet %s", piaddr (n -> net)); - debug (" netmask %s", - piaddr (n -> netmask)); - } - note ("Shared networks:"); - for (s = shared_networks; s; s = s -> next) { - note (" %s", s -> name); - for (l = s -> leases; l; l = l -> next) { - print_lease (l); - } - if (s -> last_lease) { - debug (" Last Lease:"); - print_lease (s -> last_lease); - } - } + /* Normally gp should contain the null pointer, but for convenience + it's permissible to clone a group into itself. */ + if (*gp && *gp != group) + return 0; + if (!group_allocate (&g, file, line)) + return 0; + if (group == *gp) + *gp = (struct group *)0; + group_reference (gp, g, file, line); + g -> authoritative = group -> authoritative; + group_reference (&g -> next, group, file, line); + group_dereference (&g, file, line); + return 1; } diff --git a/contrib/isc-dhcp/common/nit.c b/contrib/isc-dhcp/common/nit.c index 77f43b3..59197f2a4 100644 --- a/contrib/isc-dhcp/common/nit.c +++ b/contrib/isc-dhcp/common/nit.c @@ -4,7 +4,7 @@ with one crucial tidbit of help from Stu Grossmen. */ /* - * Copyright (c) 1996, 1998, 1999 The Internet Software Consortium. + * Copyright (c) 1996-2000 Internet Software Consortium. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -35,14 +35,16 @@ * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium - * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie - * Enterprises. To learn more about the Internet Software Consortium, - * see ``http://www.vix.com/isc''. To learn more about Vixie - * Enterprises, see ``http://www.vix.com''. */ + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. + */ #ifndef lint static char copyright[] = -"$Id: nit.c,v 1.15.2.4 1999/03/29 22:07:14 mellon Exp $ Copyright (c) 1996 The Internet Software Consortium. All rights reserved.\n"; +"$Id: nit.c,v 1.34 2001/02/17 21:17:25 mellon Exp $ Copyright (c) 1996-2000 The Internet Software Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -95,7 +97,7 @@ int if_register_nit (info) /* Open a NIT device */ sock = open ("/dev/nit", O_RDWR); if (sock < 0) - error ("Can't open NIT device for %s: %m", info -> name); + log_fatal ("Can't open NIT device for %s: %m", info -> name); /* Set the NIT device to point at this interface. */ sio.ic_cmd = NIOCBIND; @@ -103,7 +105,7 @@ int if_register_nit (info) sio.ic_dp = (char *)(info -> ifp); sio.ic_timout = INFTIM; if (ioctl (sock, I_STR, &sio) < 0) - error ("Can't attach interface %s to nit device: %m", + log_fatal ("Can't attach interface %s to nit device: %m", info -> name); /* Get the low-level address... */ @@ -112,16 +114,17 @@ int if_register_nit (info) sio.ic_dp = (char *)𝔦 sio.ic_timout = INFTIM; if (ioctl (sock, I_STR, &sio) < 0) - error ("Can't get physical layer address for %s: %m", + log_fatal ("Can't get physical layer address for %s: %m", info -> name); /* XXX code below assumes ethernet interface! */ - info -> hw_address.hlen = 6; - info -> hw_address.htype = ARPHRD_ETHER; - memcpy (info -> hw_address.haddr, ifr.ifr_ifru.ifru_addr.sa_data, 6); + info -> hw_address.hlen = 7; + info -> hw_address.hbuf [0] = ARPHRD_ETHER; + memcpy (&info -> hw_address.hbuf [1], + ifr.ifr_ifru.ifru_addr.sa_data, 6); if (ioctl (sock, I_PUSH, "pf") < 0) - error ("Can't push packet filter onto NIT for %s: %m", + log_fatal ("Can't push packet filter onto NIT for %s: %m", info -> name); return sock; @@ -150,15 +153,34 @@ void if_register_send (info) sio.ic_dp = (char *)&pf; sio.ic_timout = INFTIM; if (ioctl (info -> wfdesc, I_STR, &sio) < 0) - error ("Can't set NIT filter: %m"); + log_fatal ("Can't set NIT filter: %m"); #else info -> wfdesc = info -> rfdesc; #endif if (!quiet_interface_discovery) - note ("Sending on NIT/%s%s%s", - print_hw_addr (info -> hw_address.htype, - info -> hw_address.hlen, - info -> hw_address.haddr), + log_info ("Sending on NIT/%s%s%s", + print_hw_addr (info -> hw_address.hbuf [0], + info -> hw_address.hlen - 1, + &info -> hw_address.hbuf [1]), + (info -> shared_network ? "/" : ""), + (info -> shared_network ? + info -> shared_network -> name : "")); +} + +void if_deregister_send (info) + struct interface_info *info; +{ + /* If we're using the nit API for sending and receiving, + we don't need to register this interface twice. */ +#ifndef USE_NIT_RECEIVE + close (info -> wfdesc); +#endif + info -> wfdesc = -1; + if (!quiet_interface_discovery) + log_info ("Disabling output on NIT/%s%s%s", + print_hw_addr (info -> hw_address.hbuf [0], + info -> hw_address.hlen - 1, + &info -> hw_address.hbuf [1]), (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : "")); @@ -187,28 +209,28 @@ void if_register_receive (info) packet. */ x = 0; if (ioctl (info -> rfdesc, NIOCSSNAP, &x) < 0) - error ("Can't set NIT snap length on %s: %m", info -> name); + log_fatal ("Can't set NIT snap length on %s: %m", info -> name); /* Set the stream to byte stream mode */ if (ioctl (info -> rfdesc, I_SRDOPT, RMSGN) != 0) - note ("I_SRDOPT failed on %s: %m", info -> name); + log_info ("I_SRDOPT failed on %s: %m", info -> name); #if 0 /* Push on the chunker... */ if (ioctl (info -> rfdesc, I_PUSH, "nbuf") < 0) - error ("Can't push chunker onto NIT STREAM: %m"); + log_fatal ("Can't push chunker onto NIT STREAM: %m"); /* Set the timeout to zero. */ t.tv_sec = 0; t.tv_usec = 0; if (ioctl (info -> rfdesc, NIOCSTIME, &t) < 0) - error ("Can't set chunk timeout: %m"); + log_fatal ("Can't set chunk timeout: %m"); #endif /* Ask for no header... */ x = 0; if (ioctl (info -> rfdesc, NIOCSFLAGS, &x) < 0) - error ("Can't set NIT flags on %s: %m", info -> name); + log_fatal ("Can't set NIT flags on %s: %m", info -> name); /* Set up the NIT filter program. */ /* XXX Unlike the BPF filter program, this one won't work if the @@ -236,13 +258,31 @@ void if_register_receive (info) sio.ic_dp = (char *)&pf; sio.ic_timout = INFTIM; if (ioctl (info -> rfdesc, I_STR, &sio) < 0) - error ("Can't set NIT filter on %s: %m", info -> name); + log_fatal ("Can't set NIT filter on %s: %m", info -> name); if (!quiet_interface_discovery) - note ("Listening on NIT/%s%s%s", - print_hw_addr (info -> hw_address.htype, - info -> hw_address.hlen, - info -> hw_address.haddr), + log_info ("Listening on NIT/%s%s%s", + print_hw_addr (info -> hw_address.hbuf [0], + info -> hw_address.hlen - 1, + &info -> hw_address.hbuf [1]), + (info -> shared_network ? "/" : ""), + (info -> shared_network ? + info -> shared_network -> name : "")); +} + +void if_deregister_receive (info) + struct interface_info *info; +{ + /* If we're using the nit API for sending and receiving, + we don't need to register this interface twice. */ + close (info -> rfdesc); + info -> rfdesc = -1; + + if (!quiet_interface_discovery) + log_info ("Disabling input on NIT/%s%s%s", + print_hw_addr (info -> hw_address.hbuf [0], + info -> hw_address.hlen - 1, + &info -> hw_address.hbuf [1]), (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : "")); @@ -259,11 +299,12 @@ ssize_t send_packet (interface, packet, raw, len, from, to, hto) struct sockaddr_in *to; struct hardware *hto; { - int bufp; - unsigned char buf [1536 + sizeof (struct sockaddr)]; + unsigned hbufp, ibufp; + double hh [16]; + double ih [1536 / sizeof (double)]; + unsigned char *buf = (unsigned char *)ih; struct sockaddr *junk; struct strbuf ctl, data; - int hw_end; struct sockaddr_in foo; int result; @@ -272,38 +313,35 @@ ssize_t send_packet (interface, packet, raw, len, from, to, hto) len, from, to, hto); /* Start with the sockaddr struct... */ - junk = (struct sockaddr *)&buf [0]; - bufp = ((unsigned char *)&junk -> sa_data [0]) - &buf [0]; + junk = (struct sockaddr *)&hh [0]; + hbufp = (((unsigned char *)&junk -> sa_data [0]) - + (unsigned char *)&hh[0]); + ibufp = 0; /* Assemble the headers... */ - assemble_hw_header (interface, buf, &bufp, hto); - hw_end = bufp; - assemble_udp_ip_header (interface, buf, &bufp, from.s_addr, - to -> sin_addr.s_addr, to -> sin_port, - raw, len); + assemble_hw_header (interface, (unsigned char *)junk, &hbufp, hto); + assemble_udp_ip_header (interface, buf, &ibufp, + from.s_addr, to -> sin_addr.s_addr, + to -> sin_port, (unsigned char *)raw, len); /* Copy the data into the buffer (yuk). */ - memcpy (buf + bufp, raw, len); + memcpy (buf + ibufp, raw, len); /* Set up the sockaddr structure... */ #if USE_SIN_LEN - junk -> sa_len = hw_end - 2; /* XXX */ + junk -> sa_len = hbufp - 2; /* XXX */ #endif junk -> sa_family = AF_UNSPEC; -#if 0 /* Already done. */ - memcpy (junk.sa_data, buf, hw_len); -#endif - /* Set up the msg_buf structure... */ - ctl.buf = (char *)&buf [0]; - ctl.maxlen = ctl.len = hw_end; - data.buf = (char *)&buf [hw_end]; - data.maxlen = data.len = bufp + len - hw_end; + ctl.buf = (char *)&hh [0]; + ctl.maxlen = ctl.len = hbufp; + data.buf = (char *)&ih [0]; + data.maxlen = data.len = ibufp + len; result = putmsg (interface -> wfdesc, &ctl, &data, 0); if (result < 0) - warn ("send_packet: %m"); + log_error ("send_packet: %m"); return result; } #endif /* USE_NIT_SEND */ @@ -355,7 +393,8 @@ ssize_t receive_packet (interface, buf, len, from, hfrom) return length; } -int can_unicast_without_arp () +int can_unicast_without_arp (ip) + struct interface_info *ip; { return 1; } @@ -366,14 +405,25 @@ int can_receive_unicast_unconfigured (ip) return 1; } +int supports_multiple_interfaces (ip) + struct interface_info *ip; +{ + return 1; +} + void maybe_setup_fallback () { - struct interface_info *fbi; - fbi = setup_fallback (); - if (fbi) { + isc_result_t status; + struct interface_info *fbi = (struct interface_info *)0; + if (setup_fallback (&fbi, MDL)) { if_register_fallback (fbi); - add_protocol ("fallback", fallback_interface -> wfdesc, - fallback_discard, fallback_interface); + status = omapi_register_io_object ((omapi_object_t *)fbi, + if_readsocket, 0, + fallback_discard, 0, 0); + if (status != ISC_R_SUCCESS) + log_fatal ("Can't register I/O handle for %s: %s", + fbi -> name, isc_result_totext (status)); + interface_dereference (&fbi, MDL); } } #endif diff --git a/contrib/isc-dhcp/common/options.c b/contrib/isc-dhcp/common/options.c index b840716..b7a5a04 100644 --- a/contrib/isc-dhcp/common/options.c +++ b/contrib/isc-dhcp/common/options.c @@ -3,7 +3,7 @@ DHCP options parsing and reassembly. */ /* - * Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium. + * Copyright (c) 1995-2001 Internet Software Consortium. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,176 +34,470 @@ * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium - * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie - * Enterprises. To learn more about the Internet Software Consortium, - * see ``http://www.vix.com/isc''. To learn more about Vixie - * Enterprises, see ``http://www.vix.com''. + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. */ #ifndef lint static char copyright[] = -"$Id: options.c,v 1.26.2.11 2000/06/24 07:24:02 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium. All rights reserved.\n"; +"$Id: options.c,v 1.85.2.6 2001/10/18 20:11:38 mellon Exp $ Copyright (c) 1995-2001 The Internet Software Consortium. All rights reserved.\n"; #endif /* not lint */ #define DHCP_OPTION_DATA #include "dhcpd.h" -#include <ctype.h> +#include <omapip/omapip_p.h> + +struct option *vendor_cfg_option; + +static void do_option_set PROTO ((pair *, + struct option_cache *, + enum statement_op)); /* Parse all available options out of the specified packet. */ -void parse_options (packet) +int parse_options (packet) struct packet *packet; { - /* Initially, zero all option pointers. */ - memset (packet -> options, 0, sizeof (packet -> options)); + int i; + struct option_cache *op = (struct option_cache *)0; + + /* Allocate a new option state. */ + if (!option_state_allocate (&packet -> options, MDL)) { + packet -> options_valid = 0; + return 0; + } /* If we don't see the magic cookie, there's nothing to parse. */ if (memcmp (packet -> raw -> options, DHCP_OPTIONS_COOKIE, 4)) { packet -> options_valid = 0; - return; + return 1; } /* Go through the options field, up to the end of the packet or the End field. */ - parse_option_buffer (packet, &packet -> raw -> options [4], - packet -> packet_length - DHCP_FIXED_NON_UDP - 4); + if (!parse_option_buffer (packet -> options, + &packet -> raw -> options [4], + (packet -> packet_length - + DHCP_FIXED_NON_UDP - 4), + &dhcp_universe)) + return 0; + /* If we parsed a DHCP Option Overload option, parse more options out of the buffer(s) containing them. */ - if (packet -> options_valid - && packet -> options [DHO_DHCP_OPTION_OVERLOAD].data) { - if (packet -> options [DHO_DHCP_OPTION_OVERLOAD].data [0] & 1) - parse_option_buffer (packet, - (unsigned char *) - packet -> raw -> file, - sizeof packet -> raw -> file); - if (packet -> options [DHO_DHCP_OPTION_OVERLOAD].data [0] & 2) - parse_option_buffer (packet, - (unsigned char *) - packet -> raw -> sname, - sizeof packet -> raw -> sname); + if (packet -> options_valid && + (op = lookup_option (&dhcp_universe, packet -> options, + DHO_DHCP_OPTION_OVERLOAD))) { + if (op -> data.data [0] & 1) { + if (!parse_option_buffer + (packet -> options, + (unsigned char *)packet -> raw -> file, + sizeof packet -> raw -> file, + &dhcp_universe)) + return 0; + } + if (op -> data.data [0] & 2) { + if (!parse_option_buffer + (packet -> options, + (unsigned char *)packet -> raw -> sname, + sizeof packet -> raw -> sname, + &dhcp_universe)) + return 0; + } } + packet -> options_valid = 1; + return 1; } /* Parse options out of the specified buffer, storing addresses of option values in packet -> options and setting packet -> options_valid if no errors are encountered. */ -void parse_option_buffer (packet, buffer, length) - struct packet *packet; - unsigned char *buffer; - int length; +int parse_option_buffer (options, buffer, length, universe) + struct option_state *options; + const unsigned char *buffer; + unsigned length; + struct universe *universe; { - unsigned char *s, *t; - unsigned char *end = buffer + length; - int len; + unsigned char *t; + const unsigned char *end = buffer + length; + unsigned len, offset; int code; + struct option_cache *op = (struct option_cache *)0; + struct buffer *bp = (struct buffer *)0; - for (s = buffer; *s != DHO_END && s < end; ) { - code = s [0]; + if (!buffer_allocate (&bp, length, MDL)) { + log_error ("no memory for option buffer."); + return 0; + } + memcpy (bp -> data, buffer, length); + + for (offset = 0; buffer [offset] != DHO_END && offset < length; ) { + code = buffer [offset]; /* Pad options don't have a length - just skip them. */ if (code == DHO_PAD) { - ++s; + ++offset; continue; } + + /* Don't look for length if the buffer isn't that big. */ + if (offset + 2 > length) { + len = 65536; + goto bogus; + } + /* All other fields (except end, see above) have a one-byte length. */ - len = s [1]; + len = buffer [offset + 1]; /* If the length is outrageous, the options are bad. */ - if (s + len + 2 > end) { - warn ("Option %s length %d overflows input buffer.", - dhcp_options [code].name, - len); - packet -> options_valid = 0; - return; + if (offset + len + 2 > length) { + bogus: + log_error ("parse_option_buffer: option %s (%d) %s.", + dhcp_options [code].name, len, + "larger than buffer"); + buffer_dereference (&bp, MDL); + return 0; } - /* If we haven't seen this option before, just make - space for it and copy it there. */ - if (!packet -> options [code].data) { - if (!(t = ((unsigned char *) - dmalloc (len + 1, "parse_option_buffer")))) - error ("Can't allocate storage for option %s.", - dhcp_options [code].name); - /* Copy and NUL-terminate the option (in case it's an - ASCII string. */ - memcpy (t, &s [2], len); - t [len] = 0; - packet -> options [code].len = len; - packet -> options [code].data = t; - } else { - /* If it's a repeat, concatenate it to whatever - we last saw. This is really only required - for clients, but what the heck... */ - t = ((unsigned char *) - dmalloc (len + packet -> options [code].len + 1, - "parse_option_buffer")); - if (!t) - error ("Can't expand storage for option %s.", - dhcp_options [code].name); - memcpy (t, packet -> options [code].data, - packet -> options [code].len); - memcpy (t + packet -> options [code].len, - &s [2], len); - packet -> options [code].len += len; - t [packet -> options [code].len] = 0; - dfree (packet -> options [code].data, - "parse_option_buffer"); - packet -> options [code].data = t; - } - s += len + 2; + + /* If the option contains an encapsulation, parse it. If + the parse fails, or the option isn't an encapsulation (by + far the most common case), or the option isn't entirely + an encapsulation, keep the raw data as well. */ + if (!((universe -> options [code] -> format [0] == 'e' || + universe -> options [code] -> format [0] == 'E') && + (parse_encapsulated_suboptions + (options, universe -> options [code], + buffer + offset + 2, len, + universe, (const char *)0)))) { + save_option_buffer (universe, options, bp, + &bp -> data [offset + 2], len, + universe -> options [code], 1); + } + offset += len + 2; } - packet -> options_valid = 1; + buffer_dereference (&bp, MDL); + return 1; +} + +/* If an option in an option buffer turns out to be an encapsulation, + figure out what to do. If we don't know how to de-encapsulate it, + or it's not well-formed, return zero; otherwise, return 1, indicating + that we succeeded in de-encapsulating it. */ + +struct universe *find_option_universe (struct option *eopt, const char *uname) +{ + int i; + char *s, *t; + struct universe *universe = (struct universe *)0; + + /* Look for the E option in the option format. */ + s = strchr (eopt -> format, 'E'); + if (!s) { + log_error ("internal encapsulation format error 1."); + return 0; + } + /* Look for the universe name in the option format. */ + t = strchr (++s, '.'); + /* If there was no trailing '.', or there's something after the + trailing '.', the option is bogus and we can't use it. */ + if (!t || t [1]) { + log_error ("internal encapsulation format error 2."); + return 0; + } + if (t == s && uname) { + for (i = 0; i < universe_count; i++) { + if (!strcmp (universes [i] -> name, uname)) { + universe = universes [i]; + break; + } + } + } else if (t != s) { + for (i = 0; i < universe_count; i++) { + if (strlen (universes [i] -> name) == t - s && + !memcmp (universes [i] -> name, + s, (unsigned)(t - s))) { + universe = universes [i]; + break; + } + } + } + return universe; +} + +/* If an option in an option buffer turns out to be an encapsulation, + figure out what to do. If we don't know how to de-encapsulate it, + or it's not well-formed, return zero; otherwise, return 1, indicating + that we succeeded in de-encapsulating it. */ + +int parse_encapsulated_suboptions (struct option_state *options, + struct option *eopt, + const unsigned char *buffer, + unsigned len, struct universe *eu, + const char *uname) +{ + int i; + struct universe *universe = find_option_universe (eopt, uname); + + /* If we didn't find the universe, we can't do anything with it + right now (e.g., we can't decode vendor options until we've + decoded the packet and executed the scopes that it matches). */ + if (!universe) + return 0; + + /* If we don't have a decoding function for it, we can't decode + it. */ + if (!universe -> decode) + return 0; + + i = (*universe -> decode) (options, buffer, len, universe); + + /* If there is stuff before the suboptions, we have to keep it. */ + if (eopt -> format [0] != 'E') + return 0; + /* Otherwise, return the status of the decode function. */ + return i; +} + +int fqdn_universe_decode (struct option_state *options, + const unsigned char *buffer, + unsigned length, struct universe *u) +{ + char *name; + struct buffer *bp = (struct buffer *)0; + + /* FQDN options have to be at least four bytes long. */ + if (length < 3) + return 0; + + /* Save the contents of the option in a buffer. */ + if (!buffer_allocate (&bp, length + 4, MDL)) { + log_error ("no memory for option buffer."); + return 0; + } + memcpy (&bp -> data [3], buffer + 1, length - 1); + + if (buffer [0] & 4) /* encoded */ + bp -> data [0] = 1; + else + bp -> data [0] = 0; + if (!save_option_buffer (&fqdn_universe, options, bp, + &bp -> data [0], 1, + &fqdn_options [FQDN_ENCODED], 0)) { + bad: + buffer_dereference (&bp, MDL); + return 0; + } + + if (buffer [0] & 1) /* server-update */ + bp -> data [2] = 1; + else + bp -> data [2] = 0; + if (buffer [0] & 2) /* no-client-update */ + bp -> data [1] = 1; + else + bp -> data [1] = 0; + + /* XXX Ideally we should store the name in DNS format, so if the + XXX label isn't in DNS format, we convert it to DNS format, + XXX rather than converting labels specified in DNS format to + XXX the plain ASCII representation. But that's hard, so + XXX not now. */ + + /* Not encoded using DNS format? */ + if (!bp -> data [0]) { + unsigned i; + + /* Some broken clients NUL-terminate this option. */ + if (buffer [length - 1] == 0) { + --length; + bp -> data [1] = 1; + } + + /* Determine the length of the hostname component of the + name. If the name contains no '.' character, it + represents a non-qualified label. */ + for (i = 3; i < length && buffer [i] != '.'; i++); + i -= 3; + + /* Note: If the client sends a FQDN, the first '.' will + be used as a NUL terminator for the hostname. */ + if (i) + if (!save_option_buffer (&fqdn_universe, options, bp, + &bp -> data[5], i, + &fqdn_options [FQDN_HOSTNAME], + 0)) + goto bad; + /* Note: If the client sends a single label, the + FQDN_DOMAINNAME option won't be set. */ + if (length > 4 + i && + !save_option_buffer (&fqdn_universe, options, bp, + &bp -> data[6 + i], length - 4 - i, + &fqdn_options [FQDN_DOMAINNAME], 1)) + goto bad; + /* Also save the whole name. */ + if (length > 3) + if (!save_option_buffer (&fqdn_universe, options, bp, + &bp -> data [5], length - 3, + &fqdn_options [FQDN_FQDN], 1)) + goto bad; + } else { + unsigned len; + unsigned total_len = 0; + unsigned first_len = 0; + int terminated = 0; + unsigned char *s; + + s = &bp -> data[5]; + + while (s < &bp -> data[0] + length + 2) { + len = *s; + if (len > 63) { + log_info ("fancy bits in fqdn option"); + return 0; + } + if (len == 0) { + terminated = 1; + break; + } + if (s + len > &bp -> data [0] + length + 3) { + log_info ("fqdn tag longer than buffer"); + return 0; + } + + if (first_len == 0) { + first_len = len; + } + + *s = '.'; + s += len + 1; + total_len += len; + } + + if (!terminated) { + first_len = total_len; + } + + if (first_len > 0 && + !save_option_buffer (&fqdn_universe, options, bp, + &bp -> data[6], first_len, + &fqdn_options [FQDN_HOSTNAME], 0)) + goto bad; + if (total_len > 0 && first_len != total_len) { + if (!save_option_buffer + (&fqdn_universe, options, bp, + &bp -> data[6 + first_len], total_len - first_len, + &fqdn_options [FQDN_DOMAINNAME], 1)) + goto bad; + } + if (total_len > 0) + if (!save_option_buffer (&fqdn_universe, options, bp, + &bp -> data [6], total_len, + &fqdn_options [FQDN_FQDN], 1)) + goto bad; + } + + if (!save_option_buffer (&fqdn_universe, options, bp, + &bp -> data [1], 1, + &fqdn_options [FQDN_NO_CLIENT_UPDATE], 0)) + goto bad; + if (!save_option_buffer (&fqdn_universe, options, bp, + &bp -> data [2], 1, + &fqdn_options [FQDN_SERVER_UPDATE], 0)) + goto bad; + + if (!save_option_buffer (&fqdn_universe, options, bp, + &bp -> data [3], 1, + &fqdn_options [FQDN_RCODE1], 0)) + goto bad; + if (!save_option_buffer (&fqdn_universe, options, bp, + &bp -> data [4], 1, + &fqdn_options [FQDN_RCODE2], 0)) + goto bad; + + buffer_dereference (&bp, MDL); + return 1; } /* cons options into a big buffer, and then split them out into the three seperate buffers if needed. This allows us to cons up a set of vendor options using the same routine. */ -int cons_options (inpacket, outpacket, mms, - options, overload, terminate, bootpp, prl, prl_len) +int cons_options (inpacket, outpacket, lease, client_state, + mms, in_options, cfg_options, + scope, overload, terminate, bootpp, prl, vuname) struct packet *inpacket; struct dhcp_packet *outpacket; + struct lease *lease; + struct client_state *client_state; int mms; - struct tree_cache **options; + struct option_state *in_options; + struct option_state *cfg_options; + struct binding_scope **scope; int overload; /* Overload flags that may be set. */ int terminate; int bootpp; - u_int8_t *prl; - int prl_len; + struct data_string *prl; + const char *vuname; { - unsigned char priority_list [300]; +#define PRIORITY_COUNT 300 + unsigned priority_list [PRIORITY_COUNT]; int priority_len; unsigned char buffer [4096]; /* Really big buffer... */ - int main_buffer_size; - int mainbufix, bufix; - int option_size; - int length; + unsigned main_buffer_size; + unsigned mainbufix, bufix, agentix; + unsigned option_size; + unsigned length; + int i; + struct option_cache *op; + struct data_string ds; + pair pp, *hash; + int need_endopt = 0; + int have_sso = 0; - /* If the client has provided a maximum DHCP message size, - use that; otherwise, if it's BOOTP, only 64 bytes; otherwise - use up to the minimum IP MTU size (576 bytes). */ - /* XXX if a BOOTP client specifies a max message size, we will - honor it. */ - if (!mms && - inpacket && - inpacket -> options [DHO_DHCP_MAX_MESSAGE_SIZE].data && - (inpacket -> options [DHO_DHCP_MAX_MESSAGE_SIZE].len >= - sizeof (u_int16_t))) - mms = getUShort (inpacket -> options - [DHO_DHCP_MAX_MESSAGE_SIZE].data); + memset (&ds, 0, sizeof ds); + + /* If there's a Maximum Message Size option in the incoming packet + and no alternate maximum message size has been specified, take the + one in the packet. */ + + if (!mms && inpacket && + (op = lookup_option (&dhcp_universe, inpacket -> options, + DHO_DHCP_MAX_MESSAGE_SIZE))) { + evaluate_option_cache (&ds, inpacket, + lease, client_state, in_options, + cfg_options, scope, op, MDL); + if (ds.len >= sizeof (u_int16_t)) + mms = getUShort (ds.data); + data_string_forget (&ds, MDL); + } /* If the client has provided a maximum DHCP message size, use that; otherwise, if it's BOOTP, only 64 bytes; otherwise use up to the minimum IP MTU size (576 bytes). */ /* XXX if a BOOTP client specifies a max message size, we will honor it. */ - if (mms) + + if (mms) { main_buffer_size = mms - DHCP_FIXED_LEN; - else if (bootpp) - main_buffer_size = 64; - else + + /* Enforce a minimum packet size... */ + if (main_buffer_size < (576 - DHCP_FIXED_LEN)) + main_buffer_size = 576 - DHCP_FIXED_LEN; + } else if (bootpp) { + if (inpacket) { + main_buffer_size = + inpacket -> packet_length - DHCP_FIXED_LEN; + if (main_buffer_size < 64) + main_buffer_size = 64; + } else + main_buffer_size = 64; + } else main_buffer_size = 576 - DHCP_FIXED_LEN; + /* Set a hard limit at the size of the output buffer. */ if (main_buffer_size > sizeof buffer) main_buffer_size = sizeof buffer; @@ -213,35 +507,96 @@ int cons_options (inpacket, outpacket, mms, priority_list [priority_len++] = DHO_DHCP_SERVER_IDENTIFIER; priority_list [priority_len++] = DHO_DHCP_LEASE_TIME; priority_list [priority_len++] = DHO_DHCP_MESSAGE; + priority_list [priority_len++] = DHO_DHCP_REQUESTED_ADDRESS; - /* If the client has provided a list of options that it wishes - returned, use it to prioritize. Otherwise, prioritize - based on the default priority list. */ - - if (inpacket && - inpacket -> options [DHO_DHCP_PARAMETER_REQUEST_LIST].data) { - int prlen = (inpacket -> - options [DHO_DHCP_PARAMETER_REQUEST_LIST].len); - if (prlen + priority_len > sizeof priority_list) - prlen = (sizeof priority_list) - priority_len; - - memcpy (&priority_list [priority_len], - (inpacket -> options - [DHO_DHCP_PARAMETER_REQUEST_LIST].data), prlen); - priority_len += prlen; - prl = priority_list; - } else if (prl) { - if (prl_len + priority_len > sizeof priority_list) - prl_len = (sizeof priority_list) - priority_len; - - memcpy (&priority_list [priority_len], prl, prl_len); - priority_len += prl_len; - prl = priority_list; + if (prl && prl -> len > 0) { + if ((op = lookup_option (&dhcp_universe, cfg_options, + DHO_SUBNET_SELECTION))) { + if (priority_len < PRIORITY_COUNT) + priority_list [priority_len++] = + DHO_SUBNET_SELECTION; + } + + data_string_truncate (prl, (PRIORITY_COUNT - priority_len)); + + for (i = 0; i < prl -> len; i++) { + /* Prevent client from changing order of delivery + of relay agent information option. */ + if (prl -> data [i] != DHO_DHCP_AGENT_OPTIONS) + priority_list [priority_len++] = + prl -> data [i]; + } } else { - memcpy (&priority_list [priority_len], - dhcp_option_default_priority_list, - sizeof_dhcp_option_default_priority_list); - priority_len += sizeof_dhcp_option_default_priority_list; + /* First, hardcode some more options that ought to be + sent first... */ + priority_list [priority_len++] = DHO_SUBNET_MASK; + priority_list [priority_len++] = DHO_ROUTERS; + priority_list [priority_len++] = DHO_DOMAIN_NAME_SERVERS; + priority_list [priority_len++] = DHO_HOST_NAME; + + /* Append a list of the standard DHCP options from the + standard DHCP option space. Actually, if a site + option space hasn't been specified, we wind up + treating the dhcp option space as the site option + space, and the first for loop is skipped, because + it's slightly more general to do it this way, + taking the 1Q99 DHCP futures work into account. */ + if (cfg_options -> site_code_min) { + for (i = 0; i < OPTION_HASH_SIZE; i++) { + hash = cfg_options -> universes [dhcp_universe.index]; + for (pp = hash [i]; pp; pp = pp -> cdr) { + op = (struct option_cache *)(pp -> car); + if (op -> option -> code < + cfg_options -> site_code_min && + priority_len < PRIORITY_COUNT && + (op -> option -> code != + DHO_DHCP_AGENT_OPTIONS)) + priority_list [priority_len++] = + op -> option -> code; + } + } + } + + /* Now cycle through the site option space, or if there + is no site option space, we'll be cycling through the + dhcp option space. */ + for (i = 0; i < OPTION_HASH_SIZE; i++) { + hash = (cfg_options -> universes + [cfg_options -> site_universe]); + for (pp = hash [i]; pp; pp = pp -> cdr) { + op = (struct option_cache *)(pp -> car); + if (op -> option -> code >= + cfg_options -> site_code_min && + priority_len < PRIORITY_COUNT && + (op -> option -> code != + DHO_DHCP_AGENT_OPTIONS)) + priority_list [priority_len++] = + op -> option -> code; + } + } + + /* Now go through all the universes for which options + were set and see if there are encapsulations for + them; if there are, put the encapsulation options + on the priority list as well. */ + for (i = 0; i < cfg_options -> universe_count; i++) { + if (cfg_options -> universes [i] && + universes [i] -> enc_opt && + priority_len < PRIORITY_COUNT && + universes [i] -> enc_opt -> universe == &dhcp_universe) + { + if (universes [i] -> enc_opt -> code != + DHO_DHCP_AGENT_OPTIONS) + priority_list [priority_len++] = + universes [i] -> enc_opt -> code; + } + } + + /* The vendor option space can't stand on its own, so always + add it to the list. */ + if (priority_len < PRIORITY_COUNT) + priority_list [priority_len++] = + DHO_VENDOR_ENCAPSULATED_OPTIONS; } /* Copy the options into the big buffer... */ @@ -249,11 +604,13 @@ int cons_options (inpacket, outpacket, mms, (main_buffer_size - 7 + ((overload & 1) ? DHCP_FILE_LEN : 0) + ((overload & 2) ? DHCP_SNAME_LEN : 0)), - options, priority_list, priority_len, + inpacket, lease, client_state, + in_options, cfg_options, scope, + priority_list, priority_len, main_buffer_size, (main_buffer_size + ((overload & 1) ? DHCP_FILE_LEN : 0)), - terminate); + terminate, vuname); /* Put the cookie up front... */ memcpy (outpacket -> options, DHCP_OPTIONS_COOKIE, 4); @@ -267,13 +624,12 @@ int cons_options (inpacket, outpacket, mms, memcpy (&outpacket -> options [mainbufix], buffer, option_size); mainbufix += option_size; + agentix = mainbufix; if (mainbufix < main_buffer_size) - outpacket -> options [mainbufix++] - = DHO_END; + need_endopt = 1; length = DHCP_FIXED_NON_UDP + mainbufix; } else { - outpacket -> options [mainbufix++] = - DHO_DHCP_OPTION_OVERLOAD; + outpacket -> options [mainbufix++] = DHO_DHCP_OPTION_OVERLOAD; outpacket -> options [mainbufix++] = 1; if (option_size > main_buffer_size - mainbufix + DHCP_FILE_LEN) outpacket -> options [mainbufix++] = 3; @@ -282,8 +638,10 @@ int cons_options (inpacket, outpacket, mms, memcpy (&outpacket -> options [mainbufix], buffer, main_buffer_size - mainbufix); + length = DHCP_FIXED_NON_UDP + main_buffer_size; + agentix = main_buffer_size; + bufix = main_buffer_size - mainbufix; - length = DHCP_FIXED_NON_UDP + mainbufix; if (overload & 1) { if (option_size - bufix <= DHCP_FILE_LEN) { memcpy (outpacket -> file, @@ -314,220 +672,400 @@ int cons_options (inpacket, outpacket, mms, = DHO_PAD; } } + + /* Now hack in the agent options if there are any. */ + priority_list [0] = DHO_DHCP_AGENT_OPTIONS; + priority_len = 1; + agentix += + store_options (&outpacket -> options [agentix], + 1500 - DHCP_FIXED_LEN - agentix, + inpacket, lease, client_state, + in_options, cfg_options, scope, + priority_list, priority_len, + 1500 - DHCP_FIXED_LEN - agentix, + 1500 - DHCP_FIXED_LEN - agentix, 0, (char *)0); + + /* Tack a DHO_END option onto the packet if we need to. */ + if (agentix < 1500 - DHCP_FIXED_LEN && need_endopt) + outpacket -> options [agentix++] = DHO_END; + + /* Figure out the length. */ + length = DHCP_FIXED_NON_UDP + agentix; return length; } /* Store all the requested options into the requested buffer. */ -int store_options (buffer, buflen, options, priority_list, priority_len, - first_cutoff, second_cutoff, terminate) +int store_options (buffer, buflen, packet, lease, client_state, + in_options, cfg_options, scope, priority_list, priority_len, + first_cutoff, second_cutoff, terminate, vuname) unsigned char *buffer; - int buflen; - struct tree_cache **options; - unsigned char *priority_list; + unsigned buflen; + struct packet *packet; + struct lease *lease; + struct client_state *client_state; + struct option_state *in_options; + struct option_state *cfg_options; + struct binding_scope **scope; + unsigned *priority_list; int priority_len; - int first_cutoff, second_cutoff; + unsigned first_cutoff, second_cutoff; int terminate; + const char *vuname; { int bufix = 0; - int option_stored [256]; int i; int ix; int tto; + struct data_string od; + struct option_cache *oc; + unsigned code; + int optstart; + + memset (&od, 0, sizeof od); - /* Zero out the stored-lengths array. */ - memset (option_stored, 0, sizeof option_stored); + /* Eliminate duplicate options in the parameter request list. + There's got to be some clever knuthian way to do this: + Eliminate all but the first occurance of a value in an array + of values without otherwise disturbing the order of the array. */ + for (i = 0; i < priority_len - 1; i++) { + tto = 0; + for (ix = i + 1; ix < priority_len + tto; ix++) { + if (tto) + priority_list [ix - tto] = + priority_list [ix]; + if (priority_list [i] == priority_list [ix]) { + tto++; + priority_len--; + } + } + } /* Copy out the options in the order that they appear in the priority list... */ for (i = 0; i < priority_len; i++) { - /* Code for next option to try to store. */ - int code = priority_list [i]; - int optstart; + /* Number of bytes left to store (some may already + have been stored by a previous pass). */ + unsigned length; + int optstart; + struct universe *u; + int have_encapsulation = 0; + struct data_string encapsulation; - /* Number of bytes left to store (some may already - have been stored by a previous pass). */ - int length; + memset (&encapsulation, 0, sizeof encapsulation); - /* If no data is available for this option, skip it. */ - if (!options [code]) { - continue; - } + /* Code for next option to try to store. */ + code = priority_list [i]; + + /* Look up the option in the site option space if the code + is above the cutoff, otherwise in the DHCP option space. */ + if (code >= cfg_options -> site_code_min) + u = universes [cfg_options -> site_universe]; + else + u = &dhcp_universe; - /* The client could ask for things that are mandatory, - in which case we should avoid storing them twice... */ - if (option_stored [code]) - continue; - option_stored [code] = 1; + oc = lookup_option (u, cfg_options, code); - /* Find the value of the option... */ - if (!tree_evaluate (options [code])) { - continue; - } + /* It's an encapsulation, try to find the universe + to be encapsulated first, except that if it's a straight + encapsulation and the user has provided a value for the + encapsulation option, use the user-provided value. */ + if ((u -> options [code] -> format [0] == 'E' && !oc) || + u -> options [code] -> format [0] == 'e') { + int uix; + static char *s, *t; + struct option_cache *tmp; + struct data_string name; - /* We should now have a constant length for the option. */ - length = options [code] -> len; + s = strchr (u -> options [code] -> format, 'E'); + if (s) + t = strchr (++s, '.'); + if (s && t) { + memset (&name, 0, sizeof name); - /* Do we add a NUL? */ - if (terminate && dhcp_options [code].format [0] == 't') { - length++; - tto = 1; - } else { - tto = 0; + /* A zero-length universe name means the vendor + option space, if one is defined. */ + if (t == s) { + if (vendor_cfg_option) { + tmp = lookup_option (vendor_cfg_option -> universe, + cfg_options, + vendor_cfg_option -> code); + if (tmp) + evaluate_option_cache (&name, packet, lease, + client_state, + in_options, + cfg_options, + scope, tmp, MDL); + } else if (vuname) { + name.data = (unsigned char *)s; + name.len = strlen (s); + } + } else { + name.data = (unsigned char *)s; + name.len = t - s; + } + + /* If we found a universe, and there are options configured + for that universe, try to encapsulate it. */ + if (name.len) { + have_encapsulation = + (option_space_encapsulate + (&encapsulation, packet, lease, client_state, + in_options, cfg_options, scope, &name)); + data_string_forget (&name, MDL); + } } + } - /* Try to store the option. */ - - /* If the option's length is more than 255, we must store it - in multiple hunks. Store 255-byte hunks first. However, - in any case, if the option data will cross a buffer - boundary, split it across that boundary. */ + /* In order to avoid memory leaks, we have to get to here + with any option cache that we allocated in tmp not being + referenced by tmp, and whatever option cache is referenced + by oc being an actual reference. lookup_option doesn't + generate a reference (this needs to be fixed), so the + preceding goop ensures that if we *didn't* generate a new + option cache, oc still winds up holding an actual reference. */ - ix = 0; + /* If no data is available for this option, skip it. */ + if (!oc && !have_encapsulation) { + continue; + } + + /* Find the value of the option... */ + if (oc) { + evaluate_option_cache (&od, packet, + lease, client_state, in_options, + cfg_options, scope, oc, MDL); + if (!od.len) { + data_string_forget (&encapsulation, MDL); + data_string_forget (&od, MDL); + have_encapsulation = 0; + continue; + } + } - optstart = bufix; - while (length) { - unsigned char incr = length > 255 ? 255 : length; + /* We should now have a constant length for the option. */ + length = od.len; + if (have_encapsulation) { + length += encapsulation.len; + if (!od.len) { + data_string_copy (&od, &encapsulation, MDL); + data_string_forget (&encapsulation, MDL); + } else { + struct buffer *bp = (struct buffer *)0; + if (!buffer_allocate (&bp, length, MDL)) { + option_cache_dereference (&oc, MDL); + data_string_forget (&od, MDL); + data_string_forget (&encapsulation, MDL); + continue; + } + memcpy (&bp -> data [0], od.data, od.len); + memcpy (&bp -> data [od.len], encapsulation.data, + encapsulation.len); + data_string_forget (&od, MDL); + data_string_forget (&encapsulation, MDL); + od.data = &bp -> data [0]; + buffer_reference (&od.buffer, bp, MDL); + buffer_dereference (&bp, MDL); + od.len = length; + od.terminated = 0; + } + } - /* If this hunk of the buffer will cross a - boundary, only go up to the boundary in this - pass. */ - if (bufix < first_cutoff && - bufix + incr > first_cutoff) - incr = first_cutoff - bufix; - else if (bufix < second_cutoff && - bufix + incr > second_cutoff) - incr = second_cutoff - bufix; + /* Do we add a NUL? */ + if (terminate && dhcp_options [code].format [0] == 't') { + length++; + tto = 1; + } else { + tto = 0; + } - /* If this option is going to overflow the buffer, - skip it. */ - if (bufix + 2 + incr > buflen) { - bufix = optstart; - break; - } + /* Try to store the option. */ + + /* If the option's length is more than 255, we must store it + in multiple hunks. Store 255-byte hunks first. However, + in any case, if the option data will cross a buffer + boundary, split it across that boundary. */ - /* Everything looks good - copy it in! */ - buffer [bufix] = code; - buffer [bufix + 1] = incr; - if (tto && incr == length) { - memcpy (buffer + bufix + 2, - options [code] -> value + ix, - incr - 1); - buffer [bufix + 2 + incr - 1] = 0; - } else { - memcpy (buffer + bufix + 2, - options [code] -> value + ix, incr); - } - length -= incr; - ix += incr; - bufix += 2 + incr; - } + ix = 0; + optstart = bufix; + while (length) { + unsigned char incr = length > 255 ? 255 : length; + int consumed = 0; + + /* If this hunk of the buffer will cross a + boundary, only go up to the boundary in this + pass. */ + if (bufix < first_cutoff && + bufix + incr > first_cutoff) + incr = first_cutoff - bufix; + else if (bufix < second_cutoff && + bufix + incr > second_cutoff) + incr = second_cutoff - bufix; + + /* If this option is going to overflow the buffer, + skip it. */ + if (bufix + 2 + incr > buflen) { + bufix = optstart; + break; + } + + /* Everything looks good - copy it in! */ + buffer [bufix] = code; + buffer [bufix + 1] = incr; + if (tto && incr == length) { + memcpy (buffer + bufix + 2, + od.data + ix, (unsigned)(incr - 1)); + buffer [bufix + 2 + incr - 1] = 0; + } else { + memcpy (buffer + bufix + 2, + od.data + ix, (unsigned)incr); + } + length -= incr; + ix += incr; + bufix += 2 + incr; + } + data_string_forget (&od, MDL); } + return bufix; } /* Format the specified option so that a human can easily read it. */ -char *pretty_print_option (code, data, len, emit_commas, emit_quotes) - unsigned int code; - unsigned char *data; - int len; +const char *pretty_print_option (option, data, len, emit_commas, emit_quotes) + struct option *option; + const unsigned char *data; + unsigned len; int emit_commas; int emit_quotes; { static char optbuf [32768]; /* XXX */ int hunksize = 0; + int opthunk = 0; + int hunkinc = 0; int numhunk = -1; int numelem = 0; char fmtbuf [32]; - int i, j, k; + struct enumeration *enumbuf [32]; + int i, j, k, l; char *op = optbuf; - unsigned char *dp = data; + const unsigned char *dp = data; struct in_addr foo; char comma; - - /* Code should be between 0 and 255. */ - if (code > 255) - error ("pretty_print_option: bad code %d\n", code); + unsigned long tval; if (emit_commas) comma = ','; else comma = ' '; + memset (enumbuf, 0, sizeof enumbuf); + /* Figure out the size of the data. */ - for (i = 0; dhcp_options [code].format [i]; i++) { + for (l = i = 0; option -> format [i]; i++, l++) { if (!numhunk) { - warn ("%s: Excess information in format string: %s\n", - dhcp_options [code].name, - &(dhcp_options [code].format [i])); + log_error ("%s: Extra codes in format string: %s", + option -> name, + &(option -> format [i])); break; } numelem++; - fmtbuf [i] = dhcp_options [code].format [i]; - switch (dhcp_options [code].format [i]) { + fmtbuf [l] = option -> format [i]; + switch (option -> format [i]) { + case 'a': + --numelem; + fmtbuf [l] = 0; + numhunk = 0; + break; case 'A': --numelem; - fmtbuf [i] = 0; + fmtbuf [l] = 0; numhunk = 0; break; + case 'E': + /* Skip the universe name. */ + while (option -> format [i] && + option -> format [i] != '.') + i++; case 'X': for (k = 0; k < len; k++) { if (!isascii (data [k]) || !isprint (data [k])) break; } - if (k == len) { - fmtbuf [i] = 't'; + /* If we found no bogus characters, or the bogus + character we found is a trailing NUL, it's + okay to print this option as text. */ + if (k == len || (k + 1 == len && data [k] == 0)) { + fmtbuf [l] = 't'; numhunk = -2; } else { - fmtbuf [i] = 'x'; + fmtbuf [l] = 'x'; hunksize++; comma = ':'; numhunk = 0; } - fmtbuf [i + 1] = 0; + fmtbuf [l + 1] = 0; break; + case 'd': case 't': - fmtbuf [i] = 't'; - fmtbuf [i + 1] = 0; + fmtbuf [l] = 't'; + fmtbuf [l + 1] = 0; numhunk = -2; break; + case 'N': + k = i; + while (option -> format [i] && + option -> format [i] != '.') + i++; + enumbuf [l] = + find_enumeration (&option -> format [k] + 1, + i - k - 1); + hunksize += 1; + hunkinc = 1; + break; case 'I': case 'l': case 'L': + case 'T': hunksize += 4; + hunkinc = 4; break; case 's': case 'S': hunksize += 2; + hunkinc = 2; break; case 'b': case 'B': case 'f': hunksize++; + hunkinc = 1; break; case 'e': break; + case 'o': + opthunk += hunkinc; + break; default: - warn ("%s: garbage in format string: %s\n", - dhcp_options [code].name, - &(dhcp_options [code].format [i])); + log_error ("%s: garbage in format string: %s", + option -> name, + &(option -> format [i])); break; } } /* Check for too few bytes... */ - if (hunksize > len) { - warn ("%s: expecting at least %d bytes; got %d", - dhcp_options [code].name, + if (hunksize - opthunk > len) { + log_error ("%s: expecting at least %d bytes; got %d", + option -> name, hunksize, len); return "<error>"; } /* Check for too many bytes... */ if (numhunk == -1 && hunksize < len) - warn ("%s: %d extra bytes", - dhcp_options [code].name, + log_error ("%s: %d extra bytes", + option -> name, len - hunksize); /* If this is an array, compute its size. */ @@ -535,8 +1073,8 @@ char *pretty_print_option (code, data, len, emit_commas, emit_quotes) numhunk = len / hunksize; /* See if we got an exact number of hunks. */ if (numhunk > 0 && numhunk * hunksize < len) - warn ("%s: %d extra bytes at end of array\n", - dhcp_options [code].name, + log_error ("%s: %d extra bytes at end of array\n", + option -> name, len - numhunk * hunksize); /* A one-hunk array prints the same as a single hunk. */ @@ -574,6 +1112,21 @@ char *pretty_print_option (code, data, len, emit_commas, emit_quotes) *op++ = '"'; *op = 0; break; + /* pretty-printing an array of enums is + going to get ugly. */ + case 'N': + if (!enumbuf [j]) + goto enum_as_num; + for (i = 0; ;i++) { + if (!enumbuf [j] -> values [i].name) + goto enum_as_num; + if (enumbuf [j] -> values [i].value == + *dp) + break; + } + strcpy (op, enumbuf [j] -> values [i].name); + op += strlen (op); + break; case 'I': foo.s_addr = htonl (getULong (dp)); strcpy (op, inet_ntoa (foo)); @@ -583,23 +1136,31 @@ char *pretty_print_option (code, data, len, emit_commas, emit_quotes) sprintf (op, "%ld", (long)getLong (dp)); dp += 4; break; + case 'T': + tval = getULong (dp); + if (tval == -1) + sprintf (op, "%s", "infinite"); + else + sprintf (op, "%ld", tval); + break; case 'L': sprintf (op, "%ld", (unsigned long)getULong (dp)); dp += 4; break; case 's': - sprintf (op, "%d", getShort (dp)); + sprintf (op, "%d", (int)getShort (dp)); dp += 2; break; case 'S': - sprintf (op, "%d", getUShort (dp)); + sprintf (op, "%d", (unsigned)getUShort (dp)); dp += 2; break; case 'b': - sprintf (op, "%d", *(char *)dp++); + sprintf (op, "%d", *(const char *)dp++); break; case 'B': + enum_as_num: sprintf (op, "%d", *dp++); break; case 'x': @@ -609,58 +1170,1051 @@ char *pretty_print_option (code, data, len, emit_commas, emit_quotes) strcpy (op, *dp++ ? "true" : "false"); break; default: - warn ("Unexpected format code %c", fmtbuf [j]); + log_error ("Unexpected format code %c", + fmtbuf [j]); } op += strlen (op); + if (dp == data + len) + break; if (j + 1 < numelem && comma != ':') *op++ = ' '; } if (i + 1 < numhunk) { *op++ = comma; } - + if (dp == data + len) + break; } return optbuf; } +int get_option (result, universe, packet, lease, client_state, + in_options, cfg_options, options, scope, code, file, line) + struct data_string *result; + struct universe *universe; + struct packet *packet; + struct lease *lease; + struct client_state *client_state; + struct option_state *in_options; + struct option_state *cfg_options; + struct option_state *options; + struct binding_scope **scope; + unsigned code; + const char *file; + int line; +{ + struct option_cache *oc; + + if (!universe -> lookup_func) + return 0; + oc = ((*universe -> lookup_func) (universe, options, code)); + if (!oc) + return 0; + if (!evaluate_option_cache (result, packet, lease, client_state, + in_options, cfg_options, scope, oc, + file, line)) + return 0; + return 1; +} + +void set_option (universe, options, option, op) + struct universe *universe; + struct option_state *options; + struct option_cache *option; + enum statement_op op; +{ + struct option_cache *oc, *noc; + + switch (op) { + case if_statement: + case add_statement: + case eval_statement: + case break_statement: + default: + log_error ("bogus statement type in do_option_set."); + break; + + case default_option_statement: + oc = lookup_option (universe, options, + option -> option -> code); + if (oc) + break; + save_option (universe, options, option); + break; + + case supersede_option_statement: + case send_option_statement: + /* Install the option, replacing any existing version. */ + save_option (universe, options, option); + break; + + case append_option_statement: + case prepend_option_statement: + oc = lookup_option (universe, options, + option -> option -> code); + if (!oc) { + save_option (universe, options, option); + break; + } + /* If it's not an expression, make it into one. */ + if (!oc -> expression && oc -> data.len) { + if (!expression_allocate (&oc -> expression, MDL)) { + log_error ("Can't allocate const expression."); + break; + } + oc -> expression -> op = expr_const_data; + data_string_copy + (&oc -> expression -> data.const_data, + &oc -> data, MDL); + data_string_forget (&oc -> data, MDL); + } + noc = (struct option_cache *)0; + if (!option_cache_allocate (&noc, MDL)) + break; + if (op == append_option_statement) { + if (!make_concat (&noc -> expression, + oc -> expression, + option -> expression)) { + option_cache_dereference (&noc, MDL); + break; + } + } else { + if (!make_concat (&noc -> expression, + option -> expression, + oc -> expression)) { + option_cache_dereference (&noc, MDL); + break; + } + } + noc -> option = oc -> option; + save_option (universe, options, noc); + option_cache_dereference (&noc, MDL); + break; + } +} + +struct option_cache *lookup_option (universe, options, code) + struct universe *universe; + struct option_state *options; + unsigned code; +{ + if (!options) + return (struct option_cache *)0; + if (universe -> lookup_func) + return (*universe -> lookup_func) (universe, options, code); + else + log_error ("can't look up options in %s space.", + universe -> name); + return (struct option_cache *)0; +} + +struct option_cache *lookup_hashed_option (universe, options, code) + struct universe *universe; + struct option_state *options; + unsigned code; +{ + int hashix; + pair bptr; + pair *hash; + + /* Make sure there's a hash table. */ + if (universe -> index >= options -> universe_count || + !(options -> universes [universe -> index])) + return (struct option_cache *)0; + + hash = options -> universes [universe -> index]; + + hashix = compute_option_hash (code); + for (bptr = hash [hashix]; bptr; bptr = bptr -> cdr) { + if (((struct option_cache *)(bptr -> car)) -> option -> code == + code) + return (struct option_cache *)(bptr -> car); + } + return (struct option_cache *)0; +} + +int save_option_buffer (struct universe *universe, + struct option_state *options, + struct buffer *bp, + unsigned char *buffer, unsigned length, + struct option *option, int tp) +{ + struct buffer *lbp = (struct buffer *)0; + struct option_cache *op = (struct option_cache *)0; + + if (!option_cache_allocate (&op, MDL)) { + log_error ("No memory for option %s.%s.", + universe -> name, + option -> name); + return 0; + } + + /* If we weren't passed a buffer in which the data are saved and + refcounted, allocate one now. */ + if (!bp) { + if (!buffer_allocate (&lbp, length, MDL)) { + log_error ("no memory for option buffer."); + + option_cache_dereference (&op, MDL); + return 0; + } + memcpy (lbp -> data, buffer, length + tp); + bp = lbp; + buffer = &bp -> data [0]; /* Refer to saved buffer. */ + } + + /* Reference buffer copy to option cache. */ + op -> data.buffer = (struct buffer *)0; + buffer_reference (&op -> data.buffer, bp, MDL); + + /* Point option cache into buffer. */ + op -> data.data = buffer; + op -> data.len = length; + + if (tp) { + /* NUL terminate (we can get away with this because we (or + the caller!) allocated one more than the buffer size, and + because the byte following the end of an option is always + the code of the next option, which the caller is getting + out of the *original* buffer. */ + buffer [length] = 0; + op -> data.terminated = 1; + } else + op -> data.terminated = 0; + + op -> option = option; + + /* Now store the option. */ + save_option (universe, options, op); + + /* And let go of our reference. */ + option_cache_dereference (&op, MDL); + + return 1; +} + +void save_option (struct universe *universe, + struct option_state *options, struct option_cache *oc) +{ + if (universe -> save_func) + (*universe -> save_func) (universe, options, oc); + else + log_error ("can't store options in %s space.", + universe -> name); +} + +void save_hashed_option (universe, options, oc) + struct universe *universe; + struct option_state *options; + struct option_cache *oc; +{ + int hashix; + pair bptr; + pair *hash = options -> universes [universe -> index]; + + if (oc -> refcnt == 0) + abort (); + + /* Compute the hash. */ + hashix = compute_option_hash (oc -> option -> code); + + /* If there's no hash table, make one. */ + if (!hash) { + hash = (pair *)dmalloc (OPTION_HASH_SIZE * sizeof *hash, MDL); + if (!hash) { + log_error ("no memory to store %s.%s", + universe -> name, oc -> option -> name); + return; + } + memset (hash, 0, OPTION_HASH_SIZE * sizeof *hash); + options -> universes [universe -> index] = (VOIDPTR)hash; + } else { + /* Try to find an existing option matching the new one. */ + for (bptr = hash [hashix]; bptr; bptr = bptr -> cdr) { + if (((struct option_cache *) + (bptr -> car)) -> option -> code == + oc -> option -> code) + break; + } + + /* If we find one, dereference it and put the new one + in its place. */ + if (bptr) { + option_cache_dereference + ((struct option_cache **)&bptr -> car, MDL); + option_cache_reference + ((struct option_cache **)&bptr -> car, + oc, MDL); + return; + } + } + + /* Otherwise, just put the new one at the head of the list. */ + bptr = new_pair (MDL); + if (!bptr) { + log_error ("No memory for option_cache reference."); + return; + } + bptr -> cdr = hash [hashix]; + bptr -> car = 0; + option_cache_reference ((struct option_cache **)&bptr -> car, oc, MDL); + hash [hashix] = bptr; +} + +void delete_option (universe, options, code) + struct universe *universe; + struct option_state *options; + int code; +{ + if (universe -> delete_func) + (*universe -> delete_func) (universe, options, code); + else + log_error ("can't delete options from %s space.", + universe -> name); +} + +void delete_hashed_option (universe, options, code) + struct universe *universe; + struct option_state *options; + int code; +{ + int hashix; + pair bptr, prev = (pair)0; + pair *hash = options -> universes [universe -> index]; + + /* There may not be any options in this space. */ + if (!hash) + return; + + /* Try to find an existing option matching the new one. */ + hashix = compute_option_hash (code); + for (bptr = hash [hashix]; bptr; bptr = bptr -> cdr) { + if (((struct option_cache *)(bptr -> car)) -> option -> code + == code) + break; + prev = bptr; + } + /* If we found one, wipe it out... */ + if (bptr) { + if (prev) + prev -> cdr = bptr -> cdr; + else + hash [hashix] = bptr -> cdr; + option_cache_dereference + ((struct option_cache **)(&bptr -> car), MDL); + free_pair (bptr, MDL); + } +} + +extern struct option_cache *free_option_caches; /* XXX */ + +int option_cache_dereference (ptr, file, line) + struct option_cache **ptr; + const char *file; + int line; +{ + if (!ptr || !*ptr) { + log_error ("Null pointer in option_cache_dereference: %s(%d)", + file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + + (*ptr) -> refcnt--; + rc_register (file, line, ptr, *ptr, (*ptr) -> refcnt, 1, RC_MISC); + if (!(*ptr) -> refcnt) { + if ((*ptr) -> data.buffer) + data_string_forget (&(*ptr) -> data, file, line); + if ((*ptr) -> expression) + expression_dereference (&(*ptr) -> expression, + file, line); + if ((*ptr) -> next) + option_cache_dereference (&((*ptr) -> next), + file, line); + /* Put it back on the free list... */ + (*ptr) -> expression = (struct expression *)free_option_caches; + free_option_caches = *ptr; + dmalloc_reuse (free_option_caches, (char *)0, 0, 0); + } + if ((*ptr) -> refcnt < 0) { + log_error ("%s(%d): negative refcnt!", file, line); +#if defined (DEBUG_RC_HISTORY) + dump_rc_history (*ptr); +#endif +#if defined (POINTER_DEBUG) + abort (); +#else + *ptr = (struct option_cache *)0; + return 0; +#endif + } + *ptr = (struct option_cache *)0; + return 1; + +} + +int hashed_option_state_dereference (universe, state, file, line) + struct universe *universe; + struct option_state *state; + const char *file; + int line; +{ + pair *heads; + pair cp, next; + int i; + + /* Get the pointer to the array of hash table bucket heads. */ + heads = (pair *)(state -> universes [universe -> index]); + if (!heads) + return 0; + + /* For each non-null head, loop through all the buckets dereferencing + the attached option cache structures and freeing the buckets. */ + for (i = 0; i < OPTION_HASH_SIZE; i++) { + for (cp = heads [i]; cp; cp = next) { + next = cp -> cdr; + option_cache_dereference + ((struct option_cache **)&cp -> car, + file, line); + free_pair (cp, file, line); + } + } + + dfree (heads, file, line); + state -> universes [universe -> index] = (void *)0; + return 1; +} + +int store_option (result, universe, packet, lease, client_state, + in_options, cfg_options, scope, oc) + struct data_string *result; + struct universe *universe; + struct packet *packet; + struct lease *lease; + struct client_state *client_state; + struct option_state *in_options; + struct option_state *cfg_options; + struct binding_scope **scope; + struct option_cache *oc; +{ + struct data_string d1, d2; + + memset (&d1, 0, sizeof d1); + memset (&d2, 0, sizeof d2); + + if (evaluate_option_cache (&d2, packet, lease, client_state, + in_options, cfg_options, scope, oc, MDL)) { + if (!buffer_allocate (&d1.buffer, + (result -> len + + universe -> length_size + + universe -> tag_size + d2.len), MDL)) { + data_string_forget (result, MDL); + data_string_forget (&d2, MDL); + return 0; + } + d1.data = &d1.buffer -> data [0]; + if (result -> len) + memcpy (d1.buffer -> data, + result -> data, result -> len); + d1.len = result -> len; + (*universe -> store_tag) (&d1.buffer -> data [d1.len], + oc -> option -> code); + d1.len += universe -> tag_size; + (*universe -> store_length) (&d1.buffer -> data [d1.len], + d2.len); + d1.len += universe -> length_size; + memcpy (&d1.buffer -> data [d1.len], d2.data, d2.len); + d1.len += d2.len; + data_string_forget (&d2, MDL); + data_string_forget (result, MDL); + data_string_copy (result, &d1, MDL); + data_string_forget (&d1, MDL); + return 1; + } + return 0; +} + +int option_space_encapsulate (result, packet, lease, client_state, + in_options, cfg_options, scope, name) + struct data_string *result; + struct packet *packet; + struct lease *lease; + struct client_state *client_state; + struct option_state *in_options; + struct option_state *cfg_options; + struct binding_scope **scope; + struct data_string *name; +{ + struct universe *u; + + u = (struct universe *)0; + universe_hash_lookup (&u, universe_hash, + (const char *)name -> data, name -> len, MDL); + if (!u) + return 0; + + if (u -> encapsulate) + return (*u -> encapsulate) (result, packet, lease, + client_state, + in_options, cfg_options, scope, u); + log_error ("encapsulation requested for %s with no support.", + name -> data); + return 0; +} + +int hashed_option_space_encapsulate (result, packet, lease, client_state, + in_options, cfg_options, scope, universe) + struct data_string *result; + struct packet *packet; + struct lease *lease; + struct client_state *client_state; + struct option_state *in_options; + struct option_state *cfg_options; + struct binding_scope **scope; + struct universe *universe; +{ + pair p, *hash; + int status; + int i; + + if (universe -> index >= cfg_options -> universe_count) + return 0; + + hash = cfg_options -> universes [universe -> index]; + if (!hash) + return 0; + + status = 0; + for (i = 0; i < OPTION_HASH_SIZE; i++) { + for (p = hash [i]; p; p = p -> cdr) { + if (store_option (result, universe, packet, + lease, client_state, in_options, + cfg_options, scope, + (struct option_cache *)p -> car)) + status = 1; + } + } + + return status; +} + +int nwip_option_space_encapsulate (result, packet, lease, client_state, + in_options, cfg_options, scope, universe) + struct data_string *result; + struct packet *packet; + struct lease *lease; + struct client_state *client_state; + struct option_state *in_options; + struct option_state *cfg_options; + struct binding_scope **scope; + struct universe *universe; +{ + pair ocp; + int status; + int i; + static struct option_cache *no_nwip; + struct data_string ds; + struct option_chain_head *head; + + if (universe -> index >= cfg_options -> universe_count) + return 0; + head = ((struct option_chain_head *) + cfg_options -> universes [fqdn_universe.index]); + if (!head) + return 0; + + status = 0; + for (ocp = head -> first; ocp; ocp = ocp -> cdr) { + struct option_cache *oc = (struct option_cache *)(ocp -> car); + if (store_option (result, universe, packet, + lease, client_state, in_options, + cfg_options, scope, + (struct option_cache *)ocp -> car)) + status = 1; + } + + /* If there's no data, the nwip suboption is supposed to contain + a suboption saying there's no data. */ + if (!status) { + if (!no_nwip) { + static unsigned char nni [] = { 1, 0 }; + memset (&ds, 0, sizeof ds); + ds.data = nni; + ds.len = 2; + if (option_cache_allocate (&no_nwip, MDL)) + data_string_copy (&no_nwip -> data, &ds, MDL); + no_nwip -> option = nwip_universe.options [1]; + } + if (no_nwip) { + if (store_option (result, universe, packet, lease, + client_state, in_options, + cfg_options, scope, no_nwip)) + status = 1; + } + } else { + memset (&ds, 0, sizeof ds); + + /* If we have nwip options, the first one has to be the + nwip-exists-in-option-area option. */ + if (!buffer_allocate (&ds.buffer, result -> len + 2, MDL)) { + data_string_forget (result, MDL); + return 0; + } + ds.data = &ds.buffer -> data [0]; + ds.buffer -> data [0] = 2; + ds.buffer -> data [1] = 0; + memcpy (&ds.buffer -> data [2], result -> data, result -> len); + data_string_forget (result, MDL); + data_string_copy (result, &ds, MDL); + data_string_forget (&ds, MDL); + } + + return status; +} + +int fqdn_option_space_encapsulate (result, packet, lease, client_state, + in_options, cfg_options, scope, universe) + struct data_string *result; + struct packet *packet; + struct lease *lease; + struct client_state *client_state; + struct option_state *in_options; + struct option_state *cfg_options; + struct binding_scope **scope; + struct universe *universe; +{ + pair ocp; + struct data_string results [FQDN_SUBOPTION_COUNT + 1]; + unsigned i; + unsigned len; + struct buffer *bp = (struct buffer *)0; + struct option_chain_head *head; + + /* If there's no FQDN universe, don't encapsulate. */ + if (fqdn_universe.index >= cfg_options -> universe_count) + return 0; + head = ((struct option_chain_head *) + cfg_options -> universes [fqdn_universe.index]); + if (!head) + return 0; + + /* Figure out the values of all the suboptions. */ + memset (results, 0, sizeof results); + for (ocp = head -> first; ocp; ocp = ocp -> cdr) { + struct option_cache *oc = (struct option_cache *)(ocp -> car); + if (oc -> option -> code > FQDN_SUBOPTION_COUNT) + continue; + evaluate_option_cache (&results [oc -> option -> code], + packet, lease, client_state, in_options, + cfg_options, scope, oc, MDL); + } + len = 4 + results [FQDN_FQDN].len; + /* Save the contents of the option in a buffer. */ + if (!buffer_allocate (&bp, len, MDL)) { + log_error ("no memory for option buffer."); + return 0; + } + buffer_reference (&result -> buffer, bp, MDL); + result -> len = 3; + result -> data = &bp -> data [0]; + + memset (&bp -> data [0], 0, len); + if (results [FQDN_NO_CLIENT_UPDATE].len && + results [FQDN_NO_CLIENT_UPDATE].data [0]) + bp -> data [0] |= 2; + if (results [FQDN_SERVER_UPDATE].len && + results [FQDN_SERVER_UPDATE].data [0]) + bp -> data [0] |= 1; + if (results [FQDN_RCODE1].len) + bp -> data [1] = results [FQDN_RCODE1].data [0]; + if (results [FQDN_RCODE2].len) + bp -> data [2] = results [FQDN_RCODE2].data [0]; + + if (results [FQDN_ENCODED].len && + results [FQDN_ENCODED].data [0]) { + unsigned char *out; + int i; + bp -> data [0] |= 4; + out = &bp -> data [3]; + if (results [FQDN_FQDN].len) { + i = 0; + while (i < results [FQDN_FQDN].len) { + int j; + for (j = i; ('.' != + results [FQDN_FQDN].data [j]) && + j < results [FQDN_FQDN].len; j++) + ; + *out++ = j - i; + memcpy (out, &results [FQDN_FQDN].data [i], + (unsigned)(j - i)); + out += j - i; + i = j; + if (results [FQDN_FQDN].data [j] == '.') + i++; + } + if ((results [FQDN_FQDN].data + [results [FQDN_FQDN].len - 1] == '.')) + *out++ = 0; + result -> len = out - result -> data; + result -> terminated = 0; + } + } else { + if (results [FQDN_FQDN].len) { + memcpy (&bp -> data [3], results [FQDN_FQDN].data, + results [FQDN_FQDN].len); + result -> len += results [FQDN_FQDN].len; + result -> terminated = 0; + } + } + for (i = 1; i <= FQDN_SUBOPTION_COUNT; i++) { + if (results [i].len) + data_string_forget (&results [i], MDL); + } + buffer_dereference (&bp, MDL); + return 1; +} + +void option_space_foreach (struct packet *packet, struct lease *lease, + struct client_state *client_state, + struct option_state *in_options, + struct option_state *cfg_options, + struct binding_scope **scope, + struct universe *u, void *stuff, + void (*func) (struct option_cache *, + struct packet *, + struct lease *, struct client_state *, + struct option_state *, + struct option_state *, + struct binding_scope **, + struct universe *, void *)) +{ + if (u -> foreach) + (*u -> foreach) (packet, lease, client_state, in_options, + cfg_options, scope, u, stuff, func); +} + +void suboption_foreach (struct packet *packet, struct lease *lease, + struct client_state *client_state, + struct option_state *in_options, + struct option_state *cfg_options, + struct binding_scope **scope, + struct universe *u, void *stuff, + void (*func) (struct option_cache *, + struct packet *, + struct lease *, struct client_state *, + struct option_state *, + struct option_state *, + struct binding_scope **, + struct universe *, void *), + struct option_cache *oc, + const char *vsname) +{ + struct universe *universe = find_option_universe (oc -> option, + vsname); + int i; + + if (universe -> foreach) + (*universe -> foreach) (packet, lease, client_state, + in_options, cfg_options, + scope, universe, stuff, func); +} + +void hashed_option_space_foreach (struct packet *packet, struct lease *lease, + struct client_state *client_state, + struct option_state *in_options, + struct option_state *cfg_options, + struct binding_scope **scope, + struct universe *u, void *stuff, + void (*func) (struct option_cache *, + struct packet *, + struct lease *, + struct client_state *, + struct option_state *, + struct option_state *, + struct binding_scope **, + struct universe *, void *)) +{ + pair *hash; + int i; + struct option_cache *oc; + + if (cfg_options -> universe_count <= u -> index) + return; + + hash = cfg_options -> universes [u -> index]; + if (!hash) + return; + for (i = 0; i < OPTION_HASH_SIZE; i++) { + pair p; + /* XXX save _all_ options! XXX */ + for (p = hash [i]; p; p = p -> cdr) { + oc = (struct option_cache *)p -> car; + (*func) (oc, packet, lease, client_state, + in_options, cfg_options, scope, u, stuff); + } + } +} + +void save_linked_option (universe, options, oc) + struct universe *universe; + struct option_state *options; + struct option_cache *oc; +{ + pair *tail; + pair np = (pair )0; + struct option_chain_head *head; + + if (universe -> index >= options -> universe_count) + return; + head = ((struct option_chain_head *) + options -> universes [universe -> index]); + if (!head) { + if (!option_chain_head_allocate (((struct option_chain_head **) + &options -> universes + [universe -> index]), MDL)) + return; + head = ((struct option_chain_head *) + options -> universes [universe -> index]); + } + + /* Find the tail of the list. */ + for (tail = &head -> first; *tail; tail = &((*tail) -> cdr)) { + if (oc -> option == + ((struct option_cache *)((*tail) -> car)) -> option) { + option_cache_dereference ((struct option_cache **) + (&(*tail) -> car), MDL); + option_cache_reference ((struct option_cache **) + (&(*tail) -> car), oc, MDL); + return; + } + } + + *tail = cons (0, 0); + if (*tail) { + option_cache_reference ((struct option_cache **) + (&(*tail) -> car), oc, MDL); + } +} + +int linked_option_space_encapsulate (result, packet, lease, client_state, + in_options, cfg_options, scope, universe) + struct data_string *result; + struct packet *packet; + struct lease *lease; + struct client_state *client_state; + struct option_state *in_options; + struct option_state *cfg_options; + struct binding_scope **scope; + struct universe *universe; +{ + int status; + pair oc; + struct option_chain_head *head; + + if (universe -> index >= cfg_options -> universe_count) + return 0; + head = ((struct option_chain_head *) + cfg_options -> universes [universe -> index]); + if (!head) + return 0; + + status = 0; + for (oc = head -> first; oc; oc = oc -> cdr) { + if (store_option (result, universe, packet, + lease, client_state, in_options, cfg_options, + scope, (struct option_cache *)(oc -> car))) + status = 1; + } + + return status; +} + +void delete_linked_option (universe, options, code) + struct universe *universe; + struct option_state *options; + int code; +{ + pair *tail, tmp = (pair)0; + struct option_chain_head *head; + + if (universe -> index >= options -> universe_count) + return; + head = ((struct option_chain_head *) + options -> universes [universe -> index]); + if (!head) + return; + + for (tail = &head -> first; *tail; tail = &((*tail) -> cdr)) { + if (code == + ((struct option_cache *)(*tail) -> car) -> option -> code) + { + tmp = (*tail) -> cdr; + option_cache_dereference ((struct option_cache **) + (&(*tail) -> car), MDL); + dfree (*tail, MDL); + (*tail) = tmp; + break; + } + } +} + +struct option_cache *lookup_linked_option (universe, options, code) + struct universe *universe; + struct option_state *options; + unsigned code; +{ + pair oc; + struct option_chain_head *head; + + if (universe -> index >= options -> universe_count) + return 0; + head = ((struct option_chain_head *) + options -> universes [universe -> index]); + if (!head) + return 0; + + for (oc = head -> first; oc; oc = oc -> cdr) { + if (code == + ((struct option_cache *)(oc -> car)) -> option -> code) { + return (struct option_cache *)(oc -> car); + } + } + + return (struct option_cache *)0; +} + +int linked_option_state_dereference (universe, state, file, line) + struct universe *universe; + struct option_state *state; + const char *file; + int line; +{ + return (option_chain_head_dereference + ((struct option_chain_head **) + (&state -> universes [universe -> index]), MDL)); +} + +void linked_option_space_foreach (struct packet *packet, struct lease *lease, + struct client_state *client_state, + struct option_state *in_options, + struct option_state *cfg_options, + struct binding_scope **scope, + struct universe *u, void *stuff, + void (*func) (struct option_cache *, + struct packet *, + struct lease *, + struct client_state *, + struct option_state *, + struct option_state *, + struct binding_scope **, + struct universe *, void *)) +{ + pair car; + struct option_chain_head *head; + + if (u -> index >= cfg_options -> universe_count) + return; + head = ((struct option_chain_head *) + cfg_options -> universes [u -> index]); + if (!head) + return; + for (car = head -> first; car; car = car -> cdr) { + (*func) ((struct option_cache *)(car -> car), + packet, lease, client_state, + in_options, cfg_options, scope, u, stuff); + } +} + void do_packet (interface, packet, len, from_port, from, hfrom) struct interface_info *interface; struct dhcp_packet *packet; - int len; + unsigned len; unsigned int from_port; struct iaddr from; struct hardware *hfrom; { - struct packet tp; int i; + struct option_cache *op; + struct packet *decoded_packet; +#if defined (DEBUG_MEMORY_LEAKAGE) + unsigned long previous_outstanding = dmalloc_outstanding; +#endif + +#if defined (TRACING) + trace_inpacket_stash (interface, packet, len, from_port, from, hfrom); +#endif + decoded_packet = (struct packet *)0; + if (!packet_allocate (&decoded_packet, MDL)) { + log_error ("do_packet: no memory for incoming packet!"); + return; + } + decoded_packet -> raw = packet; + decoded_packet -> packet_length = len; + decoded_packet -> client_port = from_port; + decoded_packet -> client_addr = from; + interface_reference (&decoded_packet -> interface, interface, MDL); + decoded_packet -> haddr = hfrom; + if (packet -> hlen > sizeof packet -> chaddr) { - note ("Discarding packet with invalid hlen."); + packet_dereference (&decoded_packet, MDL); + log_info ("Discarding packet with bogus hlen."); return; } - memset (&tp, 0, sizeof tp); - tp.raw = packet; - tp.packet_length = len; - tp.client_port = from_port; - tp.client_addr = from; - tp.interface = interface; - tp.haddr = hfrom; - - parse_options (&tp); - if (tp.options_valid && - tp.options [DHO_DHCP_MESSAGE_TYPE].data) - tp.packet_type = - tp.options [DHO_DHCP_MESSAGE_TYPE].data [0]; - if (tp.packet_type) - dhcp (&tp); - else - bootp (&tp); + /* If there's an option buffer, try to parse it. */ + if (decoded_packet -> packet_length >= DHCP_FIXED_NON_UDP + 4) { + if (!parse_options (decoded_packet)) { + if (decoded_packet -> options) + option_state_dereference + (&decoded_packet -> options, MDL); + packet_dereference (&decoded_packet, MDL); + return; + } - /* Free the data associated with the options. */ - for (i = 0; i < 256; i++) { - if (tp.options [i].len && tp.options [i].data) - dfree (tp.options [i].data, "do_packet"); + if (decoded_packet -> options_valid && + (op = lookup_option (&dhcp_universe, + decoded_packet -> options, + DHO_DHCP_MESSAGE_TYPE))) { + struct data_string dp; + memset (&dp, 0, sizeof dp); + evaluate_option_cache (&dp, decoded_packet, + (struct lease *)0, + (struct client_state *)0, + decoded_packet -> options, + (struct option_state *)0, + (struct binding_scope **)0, + op, MDL); + if (dp.len > 0) + decoded_packet -> packet_type = dp.data [0]; + else + decoded_packet -> packet_type = 0; + data_string_forget (&dp, MDL); + } } + + if (decoded_packet -> packet_type) + dhcp (decoded_packet); + else + bootp (decoded_packet); + + /* If the caller kept the packet, they'll have upped the refcnt. */ + packet_dereference (&decoded_packet, MDL); + +#if defined (DEBUG_MEMORY_LEAKAGE) + log_info ("generation %ld: %ld new, %ld outstanding, %ld long-term", + dmalloc_generation, + dmalloc_outstanding - previous_outstanding, + dmalloc_outstanding, dmalloc_longterm); +#endif +#if defined (DEBUG_MEMORY_LEAKAGE) + dmalloc_dump_outstanding (); +#endif +#if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY) + dump_rc_history (0); +#endif } diff --git a/contrib/isc-dhcp/common/packet.c b/contrib/isc-dhcp/common/packet.c index 6a15fcf..8fe3894 100644 --- a/contrib/isc-dhcp/common/packet.c +++ b/contrib/isc-dhcp/common/packet.c @@ -3,7 +3,7 @@ Packet assembly code, originally contributed by Archie Cobbs. */ /* - * Copyright (c) 1995, 1996, 1999 The Internet Software Consortium. + * Copyright (c) 1996-2001 Internet Software Consortium. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -33,16 +33,16 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * This software has been written for the Internet Software Consortium - * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie - * Enterprises. To learn more about the Internet Software Consortium, - * see ``http://www.vix.com/isc''. To learn more about Vixie - * Enterprises, see ``http://www.vix.com''. + * This code was originally contributed by Archie Cobbs, and is still + * very similar to that contribution, although the packet checksum code + * has been hacked significantly with the help of quite a few ISC DHCP + * users, without whose gracious and thorough help the checksum code would + * still be disabled. */ #ifndef lint static char copyright[] = -"$Id: packet.c,v 1.18.2.6 1999/06/10 00:58:16 mellon Exp $ Copyright (c) 1996 The Internet Software Consortium. All rights reserved.\n"; +"$Id: packet.c,v 1.40.2.1 2001/05/31 19:28:51 mellon Exp $ Copyright (c) 1996-2001 The Internet Software Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -50,25 +50,26 @@ static char copyright[] = #if defined (PACKET_ASSEMBLY) || defined (PACKET_DECODING) #include "includes/netinet/ip.h" #include "includes/netinet/udp.h" +#include "includes/netinet/if_ether.h" #endif /* PACKET_ASSEMBLY || PACKET_DECODING */ /* Compute the easy part of the checksum on a range of bytes. */ u_int32_t checksum (buf, nbytes, sum) unsigned char *buf; - int nbytes; + unsigned nbytes; u_int32_t sum; { - int i; + unsigned i; #ifdef DEBUG_CHECKSUM - debug ("checksum (%x %d %x)", buf, nbytes, sum); + log_debug ("checksum (%x %d %x)", buf, nbytes, sum); #endif /* Checksum all the pairs of bytes first... */ - for (i = 0; i < (nbytes & ~1); i += 2) { + for (i = 0; i < (nbytes & ~1U); i += 2) { #ifdef DEBUG_CHECKSUM_VERBOSE - debug ("sum = %x", sum); + log_debug ("sum = %x", sum); #endif sum += (u_int16_t) ntohs(*((u_int16_t *)(buf + i))); /* Add carry. */ @@ -80,7 +81,7 @@ u_int32_t checksum (buf, nbytes, sum) byte order is big-endian, so the remaining byte is the high byte. */ if (i < nbytes) { #ifdef DEBUG_CHECKSUM_VERBOSE - debug ("sum = %x", sum); + log_debug ("sum = %x", sum); #endif sum += buf [i] << 8; /* Add carry. */ @@ -91,41 +92,43 @@ u_int32_t checksum (buf, nbytes, sum) return sum; } -/* Finish computing the sum, and then put it into network byte order. */ +/* Finish computing the checksum, and then put it into network byte order. */ u_int32_t wrapsum (sum) u_int32_t sum; { #ifdef DEBUG_CHECKSUM - debug ("wrapsum (%x)", sum); + log_debug ("wrapsum (%x)", sum); #endif sum = ~sum & 0xFFFF; #ifdef DEBUG_CHECKSUM_VERBOSE - debug ("sum = %x", sum); + log_debug ("sum = %x", sum); #endif #ifdef DEBUG_CHECKSUM - debug ("wrapsum returns %x", htons (sum)); + log_debug ("wrapsum returns %x", htons (sum)); #endif return htons(sum); } #ifdef PACKET_ASSEMBLY -/* Assemble an hardware header... */ -/* XXX currently only supports ethernet; doesn't check for other types. */ - void assemble_hw_header (interface, buf, bufix, to) struct interface_info *interface; unsigned char *buf; - int *bufix; + unsigned *bufix; struct hardware *to; { #if defined (HAVE_TR_SUPPORT) - if (interface -> hw_address.htype == HTYPE_IEEE802) + if (interface -> hw_address.hbuf [0] == HTYPE_IEEE802) assemble_tr_header (interface, buf, bufix, to); else #endif +#if defined (DEC_FDDI) + if (interface -> hw_address.hbuf [0] == HTYPE_FDDI) + assemble_fddi_header (interface, buf, bufix, to); + else +#endif assemble_ethernet_header (interface, buf, bufix, to); } @@ -136,19 +139,19 @@ void assemble_udp_ip_header (interface, buf, bufix, from, to, port, data, len) struct interface_info *interface; unsigned char *buf; - int *bufix; + unsigned *bufix; u_int32_t from; u_int32_t to; - unsigned int port; + u_int32_t port; unsigned char *data; - int len; + unsigned len; { struct ip ip; struct udphdr udp; /* Fill out the IP header */ - ip.ip_v = 4; - ip.ip_hl = 5; + IP_V_SET (&ip, 4); + IP_HL_SET (&ip, 20); ip.ip_tos = IPTOS_LOWDELAY; ip.ip_len = htons(sizeof(ip) + sizeof(udp) + len); ip.ip_id = 0; @@ -193,18 +196,24 @@ void assemble_udp_ip_header (interface, buf, bufix, #ifdef PACKET_DECODING /* Decode a hardware header... */ +/* XXX currently only supports ethernet; doesn't check for other types. */ ssize_t decode_hw_header (interface, buf, bufix, from) struct interface_info *interface; unsigned char *buf; - int bufix; + unsigned bufix; struct hardware *from; { #if defined (HAVE_TR_SUPPORT) - if (interface -> hw_address.htype == HTYPE_IEEE802) + if (interface -> hw_address.hbuf [0] == HTYPE_IEEE802) return decode_tr_header (interface, buf, bufix, from); else #endif +#if defined (DEC_FDDI) + if (interface -> hw_address.hbuf [0] == HTYPE_FDDI) + return decode_fddi_header (interface, buf, bufix, from); + else +#endif return decode_ethernet_header (interface, buf, bufix, from); } @@ -213,10 +222,10 @@ ssize_t decode_hw_header (interface, buf, bufix, from) ssize_t decode_udp_ip_header (interface, buf, bufix, from, data, buflen) struct interface_info *interface; unsigned char *buf; - int bufix; + unsigned bufix; struct sockaddr_in *from; unsigned char *data; - int buflen; + unsigned buflen; { struct ip *ip; struct udphdr *udp; @@ -228,7 +237,9 @@ ssize_t decode_udp_ip_header (interface, buf, bufix, from, data, buflen) static int udp_packets_bad_checksum; static int udp_packets_length_checked; static int udp_packets_length_overflow; - int len; + unsigned len; + unsigned ulen; + int ignore = 0; ip = (struct ip *)(buf + bufix); udp = (struct udphdr *)(buf + bufix + ip_len); @@ -243,23 +254,34 @@ ssize_t decode_udp_ip_header (interface, buf, bufix, from, data, buflen) return -1; #endif /* USERLAND_FILTER */ + ulen = ntohs (udp -> uh_ulen); + if (ulen < sizeof *udp || + ((unsigned char *)udp) + ulen > buf + bufix + buflen) { + log_info ("bogus UDP packet length: %d", ulen); + return -1; + } + /* Check the IP header checksum - it should be zero. */ ++ip_packets_seen; if (wrapsum (checksum (buf + bufix, ip_len, 0))) { ++ip_packets_bad_checksum; if (ip_packets_seen > 4 && (ip_packets_seen / ip_packets_bad_checksum) < 2) { - note ("%d bad IP checksums seen in %d packets", - ip_packets_bad_checksum, ip_packets_seen); + log_info ("%d bad IP checksums seen in %d packets", + ip_packets_bad_checksum, ip_packets_seen); ip_packets_seen = ip_packets_bad_checksum = 0; } return -1; } /* Check the IP packet length. */ - if (ntohs (ip -> ip_len) != buflen) - debug ("ip length %d disagrees with bytes received %d.", - ntohs (ip -> ip_len), buflen); + if (ntohs (ip -> ip_len) != buflen) { + if ((ntohs (ip -> ip_len + 2) & ~1) == buflen) + ignore = 1; + else + log_debug ("ip length %d disagrees with bytes received %d.", + ntohs (ip -> ip_len), buflen); + } /* Copy out the IP source address... */ memcpy (&from -> sin_addr, &ip -> ip_src, 4); @@ -270,23 +292,29 @@ ssize_t decode_udp_ip_header (interface, buf, bufix, from, data, buflen) if (!data) { data = buf + bufix + ip_len + sizeof *udp; - len = ntohs (udp -> uh_ulen) - sizeof *udp; + len = ulen - sizeof *udp; ++udp_packets_length_checked; if (len + data > buf + bufix + buflen) { ++udp_packets_length_overflow; if (udp_packets_length_checked > 4 && (udp_packets_length_checked / udp_packets_length_overflow) < 2) { - note ("%d udp packets in %d too long - dropped", - udp_packets_length_overflow, - udp_packets_length_checked); + log_info ("%d udp packets in %d too long - dropped", + udp_packets_length_overflow, + udp_packets_length_checked); udp_packets_length_overflow = udp_packets_length_checked = 0; } return -1; } - if (len + data != buf + bufix + buflen) - debug ("accepting packet with data after udp payload."); + if (len + data < buf + bufix + buflen && + len + data != buf + bufix + buflen && !ignore) + log_debug ("accepting packet with data after udp payload."); + if (len + data > buf + bufix + buflen) { + log_debug ("dropping packet with bogus uh_ulen %ld", + (long)(len + sizeof *udp)); + return -1; + } } usum = udp -> uh_sum; @@ -298,16 +326,15 @@ ssize_t decode_udp_ip_header (interface, buf, bufix, from, data, buflen) &ip -> ip_src, 2 * sizeof ip -> ip_src, IPPROTO_UDP + - (u_int32_t) - ntohs (udp -> uh_ulen))))); + (u_int32_t)ulen)))); udp_packets_seen++; if (usum && usum != sum) { udp_packets_bad_checksum++; if (udp_packets_seen > 4 && (udp_packets_seen / udp_packets_bad_checksum) < 2) { - note ("%d bad udp checksums in %d packets", - udp_packets_bad_checksum, udp_packets_seen); + log_info ("%d bad udp checksums in %d packets", + udp_packets_bad_checksum, udp_packets_seen); udp_packets_seen = udp_packets_bad_checksum = 0; } return -1; diff --git a/contrib/isc-dhcp/common/parse.c b/contrib/isc-dhcp/common/parse.c index fe02689..a2d13f8 100644 --- a/contrib/isc-dhcp/common/parse.c +++ b/contrib/isc-dhcp/common/parse.c @@ -3,7 +3,7 @@ Common parser code for dhcpd and dhclient. */ /* - * Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium. + * Copyright (c) 1995-2001 Internet Software Consortium. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,19 +34,58 @@ * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium - * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie - * Enterprises. To learn more about the Internet Software Consortium, - * see ``http://www.vix.com/isc''. To learn more about Vixie - * Enterprises, see ``http://www.vix.com''. + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. */ #ifndef lint static char copyright[] = -"$Id: parse.c,v 1.2.2.4 1999/03/29 22:18:53 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium. All rights reserved.\n"; +"$Id: parse.c,v 1.104.2.8 2002/01/10 19:37:51 mellon Exp $ Copyright (c) 1995-2001 The Internet Software Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" -#include "dhctoken.h" + +/* Enumerations can be specified in option formats, and are used for + parsing, so we define the routines that manage them here. */ + +struct enumeration *enumerations; + +void add_enumeration (struct enumeration *enumeration) +{ + enumeration -> next = enumerations; + enumerations = enumeration; +} + +struct enumeration *find_enumeration (const char *name, int length) +{ + struct enumeration *e; + + for (e = enumerations; e; e = e -> next) + if (strlen (e -> name) == length && + !memcmp (e -> name, name, (unsigned)length)) + return e; + return (struct enumeration *)0; +} + +struct enumeration_value *find_enumeration_value (const char *name, + int length, + const char *value) +{ + struct enumeration *e; + int i; + + e = find_enumeration (name, length); + if (e) { + for (i = 0; e -> values [i].name; i++) { + if (!strcmp (value, e -> values [i].name)) + return &e -> values [i]; + } + } + return (struct enumeration_value *)0; +} /* Skip to the semicolon ending the current statement. If we encounter braces, the matching closing brace terminates the statement. If we @@ -63,17 +102,26 @@ static char copyright[] = ...et cetera. */ void skip_to_semi (cfile) - FILE *cfile; + struct parse *cfile; { - int token; - char *val; - int brace_count = 0; + skip_to_rbrace (cfile, 0); +} +void skip_to_rbrace (cfile, brace_count) + struct parse *cfile; + int brace_count; +{ + enum dhcp_token token; + const char *val; + +#if defined (DEBUG_TOKEN) + log_error ("skip_to_rbrace: %d\n", brace_count); +#endif do { - token = peek_token (&val, cfile); + token = peek_token (&val, (unsigned *)0, cfile); if (token == RBRACE) { + token = next_token (&val, (unsigned *)0, cfile); if (brace_count) { - token = next_token (&val, cfile); if (!--brace_count) return; } else @@ -81,28 +129,28 @@ void skip_to_semi (cfile) } else if (token == LBRACE) { brace_count++; } else if (token == SEMI && !brace_count) { - token = next_token (&val, cfile); + token = next_token (&val, (unsigned *)0, cfile); return; } else if (token == EOL) { /* EOL only happens when parsing /etc/resolv.conf, and we treat it like a semicolon because the resolv.conf file is line-oriented. */ - token = next_token (&val, cfile); + token = next_token (&val, (unsigned *)0, cfile); return; } - token = next_token (&val, cfile); - } while (token != EOF); + token = next_token (&val, (unsigned *)0, cfile); + } while (token != END_OF_FILE); } int parse_semi (cfile) - FILE *cfile; + struct parse *cfile; { - int token; - char *val; + enum dhcp_token token; + const char *val; - token = next_token (&val, cfile); + token = next_token (&val, (unsigned *)0, cfile); if (token != SEMI) { - parse_warn ("semicolon expected."); + parse_warn (cfile, "semicolon expected."); skip_to_semi (cfile); return 0; } @@ -111,76 +159,100 @@ int parse_semi (cfile) /* string-parameter :== STRING SEMI */ -char *parse_string (cfile) - FILE *cfile; +int parse_string (cfile, sptr, lptr) + struct parse *cfile; + char **sptr; + unsigned *lptr; { - char *val; - int token; + const char *val; + enum dhcp_token token; char *s; + unsigned len; - token = next_token (&val, cfile); + token = next_token (&val, &len, cfile); if (token != STRING) { - parse_warn ("filename must be a string"); + parse_warn (cfile, "expecting a string"); skip_to_semi (cfile); - return (char *)0; + return 0; } - s = (char *)malloc (strlen (val) + 1); + s = (char *)dmalloc (len + 1, MDL); if (!s) - error ("no memory for string %s.", val); - strcpy (s, val); + log_fatal ("no memory for string %s.", val); + memcpy (s, val, len + 1); - if (!parse_semi (cfile)) - return (char *)0; - return s; + if (!parse_semi (cfile)) { + dfree (s, MDL); + return 0; + } + if (sptr) + *sptr = s; + else + dfree (s, MDL); + if (lptr) + *lptr = len; + return 1; } -/* hostname :== identifier | hostname DOT identifier */ +/* + * hostname :== IDENTIFIER + * | IDENTIFIER DOT + * | hostname DOT IDENTIFIER + */ char *parse_host_name (cfile) - FILE *cfile; + struct parse *cfile; { - char *val; - int token; - int len = 0; + const char *val; + enum dhcp_token token; + unsigned len = 0; char *s; char *t; pair c = (pair)0; + int ltid = 0; /* Read a dotted hostname... */ do { /* Read a token, which should be an identifier. */ - token = next_token (&val, cfile); - if (!is_identifier (token) && token != NUMBER) { - parse_warn ("expecting an identifier in hostname"); - skip_to_semi (cfile); - return (char *)0; - } + token = peek_token (&val, (unsigned *)0, cfile); + if (!is_identifier (token) && token != NUMBER) + break; + token = next_token (&val, (unsigned *)0, cfile); + /* Store this identifier... */ - if (!(s = (char *)malloc (strlen (val) + 1))) - error ("can't allocate temp space for hostname."); + if (!(s = (char *)dmalloc (strlen (val) + 1, MDL))) + log_fatal ("can't allocate temp space for hostname."); strcpy (s, val); c = cons ((caddr_t)s, c); len += strlen (s) + 1; /* Look for a dot; if it's there, keep going, otherwise we're done. */ - token = peek_token (&val, cfile); - if (token == DOT) - token = next_token (&val, cfile); + token = peek_token (&val, (unsigned *)0, cfile); + if (token == DOT) { + token = next_token (&val, (unsigned *)0, cfile); + ltid = 1; + } else + ltid = 0; } while (token == DOT); + /* Should be at least one token. */ + if (!len) + return (char *)0; + /* Assemble the hostname together into a string. */ - if (!(s = (char *)malloc (len))) - error ("can't allocate space for hostname."); - t = s + len; + if (!(s = (char *)dmalloc (len + ltid, MDL))) + log_fatal ("can't allocate space for hostname."); + t = s + len + ltid; *--t = 0; + if (ltid) + *--t = '.'; while (c) { pair cdr = c -> cdr; - int l = strlen ((char *)(c -> car)); + unsigned l = strlen ((char *)(c -> car)); t -= l; memcpy (t, (char *)(c -> car), l); /* Free up temp space. */ - free (c -> car); - free (c); + dfree (c -> car, MDL); + dfree (c, MDL); c = cdr; if (t != s) *--t = '.'; @@ -188,10 +260,66 @@ char *parse_host_name (cfile) return s; } +/* ip-addr-or-hostname :== ip-address | hostname + ip-address :== NUMBER DOT NUMBER DOT NUMBER DOT NUMBER + + Parse an ip address or a hostname. If uniform is zero, put in + an expr_substring node to limit hostnames that evaluate to more + than one IP address. */ + +int parse_ip_addr_or_hostname (expr, cfile, uniform) + struct expression **expr; + struct parse *cfile; + int uniform; +{ + const char *val; + enum dhcp_token token; + unsigned char addr [4]; + unsigned len = sizeof addr; + char *name; + struct expression *x = (struct expression *)0; + + token = peek_token (&val, (unsigned *)0, cfile); + if (is_identifier (token)) { + name = parse_host_name (cfile); + if (!name) + return 0; + if (!make_host_lookup (expr, name)) + return 0; + if (!uniform) { + if (!make_limit (&x, *expr, 4)) + return 0; + expression_dereference (expr, MDL); + *expr = x; + } + } else if (token == NUMBER) { + if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8)) + return 0; + return make_const_data (expr, addr, len, 0, 1, MDL); + } else { + if (token != RBRACE && token != LBRACE) + token = next_token (&val, (unsigned *)0, cfile); + parse_warn (cfile, "%s (%d): expecting IP address or hostname", + val, token); + if (token != SEMI) + skip_to_semi (cfile); + return 0; + } + + return 1; +} + +/* + * ip-address :== NUMBER DOT NUMBER DOT NUMBER DOT NUMBER + */ + int parse_ip_addr (cfile, addr) - FILE *cfile; + struct parse *cfile; struct iaddr *addr; { + const char *val; + enum dhcp_token token; + addr -> len = 4; if (parse_numeric_aggregate (cfile, addr -> iabuf, &addr -> len, DOT, 10, 8)) @@ -199,33 +327,41 @@ int parse_ip_addr (cfile, addr) return 0; } -/* hardware-parameter :== HARDWARE ETHERNET csns SEMI - csns :== NUMBER | csns COLON NUMBER */ +/* + * hardware-parameter :== HARDWARE hardware-type colon-seperated-hex-list SEMI + * hardware-type :== ETHERNET | TOKEN_RING + */ void parse_hardware_param (cfile, hardware) - FILE *cfile; + struct parse *cfile; struct hardware *hardware; { - char *val; - int token; - int hlen; + const char *val; + enum dhcp_token token; + unsigned hlen; unsigned char *t; - token = next_token (&val, cfile); + token = next_token (&val, (unsigned *)0, cfile); switch (token) { case ETHERNET: - hardware -> htype = HTYPE_ETHER; + hardware -> hbuf [0] = HTYPE_ETHER; break; case TOKEN_RING: - hardware -> htype = HTYPE_IEEE802; + hardware -> hbuf [0] = HTYPE_IEEE802; break; case FDDI: - hardware -> htype = HTYPE_FDDI; + hardware -> hbuf [0] = HTYPE_FDDI; break; default: - parse_warn ("expecting a network hardware type"); - skip_to_semi (cfile); - return; + if (!strncmp (val, "unknown-", 8)) { + hardware -> hbuf [0] = atoi (&val [8]); + } else { + parse_warn (cfile, + "expecting a network hardware type"); + skip_to_semi (cfile); + + return; + } } /* Parse the hardware address information. Technically, @@ -236,26 +372,33 @@ void parse_hardware_param (cfile, hardware) that data in the lease file rather than simply failing on such clients. Yuck. */ hlen = 0; + token = peek_token (&val, (unsigned *)0, cfile); + if (token == SEMI) { + hardware -> hlen = 1; + goto out; + } t = parse_numeric_aggregate (cfile, (unsigned char *)0, &hlen, COLON, 16, 8); - if (!t) + if (!t) { + hardware -> hlen = 1; return; - if (hlen > sizeof hardware -> haddr) { - free (t); - parse_warn ("hardware address too long"); + } + if (hlen + 1 > sizeof hardware -> hbuf) { + dfree (t, MDL); + parse_warn (cfile, "hardware address too long"); } else { - hardware -> hlen = hlen; - memcpy ((unsigned char *)&hardware -> haddr [0], - t, hardware -> hlen); - if (hlen < sizeof hardware -> haddr) - memset (&hardware -> haddr [hlen], 0, - (sizeof hardware -> haddr) - hlen); - free (t); + hardware -> hlen = hlen + 1; + memcpy ((unsigned char *)&hardware -> hbuf [1], t, hlen); + if (hlen + 1 < sizeof hardware -> hbuf) + memset (&hardware -> hbuf [hlen + 1], 0, + (sizeof hardware -> hbuf) - hlen - 1); + dfree (t, MDL); } - token = next_token (&val, cfile); + out: + token = next_token (&val, (unsigned *)0, cfile); if (token != SEMI) { - parse_warn ("expecting semicolon."); + parse_warn (cfile, "expecting semicolon."); skip_to_semi (cfile); } } @@ -263,19 +406,19 @@ void parse_hardware_param (cfile, hardware) /* lease-time :== NUMBER SEMI */ void parse_lease_time (cfile, timep) - FILE *cfile; + struct parse *cfile; TIME *timep; { - char *val; - int token; + const char *val; + enum dhcp_token token; - token = next_token (&val, cfile); + token = next_token (&val, (unsigned *)0, cfile); if (token != NUMBER) { - parse_warn ("Expecting numeric lease time"); + parse_warn (cfile, "Expecting numeric lease time"); skip_to_semi (cfile); return; } - convert_num ((unsigned char *)timep, val, 10, 32); + convert_num (cfile, (unsigned char *)timep, val, 10, 32); /* Unswap the number - convert_num returns stuff in NBO. */ *timep = ntohl (*timep); /* XXX */ @@ -291,97 +434,100 @@ void parse_lease_time (cfile, timep) unsigned char *parse_numeric_aggregate (cfile, buf, max, seperator, base, size) - FILE *cfile; + struct parse *cfile; unsigned char *buf; - int *max; + unsigned *max; int seperator; int base; - int size; + unsigned size; { - char *val; - int token; - unsigned char *bufp = buf, *s; - char *t; - int count = 0; + const char *val; + enum dhcp_token token; + unsigned char *bufp = buf, *s, *t; + unsigned count = 0; pair c = (pair)0; if (!bufp && *max) { - bufp = (unsigned char *)malloc (*max * size / 8); + bufp = (unsigned char *)dmalloc (*max * size / 8, MDL); if (!bufp) - error ("can't allocate space for numeric aggregate"); + log_fatal ("no space for numeric aggregate"); + s = 0; } else s = bufp; do { if (count) { - token = peek_token (&val, cfile); + token = peek_token (&val, (unsigned *)0, cfile); if (token != seperator) { if (!*max) break; if (token != RBRACE && token != LBRACE) - token = next_token (&val, cfile); - parse_warn ("too few numbers."); + token = next_token (&val, + (unsigned *)0, + cfile); + parse_warn (cfile, "too few numbers."); if (token != SEMI) skip_to_semi (cfile); return (unsigned char *)0; } - token = next_token (&val, cfile); + token = next_token (&val, (unsigned *)0, cfile); } - token = next_token (&val, cfile); + token = next_token (&val, (unsigned *)0, cfile); - if (token == EOF) { - parse_warn ("unexpected end of file"); + if (token == END_OF_FILE) { + parse_warn (cfile, "unexpected end of file"); break; } /* Allow NUMBER_OR_NAME if base is 16. */ if (token != NUMBER && (base != 16 || token != NUMBER_OR_NAME)) { - parse_warn ("expecting numeric value."); + parse_warn (cfile, "expecting numeric value."); skip_to_semi (cfile); return (unsigned char *)0; } /* If we can, convert the number now; otherwise, build a linked list of all the numbers. */ if (s) { - convert_num (s, val, base, size); + convert_num (cfile, s, val, base, size); s += size / 8; } else { - t = (char *)malloc (strlen (val) + 1); + t = (unsigned char *)dmalloc (strlen (val) + 1, MDL); if (!t) - error ("no temp space for number."); - strcpy (t, val); - c = cons (t, c); + log_fatal ("no temp space for number."); + strcpy ((char *)t, val); + c = cons ((caddr_t)t, c); } } while (++count != *max); /* If we had to cons up a list, convert it now. */ if (c) { - bufp = (unsigned char *)malloc (count * size / 8); + bufp = (unsigned char *)dmalloc (count * size / 8, MDL); if (!bufp) - error ("can't allocate space for numeric aggregate."); + log_fatal ("no space for numeric aggregate."); s = bufp + count - size / 8; *max = count; } while (c) { pair cdr = c -> cdr; - convert_num (s, (char *)(c -> car), base, size); + convert_num (cfile, s, (char *)(c -> car), base, size); s -= size / 8; /* Free up temp space. */ - free (c -> car); - free (c); + dfree (c -> car, MDL); + dfree (c, MDL); c = cdr; } return bufp; } -void convert_num (buf, str, base, size) +void convert_num (cfile, buf, str, base, size) + struct parse *cfile; unsigned char *buf; - char *str; + const char *str; int base; - int size; + unsigned size; { - char *ptr = str; + const char *ptr = str; int negative = 0; u_int32_t val = 0; int tval; @@ -419,12 +565,13 @@ void convert_num (buf, str, base, size) else if (tval >= '0') tval -= '0'; else { - warn ("Bogus number: %s.", str); + parse_warn (cfile, "Bogus number: %s.", str); break; } if (tval >= base) { - warn ("Bogus number: %s: digit %d not in base %d\n", - str, tval, base); + parse_warn (cfile, + "Bogus number %s: digit %d not in base %d", + str, tval, base); break; } val = val * base + tval; @@ -437,16 +584,22 @@ void convert_num (buf, str, base, size) if (val > max) { switch (base) { case 8: - warn ("value %s%o exceeds max (%d) for precision.", - negative ? "-" : "", val, max); + parse_warn (cfile, + "%s%lo exceeds max (%d) for precision.", + negative ? "-" : "", + (unsigned long)val, max); break; case 16: - warn ("value %s%x exceeds max (%d) for precision.", - negative ? "-" : "", val, max); + parse_warn (cfile, + "%s%lx exceeds max (%d) for precision.", + negative ? "-" : "", + (unsigned long)val, max); break; default: - warn ("value %s%u exceeds max (%d) for precision.", - negative ? "-" : "", val, max); + parse_warn (cfile, + "%s%lu exceeds max (%d) for precision.", + negative ? "-" : "", + (unsigned long)val, max); break; } } @@ -457,13 +610,14 @@ void convert_num (buf, str, base, size) *buf = -(unsigned long)val; break; case 16: - putShort (buf, -(unsigned long)val); + putShort (buf, -(long)val); break; case 32: - putLong (buf, -(unsigned long)val); + putLong (buf, -(long)val); break; default: - warn ("Unexpected integer size: %d\n", size); + parse_warn (cfile, + "Unexpected integer size: %d\n", size); break; } } else { @@ -478,160 +632,182 @@ void convert_num (buf, str, base, size) putULong (buf, val); break; default: - warn ("Unexpected integer size: %d\n", size); + parse_warn (cfile, + "Unexpected integer size: %d\n", size); break; } } } -/* date :== NUMBER NUMBER SLASH NUMBER SLASH NUMBER - NUMBER COLON NUMBER COLON NUMBER SEMI - - Dates are always in GMT; first number is day of week; next is - year/month/day; next is hours:minutes:seconds on a 24-hour - clock. */ +/* + * date :== NUMBER NUMBER SLASH NUMBER SLASH NUMBER + * NUMBER COLON NUMBER COLON NUMBER SEMI | + * NUMBER NUMBER SLASH NUMBER SLASH NUMBER + * NUMBER COLON NUMBER COLON NUMBER NUMBER SEMI | + * NEVER + * + * Dates are stored in GMT or with a timezone offset; first number is day + * of week; next is year/month/day; next is hours:minutes:seconds on a + * 24-hour clock, followed by the timezone offset in seconds, which is + * optional. + */ TIME parse_date (cfile) - FILE *cfile; + struct parse *cfile; { struct tm tm; int guess; - char *val; - int token; + int tzoff, wday, year, mon, mday, hour, min, sec; + const char *val; + enum dhcp_token token; static int months [11] = { 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; - /* Day of week... */ - token = next_token (&val, cfile); + /* Day of week, or "never"... */ + token = next_token (&val, (unsigned *)0, cfile); + if (token == NEVER) { + if (!parse_semi (cfile)) + return 0; + return MAX_TIME; + } + if (token != NUMBER) { - parse_warn ("numeric day of week expected."); + parse_warn (cfile, "numeric day of week expected."); if (token != SEMI) skip_to_semi (cfile); return (TIME)0; } - tm.tm_wday = atoi (val); + wday = atoi (val); /* Year... */ - token = next_token (&val, cfile); + token = next_token (&val, (unsigned *)0, cfile); if (token != NUMBER) { - parse_warn ("numeric year expected."); + parse_warn (cfile, "numeric year expected."); if (token != SEMI) skip_to_semi (cfile); return (TIME)0; } - tm.tm_year = atoi (val); - if (tm.tm_year > 1900) - tm.tm_year -= 1900; + + /* Note: the following is not a Y2K bug - it's a Y1.9K bug. Until + somebody invents a time machine, I think we can safely disregard + it. This actually works around a stupid Y2K bug that was present + in a very early beta release of dhcpd. */ + year = atoi (val); + if (year > 1900) + year -= 1900; /* Slash seperating year from month... */ - token = next_token (&val, cfile); + token = next_token (&val, (unsigned *)0, cfile); if (token != SLASH) { - parse_warn ("expected slash seperating year from month."); + parse_warn (cfile, + "expected slash seperating year from month."); if (token != SEMI) skip_to_semi (cfile); return (TIME)0; } /* Month... */ - token = next_token (&val, cfile); + token = next_token (&val, (unsigned *)0, cfile); if (token != NUMBER) { - parse_warn ("numeric month expected."); + parse_warn (cfile, "numeric month expected."); if (token != SEMI) skip_to_semi (cfile); return (TIME)0; } - tm.tm_mon = atoi (val) - 1; + mon = atoi (val) - 1; /* Slash seperating month from day... */ - token = next_token (&val, cfile); + token = next_token (&val, (unsigned *)0, cfile); if (token != SLASH) { - parse_warn ("expected slash seperating month from day."); + parse_warn (cfile, + "expected slash seperating month from day."); if (token != SEMI) skip_to_semi (cfile); return (TIME)0; } /* Month... */ - token = next_token (&val, cfile); + token = next_token (&val, (unsigned *)0, cfile); if (token != NUMBER) { - parse_warn ("numeric day of month expected."); + parse_warn (cfile, "numeric day of month expected."); if (token != SEMI) skip_to_semi (cfile); return (TIME)0; } - tm.tm_mday = atoi (val); + mday = atoi (val); /* Hour... */ - token = next_token (&val, cfile); + token = next_token (&val, (unsigned *)0, cfile); if (token != NUMBER) { - parse_warn ("numeric hour expected."); + parse_warn (cfile, "numeric hour expected."); if (token != SEMI) skip_to_semi (cfile); return (TIME)0; } - tm.tm_hour = atoi (val); + hour = atoi (val); /* Colon seperating hour from minute... */ - token = next_token (&val, cfile); + token = next_token (&val, (unsigned *)0, cfile); if (token != COLON) { - parse_warn ("expected colon seperating hour from minute."); + parse_warn (cfile, + "expected colon seperating hour from minute."); if (token != SEMI) skip_to_semi (cfile); return (TIME)0; } /* Minute... */ - token = next_token (&val, cfile); + token = next_token (&val, (unsigned *)0, cfile); if (token != NUMBER) { - parse_warn ("numeric minute expected."); + parse_warn (cfile, "numeric minute expected."); if (token != SEMI) skip_to_semi (cfile); return (TIME)0; } - tm.tm_min = atoi (val); + min = atoi (val); /* Colon seperating minute from second... */ - token = next_token (&val, cfile); + token = next_token (&val, (unsigned *)0, cfile); if (token != COLON) { - parse_warn ("expected colon seperating hour from minute."); + parse_warn (cfile, + "expected colon seperating hour from minute."); if (token != SEMI) skip_to_semi (cfile); return (TIME)0; } /* Minute... */ - token = next_token (&val, cfile); + token = next_token (&val, (unsigned *)0, cfile); if (token != NUMBER) { - parse_warn ("numeric minute expected."); + parse_warn (cfile, "numeric minute expected."); if (token != SEMI) skip_to_semi (cfile); return (TIME)0; } - tm.tm_sec = atoi (val); - tm.tm_isdst = 0; + sec = atoi (val); - /* XXX */ /* We assume that mktime does not use tm_yday. */ - tm.tm_yday = 0; + token = peek_token (&val, (unsigned *)0, cfile); + if (token == NUMBER) { + token = next_token (&val, (unsigned *)0, cfile); + tzoff = atoi (val); + } else + tzoff = 0; /* Make sure the date ends in a semicolon... */ - token = next_token (&val, cfile); - if (token != SEMI) { - parse_warn ("semicolon expected."); - skip_to_semi (cfile); + if (!parse_semi (cfile)) return 0; - } /* Guess the time value... */ - guess = ((((((365 * (tm.tm_year - 70) + /* Days in years since '70 */ - (tm.tm_year - 69) / 4 + /* Leap days since '70 */ - (tm.tm_mon /* Days in months this year */ - ? months [tm.tm_mon - 1] + guess = ((((((365 * (year - 70) + /* Days in years since '70 */ + (year - 69) / 4 + /* Leap days since '70 */ + (mon /* Days in months this year */ + ? months [mon - 1] : 0) + - (tm.tm_mon > 1 && /* Leap day this year */ - !((tm.tm_year - 72) & 3)) + - tm.tm_mday - 1) * 24) + /* Day of month */ - tm.tm_hour) * 60) + - tm.tm_min) * 60) + tm.tm_sec; + (mon > 1 && /* Leap day this year */ + !((year - 72) & 3)) + + mday - 1) * 24) + /* Day of month */ + hour) * 60) + + min) * 60) + sec + tzoff; /* This guess could be wrong because of leap seconds or other weirdness we don't know about that the system does. For @@ -644,3 +820,3999 @@ TIME parse_date (cfile) return guess; } + +/* + * option-name :== IDENTIFIER | + IDENTIFIER . IDENTIFIER + */ + +struct option *parse_option_name (cfile, allocate, known) + struct parse *cfile; + int allocate; + int *known; +{ + const char *val; + enum dhcp_token token; + char *uname; + struct universe *universe; + struct option *option; + + token = next_token (&val, (unsigned *)0, cfile); + if (!is_identifier (token)) { + parse_warn (cfile, + "expecting identifier after option keyword."); + if (token != SEMI) + skip_to_semi (cfile); + return (struct option *)0; + } + uname = dmalloc (strlen (val) + 1, MDL); + if (!uname) + log_fatal ("no memory for uname information."); + strcpy (uname, val); + token = peek_token (&val, (unsigned *)0, cfile); + if (token == DOT) { + /* Go ahead and take the DOT token... */ + token = next_token (&val, (unsigned *)0, cfile); + + /* The next token should be an identifier... */ + token = next_token (&val, (unsigned *)0, cfile); + if (!is_identifier (token)) { + parse_warn (cfile, "expecting identifier after '.'"); + if (token != SEMI) + skip_to_semi (cfile); + return (struct option *)0; + } + + /* Look up the option name hash table for the specified + uname. */ + universe = (struct universe *)0; + if (!universe_hash_lookup (&universe, universe_hash, + uname, 0, MDL)) { + parse_warn (cfile, "no option space named %s.", uname); + skip_to_semi (cfile); + return (struct option *)0; + } + } else { + /* Use the default hash table, which contains all the + standard dhcp option names. */ + val = uname; + universe = &dhcp_universe; + } + + /* Look up the actual option info... */ + option = (struct option *)0; + option_hash_lookup (&option, universe -> hash, val, 0, MDL); + + /* If we didn't get an option structure, it's an undefined option. */ + if (option) { + if (known) + *known = 1; + } else { + /* If we've been told to allocate, that means that this + (might) be an option code definition, so we'll create + an option structure just in case. */ + if (allocate) { + option = new_option (MDL); + if (val == uname) + option -> name = val; + else { + char *s; + dfree (uname, MDL); + s = dmalloc (strlen (val) + 1, MDL); + if (!s) + log_fatal ("no memory for option %s.%s", + universe -> name, val); + strcpy (s, val); + option -> name = s; + } + option -> universe = universe; + option -> code = 0; + return option; + } + if (val == uname) + parse_warn (cfile, "no option named %s", val); + else + parse_warn (cfile, "no option named %s in space %s", + val, uname); + skip_to_semi (cfile); + return (struct option *)0; + } + + /* Free the initial identifier token. */ + dfree (uname, MDL); + return option; +} + +/* IDENTIFIER SEMI */ + +void parse_option_space_decl (cfile) + struct parse *cfile; +{ + int token; + const char *val; + struct universe **ua, *nu; + char *s; + + next_token (&val, (unsigned *)0, cfile); /* Discard the SPACE token, + which was checked by the + caller. */ + token = next_token (&val, (unsigned *)0, cfile); + if (!is_identifier (token)) { + parse_warn (cfile, "expecting identifier."); + skip_to_semi (cfile); + return; + } + nu = new_universe (MDL); + if (!nu) + log_fatal ("No memory for new option space."); + + /* Set up the server option universe... */ + s = dmalloc (strlen (val) + 1, MDL); + if (!s) + log_fatal ("No memory for new option space name."); + strcpy (s, val); + nu -> name = s; + nu -> lookup_func = lookup_hashed_option; + nu -> option_state_dereference = + hashed_option_state_dereference; + nu -> foreach = hashed_option_space_foreach; + nu -> save_func = save_hashed_option; + nu -> delete_func = delete_hashed_option; + nu -> encapsulate = hashed_option_space_encapsulate; + nu -> decode = parse_option_buffer; + nu -> length_size = 1; + nu -> tag_size = 1; + nu -> store_tag = putUChar; + nu -> store_length = putUChar; + nu -> index = universe_count++; + if (nu -> index >= universe_max) { + ua = dmalloc (universe_max * 2 * sizeof *ua, MDL); + if (!ua) + log_fatal ("No memory to expand option space array."); + memcpy (ua, universes, universe_max * sizeof *ua); + universe_max *= 2; + dfree (universes, MDL); + universes = ua; + } + universes [nu -> index] = nu; + option_new_hash (&nu -> hash, 1, MDL); + if (!nu -> hash) + log_fatal ("Can't allocate %s option hash table.", nu -> name); + universe_hash_add (universe_hash, nu -> name, 0, nu, MDL); + parse_semi (cfile); +} + +/* This is faked up to look good right now. Ideally, this should do a + recursive parse and allow arbitrary data structure definitions, but for + now it just allows you to specify a single type, an array of single types, + a sequence of types, or an array of sequences of types. + + ocd :== NUMBER EQUALS ocsd SEMI + + ocsd :== ocsd_type | + ocsd_type_sequence | + ARRAY OF ocsd_simple_type_sequence + + ocsd_type_sequence :== LBRACE ocsd_types RBRACE + + ocsd_simple_type_sequence :== LBRACE ocsd_simple_types RBRACE + + ocsd_types :== ocsd_type | + ocsd_types ocsd_type + + ocsd_type :== ocsd_simple_type | + ARRAY OF ocsd_simple_type + + ocsd_simple_types :== ocsd_simple_type | + ocsd_simple_types ocsd_simple_type + + ocsd_simple_type :== BOOLEAN | + INTEGER NUMBER | + SIGNED INTEGER NUMBER | + UNSIGNED INTEGER NUMBER | + IP-ADDRESS | + TEXT | + STRING | + ENCAPSULATE identifier */ + +int parse_option_code_definition (cfile, option) + struct parse *cfile; + struct option *option; +{ + const char *val; + enum dhcp_token token; + unsigned arrayp = 0; + int recordp = 0; + int no_more_in_record = 0; + char tokbuf [128]; + unsigned tokix = 0; + char type; + int code; + int is_signed; + char *s; + int has_encapsulation = 0; + + /* Parse the option code. */ + token = next_token (&val, (unsigned *)0, cfile); + if (token != NUMBER) { + parse_warn (cfile, "expecting option code number."); + skip_to_semi (cfile); + return 0; + } + option -> code = atoi (val); + + token = next_token (&val, (unsigned *)0, cfile); + if (token != EQUAL) { + parse_warn (cfile, "expecting \"=\""); + skip_to_semi (cfile); + return 0; + } + + /* See if this is an array. */ + token = next_token (&val, (unsigned *)0, cfile); + if (token == ARRAY) { + token = next_token (&val, (unsigned *)0, cfile); + if (token != OF) { + parse_warn (cfile, "expecting \"of\"."); + skip_to_semi (cfile); + return 0; + } + arrayp = 1; + token = next_token (&val, (unsigned *)0, cfile); + } + + if (token == LBRACE) { + recordp = 1; + token = next_token (&val, (unsigned *)0, cfile); + } + + /* At this point we're expecting a data type. */ + next_type: + if (has_encapsulation) { + parse_warn (cfile, + "encapsulate must always be the last item."); + skip_to_semi (cfile); + return 0; + } + + switch (token) { + case ARRAY: + if (arrayp) { + parse_warn (cfile, "no nested arrays."); + skip_to_rbrace (cfile, recordp); + if (recordp) + skip_to_semi (cfile); + return 0; + } + token = next_token (&val, (unsigned *)0, cfile); + if (token != OF) { + parse_warn (cfile, "expecting \"of\"."); + skip_to_semi (cfile); + return 0; + } + arrayp = recordp + 1; + token = next_token (&val, (unsigned *)0, cfile); + if ((recordp) && (token == LBRACE)) { + parse_warn (cfile, + "only uniform array inside record."); + skip_to_rbrace (cfile, recordp + 1); + skip_to_semi (cfile); + return 0; + } + goto next_type; + case BOOLEAN: + type = 'f'; + break; + case INTEGER: + is_signed = 1; + parse_integer: + token = next_token (&val, (unsigned *)0, cfile); + if (token != NUMBER) { + parse_warn (cfile, "expecting number."); + skip_to_rbrace (cfile, recordp); + if (recordp) + skip_to_semi (cfile); + return 0; + } + switch (atoi (val)) { + case 8: + type = is_signed ? 'b' : 'B'; + break; + case 16: + type = is_signed ? 's' : 'S'; + break; + case 32: + type = is_signed ? 'l' : 'L'; + break; + default: + parse_warn (cfile, + "%s bit precision is not supported.", val); + skip_to_rbrace (cfile, recordp); + if (recordp) + skip_to_semi (cfile); + return 0; + } + break; + case SIGNED: + is_signed = 1; + parse_signed: + token = next_token (&val, (unsigned *)0, cfile); + if (token != INTEGER) { + parse_warn (cfile, "expecting \"integer\" keyword."); + skip_to_rbrace (cfile, recordp); + if (recordp) + skip_to_semi (cfile); + return 0; + } + goto parse_integer; + case UNSIGNED: + is_signed = 0; + goto parse_signed; + + case IP_ADDRESS: + type = 'I'; + break; + case DOMAIN_NAME: + type = 'd'; + goto no_arrays; + case TEXT: + type = 't'; + no_arrays: + if (arrayp) { + parse_warn (cfile, "arrays of text strings not %s", + "yet supported."); + skip_to_rbrace (cfile, recordp); + if (recordp) + skip_to_semi (cfile); + return 0; + } + no_more_in_record = 1; + break; + case STRING_TOKEN: + type = 'X'; + goto no_arrays; + + case ENCAPSULATE: + token = next_token (&val, (unsigned *)0, cfile); + if (!is_identifier (token)) { + parse_warn (cfile, + "expecting option space identifier"); + skip_to_semi (cfile); + return 0; + } + if (strlen (val) + tokix + 2 > sizeof (tokbuf)) + goto toobig; + tokbuf [tokix++] = 'E'; + strcpy (&tokbuf [tokix], val); + tokix += strlen (val); + type = '.'; + has_encapsulation = 1; + break; + + default: + parse_warn (cfile, "unknown data type %s", val); + skip_to_rbrace (cfile, recordp); + if (recordp) + skip_to_semi (cfile); + return 0; + } + + if (tokix == sizeof tokbuf) { + toobig: + parse_warn (cfile, "too many types in record."); + skip_to_rbrace (cfile, recordp); + if (recordp) + skip_to_semi (cfile); + return 0; + } + tokbuf [tokix++] = type; + + if (recordp) { + token = next_token (&val, (unsigned *)0, cfile); + if (arrayp > recordp) { + if (tokix == sizeof tokbuf) { + parse_warn (cfile, + "too many types in record."); + skip_to_rbrace (cfile, 1); + skip_to_semi (cfile); + return 0; + } + arrayp = 0; + tokbuf[tokix++] = 'a'; + } + if (token == COMMA) { + if (no_more_in_record) { + parse_warn (cfile, + "%s must be at end of record.", + type == 't' ? "text" : "string"); + skip_to_rbrace (cfile, 1); + if (recordp) + skip_to_semi (cfile); + return 0; + } + token = next_token (&val, (unsigned *)0, cfile); + goto next_type; + } + if (token != RBRACE) { + parse_warn (cfile, "expecting right brace."); + skip_to_rbrace (cfile, 1); + if (recordp) + skip_to_semi (cfile); + return 0; + } + } + if (!parse_semi (cfile)) { + parse_warn (cfile, "semicolon expected."); + skip_to_semi (cfile); + if (recordp) + skip_to_semi (cfile); + return 0; + } + if (has_encapsulation && arrayp) { + parse_warn (cfile, + "Arrays of encapsulations don't make sense."); + return 0; + } + if (has_encapsulation && tokbuf [0] == 'E') + has_encapsulation = 0; + s = dmalloc (tokix + + (arrayp ? 1 : 0) + + (has_encapsulation ? 1 : 0) + 1, MDL); + if (!s) + log_fatal ("no memory for option format."); + if (has_encapsulation) + s [0] = 'e'; + memcpy (s + has_encapsulation, tokbuf, tokix); + tokix += has_encapsulation; + if (arrayp) + s [tokix++] = (arrayp > recordp) ? 'a' : 'A'; + s [tokix] = 0; + option -> format = s; + if (option -> universe -> options [option -> code]) { + /* XXX Free the option, but we can't do that now because they + XXX may start out static. */ + } + option -> universe -> options [option -> code] = option; + option_hash_add (option -> universe -> hash, + (const char *)option -> name, + 0, option, MDL); + return 1; +} + +/* + * base64 :== NUMBER_OR_STRING + */ + +int parse_base64 (data, cfile) + struct data_string *data; + struct parse *cfile; +{ + enum dhcp_token token; + const char *val; + int i, j, k; + unsigned acc = 0; + static unsigned char + from64 [] = {64, 64, 64, 64, 64, 64, 64, 64, /* \"#$%&' */ + 64, 64, 64, 62, 64, 64, 64, 63, /* ()*+,-./ */ + 52, 53, 54, 55, 56, 57, 58, 59, /* 01234567 */ + 60, 61, 64, 64, 64, 64, 64, 64, /* 89:;<=>? */ + 64, 0, 1, 2, 3, 4, 5, 6, /* @ABCDEFG */ + 7, 8, 9, 10, 11, 12, 13, 14, /* HIJKLMNO */ + 15, 16, 17, 18, 19, 20, 21, 22, /* PQRSTUVW */ + 23, 24, 25, 64, 64, 64, 64, 64, /* XYZ[\]^_ */ + 64, 26, 27, 28, 29, 30, 31, 32, /* 'abcdefg */ + 33, 34, 35, 36, 37, 38, 39, 40, /* hijklmno */ + 41, 42, 43, 44, 45, 46, 47, 48, /* pqrstuvw */ + 49, 50, 51, 64, 64, 64, 64, 64}; /* xyz{|}~ */ + struct string_list *bufs = (struct string_list *)0, + *last = (struct string_list *)0, + *t; + int cc = 0; + int terminated = 0; + + /* It's possible for a + or a / to cause a base64 quantity to be + tokenized into more than one token, so we have to parse them all + in before decoding. */ + do { + unsigned l; + + token = next_token (&val, &l, cfile); + t = dmalloc (l + sizeof *t, MDL); + if (!t) + log_fatal ("no memory for base64 buffer."); + memset (t, 0, (sizeof *t) - 1); + memcpy (t -> string, val, l + 1); + cc += l; + if (last) + last -> next = t; + else + bufs = t; + last = t; + token = peek_token (&val, (unsigned *)0, cfile); + } while (token == NUMBER_OR_NAME || token == NAME || token == EQUAL || + token == NUMBER || token == PLUS || token == SLASH || + token == STRING); + + data -> len = cc; + data -> len = (data -> len * 3) / 4; + if (!buffer_allocate (&data -> buffer, data -> len, MDL)) { + parse_warn (cfile, "can't allocate buffer for base64 data."); + data -> len = 0; + data -> data = (unsigned char *)0; + return 0; + } + + j = k = 0; + for (t = bufs; t; t = t -> next) { + for (i = 0; t -> string [i]; i++) { + unsigned foo = t -> string [i]; + if (terminated && foo != '=') { + parse_warn (cfile, + "stuff after base64 '=' terminator: %s.", + &t -> string [i]); + goto bad; + } + if (foo < ' ' || foo > 'z') { + bad64: + parse_warn (cfile, + "invalid base64 character %d.", + t -> string [i]); + bad: + data_string_forget (data, MDL); + goto out; + } + if (foo == '=') + terminated = 1; + else { + foo = from64 [foo - ' ']; + if (foo == 64) + goto bad64; + acc = (acc << 6) + foo; + switch (k % 4) { + case 0: + break; + case 1: + data -> buffer -> data [j++] = (acc >> 4); + acc = acc & 0x0f; + break; + + case 2: + data -> buffer -> data [j++] = (acc >> 2); + acc = acc & 0x03; + break; + case 3: + data -> buffer -> data [j++] = acc; + acc = 0; + break; + } + } + k++; + } + } + if (k % 4) { + if (acc) { + parse_warn (cfile, + "partial base64 value left over: %d.", + acc); + } + } + data -> len = j; + data -> data = data -> buffer -> data; + out: + for (t = bufs; t; t = last) { + last = t -> next; + dfree (t, MDL); + } + if (data -> len) + return 1; + else + return 0; +} + + +/* + * colon-seperated-hex-list :== NUMBER | + * NUMBER COLON colon-seperated-hex-list + */ + +int parse_cshl (data, cfile) + struct data_string *data; + struct parse *cfile; +{ + u_int8_t ibuf [128]; + unsigned ilen = 0; + unsigned tlen = 0; + struct option_tag *sl = (struct option_tag *)0; + struct option_tag *next, **last = &sl; + enum dhcp_token token; + const char *val; + unsigned char *rvp; + + do { + token = next_token (&val, (unsigned *)0, cfile); + if (token != NUMBER && token != NUMBER_OR_NAME) { + parse_warn (cfile, "expecting hexadecimal number."); + skip_to_semi (cfile); + for (; sl; sl = next) { + next = sl -> next; + dfree (sl, MDL); + } + return 0; + } + if (ilen == sizeof ibuf) { + next = (struct option_tag *) + dmalloc (ilen - 1 + + sizeof (struct option_tag), MDL); + if (!next) + log_fatal ("no memory for string list."); + memcpy (next -> data, ibuf, ilen); + *last = next; + last = &next -> next; + tlen += ilen; + ilen = 0; + } + convert_num (cfile, &ibuf [ilen++], val, 16, 8); + + token = peek_token (&val, (unsigned *)0, cfile); + if (token != COLON) + break; + token = next_token (&val, (unsigned *)0, cfile); + } while (1); + + if (!buffer_allocate (&data -> buffer, tlen + ilen, MDL)) + log_fatal ("no memory to store octet data."); + data -> data = &data -> buffer -> data [0]; + data -> len = tlen + ilen; + data -> terminated = 0; + + rvp = &data -> buffer -> data [0]; + while (sl) { + next = sl -> next; + memcpy (rvp, sl -> data, sizeof ibuf); + rvp += sizeof ibuf; + dfree (sl, MDL); + sl = next; + } + + memcpy (rvp, ibuf, ilen); + return 1; +} + +/* + * executable-statements :== executable-statement executable-statements | + * executable-statement + * + * executable-statement :== + * IF if-statement | + * ADD class-name SEMI | + * BREAK SEMI | + * OPTION option-parameter SEMI | + * SUPERSEDE option-parameter SEMI | + * PREPEND option-parameter SEMI | + * APPEND option-parameter SEMI + */ + +int parse_executable_statements (statements, cfile, lose, case_context) + struct executable_statement **statements; + struct parse *cfile; + int *lose; + enum expression_context case_context; +{ + struct executable_statement **next; + + next = statements; + while (parse_executable_statement (next, cfile, lose, case_context)) + next = &((*next) -> next); + if (!*lose) + return 1; + return 0; +} + +int parse_executable_statement (result, cfile, lose, case_context) + struct executable_statement **result; + struct parse *cfile; + int *lose; + enum expression_context case_context; +{ + enum dhcp_token token; + const char *val; + struct executable_statement base; + struct class *cta; + struct option *option; + struct option_cache *cache; + int known; + int flag; + int i; + struct dns_zone *zone; + isc_result_t status; + char *s; + + token = peek_token (&val, (unsigned *)0, cfile); + switch (token) { + case IF: + next_token (&val, (unsigned *)0, cfile); + return parse_if_statement (result, cfile, lose); + + case TOKEN_ADD: + token = next_token (&val, (unsigned *)0, cfile); + token = next_token (&val, (unsigned *)0, cfile); + if (token != STRING) { + parse_warn (cfile, "expecting class name."); + skip_to_semi (cfile); + *lose = 1; + return 0; + } + cta = (struct class *)0; + status = find_class (&cta, val, MDL); + if (status != ISC_R_SUCCESS) { + parse_warn (cfile, "class %s: %s", + val, isc_result_totext (status)); + skip_to_semi (cfile); + *lose = 1; + return 0; + } + if (!parse_semi (cfile)) { + *lose = 1; + return 0; + } + if (!executable_statement_allocate (result, MDL)) + log_fatal ("no memory for new statement."); + (*result) -> op = add_statement; + (*result) -> data.add = cta; + break; + + case BREAK: + token = next_token (&val, (unsigned *)0, cfile); + if (!parse_semi (cfile)) { + *lose = 1; + return 0; + } + if (!executable_statement_allocate (result, MDL)) + log_fatal ("no memory for new statement."); + (*result) -> op = break_statement; + break; + + case SEND: + token = next_token (&val, (unsigned *)0, cfile); + known = 0; + option = parse_option_name (cfile, 0, &known); + if (!option) { + *lose = 1; + return 0; + } + return parse_option_statement (result, cfile, 1, option, + send_option_statement); + + case SUPERSEDE: + case OPTION: + token = next_token (&val, (unsigned *)0, cfile); + known = 0; + option = parse_option_name (cfile, 0, &known); + if (!option) { + *lose = 1; + return 0; + } + return parse_option_statement (result, cfile, 1, option, + supersede_option_statement); + + case ALLOW: + flag = 1; + goto pad; + case DENY: + flag = 0; + goto pad; + case IGNORE: + flag = 2; + pad: + token = next_token (&val, (unsigned *)0, cfile); + cache = (struct option_cache *)0; + if (!parse_allow_deny (&cache, cfile, flag)) + return 0; + if (!executable_statement_allocate (result, MDL)) + log_fatal ("no memory for new statement."); + (*result) -> op = supersede_option_statement; + (*result) -> data.option = cache; + break; + + case DEFAULT: + token = next_token (&val, (unsigned *)0, cfile); + token = peek_token (&val, (unsigned *)0, cfile); + if (token == COLON) + goto switch_default; + known = 0; + option = parse_option_name (cfile, 0, &known); + if (!option) { + *lose = 1; + return 0; + } + return parse_option_statement (result, cfile, 1, option, + default_option_statement); + + case PREPEND: + token = next_token (&val, (unsigned *)0, cfile); + known = 0; + option = parse_option_name (cfile, 0, &known); + if (!option) { + *lose = 1; + return 0; + } + return parse_option_statement (result, cfile, 1, option, + prepend_option_statement); + + case APPEND: + token = next_token (&val, (unsigned *)0, cfile); + known = 0; + option = parse_option_name (cfile, 0, &known); + if (!option) { + *lose = 1; + return 0; + } + return parse_option_statement (result, cfile, 1, option, + append_option_statement); + + case ON: + token = next_token (&val, (unsigned *)0, cfile); + return parse_on_statement (result, cfile, lose); + + case SWITCH: + token = next_token (&val, (unsigned *)0, cfile); + return parse_switch_statement (result, cfile, lose); + + case CASE: + token = next_token (&val, (unsigned *)0, cfile); + if (case_context == context_any) { + parse_warn (cfile, + "case statement in inappropriate scope."); + *lose = 1; + skip_to_semi (cfile); + return 0; + } + return parse_case_statement (result, + cfile, lose, case_context); + + switch_default: + token = next_token (&val, (unsigned *)0, cfile); + if (case_context == context_any) { + parse_warn (cfile, "switch default statement in %s", + "inappropriate scope."); + + *lose = 1; + return 0; + } else { + if (!executable_statement_allocate (result, MDL)) + log_fatal ("no memory for default statement."); + (*result) -> op = default_statement; + return 1; + } + + case DEFINE: + case TOKEN_SET: + token = next_token (&val, (unsigned *)0, cfile); + if (token == DEFINE) + flag = 1; + else + flag = 0; + + token = next_token (&val, (unsigned *)0, cfile); + if (token != NAME && token != NUMBER_OR_NAME) { + parse_warn (cfile, + "%s can't be a variable name", val); + badset: + skip_to_semi (cfile); + *lose = 1; + return 0; + } + + if (!executable_statement_allocate (result, MDL)) + log_fatal ("no memory for set statement."); + (*result) -> op = flag ? define_statement : set_statement; + (*result) -> data.set.name = dmalloc (strlen (val) + 1, MDL); + if (!(*result)->data.set.name) + log_fatal ("can't allocate variable name"); + strcpy ((*result) -> data.set.name, val); + token = next_token (&val, (unsigned *)0, cfile); + + if (token == LPAREN) { + struct string_list *head, *cur, *new; + struct expression *expr; + head = cur = (struct string_list *)0; + do { + token = next_token (&val, + (unsigned *)0, cfile); + if (token == RPAREN) + break; + if (token != NAME && token != NUMBER_OR_NAME) { + parse_warn (cfile, + "expecting argument name"); + skip_to_rbrace (cfile, 0); + *lose = 1; + executable_statement_dereference + (result, MDL); + return 0; + } + new = ((struct string_list *) + dmalloc (sizeof (struct string_list) + + strlen (val), MDL)); + if (!new) + log_fatal ("can't allocate string."); + memset (new, 0, sizeof *new); + strcpy (new -> string, val); + if (cur) { + cur -> next = new; + cur = new; + } else { + head = cur = new; + } + token = next_token (&val, + (unsigned *)0, cfile); + } while (token == COMMA); + + if (token != RPAREN) { + parse_warn (cfile, "expecting right paren."); + badx: + skip_to_semi (cfile); + *lose = 1; + executable_statement_dereference (result, MDL); + return 0; + } + + token = next_token (&val, (unsigned *)0, cfile); + if (token != LBRACE) { + parse_warn (cfile, "expecting left brace."); + goto badx; + } + + expr = (struct expression *)0; + if (!(expression_allocate (&expr, MDL))) + log_fatal ("can't allocate expression."); + expr -> op = expr_function; + if (!fundef_allocate (&expr -> data.func, MDL)) + log_fatal ("can't allocate fundef."); + expr -> data.func -> args = head; + (*result) -> data.set.expr = expr; + + if (!(parse_executable_statements + (&expr -> data.func -> statements, cfile, lose, + case_context))) { + if (*lose) + goto badx; + } + + token = next_token (&val, (unsigned *)0, cfile); + if (token != RBRACE) { + parse_warn (cfile, "expecting rigt brace."); + goto badx; + } + } else { + if (token != EQUAL) { + parse_warn (cfile, + "expecting '=' in %s statement.", + flag ? "define" : "set"); + goto badset; + } + + if (!parse_expression (&(*result) -> data.set.expr, + cfile, lose, context_any, + (struct expression **)0, + expr_none)) { + if (!*lose) + parse_warn (cfile, + "expecting expression."); + else + *lose = 1; + skip_to_semi (cfile); + executable_statement_dereference (result, MDL); + return 0; + } + if (parse_semi (cfile)) { + *lose = 1; + executable_statement_dereference (result, MDL); + return 0; + } + } + break; + + case UNSET: + token = next_token (&val, (unsigned *)0, cfile); + + token = next_token (&val, (unsigned *)0, cfile); + if (token != NAME && token != NUMBER_OR_NAME) { + parse_warn (cfile, + "%s can't be a variable name", val); + badunset: + skip_to_semi (cfile); + *lose = 1; + return 0; + } + + if (!executable_statement_allocate (result, MDL)) + log_fatal ("no memory for set statement."); + (*result) -> op = unset_statement; + (*result) -> data.unset = dmalloc (strlen (val) + 1, MDL); + if (!(*result)->data.unset) + log_fatal ("can't allocate variable name"); + strcpy ((*result) -> data.unset, val); + if (!parse_semi (cfile)) { + *lose = 1; + executable_statement_dereference (result, MDL); + return 0; + } + break; + + case EVAL: + token = next_token (&val, (unsigned *)0, cfile); + + if (!executable_statement_allocate (result, MDL)) + log_fatal ("no memory for eval statement."); + (*result) -> op = eval_statement; + + if (!parse_expression (&(*result) -> data.eval, + cfile, lose, context_data, /* XXX */ + (struct expression **)0, expr_none)) { + if (!*lose) + parse_warn (cfile, + "expecting data expression."); + else + *lose = 1; + skip_to_semi (cfile); + executable_statement_dereference (result, MDL); + return 0; + } + if (!parse_semi (cfile)) { + *lose = 1; + executable_statement_dereference (result, MDL); + } + break; + + case RETURN: + token = next_token (&val, (unsigned *)0, cfile); + + if (!executable_statement_allocate (result, MDL)) + log_fatal ("no memory for return statement."); + (*result) -> op = return_statement; + + if (!parse_expression (&(*result) -> data.retval, + cfile, lose, context_data, + (struct expression **)0, expr_none)) { + if (!*lose) + parse_warn (cfile, + "expecting data expression."); + else + *lose = 1; + skip_to_semi (cfile); + executable_statement_dereference (result, MDL); + return 0; + } + if (!parse_semi (cfile)) { + *lose = 1; + executable_statement_dereference (result, MDL); + return 0; + } + break; + + case LOG: + token = next_token (&val, (unsigned *)0, cfile); + + if (!executable_statement_allocate (result, MDL)) + log_fatal ("no memory for log statement."); + (*result) -> op = log_statement; + + token = next_token (&val, (unsigned *)0, cfile); + if (token != LPAREN) { + parse_warn (cfile, "left parenthesis expected."); + skip_to_semi (cfile); + *lose = 1; + return 0; + } + + token = peek_token (&val, (unsigned *)0, cfile); + i = 1; + if (token == FATAL) { + (*result) -> data.log.priority = log_priority_fatal; + } else if (token == ERROR) { + (*result) -> data.log.priority = log_priority_error; + } else if (token == TOKEN_DEBUG) { + (*result) -> data.log.priority = log_priority_debug; + } else if (token == INFO) { + (*result) -> data.log.priority = log_priority_info; + } else { + (*result) -> data.log.priority = log_priority_debug; + i = 0; + } + if (i) { + token = next_token (&val, (unsigned *)0, cfile); + token = next_token (&val, (unsigned *)0, cfile); + if (token != COMMA) { + parse_warn (cfile, "comma expected."); + skip_to_semi (cfile); + *lose = 1; + return 0; + } + } + + if (!(parse_data_expression + (&(*result) -> data.log.expr, cfile, lose))) { + skip_to_semi (cfile); + *lose = 1; + return 0; + } + + token = next_token (&val, (unsigned *)0, cfile); + if (token != RPAREN) { + parse_warn (cfile, "right parenthesis expected."); + skip_to_semi (cfile); + *lose = 1; + return 0; + } + + token = next_token (&val, (unsigned *)0, cfile); + if (token != SEMI) { + parse_warn (cfile, "semicolon expected."); + skip_to_semi (cfile); + *lose = 1; + return 0; + } + break; + + /* Not really a statement, but we parse it here anyway + because it's appropriate for all DHCP agents with + parsers. */ + case ZONE: + token = next_token (&val, (unsigned *)0, cfile); + zone = (struct dns_zone *)0; + if (!dns_zone_allocate (&zone, MDL)) + log_fatal ("no memory for new zone."); + zone -> name = parse_host_name (cfile); + if (!zone -> name) { + badzone: + parse_warn (cfile, "expecting hostname."); + *lose = 1; + skip_to_semi (cfile); + dns_zone_dereference (&zone, MDL); + return 0; + } + i = strlen (zone -> name); + if (zone -> name [i - 1] != '.') { + s = dmalloc ((unsigned)i + 2, MDL); + if (!s) + goto badzone; + strcpy (s, zone -> name); + s [i] = '.'; + s [i + 1] = 0; + dfree (zone -> name, MDL); + zone -> name = s; + } + if (!parse_zone (zone, cfile)) + goto badzone; + status = enter_dns_zone (zone); + if (status != ISC_R_SUCCESS) { + if (parse_semi (cfile)) + parse_warn (cfile, "dns zone key %s: %s", + zone -> name, + isc_result_totext (status)); + dns_zone_dereference (&zone, MDL); + return 0; + } + dns_zone_dereference (&zone, MDL); + return 1; + + /* Also not really a statement, but same idea as above. */ + case KEY: + token = next_token (&val, (unsigned *)0, cfile); + if (!parse_key (cfile)) { + *lose = 1; + return 0; + } + return 1; + + default: + if (config_universe && is_identifier (token)) { + option = (struct option *)0; + option_hash_lookup (&option, config_universe -> hash, + val, 0, MDL); + if (option) { + token = next_token (&val, + (unsigned *)0, cfile); + return parse_option_statement + (result, cfile, 1, option, + supersede_option_statement); + } + } + + if (token == NUMBER_OR_NAME || token == NAME) { + /* This is rather ugly. Since function calls are + data expressions, fake up an eval statement. */ + if (!executable_statement_allocate (result, MDL)) + log_fatal ("no memory for eval statement."); + (*result) -> op = eval_statement; + + if (!parse_expression (&(*result) -> data.eval, + cfile, lose, context_data, + (struct expression **)0, + expr_none)) { + if (!*lose) + parse_warn (cfile, "expecting " + "function call."); + else + *lose = 1; + skip_to_semi (cfile); + executable_statement_dereference (result, MDL); + return 0; + } + if (!parse_semi (cfile)) { + *lose = 1; + executable_statement_dereference (result, MDL); + return 0; + } + break; + } + + *lose = 0; + return 0; + } + + return 1; +} + +/* zone-statements :== zone-statement | + zone-statement zone-statements + zone-statement :== + PRIMARY ip-addresses SEMI | + SECONDARY ip-addresses SEMI | + key-reference SEMI + ip-addresses :== ip-addr-or-hostname | + ip-addr-or-hostname COMMA ip-addresses + key-reference :== KEY STRING | + KEY identifier */ + +int parse_zone (struct dns_zone *zone, struct parse *cfile) +{ + int token; + const char *val; + char *key_name; + struct option_cache *oc; + int done = 0; + + token = next_token (&val, (unsigned *)0, cfile); + if (token != LBRACE) { + parse_warn (cfile, "expecting left brace"); + return 0; + } + + do { + token = peek_token (&val, (unsigned *)0, cfile); + switch (token) { + case PRIMARY: + if (zone -> primary) { + parse_warn (cfile, + "more than one primary."); + skip_to_semi (cfile); + return 0; + } + if (!option_cache_allocate (&zone -> primary, MDL)) + log_fatal ("can't allocate primary option cache."); + oc = zone -> primary; + goto consemup; + + case SECONDARY: + if (zone -> secondary) { + parse_warn (cfile, "more than one secondary."); + skip_to_semi (cfile); + return 0; + } + if (!option_cache_allocate (&zone -> secondary, MDL)) + log_fatal ("can't allocate secondary."); + oc = zone -> secondary; + consemup: + token = next_token (&val, (unsigned *)0, cfile); + do { + struct expression *expr = (struct expression *)0; + if (!parse_ip_addr_or_hostname (&expr, cfile, 0)) { + parse_warn (cfile, + "expecting IP addr or hostname."); + skip_to_semi (cfile); + return 0; + } + if (oc -> expression) { + struct expression *old = + (struct expression *)0; + expression_reference (&old, + oc -> expression, + MDL); + expression_dereference (&oc -> expression, + MDL); + if (!make_concat (&oc -> expression, + old, expr)) + log_fatal ("no memory for concat."); + expression_dereference (&expr, MDL); + expression_dereference (&old, MDL); + } else { + expression_reference (&oc -> expression, + expr, MDL); + expression_dereference (&expr, MDL); + } + token = next_token (&val, (unsigned *)0, cfile); + } while (token == COMMA); + if (token != SEMI) { + parse_warn (cfile, "expecting semicolon."); + skip_to_semi (cfile); + return 0; + } + break; + + case KEY: + token = next_token (&val, (unsigned *)0, cfile); + token = peek_token (&val, (unsigned *)0, cfile); + if (token == STRING) { + token = next_token (&val, (unsigned *)0, cfile); + key_name = (char *)0; + } else { + key_name = parse_host_name (cfile); + if (!key_name) { + parse_warn (cfile, "expecting key name."); + skip_to_semi (cfile); + return 0; + } + val = key_name; + } + if (omapi_auth_key_lookup_name (&zone -> key, val) != + ISC_R_SUCCESS) + parse_warn (cfile, "unknown key %s", val); + if (key_name) + dfree (key_name, MDL); + if (!parse_semi (cfile)) + return 0; + break; + + default: + done = 1; + break; + } + } while (!done); + + token = next_token (&val, (unsigned *)0, cfile); + if (token != RBRACE) { + parse_warn (cfile, "expecting right brace."); + return 0; + } + return 1; +} + +/* key-statements :== key-statement | + key-statement key-statements + key-statement :== + ALGORITHM host-name SEMI | + secret-definition SEMI + secret-definition :== SECRET base64val | + SECRET STRING */ + +int parse_key (struct parse *cfile) +{ + int token; + const char *val; + int done = 0; + struct auth_key *key; + struct data_string ds; + isc_result_t status; + char *s; + + key = (struct auth_key *)0; + if (omapi_auth_key_new (&key, MDL) != ISC_R_SUCCESS) + log_fatal ("no memory for key"); + + token = peek_token (&val, (unsigned *)0, cfile); + if (token == STRING) { + token = next_token (&val, (unsigned *)0, cfile); + key -> name = dmalloc (strlen (val) + 1, MDL); + if (!key -> name) + log_fatal ("no memory for key name."); + strcpy (key -> name, val); + + } else { + key -> name = parse_host_name (cfile); + if (!key -> name) { + parse_warn (cfile, "expecting key name."); + skip_to_semi (cfile); + goto bad; + } + } + + token = next_token (&val, (unsigned *)0, cfile); + if (token != LBRACE) { + parse_warn (cfile, "expecting left brace"); + goto bad; + } + + do { + token = next_token (&val, (unsigned *)0, cfile); + switch (token) { + case ALGORITHM: + if (key -> algorithm) { + parse_warn (cfile, + "key %s: too many algorithms", + key -> name); + goto rbad; + } + key -> algorithm = parse_host_name (cfile); + if (!key -> algorithm) { + parse_warn (cfile, + "expecting key algorithm name."); + goto rbad; + } + if (!parse_semi (cfile)) + goto rbad; + /* If the algorithm name isn't an FQDN, tack on + the .SIG-ALG.REG.NET. domain. */ + s = strrchr (key -> algorithm, '.'); + if (!s) { + static char add [] = ".SIG-ALG.REG.INT."; + s = dmalloc (strlen (key -> algorithm) + + sizeof (add), MDL); + if (!s) { + log_error ("no memory for key %s.", + "algorithm"); + goto rbad; + } + strcpy (s, key -> algorithm); + strcat (s, add); + dfree (key -> algorithm, MDL); + key -> algorithm = s; + } else if (s [1]) { + /* If there is no trailing '.', hack one in. */ + s = dmalloc (strlen (key -> algorithm) + 2, MDL); + if (!s) { + log_error ("no memory for key %s.", + key -> algorithm); + goto rbad; + } + strcpy (s, key -> algorithm); + strcat (s, "."); + dfree (key -> algorithm, MDL); + key -> algorithm = s; + } + break; + + case SECRET: + if (key -> key) { + parse_warn (cfile, "key %s: too many secrets", + key -> name); + goto rbad; + } + + memset (&ds, 0, sizeof(ds)); + if (!parse_base64 (&ds, cfile)) + goto rbad; + status = omapi_data_string_new (&key -> key, ds.len, + MDL); + if (status != ISC_R_SUCCESS) + goto rbad; + memcpy (key -> key -> value, + ds.buffer -> data, ds.len); + data_string_forget (&ds, MDL); + + if (!parse_semi (cfile)) + goto rbad; + break; + + default: + done = 1; + break; + } + } while (!done); + if (token != RBRACE) { + parse_warn (cfile, "expecting right brace."); + goto rbad; + } + /* Allow the BIND 8 syntax, which has a semicolon after each + closing brace. */ + token = peek_token (&val, (unsigned *)0, cfile); + if (token == SEMI) + token = next_token (&val, (unsigned *)0, cfile); + + /* Remember the key. */ + status = omapi_auth_key_enter (key); + if (status != ISC_R_SUCCESS) { + parse_warn (cfile, "tsig key %s: %s", + key -> name, isc_result_totext (status)); + goto bad; + } + omapi_auth_key_dereference (&key, MDL); + return 1; + + rbad: + skip_to_rbrace (cfile, 1); + bad: + omapi_auth_key_dereference (&key, MDL); + return 0; +} + +/* + * on-statement :== event-types LBRACE executable-statements RBRACE + * event-types :== event-type OR event-types | + * event-type + * event-type :== EXPIRY | COMMIT | RELEASE + */ + +int parse_on_statement (result, cfile, lose) + struct executable_statement **result; + struct parse *cfile; + int *lose; +{ + enum dhcp_token token; + const char *val; + + if (!executable_statement_allocate (result, MDL)) + log_fatal ("no memory for new statement."); + (*result) -> op = on_statement; + + do { + token = next_token (&val, (unsigned *)0, cfile); + switch (token) { + case EXPIRY: + (*result) -> data.on.evtypes |= ON_EXPIRY; + break; + + case COMMIT: + (*result) -> data.on.evtypes |= ON_COMMIT; + break; + + case RELEASE: + (*result) -> data.on.evtypes |= ON_RELEASE; + break; + + case TRANSMISSION: + (*result) -> data.on.evtypes |= ON_TRANSMISSION; + break; + + default: + parse_warn (cfile, "expecting a lease event type"); + skip_to_semi (cfile); + *lose = 1; + executable_statement_dereference (result, MDL); + return 0; + } + token = next_token (&val, (unsigned *)0, cfile); + } while (token == OR); + + /* Semicolon means no statements. */ + if (token == SEMI) + return 1; + + if (token != LBRACE) { + parse_warn (cfile, "left brace expected."); + skip_to_semi (cfile); + *lose = 1; + executable_statement_dereference (result, MDL); + return 0; + } + if (!parse_executable_statements (&(*result) -> data.on.statements, + cfile, lose, context_any)) { + if (*lose) { + /* Try to even things up. */ + do { + token = next_token (&val, + (unsigned *)0, cfile); + } while (token != END_OF_FILE && token != RBRACE); + executable_statement_dereference (result, MDL); + return 0; + } + } + token = next_token (&val, (unsigned *)0, cfile); + if (token != RBRACE) { + parse_warn (cfile, "right brace expected."); + skip_to_semi (cfile); + *lose = 1; + executable_statement_dereference (result, MDL); + return 0; + } + return 1; +} + +/* + * switch-statement :== LPAREN expr RPAREN LBRACE executable-statements RBRACE + * + */ + +int parse_switch_statement (result, cfile, lose) + struct executable_statement **result; + struct parse *cfile; + int *lose; +{ + enum dhcp_token token; + const char *val; + + if (!executable_statement_allocate (result, MDL)) + log_fatal ("no memory for new statement."); + (*result) -> op = switch_statement; + + token = next_token (&val, (unsigned *)0, cfile); + if (token != LPAREN) { + parse_warn (cfile, "expecting left brace."); + pfui: + *lose = 1; + skip_to_semi (cfile); + gnorf: + executable_statement_dereference (result, MDL); + return 0; + } + + if (!parse_expression (&(*result) -> data.s_switch.expr, + cfile, lose, context_data_or_numeric, + (struct expression **)0, expr_none)) { + if (!*lose) { + parse_warn (cfile, + "expecting data or numeric expression."); + goto pfui; + } + goto gnorf; + } + + token = next_token (&val, (unsigned *)0, cfile); + if (token != RPAREN) { + parse_warn (cfile, "right paren expected."); + goto pfui; + } + + token = next_token (&val, (unsigned *)0, cfile); + if (token != LBRACE) { + parse_warn (cfile, "left brace expected."); + goto pfui; + } + if (!(parse_executable_statements + (&(*result) -> data.s_switch.statements, cfile, lose, + (is_data_expression ((*result) -> data.s_switch.expr) + ? context_data : context_numeric)))) { + if (*lose) { + skip_to_rbrace (cfile, 1); + executable_statement_dereference (result, MDL); + return 0; + } + } + token = next_token (&val, (unsigned *)0, cfile); + if (token != RBRACE) { + parse_warn (cfile, "right brace expected."); + goto pfui; + } + return 1; +} + +/* + * case-statement :== CASE expr COLON + * + */ + +int parse_case_statement (result, cfile, lose, case_context) + struct executable_statement **result; + struct parse *cfile; + int *lose; + enum expression_context case_context; +{ + enum dhcp_token token; + const char *val; + + if (!executable_statement_allocate (result, MDL)) + log_fatal ("no memory for new statement."); + (*result) -> op = case_statement; + + if (!parse_expression (&(*result) -> data.c_case, + cfile, lose, case_context, + (struct expression **)0, expr_none)) + { + if (!*lose) { + parse_warn (cfile, "expecting %s expression.", + (case_context == context_data + ? "data" : "numeric")); + } + pfui: + *lose = 1; + skip_to_semi (cfile); + executable_statement_dereference (result, MDL); + return 0; + } + + token = next_token (&val, (unsigned *)0, cfile); + if (token != COLON) { + parse_warn (cfile, "colon expected."); + goto pfui; + } + return 1; +} + +/* + * if-statement :== boolean-expression LBRACE executable-statements RBRACE + * else-statement + * + * else-statement :== <null> | + * ELSE LBRACE executable-statements RBRACE | + * ELSE IF if-statement | + * ELSIF if-statement + */ + +int parse_if_statement (result, cfile, lose) + struct executable_statement **result; + struct parse *cfile; + int *lose; +{ + enum dhcp_token token; + const char *val; + int parenp; + + if (!executable_statement_allocate (result, MDL)) + log_fatal ("no memory for if statement."); + + (*result) -> op = if_statement; + + token = peek_token (&val, (unsigned *)0, cfile); + if (token == LPAREN) { + parenp = 1; + next_token (&val, (unsigned *)0, cfile); + } else + parenp = 0; + + + if (!parse_boolean_expression (&(*result) -> data.ie.expr, + cfile, lose)) { + if (!*lose) + parse_warn (cfile, "boolean expression expected."); + executable_statement_dereference (result, MDL); + *lose = 1; + return 0; + } +#if defined (DEBUG_EXPRESSION_PARSE) + print_expression ("if condition", (*result) -> data.ie.expr); +#endif + if (parenp) { + token = next_token (&val, (unsigned *)0, cfile); + if (token != RPAREN) { + parse_warn (cfile, "expecting right paren."); + *lose = 1; + executable_statement_dereference (result, MDL); + return 0; + } + } + token = next_token (&val, (unsigned *)0, cfile); + if (token != LBRACE) { + parse_warn (cfile, "left brace expected."); + skip_to_semi (cfile); + *lose = 1; + executable_statement_dereference (result, MDL); + return 0; + } + if (!parse_executable_statements (&(*result) -> data.ie.tc, + cfile, lose, context_any)) { + if (*lose) { + /* Try to even things up. */ + do { + token = next_token (&val, + (unsigned *)0, cfile); + } while (token != END_OF_FILE && token != RBRACE); + executable_statement_dereference (result, MDL); + return 0; + } + } + token = next_token (&val, (unsigned *)0, cfile); + if (token != RBRACE) { + parse_warn (cfile, "right brace expected."); + skip_to_semi (cfile); + *lose = 1; + executable_statement_dereference (result, MDL); + return 0; + } + token = peek_token (&val, (unsigned *)0, cfile); + if (token == ELSE) { + token = next_token (&val, (unsigned *)0, cfile); + token = peek_token (&val, (unsigned *)0, cfile); + if (token == IF) { + token = next_token (&val, (unsigned *)0, cfile); + if (!parse_if_statement (&(*result) -> data.ie.fc, + cfile, lose)) { + if (!*lose) + parse_warn (cfile, + "expecting if statement"); + executable_statement_dereference (result, MDL); + *lose = 1; + return 0; + } + } else if (token != LBRACE) { + parse_warn (cfile, "left brace or if expected."); + skip_to_semi (cfile); + *lose = 1; + executable_statement_dereference (result, MDL); + return 0; + } else { + token = next_token (&val, (unsigned *)0, cfile); + if (!(parse_executable_statements + (&(*result) -> data.ie.fc, + cfile, lose, context_any))) { + executable_statement_dereference (result, MDL); + return 0; + } + token = next_token (&val, (unsigned *)0, cfile); + if (token != RBRACE) { + parse_warn (cfile, "right brace expected."); + skip_to_semi (cfile); + *lose = 1; + executable_statement_dereference (result, MDL); + return 0; + } + } + } else if (token == ELSIF) { + token = next_token (&val, (unsigned *)0, cfile); + if (!parse_if_statement (&(*result) -> data.ie.fc, + cfile, lose)) { + if (!*lose) + parse_warn (cfile, + "expecting conditional."); + executable_statement_dereference (result, MDL); + *lose = 1; + return 0; + } + } else + (*result) -> data.ie.fc = (struct executable_statement *)0; + + return 1; +} + +/* + * boolean_expression :== CHECK STRING | + * NOT boolean-expression | + * data-expression EQUAL data-expression | + * data-expression BANG EQUAL data-expression | + * boolean-expression AND boolean-expression | + * boolean-expression OR boolean-expression + * EXISTS OPTION-NAME + */ + +int parse_boolean_expression (expr, cfile, lose) + struct expression **expr; + struct parse *cfile; + int *lose; +{ + /* Parse an expression... */ + if (!parse_expression (expr, cfile, lose, context_boolean, + (struct expression **)0, expr_none)) + return 0; + + if (!is_boolean_expression (*expr) && + (*expr) -> op != expr_variable_reference && + (*expr) -> op != expr_funcall) { + parse_warn (cfile, "Expecting a boolean expression."); + *lose = 1; + expression_dereference (expr, MDL); + return 0; + } + return 1; +} + +/* + * data_expression :== SUBSTRING LPAREN data-expression COMMA + * numeric-expression COMMA + * numeric-expression RPAREN | + * CONCAT LPAREN data-expression COMMA + data-expression RPAREN + * SUFFIX LPAREN data_expression COMMA + * numeric-expression RPAREN | + * OPTION option_name | + * HARDWARE | + * PACKET LPAREN numeric-expression COMMA + * numeric-expression RPAREN | + * STRING | + * colon_seperated_hex_list + */ + +int parse_data_expression (expr, cfile, lose) + struct expression **expr; + struct parse *cfile; + int *lose; +{ + /* Parse an expression... */ + if (!parse_expression (expr, cfile, lose, context_data, + (struct expression **)0, expr_none)) + return 0; + + if (!is_data_expression (*expr) && + (*expr) -> op != expr_variable_reference && + (*expr) -> op != expr_funcall) { + parse_warn (cfile, "Expecting a data expression."); + *lose = 1; + return 0; + } + return 1; +} + +/* + * numeric-expression :== EXTRACT_INT LPAREN data-expression + * COMMA number RPAREN | + * NUMBER + */ + +int parse_numeric_expression (expr, cfile, lose) + struct expression **expr; + struct parse *cfile; + int *lose; +{ + /* Parse an expression... */ + if (!parse_expression (expr, cfile, lose, context_numeric, + (struct expression **)0, expr_none)) + return 0; + + if (!is_numeric_expression (*expr) && + (*expr) -> op != expr_variable_reference && + (*expr) -> op != expr_funcall) { + parse_warn (cfile, "Expecting a numeric expression."); + *lose = 1; + return 0; + } + return 1; +} + +/* + * dns-expression :== + * UPDATE LPAREN ns-class COMMA ns-type COMMA data-expression COMMA + * data-expression COMMA numeric-expression RPAREN + * DELETE LPAREN ns-class COMMA ns-type COMMA data-expression COMMA + * data-expression RPAREN + * EXISTS LPAREN ns-class COMMA ns-type COMMA data-expression COMMA + * data-expression RPAREN + * NOT EXISTS LPAREN ns-class COMMA ns-type COMMA data-expression COMMA + * data-expression RPAREN + * ns-class :== IN | CHAOS | HS | NUMBER + * ns-type :== A | PTR | MX | TXT | NUMBER + */ + +int parse_dns_expression (expr, cfile, lose) + struct expression **expr; + struct parse *cfile; + int *lose; +{ + /* Parse an expression... */ + if (!parse_expression (expr, cfile, lose, context_dns, + (struct expression **)0, expr_none)) + return 0; + + if (!is_dns_expression (*expr) && + (*expr) -> op != expr_variable_reference && + (*expr) -> op != expr_funcall) { + parse_warn (cfile, "Expecting a dns update subexpression."); + *lose = 1; + return 0; + } + return 1; +} + +/* Parse a subexpression that does not contain a binary operator. */ + +int parse_non_binary (expr, cfile, lose, context) + struct expression **expr; + struct parse *cfile; + int *lose; + enum expression_context context; +{ + enum dhcp_token token; + const char *val; + struct collection *col; + struct option *option; + struct expression *nexp, **ep; + int known; + enum expr_op opcode; + const char *s; + char *cptr; + struct executable_statement *stmt; + int i; + unsigned long u; + isc_result_t status, code; + unsigned len; + + token = peek_token (&val, (unsigned *)0, cfile); + + /* Check for unary operators... */ + switch (token) { + case CHECK: + token = next_token (&val, (unsigned *)0, cfile); + token = next_token (&val, (unsigned *)0, cfile); + if (token != STRING) { + parse_warn (cfile, "string expected."); + skip_to_semi (cfile); + *lose = 1; + return 0; + } + for (col = collections; col; col = col -> next) + if (!strcmp (col -> name, val)) + break; + if (!col) { + parse_warn (cfile, "unknown collection."); + *lose = 1; + return 0; + } + if (!expression_allocate (expr, MDL)) + log_fatal ("can't allocate expression"); + (*expr) -> op = expr_check; + (*expr) -> data.check = col; + break; + + case TOKEN_NOT: + token = next_token (&val, (unsigned *)0, cfile); + if (context == context_dns) { + token = peek_token (&val, (unsigned *)0, cfile); + goto not_exists; + } + if (!expression_allocate (expr, MDL)) + log_fatal ("can't allocate expression"); + (*expr) -> op = expr_not; + if (!parse_non_binary (&(*expr) -> data.not, + cfile, lose, context_boolean)) { + if (!*lose) { + parse_warn (cfile, "expression expected"); + skip_to_semi (cfile); + } + *lose = 1; + expression_dereference (expr, MDL); + return 0; + } + if (!is_boolean_expression ((*expr) -> data.not)) { + *lose = 1; + parse_warn (cfile, "boolean expression expected"); + skip_to_semi (cfile); + expression_dereference (expr, MDL); + return 0; + } + break; + + case LPAREN: + token = next_token (&val, (unsigned *)0, cfile); + if (!parse_expression (expr, cfile, lose, context, + (struct expression **)0, expr_none)) { + if (!*lose) { + parse_warn (cfile, "expression expected"); + skip_to_semi (cfile); + } + *lose = 1; + return 0; + } + token = next_token (&val, (unsigned *)0, cfile); + if (token != RPAREN) { + *lose = 1; + parse_warn (cfile, "right paren expected"); + skip_to_semi (cfile); + return 0; + } + break; + + case EXISTS: + if (context == context_dns) + goto ns_exists; + token = next_token (&val, (unsigned *)0, cfile); + if (!expression_allocate (expr, MDL)) + log_fatal ("can't allocate expression"); + (*expr) -> op = expr_exists; + known = 0; + (*expr) -> data.option = parse_option_name (cfile, 0, &known); + if (!(*expr) -> data.option) { + *lose = 1; + expression_dereference (expr, MDL); + return 0; + } + break; + + case STATIC: + token = next_token (&val, (unsigned *)0, cfile); + if (!expression_allocate (expr, MDL)) + log_fatal ("can't allocate expression"); + (*expr) -> op = expr_static; + break; + + case KNOWN: + token = next_token (&val, (unsigned *)0, cfile); + if (!expression_allocate (expr, MDL)) + log_fatal ("can't allocate expression"); + (*expr) -> op = expr_known; + break; + + case SUBSTRING: + token = next_token (&val, (unsigned *)0, cfile); + if (!expression_allocate (expr, MDL)) + log_fatal ("can't allocate expression"); + (*expr) -> op = expr_substring; + + token = next_token (&val, (unsigned *)0, cfile); + if (token != LPAREN) { + nolparen: + expression_dereference (expr, MDL); + parse_warn (cfile, "left parenthesis expected."); + *lose = 1; + return 0; + } + + if (!parse_data_expression (&(*expr) -> data.substring.expr, + cfile, lose)) { + nodata: + expression_dereference (expr, MDL); + if (!*lose) { + parse_warn (cfile, + "expecting data expression."); + skip_to_semi (cfile); + *lose = 1; + } + return 0; + } + + token = next_token (&val, (unsigned *)0, cfile); + if (token != COMMA) { + nocomma: + expression_dereference (expr, MDL); + parse_warn (cfile, "comma expected."); + *lose = 1; + + return 0; + } + + if (!parse_numeric_expression + (&(*expr) -> data.substring.offset,cfile, lose)) { + nonum: + if (!*lose) { + parse_warn (cfile, + "expecting numeric expression."); + skip_to_semi (cfile); + *lose = 1; + } + expression_dereference (expr, MDL); + return 0; + } + + token = next_token (&val, (unsigned *)0, cfile); + if (token != COMMA) + goto nocomma; + + if (!parse_numeric_expression + (&(*expr) -> data.substring.len, cfile, lose)) + goto nonum; + + token = next_token (&val, (unsigned *)0, cfile); + if (token != RPAREN) { + norparen: + parse_warn (cfile, "right parenthesis expected."); + *lose = 1; + expression_dereference (expr, MDL); + return 0; + } + break; + + case SUFFIX: + token = next_token (&val, (unsigned *)0, cfile); + if (!expression_allocate (expr, MDL)) + log_fatal ("can't allocate expression"); + (*expr) -> op = expr_suffix; + + token = next_token (&val, (unsigned *)0, cfile); + if (token != LPAREN) + goto nolparen; + + if (!parse_data_expression (&(*expr) -> data.suffix.expr, + cfile, lose)) + goto nodata; + + token = next_token (&val, (unsigned *)0, cfile); + if (token != COMMA) + goto nocomma; + + if (!parse_numeric_expression (&(*expr) -> data.suffix.len, + cfile, lose)) + goto nonum; + + token = next_token (&val, (unsigned *)0, cfile); + if (token != RPAREN) + goto norparen; + break; + + case CONCAT: + token = next_token (&val, (unsigned *)0, cfile); + if (!expression_allocate (expr, MDL)) + log_fatal ("can't allocate expression"); + (*expr) -> op = expr_concat; + + token = next_token (&val, (unsigned *)0, cfile); + if (token != LPAREN) + goto nolparen; + + if (!parse_data_expression (&(*expr) -> data.concat [0], + cfile, lose)) + goto nodata; + + token = next_token (&val, (unsigned *)0, cfile); + if (token != COMMA) + goto nocomma; + + concat_another: + if (!parse_data_expression (&(*expr) -> data.concat [1], + cfile, lose)) + goto nodata; + + token = next_token (&val, (unsigned *)0, cfile); + + if (token == COMMA) { + nexp = (struct expression *)0; + if (!expression_allocate (&nexp, MDL)) + log_fatal ("can't allocate at CONCAT2"); + nexp -> op = expr_concat; + expression_reference (&nexp -> data.concat [0], + *expr, MDL); + expression_dereference (expr, MDL); + expression_reference (expr, nexp, MDL); + expression_dereference (&nexp, MDL); + goto concat_another; + } + + if (token != RPAREN) + goto norparen; + break; + + case BINARY_TO_ASCII: + token = next_token (&val, (unsigned *)0, cfile); + if (!expression_allocate (expr, MDL)) + log_fatal ("can't allocate expression"); + (*expr) -> op = expr_binary_to_ascii; + + token = next_token (&val, (unsigned *)0, cfile); + if (token != LPAREN) + goto nolparen; + + if (!parse_numeric_expression (&(*expr) -> data.b2a.base, + cfile, lose)) + goto nodata; + + token = next_token (&val, (unsigned *)0, cfile); + if (token != COMMA) + goto nocomma; + + if (!parse_numeric_expression (&(*expr) -> data.b2a.width, + cfile, lose)) + goto nodata; + + token = next_token (&val, (unsigned *)0, cfile); + if (token != COMMA) + goto nocomma; + + if (!parse_data_expression (&(*expr) -> data.b2a.seperator, + cfile, lose)) + goto nodata; + + token = next_token (&val, (unsigned *)0, cfile); + if (token != COMMA) + goto nocomma; + + if (!parse_data_expression (&(*expr) -> data.b2a.buffer, + cfile, lose)) + goto nodata; + + token = next_token (&val, (unsigned *)0, cfile); + if (token != RPAREN) + goto norparen; + break; + + case REVERSE: + token = next_token (&val, (unsigned *)0, cfile); + if (!expression_allocate (expr, MDL)) + log_fatal ("can't allocate expression"); + (*expr) -> op = expr_reverse; + + token = next_token (&val, (unsigned *)0, cfile); + if (token != LPAREN) + goto nolparen; + + if (!(parse_numeric_expression + (&(*expr) -> data.reverse.width, cfile, lose))) + goto nodata; + + token = next_token (&val, (unsigned *)0, cfile); + if (token != COMMA) + goto nocomma; + + if (!(parse_data_expression + (&(*expr) -> data.reverse.buffer, cfile, lose))) + goto nodata; + + token = next_token (&val, (unsigned *)0, cfile); + if (token != RPAREN) + goto norparen; + break; + + case PICK: + /* pick (a, b, c) actually produces an internal representation + that looks like pick (a, pick (b, pick (c, nil))). */ + token = next_token (&val, (unsigned *)0, cfile); + if (!(expression_allocate (expr, MDL))) + log_fatal ("can't allocate expression"); + + token = next_token (&val, (unsigned *)0, cfile); + if (token != LPAREN) + goto nolparen; + + nexp = (struct expression *)0; + expression_reference (&nexp, *expr, MDL); + do { + nexp -> op = expr_pick_first_value; + if (!(parse_data_expression + (&nexp -> data.pick_first_value.car, + cfile, lose))) + goto nodata; + + token = next_token (&val, (unsigned *)0, cfile); + if (token == COMMA) { + struct expression *foo = (struct expression *)0; + if (!expression_allocate (&foo, MDL)) + log_fatal ("can't allocate expr"); + expression_reference + (&nexp -> data.pick_first_value.cdr, foo, MDL); + expression_dereference (&nexp, MDL); + expression_reference (&nexp, foo, MDL); + expression_dereference (&foo, MDL); + } + } while (token == COMMA); + expression_dereference (&nexp, MDL); + + if (token != RPAREN) + goto norparen; + break; + + /* dns-update and dns-delete are present for historical + purposes, but are deprecated in favor of ns-update + in combination with update, delete, exists and not + exists. */ + case DNS_UPDATE: + case DNS_DELETE: +#if !defined (NSUPDATE) + parse_warn (cfile, + "Please rebuild dhcpd with --with-nsupdate."); +#endif + token = next_token (&val, (unsigned *)0, cfile); + if (token == DNS_UPDATE) + opcode = expr_ns_add; + else + opcode = expr_ns_delete; + + token = next_token (&val, (unsigned *)0, cfile); + if (token != LPAREN) + goto nolparen; + + token = next_token (&val, (unsigned *)0, cfile); + if (token != STRING) { + parse_warn (cfile, + "parse_expression: expecting string."); + badnsupdate: + skip_to_semi (cfile); + *lose = 1; + return 0; + } + + if (!strcasecmp (val, "a")) + u = T_A; + else if (!strcasecmp (val, "ptr")) + u = T_PTR; + else if (!strcasecmp (val, "mx")) + u = T_MX; + else if (!strcasecmp (val, "cname")) + u = T_CNAME; + else if (!strcasecmp (val, "TXT")) + u = T_TXT; + else { + parse_warn (cfile, "unexpected rrtype: %s", val); + goto badnsupdate; + } + + s = (opcode == expr_ns_add + ? "old-dns-update" + : "old-dns-delete"); + cptr = dmalloc (strlen (s) + 1, MDL); + if (!cptr) + log_fatal ("can't allocate name for %s", s); + strcpy (cptr, s); + if (!expression_allocate (expr, MDL)) + log_fatal ("can't allocate expression"); + (*expr) -> op = expr_funcall; + (*expr) -> data.funcall.name = cptr; + + /* Fake up a function call. */ + ep = &(*expr) -> data.funcall.arglist; + if (!expression_allocate (ep, MDL)) + log_fatal ("can't allocate expression"); + (*ep) -> op = expr_arg; + if (!make_const_int (&(*ep) -> data.arg.val, u)) + log_fatal ("can't allocate rrtype value."); + + token = next_token (&val, (unsigned *)0, cfile); + if (token != COMMA) + goto nocomma; + ep = &((*ep) -> data.arg.next); + if (!expression_allocate (ep, MDL)) + log_fatal ("can't allocate expression"); + (*ep) -> op = expr_arg; + if (!(parse_data_expression (&(*ep) -> data.arg.val, + cfile, lose))) + goto nodata; + + token = next_token (&val, (unsigned *)0, cfile); + if (token != COMMA) + goto nocomma; + + ep = &((*ep) -> data.arg.next); + if (!expression_allocate (ep, MDL)) + log_fatal ("can't allocate expression"); + (*ep) -> op = expr_arg; + if (!(parse_data_expression (&(*ep) -> data.arg.val, + cfile, lose))) + goto nodata; + + if (opcode == expr_ns_add) { + token = next_token (&val, (unsigned *)0, cfile); + if (token != COMMA) + goto nocomma; + + ep = &((*ep) -> data.arg.next); + if (!expression_allocate (ep, MDL)) + log_fatal ("can't allocate expression"); + (*ep) -> op = expr_arg; + if (!(parse_numeric_expression (&(*ep) -> data.arg.val, + cfile, lose))) { + parse_warn (cfile, + "expecting numeric expression."); + goto badnsupdate; + } + } + + token = next_token (&val, (unsigned *)0, cfile); + if (token != RPAREN) + goto norparen; + break; + + case NS_UPDATE: +#if !defined (NSUPDATE) + parse_warn (cfile, + "Please rebuild dhcpd with --with-nsupdate."); +#endif + token = next_token (&val, (unsigned *)0, cfile); + if (!expression_allocate (expr, MDL)) + log_fatal ("can't allocate expression"); + + token = next_token (&val, (unsigned *)0, cfile); + if (token != LPAREN) + goto nolparen; + + nexp = *expr; + do { + nexp -> op = expr_dns_transaction; + if (!(parse_dns_expression + (&nexp -> data.dns_transaction.car, + cfile, lose))) + { + if (!*lose) + parse_warn + (cfile, + "expecting dns expression."); + badnstrans: + expression_dereference (expr, MDL); + *lose = 1; + return 0; + } + + token = next_token (&val, (unsigned *)0, cfile); + + if (token == COMMA) { + if (!(expression_allocate + (&nexp -> data.dns_transaction.cdr, + MDL))) + log_fatal + ("can't allocate expression"); + nexp = nexp -> data.dns_transaction.cdr; + } + } while (token == COMMA); + + if (token != RPAREN) + goto norparen; + break; + + /* NOT EXISTS is special cased above... */ + not_exists: + token = peek_token (&val, (unsigned *)0, cfile); + if (token != EXISTS) { + parse_warn (cfile, "expecting DNS prerequisite."); + *lose = 1; + return 0; + } + opcode = expr_ns_not_exists; + goto nsupdatecode; + case TOKEN_ADD: + opcode = expr_ns_add; + goto nsupdatecode; + case TOKEN_DELETE: + opcode = expr_ns_delete; + goto nsupdatecode; + ns_exists: + opcode = expr_ns_exists; + nsupdatecode: + token = next_token (&val, (unsigned *)0, cfile); + +#if !defined (NSUPDATE) + parse_warn (cfile, + "Please rebuild dhcpd with --with-nsupdate."); +#endif + if (!expression_allocate (expr, MDL)) + log_fatal ("can't allocate expression"); + (*expr) -> op = opcode; + + token = next_token (&val, (unsigned *)0, cfile); + if (token != LPAREN) + goto nolparen; + + token = next_token (&val, (unsigned *)0, cfile); + if (!is_identifier (token) && token != NUMBER) { + parse_warn (cfile, "expecting identifier or number."); + badnsop: + expression_dereference (expr, MDL); + skip_to_semi (cfile); + *lose = 1; + return 0; + } + + if (token == NUMBER) + (*expr) -> data.ns_add.rrclass = atoi (val); + else if (!strcasecmp (val, "in")) + (*expr) -> data.ns_add.rrclass = C_IN; + else if (!strcasecmp (val, "chaos")) + (*expr) -> data.ns_add.rrclass = C_CHAOS; + else if (!strcasecmp (val, "hs")) + (*expr) -> data.ns_add.rrclass = C_HS; + else { + parse_warn (cfile, "unexpected rrclass: %s", val); + goto badnsop; + } + + token = next_token (&val, (unsigned *)0, cfile); + if (token != COMMA) + goto nocomma; + + token = next_token (&val, (unsigned *)0, cfile); + if (!is_identifier (token) && token != NUMBER) { + parse_warn (cfile, "expecting identifier or number."); + goto badnsop; + } + + if (token == NUMBER) + (*expr) -> data.ns_add.rrtype = atoi (val); + else if (!strcasecmp (val, "a")) + (*expr) -> data.ns_add.rrtype = T_A; + else if (!strcasecmp (val, "ptr")) + (*expr) -> data.ns_add.rrtype = T_PTR; + else if (!strcasecmp (val, "mx")) + (*expr) -> data.ns_add.rrtype = T_MX; + else if (!strcasecmp (val, "cname")) + (*expr) -> data.ns_add.rrtype = T_CNAME; + else if (!strcasecmp (val, "TXT")) + (*expr) -> data.ns_add.rrtype = T_TXT; + else { + parse_warn (cfile, "unexpected rrtype: %s", val); + goto badnsop; + } + + token = next_token (&val, (unsigned *)0, cfile); + if (token != COMMA) + goto nocomma; + + if (!(parse_data_expression + (&(*expr) -> data.ns_add.rrname, cfile, lose))) + goto nodata; + + token = next_token (&val, (unsigned *)0, cfile); + if (token != COMMA) + goto nocomma; + + if (!(parse_data_expression + (&(*expr) -> data.ns_add.rrdata, cfile, lose))) + goto nodata; + + if (opcode == expr_ns_add) { + token = next_token (&val, (unsigned *)0, cfile); + if (token != COMMA) + goto nocomma; + + if (!(parse_numeric_expression + (&(*expr) -> data.ns_add.ttl, cfile, + lose))) { + if (!*lose) + parse_warn (cfile, + "expecting numeric expression."); + goto badnsupdate; + } + } + + token = next_token (&val, (unsigned *)0, cfile); + if (token != RPAREN) + goto norparen; + break; + + case OPTION: + case CONFIG_OPTION: + if (!expression_allocate (expr, MDL)) + log_fatal ("can't allocate expression"); + (*expr) -> op = (token == OPTION + ? expr_option + : expr_config_option); + token = next_token (&val, (unsigned *)0, cfile); + known = 0; + (*expr) -> data.option = parse_option_name (cfile, 0, &known); + if (!(*expr) -> data.option) { + *lose = 1; + expression_dereference (expr, MDL); + return 0; + } + break; + + case HARDWARE: + token = next_token (&val, (unsigned *)0, cfile); + if (!expression_allocate (expr, MDL)) + log_fatal ("can't allocate expression"); + (*expr) -> op = expr_hardware; + break; + + case LEASED_ADDRESS: + token = next_token (&val, (unsigned *)0, cfile); + if (!expression_allocate (expr, MDL)) + log_fatal ("can't allocate expression"); + (*expr) -> op = expr_leased_address; + break; + + case CLIENT_STATE: + token = next_token (&val, (unsigned *)0, cfile); + if (!expression_allocate (expr, MDL)) + log_fatal ("can't allocate expression"); + (*expr) -> op = expr_client_state; + break; + + case FILENAME: + token = next_token (&val, (unsigned *)0, cfile); + if (!expression_allocate (expr, MDL)) + log_fatal ("can't allocate expression"); + (*expr) -> op = expr_filename; + break; + + case SERVER_NAME: + token = next_token (&val, (unsigned *)0, cfile); + if (!expression_allocate (expr, MDL)) + log_fatal ("can't allocate expression"); + (*expr) -> op = expr_sname; + break; + + case LEASE_TIME: + token = next_token (&val, (unsigned *)0, cfile); + if (!expression_allocate (expr, MDL)) + log_fatal ("can't allocate expression"); + (*expr) -> op = expr_lease_time; + break; + + case TOKEN_NULL: + token = next_token (&val, (unsigned *)0, cfile); + if (!expression_allocate (expr, MDL)) + log_fatal ("can't allocate expression"); + (*expr) -> op = expr_null; + break; + + case HOST_DECL_NAME: + token = next_token (&val, (unsigned *)0, cfile); + if (!expression_allocate (expr, MDL)) + log_fatal ("can't allocate expression"); + (*expr) -> op = expr_host_decl_name; + break; + + case UPDATED_DNS_RR: + token = next_token (&val, (unsigned *)0, cfile); + + token = next_token (&val, (unsigned *)0, cfile); + if (token != LPAREN) + goto nolparen; + + token = next_token (&val, (unsigned *)0, cfile); + if (token != STRING) { + parse_warn (cfile, "expecting string."); + bad_rrtype: + *lose = 1; + return 0; + } + if (!strcasecmp (val, "a")) + s = "ddns-fwd-name"; + else if (!strcasecmp (val, "ptr")) + s = "ddns-rev-name"; + else { + parse_warn (cfile, "invalid DNS rrtype: %s", val); + goto bad_rrtype; + } + + token = next_token (&val, (unsigned *)0, cfile); + if (token != RPAREN) + goto norparen; + + if (!expression_allocate (expr, MDL)) + log_fatal ("can't allocate expression"); + (*expr) -> op = expr_variable_reference; + (*expr) -> data.variable = + dmalloc (strlen (s) + 1, MDL); + if (!(*expr) -> data.variable) + log_fatal ("can't allocate variable name."); + strcpy ((*expr) -> data.variable, s); + break; + + case PACKET: + token = next_token (&val, (unsigned *)0, cfile); + if (!expression_allocate (expr, MDL)) + log_fatal ("can't allocate expression"); + (*expr) -> op = expr_packet; + + token = next_token (&val, (unsigned *)0, cfile); + if (token != LPAREN) + goto nolparen; + + if (!parse_numeric_expression (&(*expr) -> data.packet.offset, + cfile, lose)) + goto nonum; + + token = next_token (&val, (unsigned *)0, cfile); + if (token != COMMA) + goto nocomma; + + if (!parse_numeric_expression (&(*expr) -> data.packet.len, + cfile, lose)) + goto nonum; + + token = next_token (&val, (unsigned *)0, cfile); + if (token != RPAREN) + goto norparen; + break; + + case STRING: + token = next_token (&val, &len, cfile); + if (!make_const_data (expr, (const unsigned char *)val, + len, 1, 1, MDL)) + log_fatal ("can't make constant string expression."); + break; + + case EXTRACT_INT: + token = next_token (&val, (unsigned *)0, cfile); + token = next_token (&val, (unsigned *)0, cfile); + if (token != LPAREN) { + parse_warn (cfile, "left parenthesis expected."); + *lose = 1; + return 0; + } + + if (!expression_allocate (expr, MDL)) + log_fatal ("can't allocate expression"); + + if (!parse_data_expression (&(*expr) -> data.extract_int, + cfile, lose)) { + if (!*lose) { + parse_warn (cfile, + "expecting data expression."); + skip_to_semi (cfile); + *lose = 1; + } + expression_dereference (expr, MDL); + return 0; + } + + token = next_token (&val, (unsigned *)0, cfile); + if (token != COMMA) { + parse_warn (cfile, "comma expected."); + *lose = 1; + expression_dereference (expr, MDL); + return 0; + } + + token = next_token (&val, (unsigned *)0, cfile); + if (token != NUMBER) { + parse_warn (cfile, "number expected."); + *lose = 1; + expression_dereference (expr, MDL); + return 0; + } + switch (atoi (val)) { + case 8: + (*expr) -> op = expr_extract_int8; + break; + + case 16: + (*expr) -> op = expr_extract_int16; + break; + + case 32: + (*expr) -> op = expr_extract_int32; + break; + + default: + parse_warn (cfile, + "unsupported integer size %d", atoi (val)); + *lose = 1; + skip_to_semi (cfile); + expression_dereference (expr, MDL); + return 0; + } + + token = next_token (&val, (unsigned *)0, cfile); + if (token != RPAREN) { + parse_warn (cfile, "right parenthesis expected."); + *lose = 1; + expression_dereference (expr, MDL); + return 0; + } + break; + + case ENCODE_INT: + token = next_token (&val, (unsigned *)0, cfile); + token = next_token (&val, (unsigned *)0, cfile); + if (token != LPAREN) { + parse_warn (cfile, "left parenthesis expected."); + *lose = 1; + return 0; + } + + if (!expression_allocate (expr, MDL)) + log_fatal ("can't allocate expression"); + + if (!parse_numeric_expression (&(*expr) -> data.encode_int, + cfile, lose)) { + parse_warn (cfile, "expecting numeric expression."); + skip_to_semi (cfile); + *lose = 1; + expression_dereference (expr, MDL); + return 0; + } + + token = next_token (&val, (unsigned *)0, cfile); + if (token != COMMA) { + parse_warn (cfile, "comma expected."); + *lose = 1; + expression_dereference (expr, MDL); + return 0; + } + + token = next_token (&val, (unsigned *)0, cfile); + if (token != NUMBER) { + parse_warn (cfile, "number expected."); + *lose = 1; + expression_dereference (expr, MDL); + return 0; + } + switch (atoi (val)) { + case 8: + (*expr) -> op = expr_encode_int8; + break; + + case 16: + (*expr) -> op = expr_encode_int16; + break; + + case 32: + (*expr) -> op = expr_encode_int32; + break; + + default: + parse_warn (cfile, + "unsupported integer size %d", atoi (val)); + *lose = 1; + skip_to_semi (cfile); + expression_dereference (expr, MDL); + return 0; + } + + token = next_token (&val, (unsigned *)0, cfile); + if (token != RPAREN) { + parse_warn (cfile, "right parenthesis expected."); + *lose = 1; + expression_dereference (expr, MDL); + return 0; + } + break; + + case NUMBER: + /* If we're in a numeric context, this should just be a + number, by itself. */ + if (context == context_numeric || + context == context_data_or_numeric) { + next_token (&val, (unsigned *)0, cfile); + if (!expression_allocate (expr, MDL)) + log_fatal ("can't allocate expression"); + (*expr) -> op = expr_const_int; + (*expr) -> data.const_int = atoi (val); + break; + } + + case NUMBER_OR_NAME: + if (!expression_allocate (expr, MDL)) + log_fatal ("can't allocate expression"); + + (*expr) -> op = expr_const_data; + if (!parse_cshl (&(*expr) -> data.const_data, cfile)) { + expression_dereference (expr, MDL); + return 0; + } + break; + + case NS_FORMERR: + known = FORMERR; + goto ns_const; + ns_const: + token = next_token (&val, (unsigned *)0, cfile); + if (!expression_allocate (expr, MDL)) + log_fatal ("can't allocate expression"); + (*expr) -> op = expr_const_int; + (*expr) -> data.const_int = known; + break; + + case NS_NOERROR: + known = ISC_R_SUCCESS; + goto ns_const; + + case NS_NOTAUTH: + known = ISC_R_NOTAUTH; + goto ns_const; + + case NS_NOTIMP: + known = ISC_R_NOTIMPLEMENTED; + goto ns_const; + + case NS_NOTZONE: + known = ISC_R_NOTZONE; + goto ns_const; + + case NS_NXDOMAIN: + known = ISC_R_NXDOMAIN; + goto ns_const; + + case NS_NXRRSET: + known = ISC_R_NXRRSET; + goto ns_const; + + case NS_REFUSED: + known = ISC_R_REFUSED; + goto ns_const; + + case NS_SERVFAIL: + known = ISC_R_SERVFAIL; + goto ns_const; + + case NS_YXDOMAIN: + known = ISC_R_YXDOMAIN; + goto ns_const; + + case NS_YXRRSET: + known = ISC_R_YXRRSET; + goto ns_const; + + case BOOTING: + known = S_INIT; + goto ns_const; + + case REBOOT: + known = S_REBOOTING; + goto ns_const; + + case SELECT: + known = S_SELECTING; + goto ns_const; + + case REQUEST: + known = S_REQUESTING; + goto ns_const; + + case BOUND: + known = S_BOUND; + goto ns_const; + + case RENEW: + known = S_RENEWING; + goto ns_const; + + case REBIND: + known = S_REBINDING; + goto ns_const; + + case DEFINED: + token = next_token (&val, (unsigned *)0, cfile); + token = next_token (&val, (unsigned *)0, cfile); + if (token != LPAREN) + goto nolparen; + + token = next_token (&val, (unsigned *)0, cfile); + if (token != NAME && token != NUMBER_OR_NAME) { + parse_warn (cfile, "%s can't be a variable name", val); + skip_to_semi (cfile); + *lose = 1; + return 0; + } + + if (!expression_allocate (expr, MDL)) + log_fatal ("can't allocate expression"); + (*expr) -> op = expr_variable_exists; + (*expr) -> data.variable = dmalloc (strlen (val) + 1, MDL); + if (!(*expr)->data.variable) + log_fatal ("can't allocate variable name"); + strcpy ((*expr) -> data.variable, val); + token = next_token (&val, (unsigned *)0, cfile); + if (token != RPAREN) + goto norparen; + break; + + /* Not a valid start to an expression... */ + default: + if (token != NAME && token != NUMBER_OR_NAME) + return 0; + + token = next_token (&val, (unsigned *)0, cfile); + + /* Save the name of the variable being referenced. */ + cptr = dmalloc (strlen (val) + 1, MDL); + if (!cptr) + log_fatal ("can't allocate variable name"); + strcpy (cptr, val); + + /* Simple variable reference, as far as we can tell. */ + token = peek_token (&val, (unsigned *)0, cfile); + if (token != LPAREN) { + if (!expression_allocate (expr, MDL)) + log_fatal ("can't allocate expression"); + (*expr) -> op = expr_variable_reference; + (*expr) -> data.variable = cptr; + break; + } + + token = next_token (&val, (unsigned *)0, cfile); + if (!expression_allocate (expr, MDL)) + log_fatal ("can't allocate expression"); + (*expr) -> op = expr_funcall; + (*expr) -> data.funcall.name = cptr; + + /* Now parse the argument list. */ + ep = &(*expr) -> data.funcall.arglist; + do { + if (!expression_allocate (ep, MDL)) + log_fatal ("can't allocate expression"); + (*ep) -> op = expr_arg; + if (!parse_expression (&(*ep) -> data.arg.val, + cfile, lose, context_any, + (struct expression **)0, + expr_none)) { + if (!*lose) { + parse_warn (cfile, + "expecting expression."); + *lose = 1; + } + skip_to_semi (cfile); + expression_dereference (expr, MDL); + return 0; + } + ep = &((*ep) -> data.arg.next); + token = next_token (&val, (unsigned *)0, cfile); + } while (token == COMMA); + if (token != RPAREN) { + parse_warn (cfile, "Right parenthesis expected."); + skip_to_semi (cfile); + *lose = 1; + expression_dereference (expr, MDL); + return 0; + } + break; + } + return 1; +} + +/* Parse an expression. */ + +int parse_expression (expr, cfile, lose, context, plhs, binop) + struct expression **expr; + struct parse *cfile; + int *lose; + enum expression_context context; + struct expression **plhs; + enum expr_op binop; +{ + enum dhcp_token token; + const char *val; + struct expression *rhs = (struct expression *)0, *tmp; + struct expression *lhs = (struct expression *)0; + enum expr_op next_op; + enum expression_context + lhs_context = context_any, + rhs_context = context_any; + + /* Consume the left hand side we were passed. */ + if (plhs) { + expression_reference (&lhs, *plhs, MDL); + expression_dereference (plhs, MDL); + } + + new_rhs: + if (!parse_non_binary (&rhs, cfile, lose, context)) { + /* If we already have a left-hand side, then it's not + okay for there not to be a right-hand side here, so + we need to flag it as an error. */ + if (lhs) { + if (!*lose) { + parse_warn (cfile, + "expecting right-hand side."); + *lose = 1; + skip_to_semi (cfile); + } + expression_dereference (&lhs, MDL); + } + return 0; + } + + /* At this point, rhs contains either an entire subexpression, + or at least a left-hand-side. If we do not see a binary token + as the next token, we're done with the expression. */ + + token = peek_token (&val, (unsigned *)0, cfile); + switch (token) { + case BANG: + token = next_token (&val, (unsigned *)0, cfile); + token = peek_token (&val, (unsigned *)0, cfile); + if (token != EQUAL) { + parse_warn (cfile, "! in boolean context without ="); + *lose = 1; + skip_to_semi (cfile); + if (lhs) + expression_dereference (&lhs, MDL); + return 0; + } + next_op = expr_not_equal; + context = expression_context (rhs); + break; + + case EQUAL: + next_op = expr_equal; + context = expression_context (rhs); + break; + + case AND: + next_op = expr_and; + context = expression_context (rhs); + if (context != context_boolean) { + needbool: + parse_warn (cfile, "expecting boolean expressions"); + skip_to_semi (cfile); + expression_dereference (&rhs, MDL); + *lose = 1; + return 0; + } + break; + + case OR: + next_op = expr_or; + context = expression_context (rhs); + if (context != context_boolean) + goto needbool; + break; + + case PLUS: + next_op = expr_add; + context = expression_context (rhs); + if (context != context_numeric) { + neednum: + parse_warn (cfile, "expecting numeric expressions"); + skip_to_semi (cfile); + expression_dereference (&rhs, MDL); + *lose = 1; + return 0; + } + break; + + case MINUS: + next_op = expr_subtract; + context = expression_context (rhs); + if (context != context_numeric) + goto neednum; + break; + + case SLASH: + next_op = expr_divide; + context = expression_context (rhs); + if (context != context_numeric) + goto neednum; + break; + + case ASTERISK: + next_op = expr_multiply; + context = expression_context (rhs); + if (context != context_numeric) + goto neednum; + break; + + case PERCENT: + next_op = expr_remainder; + context = expression_context (rhs); + if (context != context_numeric) + goto neednum; + break; + + case AMPERSAND: + next_op = expr_binary_and; + context = expression_context (rhs); + if (context != context_numeric) + goto neednum; + break; + + case PIPE: + next_op = expr_binary_or; + context = expression_context (rhs); + if (context != context_numeric) + goto neednum; + break; + + case CARET: + next_op = expr_binary_xor; + context = expression_context (rhs); + if (context != context_numeric) + goto neednum; + break; + + default: + next_op = expr_none; + } + + /* If we have no lhs yet, we just parsed it. */ + if (!lhs) { + /* If there was no operator following what we just parsed, + then we're done - return it. */ + if (next_op == expr_none) { + *expr = rhs; + return 1; + } + lhs = rhs; + rhs = (struct expression *)0; + binop = next_op; + next_token (&val, (unsigned *)0, cfile); + goto new_rhs; + } + + /* Now, if we didn't find a binary operator, we're done parsing + this subexpression, so combine it with the preceding binary + operator and return the result. */ + if (next_op == expr_none) { + if (!expression_allocate (expr, MDL)) + log_fatal ("Can't allocate expression!"); + + (*expr) -> op = binop; + /* All the binary operators' data union members + are the same, so we'll cheat and use the member + for the equals operator. */ + (*expr) -> data.equal [0] = lhs; + (*expr) -> data.equal [1] = rhs; + return 1; + } + + /* Eat the operator token - we now know it was a binary operator... */ + token = next_token (&val, (unsigned *)0, cfile); + + /* If the binary operator we saw previously has a lower precedence + than the next operator, then the rhs we just parsed for that + operator is actually the lhs of the operator with the higher + precedence - to get the real rhs, we need to recurse on the + new operator. */ + if (binop != expr_none && + op_precedence (binop, next_op) < 0) { + tmp = rhs; + rhs = (struct expression *)0; + if (!parse_expression (&rhs, cfile, lose, op_context (next_op), + &tmp, next_op)) { + if (!*lose) { + parse_warn (cfile, + "expecting a subexpression"); + *lose = 1; + } + return 0; + } + next_op = expr_none; + } + + /* Now combine the LHS and the RHS using binop. */ + tmp = (struct expression *)0; + if (!expression_allocate (&tmp, MDL)) + log_fatal ("No memory for equal precedence combination."); + + /* Store the LHS and RHS. */ + tmp -> data.equal [0] = lhs; + tmp -> data.equal [1] = rhs; + tmp -> op = binop; + + lhs = tmp; + tmp = (struct expression *)0; + rhs = (struct expression *)0; + + /* Recursions don't return until we have parsed the end of the + expression, so if we recursed earlier, we can now return what + we got. */ + if (next_op == expr_none) { + *expr = lhs; + return 1; + } + + binop = next_op; + goto new_rhs; +} + +/* option-statement :== identifier DOT identifier <syntax> SEMI + | identifier <syntax> SEMI + + Option syntax is handled specially through format strings, so it + would be painful to come up with BNF for it. However, it always + starts as above and ends in a SEMI. */ + +int parse_option_statement (result, cfile, lookups, option, op) + struct executable_statement **result; + struct parse *cfile; + int lookups; + struct option *option; + enum statement_op op; +{ + const char *val; + enum dhcp_token token; + const char *fmt = NULL; + struct expression *expr = (struct expression *)0; + struct expression *tmp; + int lose; + struct executable_statement *stmt; + int ftt = 1; + + token = peek_token (&val, (unsigned *)0, cfile); + if (token == SEMI) { + /* Eat the semicolon... */ + token = next_token (&val, (unsigned *)0, cfile); + goto done; + } + + if (token == EQUAL) { + /* Eat the equals sign. */ + token = next_token (&val, (unsigned *)0, cfile); + + /* Parse a data expression and use its value for the data. */ + if (!parse_data_expression (&expr, cfile, &lose)) { + /* In this context, we must have an executable + statement, so if we found something else, it's + still an error. */ + if (!lose) { + parse_warn (cfile, + "expecting a data expression."); + skip_to_semi (cfile); + } + return 0; + } + + /* We got a valid expression, so use it. */ + goto done; + } + + /* Parse the option data... */ + do { + /* Set a flag if this is an array of a simple type (i.e., + not an array of pairs of IP addresses, or something + like that. */ + int uniform = option -> format [1] == 'A'; + + and_again: + /* Set fmt to start of format for 'A' and one char back + for 'a' */ + if ((fmt != NULL) && + (fmt != option -> format) && (*fmt == 'a')) + fmt -= 1; + else + fmt = ((fmt == NULL) || + (*fmt == 'A')) ? option -> format : fmt; + + /* 'a' means always uniform */ + uniform |= (fmt [1] == 'a'); + + for ( ; *fmt; fmt++) { + if ((*fmt == 'A') || (*fmt == 'a')) + break; + if (*fmt == 'o') + continue; + tmp = expr; + expr = (struct expression *)0; + if (!parse_option_token (&expr, cfile, &fmt, + tmp, uniform, lookups)) { + if (fmt [1] != 'o') { + if (tmp) + expression_dereference (&tmp, + MDL); + return 0; + } + expr = tmp; + tmp = (struct expression *)0; + } + if (tmp) + expression_dereference (&tmp, MDL); + } + if ((*fmt == 'A') || (*fmt == 'a')) { + token = peek_token (&val, (unsigned *)0, cfile); + /* Comma means: continue with next element in array */ + if (token == COMMA) { + token = next_token (&val, + (unsigned *)0, cfile); + continue; + } + /* no comma: end of array. + 'A' or end of string means: leave the loop */ + if ((*fmt == 'A') || (fmt[1] == '\0')) + break; + /* 'a' means: go on with next char */ + if (*fmt == 'a') { + fmt++; + goto and_again; + } + } + } while ((*fmt == 'A') || (*fmt == 'a')); + + done: + if (!parse_semi (cfile)) + return 0; + if (!executable_statement_allocate (result, MDL)) + log_fatal ("no memory for option statement."); + (*result) -> op = op; + if (expr && !option_cache (&(*result) -> data.option, + (struct data_string *)0, expr, option, MDL)) + log_fatal ("no memory for option cache"); + if (expr) + expression_dereference (&expr, MDL); + return 1; +} + +int parse_option_token (rv, cfile, fmt, expr, uniform, lookups) + struct expression **rv; + struct parse *cfile; + const char **fmt; + struct expression *expr; + int uniform; + int lookups; +{ + const char *val; + enum dhcp_token token; + struct expression *t = (struct expression *)0; + unsigned char buf [4]; + unsigned len; + unsigned char *ob; + struct iaddr addr; + int num; + const char *f, *g; + struct enumeration_value *e; + + switch (**fmt) { + case 'U': + token = peek_token (&val, (unsigned *)0, cfile); + if (!is_identifier (token)) { + if ((*fmt) [1] != 'o') { + parse_warn (cfile, "expecting identifier."); + skip_to_semi (cfile); + } + return 0; + } + token = next_token (&val, &len, cfile); + if (!make_const_data (&t, (const unsigned char *)val, + len, 1, 1, MDL)) + log_fatal ("No memory for %s", val); + break; + + case 'E': + g = strchr (*fmt, '.'); + if (!g) { + parse_warn (cfile, + "malformed encapsulation format (bug!)"); + skip_to_semi (cfile); + return 0; + } + *fmt = g; + case 'X': + token = peek_token (&val, (unsigned *)0, cfile); + if (token == NUMBER_OR_NAME || token == NUMBER) { + if (!expression_allocate (&t, MDL)) + return 0; + if (!parse_cshl (&t -> data.const_data, cfile)) { + expression_dereference (&t, MDL); + return 0; + } + t -> op = expr_const_data; + } else if (token == STRING) { + token = next_token (&val, &len, cfile); + if (!make_const_data (&t, (const unsigned char *)val, + len, 1, 1, MDL)) + log_fatal ("No memory for \"%s\"", val); + } else { + if ((*fmt) [1] != 'o') { + parse_warn (cfile, "expecting string %s.", + "or hexadecimal data"); + skip_to_semi (cfile); + } + return 0; + } + break; + + case 'd': /* Domain name... */ + val = parse_host_name (cfile); + if (!val) { + parse_warn (cfile, "not a valid domain name."); + skip_to_semi (cfile); + return 0; + } + len = strlen (val); + goto make_string; + + case 't': /* Text string... */ + token = peek_token (&val, (unsigned *)0, cfile); + if (token != STRING && !is_identifier (token)) { + if ((*fmt) [1] != 'o') { + parse_warn (cfile, "expecting string."); + if (token != SEMI) + skip_to_semi (cfile); + } + return 0; + } + token = next_token (&val, &len, cfile); + make_string: + if (!make_const_data (&t, (const unsigned char *)val, + len, 1, 1, MDL)) + log_fatal ("No memory for concatenation"); + break; + + case 'N': + f = (*fmt) + 1; + g = strchr (*fmt, '.'); + if (!g) { + parse_warn (cfile, "malformed %s (bug!)", + "enumeration format"); + foo: + skip_to_semi (cfile); + return 0; + } + *fmt = g; + token = next_token (&val, (unsigned *)0, cfile); + if (!is_identifier (token)) { + parse_warn (cfile, + "identifier expected"); + goto foo; + } + e = find_enumeration_value (f, (*fmt) - f, val); + if (!e) { + parse_warn (cfile, "unknown value"); + goto foo; + } + if (!make_const_data (&t, &e -> value, 1, 0, 1, MDL)) + return 0; + break; + + case 'I': /* IP address or hostname. */ + if (lookups) { + if (!parse_ip_addr_or_hostname (&t, cfile, uniform)) + return 0; + } else { + if (!parse_ip_addr (cfile, &addr)) + return 0; + if (!make_const_data (&t, addr.iabuf, addr.len, + 0, 1, MDL)) + return 0; + } + break; + + case 'T': /* Lease interval. */ + token = peek_token (&val, (unsigned *)0, cfile); + if (token != INFINITE) + goto check_number; + token = next_token (&val, (unsigned *)0, cfile); + putLong (buf, -1); + if (!make_const_data (&t, buf, 4, 0, 1, MDL)) + return 0; + break; + + case 'L': /* Unsigned 32-bit integer... */ + case 'l': /* Signed 32-bit integer... */ + token = peek_token (&val, (unsigned *)0, cfile); + check_number: + if (token != NUMBER) { + need_number: + if ((*fmt) [1] != 'o') { + parse_warn (cfile, "expecting number."); + if (token != SEMI) + skip_to_semi (cfile); + } + return 0; + } + token = next_token (&val, (unsigned *)0, cfile); + convert_num (cfile, buf, val, 0, 32); + if (!make_const_data (&t, buf, 4, 0, 1, MDL)) + return 0; + break; + + case 's': /* Signed 16-bit integer. */ + case 'S': /* Unsigned 16-bit integer. */ + token = peek_token (&val, (unsigned *)0, cfile); + if (token != NUMBER) + goto need_number; + token = next_token (&val, (unsigned *)0, cfile); + convert_num (cfile, buf, val, 0, 16); + if (!make_const_data (&t, buf, 2, 0, 1, MDL)) + return 0; + break; + + case 'b': /* Signed 8-bit integer. */ + case 'B': /* Unsigned 8-bit integer. */ + token = peek_token (&val, (unsigned *)0, cfile); + if (token != NUMBER) + goto need_number; + token = next_token (&val, (unsigned *)0, cfile); + convert_num (cfile, buf, val, 0, 8); + if (!make_const_data (&t, buf, 1, 0, 1, MDL)) + return 0; + break; + + case 'f': /* Boolean flag. */ + token = peek_token (&val, (unsigned *)0, cfile); + if (!is_identifier (token)) { + if ((*fmt) [1] != 'o') + parse_warn (cfile, "expecting identifier."); + bad_flag: + if ((*fmt) [1] != 'o') { + if (token != SEMI) + skip_to_semi (cfile); + } + return 0; + } + if (!strcasecmp (val, "true") + || !strcasecmp (val, "on")) + buf [0] = 1; + else if (!strcasecmp (val, "false") + || !strcasecmp (val, "off")) + buf [0] = 0; + else if (!strcasecmp (val, "ignore")) + buf [0] = 2; + else { + if ((*fmt) [1] != 'o') + parse_warn (cfile, "expecting boolean."); + goto bad_flag; + } + token = next_token (&val, (unsigned *)0, cfile); + if (!make_const_data (&t, buf, 1, 0, 1, MDL)) + return 0; + break; + + default: + parse_warn (cfile, "Bad format %c in parse_option_token.", + **fmt); + skip_to_semi (cfile); + return 0; + } + if (expr) { + if (!make_concat (rv, expr, t)) + return 0; + } else + expression_reference (rv, t, MDL); + expression_dereference (&t, MDL); + return 1; +} + +int parse_option_decl (oc, cfile) + struct option_cache **oc; + struct parse *cfile; +{ + const char *val; + int token; + u_int8_t buf [4]; + u_int8_t hunkbuf [1024]; + unsigned hunkix = 0; + const char *fmt, *f; + struct option *option; + struct iaddr ip_addr; + u_int8_t *dp; + unsigned len; + int nul_term = 0; + struct buffer *bp; + int known = 0; + struct enumeration_value *e; + + option = parse_option_name (cfile, 0, &known); + if (!option) + return 0; + + /* Parse the option data... */ + do { + /* Set a flag if this is an array of a simple type (i.e., + not an array of pairs of IP addresses, or something + like that. */ + int uniform = option -> format [1] == 'A'; + + for (fmt = option -> format; *fmt; fmt++) { + if (*fmt == 'A') + break; + switch (*fmt) { + case 'E': + fmt = strchr (fmt, '.'); + if (!fmt) { + parse_warn (cfile, + "malformed %s (bug!)", + "encapsulation format"); + skip_to_semi (cfile); + return 0; + } + case 'X': + len = parse_X (cfile, &hunkbuf [hunkix], + sizeof hunkbuf - hunkix); + hunkix += len; + break; + + case 't': /* Text string... */ + token = next_token (&val, + &len, cfile); + if (token != STRING) { + parse_warn (cfile, + "expecting string."); + skip_to_semi (cfile); + return 0; + } + if (hunkix + len + 1 > sizeof hunkbuf) { + parse_warn (cfile, + "option data buffer %s", + "overflow"); + skip_to_semi (cfile); + return 0; + } + memcpy (&hunkbuf [hunkix], val, len + 1); + nul_term = 1; + hunkix += len; + break; + + case 'N': + f = fmt; + fmt = strchr (fmt, '.'); + if (!fmt) { + parse_warn (cfile, + "malformed %s (bug!)", + "enumeration format"); + foo: + skip_to_semi (cfile); + return 0; + } + token = next_token (&val, + (unsigned *)0, cfile); + if (!is_identifier (token)) { + parse_warn (cfile, + "identifier expected"); + goto foo; + } + e = find_enumeration_value (f, fmt - f, val); + if (!e) { + parse_warn (cfile, + "unknown value"); + goto foo; + } + len = 1; + dp = &e -> value; + goto alloc; + + case 'I': /* IP address. */ + if (!parse_ip_addr (cfile, &ip_addr)) + return 0; + len = ip_addr.len; + dp = ip_addr.iabuf; + + alloc: + if (hunkix + len > sizeof hunkbuf) { + parse_warn (cfile, + "option data buffer %s", + "overflow"); + skip_to_semi (cfile); + return 0; + } + memcpy (&hunkbuf [hunkix], dp, len); + hunkix += len; + break; + + case 'L': /* Unsigned 32-bit integer... */ + case 'l': /* Signed 32-bit integer... */ + token = next_token (&val, + (unsigned *)0, cfile); + if (token != NUMBER) { + need_number: + parse_warn (cfile, + "expecting number."); + if (token != SEMI) + skip_to_semi (cfile); + return 0; + } + convert_num (cfile, buf, val, 0, 32); + len = 4; + dp = buf; + goto alloc; + + case 's': /* Signed 16-bit integer. */ + case 'S': /* Unsigned 16-bit integer. */ + token = next_token (&val, + (unsigned *)0, cfile); + if (token != NUMBER) + goto need_number; + convert_num (cfile, buf, val, 0, 16); + len = 2; + dp = buf; + goto alloc; + + case 'b': /* Signed 8-bit integer. */ + case 'B': /* Unsigned 8-bit integer. */ + token = next_token (&val, + (unsigned *)0, cfile); + if (token != NUMBER) + goto need_number; + convert_num (cfile, buf, val, 0, 8); + len = 1; + dp = buf; + goto alloc; + + case 'f': /* Boolean flag. */ + token = next_token (&val, + (unsigned *)0, cfile); + if (!is_identifier (token)) { + parse_warn (cfile, + "expecting identifier."); + bad_flag: + if (token != SEMI) + skip_to_semi (cfile); + return 0; + } + if (!strcasecmp (val, "true") + || !strcasecmp (val, "on")) + buf [0] = 1; + else if (!strcasecmp (val, "false") + || !strcasecmp (val, "off")) + buf [0] = 0; + else { + parse_warn (cfile, + "expecting boolean."); + goto bad_flag; + } + len = 1; + dp = buf; + goto alloc; + + default: + log_error ("parse_option_param: Bad format %c", + *fmt); + skip_to_semi (cfile); + return 0; + } + } + token = next_token (&val, (unsigned *)0, cfile); + } while (*fmt == 'A' && token == COMMA); + + if (token != SEMI) { + parse_warn (cfile, "semicolon expected."); + skip_to_semi (cfile); + return 0; + } + + bp = (struct buffer *)0; + if (!buffer_allocate (&bp, hunkix + nul_term, MDL)) + log_fatal ("no memory to store option declaration."); + if (!bp -> data) + log_fatal ("out of memory allocating option data."); + memcpy (bp -> data, hunkbuf, hunkix + nul_term); + + if (!option_cache_allocate (oc, MDL)) + log_fatal ("out of memory allocating option cache."); + + (*oc) -> data.buffer = bp; + (*oc) -> data.data = &bp -> data [0]; + (*oc) -> data.terminated = nul_term; + (*oc) -> data.len = hunkix; + (*oc) -> option = option; + return 1; +} + +/* Consider merging parse_cshl into this. */ + +int parse_X (cfile, buf, max) + struct parse *cfile; + u_int8_t *buf; + unsigned max; +{ + int token; + const char *val; + unsigned len; + u_int8_t *s; + + token = peek_token (&val, (unsigned *)0, cfile); + if (token == NUMBER_OR_NAME || token == NUMBER) { + len = 0; + do { + token = next_token (&val, (unsigned *)0, cfile); + if (token != NUMBER && token != NUMBER_OR_NAME) { + parse_warn (cfile, + "expecting hexadecimal constant."); + skip_to_semi (cfile); + return 0; + } + convert_num (cfile, &buf [len], val, 16, 8); + if (len++ > max) { + parse_warn (cfile, + "hexadecimal constant too long."); + skip_to_semi (cfile); + return 0; + } + token = peek_token (&val, (unsigned *)0, cfile); + if (token == COLON) + token = next_token (&val, + (unsigned *)0, cfile); + } while (token == COLON); + val = (char *)buf; + } else if (token == STRING) { + token = next_token (&val, &len, cfile); + if (len + 1 > max) { + parse_warn (cfile, "string constant too long."); + skip_to_semi (cfile); + return 0; + } + memcpy (buf, val, len + 1); + } else { + parse_warn (cfile, "expecting string or hexadecimal data"); + skip_to_semi (cfile); + return 0; + } + return len; +} + +int parse_warn (struct parse *cfile, const char *fmt, ...) +{ + va_list list; + char lexbuf [256]; + char mbuf [1024]; + char fbuf [1024]; + unsigned i, lix; + + do_percentm (mbuf, fmt); +#ifndef NO_SNPRINTF + snprintf (fbuf, sizeof fbuf, "%s line %d: %s", + cfile -> tlname, cfile -> lexline, mbuf); +#else + sprintf (fbuf, "%s line %d: %s", + cfile -> tlname, cfile -> lexline, mbuf); +#endif + + va_start (list, fmt); + vsnprintf (mbuf, sizeof mbuf, fbuf, list); + va_end (list); + + lix = 0; + for (i = 0; + cfile -> token_line [i] && i < (cfile -> lexchar - 1); i++) { + if (lix < (sizeof lexbuf) - 1) + lexbuf [lix++] = ' '; + if (cfile -> token_line [i] == '\t') { + for (lix; + lix < (sizeof lexbuf) - 1 && (lix & 7); lix++) + lexbuf [lix] = ' '; + } + } + lexbuf [lix] = 0; + +#ifndef DEBUG + syslog (log_priority | LOG_ERR, "%s", mbuf); + syslog (log_priority | LOG_ERR, "%s", cfile -> token_line); + if (cfile -> lexchar < 81) + syslog (log_priority | LOG_ERR, "%s^", lexbuf); +#endif + + if (log_perror) { + write (2, mbuf, strlen (mbuf)); + write (2, "\n", 1); + write (2, cfile -> token_line, strlen (cfile -> token_line)); + write (2, "\n", 1); + if (cfile -> lexchar < 81) + write (2, lexbuf, lix); + write (2, "^\n", 2); + } + + cfile -> warnings_occurred = 1; + + return 0; +} diff --git a/contrib/isc-dhcp/common/print.c b/contrib/isc-dhcp/common/print.c index d05af8d..67e8ddd 100644 --- a/contrib/isc-dhcp/common/print.c +++ b/contrib/isc-dhcp/common/print.c @@ -3,7 +3,7 @@ Turn data structures into printable text. */ /* - * Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium. + * Copyright (c) 1995-2001 Internet Software Consortium. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,19 +34,146 @@ * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium - * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie - * Enterprises. To learn more about the Internet Software Consortium, - * see ``http://www.vix.com/isc''. To learn more about Vixie - * Enterprises, see ``http://www.vix.com''. + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. */ #ifndef lint static char copyright[] = -"$Id: print.c,v 1.16.2.3 1999/02/13 19:19:03 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium. All rights reserved.\n"; +"$Id: print.c,v 1.53.2.4 2001/08/08 14:49:20 mellon Exp $ Copyright (c) 1995-2001 The Internet Software Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" +char *quotify_string (const char *s, const char *file, int line) +{ + unsigned len = 0; + const char *sp; + char *buf, *nsp; + + for (sp = s; sp && *sp; sp++) { + if (*sp == ' ') + len++; + else if (!isascii (*sp) || !isprint (*sp)) + len += 4; + else if (*sp == '"' || *sp == '\\') + len += 2; + else + len++; + } + + buf = dmalloc (len + 1, file, line); + if (buf) { + nsp = buf; + for (sp = s; sp && *sp; sp++) { + if (*sp == ' ') + *nsp++ = ' '; + else if (!isascii (*sp) || !isprint (*sp)) { + sprintf (nsp, "\\%03o", + *(const unsigned char *)sp); + nsp += 4; + } else if (*sp == '"' || *sp == '\\') { + *nsp++ = '\\'; + *nsp++ = *sp; + } else + *nsp++ = *sp; + } + *nsp++ = 0; + } + return buf; +} + +char *quotify_buf (const unsigned char *s, unsigned len, + const char *file, int line) +{ + unsigned nulen = 0; + char *buf, *nsp; + int i; + + for (i = 0; i < len; i++) { + if (s [i] == ' ') + nulen++; + else if (!isascii (s [i]) || !isprint (s [i])) + nulen += 4; + else if (s [i] == '"' || s [i] == '\\') + nulen += 2; + else + nulen++; + } + + buf = dmalloc (nulen + 1, MDL); + if (buf) { + nsp = buf; + for (i = 0; i < len; i++) { + if (s [i] == ' ') + *nsp++ = ' '; + else if (!isascii (s [i]) || !isprint (s [i])) { + sprintf (nsp, "\\%03o", s [i]); + nsp += 4; + } else if (s [i] == '"' || s [i] == '\\') { + *nsp++ = '\\'; + *nsp++ = s [i]; + } else + *nsp++ = s [i]; + } + *nsp++ = 0; + } + return buf; +} + +char *print_base64 (const unsigned char *buf, unsigned len, + const char *file, int line) +{ + char *s, *b; + unsigned bl; + int i; + unsigned val, extra; + static char to64 [] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + bl = ((len * 4 + 2) / 3) + 1; + b = dmalloc (bl + 1, file, line); + if (!b) + return (char *)0; + + i = 0; + s = b; + while (i != len) { + val = buf [i++]; + extra = val & 3; + val = val >> 2; + *s++ = to64 [val]; + if (i == len) { + *s++ = to64 [extra << 4]; + *s++ = '='; + break; + } + val = (extra << 8) + buf [i++]; + extra = val & 15; + val = val >> 4; + *s++ = to64 [val]; + if (i == len) { + *s++ = to64 [extra << 2]; + *s++ = '='; + break; + } + val = (extra << 8) + buf [i++]; + extra = val & 0x3f; + val = val >> 6; + *s++ = to64 [val]; + *s++ = to64 [extra]; + } + if (!len) + *s++ = '='; + *s++ = 0; + if (s > b + bl + 1) + abort (); + return b; +} + char *print_hw_addr (htype, hlen, data) int htype; int hlen; @@ -56,9 +183,9 @@ char *print_hw_addr (htype, hlen, data) char *s; int i; - if (htype == 0 || hlen == 0) { - strcpy (habuf, "<null>"); - } else { + if (hlen <= 0) + habuf [0] = 0; + else { s = habuf; for (i = 0; i < hlen; i++) { sprintf (s, "%02x", data [i]); @@ -76,70 +203,102 @@ void print_lease (lease) struct tm *t; char tbuf [32]; - debug (" Lease %s", + log_debug (" Lease %s", piaddr (lease -> ip_addr)); t = gmtime (&lease -> starts); strftime (tbuf, sizeof tbuf, "%Y/%m/%d %H:%M:%S", t); - debug (" start %s", tbuf); + log_debug (" start %s", tbuf); t = gmtime (&lease -> ends); strftime (tbuf, sizeof tbuf, "%Y/%m/%d %H:%M:%S", t); - debug (" end %s", tbuf); - - t = gmtime (&lease -> timestamp); - strftime (tbuf, sizeof tbuf, "%Y/%m/%d %H:%M:%S", t); - debug (" stamp %s", tbuf); + log_debug (" end %s", tbuf); - debug (" hardware addr = %s", - print_hw_addr (lease -> hardware_addr.htype, - lease -> hardware_addr.hlen, - lease -> hardware_addr.haddr)); - debug (" host %s ", + if (lease -> hardware_addr.hlen) + log_debug (" hardware addr = %s", + print_hw_addr (lease -> hardware_addr.hbuf [0], + lease -> hardware_addr.hlen - 1, + &lease -> hardware_addr.hbuf [1])); + log_debug (" host %s ", lease -> host ? lease -> host -> name : "<none>"); } +#if defined (DEBUG) +void dump_packet_option (struct option_cache *oc, + struct packet *packet, + struct lease *lease, + struct client_state *client, + struct option_state *in_options, + struct option_state *cfg_options, + struct binding_scope **scope, + struct universe *u, void *foo) +{ + const char *name, *dot; + struct data_string ds; + memset (&ds, 0, sizeof ds); + + if (u != &dhcp_universe) { + name = u -> name; + dot = "."; + } else { + name = ""; + dot = ""; + } + if (evaluate_option_cache (&ds, packet, lease, client, + in_options, cfg_options, scope, oc, MDL)) { + log_debug (" option %s%s%s %s;\n", + name, dot, oc -> option -> name, + pretty_print_option (oc -> option, + ds.data, ds.len, 1, 1)); + data_string_forget (&ds, MDL); + } +} + void dump_packet (tp) struct packet *tp; { struct dhcp_packet *tdp = tp -> raw; - debug ("packet length %d", tp -> packet_length); - debug ("op = %d htype = %d hlen = %d hops = %d", + log_debug ("packet length %d", tp -> packet_length); + log_debug ("op = %d htype = %d hlen = %d hops = %d", tdp -> op, tdp -> htype, tdp -> hlen, tdp -> hops); - debug ("xid = %x secs = %d flags = %x", - tdp -> xid, tdp -> secs, tdp -> flags); - debug ("ciaddr = %s", inet_ntoa (tdp -> ciaddr)); - debug ("yiaddr = %s", inet_ntoa (tdp -> yiaddr)); - debug ("siaddr = %s", inet_ntoa (tdp -> siaddr)); - debug ("giaddr = %s", inet_ntoa (tdp -> giaddr)); - debug ("chaddr = %02.2x:%02.2x:%02.2x:%02.2x:%02.2x:%02.2x", + log_debug ("xid = %x secs = %ld flags = %x", + tdp -> xid, (unsigned long)tdp -> secs, tdp -> flags); + log_debug ("ciaddr = %s", inet_ntoa (tdp -> ciaddr)); + log_debug ("yiaddr = %s", inet_ntoa (tdp -> yiaddr)); + log_debug ("siaddr = %s", inet_ntoa (tdp -> siaddr)); + log_debug ("giaddr = %s", inet_ntoa (tdp -> giaddr)); + log_debug ("chaddr = %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", ((unsigned char *)(tdp -> chaddr)) [0], ((unsigned char *)(tdp -> chaddr)) [1], ((unsigned char *)(tdp -> chaddr)) [2], ((unsigned char *)(tdp -> chaddr)) [3], ((unsigned char *)(tdp -> chaddr)) [4], ((unsigned char *)(tdp -> chaddr)) [5]); - debug ("filename = %s", tdp -> file); - debug ("server_name = %s", tdp -> sname); + log_debug ("filename = %s", tdp -> file); + log_debug ("server_name = %s", tdp -> sname); if (tp -> options_valid) { int i; - for (i = 0; i < 256; i++) { - if (tp -> options [i].data) - debug (" %s = %s", - dhcp_options [i].name, - pretty_print_option - (i, tp -> options [i].data, - tp -> options [i].len, 1, 1)); + for (i = 0; i < tp -> options -> universe_count; i++) { + if (tp -> options -> universes [i]) { + option_space_foreach (tp, (struct lease *)0, + (struct client_state *)0, + (struct option_state *)0, + tp -> options, + &global_scope, + universes [i], 0, + dump_packet_option); + } } } - debug (""); + log_debug ("%s", ""); } +#endif void dump_raw (buf, len) - unsigned char *buf; - int len; + const unsigned char *buf; + unsigned len; { int i; char lbuf [80]; @@ -150,7 +309,7 @@ void dump_raw (buf, len) for (i = 0; i < len; i++) { if ((i & 15) == 0) { if (lbix) - note (lbuf); + log_info (lbuf); sprintf (lbuf, "%03x:", i); lbix = 4; } else if ((i & 7) == 0) @@ -158,7 +317,7 @@ void dump_raw (buf, len) sprintf (&lbuf [lbix], " %02x", buf [i]); lbix += 3; } - note (lbuf); + log_info (lbuf); } void hash_dump (table) @@ -173,12 +332,1042 @@ void hash_dump (table) for (i = 0; i < table -> hash_count; i++) { if (!table -> buckets [i]) continue; - note ("hash bucket %d:", i); + log_info ("hash bucket %d:", i); for (bp = table -> buckets [i]; bp; bp = bp -> next) { if (bp -> len) dump_raw (bp -> name, bp -> len); else - note ((char *)bp -> name); + log_info ((const char *)bp -> name); + } + } +} + +#define HBLEN 60 + +#define DECLARE_HEX_PRINTER(x) \ +char *print_hex##x (len, data, limit) \ + unsigned len; \ + const u_int8_t *data; \ + unsigned limit; \ +{ \ + \ + static char hex_buf##x [HBLEN + 1]; \ + unsigned i; \ + \ + if (limit > HBLEN) \ + limit = HBLEN; \ + \ + for (i = 0; i < (limit - 2) && i < len; i++) { \ + if (!isascii (data [i]) || !isprint (data [i])) { \ + for (i = 0; i < limit / 3 && i < len; i++) { \ + sprintf (&hex_buf##x [i * 3], \ + "%02x:", data [i]); \ + } \ + hex_buf##x [i * 3 - 1] = 0; \ + return hex_buf##x; \ + } \ + } \ + hex_buf##x [0] = '"'; \ + i = len; \ + if (i > limit - 2) \ + i = limit - 2; \ + memcpy (&hex_buf##x [1], data, i); \ + hex_buf##x [i + 1] = '"'; \ + hex_buf##x [i + 2] = 0; \ + return hex_buf##x; \ +} + +DECLARE_HEX_PRINTER (_1) +DECLARE_HEX_PRINTER (_2) +DECLARE_HEX_PRINTER (_3) + +#define DQLEN 80 + +char *print_dotted_quads (len, data) + unsigned len; + const u_int8_t *data; +{ + static char dq_buf [DQLEN + 1]; + int i; + char *s, *last; + + s = &dq_buf [0]; + last = s; + + i = 0; + + do { + sprintf (s, "%d.%d.%d.%d, ", + data [i], data [i + 1], data [i + 2], data [i + 3]); + s += strlen (s); + i += 4; + } while ((s - &dq_buf [0] > DQLEN - 21) && + i + 3 < len); + if (i == len) + s [-2] = 0; + else + strcpy (s, "..."); + return dq_buf; +} + +char *print_dec_1 (val) + unsigned long val; +{ + static char vbuf [32]; + sprintf (vbuf, "%lu", val); + return vbuf; +} + +char *print_dec_2 (val) + unsigned long val; +{ + static char vbuf [32]; + sprintf (vbuf, "%lu", val); + return vbuf; +} + +static unsigned print_subexpression PROTO ((struct expression *, + char *, unsigned)); + +static unsigned print_subexpression (expr, buf, len) + struct expression *expr; + char *buf; + unsigned len; +{ + unsigned rv, left; + const char *s; + + switch (expr -> op) { + case expr_none: + if (len > 3) { + strcpy (buf, "nil"); + return 3; + } + break; + + case expr_match: + if (len > 7) { + strcpy (buf, "(match)"); + return 7; + } + break; + + case expr_check: + rv = 10 + strlen (expr -> data.check -> name); + if (len > rv) { + sprintf (buf, "(check %s)", + expr -> data.check -> name); + return rv; + } + break; + + case expr_equal: + if (len > 6) { + rv = 4; + strcpy (buf, "(eq "); + rv += print_subexpression (expr -> data.equal [0], + buf + rv, len - rv - 2); + buf [rv++] = ' '; + rv += print_subexpression (expr -> data.equal [1], + buf + rv, len - rv - 1); + buf [rv++] = ')'; + buf [rv] = 0; + return rv; + } + break; + + case expr_not_equal: + if (len > 7) { + rv = 5; + strcpy (buf, "(neq "); + rv += print_subexpression (expr -> data.equal [0], + buf + rv, len - rv - 2); + buf [rv++] = ' '; + rv += print_subexpression (expr -> data.equal [1], + buf + rv, len - rv - 1); + buf [rv++] = ')'; + buf [rv] = 0; + return rv; + } + break; + + case expr_substring: + if (len > 11) { + rv = 8; + strcpy (buf, "(substr "); + rv += print_subexpression (expr -> data.substring.expr, + buf + rv, len - rv - 3); + buf [rv++] = ' '; + rv += print_subexpression + (expr -> data.substring.offset, + buf + rv, len - rv - 2); + buf [rv++] = ' '; + rv += print_subexpression (expr -> data.substring.len, + buf + rv, len - rv - 1); + buf [rv++] = ')'; + buf [rv] = 0; + return rv; + } + break; + + case expr_suffix: + if (len > 10) { + rv = 8; + strcpy (buf, "(suffix "); + rv += print_subexpression (expr -> data.suffix.expr, + buf + rv, len - rv - 2); + if (len > rv) + buf [rv++] = ' '; + rv += print_subexpression (expr -> data.suffix.len, + buf + rv, len - rv - 1); + if (len > rv) + buf [rv++] = ')'; + buf [rv] = 0; + return rv; + } + break; + + case expr_concat: + if (len > 10) { + rv = 8; + strcpy (buf, "(concat "); + rv += print_subexpression (expr -> data.concat [0], + buf + rv, len - rv - 2); + buf [rv++] = ' '; + rv += print_subexpression (expr -> data.concat [1], + buf + rv, len - rv - 1); + buf [rv++] = ')'; + buf [rv] = 0; + return rv; + } + break; + + case expr_pick_first_value: + if (len > 8) { + rv = 6; + strcpy (buf, "(pick1st "); + rv += print_subexpression + (expr -> data.pick_first_value.car, + buf + rv, len - rv - 2); + buf [rv++] = ' '; + rv += print_subexpression + (expr -> data.pick_first_value.cdr, + buf + rv, len - rv - 1); + buf [rv++] = ')'; + buf [rv] = 0; + return rv; + } + break; + + case expr_host_lookup: + rv = 15 + strlen (expr -> data.host_lookup -> hostname); + if (len > rv) { + sprintf (buf, "(dns-lookup %s)", + expr -> data.host_lookup -> hostname); + return rv; + } + break; + + case expr_and: + s = "and"; + binop: + rv = strlen (s); + if (len > rv + 4) { + buf [0] = '('; + strcpy (&buf [1], s); + rv += 1; + buf [rv++] = ' '; + rv += print_subexpression (expr -> data.and [0], + buf + rv, len - rv - 2); + buf [rv++] = ' '; + rv += print_subexpression (expr -> data.and [1], + buf + rv, len - rv - 1); + buf [rv++] = ')'; + buf [rv] = 0; + return rv; + } + break; + + case expr_or: + s = "or"; + goto binop; + + case expr_add: + s = "+"; + goto binop; + + case expr_subtract: + s = "-"; + goto binop; + + case expr_multiply: + s = "*"; + goto binop; + + case expr_divide: + s = "/"; + goto binop; + + case expr_remainder: + s = "%"; + goto binop; + + case expr_binary_and: + s = "&"; + goto binop; + + case expr_binary_or: + s = "|"; + goto binop; + + case expr_binary_xor: + s = "^"; + goto binop; + + case expr_not: + if (len > 6) { + rv = 5; + strcpy (buf, "(not "); + rv += print_subexpression (expr -> data.not, + buf + rv, len - rv - 1); + buf [rv++] = ')'; + buf [rv] = 0; + return rv; + } + break; + + case expr_config_option: + s = "cfg-option"; + goto dooption; + + case expr_option: + s = "option"; + dooption: + rv = strlen (s) + 2 + (strlen (expr -> data.option -> name) + + strlen (expr -> data.option -> universe -> name)); + if (len > rv) { + sprintf (buf, "(option %s.%s)", + expr -> data.option -> universe -> name, + expr -> data.option -> name); + return rv; + } + break; + + case expr_hardware: + if (len > 10) { + strcpy (buf, "(hardware)"); + return 10; + } + break; + + case expr_packet: + if (len > 10) { + rv = 8; + strcpy (buf, "(substr "); + rv += print_subexpression (expr -> data.packet.offset, + buf + rv, len - rv - 2); + buf [rv++] = ' '; + rv += print_subexpression (expr -> data.packet.len, + buf + rv, len - rv - 1); + buf [rv++] = ')'; + buf [rv] = 0; + return rv; + } + break; + + case expr_const_data: + s = print_hex_1 (expr -> data.const_data.len, + expr -> data.const_data.data, len); + rv = strlen (s); + if (rv >= len) + rv = len - 1; + strncpy (buf, s, rv); + buf [rv] = 0; + return rv; + + case expr_encapsulate: + rv = 13; + strcpy (buf, "(encapsulate "); + rv += expr -> data.encapsulate.len; + if (rv + 2 > len) + rv = len - 2; + strncpy (buf, + (const char *)expr -> data.encapsulate.data, rv - 13); + buf [rv++] = ')'; + buf [rv++] = 0; + break; + + case expr_extract_int8: + if (len > 7) { + rv = 6; + strcpy (buf, "(int8 "); + rv += print_subexpression (expr -> data.extract_int, + buf + rv, len - rv - 1); + buf [rv++] = ')'; + buf [rv] = 0; + return rv; + } + break; + + case expr_extract_int16: + if (len > 8) { + rv = 7; + strcpy (buf, "(int16 "); + rv += print_subexpression (expr -> data.extract_int, + buf + rv, len - rv - 1); + buf [rv++] = ')'; + buf [rv] = 0; + return rv; + } + break; + + case expr_extract_int32: + if (len > 8) { + rv = 7; + strcpy (buf, "(int32 "); + rv += print_subexpression (expr -> data.extract_int, + buf + rv, len - rv - 1); + buf [rv++] = ')'; + buf [rv] = 0; + return rv; + } + break; + + case expr_encode_int8: + if (len > 7) { + rv = 6; + strcpy (buf, "(to-int8 "); + rv += print_subexpression (expr -> data.encode_int, + buf + rv, len - rv - 1); + buf [rv++] = ')'; + buf [rv] = 0; + return rv; + } + break; + + case expr_encode_int16: + if (len > 8) { + rv = 7; + strcpy (buf, "(to-int16 "); + rv += print_subexpression (expr -> data.encode_int, + buf + rv, len - rv - 1); + buf [rv++] = ')'; + buf [rv] = 0; + return rv; + } + break; + + case expr_encode_int32: + if (len > 8) { + rv = 7; + strcpy (buf, "(to-int32 "); + rv += print_subexpression (expr -> data.encode_int, + buf + rv, len - rv - 1); + buf [rv++] = ')'; + buf [rv] = 0; + return rv; } + break; + + case expr_const_int: + s = print_dec_1 (expr -> data.const_int); + rv = strlen (s); + if (len > rv) { + strcpy (buf, s); + return rv; + } + break; + + case expr_exists: + rv = 10 + (strlen (expr -> data.option -> name) + + strlen (expr -> data.option -> universe -> name)); + if (len > rv) { + sprintf (buf, "(exists %s.%s)", + expr -> data.option -> universe -> name, + expr -> data.option -> name); + return rv; + } + break; + + case expr_variable_exists: + rv = 10 + strlen (expr -> data.variable); + if (len > rv) { + sprintf (buf, "(defined %s)", expr -> data.variable); + return rv; + } + break; + + case expr_variable_reference: + rv = strlen (expr -> data.variable); + if (len > rv) { + sprintf (buf, "%s", expr -> data.variable); + return rv; + } + break; + + case expr_known: + s = "known"; + astring: + rv = strlen (s); + if (len > rv) { + strcpy (buf, s); + return rv; + } + break; + + case expr_leased_address: + s = "leased-address"; + goto astring; + + case expr_client_state: + s = "client-state"; + goto astring; + + case expr_host_decl_name: + s = "host-decl-name"; + goto astring; + + case expr_lease_time: + s = "lease-time"; + goto astring; + + case expr_static: + s = "static"; + goto astring; + + case expr_filename: + s = "filename"; + goto astring; + + case expr_sname: + s = "server-name"; + goto astring; + + case expr_reverse: + if (len > 11) { + rv = 13; + strcpy (buf, "(reverse "); + rv += print_subexpression (expr -> data.reverse.width, + buf + rv, len - rv - 2); + buf [rv++] = ' '; + rv += print_subexpression (expr -> data.reverse.buffer, + buf + rv, len - rv - 1); + buf [rv++] = ')'; + buf [rv] = 0; + return rv; + } + break; + + case expr_binary_to_ascii: + if (len > 5) { + rv = 9; + strcpy (buf, "(b2a "); + rv += print_subexpression (expr -> data.b2a.base, + buf + rv, len - rv - 4); + buf [rv++] = ' '; + rv += print_subexpression (expr -> data.b2a.width, + buf + rv, len - rv - 3); + buf [rv++] = ' '; + rv += print_subexpression (expr -> data.b2a.seperator, + buf + rv, len - rv - 2); + buf [rv++] = ' '; + rv += print_subexpression (expr -> data.b2a.buffer, + buf + rv, len - rv - 1); + buf [rv++] = ')'; + buf [rv] = 0; + return rv; + } + break; + + case expr_dns_transaction: + rv = 10; + if (len < rv + 2) { + buf [0] = '('; + strcpy (&buf [1], "ns-update "); + while (len < rv + 2) { + rv += print_subexpression + (expr -> data.dns_transaction.car, + buf + rv, len - rv - 2); + buf [rv++] = ' '; + expr = expr -> data.dns_transaction.cdr; + } + buf [rv - 1] = ')'; + buf [rv] = 0; + return rv; + } + return 0; + + case expr_ns_delete: + s = "delete"; + left = 4; + goto dodnsupd; + case expr_ns_exists: + s = "exists"; + left = 4; + goto dodnsupd; + case expr_ns_not_exists: + s = "not_exists"; + left = 4; + goto dodnsupd; + case expr_ns_add: + s = "update"; + left = 5; + dodnsupd: + rv = strlen (s); + if (len > strlen (s) + 1) { + buf [0] = '('; + strcpy (buf + 1, s); + rv++; + buf [rv++] = ' '; + s = print_dec_1 (expr -> data.ns_add.rrclass); + if (len > rv + strlen (s) + left) { + strcpy (&buf [rv], s); + rv += strlen (&buf [rv]); + } + buf [rv++] = ' '; + left--; + s = print_dec_1 (expr -> data.ns_add.rrtype); + if (len > rv + strlen (s) + left) { + strcpy (&buf [rv], s); + rv += strlen (&buf [rv]); + } + buf [rv++] = ' '; + left--; + rv += print_subexpression + (expr -> data.ns_add.rrname, + buf + rv, len - rv - left); + buf [rv++] = ' '; + left--; + rv += print_subexpression + (expr -> data.ns_add.rrdata, + buf + rv, len - rv - left); + buf [rv++] = ' '; + left--; + rv += print_subexpression + (expr -> data.ns_add.ttl, + buf + rv, len - rv - left); + buf [rv++] = ')'; + buf [rv] = 0; + return rv; + } + break; + + case expr_null: + if (len > 6) { + strcpy (buf, "(null)"); + return 6; + } + break; + case expr_funcall: + rv = 12 + strlen (expr -> data.funcall.name); + if (len > rv + 1) { + strcpy (buf, "(funcall "); + strcpy (buf + 9, expr -> data.funcall.name); + buf [rv++] = ' '; + rv += print_subexpression + (expr -> data.funcall.arglist, buf + rv, + len - rv - 1); + buf [rv++] = ')'; + buf [rv] = 0; + return rv; + } + break; + + case expr_arg: + rv = print_subexpression (expr -> data.arg.val, buf, len); + if (expr -> data.arg.next && rv + 2 < len) { + buf [rv++] = ' '; + rv += print_subexpression (expr -> data.arg.next, + buf, len); + if (rv + 1 < len) + buf [rv++] = 0; + return rv; + } + break; + case expr_function: + rv = 9; + if (len > rv + 1) { + struct string_list *foo; + strcpy (buf, "(function"); + for (foo = expr -> data.func -> args; + foo; foo = foo -> next) { + if (len > rv + 2 + strlen (foo -> string)) { + buf [rv - 1] = ' '; + strcpy (&buf [rv], foo -> string); + rv += strlen (foo -> string); + } + } + buf [rv] = ')'; + buf [rv++] = 0; + return rv; + } + } + return 0; +} + +void print_expression (name, expr) + const char *name; + struct expression *expr; +{ + char buf [1024]; + + print_subexpression (expr, buf, sizeof buf); + log_info ("%s: %s", name, buf); +} + +int token_print_indent_concat (FILE *file, int col, int indent, + const char *prefix, + const char *suffix, ...) +{ + va_list list; + char *buf; + unsigned len; + char *s, *t, *u; + + va_start (list, suffix); + s = va_arg (list, char *); + len = 0; + while (s) { + len += strlen (s); + s = va_arg (list, char *); + } + va_end (list); + + t = dmalloc (len + 1, MDL); + if (!t) + log_fatal ("token_print_indent: no memory for copy buffer"); + + va_start (list, suffix); + s = va_arg (list, char *); + u = t; + while (s) { + len = strlen (s); + strcpy (u, s); + u += len; + } + va_end (list); + + len = token_print_indent (file, col, indent, + prefix, suffix, t); + dfree (t, MDL); + return col; +} + +int token_indent_data_string (FILE *file, int col, int indent, + const char *prefix, const char *suffix, + struct data_string *data) +{ + int i; + char *buf; + char obuf [3]; + + /* See if this is just ASCII. */ + for (i = 0; i < data -> len; i++) + if (!isascii (data -> data [i]) || + !isprint (data -> data [i])) + break; + + /* If we have a purely ASCII string, output it as text. */ + if (i == data -> len) { + char *buf = dmalloc (data -> len + 3, MDL); + if (buf) { + buf [0] = '"'; + memcpy (buf + 1, data -> data, data -> len); + buf [data -> len + 1] = '"'; + buf [data -> len + 2] = 0; + i = token_print_indent (file, col, indent, + prefix, suffix, buf); + dfree (buf, MDL); + return i; + } + } + + for (i = 0; i < data -> len; i++) { + sprintf (obuf, "%2.2x", data -> data [i]); + col = token_print_indent (file, col, indent, + i == 0 ? prefix : "", + (i + 1 == data -> len + ? suffix + : ""), obuf); + if (i + 1 != data -> len) + col = token_print_indent (file, col, indent, + prefix, suffix, ":"); + } + return col; +} + +int token_print_indent (FILE *file, int col, int indent, + const char *prefix, + const char *suffix, const char *buf) +{ + int len = strlen (buf) + strlen (prefix); + if (col + len > 79) { + if (indent + len < 79) { + indent_spaces (file, indent); + col = indent; + } else { + indent_spaces (file, col); + col = len > 79 ? 0 : 79 - len - 1; + } + } else if (prefix && *prefix) { + fputs (prefix, file); + col += strlen (prefix); + } + fputs (buf, file); + col += len; + if (suffix && *suffix) { + if (col + strlen (suffix) > 79) { + indent_spaces (file, indent); + col = indent; + } else { + fputs (suffix, file); + col += strlen (suffix); + } + } + return col; +} + +void indent_spaces (FILE *file, int indent) +{ + int i; + fputc ('\n', file); + for (i = 0; i < indent; i++) + fputc (' ', file); +} + +#if defined (NSUPDATE) +void print_dns_status (int status, ns_updque *uq) +{ + char obuf [1024]; + char *s = &obuf [0], *end = &obuf [1022]; + ns_updrec *u; + int position; + int ttlp; + const char *predicate = "if", *en, *op; + int errorp; + + for (u = ISC_LIST_HEAD (*uq); u; u = ISC_LIST_NEXT (u, r_link)) { + ttlp = 0; + + switch (u -> r_opcode) + { + case NXRRSET: + op = "rrset doesn't exist"; + position = 1; + break; + case YXRRSET: + op = "rrset exists"; + position = 1; + break; + case NXDOMAIN: + op = "domain doesn't exist"; + position = 1; + break; + case YXDOMAIN: + op = "domain exists"; + position = 1; + break; + case ADD: + op = "add"; + position = 0; + ttlp = 1; + break; + case DELETE: + op = "delete"; + position = 0; + break; + default: + op = "unknown"; + position = 0; + break; + } + if (!position) { + if (s != &obuf [0] && s + 1 < end) + *s++ = ' '; + if (s + strlen (op) < end) { + strcpy (s, op); + s += strlen (s); + } + } else { + if (s != &obuf [0] && s + 1 < end) + *s++ = ' '; + if (s + strlen (predicate) < end) { + strcpy (s, predicate); + s += strlen (s); + } + predicate = "and"; + } + if (ttlp) { + if (s + 1 < end) + *s++ = ' '; + /* 27 is as big as a ttl can get. */ + if (s + 27 < end) { + sprintf (s, "%lu", + (unsigned long)(u -> r_ttl)); + s += strlen (s); + } + } + switch (u -> r_class) { + case C_IN: + en = "IN"; + break; + case C_CHAOS: + en = "CHAOS"; + break; + case C_HS: + en = "HS"; + break; + default: + en = "UNKNOWN"; + break; + } + if (s + strlen (en) < end) { + if (s + 1 < end) + *s++ = ' '; + strcpy (s, en); + s += strlen (en); + } + switch (u -> r_type) { + case T_A: + en = "A"; + break; + case T_PTR: + en = "PTR"; + break; + case T_MX: + en = "MX"; + break; + case T_TXT: + en = "TXT"; + break; + case T_CNAME: + en = "CNAME"; + break; + default: + en = "UNKNOWN"; + break; + } + if (s + strlen (en) < end) { + if (s + 1 < end) + *s++ = ' '; + strcpy (s, en); + s += strlen (en); + } + if (u -> r_dname) { + if (s + 1 < end) + *s++ = ' '; + if (s + strlen (u -> r_dname) < end) { + strcpy (s, u -> r_dname); + s += strlen (s); + } + } + if (u -> r_data) { + if (s + 1 < end) + *s++ = ' '; + if (u -> r_type == T_TXT) { + if (s + 1 < end) + *s++ = '"'; + } + if (s + u -> r_size < end) { + memcpy (s, u -> r_data, u -> r_size); + s += u -> r_size; + if (u -> r_type == T_TXT) { + if (s + 1 < end) + *s++ = '"'; + } + } + } + if (position) { + if (s + 1 < end) + *s++ = ' '; + if (s + strlen (op) < end) { + strcpy (s, op); + s += strlen (s); + } + } + if (u == ISC_LIST_TAIL (*uq)) + break; + } + if (s == &obuf [0]) { + strcpy (s, "empty update"); + s += strlen (s); + } + if (status == NOERROR) + errorp = 0; + else + errorp = 1; + en = isc_result_totext (status); +#if 0 + switch (status) { + case -1: + en = "resolver failed"; + break; + + case FORMERR: + en = "format error"; + break; + + case NOERROR: + en = "succeeded"; + errorp = 0; + break; + + case NOTAUTH: + en = "not authorized"; + break; + + case NOTIMP: + en = "not implemented"; + break; + + case NOTZONE: + en = "not a single valid zone"; + break; + + case NXDOMAIN: + en = "no such domain"; + break; + + case NXRRSET: + en = "no such record"; + break; + + case REFUSED: + en = "refused"; + break; + + case SERVFAIL: + en = "server failed"; + break; + + case YXDOMAIN: + en = "domain exists"; + break; + + case YXRRSET: + en = "record exists"; + break; + + default: + en = "unknown error"; + break; + } +#endif + + if (s + 2 < end) { + *s++ = ':'; + *s++ = ' '; + } + if (s + strlen (en) < end) { + strcpy (s, en); + s += strlen (en); } + if (s + 1 < end) + *s++ = '.'; + *s++ = 0; + if (errorp) + log_error (obuf); + else + log_info (obuf); } +#endif /* NSUPDATE */ diff --git a/contrib/isc-dhcp/common/raw.c b/contrib/isc-dhcp/common/raw.c index 0ef9289..c56b681 100644 --- a/contrib/isc-dhcp/common/raw.c +++ b/contrib/isc-dhcp/common/raw.c @@ -16,7 +16,7 @@ Sigh. */ /* - * Copyright (c) 1995, 1996, 1997, 1999 The Internet Software Consortium. + * Copyright (c) 1995-2000 Internet Software Consortium. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -47,14 +47,16 @@ * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium - * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie - * Enterprises. To learn more about the Internet Software Consortium, - * see ``http://www.vix.com/isc''. To learn more about Vixie - * Enterprises, see ``http://www.vix.com''. */ + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. + */ #ifndef lint static char copyright[] = -"$Id: raw.c,v 1.11.2.4 1999/07/20 20:03:10 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1999 The Internet Software Consortium. All rights reserved.\n"; +"$Id: raw.c,v 1.17 2000/03/17 03:59:01 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -79,39 +81,46 @@ void if_register_send (info) /* List addresses on which we're listening. */ if (!quiet_interface_discovery) - note ("Sending on Raw Socket/%s/%s%s%s", - info -> name, - print_hw_addr (info -> hw_address.htype, - info -> hw_address.hlen, - info -> hw_address.haddr), - (info -> shared_network ? "/" : ""), - (info -> shared_network ? - info -> shared_network -> name : "")); - + log_info ("Sending on %s, port %d", + piaddr (info -> address), htons (local_port)); if ((sock = socket (AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) - error ("Can't create dhcp socket: %m"); + log_fatal ("Can't create dhcp socket: %m"); /* Set the BROADCAST option so that we can broadcast DHCP responses. */ flag = 1; if (setsockopt (sock, SOL_SOCKET, SO_BROADCAST, &flag, sizeof flag) < 0) - error ("Can't set SO_BROADCAST option on dhcp socket: %m"); + log_fatal ("Can't set SO_BROADCAST option on dhcp socket: %m"); /* Set the IP_HDRINCL flag so that we can supply our own IP headers... */ if (setsockopt (sock, IPPROTO_IP, IP_HDRINCL, &flag, sizeof flag) < 0) - error ("Can't set IP_HDRINCL flag: %m"); + log_fatal ("Can't set IP_HDRINCL flag: %m"); info -> wfdesc = sock; if (!quiet_interface_discovery) - note ("Sending on Raw/%s%s%s", + log_info ("Sending on Raw/%s%s%s", + info -> name, + (info -> shared_network ? "/" : ""), + (info -> shared_network ? + info -> shared_network -> name : "")); +} + +void if_deregister_send (info) + struct interface_info *info; +{ + close (info -> wfdesc); + info -> wfdesc = -1; + + if (!quiet_interface_discovery) + log_info ("Disabling output on Raw/%s%s%s", info -> name, (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : "")); } -ssize_t send_packet (interface, packet, raw, len, from, to, hto) +size_t send_packet (interface, packet, raw, len, from, to, hto) struct interface_info *interface; struct packet *packet; struct dhcp_packet *raw; @@ -120,7 +129,7 @@ ssize_t send_packet (interface, packet, raw, len, from, to, hto) struct sockaddr_in *to; struct hardware *hto; { - unsigned char buf [1500]; + unsigned char buf [256]; int bufp = 0; struct iovec iov [2]; int result; @@ -129,37 +138,16 @@ ssize_t send_packet (interface, packet, raw, len, from, to, hto) assemble_udp_ip_header (interface, buf, &bufp, from.s_addr, to -> sin_addr.s_addr, to -> sin_port, (unsigned char *)raw, len); - if (len + bufp > sizeof buf) { - warn ("send_packet: packet too large (%s)", len + bufp); - return; - } - memcpy (buf + bufp, raw, len); - bufp += len; - result = sendto (interface -> wfdesc, (char *)buf, bufp, 0, - (struct sockaddr *)to, sizeof *to); - if (result < 0) - warn ("send_packet: %m"); - return result; -} - -int can_unicast_without_arp () -{ - return 1; -} -int can_receive_unicast_unconfigured (ip) - struct interface_info *ip; -{ - return 1; -} + /* Fire it off */ + iov [0].iov_base = (char *)buf; + iov [0].iov_len = bufp; + iov [1].iov_base = (char *)raw; + iov [1].iov_len = len; -void maybe_setup_fallback () -{ -} - -void if_reinitialize_send (info) - struct interface_info *info; -{ + result = writev(interface -> wfdesc, iov, 2); + if (result < 0) + log_error ("send_packet: %m"); + return result; } - -#endif /* USE_RAW_SEND */ +#endif /* USE_SOCKET_SEND */ diff --git a/contrib/isc-dhcp/common/resolv.c b/contrib/isc-dhcp/common/resolv.c new file mode 100644 index 0000000..396f9ef --- /dev/null +++ b/contrib/isc-dhcp/common/resolv.c @@ -0,0 +1,212 @@ +/* resolv.c + + Parser for /etc/resolv.conf file. */ + +/* + * Copyright (c) 1996-2001 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. + */ + +#ifndef lint +static char copyright[] = +"$Id: resolv.c,v 1.16 2001/05/02 06:39:43 mellon Exp $ Copyright (c) 1996-2001 The Internet Software Consortium. All rights reserved.\n"; +#endif /* not lint */ + +#include "dhcpd.h" + +struct name_server *name_servers; +struct domain_search_list *domains; +char path_resolv_conf [] = _PATH_RESOLV_CONF; + +void read_resolv_conf (parse_time) + TIME parse_time; +{ + int file; + struct parse *cfile; + const char *val; + int token; + int declaration = 0; + struct name_server *sp, *sl, *ns; + struct domain_search_list *dp, *dl, *nd; + struct iaddr *iaddr; + + if ((file = open (path_resolv_conf, O_RDONLY)) < 0) { + log_error ("Can't open %s: %m", path_resolv_conf); + return; + } + + cfile = (struct parse *)0; + new_parse (&cfile, file, (char *)0, 0, path_resolv_conf, 1); + + do { + token = next_token (&val, (unsigned *)0, cfile); + if (token == END_OF_FILE) + break; + else if (token == EOL) + continue; + else if (token == DOMAIN || token == SEARCH) { + do { + struct domain_search_list *nd, **dp; + char *dn; + + dn = parse_host_name (cfile); + if (!dn) + break; + + dp = &domains; + for (nd = domains; nd; nd = nd -> next) { + dp = &nd -> next; + if (!strcmp (nd -> domain, dn)) + break; + } + if (!nd) { + nd = new_domain_search_list (MDL); + if (!nd) + log_fatal ("No memory for %s", + dn); + nd -> next = + (struct domain_search_list *)0; + *dp = nd; + nd -> domain = dn; + dn = (char *)0; + } + nd -> rcdate = parse_time; + token = peek_token (&val, + (unsigned *)0, cfile); + } while (token != EOL); + if (token != EOL) { + parse_warn (cfile, + "junk after domain declaration"); + skip_to_semi (cfile); + } + token = next_token (&val, (unsigned *)0, cfile); + } else if (token == NAMESERVER) { + struct name_server *ns, **sp; + struct iaddr iaddr; + + parse_ip_addr (cfile, &iaddr); + + sp = &name_servers; + for (ns = name_servers; ns; ns = ns -> next) { + sp = &ns -> next; + if (!memcmp (&ns -> addr.sin_addr, + iaddr.iabuf, iaddr.len)) + break; + } + if (!ns) { + ns = new_name_server (MDL); + if (!ns) + log_fatal ("No memory for nameserver %s", + piaddr (iaddr)); + ns -> next = (struct name_server *)0; + *sp = ns; + memcpy (&ns -> addr.sin_addr, + iaddr.iabuf, iaddr.len); +#ifdef HAVE_SA_LEN + ns -> addr.sin_len = sizeof ns -> addr; +#endif + ns -> addr.sin_family = AF_INET; + ns -> addr.sin_port = htons (53); + memset (ns -> addr.sin_zero, 0, + sizeof ns -> addr.sin_zero); + } + ns -> rcdate = parse_time; + skip_to_semi (cfile); + } else + skip_to_semi (cfile); /* Ignore what we don't grok. */ + } while (1); + token = next_token (&val, (unsigned *)0, cfile); + + /* Lose servers that are no longer in /etc/resolv.conf. */ + sl = (struct name_server *)0; + for (sp = name_servers; sp; sp = ns) { + ns = sp -> next; + if (sp -> rcdate != parse_time) { + if (sl) + sl -> next = sp -> next; + else + name_servers = sp -> next; + /* We can't actually free the name server structure, + because somebody might be hanging on to it. If + your /etc/resolv.conf file changes a lot, this + could be a noticable memory leak. */ + } else + sl = sp; + } + + /* Lose domains that are no longer in /etc/resolv.conf. */ + dl = (struct domain_search_list *)0; + for (dp = domains; dp; dp = nd) { + nd = dp -> next; + if (dp -> rcdate != parse_time) { + if (dl) + dl -> next = dp -> next; + else + domains = dp -> next; + free_domain_search_list (dp, MDL); + } else + dl = dp; + } + close (file); + end_parse (&cfile); +} + +/* Pick a name server from the /etc/resolv.conf file. */ + +struct name_server *first_name_server () +{ + FILE *rc; + static TIME rcdate; + struct stat st; + + /* Check /etc/resolv.conf and reload it if it's changed. */ + if (cur_time > rcdate) { + if (stat (path_resolv_conf, &st) < 0) { + log_error ("Can't stat %s", path_resolv_conf); + return (struct name_server *)0; + } + if (st.st_mtime > rcdate) { + char rcbuf [512]; + char *s, *t, *u; + rcdate = cur_time + 1; + + read_resolv_conf (rcdate); + } + } + + return name_servers; +} diff --git a/contrib/isc-dhcp/common/socket.c b/contrib/isc-dhcp/common/socket.c index 0a6b0b8..b4ecd14 100644 --- a/contrib/isc-dhcp/common/socket.c +++ b/contrib/isc-dhcp/common/socket.c @@ -3,8 +3,8 @@ BSD socket interface code... */ /* - * Copyright (c) 1995, 1996, 1997, 1998, 1999 - * The Internet Software Consortium. All rights reserved. + * Copyright (c) 1995-2000 Internet Software Consortium. + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -34,10 +34,11 @@ * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium - * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie - * Enterprises. To learn more about the Internet Software Consortium, - * see ``http://www.vix.com/isc''. To learn more about Vixie - * Enterprises, see ``http://www.vix.com''. + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. */ /* SO_BINDTODEVICE support added by Elliot Poger (poger@leland.stanford.edu). @@ -50,7 +51,7 @@ #ifndef lint static char copyright[] = -"$Id: socket.c,v 1.26.2.12 1999/10/25 15:39:55 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium. All rights reserved.\n"; +"$Id: socket.c,v 1.55.2.1 2002/01/17 19:42:55 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -108,7 +109,7 @@ int if_register_socket (info) #if !defined (HAVE_SO_BINDTODEVICE) && !defined (USE_FALLBACK) /* Make sure only one interface is registered. */ if (once) - error ("The standard socket API can only support %s", + log_fatal ("The standard socket API can only support %s", "hosts with a single network interface."); once = 1; #endif @@ -116,35 +117,44 @@ int if_register_socket (info) /* Set up the address we're going to bind to. */ name.sin_family = AF_INET; name.sin_port = local_port; - name.sin_addr.s_addr = INADDR_ANY; + name.sin_addr = local_address; memset (name.sin_zero, 0, sizeof (name.sin_zero)); /* Make a socket... */ if ((sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) - error ("Can't create dhcp socket: %m"); + log_fatal ("Can't create dhcp socket: %m"); /* Set the REUSEADDR option so that we don't fail to start if we're being restarted. */ flag = 1; if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (char *)&flag, sizeof flag) < 0) - error ("Can't set SO_REUSEADDR option on dhcp socket: %m"); + log_fatal ("Can't set SO_REUSEADDR option on dhcp socket: %m"); - /* Set the BROADCAST option so that we can broadcast DHCP responses. */ - if (setsockopt (sock, SOL_SOCKET, SO_BROADCAST, - (char *)&flag, sizeof flag) < 0) - error ("Can't set SO_BROADCAST option on dhcp socket: %m"); + /* Set the BROADCAST option so that we can broadcast DHCP responses. + We shouldn't do this for fallback devices, and we can detect that + a device is a fallback because it has no ifp structure. */ + if (info -> ifp && + (setsockopt (sock, SOL_SOCKET, SO_BROADCAST, + (char *)&flag, sizeof flag) < 0)) + log_fatal ("Can't set SO_BROADCAST option on dhcp socket: %m"); /* Bind the socket to this interface's IP address. */ - if (bind (sock, (struct sockaddr *)&name, sizeof name) < 0) - error ("Can't bind to dhcp address: %m"); + if (bind (sock, (struct sockaddr *)&name, sizeof name) < 0) { + log_error ("Can't bind to dhcp address: %m"); + log_error ("Please make sure there is no other dhcp server"); + log_error ("running and that there's no entry for dhcp or"); + log_error ("bootp in /etc/inetd.conf. Also make sure you"); + log_error ("are not running HP JetAdmin software, which"); + log_fatal ("includes a bootp server."); + } #if defined (HAVE_SO_BINDTODEVICE) /* Bind this socket to this interface. */ if (info -> ifp && setsockopt (sock, SOL_SOCKET, SO_BINDTODEVICE, (char *)(info -> ifp), sizeof *(info -> ifp)) < 0) { - error("setsockopt: SO_BINDTODEVICE: %m"); + log_fatal ("setsockopt: SO_BINDTODEVICE: %m"); } #endif @@ -158,16 +168,39 @@ void if_register_send (info) { #ifndef USE_SOCKET_RECEIVE info -> wfdesc = if_register_socket (info); +#if defined (USE_SOCKET_FALLBACK) + /* Fallback only registers for send, but may need to receive as + well. */ + info -> rfdesc = info -> wfdesc; +#endif #else info -> wfdesc = info -> rfdesc; #endif if (!quiet_interface_discovery) - note ("Sending on Socket/%s%s%s", + log_info ("Sending on Socket/%s%s%s", + info -> name, + (info -> shared_network ? "/" : ""), + (info -> shared_network ? + info -> shared_network -> name : "")); +} + +#if defined (USE_SOCKET_SEND) +void if_deregister_send (info) + struct interface_info *info; +{ +#ifndef USE_SOCKET_RECEIVE + close (info -> wfdesc); +#endif + info -> wfdesc = -1; + + if (!quiet_interface_discovery) + log_info ("Disabling output on Socket/%s%s%s", info -> name, (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : "")); } +#endif /* USE_SOCKET_SEND */ #endif /* USE_SOCKET_SEND || USE_SOCKET_FALLBACK */ #ifdef USE_SOCKET_RECEIVE @@ -178,7 +211,21 @@ void if_register_receive (info) we don't need to register this interface twice. */ info -> rfdesc = if_register_socket (info); if (!quiet_interface_discovery) - note ("Listening on Socket/%s%s%s", + log_info ("Listening on Socket/%s%s%s", + info -> name, + (info -> shared_network ? "/" : ""), + (info -> shared_network ? + info -> shared_network -> name : "")); +} + +void if_deregister_receive (info) + struct interface_info *info; +{ + close (info -> rfdesc); + info -> rfdesc = -1; + + if (!quiet_interface_discovery) + log_info ("Disabling input on Socket/%s%s%s", info -> name, (info -> shared_network ? "/" : ""), (info -> shared_network ? @@ -211,10 +258,10 @@ ssize_t send_packet (interface, packet, raw, len, from, to, hto) retry++ < 10); #endif if (result < 0) { - warn ("send_packet: %m"); + log_error ("send_packet: %m"); if (errno == ENETUNREACH) - warn ("send_packet: please consult README file %s", - "regarding broadcast address."); + log_error ("send_packet: please consult README file%s", + " regarding broadcast address."); } return result; } @@ -228,7 +275,7 @@ ssize_t receive_packet (interface, buf, len, from, hfrom) struct sockaddr_in *from; struct hardware *hfrom; { - int flen = sizeof *from; + SOCKLEN_T flen = sizeof *from; int result; #ifdef IGNORE_HOSTUNREACH @@ -250,24 +297,35 @@ ssize_t receive_packet (interface, buf, len, from, hfrom) #if defined (USE_SOCKET_FALLBACK) /* This just reads in a packet and silently discards it. */ -void fallback_discard (protocol) - struct protocol *protocol; +isc_result_t fallback_discard (object) + omapi_object_t *object; { char buf [1540]; struct sockaddr_in from; - int flen = sizeof from; + SOCKLEN_T flen = sizeof from; int status; - struct interface_info *interface = protocol -> local; + struct interface_info *interface; + + if (object -> type != dhcp_type_interface) + return ISC_R_INVALIDARG; + interface = (struct interface_info *)object; status = recvfrom (interface -> wfdesc, buf, sizeof buf, 0, (struct sockaddr *)&from, &flen); - if (status < 0) - warn ("fallback_discard: %m"); +#if defined (DEBUG) + /* Only report fallback discard errors if we're debugging. */ + if (status < 0) { + log_error ("fallback_discard: %m"); + return ISC_R_UNEXPECTED; + } +#endif + return ISC_R_SUCCESS; } #endif /* USE_SOCKET_FALLBACK */ #if defined (USE_SOCKET_SEND) -int can_unicast_without_arp () +int can_unicast_without_arp (ip) + struct interface_info *ip; { return 0; } @@ -282,18 +340,40 @@ int can_receive_unicast_unconfigured (ip) #endif } +int supports_multiple_interfaces (ip) + struct interface_info *ip; +{ +#if defined (SO_BINDTODEVICE) + return 1; +#else + return 0; +#endif +} + /* If we have SO_BINDTODEVICE, set up a fallback interface; otherwise, do not. */ void maybe_setup_fallback () { #if defined (USE_SOCKET_FALLBACK) - struct interface_info *fbi; - fbi = setup_fallback (); - if (fbi) { + isc_result_t status; + struct interface_info *fbi = (struct interface_info *)0; + if (setup_fallback (&fbi, MDL)) { fbi -> wfdesc = if_register_socket (fbi); - add_protocol ("fallback", - fbi -> wfdesc, fallback_discard, fbi); + fbi -> rfdesc = fbi -> wfdesc; + log_info ("Sending on Socket/%s%s%s", + fbi -> name, + (fbi -> shared_network ? "/" : ""), + (fbi -> shared_network ? + fbi -> shared_network -> name : "")); + + status = omapi_register_io_object ((omapi_object_t *)fbi, + if_readsocket, 0, + fallback_discard, 0, 0); + if (status != ISC_R_SUCCESS) + log_fatal ("Can't register I/O handle for %s: %s", + fbi -> name, isc_result_totext (status)); + interface_dereference (&fbi, MDL); } #endif } diff --git a/contrib/isc-dhcp/common/tables.c b/contrib/isc-dhcp/common/tables.c index 9274e38..d3e2379 100644 --- a/contrib/isc-dhcp/common/tables.c +++ b/contrib/isc-dhcp/common/tables.c @@ -3,7 +3,7 @@ Tables of information... */ /* - * Copyright (c) 1995, 1996 The Internet Software Consortium. + * Copyright (c) 1995-2001 Internet Software Consortium. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,24 +34,31 @@ * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium - * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie - * Enterprises. To learn more about the Internet Software Consortium, - * see ``http://www.vix.com/isc''. To learn more about Vixie - * Enterprises, see ``http://www.vix.com''. + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. */ #ifndef lint static char copyright[] = -"$Id: tables.c,v 1.13.2.4 1999/04/24 16:46:44 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n"; +"$Id: tables.c,v 1.51.2.4 2001/10/17 03:26:26 mellon Exp $ Copyright (c) 1995-2001 The Internet Software Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" +/* XXXDPN: Moved here from hash.c, when it moved to libomapi. Not sure + where these really belong. */ +HASH_FUNCTIONS (group, const char *, struct group_object, group_hash_t, + group_reference, group_dereference) +HASH_FUNCTIONS (universe, const char *, struct universe, universe_hash_t, 0, 0) +HASH_FUNCTIONS (option, const char *, struct option, option_hash_t, 0, 0) + /* DHCP Option names, formats and codes, from RFC1533. Format codes: - e - end of data I - IP address l - 32-bit signed integer L - 32-bit unsigned integer @@ -62,6 +69,32 @@ static char copyright[] = t - ASCII text f - flag (true or false) A - array of whatever precedes (e.g., IA means array of IP addresses) + a - array of the preceding character (e.g., IIa means two or more IP + addresses) + U - name of an option space (universe) + F - implicit flag - the presence of the option indicates that the + flag is true. + o - the preceding value is optional. + E - encapsulation, string or colon-seperated hex list (the latter + two for parsing). E is followed by a text string containing + the name of the option space to encapsulate, followed by a '.'. + If the E is immediately followed by '.', the applicable vendor + option space is used if one is defined. + e - If an encapsulation directive is not the first thing in the string, + the option scanner requires an efficient way to find the encapsulation. + This is done by placing a 'e' at the beginning of the option. The + 'e' has no other purpose, and is not required if 'E' is the first + thing in the option. + X - either an ASCII string or binary data. On output, the string is + scanned to see if it's printable ASCII and, if so, output as a + quoted string. If not, it's output as colon-seperated hex. On + input, the option can be specified either as a quoted string or as + a colon-seperated hex list. + N - enumeration. N is followed by a text string containing + the name of the set of enumeration values to parse or emit, + followed by a '.'. The width of the data is specified in the + named enumeration. Named enumerations are tracked in parse.c. + d - Domain name (i.e., FOO or FOO.BAR). */ struct universe dhcp_universe; @@ -109,7 +142,7 @@ struct option dhcp_options [256] = { { "nis-domain", "t", &dhcp_universe, 40 }, { "nis-servers", "IA", &dhcp_universe, 41 }, { "ntp-servers", "IA", &dhcp_universe, 42 }, - { "vendor-encapsulated-options", "X", &dhcp_universe, 43 }, + { "vendor-encapsulated-options", "E.", &dhcp_universe, 43 }, { "netbios-name-servers", "IA", &dhcp_universe, 44 }, { "netbios-dd-server", "IA", &dhcp_universe, 45 }, { "netbios-node-type", "B", &dhcp_universe, 46 }, @@ -126,10 +159,10 @@ struct option dhcp_options [256] = { { "dhcp-max-message-size", "S", &dhcp_universe, 57 }, { "dhcp-renewal-time", "L", &dhcp_universe, 58 }, { "dhcp-rebinding-time", "L", &dhcp_universe, 59 }, - { "dhcp-class-identifier", "t", &dhcp_universe, 60 }, + { "vendor-class-identifier", "X", &dhcp_universe, 60 }, { "dhcp-client-identifier", "X", &dhcp_universe, 61 }, - { "option-62", "X", &dhcp_universe, 62 }, - { "option-63", "X", &dhcp_universe, 63 }, + { "nwip-domain", "X", &dhcp_universe, 62 }, + { "nwip-suboptions", "Enwip.", &dhcp_universe, 63 }, { "nisplus-domain", "t", &dhcp_universe, 64 }, { "nisplus-servers", "IA", &dhcp_universe, 65 }, { "tftp-server-name", "t", &dhcp_universe, 66 }, @@ -144,272 +177,707 @@ struct option dhcp_options [256] = { { "streettalk-server", "IA", &dhcp_universe, 75 }, { "streettalk-directory-assistance-server", "IA", &dhcp_universe, 76 }, { "user-class", "t", &dhcp_universe, 77 }, - { "option-78", "X", &dhcp_universe, 78 }, - { "option-79", "X", &dhcp_universe, 79 }, - { "option-80", "X", &dhcp_universe, 80 }, - { "option-81", "X", &dhcp_universe, 81 }, - { "option-82", "X", &dhcp_universe, 82 }, - { "option-83", "X", &dhcp_universe, 83 }, - { "option-84", "X", &dhcp_universe, 84 }, + { "slp-directory-agent", "fIa", &dhcp_universe, 78 }, + { "slp-service-scope", "fto", &dhcp_universe, 79 }, + { "#80", "X", &dhcp_universe, 80 }, + { "fqdn", "Efqdn.", &dhcp_universe, 81 }, + { "relay-agent-information", "Eagent.", &dhcp_universe, 82 }, + { "#83", "X", &dhcp_universe, 83 }, + { "#84", "X", &dhcp_universe, 84 }, { "nds-servers", "IA", &dhcp_universe, 85 }, { "nds-tree-name", "X", &dhcp_universe, 86 }, { "nds-context", "X", &dhcp_universe, 87 }, - { "option-88", "X", &dhcp_universe, 88 }, - { "option-89", "X", &dhcp_universe, 89 }, - { "option-90", "X", &dhcp_universe, 90 }, - { "option-91", "X", &dhcp_universe, 91 }, - { "option-92", "X", &dhcp_universe, 92 }, - { "option-93", "X", &dhcp_universe, 93 }, - { "option-94", "X", &dhcp_universe, 94 }, - { "option-95", "X", &dhcp_universe, 95 }, - { "option-96", "X", &dhcp_universe, 96 }, - { "option-97", "X", &dhcp_universe, 97 }, - { "option-98", "X", &dhcp_universe, 98 }, - { "option-99", "X", &dhcp_universe, 99 }, - { "option-100", "X", &dhcp_universe, 100 }, - { "option-101", "X", &dhcp_universe, 101 }, - { "option-102", "X", &dhcp_universe, 102 }, - { "option-103", "X", &dhcp_universe, 103 }, - { "option-104", "X", &dhcp_universe, 104 }, - { "option-105", "X", &dhcp_universe, 105 }, - { "option-106", "X", &dhcp_universe, 106 }, - { "option-107", "X", &dhcp_universe, 107 }, - { "option-108", "X", &dhcp_universe, 108 }, - { "option-109", "X", &dhcp_universe, 109 }, - { "option-110", "X", &dhcp_universe, 110 }, - { "option-111", "X", &dhcp_universe, 111 }, - { "option-112", "X", &dhcp_universe, 112 }, - { "option-113", "X", &dhcp_universe, 113 }, - { "option-114", "X", &dhcp_universe, 114 }, - { "option-115", "X", &dhcp_universe, 115 }, - { "option-116", "X", &dhcp_universe, 116 }, - { "option-117", "X", &dhcp_universe, 117 }, - { "option-118", "X", &dhcp_universe, 118 }, - { "option-119", "X", &dhcp_universe, 119 }, - { "option-120", "X", &dhcp_universe, 120 }, - { "option-121", "X", &dhcp_universe, 121 }, - { "option-122", "X", &dhcp_universe, 122 }, - { "option-123", "X", &dhcp_universe, 123 }, - { "option-124", "X", &dhcp_universe, 124 }, - { "option-125", "X", &dhcp_universe, 125 }, - { "option-126", "X", &dhcp_universe, 126 }, - { "option-127", "X", &dhcp_universe, 127 }, - { "option-128", "X", &dhcp_universe, 128 }, - { "option-129", "X", &dhcp_universe, 129 }, - { "option-130", "X", &dhcp_universe, 130 }, - { "option-131", "X", &dhcp_universe, 131 }, - { "option-132", "X", &dhcp_universe, 132 }, - { "option-133", "X", &dhcp_universe, 133 }, - { "option-134", "X", &dhcp_universe, 134 }, - { "option-135", "X", &dhcp_universe, 135 }, - { "option-136", "X", &dhcp_universe, 136 }, - { "option-137", "X", &dhcp_universe, 137 }, - { "option-138", "X", &dhcp_universe, 138 }, - { "option-139", "X", &dhcp_universe, 139 }, - { "option-140", "X", &dhcp_universe, 140 }, - { "option-141", "X", &dhcp_universe, 141 }, - { "option-142", "X", &dhcp_universe, 142 }, - { "option-143", "X", &dhcp_universe, 143 }, - { "option-144", "X", &dhcp_universe, 144 }, - { "option-145", "X", &dhcp_universe, 145 }, - { "option-146", "X", &dhcp_universe, 146 }, - { "option-147", "X", &dhcp_universe, 147 }, - { "option-148", "X", &dhcp_universe, 148 }, - { "option-149", "X", &dhcp_universe, 149 }, - { "option-150", "X", &dhcp_universe, 150 }, - { "option-151", "X", &dhcp_universe, 151 }, - { "option-152", "X", &dhcp_universe, 152 }, - { "option-153", "X", &dhcp_universe, 153 }, - { "option-154", "X", &dhcp_universe, 154 }, - { "option-155", "X", &dhcp_universe, 155 }, - { "option-156", "X", &dhcp_universe, 156 }, - { "option-157", "X", &dhcp_universe, 157 }, - { "option-158", "X", &dhcp_universe, 158 }, - { "option-159", "X", &dhcp_universe, 159 }, - { "option-160", "X", &dhcp_universe, 160 }, - { "option-161", "X", &dhcp_universe, 161 }, - { "option-162", "X", &dhcp_universe, 162 }, - { "option-163", "X", &dhcp_universe, 163 }, - { "option-164", "X", &dhcp_universe, 164 }, - { "option-165", "X", &dhcp_universe, 165 }, - { "option-166", "X", &dhcp_universe, 166 }, - { "option-167", "X", &dhcp_universe, 167 }, - { "option-168", "X", &dhcp_universe, 168 }, - { "option-169", "X", &dhcp_universe, 169 }, - { "option-170", "X", &dhcp_universe, 170 }, - { "option-171", "X", &dhcp_universe, 171 }, - { "option-172", "X", &dhcp_universe, 172 }, - { "option-173", "X", &dhcp_universe, 173 }, - { "option-174", "X", &dhcp_universe, 174 }, - { "option-175", "X", &dhcp_universe, 175 }, - { "option-176", "X", &dhcp_universe, 176 }, - { "option-177", "X", &dhcp_universe, 177 }, - { "option-178", "X", &dhcp_universe, 178 }, - { "option-179", "X", &dhcp_universe, 179 }, - { "option-180", "X", &dhcp_universe, 180 }, - { "option-181", "X", &dhcp_universe, 181 }, - { "option-182", "X", &dhcp_universe, 182 }, - { "option-183", "X", &dhcp_universe, 183 }, - { "option-184", "X", &dhcp_universe, 184 }, - { "option-185", "X", &dhcp_universe, 185 }, - { "option-186", "X", &dhcp_universe, 186 }, - { "option-187", "X", &dhcp_universe, 187 }, - { "option-188", "X", &dhcp_universe, 188 }, - { "option-189", "X", &dhcp_universe, 189 }, - { "option-190", "X", &dhcp_universe, 190 }, - { "option-191", "X", &dhcp_universe, 191 }, - { "option-192", "X", &dhcp_universe, 192 }, - { "option-193", "X", &dhcp_universe, 193 }, - { "option-194", "X", &dhcp_universe, 194 }, - { "option-195", "X", &dhcp_universe, 195 }, - { "option-196", "X", &dhcp_universe, 196 }, - { "option-197", "X", &dhcp_universe, 197 }, - { "option-198", "X", &dhcp_universe, 198 }, - { "option-199", "X", &dhcp_universe, 199 }, - { "option-200", "X", &dhcp_universe, 200 }, - { "option-201", "X", &dhcp_universe, 201 }, - { "option-202", "X", &dhcp_universe, 202 }, - { "option-203", "X", &dhcp_universe, 203 }, - { "option-204", "X", &dhcp_universe, 204 }, - { "option-205", "X", &dhcp_universe, 205 }, - { "option-206", "X", &dhcp_universe, 206 }, - { "option-207", "X", &dhcp_universe, 207 }, - { "option-208", "X", &dhcp_universe, 208 }, - { "option-209", "X", &dhcp_universe, 209 }, - { "option-210", "X", &dhcp_universe, 210 }, - { "option-211", "X", &dhcp_universe, 211 }, - { "option-212", "X", &dhcp_universe, 212 }, - { "option-213", "X", &dhcp_universe, 213 }, - { "option-214", "X", &dhcp_universe, 214 }, - { "option-215", "X", &dhcp_universe, 215 }, - { "option-216", "X", &dhcp_universe, 216 }, - { "option-217", "X", &dhcp_universe, 217 }, - { "option-218", "X", &dhcp_universe, 218 }, - { "option-219", "X", &dhcp_universe, 219 }, - { "option-220", "X", &dhcp_universe, 220 }, - { "option-221", "X", &dhcp_universe, 221 }, - { "option-222", "X", &dhcp_universe, 222 }, - { "option-223", "X", &dhcp_universe, 223 }, - { "option-224", "X", &dhcp_universe, 224 }, - { "option-225", "X", &dhcp_universe, 225 }, - { "option-226", "X", &dhcp_universe, 226 }, - { "option-227", "X", &dhcp_universe, 227 }, - { "option-228", "X", &dhcp_universe, 228 }, - { "option-229", "X", &dhcp_universe, 229 }, - { "option-230", "X", &dhcp_universe, 230 }, - { "option-231", "X", &dhcp_universe, 231 }, - { "option-232", "X", &dhcp_universe, 232 }, - { "option-233", "X", &dhcp_universe, 233 }, - { "option-234", "X", &dhcp_universe, 234 }, - { "option-235", "X", &dhcp_universe, 235 }, - { "option-236", "X", &dhcp_universe, 236 }, - { "option-237", "X", &dhcp_universe, 237 }, - { "option-238", "X", &dhcp_universe, 238 }, - { "option-239", "X", &dhcp_universe, 239 }, - { "option-240", "X", &dhcp_universe, 240 }, - { "option-241", "X", &dhcp_universe, 241 }, - { "option-242", "X", &dhcp_universe, 242 }, - { "option-243", "X", &dhcp_universe, 243 }, - { "option-244", "X", &dhcp_universe, 244 }, - { "option-245", "X", &dhcp_universe, 245 }, - { "option-246", "X", &dhcp_universe, 246 }, - { "option-247", "X", &dhcp_universe, 247 }, - { "option-248", "X", &dhcp_universe, 248 }, - { "option-249", "X", &dhcp_universe, 249 }, - { "option-250", "X", &dhcp_universe, 250 }, - { "option-251", "X", &dhcp_universe, 251 }, - { "option-252", "X", &dhcp_universe, 252 }, - { "option-253", "X", &dhcp_universe, 253 }, - { "option-254", "X", &dhcp_universe, 254 }, + { "#88", "X", &dhcp_universe, 88 }, + { "#89", "X", &dhcp_universe, 89 }, + { "#90", "X", &dhcp_universe, 90 }, + { "#91", "X", &dhcp_universe, 91 }, + { "#92", "X", &dhcp_universe, 92 }, + { "#93", "X", &dhcp_universe, 93 }, + { "#94", "X", &dhcp_universe, 94 }, + { "#95", "X", &dhcp_universe, 95 }, + { "#96", "X", &dhcp_universe, 96 }, + { "#97", "X", &dhcp_universe, 97 }, + { "uap-servers", "t", &dhcp_universe, 98 }, + { "#99", "X", &dhcp_universe, 99 }, + { "#100", "X", &dhcp_universe, 100 }, + { "#101", "X", &dhcp_universe, 101 }, + { "#102", "X", &dhcp_universe, 102 }, + { "#103", "X", &dhcp_universe, 103 }, + { "#104", "X", &dhcp_universe, 104 }, + { "#105", "X", &dhcp_universe, 105 }, + { "#106", "X", &dhcp_universe, 106 }, + { "#107", "X", &dhcp_universe, 107 }, + { "#108", "X", &dhcp_universe, 108 }, + { "#109", "X", &dhcp_universe, 109 }, + { "#110", "X", &dhcp_universe, 110 }, + { "#111", "X", &dhcp_universe, 111 }, + { "#112", "X", &dhcp_universe, 112 }, + { "#113", "X", &dhcp_universe, 113 }, + { "#114", "X", &dhcp_universe, 114 }, + { "#115", "X", &dhcp_universe, 115 }, + { "#116", "X", &dhcp_universe, 116 }, + { "#117", "X", &dhcp_universe, 117 }, + { "subnet-selection", "X", &dhcp_universe, 118 }, + { "#119", "X", &dhcp_universe, 119 }, + { "#120", "X", &dhcp_universe, 120 }, + { "#121", "X", &dhcp_universe, 121 }, + { "#122", "X", &dhcp_universe, 122 }, + { "#123", "X", &dhcp_universe, 123 }, + { "#124", "X", &dhcp_universe, 124 }, + { "#125", "X", &dhcp_universe, 125 }, + { "#126", "X", &dhcp_universe, 126 }, + { "#127", "X", &dhcp_universe, 127 }, + { "#128", "X", &dhcp_universe, 128 }, + { "#129", "X", &dhcp_universe, 129 }, + { "#130", "X", &dhcp_universe, 130 }, + { "#131", "X", &dhcp_universe, 131 }, + { "#132", "X", &dhcp_universe, 132 }, + { "#133", "X", &dhcp_universe, 133 }, + { "#134", "X", &dhcp_universe, 134 }, + { "#135", "X", &dhcp_universe, 135 }, + { "#136", "X", &dhcp_universe, 136 }, + { "#137", "X", &dhcp_universe, 137 }, + { "#138", "X", &dhcp_universe, 138 }, + { "#139", "X", &dhcp_universe, 139 }, + { "#140", "X", &dhcp_universe, 140 }, + { "#141", "X", &dhcp_universe, 141 }, + { "#142", "X", &dhcp_universe, 142 }, + { "#143", "X", &dhcp_universe, 143 }, + { "#144", "X", &dhcp_universe, 144 }, + { "#145", "X", &dhcp_universe, 145 }, + { "#146", "X", &dhcp_universe, 146 }, + { "#147", "X", &dhcp_universe, 147 }, + { "#148", "X", &dhcp_universe, 148 }, + { "#149", "X", &dhcp_universe, 149 }, + { "#150", "X", &dhcp_universe, 150 }, + { "#151", "X", &dhcp_universe, 151 }, + { "#152", "X", &dhcp_universe, 152 }, + { "#153", "X", &dhcp_universe, 153 }, + { "#154", "X", &dhcp_universe, 154 }, + { "#155", "X", &dhcp_universe, 155 }, + { "#156", "X", &dhcp_universe, 156 }, + { "#157", "X", &dhcp_universe, 157 }, + { "#158", "X", &dhcp_universe, 158 }, + { "#159", "X", &dhcp_universe, 159 }, + { "#160", "X", &dhcp_universe, 160 }, + { "#161", "X", &dhcp_universe, 161 }, + { "#162", "X", &dhcp_universe, 162 }, + { "#163", "X", &dhcp_universe, 163 }, + { "#164", "X", &dhcp_universe, 164 }, + { "#165", "X", &dhcp_universe, 165 }, + { "#166", "X", &dhcp_universe, 166 }, + { "#167", "X", &dhcp_universe, 167 }, + { "#168", "X", &dhcp_universe, 168 }, + { "#169", "X", &dhcp_universe, 169 }, + { "#170", "X", &dhcp_universe, 170 }, + { "#171", "X", &dhcp_universe, 171 }, + { "#172", "X", &dhcp_universe, 172 }, + { "#173", "X", &dhcp_universe, 173 }, + { "#174", "X", &dhcp_universe, 174 }, + { "#175", "X", &dhcp_universe, 175 }, + { "#176", "X", &dhcp_universe, 176 }, + { "#177", "X", &dhcp_universe, 177 }, + { "#178", "X", &dhcp_universe, 178 }, + { "#179", "X", &dhcp_universe, 179 }, + { "#180", "X", &dhcp_universe, 180 }, + { "#181", "X", &dhcp_universe, 181 }, + { "#182", "X", &dhcp_universe, 182 }, + { "#183", "X", &dhcp_universe, 183 }, + { "#184", "X", &dhcp_universe, 184 }, + { "#185", "X", &dhcp_universe, 185 }, + { "#186", "X", &dhcp_universe, 186 }, + { "#187", "X", &dhcp_universe, 187 }, + { "#188", "X", &dhcp_universe, 188 }, + { "#189", "X", &dhcp_universe, 189 }, + { "#190", "X", &dhcp_universe, 190 }, + { "#191", "X", &dhcp_universe, 191 }, + { "#192", "X", &dhcp_universe, 192 }, + { "#193", "X", &dhcp_universe, 193 }, + { "#194", "X", &dhcp_universe, 194 }, + { "#195", "X", &dhcp_universe, 195 }, + { "#196", "X", &dhcp_universe, 196 }, + { "#197", "X", &dhcp_universe, 197 }, + { "#198", "X", &dhcp_universe, 198 }, + { "#199", "X", &dhcp_universe, 199 }, + { "#200", "X", &dhcp_universe, 200 }, + { "#201", "X", &dhcp_universe, 201 }, + { "#202", "X", &dhcp_universe, 202 }, + { "#203", "X", &dhcp_universe, 203 }, + { "#204", "X", &dhcp_universe, 204 }, + { "#205", "X", &dhcp_universe, 205 }, + { "#206", "X", &dhcp_universe, 206 }, + { "#207", "X", &dhcp_universe, 207 }, + { "#208", "X", &dhcp_universe, 208 }, + { "#209", "X", &dhcp_universe, 209 }, + { "authenticate", "X", &dhcp_universe, 210 }, + { "#211", "X", &dhcp_universe, 211 }, + { "#212", "X", &dhcp_universe, 212 }, + { "#213", "X", &dhcp_universe, 213 }, + { "#214", "X", &dhcp_universe, 214 }, + { "#215", "X", &dhcp_universe, 215 }, + { "#216", "X", &dhcp_universe, 216 }, + { "#217", "X", &dhcp_universe, 217 }, + { "#218", "X", &dhcp_universe, 218 }, + { "#219", "X", &dhcp_universe, 219 }, + { "#220", "X", &dhcp_universe, 220 }, + { "#221", "X", &dhcp_universe, 221 }, + { "#222", "X", &dhcp_universe, 222 }, + { "#223", "X", &dhcp_universe, 223 }, + { "#224", "X", &dhcp_universe, 224 }, + { "#225", "X", &dhcp_universe, 225 }, + { "#226", "X", &dhcp_universe, 226 }, + { "#227", "X", &dhcp_universe, 227 }, + { "#228", "X", &dhcp_universe, 228 }, + { "#229", "X", &dhcp_universe, 229 }, + { "#230", "X", &dhcp_universe, 230 }, + { "#231", "X", &dhcp_universe, 231 }, + { "#232", "X", &dhcp_universe, 232 }, + { "#233", "X", &dhcp_universe, 233 }, + { "#234", "X", &dhcp_universe, 234 }, + { "#235", "X", &dhcp_universe, 235 }, + { "#236", "X", &dhcp_universe, 236 }, + { "#237", "X", &dhcp_universe, 237 }, + { "#238", "X", &dhcp_universe, 238 }, + { "#239", "X", &dhcp_universe, 239 }, + { "#240", "X", &dhcp_universe, 240 }, + { "#241", "X", &dhcp_universe, 241 }, + { "#242", "X", &dhcp_universe, 242 }, + { "#243", "X", &dhcp_universe, 243 }, + { "#244", "X", &dhcp_universe, 244 }, + { "#245", "X", &dhcp_universe, 245 }, + { "#246", "X", &dhcp_universe, 246 }, + { "#247", "X", &dhcp_universe, 247 }, + { "#248", "X", &dhcp_universe, 248 }, + { "#249", "X", &dhcp_universe, 249 }, + { "#250", "X", &dhcp_universe, 250 }, + { "#251", "X", &dhcp_universe, 251 }, + { "#252", "X", &dhcp_universe, 252 }, + { "#253", "X", &dhcp_universe, 253 }, + { "#254", "X", &dhcp_universe, 254 }, { "option-end", "e", &dhcp_universe, 255 }, }; -/* Default dhcp option priority list (this is ad hoc and should not be - mistaken for a carefully crafted and optimized list). */ -unsigned char dhcp_option_default_priority_list [] = { - DHO_DHCP_REQUESTED_ADDRESS, - DHO_DHCP_OPTION_OVERLOAD, - DHO_DHCP_MAX_MESSAGE_SIZE, - DHO_DHCP_RENEWAL_TIME, - DHO_DHCP_REBINDING_TIME, - DHO_DHCP_CLASS_IDENTIFIER, - DHO_DHCP_CLIENT_IDENTIFIER, - DHO_SUBNET_MASK, - DHO_TIME_OFFSET, - DHO_ROUTERS, - DHO_TIME_SERVERS, - DHO_NAME_SERVERS, - DHO_DOMAIN_NAME_SERVERS, - DHO_HOST_NAME, - DHO_LOG_SERVERS, - DHO_COOKIE_SERVERS, - DHO_LPR_SERVERS, - DHO_IMPRESS_SERVERS, - DHO_RESOURCE_LOCATION_SERVERS, - DHO_HOST_NAME, - DHO_BOOT_SIZE, - DHO_MERIT_DUMP, - DHO_DOMAIN_NAME, - DHO_SWAP_SERVER, - DHO_ROOT_PATH, - DHO_EXTENSIONS_PATH, - DHO_IP_FORWARDING, - DHO_NON_LOCAL_SOURCE_ROUTING, - DHO_POLICY_FILTER, - DHO_MAX_DGRAM_REASSEMBLY, - DHO_DEFAULT_IP_TTL, - DHO_PATH_MTU_AGING_TIMEOUT, - DHO_PATH_MTU_PLATEAU_TABLE, - DHO_INTERFACE_MTU, - DHO_ALL_SUBNETS_LOCAL, - DHO_BROADCAST_ADDRESS, - DHO_PERFORM_MASK_DISCOVERY, - DHO_MASK_SUPPLIER, - DHO_ROUTER_DISCOVERY, - DHO_ROUTER_SOLICITATION_ADDRESS, - DHO_STATIC_ROUTES, - DHO_TRAILER_ENCAPSULATION, - DHO_ARP_CACHE_TIMEOUT, - DHO_IEEE802_3_ENCAPSULATION, - DHO_DEFAULT_TCP_TTL, - DHO_TCP_KEEPALIVE_INTERVAL, - DHO_TCP_KEEPALIVE_GARBAGE, - DHO_NIS_DOMAIN, - DHO_NIS_SERVERS, - DHO_NTP_SERVERS, - DHO_VENDOR_ENCAPSULATED_OPTIONS, - DHO_NETBIOS_NAME_SERVERS, - DHO_NETBIOS_DD_SERVER, - DHO_NETBIOS_NODE_TYPE, - DHO_NETBIOS_SCOPE, - DHO_FONT_SERVERS, - DHO_X_DISPLAY_MANAGER, - DHO_DHCP_PARAMETER_REQUEST_LIST, - - /* Presently-undefined options... */ - 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, - 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, - 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, - 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, - 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, - 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, - 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, - 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, - 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, - 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, - 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, - 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, - 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, - 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, - 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, - 251, 252, 253, 254, +struct universe nwip_universe; +struct option nwip_options [256] = { + { "pad", "", &nwip_universe, 0 }, + { "illegal-1", "", &nwip_universe, 1 }, + { "illegal-2", "", &nwip_universe, 2 }, + { "illegal-3", "", &nwip_universe, 3 }, + { "illegal-4", "", &nwip_universe, 4 }, + { "nsq-broadcast", "f", &nwip_universe, 5 }, + { "preferred-dss", "IA", &nwip_universe, 6 }, + { "nearest-nwip-server", "IA", &nwip_universe, 7 }, + { "autoretries", "B", &nwip_universe, 8 }, + { "autoretry-secs", "B", &nwip_universe, 9 }, + { "nwip-1-1", "f", &nwip_universe, 10 }, + { "primary-dss", "I", &nwip_universe, 11 }, + { "#12", "X", &nwip_universe, 12 }, + { "#13", "X", &nwip_universe, 13 }, + { "#14", "X", &nwip_universe, 14 }, + { "#15", "X", &nwip_universe, 15 }, + { "#16", "X", &nwip_universe, 16 }, + { "#17", "X", &nwip_universe, 17 }, + { "#18", "X", &nwip_universe, 18 }, + { "#19", "X", &nwip_universe, 19 }, + { "#20", "X", &nwip_universe, 20 }, + { "#21", "X", &nwip_universe, 21 }, + { "#22", "X", &nwip_universe, 22 }, + { "#23", "X", &nwip_universe, 23 }, + { "#24", "X", &nwip_universe, 24 }, + { "#25", "X", &nwip_universe, 25 }, + { "#26", "X", &nwip_universe, 26 }, + { "#27", "X", &nwip_universe, 27 }, + { "#28", "X", &nwip_universe, 28 }, + { "#29", "X", &nwip_universe, 29 }, + { "#30", "X", &nwip_universe, 30 }, + { "#31", "X", &nwip_universe, 31 }, + { "#32", "X", &nwip_universe, 32 }, + { "#33", "X", &nwip_universe, 33 }, + { "#34", "X", &nwip_universe, 34 }, + { "#35", "X", &nwip_universe, 35 }, + { "#36", "X", &nwip_universe, 36 }, + { "#37", "X", &nwip_universe, 37 }, + { "#38", "X", &nwip_universe, 38 }, + { "#39", "X", &nwip_universe, 39 }, + { "#40", "X", &nwip_universe, 40 }, + { "#41", "X", &nwip_universe, 41 }, + { "#42", "X", &nwip_universe, 42 }, + { "#43", "X", &nwip_universe, 43 }, + { "#44", "X", &nwip_universe, 44 }, + { "#45", "X", &nwip_universe, 45 }, + { "#46", "X", &nwip_universe, 46 }, + { "#47", "X", &nwip_universe, 47 }, + { "#48", "X", &nwip_universe, 48 }, + { "#49", "X", &nwip_universe, 49 }, + { "#50", "X", &nwip_universe, 50 }, + { "#51", "X", &nwip_universe, 51 }, + { "#52", "X", &nwip_universe, 52 }, + { "#53", "X", &nwip_universe, 53 }, + { "#54", "X", &nwip_universe, 54 }, + { "#55", "X", &nwip_universe, 55 }, + { "#56", "X", &nwip_universe, 56 }, + { "#57", "X", &nwip_universe, 57 }, + { "#58", "X", &nwip_universe, 58 }, + { "#59", "X", &nwip_universe, 59 }, + { "#60", "X", &nwip_universe, 60 }, + { "#61", "X", &nwip_universe, 61 }, + { "#62", "X", &nwip_universe, 62 }, + { "#63", "X", &nwip_universe, 63 }, + { "#64", "X", &nwip_universe, 64 }, + { "#65", "X", &nwip_universe, 65 }, + { "#66", "X", &nwip_universe, 66 }, + { "#67", "X", &nwip_universe, 67 }, + { "#68", "X", &nwip_universe, 68 }, + { "#69", "X", &nwip_universe, 69 }, + { "#70", "X", &nwip_universe, 70 }, + { "#71", "X", &nwip_universe, 71 }, + { "#72", "X", &nwip_universe, 72 }, + { "#73", "X", &nwip_universe, 73 }, + { "#74", "X", &nwip_universe, 74 }, + { "#75", "X", &nwip_universe, 75 }, + { "#76", "X", &nwip_universe, 76 }, + { "#77", "X", &nwip_universe, 77 }, + { "#78", "X", &nwip_universe, 78 }, + { "#79", "X", &nwip_universe, 79 }, + { "#80", "X", &nwip_universe, 80 }, + { "#81", "X", &nwip_universe, 81 }, + { "#82", "X", &nwip_universe, 82 }, + { "#83", "X", &nwip_universe, 83 }, + { "#84", "X", &nwip_universe, 84 }, + { "#85", "X", &nwip_universe, 85 }, + { "#86", "X", &nwip_universe, 86 }, + { "#87", "X", &nwip_universe, 87 }, + { "#88", "X", &nwip_universe, 88 }, + { "#89", "X", &nwip_universe, 89 }, + { "#90", "X", &nwip_universe, 90 }, + { "#91", "X", &nwip_universe, 91 }, + { "#92", "X", &nwip_universe, 92 }, + { "#93", "X", &nwip_universe, 93 }, + { "#94", "X", &nwip_universe, 94 }, + { "#95", "X", &nwip_universe, 95 }, + { "#96", "X", &nwip_universe, 96 }, + { "#97", "X", &nwip_universe, 97 }, + { "#98", "X", &nwip_universe, 98 }, + { "#99", "X", &nwip_universe, 99 }, + { "#100", "X", &nwip_universe, 100 }, + { "#101", "X", &nwip_universe, 101 }, + { "#102", "X", &nwip_universe, 102 }, + { "#103", "X", &nwip_universe, 103 }, + { "#104", "X", &nwip_universe, 104 }, + { "#105", "X", &nwip_universe, 105 }, + { "#106", "X", &nwip_universe, 106 }, + { "#107", "X", &nwip_universe, 107 }, + { "#108", "X", &nwip_universe, 108 }, + { "#109", "X", &nwip_universe, 109 }, + { "#110", "X", &nwip_universe, 110 }, + { "#111", "X", &nwip_universe, 111 }, + { "#112", "X", &nwip_universe, 112 }, + { "#113", "X", &nwip_universe, 113 }, + { "#114", "X", &nwip_universe, 114 }, + { "#115", "X", &nwip_universe, 115 }, + { "#116", "X", &nwip_universe, 116 }, + { "#117", "X", &nwip_universe, 117 }, + { "#118", "X", &nwip_universe, 118 }, + { "#119", "X", &nwip_universe, 119 }, + { "#120", "X", &nwip_universe, 120 }, + { "#121", "X", &nwip_universe, 121 }, + { "#122", "X", &nwip_universe, 122 }, + { "#123", "X", &nwip_universe, 123 }, + { "#124", "X", &nwip_universe, 124 }, + { "#125", "X", &nwip_universe, 125 }, + { "#126", "X", &nwip_universe, 126 }, + { "#127", "X", &nwip_universe, 127 }, + { "#128", "X", &nwip_universe, 128 }, + { "#129", "X", &nwip_universe, 129 }, + { "#130", "X", &nwip_universe, 130 }, + { "#131", "X", &nwip_universe, 131 }, + { "#132", "X", &nwip_universe, 132 }, + { "#133", "X", &nwip_universe, 133 }, + { "#134", "X", &nwip_universe, 134 }, + { "#135", "X", &nwip_universe, 135 }, + { "#136", "X", &nwip_universe, 136 }, + { "#137", "X", &nwip_universe, 137 }, + { "#138", "X", &nwip_universe, 138 }, + { "#139", "X", &nwip_universe, 139 }, + { "#140", "X", &nwip_universe, 140 }, + { "#141", "X", &nwip_universe, 141 }, + { "#142", "X", &nwip_universe, 142 }, + { "#143", "X", &nwip_universe, 143 }, + { "#144", "X", &nwip_universe, 144 }, + { "#145", "X", &nwip_universe, 145 }, + { "#146", "X", &nwip_universe, 146 }, + { "#147", "X", &nwip_universe, 147 }, + { "#148", "X", &nwip_universe, 148 }, + { "#149", "X", &nwip_universe, 149 }, + { "#150", "X", &nwip_universe, 150 }, + { "#151", "X", &nwip_universe, 151 }, + { "#152", "X", &nwip_universe, 152 }, + { "#153", "X", &nwip_universe, 153 }, + { "#154", "X", &nwip_universe, 154 }, + { "#155", "X", &nwip_universe, 155 }, + { "#156", "X", &nwip_universe, 156 }, + { "#157", "X", &nwip_universe, 157 }, + { "#158", "X", &nwip_universe, 158 }, + { "#159", "X", &nwip_universe, 159 }, + { "#160", "X", &nwip_universe, 160 }, + { "#161", "X", &nwip_universe, 161 }, + { "#162", "X", &nwip_universe, 162 }, + { "#163", "X", &nwip_universe, 163 }, + { "#164", "X", &nwip_universe, 164 }, + { "#165", "X", &nwip_universe, 165 }, + { "#166", "X", &nwip_universe, 166 }, + { "#167", "X", &nwip_universe, 167 }, + { "#168", "X", &nwip_universe, 168 }, + { "#169", "X", &nwip_universe, 169 }, + { "#170", "X", &nwip_universe, 170 }, + { "#171", "X", &nwip_universe, 171 }, + { "#172", "X", &nwip_universe, 172 }, + { "#173", "X", &nwip_universe, 173 }, + { "#174", "X", &nwip_universe, 174 }, + { "#175", "X", &nwip_universe, 175 }, + { "#176", "X", &nwip_universe, 176 }, + { "#177", "X", &nwip_universe, 177 }, + { "#178", "X", &nwip_universe, 178 }, + { "#179", "X", &nwip_universe, 179 }, + { "#180", "X", &nwip_universe, 180 }, + { "#181", "X", &nwip_universe, 181 }, + { "#182", "X", &nwip_universe, 182 }, + { "#183", "X", &nwip_universe, 183 }, + { "#184", "X", &nwip_universe, 184 }, + { "#185", "X", &nwip_universe, 185 }, + { "#186", "X", &nwip_universe, 186 }, + { "#187", "X", &nwip_universe, 187 }, + { "#188", "X", &nwip_universe, 188 }, + { "#189", "X", &nwip_universe, 189 }, + { "#190", "X", &nwip_universe, 190 }, + { "#191", "X", &nwip_universe, 191 }, + { "#192", "X", &nwip_universe, 192 }, + { "#193", "X", &nwip_universe, 193 }, + { "#194", "X", &nwip_universe, 194 }, + { "#195", "X", &nwip_universe, 195 }, + { "#196", "X", &nwip_universe, 196 }, + { "#197", "X", &nwip_universe, 197 }, + { "#198", "X", &nwip_universe, 198 }, + { "#199", "X", &nwip_universe, 199 }, + { "#200", "X", &nwip_universe, 200 }, + { "#201", "X", &nwip_universe, 201 }, + { "#202", "X", &nwip_universe, 202 }, + { "#203", "X", &nwip_universe, 203 }, + { "#204", "X", &nwip_universe, 204 }, + { "#205", "X", &nwip_universe, 205 }, + { "#206", "X", &nwip_universe, 206 }, + { "#207", "X", &nwip_universe, 207 }, + { "#208", "X", &nwip_universe, 208 }, + { "#209", "X", &nwip_universe, 209 }, + { "#210", "X", &nwip_universe, 210 }, + { "#211", "X", &nwip_universe, 211 }, + { "#212", "X", &nwip_universe, 212 }, + { "#213", "X", &nwip_universe, 213 }, + { "#214", "X", &nwip_universe, 214 }, + { "#215", "X", &nwip_universe, 215 }, + { "#216", "X", &nwip_universe, 216 }, + { "#217", "X", &nwip_universe, 217 }, + { "#218", "X", &nwip_universe, 218 }, + { "#219", "X", &nwip_universe, 219 }, + { "#220", "X", &nwip_universe, 220 }, + { "#221", "X", &nwip_universe, 221 }, + { "#222", "X", &nwip_universe, 222 }, + { "#223", "X", &nwip_universe, 223 }, + { "#224", "X", &nwip_universe, 224 }, + { "#225", "X", &nwip_universe, 225 }, + { "#226", "X", &nwip_universe, 226 }, + { "#227", "X", &nwip_universe, 227 }, + { "#228", "X", &nwip_universe, 228 }, + { "#229", "X", &nwip_universe, 229 }, + { "#230", "X", &nwip_universe, 230 }, + { "#231", "X", &nwip_universe, 231 }, + { "#232", "X", &nwip_universe, 232 }, + { "#233", "X", &nwip_universe, 233 }, + { "#234", "X", &nwip_universe, 234 }, + { "#235", "X", &nwip_universe, 235 }, + { "#236", "X", &nwip_universe, 236 }, + { "#237", "X", &nwip_universe, 237 }, + { "#238", "X", &nwip_universe, 238 }, + { "#239", "X", &nwip_universe, 239 }, + { "#240", "X", &nwip_universe, 240 }, + { "#241", "X", &nwip_universe, 241 }, + { "#242", "X", &nwip_universe, 242 }, + { "#243", "X", &nwip_universe, 243 }, + { "#244", "X", &nwip_universe, 244 }, + { "#245", "X", &nwip_universe, 245 }, + { "#246", "X", &nwip_universe, 246 }, + { "#247", "X", &nwip_universe, 247 }, + { "#248", "X", &nwip_universe, 248 }, + { "#249", "X", &nwip_universe, 249 }, + { "#250", "X", &nwip_universe, 250 }, + { "#251", "X", &nwip_universe, 251 }, + { "#252", "X", &nwip_universe, 252 }, + { "#253", "X", &nwip_universe, 253 }, + { "#254", "X", &nwip_universe, 254 }, + { "#end", "e", &nwip_universe, 255 }, }; -int sizeof_dhcp_option_default_priority_list = - sizeof dhcp_option_default_priority_list; - +struct universe fqdn_universe; +struct option fqdn_options [256] = { + { "pad", "", &fqdn_universe, 0 }, + { "no-client-update", "f", &fqdn_universe, 1 }, + { "server-update", "f", &fqdn_universe, 2 }, + { "encoded", "f", &fqdn_universe, 3 }, + { "rcode1", "B", &fqdn_universe, 4 }, + { "rcode2", "B", &fqdn_universe, 5 }, + { "hostname", "t", &fqdn_universe, 6 }, + { "domainname", "t", &fqdn_universe, 7 }, + { "fqdn", "t", &fqdn_universe, 8 }, + { "#9", "X", &fqdn_universe, 9 }, + { "#10", "X", &fqdn_universe, 10 }, + { "#11", "X", &fqdn_universe, 11 }, + { "#12", "X", &fqdn_universe, 12 }, + { "#13", "X", &fqdn_universe, 13 }, + { "#14", "X", &fqdn_universe, 14 }, + { "#15", "X", &fqdn_universe, 15 }, + { "#16", "X", &fqdn_universe, 16 }, + { "#17", "X", &fqdn_universe, 17 }, + { "#18", "X", &fqdn_universe, 18 }, + { "#19", "X", &fqdn_universe, 19 }, + { "#20", "X", &fqdn_universe, 20 }, + { "#21", "X", &fqdn_universe, 21 }, + { "#22", "X", &fqdn_universe, 22 }, + { "#23", "X", &fqdn_universe, 23 }, + { "#24", "X", &fqdn_universe, 24 }, + { "#25", "X", &fqdn_universe, 25 }, + { "#26", "X", &fqdn_universe, 26 }, + { "#27", "X", &fqdn_universe, 27 }, + { "#28", "X", &fqdn_universe, 28 }, + { "#29", "X", &fqdn_universe, 29 }, + { "#30", "X", &fqdn_universe, 30 }, + { "#31", "X", &fqdn_universe, 31 }, + { "#32", "X", &fqdn_universe, 32 }, + { "#33", "X", &fqdn_universe, 33 }, + { "#34", "X", &fqdn_universe, 34 }, + { "#35", "X", &fqdn_universe, 35 }, + { "#36", "X", &fqdn_universe, 36 }, + { "#37", "X", &fqdn_universe, 37 }, + { "#38", "X", &fqdn_universe, 38 }, + { "#39", "X", &fqdn_universe, 39 }, + { "#40", "X", &fqdn_universe, 40 }, + { "#41", "X", &fqdn_universe, 41 }, + { "#42", "X", &fqdn_universe, 42 }, + { "#43", "X", &fqdn_universe, 43 }, + { "#44", "X", &fqdn_universe, 44 }, + { "#45", "X", &fqdn_universe, 45 }, + { "#46", "X", &fqdn_universe, 46 }, + { "#47", "X", &fqdn_universe, 47 }, + { "#48", "X", &fqdn_universe, 48 }, + { "#49", "X", &fqdn_universe, 49 }, + { "#50", "X", &fqdn_universe, 50 }, + { "#51", "X", &fqdn_universe, 51 }, + { "#52", "X", &fqdn_universe, 52 }, + { "#53", "X", &fqdn_universe, 53 }, + { "#54", "X", &fqdn_universe, 54 }, + { "#55", "X", &fqdn_universe, 55 }, + { "#56", "X", &fqdn_universe, 56 }, + { "#57", "X", &fqdn_universe, 57 }, + { "#58", "X", &fqdn_universe, 58 }, + { "#59", "X", &fqdn_universe, 59 }, + { "#60", "X", &fqdn_universe, 60 }, + { "#61", "X", &fqdn_universe, 61 }, + { "#62", "X", &fqdn_universe, 62 }, + { "#63", "X", &fqdn_universe, 63 }, + { "#64", "X", &fqdn_universe, 64 }, + { "#65", "X", &fqdn_universe, 65 }, + { "#66", "X", &fqdn_universe, 66 }, + { "#67", "X", &fqdn_universe, 67 }, + { "#68", "X", &fqdn_universe, 68 }, + { "#69", "X", &fqdn_universe, 69 }, + { "#70", "X", &fqdn_universe, 70 }, + { "#71", "X", &fqdn_universe, 71 }, + { "#72", "X", &fqdn_universe, 72 }, + { "#73", "X", &fqdn_universe, 73 }, + { "#74", "X", &fqdn_universe, 74 }, + { "#75", "X", &fqdn_universe, 75 }, + { "#76", "X", &fqdn_universe, 76 }, + { "#77", "X", &fqdn_universe, 77 }, + { "#78", "X", &fqdn_universe, 78 }, + { "#79", "X", &fqdn_universe, 79 }, + { "#80", "X", &fqdn_universe, 80 }, + { "#81", "X", &fqdn_universe, 81 }, + { "#82", "X", &fqdn_universe, 82 }, + { "#83", "X", &fqdn_universe, 83 }, + { "#84", "X", &fqdn_universe, 84 }, + { "#85", "X", &fqdn_universe, 85 }, + { "#86", "X", &fqdn_universe, 86 }, + { "#87", "X", &fqdn_universe, 87 }, + { "#88", "X", &fqdn_universe, 88 }, + { "#89", "X", &fqdn_universe, 89 }, + { "#90", "X", &fqdn_universe, 90 }, + { "#91", "X", &fqdn_universe, 91 }, + { "#92", "X", &fqdn_universe, 92 }, + { "#93", "X", &fqdn_universe, 93 }, + { "#94", "X", &fqdn_universe, 94 }, + { "#95", "X", &fqdn_universe, 95 }, + { "#96", "X", &fqdn_universe, 96 }, + { "#97", "X", &fqdn_universe, 97 }, + { "#98", "X", &fqdn_universe, 98 }, + { "#99", "X", &fqdn_universe, 99 }, + { "#100", "X", &fqdn_universe, 100 }, + { "#101", "X", &fqdn_universe, 101 }, + { "#102", "X", &fqdn_universe, 102 }, + { "#103", "X", &fqdn_universe, 103 }, + { "#104", "X", &fqdn_universe, 104 }, + { "#105", "X", &fqdn_universe, 105 }, + { "#106", "X", &fqdn_universe, 106 }, + { "#107", "X", &fqdn_universe, 107 }, + { "#108", "X", &fqdn_universe, 108 }, + { "#109", "X", &fqdn_universe, 109 }, + { "#110", "X", &fqdn_universe, 110 }, + { "#111", "X", &fqdn_universe, 111 }, + { "#112", "X", &fqdn_universe, 112 }, + { "#113", "X", &fqdn_universe, 113 }, + { "#114", "X", &fqdn_universe, 114 }, + { "#115", "X", &fqdn_universe, 115 }, + { "#116", "X", &fqdn_universe, 116 }, + { "#117", "X", &fqdn_universe, 117 }, + { "#118", "X", &fqdn_universe, 118 }, + { "#119", "X", &fqdn_universe, 119 }, + { "#120", "X", &fqdn_universe, 120 }, + { "#121", "X", &fqdn_universe, 121 }, + { "#122", "X", &fqdn_universe, 122 }, + { "#123", "X", &fqdn_universe, 123 }, + { "#124", "X", &fqdn_universe, 124 }, + { "#125", "X", &fqdn_universe, 125 }, + { "#126", "X", &fqdn_universe, 126 }, + { "#127", "X", &fqdn_universe, 127 }, + { "#128", "X", &fqdn_universe, 128 }, + { "#129", "X", &fqdn_universe, 129 }, + { "#130", "X", &fqdn_universe, 130 }, + { "#131", "X", &fqdn_universe, 131 }, + { "#132", "X", &fqdn_universe, 132 }, + { "#133", "X", &fqdn_universe, 133 }, + { "#134", "X", &fqdn_universe, 134 }, + { "#135", "X", &fqdn_universe, 135 }, + { "#136", "X", &fqdn_universe, 136 }, + { "#137", "X", &fqdn_universe, 137 }, + { "#138", "X", &fqdn_universe, 138 }, + { "#139", "X", &fqdn_universe, 139 }, + { "#140", "X", &fqdn_universe, 140 }, + { "#141", "X", &fqdn_universe, 141 }, + { "#142", "X", &fqdn_universe, 142 }, + { "#143", "X", &fqdn_universe, 143 }, + { "#144", "X", &fqdn_universe, 144 }, + { "#145", "X", &fqdn_universe, 145 }, + { "#146", "X", &fqdn_universe, 146 }, + { "#147", "X", &fqdn_universe, 147 }, + { "#148", "X", &fqdn_universe, 148 }, + { "#149", "X", &fqdn_universe, 149 }, + { "#150", "X", &fqdn_universe, 150 }, + { "#151", "X", &fqdn_universe, 151 }, + { "#152", "X", &fqdn_universe, 152 }, + { "#153", "X", &fqdn_universe, 153 }, + { "#154", "X", &fqdn_universe, 154 }, + { "#155", "X", &fqdn_universe, 155 }, + { "#156", "X", &fqdn_universe, 156 }, + { "#157", "X", &fqdn_universe, 157 }, + { "#158", "X", &fqdn_universe, 158 }, + { "#159", "X", &fqdn_universe, 159 }, + { "#160", "X", &fqdn_universe, 160 }, + { "#161", "X", &fqdn_universe, 161 }, + { "#162", "X", &fqdn_universe, 162 }, + { "#163", "X", &fqdn_universe, 163 }, + { "#164", "X", &fqdn_universe, 164 }, + { "#165", "X", &fqdn_universe, 165 }, + { "#166", "X", &fqdn_universe, 166 }, + { "#167", "X", &fqdn_universe, 167 }, + { "#168", "X", &fqdn_universe, 168 }, + { "#169", "X", &fqdn_universe, 169 }, + { "#170", "X", &fqdn_universe, 170 }, + { "#171", "X", &fqdn_universe, 171 }, + { "#172", "X", &fqdn_universe, 172 }, + { "#173", "X", &fqdn_universe, 173 }, + { "#174", "X", &fqdn_universe, 174 }, + { "#175", "X", &fqdn_universe, 175 }, + { "#176", "X", &fqdn_universe, 176 }, + { "#177", "X", &fqdn_universe, 177 }, + { "#178", "X", &fqdn_universe, 178 }, + { "#179", "X", &fqdn_universe, 179 }, + { "#180", "X", &fqdn_universe, 180 }, + { "#181", "X", &fqdn_universe, 181 }, + { "#182", "X", &fqdn_universe, 182 }, + { "#183", "X", &fqdn_universe, 183 }, + { "#184", "X", &fqdn_universe, 184 }, + { "#185", "X", &fqdn_universe, 185 }, + { "#186", "X", &fqdn_universe, 186 }, + { "#187", "X", &fqdn_universe, 187 }, + { "#188", "X", &fqdn_universe, 188 }, + { "#189", "X", &fqdn_universe, 189 }, + { "#190", "X", &fqdn_universe, 190 }, + { "#191", "X", &fqdn_universe, 191 }, + { "#192", "X", &fqdn_universe, 192 }, + { "#193", "X", &fqdn_universe, 193 }, + { "#194", "X", &fqdn_universe, 194 }, + { "#195", "X", &fqdn_universe, 195 }, + { "#196", "X", &fqdn_universe, 196 }, + { "#197", "X", &fqdn_universe, 197 }, + { "#198", "X", &fqdn_universe, 198 }, + { "#199", "X", &fqdn_universe, 199 }, + { "#200", "X", &fqdn_universe, 200 }, + { "#201", "X", &fqdn_universe, 201 }, + { "#202", "X", &fqdn_universe, 202 }, + { "#203", "X", &fqdn_universe, 203 }, + { "#204", "X", &fqdn_universe, 204 }, + { "#205", "X", &fqdn_universe, 205 }, + { "#206", "X", &fqdn_universe, 206 }, + { "#207", "X", &fqdn_universe, 207 }, + { "#208", "X", &fqdn_universe, 208 }, + { "#209", "X", &fqdn_universe, 209 }, + { "#210", "X", &fqdn_universe, 210 }, + { "#211", "X", &fqdn_universe, 211 }, + { "#212", "X", &fqdn_universe, 212 }, + { "#213", "X", &fqdn_universe, 213 }, + { "#214", "X", &fqdn_universe, 214 }, + { "#215", "X", &fqdn_universe, 215 }, + { "#216", "X", &fqdn_universe, 216 }, + { "#217", "X", &fqdn_universe, 217 }, + { "#218", "X", &fqdn_universe, 218 }, + { "#219", "X", &fqdn_universe, 219 }, + { "#220", "X", &fqdn_universe, 220 }, + { "#221", "X", &fqdn_universe, 221 }, + { "#222", "X", &fqdn_universe, 222 }, + { "#223", "X", &fqdn_universe, 223 }, + { "#224", "X", &fqdn_universe, 224 }, + { "#225", "X", &fqdn_universe, 225 }, + { "#226", "X", &fqdn_universe, 226 }, + { "#227", "X", &fqdn_universe, 227 }, + { "#228", "X", &fqdn_universe, 228 }, + { "#229", "X", &fqdn_universe, 229 }, + { "#230", "X", &fqdn_universe, 230 }, + { "#231", "X", &fqdn_universe, 231 }, + { "#232", "X", &fqdn_universe, 232 }, + { "#233", "X", &fqdn_universe, 233 }, + { "#234", "X", &fqdn_universe, 234 }, + { "#235", "X", &fqdn_universe, 235 }, + { "#236", "X", &fqdn_universe, 236 }, + { "#237", "X", &fqdn_universe, 237 }, + { "#238", "X", &fqdn_universe, 238 }, + { "#239", "X", &fqdn_universe, 239 }, + { "#240", "X", &fqdn_universe, 240 }, + { "#241", "X", &fqdn_universe, 241 }, + { "#242", "X", &fqdn_universe, 242 }, + { "#243", "X", &fqdn_universe, 243 }, + { "#244", "X", &fqdn_universe, 244 }, + { "#245", "X", &fqdn_universe, 245 }, + { "#246", "X", &fqdn_universe, 246 }, + { "#247", "X", &fqdn_universe, 247 }, + { "#248", "X", &fqdn_universe, 248 }, + { "#249", "X", &fqdn_universe, 249 }, + { "#250", "X", &fqdn_universe, 250 }, + { "#251", "X", &fqdn_universe, 251 }, + { "#252", "X", &fqdn_universe, 252 }, + { "#253", "X", &fqdn_universe, 253 }, + { "#254", "X", &fqdn_universe, 254 }, + { "#end", "e", &fqdn_universe, 255 }, +}; -char *hardware_types [] = { +const char *hardware_types [] = { "unknown-0", "ethernet", "unknown-2", @@ -667,26 +1135,115 @@ char *hardware_types [] = { "unknown-254", "unknown-255" }; +universe_hash_t *universe_hash; +struct universe **universes; +int universe_count, universe_max; +/* Universe containing names of configuration options, which, rather than + writing "option universe-name.option-name ...;", can be set by writing + "option-name ...;". */ -struct hash_table universe_hash; +struct universe *config_universe; -void initialize_universes() +void initialize_common_option_spaces() { int i; + universe_max = 10; + universes = ((struct universe **) + dmalloc (universe_max * sizeof (struct universe *), MDL)); + if (!universes) + log_fatal ("Can't allocate option space table."); + memset (universes, 0, universe_max * sizeof (struct universe *)); + + /* Set up the DHCP option universe... */ dhcp_universe.name = "dhcp"; - dhcp_universe.hash = new_hash (); - if (!dhcp_universe.hash) - error ("Can't allocate dhcp option hash table."); + dhcp_universe.lookup_func = lookup_hashed_option; + dhcp_universe.option_state_dereference = + hashed_option_state_dereference; + dhcp_universe.save_func = save_hashed_option; + dhcp_universe.delete_func = delete_hashed_option; + dhcp_universe.encapsulate = hashed_option_space_encapsulate; + dhcp_universe.foreach = hashed_option_space_foreach; + dhcp_universe.decode = parse_option_buffer; + dhcp_universe.length_size = 1; + dhcp_universe.tag_size = 1; + dhcp_universe.store_tag = putUChar; + dhcp_universe.store_length = putUChar; + dhcp_universe.index = universe_count++; + universes [dhcp_universe.index] = &dhcp_universe; + if (!option_new_hash (&dhcp_universe.hash, 1, MDL)) + log_fatal ("Can't allocate dhcp option hash table."); for (i = 0; i < 256; i++) { dhcp_universe.options [i] = &dhcp_options [i]; - add_hash (dhcp_universe.hash, - (unsigned char *)dhcp_options [i].name, 0, - (unsigned char *)&dhcp_options [i]); + option_hash_add (dhcp_universe.hash, + dhcp_options [i].name, 0, + &dhcp_options [i], MDL); + } + + /* Set up the Novell option universe (for option 63)... */ + nwip_universe.name = "nwip"; + nwip_universe.lookup_func = lookup_linked_option; + nwip_universe.option_state_dereference = + linked_option_state_dereference; + nwip_universe.save_func = save_linked_option; + nwip_universe.delete_func = delete_linked_option; + nwip_universe.encapsulate = nwip_option_space_encapsulate; + nwip_universe.foreach = linked_option_space_foreach; + nwip_universe.decode = parse_option_buffer; + nwip_universe.length_size = 1; + nwip_universe.tag_size = 1; + nwip_universe.store_tag = putUChar; + nwip_universe.store_length = putUChar; + fqdn_universe.enc_opt = &dhcp_options [DHO_NWIP_SUBOPTIONS]; + nwip_universe.index = universe_count++; + universes [nwip_universe.index] = &nwip_universe; + option_new_hash (&nwip_universe.hash, 1, MDL); + if (!nwip_universe.hash) + log_fatal ("Can't allocate nwip option hash table."); + for (i = 0; i < 256; i++) { + nwip_universe.options [i] = &nwip_options [i]; + option_hash_add (nwip_universe.hash, + nwip_options [i].name, 0, + &nwip_options [i], MDL); + } + + /* Set up the FQDN option universe... */ + fqdn_universe.name = "fqdn"; + fqdn_universe.lookup_func = lookup_linked_option; + fqdn_universe.option_state_dereference = + linked_option_state_dereference; + fqdn_universe.save_func = save_linked_option; + fqdn_universe.delete_func = delete_linked_option; + fqdn_universe.encapsulate = fqdn_option_space_encapsulate; + fqdn_universe.foreach = linked_option_space_foreach; + fqdn_universe.decode = fqdn_universe_decode; + fqdn_universe.length_size = 1; + fqdn_universe.tag_size = 1; + fqdn_universe.store_tag = putUChar; + fqdn_universe.store_length = putUChar; + fqdn_universe.index = universe_count++; + fqdn_universe.enc_opt = &dhcp_options [DHO_FQDN]; + universes [fqdn_universe.index] = &fqdn_universe; + option_new_hash (&fqdn_universe.hash, 1, MDL); + if (!fqdn_universe.hash) + log_fatal ("Can't allocate fqdn option hash table."); + for (i = 0; i < 256; i++) { + fqdn_universe.options [i] = &fqdn_options [i]; + option_hash_add (fqdn_universe.hash, + fqdn_options [i].name, 0, + &fqdn_options [i], MDL); } - universe_hash.hash_count = DEFAULT_HASH_SIZE; - add_hash (&universe_hash, - (unsigned char *)dhcp_universe.name, 0, - (unsigned char *)&dhcp_universe); + + /* Set up the hash of universes. */ + universe_new_hash (&universe_hash, 1, MDL); + universe_hash_add (universe_hash, + dhcp_universe.name, 0, + &dhcp_universe, MDL); + universe_hash_add (universe_hash, + nwip_universe.name, 0, + &nwip_universe, MDL); + universe_hash_add (universe_hash, + fqdn_universe.name, 0, + &fqdn_universe, MDL); } diff --git a/contrib/isc-dhcp/common/tr.c b/contrib/isc-dhcp/common/tr.c index b19c183..3352d0a 100644 --- a/contrib/isc-dhcp/common/tr.c +++ b/contrib/isc-dhcp/common/tr.c @@ -1,8 +1,45 @@ +/* tr.c + + token ring interface support + Contributed in May of 1999 by Andrew Chittenden */ + /* - * packet_tr.c - token ring interface code, contributed in May of 1999 - * by Andrew Chittenden + * Copyright (c) 1996-2000 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ +#ifndef lint +static char copyright[] = +"$Id: tr.c,v 1.7 2001/04/27 22:23:02 mellon Exp $ Copyright (c) 1996-2000 The Internet Software Consortium. All rights reserved.\n"; +#endif /* not lint */ + #include "dhcpd.h" #if defined (HAVE_TR_SUPPORT) && \ @@ -44,7 +81,7 @@ static struct timeval routing_timer; void assemble_tr_header (interface, buf, bufix, to) struct interface_info *interface; unsigned char *buf; - int *bufix; + unsigned *bufix; struct hardware *to; { struct trh_hdr *trh; @@ -54,14 +91,14 @@ void assemble_tr_header (interface, buf, bufix, to) /* set up the token header */ trh = (struct trh_hdr *) &buf[*bufix]; - if (interface -> hw_address.hlen == sizeof (trh->saddr)) - memcpy (trh->saddr, interface -> hw_address.haddr, + if (interface -> hw_address.hlen - 1 == sizeof (trh->saddr)) + memcpy (trh->saddr, &interface -> hw_address.hbuf [1], sizeof (trh->saddr)); else memset (trh->saddr, 0x00, sizeof (trh->saddr)); - if (to && to -> hlen == 6) /* XXX */ - memcpy (trh->daddr, to -> haddr, sizeof trh->daddr); + if (to && to -> hlen == 7) /* XXX */ + memcpy (trh->daddr, &to -> hbuf [1], sizeof trh->daddr); else memset (trh->daddr, 0xff, sizeof (trh->daddr)); @@ -97,7 +134,7 @@ static unsigned char tr_broadcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; ssize_t decode_tr_header (interface, buf, bufix, from) struct interface_info *interface; unsigned char *buf; - int bufix; + unsigned bufix; struct hardware *from; { struct trh_hdr *trh = (struct trh_hdr *) buf + bufix; @@ -143,14 +180,14 @@ ssize_t decode_tr_header (interface, buf, bufix, from) * filter code in bpf.c */ llc = (struct trllc *)(buf + bufix + hdr_len); ip = (struct ip *) (llc + 1); - udp = (struct udphdr *) ((unsigned char*) ip + ip->ip_hl * 4); + udp = (struct udphdr *) ((unsigned char*) ip + IP_HL (ip)); /* make sure it is a snap encoded, IP, UDP, unfragmented packet sent * to our port */ if (llc->dsap != EXTENDED_SAP || ntohs(llc->ethertype) != ETHERTYPE_IP || ip->ip_p != IPPROTO_UDP - || (ip->ip_off & IP_OFFMASK) != 0 + || (ntohs (ip->ip_off) & IP_OFFMASK) != 0 || udp->uh_dport != local_port) return -1; @@ -241,8 +278,8 @@ static void save_source_routing(trh, interface) /* found an entry so update it with fresh information */ if (rover != NULL) { - if ((trh->saddr[0] & TR_RII) - && (((ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8) > 2)) { + if ((trh->saddr[0] & TR_RII) && + ((ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8) > 2) { rcf = ntohs(trh->rcf); rcf &= ~TR_RCF_BROADCAST_MASK; memcpy(rover->rseg, trh->rseg, sizeof(rover->rseg)); @@ -253,7 +290,7 @@ static void save_source_routing(trh, interface) } /* no entry found, so create one */ - rover = malloc(sizeof(struct routing_entry)); + rover = dmalloc (sizeof (struct routing_entry), MDL); if (rover == NULL) { fprintf(stderr, "%s: unable to save source routing information\n", @@ -294,7 +331,7 @@ static void expire_routes() while((rover = *prover) != NULL) { if ((now.tv_sec - rover->access_time) > routing_timeout) { *prover = rover->next; - free(rover); + dfree (rover, MDL); } else prover = &rover->next; } diff --git a/contrib/isc-dhcp/common/tree.c b/contrib/isc-dhcp/common/tree.c index ac83d67..a9254cc 100644 --- a/contrib/isc-dhcp/common/tree.c +++ b/contrib/isc-dhcp/common/tree.c @@ -3,7 +3,7 @@ Routines for manipulating parse trees... */ /* - * Copyright (c) 1995, 1996, 1997 The Internet Software Consortium. + * Copyright (c) 1995-2001 Internet Software Consortium. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,281 +34,317 @@ * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium - * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie - * Enterprises. To learn more about the Internet Software Consortium, - * see ``http://www.vix.com/isc''. To learn more about Vixie - * Enterprises, see ``http://www.vix.com''. + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. */ #ifndef lint static char copyright[] = -"$Id: tree.c,v 1.10 1997/05/09 08:14:57 mellon Exp $ Copyright (c) 1995, 1996, 1997 The Internet Software Consortium. All rights reserved.\n"; +"$Id: tree.c,v 1.101.2.6 2001/10/18 20:12:16 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" +#include <omapip/omapip_p.h> -static TIME tree_evaluate_recurse PROTO ((int *, unsigned char **, int *, - struct tree *)); -static TIME do_host_lookup PROTO ((int *, unsigned char **, int *, - struct dns_host_entry *)); -static void do_data_copy PROTO ((int *, unsigned char **, int *, - unsigned char *, int)); +struct binding_scope *global_scope; + +static int do_host_lookup PROTO ((struct data_string *, + struct dns_host_entry *)); + +#ifdef NSUPDATE +struct __res_state resolver_state; +int resolver_inited = 0; +#endif pair cons (car, cdr) caddr_t car; pair cdr; { - pair foo = (pair)dmalloc (sizeof *foo, "cons"); + pair foo = (pair)dmalloc (sizeof *foo, MDL); if (!foo) - error ("no memory for cons."); + log_fatal ("no memory for cons."); foo -> car = car; foo -> cdr = cdr; return foo; } -struct tree_cache *tree_cache (tree) - struct tree *tree; +int make_const_option_cache (oc, buffer, data, len, option, file, line) + struct option_cache **oc; + struct buffer **buffer; + u_int8_t *data; + unsigned len; + struct option *option; + const char *file; + int line; { - struct tree_cache *tc; + struct buffer *bp; + + if (buffer) { + bp = *buffer; + *buffer = 0; + } else { + bp = (struct buffer *)0; + if (!buffer_allocate (&bp, len, file, line)) { + log_error ("%s(%d): can't allocate buffer.", + file, line); + return 0; + } + } - tc = new_tree_cache ("tree_cache"); - if (!tc) + if (!option_cache_allocate (oc, file, line)) { + log_error ("%s(%d): can't allocate option cache.", file, line); + buffer_dereference (&bp, file, line); return 0; - tc -> value = (unsigned char *)0; - tc -> len = tc -> buf_size = 0; - tc -> timeout = 0; - tc -> tree = tree; - return tc; + } + + (*oc) -> data.len = len; + (*oc) -> data.buffer = bp; + (*oc) -> data.data = &bp -> data [0]; + (*oc) -> data.terminated = 0; + if (data) + memcpy (&bp -> data [0], data, len); + (*oc) -> option = option; + return 1; } -struct tree *tree_host_lookup (name) - char *name; +int make_host_lookup (expr, name) + struct expression **expr; + const char *name; { - struct tree *nt; - nt = new_tree ("tree_host_lookup"); - if (!nt) - error ("No memory for host lookup tree node."); - nt -> op = TREE_HOST_LOOKUP; - nt -> data.host_lookup.host = enter_dns_host (name); - return nt; + if (!expression_allocate (expr, MDL)) { + log_error ("No memory for host lookup tree node."); + return 0; + } + (*expr) -> op = expr_host_lookup; + if (!enter_dns_host (&((*expr) -> data.host_lookup), name)) { + expression_dereference (expr, MDL); + return 0; + } + return 1; } -struct dns_host_entry *enter_dns_host (name) - char *name; +int enter_dns_host (dh, name) + struct dns_host_entry **dh; + const char *name; { - struct dns_host_entry *dh; - - if (!(dh = (struct dns_host_entry *)dmalloc - (sizeof (struct dns_host_entry), "enter_dns_host")) - || !(dh -> hostname = dmalloc (strlen (name) + 1, - "enter_dns_host"))) - error ("Can't allocate space for new host."); - strcpy (dh -> hostname, name); - dh -> data = (unsigned char *)0; - dh -> data_len = 0; - dh -> buf_len = 0; - dh -> timeout = 0; - return dh; + /* XXX This should really keep a hash table of hostnames + XXX and just add a new reference to a hostname that + XXX already exists, if possible, rather than creating + XXX a new structure. */ + if (!dns_host_entry_allocate (dh, name, MDL)) { + log_error ("Can't allocate space for new host."); + return 0; + } + return 1; } -struct tree *tree_const (data, len) - unsigned char *data; - int len; +int make_const_data (struct expression **expr, const unsigned char *data, + unsigned len, int terminated, int allocate, + const char *file, int line) { - struct tree *nt; - if (!(nt = new_tree ("tree_const")) - || !(nt -> data.const_val.data = - (unsigned char *)dmalloc (len, "tree_const"))) - error ("No memory for constant data tree node."); - nt -> op = TREE_CONST; - memcpy (nt -> data.const_val.data, data, len); - nt -> data.const_val.len = len; - return nt; + struct expression *nt; + + if (!expression_allocate (expr, file, line)) { + log_error ("No memory for make_const_data tree node."); + return 0; + } + nt = *expr; + + if (len) { + if (allocate) { + if (!buffer_allocate (&nt -> data.const_data.buffer, + len + terminated, file, line)) { + log_error ("Can't allocate const_data buffer"); + expression_dereference (expr, file, line); + return 0; + } + nt -> data.const_data.data = + &nt -> data.const_data.buffer -> data [0]; + memcpy (nt -> data.const_data.buffer -> data, + data, len + terminated); + } else + nt -> data.const_data.data = data; + nt -> data.const_data.terminated = terminated; + } else + nt -> data.const_data.data = 0; + + nt -> op = expr_const_data; + nt -> data.const_data.len = len; + return 1; } -struct tree *tree_concat (left, right) - struct tree *left, *right; +int make_const_int (expr, val) + struct expression **expr; + unsigned long val; { - struct tree *nt; + if (!expression_allocate (expr, MDL)) { + log_error ("No memory for make_const_int tree node."); + return 0; + } + + (*expr) -> op = expr_const_int; + (*expr) -> data.const_int = val; + return 1; +} +int make_concat (expr, left, right) + struct expression **expr; + struct expression *left, *right; +{ /* If we're concatenating a null tree to a non-null tree, just return the non-null tree; if both trees are null, return a null tree. */ - if (!left) - return right; - if (!right) - return left; - - /* If both trees are constant, combine them. */ - if (left -> op == TREE_CONST && right -> op == TREE_CONST) { - unsigned char *buf = dmalloc (left -> data.const_val.len - + right -> data.const_val.len, - "tree_concat"); - if (!buf) - error ("No memory to concatenate constants."); - memcpy (buf, left -> data.const_val.data, - left -> data.const_val.len); - memcpy (buf + left -> data.const_val.len, - right -> data.const_val.data, - right -> data.const_val.len); - dfree (left -> data.const_val.data, "tree_concat"); - dfree (right -> data.const_val.data, "tree_concat"); - left -> data.const_val.data = buf; - left -> data.const_val.len += right -> data.const_val.len; - free_tree (right, "tree_concat"); - return left; + if (!left) { + if (!right) + return 0; + expression_reference (expr, right, MDL); + return 1; + } + if (!right) { + expression_reference (expr, left, MDL); + return 1; } /* Otherwise, allocate a new node to concatenate the two. */ - if (!(nt = new_tree ("tree_concat"))) - error ("No memory for data tree concatenation node."); - nt -> op = TREE_CONCAT; - nt -> data.concat.left = left; - nt -> data.concat.right = right; - return nt; + if (!expression_allocate (expr, MDL)) { + log_error ("No memory for concatenation expression node."); + return 0; + } + + (*expr) -> op = expr_concat; + expression_reference (&(*expr) -> data.concat [0], left, MDL); + expression_reference (&(*expr) -> data.concat [1], right, MDL); + return 1; } -struct tree *tree_limit (tree, limit) - struct tree *tree; - int limit; +int make_encapsulation (expr, name) + struct expression **expr; + struct data_string *name; { - struct tree *rv; - - /* If the tree we're limiting is constant, limit it now. */ - if (tree -> op == TREE_CONST) { - if (tree -> data.const_val.len > limit) - tree -> data.const_val.len = limit; - return tree; + /* Allocate a new node to store the encapsulation. */ + if (!expression_allocate (expr, MDL)) { + log_error ("No memory for encapsulation expression node."); + return 0; } - - /* Otherwise, put in a node which enforces the limit on evaluation. */ - rv = new_tree ("tree_limit"); - if (!rv) - return (struct tree *)0; - rv -> op = TREE_LIMIT; - rv -> data.limit.tree = tree; - rv -> data.limit.limit = limit; - return rv; + + (*expr) -> op = expr_encapsulate; + data_string_copy (&(*expr) -> data.encapsulate, name, MDL); + return 1; } -int tree_evaluate (tree_cache) - struct tree_cache *tree_cache; +int make_substring (new, expr, offset, length) + struct expression **new; + struct expression *expr; + struct expression *offset; + struct expression *length; { - unsigned char *bp = tree_cache -> value; - int bc = tree_cache -> buf_size; - int bufix = 0; + /* Allocate an expression node to compute the substring. */ + if (!expression_allocate (new, MDL)) { + log_error ("no memory for substring expression."); + return 0; + } + (*new) -> op = expr_substring; + expression_reference (&(*new) -> data.substring.expr, expr, MDL); + expression_reference (&(*new) -> data.substring.offset, offset, MDL); + expression_reference (&(*new) -> data.substring.len, length, MDL); + return 1; +} - /* If there's no tree associated with this cache, it evaluates - to a constant and that was detected at startup. */ - if (!tree_cache -> tree) - return 1; +int make_limit (new, expr, limit) + struct expression **new; + struct expression *expr; + int limit; +{ + struct expression *rv; - /* Try to evaluate the tree without allocating more memory... */ - tree_cache -> timeout = tree_evaluate_recurse (&bufix, &bp, &bc, - tree_cache -> tree); + /* Allocate a node to enforce a limit on evaluation. */ + if (!expression_allocate (new, MDL)) + log_error ("no memory for limit expression"); + (*new) -> op = expr_substring; + expression_reference (&(*new) -> data.substring.expr, expr, MDL); - /* No additional allocation needed? */ - if (bufix <= bc) { - tree_cache -> len = bufix; - return 1; + /* Offset is a constant 0. */ + if (!expression_allocate (&(*new) -> data.substring.offset, MDL)) { + log_error ("no memory for limit offset expression"); + expression_dereference (new, MDL); + return 0; } + (*new) -> data.substring.offset -> op = expr_const_int; + (*new) -> data.substring.offset -> data.const_int = 0; - /* If we can't allocate more memory, return with what we - have (maybe nothing). */ - if (!(bp = (unsigned char *)dmalloc (bufix, "tree_evaluate"))) + /* Length is a constant: the specified limit. */ + if (!expression_allocate (&(*new) -> data.substring.len, MDL)) { + log_error ("no memory for limit length expression"); + expression_dereference (new, MDL); return 0; + } + (*new) -> data.substring.len -> op = expr_const_int; + (*new) -> data.substring.len -> data.const_int = limit; - /* Record the change in conditions... */ - bc = bufix; - bufix = 0; - - /* Note that the size of the result shouldn't change on the - second call to tree_evaluate_recurse, since we haven't - changed the ``current'' time. */ - tree_evaluate_recurse (&bufix, &bp, &bc, tree_cache -> tree); - - /* Free the old buffer if needed, then store the new buffer - location and size and return. */ - if (tree_cache -> value) - dfree (tree_cache -> value, "tree_evaluate"); - tree_cache -> value = bp; - tree_cache -> len = bufix; - tree_cache -> buf_size = bc; return 1; } -static TIME tree_evaluate_recurse (bufix, bufp, bufcount, tree) - int *bufix; - unsigned char **bufp; - int *bufcount; - struct tree *tree; +int option_cache (struct option_cache **oc, struct data_string *dp, + struct expression *expr, struct option *option, + const char *file, int line) { - int limit; - TIME t1, t2; - - switch (tree -> op) { - case TREE_CONCAT: - t1 = tree_evaluate_recurse (bufix, bufp, bufcount, - tree -> data.concat.left); - t2 = tree_evaluate_recurse (bufix, bufp, bufcount, - tree -> data.concat.right); - if (t1 > t2) - return t2; - return t1; - - case TREE_HOST_LOOKUP: - return do_host_lookup (bufix, bufp, bufcount, - tree -> data.host_lookup.host); - - case TREE_CONST: - do_data_copy (bufix, bufp, bufcount, - tree -> data.const_val.data, - tree -> data.const_val.len); - t1 = MAX_TIME; - return t1; - - case TREE_LIMIT: - limit = *bufix + tree -> data.limit.limit; - t1 = tree_evaluate_recurse (bufix, bufp, bufcount, - tree -> data.limit.tree); - *bufix = limit; - return t1; + if (!option_cache_allocate (oc, file, line)) + return 0; + if (dp) + data_string_copy (&(*oc) -> data, dp, file, line); + if (expr) + expression_reference (&(*oc) -> expression, expr, file, line); + (*oc) -> option = option; + return 1; +} - default: - warn ("Bad node id in tree: %d."); - t1 = MAX_TIME; - return t1; +int make_let (result, name) + struct executable_statement **result; + const char *name; +{ + if (!(executable_statement_allocate (result, MDL))) + return 0; + + (*result) -> op = let_statement; + (*result) -> data.let.name = dmalloc (strlen (name) + 1, MDL); + if (!(*result) -> data.let.name) { + executable_statement_dereference (result, MDL); + return 0; } + strcpy ((*result) -> data.let.name, name); + return 1; } - -static TIME do_host_lookup (bufix, bufp, bufcount, dns) - int *bufix; - unsigned char **bufp; - int *bufcount; + +static int do_host_lookup (result, dns) + struct data_string *result; struct dns_host_entry *dns; { struct hostent *h; - int i; - int new_len; + unsigned i, count; + unsigned new_len; #ifdef DEBUG_EVAL - debug ("time: now = %d dns = %d %d diff = %d", + log_debug ("time: now = %d dns = %d diff = %d", cur_time, dns -> timeout, cur_time - dns -> timeout); #endif /* If the record hasn't timed out, just copy the data and return. */ if (cur_time <= dns -> timeout) { #ifdef DEBUG_EVAL - debug ("easy copy: %x %d %x", - dns -> data, dns -> data_len, - dns -> data ? *(int *)(dns -> data) : 0); + log_debug ("easy copy: %d %s", + dns -> data.len, + (dns -> data.len > 4 + ? inet_ntoa (*(struct in_addr *)(dns -> data.data)) + : 0)); #endif - do_data_copy (bufix, bufp, bufcount, - dns -> data, dns -> data_len); - return dns -> timeout; + data_string_copy (result, &dns -> data, MDL); + return 1; } #ifdef DEBUG_EVAL - debug ("Looking up %s", dns -> hostname); + log_debug ("Looking up %s", dns -> hostname); #endif /* Otherwise, look it up... */ @@ -318,95 +354,3748 @@ static TIME do_host_lookup (bufix, bufp, bufcount, dns) switch (h_errno) { case HOST_NOT_FOUND: #endif - warn ("%s: host unknown.", dns -> hostname); + log_error ("%s: host unknown.", dns -> hostname); #ifndef NO_H_ERRNO break; case TRY_AGAIN: - warn ("%s: temporary name server failure", - dns -> hostname); + log_error ("%s: temporary name server failure", + dns -> hostname); break; case NO_RECOVERY: - warn ("%s: name server failed", dns -> hostname); + log_error ("%s: name server failed", dns -> hostname); break; case NO_DATA: - warn ("%s: no A record associated with address", - dns -> hostname); + log_error ("%s: no A record associated with address", + dns -> hostname); } #endif /* !NO_H_ERRNO */ /* Okay to try again after a minute. */ - return cur_time + 60; + dns -> timeout = cur_time + 60; + data_string_forget (&dns -> data, MDL); + return 0; } #ifdef DEBUG_EVAL - debug ("Lookup succeeded; first address is %x", - h -> h_addr_list [0]); + log_debug ("Lookup succeeded; first address is %s", + inet_ntoa (h -> h_addr_list [0])); #endif /* Count the number of addresses we got... */ - for (i = 0; h -> h_addr_list [i]; i++) + for (count = 0; h -> h_addr_list [count]; count++) ; + /* Dereference the old data, if any. */ + data_string_forget (&dns -> data, MDL); + /* Do we need to allocate more memory? */ - new_len = i * h -> h_length; - if (dns -> buf_len < i) { - unsigned char *buf = - (unsigned char *)dmalloc (new_len, "do_host_lookup"); - /* If we didn't get more memory, use what we have. */ - if (!buf) { - new_len = dns -> buf_len; - if (!dns -> buf_len) { - dns -> timeout = cur_time + 60; - return dns -> timeout; - } - } else { - if (dns -> data) - dfree (dns -> data, "do_host_lookup"); - dns -> data = buf; - dns -> buf_len = new_len; - } + new_len = count * h -> h_length; + if (!buffer_allocate (&dns -> data.buffer, new_len, MDL)) + { + log_error ("No memory for %s.", dns -> hostname); + return 0; } + dns -> data.data = &dns -> data.buffer -> data [0]; + dns -> data.len = new_len; + dns -> data.terminated = 0; + /* Addresses are conveniently stored one to the buffer, so we have to copy them out one at a time... :'( */ - for (i = 0; i < new_len / h -> h_length; i++) { - memcpy (dns -> data + h -> h_length * i, - h -> h_addr_list [i], h -> h_length); + for (i = 0; i < count; i++) { + memcpy (&dns -> data.buffer -> data [h -> h_length * i], + h -> h_addr_list [i], (unsigned)(h -> h_length)); } #ifdef DEBUG_EVAL - debug ("dns -> data: %x h -> h_addr_list [0]: %x", - *(int *)(dns -> data), h -> h_addr_list [0]); + log_debug ("dns -> data: %x h -> h_addr_list [0]: %x", + *(int *)(dns -> buffer), h -> h_addr_list [0]); #endif - dns -> data_len = new_len; - /* Set the timeout for an hour from now. + /* XXX Set the timeout for an hour from now. XXX This should really use the time on the DNS reply. */ dns -> timeout = cur_time + 3600; #ifdef DEBUG_EVAL - debug ("hard copy: %x %d %x", - dns -> data, dns -> data_len, *(int *)(dns -> data)); + log_debug ("hard copy: %d %s", dns -> data.len, + (dns -> data.len > 4 + ? inet_ntoa (*(struct in_addr *)(dns -> data.data)) : 0)); +#endif + data_string_copy (result, &dns -> data, MDL); + return 1; +} + +int evaluate_expression (result, packet, lease, client_state, + in_options, cfg_options, scope, expr, file, line) + struct binding_value **result; + struct packet *packet; + struct lease *lease; + struct client_state *client_state; + struct option_state *in_options; + struct option_state *cfg_options; + struct binding_scope **scope; + struct expression *expr; + const char *file; + int line; +{ + struct binding_value *bv; + int status; + struct binding *binding; + + bv = (struct binding_value *)0; + + if (expr -> op == expr_variable_reference) { + if (!scope || !*scope) + return 0; + + binding = find_binding (*scope, expr -> data.variable); + + if (binding && binding -> value) { + if (result) + binding_value_reference (result, + binding -> value, + file, line); + return 1; + } else + return 0; + } else if (expr -> op == expr_funcall) { + struct string_list *s; + struct expression *arg; + struct binding_scope *ns; + struct binding *nb; + + if (!scope || !*scope) { + log_error ("%s: no such function.", + expr -> data.funcall.name); + return 0; + } + + binding = find_binding (*scope, expr -> data.funcall.name); + + if (!binding || !binding -> value) { + log_error ("%s: no such function.", + expr -> data.funcall.name); + return 0; + } + if (binding -> value -> type != binding_function) { + log_error ("%s: not a function.", + expr -> data.funcall.name); + return 0; + } + + /* Create a new binding scope in which to define + the arguments to the function. */ + ns = (struct binding_scope *)0; + if (!binding_scope_allocate (&ns, MDL)) { + log_error ("%s: can't allocate argument scope.", + expr -> data.funcall.name); + return 0; + } + + arg = expr -> data.funcall.arglist; + s = binding -> value -> value.fundef -> args; + while (arg && s) { + nb = dmalloc (sizeof *nb, MDL); + if (!nb) { + blb: + binding_scope_dereference (&ns, MDL); + return 0; + } else { + memset (nb, 0, sizeof *nb); + nb -> name = dmalloc (strlen (s -> string) + 1, + MDL); + if (nb -> name) + strcpy (nb -> name, s -> string); + else { + dfree (nb, MDL); + nb = (struct binding *)0; + goto blb; + } + } + evaluate_expression (&nb -> value, packet, lease, + client_state, + in_options, cfg_options, scope, + arg -> data.arg.val, file, line); + nb -> next = ns -> bindings; + ns -> bindings = nb; + arg = arg -> data.arg.next; + s = s -> next; + } + if (arg) { + log_error ("%s: too many arguments.", + expr -> data.funcall.name); + binding_scope_dereference (&ns, MDL); + return 0; + } + if (s) { + log_error ("%s: too few arguments.", + expr -> data.funcall.name); + binding_scope_dereference (&ns, MDL); + return 0; + } + + if (scope && *scope) + binding_scope_reference (&ns -> outer, *scope, MDL); + + status = (execute_statements + (&bv, packet, + lease, client_state, in_options, cfg_options, &ns, + binding -> value -> value.fundef -> statements)); + binding_scope_dereference (&ns, MDL); + + if (!bv) + return 1; + } else if (is_boolean_expression (expr)) { + if (!binding_value_allocate (&bv, MDL)) + return 0; + bv -> type = binding_boolean; + status = (evaluate_boolean_expression + (&bv -> value.boolean, packet, lease, client_state, + in_options, cfg_options, scope, expr)); + } else if (is_numeric_expression (expr)) { + if (!binding_value_allocate (&bv, MDL)) + return 0; + bv -> type = binding_numeric; + status = (evaluate_numeric_expression + (&bv -> value.intval, packet, lease, client_state, + in_options, cfg_options, scope, expr)); + } else if (is_data_expression (expr)) { + if (!binding_value_allocate (&bv, MDL)) + return 0; + bv -> type = binding_data; + status = (evaluate_data_expression + (&bv -> value.data, packet, lease, client_state, + in_options, cfg_options, scope, expr, MDL)); + } else if (is_dns_expression (expr)) { +#if defined (NSUPDATE) + if (!binding_value_allocate (&bv, MDL)) + return 0; + bv -> type = binding_dns; + status = (evaluate_dns_expression + (&bv -> value.dns, packet, lease, client_state, + in_options, cfg_options, scope, expr)); +#endif + } else { + log_error ("%s: invalid expression type: %d", + "evaluate_expression", expr -> op); + return 0; + } + if (result && status) + binding_value_reference (result, bv, file, line); + binding_value_dereference (&bv, MDL); + + return status; +} + +int binding_value_dereference (struct binding_value **v, + const char *file, int line) +{ + struct binding_value *bv = *v; + + *v = (struct binding_value *)0; + + /* Decrement the reference count. If it's nonzero, we're + done. */ + --(bv -> refcnt); + rc_register (file, line, v, bv, bv -> refcnt, 1, RC_MISC); + if (bv -> refcnt > 0) + return 1; + if (bv -> refcnt < 0) { + log_error ("%s(%d): negative refcnt!", file, line); +#if defined (DEBUG_RC_HISTORY) + dump_rc_history (bv); +#endif +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + + switch (bv -> type) { + case binding_boolean: + case binding_numeric: + break; + case binding_data: + if (bv -> value.data.buffer) + data_string_forget (&bv -> value.data, file, line); + break; + case binding_dns: +#if defined (NSUPDATE) + if (bv -> value.dns) { + if (bv -> value.dns -> r_data) { + dfree (bv -> value.dns -> r_data_ephem, MDL); + bv -> value.dns -> r_data = (unsigned char *)0; + bv -> value.dns -> r_data_ephem = + (unsigned char *)0; + } + minires_freeupdrec (bv -> value.dns); + } + break; +#endif + default: + log_error ("%s(%d): invalid binding type: %d", + file, line, bv -> type); + return 0; + } + dfree (bv, file, line); + return 1; +} + +#if defined (NSUPDATE) +int evaluate_dns_expression (result, packet, lease, client_state, in_options, + cfg_options, scope, expr) + ns_updrec **result; + struct packet *packet; + struct lease *lease; + struct client_state *client_state; + struct option_state *in_options; + struct option_state *cfg_options; + struct binding_scope **scope; + struct expression *expr; +{ + ns_updrec *foo; + unsigned long ttl = 0; + char *tname; + struct data_string name, data; + int r0, r1, r2, r3; + + if (!result || *result) { + log_error ("evaluate_dns_expression called with non-null %s", + "result pointer"); +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + + switch (expr -> op) { +#if defined (NSUPDATE) + case expr_ns_add: + r0 = evaluate_numeric_expression (&ttl, packet, lease, + client_state, + in_options, cfg_options, + scope, + expr -> data.ns_add.ttl); + goto nsfinish; + + case expr_ns_exists: + ttl = 1; + + case expr_ns_delete: + case expr_ns_not_exists: + r0 = 1; + nsfinish: + memset (&name, 0, sizeof name); + r1 = evaluate_data_expression (&name, packet, lease, + client_state, + in_options, cfg_options, scope, + expr -> data.ns_add.rrname, + MDL); + if (r1) { + /* The result of the evaluation may or may not + be NUL-terminated, but we need it + terminated for sure, so we have to allocate + a buffer and terminate it. */ + tname = dmalloc (name.len + 1, MDL); + if (!tname) { + r2 = 0; + r1 = 0; + data_string_forget (&name, MDL); + } else { + memcpy (tname, name.data, name.len); + tname [name.len] = 0; + memset (&data, 0, sizeof data); + r2 = evaluate_data_expression + (&data, packet, lease, client_state, + in_options, cfg_options, scope, + expr -> data.ns_add.rrdata, MDL); + } + } else + r2 = 0; + if (r0 && r1 && (r2 || expr -> op != expr_ns_add)) { + *result = minires_mkupdrec (((expr -> op == expr_ns_add || + expr -> op == expr_ns_delete) + ? S_UPDATE : S_PREREQ), + tname, + expr -> data.ns_add.rrclass, + expr -> data.ns_add.rrtype, + ttl); + if (!*result) { + ngood: + if (r2) { + data_string_forget (&data, MDL); + r2 = 0; + } + } else { + if (data.len) { + /* As a special case, if we get exactly + four bytes of data, it's an IP address + represented as a 32-bit quantity, which + is actually what we *should* be getting + here. Because res_mkupdrec is currently + broken and expects a dotted quad, convert + it. This should be fixed when the new + resolver is merged. */ + if (data.len == 4) { + (*result) -> r_data_ephem = + dmalloc (16, MDL); + if (!(*result) -> r_data_ephem) + goto dpngood; + (*result) -> r_data = + (*result) -> r_data_ephem; + sprintf ((char *)(*result) -> r_data_ephem, + "%d.%d.%d.%d", + data.data [0], data.data [1], + data.data [2], data.data [3]); + (*result) -> r_size = + strlen ((const char *) + (*result) -> r_data); + } else { + (*result) -> r_size = data.len; + (*result) -> r_data_ephem = + dmalloc (data.len, MDL); + if (!(*result) -> r_data_ephem) { + dpngood: /* double plus ungood. */ + minires_freeupdrec (*result); + *result = 0; + goto ngood; + } + (*result) -> r_data = + (*result) -> r_data_ephem; + memcpy ((*result) -> r_data_ephem, + data.data, data.len); + } + } else { + (*result) -> r_data = 0; + (*result) -> r_size = 0; + } + switch (expr -> op) { + case expr_ns_add: + (*result) -> r_opcode = ADD; + break; + case expr_ns_delete: + (*result) -> r_opcode = DELETE; + break; + case expr_ns_exists: + (*result) -> r_opcode = YXRRSET; + break; + case expr_ns_not_exists: + (*result) -> r_opcode = NXRRSET; + break; + + /* Can't happen, but satisfy gcc. */ + default: + break; + } + } + } + if (r1) { + data_string_forget (&name, MDL); + dfree (tname, MDL); + } + if (r2) + data_string_forget (&data, MDL); + /* One flaw in the thinking here: an IP address and an + ASCII string both look like data expressions, but + for A records, we want an ASCII string, not a + binary IP address. Do I need to turn binary IP + addresses into a seperate type? */ + return (r0 && r1 && + (r2 || expr -> op != expr_ns_add) && *result); + +#else + case expr_ns_add: + case expr_ns_delete: + case expr_ns_exists: + case expr_ns_not_exists: + return 0; +#endif + case expr_funcall: + log_error ("%s: dns values for functions not supported.", + expr -> data.funcall.name); + break; + + case expr_variable_reference: + log_error ("%s: dns values for variables not supported.", + expr -> data.variable); + break; + + case expr_check: + case expr_equal: + case expr_not_equal: + case expr_and: + case expr_or: + case expr_not: + case expr_match: + case expr_static: + case expr_known: + case expr_exists: + case expr_variable_exists: + log_error ("Boolean opcode in evaluate_dns_expression: %d", + expr -> op); + return 0; + + case expr_none: + case expr_substring: + case expr_suffix: + case expr_option: + case expr_hardware: + case expr_const_data: + case expr_packet: + case expr_concat: + case expr_encapsulate: + case expr_host_lookup: + case expr_encode_int8: + case expr_encode_int16: + case expr_encode_int32: + case expr_binary_to_ascii: + case expr_reverse: + case expr_filename: + case expr_sname: + case expr_pick_first_value: + case expr_host_decl_name: + case expr_config_option: + case expr_leased_address: + case expr_null: + log_error ("Data opcode in evaluate_dns_expression: %d", + expr -> op); + return 0; + + case expr_extract_int8: + case expr_extract_int16: + case expr_extract_int32: + case expr_const_int: + case expr_lease_time: + case expr_dns_transaction: + case expr_add: + case expr_subtract: + case expr_multiply: + case expr_divide: + case expr_remainder: + case expr_binary_and: + case expr_binary_or: + case expr_binary_xor: + case expr_client_state: + log_error ("Numeric opcode in evaluate_dns_expression: %d", + expr -> op); + return 0; + + case expr_function: + log_error ("Function opcode in evaluate_dns_expression: %d", + expr -> op); + return 0; + + case expr_arg: + break; + } + + log_error ("Bogus opcode in evaluate_dns_expression: %d", + expr -> op); + return 0; +} +#endif /* defined (NSUPDATE) */ + +int evaluate_boolean_expression (result, packet, lease, client_state, + in_options, cfg_options, scope, expr) + int *result; + struct packet *packet; + struct lease *lease; + struct client_state *client_state; + struct option_state *in_options; + struct option_state *cfg_options; + struct binding_scope **scope; + struct expression *expr; +{ + struct data_string left, right; + struct data_string rrtype, rrname, rrdata; + unsigned long ttl; + int srrtype, srrname, srrdata, sttl; + int bleft, bright; + int sleft, sright; + struct binding *binding; + struct binding_value *bv, *obv; + + switch (expr -> op) { + case expr_check: + *result = check_collection (packet, lease, + expr -> data.check); +#if defined (DEBUG_EXPRESSIONS) + log_debug ("bool: check (%s) returns %s", + expr -> data.check -> name, + *result ? "true" : "false"); +#endif + return 1; + + case expr_equal: + case expr_not_equal: + bv = obv = (struct binding_value *)0; + sleft = evaluate_expression (&bv, packet, lease, client_state, + in_options, cfg_options, scope, + expr -> data.equal [0], MDL); + sright = evaluate_expression (&obv, packet, lease, + client_state, in_options, + cfg_options, scope, + expr -> data.equal [1], MDL); + if (sleft && sright) { + if (bv -> type != obv -> type) + *result = expr -> op == expr_not_equal; + else { + switch (obv -> type) { + case binding_boolean: + if (bv -> value.boolean == obv -> value.boolean) + *result = expr -> op == expr_equal; + else + *result = expr -> op == expr_not_equal; + break; + + case binding_data: + if ((bv -> value.data.len == + obv -> value.data.len) && + !memcmp (bv -> value.data.data, + obv -> value.data.data, + obv -> value.data.len)) + *result = expr -> op == expr_equal; + else + *result = expr -> op == expr_not_equal; + break; + + case binding_numeric: + if (bv -> value.intval == obv -> value.intval) + *result = expr -> op == expr_equal; + else + *result = expr -> op == expr_not_equal; + break; + + case binding_dns: +#if defined (NSUPDATE) + /* XXX This should be a comparison for equal + XXX values, not for identity. */ + if (bv -> value.dns == obv -> value.dns) + *result = expr -> op == expr_equal; + else + *result = expr -> op == expr_not_equal; +#else + *result = expr -> op == expr_not_equal; +#endif + break; + + case binding_function: + if (bv -> value.fundef == obv -> value.fundef) + *result = expr -> op == expr_equal; + else + *result = expr -> op == expr_not_equal; + break; + default: + *result = expr -> op == expr_not_equal; + break; + } + } + } else if (!sleft && !sright) + *result = expr -> op == expr_equal; + else + *result = expr -> op == expr_not_equal; + +#if defined (DEBUG_EXPRESSIONS) + log_debug ("bool: %sequal = %s", + expr -> op == expr_not_equal ? "not" : "", + (*result ? "true" : "false")); +#endif + if (sleft) + binding_value_dereference (&bv, MDL); + if (sright) + binding_value_dereference (&obv, MDL); + return 1; + + case expr_and: + sleft = evaluate_boolean_expression (&bleft, packet, lease, + client_state, + in_options, cfg_options, + scope, + expr -> data.and [0]); + if (sleft && bleft) + sright = evaluate_boolean_expression + (&bright, packet, lease, client_state, + in_options, cfg_options, + scope, expr -> data.and [1]); + else + sright = bright = 0; + +#if defined (DEBUG_EXPRESSIONS) + log_debug ("bool: and (%s, %s) = %s", + sleft ? (bleft ? "true" : "false") : "NULL", + sright ? (bright ? "true" : "false") : "NULL", + ((sleft && sright) + ? (bleft && bright ? "true" : "false") : "NULL")); +#endif + if (sleft && sright) { + *result = bleft && bright; + return 1; + } + return 0; + + case expr_or: + bleft = bright = 0; + sleft = evaluate_boolean_expression (&bleft, packet, lease, + client_state, + in_options, cfg_options, + scope, + expr -> data.or [0]); + if (!sleft || !bleft) + sright = evaluate_boolean_expression + (&bright, packet, lease, client_state, + in_options, cfg_options, + scope, expr -> data.or [1]); + else + sright = 0; +#if defined (DEBUG_EXPRESSIONS) + log_debug ("bool: or (%s, %s) = %s", + sleft ? (bleft ? "true" : "false") : "NULL", + sright ? (bright ? "true" : "false") : "NULL", + ((sleft || sright) + ? (bleft || bright ? "true" : "false") : "NULL")); +#endif + if (sleft || sright) { + *result = bleft || bright; + return 1; + } + return 0; + + case expr_not: + sleft = evaluate_boolean_expression (&bleft, packet, lease, + client_state, + in_options, cfg_options, + scope, + expr -> data.not); +#if defined (DEBUG_EXPRESSIONS) + log_debug ("bool: not (%s) = %s", + sleft ? (bleft ? "true" : "false") : "NULL", + ((sleft && sright) + ? (!bleft ? "true" : "false") : "NULL")); + +#endif + if (sleft) { + *result = !bleft; + return 1; + } + return 0; + + case expr_exists: + memset (&left, 0, sizeof left); + if (!in_options || + !get_option (&left, expr -> data.exists -> universe, + packet, lease, client_state, + in_options, cfg_options, in_options, + scope, expr -> data.exists -> code, MDL)) + *result = 0; + else { + *result = 1; + data_string_forget (&left, MDL); + } +#if defined (DEBUG_EXPRESSIONS) + log_debug ("bool: exists %s.%s = %s", + expr -> data.option -> universe -> name, + expr -> data.option -> name, + *result ? "true" : "false"); +#endif + return 1; + + case expr_known: + if (!packet) { +#if defined (DEBUG_EXPRESSIONS) + log_debug ("bool: known = NULL"); +#endif + return 0; + } +#if defined (DEBUG_EXPRESSIONS) + log_debug ("bool: known = %s", + packet -> known ? "true" : "false"); +#endif + *result = packet -> known; + return 1; + + case expr_static: + if (!lease || !(lease -> flags & STATIC_LEASE)) { +#if defined (DEBUG_EXPRESSIONS) + log_debug ("bool: static = false (%s %s %s %d)", + lease ? "y" : "n", + (lease && (lease -> flags & STATIC_LEASE) + ? "y" : "n"), + piaddr (lease -> ip_addr), + lease ? lease -> flags : 0); +#endif + *result = 0; + return 1; + } +#if defined (DEBUG_EXPRESSIONS) + log_debug ("bool: static = true"); +#endif + *result = 1; + return 1; + + case expr_variable_exists: + if (scope && *scope) { + binding = find_binding (*scope, expr -> data.variable); + + if (binding) { + if (binding -> value) + *result = 1; + else + *result = 0; + } else + *result = 0; + } else + *result = 0; +#if defined (DEBUG_EXPRESSIONS) + log_debug ("boolean: %s? = %s", expr -> data.variable, + *result ? "true" : "false"); +#endif + return 1; + + case expr_variable_reference: + if (scope && *scope) { + binding = find_binding (*scope, expr -> data.variable); + + if (binding && binding -> value) { + if (binding -> value -> type == + binding_boolean) { + *result = binding -> value -> value.boolean; + sleft = 1; + } else { + log_error ("binding type %d in %s.", + binding -> value -> type, + "evaluate_boolean_expression"); + sleft = 0; + } + } else + sleft = 0; + } else + sleft = 0; +#if defined (DEBUG_EXPRESSIONS) + log_debug ("boolean: %s = %s", expr -> data.variable, + sleft ? (*result ? "true" : "false") : "NULL"); +#endif + return sleft; + + case expr_funcall: + bv = (struct binding_value *)0; + sleft = evaluate_expression (&bv, packet, lease, client_state, + in_options, cfg_options, + scope, expr, MDL); + if (sleft) { + if (bv -> type != binding_boolean) + log_error ("%s() returned type %d in %s.", + expr -> data.funcall.name, + bv -> type, + "evaluate_boolean_expression"); + else + *result = bv -> value.boolean; + binding_value_dereference (&bv, MDL); + } +#if defined (DEBUG_EXPRESSIONS) + log_debug ("boolean: %s() = %s", expr -> data.funcall.name, + sleft ? (*result ? "true" : "false") : "NULL"); +#endif + break; + + case expr_none: + case expr_match: + case expr_substring: + case expr_suffix: + case expr_option: + case expr_hardware: + case expr_const_data: + case expr_packet: + case expr_concat: + case expr_encapsulate: + case expr_host_lookup: + case expr_encode_int8: + case expr_encode_int16: + case expr_encode_int32: + case expr_binary_to_ascii: + case expr_reverse: + case expr_pick_first_value: + case expr_host_decl_name: + case expr_config_option: + case expr_leased_address: + case expr_null: + case expr_filename: + case expr_sname: + log_error ("Data opcode in evaluate_boolean_expression: %d", + expr -> op); + return 0; + + case expr_extract_int8: + case expr_extract_int16: + case expr_extract_int32: + case expr_const_int: + case expr_lease_time: + case expr_dns_transaction: + case expr_add: + case expr_subtract: + case expr_multiply: + case expr_divide: + case expr_remainder: + case expr_binary_and: + case expr_binary_or: + case expr_binary_xor: + case expr_client_state: + log_error ("Numeric opcode in evaluate_boolean_expression: %d", + expr -> op); + return 0; + + case expr_ns_add: + case expr_ns_delete: + case expr_ns_exists: + case expr_ns_not_exists: + log_error ("dns opcode in evaluate_boolean_expression: %d", + expr -> op); + return 0; + + case expr_function: + log_error ("function definition in evaluate_boolean_expr"); + return 0; + + case expr_arg: + break; + } + + log_error ("Bogus opcode in evaluate_boolean_expression: %d", + expr -> op); + return 0; +} + +int evaluate_data_expression (result, packet, lease, client_state, + in_options, cfg_options, scope, expr, file, line) + struct data_string *result; + struct packet *packet; + struct lease *lease; + struct client_state *client_state; + struct option_state *in_options; + struct option_state *cfg_options; + struct binding_scope **scope; + struct expression *expr; + const char *file; + int line; +{ + struct data_string data, other; + unsigned long offset, len, i; + int s0, s1, s2, s3; + int status; + struct binding *binding; + char *s; + struct binding_value *bv; + + switch (expr -> op) { + /* Extract N bytes starting at byte M of a data string. */ + case expr_substring: + memset (&data, 0, sizeof data); + s0 = evaluate_data_expression (&data, packet, lease, + client_state, + in_options, cfg_options, scope, + expr -> data.substring.expr, + MDL); + + /* Evaluate the offset and length. */ + s1 = evaluate_numeric_expression + (&offset, packet, lease, client_state, in_options, + cfg_options, scope, expr -> data.substring.offset); + s2 = evaluate_numeric_expression (&len, packet, lease, + client_state, + in_options, cfg_options, + scope, + expr -> data.substring.len); + + if (s0 && s1 && s2) { + /* If the offset is after end of the string, + return an empty string. Otherwise, do the + adjustments and return what's left. */ + if (data.len > offset) { + data_string_copy (result, &data, file, line); + result -> len -= offset; + if (result -> len > len) { + result -> len = len; + result -> terminated = 0; + } + result -> data += offset; + } + s3 = 1; + } else + s3 = 0; + +#if defined (DEBUG_EXPRESSIONS) + log_debug ("data: substring (%s, %s, %s) = %s", + s0 ? print_hex_1 (data.len, data.data, 30) : "NULL", + s1 ? print_dec_1 (offset) : "NULL", + s2 ? print_dec_2 (len) : "NULL", + (s3 ? print_hex_2 (result -> len, result -> data, 30) + : "NULL")); +#endif + if (s0) + data_string_forget (&data, MDL); + if (s3) + return 1; + return 0; + + + /* Extract the last N bytes of a data string. */ + case expr_suffix: + memset (&data, 0, sizeof data); + s0 = evaluate_data_expression (&data, packet, lease, + client_state, + in_options, cfg_options, scope, + expr -> data.suffix.expr, MDL); + /* Evaluate the length. */ + s1 = evaluate_numeric_expression (&len, packet, lease, + client_state, + in_options, cfg_options, + scope, + expr -> data.suffix.len); + if (s0 && s1) { + data_string_copy (result, &data, file, line); + + /* If we are returning the last N bytes of a + string whose length is <= N, just return + the string - otherwise, compute a new + starting address and decrease the + length. */ + if (data.len > len) { + result -> data += data.len - len; + result -> len = len; + } + data_string_forget (&data, MDL); + } + +#if defined (DEBUG_EXPRESSIONS) + log_debug ("data: suffix (%s, %s) = %s", + s0 ? print_hex_1 (data.len, data.data, 30) : "NULL", + s1 ? print_dec_1 (len) : "NULL", + ((s0 && s1) + ? print_hex_2 (result -> len, result -> data, 30) + : "NULL")); +#endif + return s0 && s1; + + /* Extract an option. */ + case expr_option: + if (in_options) + s0 = get_option (result, + expr -> data.option -> universe, + packet, lease, client_state, + in_options, cfg_options, in_options, + scope, expr -> data.option -> code, + file, line); + else + s0 = 0; + +#if defined (DEBUG_EXPRESSIONS) + log_debug ("data: option %s.%s = %s", + expr -> data.option -> universe -> name, + expr -> data.option -> name, + s0 ? print_hex_1 (result -> len, result -> data, 60) + : "NULL"); +#endif + return s0; + + case expr_config_option: + if (cfg_options) + s0 = get_option (result, + expr -> data.option -> universe, + packet, lease, client_state, + in_options, cfg_options, cfg_options, + scope, expr -> data.option -> code, + file, line); + else + s0 = 0; + +#if defined (DEBUG_EXPRESSIONS) + log_debug ("data: config-option %s.%s = %s", + expr -> data.option -> universe -> name, + expr -> data.option -> name, + s0 ? print_hex_1 (result -> len, result -> data, 60) + : "NULL"); +#endif + return s0; + + /* Combine the hardware type and address. */ + case expr_hardware: + /* On the client, hardware is our hardware. */ + if (client_state) { + memset (result, 0, sizeof *result); + result -> data = + client_state -> interface -> hw_address.hbuf; + result -> len = + client_state -> interface -> hw_address.hlen; +#if defined (DEBUG_EXPRESSIONS) + log_debug ("data: hardware = %s", + print_hex_1 (result -> len, + result -> data, 60)); +#endif + return 1; + } + + /* The server cares about the client's hardware address, + so only in the case where we are examining a packet can + we return anything. */ + if (!packet || !packet -> raw) { + log_error ("data: hardware: raw packet not available"); + return 0; + } + if (packet -> raw -> hlen > sizeof packet -> raw -> chaddr) { + log_error ("data: hardware: invalid hlen (%d)\n", + packet -> raw -> hlen); + return 0; + } + result -> len = packet -> raw -> hlen + 1; + if (buffer_allocate (&result -> buffer, result -> len, + file, line)) { + result -> data = &result -> buffer -> data [0]; + result -> buffer -> data [0] = packet -> raw -> htype; + memcpy (&result -> buffer -> data [1], + packet -> raw -> chaddr, + packet -> raw -> hlen); + result -> terminated = 0; + } else { + log_error ("data: hardware: no memory for buffer."); + return 0; + } +#if defined (DEBUG_EXPRESSIONS) + log_debug ("data: hardware = %s", + print_hex_1 (result -> len, result -> data, 60)); +#endif + return 1; + + /* Extract part of the raw packet. */ + case expr_packet: + if (!packet || !packet -> raw) { + log_error ("data: packet: raw packet not available"); + return 0; + } + + s0 = evaluate_numeric_expression (&offset, packet, lease, + client_state, + in_options, cfg_options, + scope, + expr -> data.packet.offset); + s1 = evaluate_numeric_expression (&len, + packet, lease, client_state, + in_options, cfg_options, + scope, + expr -> data.packet.len); + if (s0 && s1 && offset < packet -> packet_length) { + if (offset + len > packet -> packet_length) + result -> len = + packet -> packet_length - offset; + else + result -> len = len; + if (buffer_allocate (&result -> buffer, + result -> len, file, line)) { + result -> data = &result -> buffer -> data [0]; + memcpy (result -> buffer -> data, + (((unsigned char *)(packet -> raw)) + + offset), result -> len); + result -> terminated = 0; + } else { + log_error ("data: packet: no buffer memory."); + return 0; + } + s2 = 1; + } else + s2 = 0; +#if defined (DEBUG_EXPRESSIONS) + log_debug ("data: packet (%ld, %ld) = %s", + offset, len, + s2 ? print_hex_1 (result -> len, + result -> data, 60) : NULL); +#endif + return s2; + + /* The encapsulation of all defined options in an + option space... */ + case expr_encapsulate: + if (cfg_options) + s0 = option_space_encapsulate + (result, packet, lease, client_state, + in_options, cfg_options, scope, + &expr -> data.encapsulate); + else + s0 = 0; + +#if defined (DEBUG_EXPRESSIONS) + log_debug ("data: encapsulate (%s) = %s", + expr -> data.encapsulate.data, + s0 ? print_hex_1 (result -> len, + result -> data, 60) : "NULL"); +#endif + return s0; + + /* Some constant data... */ + case expr_const_data: +#if defined (DEBUG_EXPRESSIONS) + log_debug ("data: const = %s", + print_hex_1 (expr -> data.const_data.len, + expr -> data.const_data.data, 60)); +#endif + data_string_copy (result, + &expr -> data.const_data, file, line); + return 1; + + /* Hostname lookup... */ + case expr_host_lookup: + s0 = do_host_lookup (result, expr -> data.host_lookup); +#if defined (DEBUG_EXPRESSIONS) + log_debug ("data: DNS lookup (%s) = %s", + expr -> data.host_lookup -> hostname, + (s0 + ? print_dotted_quads (result -> len, result -> data) + : "NULL")); +#endif + return s0; + + /* Concatenation... */ + case expr_concat: + memset (&data, 0, sizeof data); + s0 = evaluate_data_expression (&data, packet, lease, + client_state, + in_options, cfg_options, scope, + expr -> data.concat [0], MDL); + memset (&other, 0, sizeof other); + s1 = evaluate_data_expression (&other, packet, lease, + client_state, + in_options, cfg_options, scope, + expr -> data.concat [1], MDL); + + if (s0 && s1) { + result -> len = data.len + other.len; + if (!buffer_allocate (&result -> buffer, + (result -> len + other.terminated), + file, line)) { + log_error ("data: concat: no memory"); + result -> len = 0; + data_string_forget (&data, MDL); + data_string_forget (&other, MDL); + return 0; + } + result -> data = &result -> buffer -> data [0]; + memcpy (result -> buffer -> data, data.data, data.len); + memcpy (&result -> buffer -> data [data.len], + other.data, other.len + other.terminated); + } + + if (s0) + data_string_forget (&data, MDL); + if (s1) + data_string_forget (&other, MDL); +#if defined (DEBUG_EXPRESSIONS) + log_debug ("data: concat (%s, %s) = %s", + s0 ? print_hex_1 (data.len, data.data, 20) : "NULL", + s1 ? print_hex_2 (other.len, other.data, 20) : "NULL", + ((s0 && s1) + ? print_hex_3 (result -> len, result -> data, 30) + : "NULL")); +#endif + return s0 && s1; + + case expr_encode_int8: + s0 = evaluate_numeric_expression (&len, packet, lease, + client_state, + in_options, cfg_options, + scope, + expr -> data.encode_int); + if (s0) { + result -> len = 1; + if (!buffer_allocate (&result -> buffer, + 1, file, line)) { + log_error ("data: encode_int8: no memory"); + result -> len = 0; + s0 = 0; + } else { + result -> data = &result -> buffer -> data [0]; + result -> buffer -> data [0] = len; + } + } else + result -> len = 0; + +#if defined (DEBUG_EXPRESSIONS) + if (!s0) + log_debug ("data: encode_int8 (NULL) = NULL"); + else + log_debug ("data: encode_int8 (%ld) = %s", len, + print_hex_2 (result -> len, + result -> data, 20)); +#endif + return s0; + + + case expr_encode_int16: + s0 = evaluate_numeric_expression (&len, packet, lease, + client_state, + in_options, cfg_options, + scope, + expr -> data.encode_int); + if (s0) { + result -> len = 2; + if (!buffer_allocate (&result -> buffer, 2, + file, line)) { + log_error ("data: encode_int16: no memory"); + result -> len = 0; + s0 = 0; + } else { + result -> data = &result -> buffer -> data [0]; + putUShort (result -> buffer -> data, len); + } + } else + result -> len = 0; + +#if defined (DEBUG_EXPRESSIONS) + if (!s0) + log_debug ("data: encode_int16 (NULL) = NULL"); + else + log_debug ("data: encode_int16 (%ld) = %s", len, + print_hex_2 (result -> len, + result -> data, 20)); +#endif + return s0; + + case expr_encode_int32: + s0 = evaluate_numeric_expression (&len, packet, lease, + client_state, + in_options, cfg_options, + scope, + expr -> data.encode_int); + if (s0) { + result -> len = 4; + if (!buffer_allocate (&result -> buffer, 4, + file, line)) { + log_error ("data: encode_int32: no memory"); + result -> len = 0; + s0 = 0; + } else { + result -> data = &result -> buffer -> data [0]; + putULong (result -> buffer -> data, len); + } + } else + result -> len = 0; + +#if defined (DEBUG_EXPRESSIONS) + if (!s0) + log_debug ("data: encode_int32 (NULL) = NULL"); + else + log_debug ("data: encode_int32 (%ld) = %s", len, + print_hex_2 (result -> len, + result -> data, 20)); +#endif + return s0; + + case expr_binary_to_ascii: + /* Evaluate the base (offset) and width (len): */ + s0 = evaluate_numeric_expression + (&offset, packet, lease, client_state, in_options, + cfg_options, scope, expr -> data.b2a.base); + s1 = evaluate_numeric_expression (&len, packet, lease, + client_state, + in_options, cfg_options, + scope, + expr -> data.b2a.width); + + /* Evaluate the seperator string. */ + memset (&data, 0, sizeof data); + s2 = evaluate_data_expression (&data, packet, lease, + client_state, + in_options, cfg_options, scope, + expr -> data.b2a.seperator, + MDL); + + /* Evaluate the data to be converted. */ + memset (&other, 0, sizeof other); + s3 = evaluate_data_expression (&other, packet, lease, + client_state, + in_options, cfg_options, scope, + expr -> data.b2a.buffer, MDL); + + if (s0 && s1 && s2 && s3) { + unsigned buflen, i; + + if (len != 8 && len != 16 && len != 32) { + log_info ("binary_to_ascii: %s %ld!", + "invalid width", len); + goto b2a_out; + } + len /= 8; + + /* The buffer must be a multiple of the number's + width. */ + if (other.len % len) { + log_info ("binary-to-ascii: %s %d %s %ld!", + "length of buffer", other.len, + "not a multiple of width", len); + status = 0; + goto b2a_out; + } + + /* Count the width of the output. */ + buflen = 0; + for (i = 0; i < other.len; i += len) { + if (len == 1) { + if (offset == 8) { + if (other.data [i] < 8) + buflen++; + else if (other.data [i] < 64) + buflen += 2; + else + buflen += 3; + } else if (offset == 10) { + if (other.data [i] < 10) + buflen++; + else if (other.data [i] < 100) + buflen += 2; + else + buflen += 3; + } else if (offset == 16) { + if (other.data [i] < 16) + buflen++; + else + buflen += 2; + } else + buflen += (converted_length + (&other.data [i], + offset, 1)); + } else + buflen += (converted_length + (&other.data [i], + offset, len)); + if (i + len != other.len) + buflen += data.len; + } + + if (!buffer_allocate (&result -> buffer, + buflen + 1, file, line)) { + log_error ("data: binary-to-ascii: no memory"); + status = 0; + goto b2a_out; + } + result -> data = &result -> buffer -> data [0]; + result -> len = buflen; + result -> terminated = 1; + + buflen = 0; + for (i = 0; i < other.len; i += len) { + buflen += (binary_to_ascii + (&result -> buffer -> data [buflen], + &other.data [i], offset, len)); + if (i + len != other.len) { + memcpy (&result -> + buffer -> data [buflen], + data.data, data.len); + buflen += data.len; + } + } + /* NUL terminate. */ + result -> buffer -> data [buflen] = 0; + status = 1; + } else + status = 0; + + b2a_out: +#if defined (DEBUG_EXPRESSIONS) + log_debug ("data: binary-to-ascii (%s, %s, %s, %s) = %s", + s0 ? print_dec_1 (offset) : "NULL", + s1 ? print_dec_2 (len) : "NULL", + s2 ? print_hex_1 (data.len, data.data, 30) : "NULL", + s3 ? print_hex_2 (other.len, other.data, 30) : "NULL", + (status ? print_hex_3 (result -> len, result -> data, 30) + : "NULL")); +#endif + if (s2) + data_string_forget (&data, MDL); + if (s3) + data_string_forget (&other, MDL); + if (status) + return 1; + return 0; + + case expr_reverse: + /* Evaluate the width (len): */ + s0 = evaluate_numeric_expression + (&len, packet, lease, client_state, in_options, + cfg_options, scope, expr -> data.reverse.width); + + /* Evaluate the data. */ + memset (&data, 0, sizeof data); + s1 = evaluate_data_expression (&data, packet, lease, + client_state, + in_options, cfg_options, scope, + expr -> data.reverse.buffer, + MDL); + + if (s0 && s1) { + char *upper; + int i; + + /* The buffer must be a multiple of the number's + width. */ + if (data.len % len) { + log_info ("reverse: %s %d %s %ld!", + "length of buffer", data.len, + "not a multiple of width", len); + status = 0; + goto reverse_out; + } + + /* XXX reverse in place? I don't think we can. */ + if (!buffer_allocate (&result -> buffer, + data.len, file, line)) { + log_error ("data: reverse: no memory"); + status = 0; + goto reverse_out; + } + result -> data = &result -> buffer -> data [0]; + result -> len = data.len; + result -> terminated = 0; + + for (i = 0; i < data.len; i += len) { + memcpy (&result -> buffer -> data [i], + &data.data [data.len - i - len], len); + } + status = 1; + } else + status = 0; + + reverse_out: +#if defined (DEBUG_EXPRESSIONS) + log_debug ("data: reverse (%s, %s) = %s", + s0 ? print_dec_1 (len) : "NULL", + s1 ? print_hex_1 (data.len, data.data, 30) : "NULL", + (status ? print_hex_3 (result -> len, result -> data, 30) + : "NULL")); +#endif + if (s0) + data_string_forget (&data, MDL); + if (status) + return 1; + return 0; + + case expr_leased_address: + if (!lease) { + log_error ("data: leased_address: not available"); + return 0; + } + result -> len = lease -> ip_addr.len; + if (buffer_allocate (&result -> buffer, result -> len, + file, line)) { + result -> data = &result -> buffer -> data [0]; + memcpy (&result -> buffer -> data [0], + lease -> ip_addr.iabuf, lease -> ip_addr.len); + result -> terminated = 0; + } else { + log_error ("data: leased-address: no memory."); + return 0; + } +#if defined (DEBUG_EXPRESSIONS) + log_debug ("data: leased-address = %s", + print_hex_1 (result -> len, result -> data, 60)); +#endif + return 1; + + case expr_pick_first_value: + memset (&data, 0, sizeof data); + if ((evaluate_data_expression + (result, packet, + lease, client_state, in_options, cfg_options, + scope, expr -> data.pick_first_value.car, MDL))) { +#if defined (DEBUG_EXPRESSIONS) + log_debug ("data: pick_first_value (%s, xxx)", + print_hex_1 (result -> len, + result -> data, 40)); +#endif + return 1; + } + + if (expr -> data.pick_first_value.cdr && + (evaluate_data_expression + (result, packet, + lease, client_state, in_options, cfg_options, + scope, expr -> data.pick_first_value.cdr, MDL))) { +#if defined (DEBUG_EXPRESSIONS) + log_debug ("data: pick_first_value (NULL, %s)", + print_hex_1 (result -> len, + result -> data, 40)); +#endif + return 1; + } + +#if defined (DEBUG_EXPRESSIONS) + log_debug ("data: pick_first_value (NULL, NULL) = NULL"); +#endif + return 0; + + case expr_host_decl_name: + if (!lease || !lease -> host) { + log_error ("data: host_decl_name: not available"); + return 0; + } + result -> len = strlen (lease -> host -> name); + if (buffer_allocate (&result -> buffer, + result -> len + 1, file, line)) { + result -> data = &result -> buffer -> data [0]; + strcpy ((char *)&result -> buffer -> data [0], + lease -> host -> name); + result -> terminated = 1; + } else { + log_error ("data: host-decl-name: no memory."); + return 0; + } +#if defined (DEBUG_EXPRESSIONS) + log_debug ("data: host-decl-name = %s", lease -> host -> name); +#endif + return 1; + + case expr_null: +#if defined (DEBUG_EXPRESSIONS) + log_debug ("data: null = NULL"); +#endif + return 0; + + case expr_variable_reference: + if (scope && *scope) { + binding = find_binding (*scope, expr -> data.variable); + + if (binding && binding -> value) { + if (binding -> value -> type == binding_data) { + data_string_copy (result, + &binding -> value -> value.data, + file, line); + s0 = 1; + } else if (binding -> value -> type != binding_data) { + log_error ("binding type %d in %s.", + binding -> value -> type, + "evaluate_data_expression"); + s0 = 0; + } else + s0 = 0; + } else + s0 = 0; + } else + s0 = 0; +#if defined (DEBUG_EXPRESSIONS) + log_debug ("data: %s = %s", expr -> data.variable, + s0 ? print_hex_1 (result -> len, + result -> data, 50) : "NULL"); +#endif + return s0; + + case expr_funcall: + bv = (struct binding_value *)0; + s0 = evaluate_expression (&bv, packet, lease, client_state, + in_options, cfg_options, + scope, expr, MDL); + if (s0) { + if (bv -> type != binding_data) + log_error ("%s() returned type %d in %s.", + expr -> data.funcall.name, + bv -> type, + "evaluate_data_expression"); + else + data_string_copy (result, &bv -> value.data, + file, line); + binding_value_dereference (&bv, MDL); + } +#if defined (DEBUG_EXPRESSIONS) + log_debug ("data: %s = %s", expr -> data.funcall.name, + s0 ? print_hex_1 (result -> len, + result -> data, 50) : "NULL"); +#endif + break; + + /* Extract the filename. */ + case expr_filename: + if (packet && packet -> raw -> file [0]) { + char *fn = + memchr (packet -> raw -> file, 0, + sizeof packet -> raw -> file); + if (!fn) + fn = ((char *)packet -> raw -> file + + sizeof packet -> raw -> file); + result -> len = fn - &(packet -> raw -> file [0]); + if (buffer_allocate (&result -> buffer, + result -> len + 1, file, line)) { + result -> data = &result -> buffer -> data [0]; + memcpy (&result -> buffer -> data [0], + packet -> raw -> file, + result -> len); + result -> buffer -> data [result -> len] = 0; + result -> terminated = 1; + s0 = 1; + } else { + log_error ("data: filename: no memory."); + s0 = 0; + } + } else + s0 = 0; + +#if defined (DEBUG_EXPRESSIONS) + log_info ("data: filename = \"%s\"", + s0 ? (const char *)(result -> data) : "NULL"); +#endif + return s0; + + /* Extract the server name. */ + case expr_sname: + if (packet && packet -> raw -> sname [0]) { + char *fn = + memchr (packet -> raw -> sname, 0, + sizeof packet -> raw -> sname); + if (!fn) + fn = ((char *)packet -> raw -> sname + + sizeof packet -> raw -> sname); + result -> len = fn - &packet -> raw -> sname [0]; + if (buffer_allocate (&result -> buffer, + result -> len + 1, file, line)) { + result -> data = &result -> buffer -> data [0]; + memcpy (&result -> buffer -> data [0], + packet -> raw -> sname, + result -> len); + result -> buffer -> data [result -> len] = 0; + result -> terminated = 1; + s0 = 1; + } else { + log_error ("data: sname: no memory."); + s0 = 0; + } + } else + s0 = 0; + +#if defined (DEBUG_EXPRESSIONS) + log_info ("data: sname = \"%s\"", + s0 ? (const char *)(result -> data) : "NULL"); +#endif + return s0; + + case expr_check: + case expr_equal: + case expr_not_equal: + case expr_and: + case expr_or: + case expr_not: + case expr_match: + case expr_static: + case expr_known: + case expr_none: + case expr_exists: + case expr_variable_exists: + log_error ("Boolean opcode in evaluate_data_expression: %d", + expr -> op); + return 0; + + case expr_extract_int8: + case expr_extract_int16: + case expr_extract_int32: + case expr_const_int: + case expr_lease_time: + case expr_dns_transaction: + case expr_add: + case expr_subtract: + case expr_multiply: + case expr_divide: + case expr_remainder: + case expr_binary_and: + case expr_binary_or: + case expr_binary_xor: + case expr_client_state: + log_error ("Numeric opcode in evaluate_data_expression: %d", + expr -> op); + return 0; + + case expr_ns_add: + case expr_ns_delete: + case expr_ns_exists: + case expr_ns_not_exists: + log_error ("dns update opcode in evaluate_data_expression: %d", + expr -> op); + return 0; + + case expr_function: + log_error ("function definition in evaluate_data_expression"); + return 0; + + case expr_arg: + break; + } + + log_error ("Bogus opcode in evaluate_data_expression: %d", expr -> op); + return 0; +} + +int evaluate_numeric_expression (result, packet, lease, client_state, + in_options, cfg_options, scope, expr) + unsigned long *result; + struct packet *packet; + struct lease *lease; + struct client_state *client_state; + struct option_state *in_options; + struct option_state *cfg_options; + struct binding_scope **scope; + struct expression *expr; +{ + struct data_string data; + int status, sleft, sright; +#if defined (NSUPDATE) + ns_updrec *nut; + ns_updque uq; +#endif + struct expression *cur, *next; + struct binding *binding; + struct binding_value *bv; + unsigned long ileft, iright; + + switch (expr -> op) { + case expr_check: + case expr_equal: + case expr_not_equal: + case expr_and: + case expr_or: + case expr_not: + case expr_match: + case expr_static: + case expr_known: + case expr_none: + case expr_exists: + case expr_variable_exists: + log_error ("Boolean opcode in evaluate_numeric_expression: %d", + expr -> op); + return 0; + + case expr_substring: + case expr_suffix: + case expr_option: + case expr_hardware: + case expr_const_data: + case expr_packet: + case expr_concat: + case expr_encapsulate: + case expr_host_lookup: + case expr_encode_int8: + case expr_encode_int16: + case expr_encode_int32: + case expr_binary_to_ascii: + case expr_reverse: + case expr_filename: + case expr_sname: + case expr_pick_first_value: + case expr_host_decl_name: + case expr_config_option: + case expr_leased_address: + case expr_null: + log_error ("Data opcode in evaluate_numeric_expression: %d", + expr -> op); + return 0; + + case expr_extract_int8: + memset (&data, 0, sizeof data); + status = evaluate_data_expression + (&data, packet, lease, client_state, in_options, + cfg_options, scope, expr -> data.extract_int, MDL); + if (status) + *result = data.data [0]; +#if defined (DEBUG_EXPRESSIONS) + log_debug ("num: extract_int8 (%s) = %s", + status ? print_hex_1 (data.len, data.data, 60) : "NULL", + status ? print_dec_1 (*result) : "NULL" ); +#endif + if (status) data_string_forget (&data, MDL); + return status; + + case expr_extract_int16: + memset (&data, 0, sizeof data); + status = (evaluate_data_expression + (&data, packet, lease, client_state, in_options, + cfg_options, scope, expr -> data.extract_int, MDL)); + if (status && data.len >= 2) + *result = getUShort (data.data); +#if defined (DEBUG_EXPRESSIONS) + log_debug ("num: extract_int16 (%s) = %ld", + ((status && data.len >= 2) ? + print_hex_1 (data.len, data.data, 60) : "NULL"), + *result); +#endif + if (status) data_string_forget (&data, MDL); + return (status && data.len >= 2); + + case expr_extract_int32: + memset (&data, 0, sizeof data); + status = (evaluate_data_expression + (&data, packet, lease, client_state, in_options, + cfg_options, scope, expr -> data.extract_int, MDL)); + if (status && data.len >= 4) + *result = getULong (data.data); +#if defined (DEBUG_EXPRESSIONS) + log_debug ("num: extract_int32 (%s) = %ld", + ((status && data.len >= 4) ? + print_hex_1 (data.len, data.data, 60) : "NULL"), + *result); +#endif + if (status) data_string_forget (&data, MDL); + return (status && data.len >= 4); + + case expr_const_int: + *result = expr -> data.const_int; +#if defined (DEBUG_EXPRESSIONS) + log_debug ("number: CONSTANT = %ld", *result); +#endif + return 1; + + case expr_lease_time: + if (!lease) { + log_error ("data: leased_lease: not available"); + return 0; + } + if (lease -> ends < cur_time) { + log_error ("%s %lu when it is now %lu", + "data: lease_time: lease ends at", + (long)(lease -> ends), (long)cur_time); + return 0; + } + *result = lease -> ends - cur_time; +#if defined (DEBUG_EXPRESSIONS) + log_debug ("number: lease-time = (%lu - %lu) = %ld", + lease -> ends, + cur_time, *result); +#endif + return 1; + + case expr_dns_transaction: +#if !defined (NSUPDATE) + return 0; +#else + if (!resolver_inited) { + minires_ninit (&resolver_state); + resolver_inited = 1; + resolver_state.retrans = 1; + resolver_state.retry = 1; + } + ISC_LIST_INIT (uq); + cur = expr; + do { + next = cur -> data.dns_transaction.cdr; + nut = 0; + status = (evaluate_dns_expression + (&nut, packet, + lease, client_state, in_options, cfg_options, + scope, cur -> data.dns_transaction.car)); + if (!status) + goto dns_bad; + ISC_LIST_APPEND (uq, nut, r_link); + cur = next; + } while (next); + + /* Do the update and record the error code, if there was + an error; otherwise set it to NOERROR. */ + *result = minires_nupdate (&resolver_state, + ISC_LIST_HEAD (uq)); + status = 1; + + print_dns_status ((int)*result, &uq); + + dns_bad: + while (!ISC_LIST_EMPTY (uq)) { + ns_updrec *tmp = ISC_LIST_HEAD (uq); + ISC_LIST_UNLINK (uq, tmp, r_link); + if (tmp -> r_data_ephem) { + dfree (tmp -> r_data_ephem, MDL); + tmp -> r_data = (unsigned char *)0; + tmp -> r_data_ephem = (unsigned char *)0; + } + minires_freeupdrec (tmp); + } + return status; +#endif /* NSUPDATE */ + + case expr_variable_reference: + if (scope && *scope) { + binding = find_binding (*scope, expr -> data.variable); + + if (binding && binding -> value) { + if (binding -> value -> type == binding_numeric) { + *result = binding -> value -> value.intval; + status = 1; + } else { + log_error ("binding type %d in %s.", + binding -> value -> type, + "evaluate_numeric_expression"); + status = 0; + } + } else + status = 0; + } else + status = 0; +#if defined (DEBUG_EXPRESSIONS) + if (status) + log_debug ("numeric: %s = %ld", + expr -> data.variable, *result); + else + log_debug ("numeric: %s = NULL", + expr -> data.variable); +#endif + return status; + + case expr_funcall: + bv = (struct binding_value *)0; + status = evaluate_expression (&bv, packet, lease, + client_state, + in_options, cfg_options, + scope, expr, MDL); + if (status) { + if (bv -> type != binding_numeric) + log_error ("%s() returned type %d in %s.", + expr -> data.funcall.name, + bv -> type, + "evaluate_numeric_expression"); + else + *result = bv -> value.intval; + binding_value_dereference (&bv, MDL); + } +#if defined (DEBUG_EXPRESSIONS) + log_debug ("data: %s = %ld", expr -> data.funcall.name, + status ? *result : 0); +#endif + break; + + case expr_add: + sleft = evaluate_numeric_expression (&ileft, packet, lease, + client_state, + in_options, cfg_options, + scope, + expr -> data.and [0]); + sright = evaluate_numeric_expression (&iright, packet, lease, + client_state, + in_options, cfg_options, + scope, + expr -> data.and [1]); + +#if defined (DEBUG_EXPRESSIONS) + if (sleft && sright) + log_debug ("num: %ld + %ld = %ld", + ileft, iright, ileft + iright); + else if (sleft) + log_debug ("num: %ld + NULL = NULL", ileft); + else + log_debug ("num: NULL + %ld = NULL", iright); +#endif + if (sleft && sright) { + *result = ileft + iright; + return 1; + } + return 0; + + case expr_subtract: + sleft = evaluate_numeric_expression (&ileft, packet, lease, + client_state, + in_options, cfg_options, + scope, + expr -> data.and [0]); + sright = evaluate_numeric_expression (&iright, packet, lease, + client_state, + in_options, cfg_options, + scope, + expr -> data.and [1]); + +#if defined (DEBUG_EXPRESSIONS) + if (sleft && sright) + log_debug ("num: %ld - %ld = %ld", + ileft, iright, ileft - iright); + else if (sleft) + log_debug ("num: %ld - NULL = NULL", ileft); + else + log_debug ("num: NULL - %ld = NULL", iright); +#endif + if (sleft && sright) { + *result = ileft - iright; + return 1; + } + return 0; + + case expr_multiply: + sleft = evaluate_numeric_expression (&ileft, packet, lease, + client_state, + in_options, cfg_options, + scope, + expr -> data.and [0]); + sright = evaluate_numeric_expression (&iright, packet, lease, + client_state, + in_options, cfg_options, + scope, + expr -> data.and [1]); + +#if defined (DEBUG_EXPRESSIONS) + if (sleft && sright) + log_debug ("num: %ld * %ld = %ld", + ileft, iright, ileft * iright); + else if (sleft) + log_debug ("num: %ld * NULL = NULL", ileft); + else + log_debug ("num: NULL * %ld = NULL", iright); +#endif + if (sleft && sright) { + *result = ileft * iright; + return 1; + } + return 0; + + case expr_divide: + sleft = evaluate_numeric_expression (&ileft, packet, lease, + client_state, + in_options, cfg_options, + scope, + expr -> data.and [0]); + sright = evaluate_numeric_expression (&iright, packet, lease, + client_state, + in_options, cfg_options, + scope, + expr -> data.and [1]); + +#if defined (DEBUG_EXPRESSIONS) + if (sleft && sright) { + if (iright != 0) + log_debug ("num: %ld / %ld = %ld", + ileft, iright, ileft / iright); + else + log_debug ("num: %ld / %ld = NULL", + ileft, iright); + } else if (sleft) + log_debug ("num: %ld / NULL = NULL", ileft); + else + log_debug ("num: NULL / %ld = NULL", iright); #endif - do_data_copy (bufix, bufp, bufcount, dns -> data, dns -> data_len); - return dns -> timeout; + if (sleft && sright && iright) { + *result = ileft / iright; + return 1; + } + return 0; + + case expr_remainder: + sleft = evaluate_numeric_expression (&ileft, packet, lease, + client_state, + in_options, cfg_options, + scope, + expr -> data.and [0]); + sright = evaluate_numeric_expression (&iright, packet, lease, + client_state, + in_options, cfg_options, + scope, + expr -> data.and [1]); + +#if defined (DEBUG_EXPRESSIONS) + if (sleft && sright) { + if (iright != 0) + log_debug ("num: %ld %% %ld = %ld", + ileft, iright, ileft % iright); + else + log_debug ("num: %ld %% %ld = NULL", + ileft, iright); + } else if (sleft) + log_debug ("num: %ld %% NULL = NULL", ileft); + else + log_debug ("num: NULL %% %ld = NULL", iright); +#endif + if (sleft && sright && iright) { + *result = ileft % iright; + return 1; + } + return 0; + + case expr_binary_and: + sleft = evaluate_numeric_expression (&ileft, packet, lease, + client_state, + in_options, cfg_options, + scope, + expr -> data.and [0]); + sright = evaluate_numeric_expression (&iright, packet, lease, + client_state, + in_options, cfg_options, + scope, + expr -> data.and [1]); + +#if defined (DEBUG_EXPRESSIONS) + if (sleft && sright) + log_debug ("num: %ld | %ld = %ld", + ileft, iright, ileft & iright); + else if (sleft) + log_debug ("num: %ld & NULL = NULL", ileft); + else + log_debug ("num: NULL & %ld = NULL", iright); +#endif + if (sleft && sright) { + *result = ileft & iright; + return 1; + } + return 0; + + case expr_binary_or: + sleft = evaluate_numeric_expression (&ileft, packet, lease, + client_state, + in_options, cfg_options, + scope, + expr -> data.and [0]); + sright = evaluate_numeric_expression (&iright, packet, lease, + client_state, + in_options, cfg_options, + scope, + expr -> data.and [1]); + +#if defined (DEBUG_EXPRESSIONS) + if (sleft && sright) + log_debug ("num: %ld | %ld = %ld", + ileft, iright, ileft | iright); + else if (sleft) + log_debug ("num: %ld | NULL = NULL", ileft); + else + log_debug ("num: NULL | %ld = NULL", iright); +#endif + if (sleft && sright) { + *result = ileft | iright; + return 1; + } + return 0; + + case expr_binary_xor: + sleft = evaluate_numeric_expression (&ileft, packet, lease, + client_state, + in_options, cfg_options, + scope, + expr -> data.and [0]); + sright = evaluate_numeric_expression (&iright, packet, lease, + client_state, + in_options, cfg_options, + scope, + expr -> data.and [1]); + +#if defined (DEBUG_EXPRESSIONS) + if (sleft && sright) + log_debug ("num: %ld ^ %ld = %ld", + ileft, iright, ileft ^ iright); + else if (sleft) + log_debug ("num: %ld ^ NULL = NULL", ileft); + else + log_debug ("num: NULL ^ %ld = NULL", iright); +#endif + if (sleft && sright) { + *result = ileft ^ iright; + return 1; + } + return 0; + + case expr_client_state: + if (client_state) { +#if defined (DEBUG_EXPRESSIONS) + log_debug ("num: client-state = %d", + client_state -> state); +#endif + *result = client_state -> state; + return 1; + } else { +#if defined (DEBUG_EXPRESSIONS) + log_debug ("num: client-state = NULL"); +#endif + return 0; + } + + case expr_ns_add: + case expr_ns_delete: + case expr_ns_exists: + case expr_ns_not_exists: + log_error ("dns opcode in evaluate_numeric_expression: %d", + expr -> op); + return 0; + + case expr_function: + log_error ("function definition in evaluate_numeric_expr"); + return 0; + + case expr_arg: + break; + } + + log_error ("evaluate_numeric_expression: bogus opcode %d", expr -> op); + return 0; } -static void do_data_copy (bufix, bufp, bufcount, data, len) - int *bufix; - unsigned char **bufp; - int *bufcount; - unsigned char *data; - int len; +/* Return data hanging off of an option cache structure, or if there + isn't any, evaluate the expression hanging off of it and return the + result of that evaluation. There should never be both an expression + and a valid data_string. */ + +int evaluate_option_cache (result, packet, lease, client_state, + in_options, cfg_options, scope, oc, file, line) + struct data_string *result; + struct packet *packet; + struct lease *lease; + struct client_state *client_state; + struct option_state *in_options; + struct option_state *cfg_options; + struct binding_scope **scope; + struct option_cache *oc; + const char *file; + int line; { - int space = *bufcount - *bufix; + if (oc -> data.len) { + data_string_copy (result, &oc -> data, file, line); + return 1; + } + if (!oc -> expression) + return 0; + return evaluate_data_expression (result, packet, lease, client_state, + in_options, cfg_options, scope, + oc -> expression, file, line); +} + +/* Evaluate an option cache and extract a boolean from the result, + returning the boolean. Return false if there is no data. */ - /* If there's more space than we need, use only what we need. */ - if (space > len) - space = len; +int evaluate_boolean_option_cache (ignorep, packet, + lease, client_state, in_options, + cfg_options, scope, oc, file, line) + int *ignorep; + struct packet *packet; + struct lease *lease; + struct client_state *client_state; + struct option_state *in_options; + struct option_state *cfg_options; + struct binding_scope **scope; + struct option_cache *oc; + const char *file; + int line; +{ + struct data_string ds; + int result; - /* Copy as much data as will fit, then increment the buffer index - by the amount we actually had to copy, which could be more. */ - if (space > 0) - memcpy (*bufp + *bufix, data, space); - *bufix += len; + /* So that we can be called with option_lookup as an argument. */ + if (!oc || !in_options) + return 0; + + memset (&ds, 0, sizeof ds); + if (!evaluate_option_cache (&ds, packet, + lease, client_state, in_options, + cfg_options, scope, oc, file, line)) + return 0; + + if (ds.len) { + result = ds.data [0]; + if (result == 2) { + result = 0; + *ignorep = 1; + } else + *ignorep = 0; + } else + result = 0; + data_string_forget (&ds, MDL); + return result; } + + +/* Evaluate a boolean expression and return the result of the evaluation, + or FALSE if it failed. */ + +int evaluate_boolean_expression_result (ignorep, packet, lease, client_state, + in_options, cfg_options, scope, expr) + int *ignorep; + struct packet *packet; + struct lease *lease; + struct client_state *client_state; + struct option_state *in_options; + struct option_state *cfg_options; + struct binding_scope **scope; + struct expression *expr; +{ + int result; + + /* So that we can be called with option_lookup as an argument. */ + if (!expr) + return 0; + + if (!evaluate_boolean_expression (&result, packet, lease, client_state, + in_options, cfg_options, + scope, expr)) + return 0; + + if (result == 2) { + *ignorep = 1; + result = 0; + } else + *ignorep = 0; + return result; +} + + +/* Dereference an expression node, and if the reference count goes to zero, + dereference any data it refers to, and then free it. */ +void expression_dereference (eptr, file, line) + struct expression **eptr; + const char *file; + int line; +{ + struct expression *expr = *eptr; + + /* Zero the pointer. */ + *eptr = (struct expression *)0; + + /* Decrement the reference count. If it's nonzero, we're + done. */ + --(expr -> refcnt); + rc_register (file, line, eptr, expr, expr -> refcnt, 1, RC_MISC); + if (expr -> refcnt > 0) + return; + if (expr -> refcnt < 0) { + log_error ("%s(%d): negative refcnt!", file, line); +#if defined (DEBUG_RC_HISTORY) + dump_rc_history (expr); +#endif +#if defined (POINTER_DEBUG) + abort (); +#else + return; +#endif + } + + /* Dereference subexpressions. */ + switch (expr -> op) { + /* All the binary operators can be handled the same way. */ + case expr_equal: + case expr_not_equal: + case expr_concat: + case expr_and: + case expr_or: + case expr_add: + case expr_subtract: + case expr_multiply: + case expr_divide: + case expr_remainder: + case expr_binary_and: + case expr_binary_or: + case expr_binary_xor: + case expr_client_state: + if (expr -> data.equal [0]) + expression_dereference (&expr -> data.equal [0], + file, line); + if (expr -> data.equal [1]) + expression_dereference (&expr -> data.equal [1], + file, line); + break; + + case expr_substring: + if (expr -> data.substring.expr) + expression_dereference (&expr -> data.substring.expr, + file, line); + if (expr -> data.substring.offset) + expression_dereference (&expr -> data.substring.offset, + file, line); + if (expr -> data.substring.len) + expression_dereference (&expr -> data.substring.len, + file, line); + break; + + case expr_suffix: + if (expr -> data.suffix.expr) + expression_dereference (&expr -> data.suffix.expr, + file, line); + if (expr -> data.suffix.len) + expression_dereference (&expr -> data.suffix.len, + file, line); + break; + + case expr_not: + if (expr -> data.not) + expression_dereference (&expr -> data.not, file, line); + break; + + case expr_packet: + if (expr -> data.packet.offset) + expression_dereference (&expr -> data.packet.offset, + file, line); + if (expr -> data.packet.len) + expression_dereference (&expr -> data.packet.len, + file, line); + break; + + case expr_extract_int8: + case expr_extract_int16: + case expr_extract_int32: + if (expr -> data.extract_int) + expression_dereference (&expr -> data.extract_int, + file, line); + break; + + case expr_encode_int8: + case expr_encode_int16: + case expr_encode_int32: + if (expr -> data.encode_int) + expression_dereference (&expr -> data.encode_int, + file, line); + break; + + case expr_encapsulate: + case expr_const_data: + data_string_forget (&expr -> data.const_data, file, line); + break; + + case expr_host_lookup: + if (expr -> data.host_lookup) + dns_host_entry_dereference (&expr -> data.host_lookup, + file, line); + break; + + case expr_binary_to_ascii: + if (expr -> data.b2a.base) + expression_dereference (&expr -> data.b2a.base, + file, line); + if (expr -> data.b2a.width) + expression_dereference (&expr -> data.b2a.width, + file, line); + if (expr -> data.b2a.seperator) + expression_dereference (&expr -> data.b2a.seperator, + file, line); + if (expr -> data.b2a.buffer) + expression_dereference (&expr -> data.b2a.buffer, + file, line); + break; + + case expr_pick_first_value: + if (expr -> data.pick_first_value.car) + expression_dereference (&expr -> data.pick_first_value.car, + file, line); + if (expr -> data.pick_first_value.cdr) + expression_dereference (&expr -> data.pick_first_value.cdr, + file, line); + break; + + case expr_reverse: + if (expr -> data.reverse.width) + expression_dereference (&expr -> data.reverse.width, + file, line); + if (expr -> data.reverse.buffer) + expression_dereference + (&expr -> data.reverse.buffer, file, line); + break; + + case expr_dns_transaction: + if (expr -> data.dns_transaction.car) + expression_dereference (&expr -> data.dns_transaction.car, + file, line); + if (expr -> data.dns_transaction.cdr) + expression_dereference (&expr -> data.dns_transaction.cdr, + file, line); + break; + + case expr_ns_add: + if (expr -> data.ns_add.rrname) + expression_dereference (&expr -> data.ns_add.rrname, + file, line); + if (expr -> data.ns_add.rrdata) + expression_dereference (&expr -> data.ns_add.rrdata, + file, line); + if (expr -> data.ns_add.ttl) + expression_dereference (&expr -> data.ns_add.ttl, + file, line); + break; + + case expr_ns_delete: + case expr_ns_exists: + case expr_ns_not_exists: + if (expr -> data.ns_delete.rrname) + expression_dereference (&expr -> data.ns_delete.rrname, + file, line); + if (expr -> data.ns_delete.rrdata) + expression_dereference (&expr -> data.ns_delete.rrdata, + file, line); + break; + + case expr_variable_reference: + case expr_variable_exists: + if (expr -> data.variable) + dfree (expr -> data.variable, file, line); + break; + + case expr_funcall: + if (expr -> data.funcall.name) + dfree (expr -> data.funcall.name, file, line); + if (expr -> data.funcall.arglist) + expression_dereference (&expr -> data.funcall.arglist, + file, line); + break; + + case expr_arg: + if (expr -> data.arg.val) + expression_dereference (&expr -> data.arg.val, + file, line); + if (expr -> data.arg.next) + expression_dereference (&expr -> data.arg.next, + file, line); + break; + + case expr_function: + fundef_dereference (&expr -> data.func, file, line); + break; + + /* No subexpressions. */ + case expr_leased_address: + case expr_lease_time: + case expr_filename: + case expr_sname: + case expr_const_int: + case expr_check: + case expr_option: + case expr_hardware: + case expr_exists: + case expr_known: + case expr_null: + break; + + default: + break; + } + free_expression (expr, MDL); +} + +int is_dns_expression (expr) + struct expression *expr; +{ + return (expr -> op == expr_ns_add || + expr -> op == expr_ns_delete || + expr -> op == expr_ns_exists || + expr -> op == expr_ns_not_exists); +} + +int is_boolean_expression (expr) + struct expression *expr; +{ + return (expr -> op == expr_check || + expr -> op == expr_exists || + expr -> op == expr_variable_exists || + expr -> op == expr_equal || + expr -> op == expr_not_equal || + expr -> op == expr_and || + expr -> op == expr_or || + expr -> op == expr_not || + expr -> op == expr_known || + expr -> op == expr_static); +} + +int is_data_expression (expr) + struct expression *expr; +{ + return (expr -> op == expr_substring || + expr -> op == expr_suffix || + expr -> op == expr_option || + expr -> op == expr_hardware || + expr -> op == expr_const_data || + expr -> op == expr_packet || + expr -> op == expr_concat || + expr -> op == expr_encapsulate || + expr -> op == expr_encode_int8 || + expr -> op == expr_encode_int16 || + expr -> op == expr_encode_int32 || + expr -> op == expr_host_lookup || + expr -> op == expr_binary_to_ascii || + expr -> op == expr_filename || + expr -> op == expr_sname || + expr -> op == expr_reverse || + expr -> op == expr_pick_first_value || + expr -> op == expr_host_decl_name || + expr -> op == expr_leased_address || + expr -> op == expr_config_option || + expr -> op == expr_null); +} + +int is_numeric_expression (expr) + struct expression *expr; +{ + return (expr -> op == expr_extract_int8 || + expr -> op == expr_extract_int16 || + expr -> op == expr_extract_int32 || + expr -> op == expr_const_int || + expr -> op == expr_lease_time || + expr -> op == expr_dns_transaction || + expr -> op == expr_add || + expr -> op == expr_subtract || + expr -> op == expr_multiply || + expr -> op == expr_divide || + expr -> op == expr_remainder || + expr -> op == expr_binary_and || + expr -> op == expr_binary_or || + expr -> op == expr_binary_xor || + expr -> op == expr_client_state); +} + +int is_compound_expression (expr) + struct expression *expr; +{ + return (expr -> op == expr_ns_add || + expr -> op == expr_ns_delete || + expr -> op == expr_ns_exists || + expr -> op == expr_ns_not_exists || + expr -> op == expr_substring || + expr -> op == expr_suffix || + expr -> op == expr_option || + expr -> op == expr_concat || + expr -> op == expr_encode_int8 || + expr -> op == expr_encode_int16 || + expr -> op == expr_encode_int32 || + expr -> op == expr_binary_to_ascii || + expr -> op == expr_reverse || + expr -> op == expr_pick_first_value || + expr -> op == expr_config_option || + expr -> op == expr_extract_int8 || + expr -> op == expr_extract_int16 || + expr -> op == expr_extract_int32 || + expr -> op == expr_dns_transaction); +} + +static int op_val PROTO ((enum expr_op)); + +static int op_val (op) + enum expr_op op; +{ + switch (op) { + case expr_none: + case expr_match: + case expr_static: + case expr_check: + case expr_substring: + case expr_suffix: + case expr_concat: + case expr_encapsulate: + case expr_host_lookup: + case expr_not: + case expr_option: + case expr_hardware: + case expr_packet: + case expr_const_data: + case expr_extract_int8: + case expr_extract_int16: + case expr_extract_int32: + case expr_encode_int8: + case expr_encode_int16: + case expr_encode_int32: + case expr_const_int: + case expr_exists: + case expr_variable_exists: + case expr_known: + case expr_binary_to_ascii: + case expr_reverse: + case expr_filename: + case expr_sname: + case expr_pick_first_value: + case expr_host_decl_name: + case expr_config_option: + case expr_leased_address: + case expr_lease_time: + case expr_dns_transaction: + case expr_null: + case expr_variable_reference: + case expr_ns_add: + case expr_ns_delete: + case expr_ns_exists: + case expr_ns_not_exists: + case expr_arg: + case expr_funcall: + case expr_function: + /* XXXDPN: Need to assign sane precedences to these. */ + case expr_binary_and: + case expr_binary_or: + case expr_binary_xor: + case expr_client_state: + return 100; + + case expr_equal: + case expr_not_equal: + return 3; + + case expr_and: + case expr_multiply: + case expr_divide: + case expr_remainder: + return 1; + + case expr_or: + case expr_add: + case expr_subtract: + return 2; + } + return 100; +} + +int op_precedence (op1, op2) + enum expr_op op1, op2; +{ + int ov1, ov2; + + return op_val (op1) - op_val (op2); +} + +enum expression_context expression_context (struct expression *expr) +{ + if (is_data_expression (expr)) + return context_data; + if (is_numeric_expression (expr)) + return context_numeric; + if (is_boolean_expression (expr)) + return context_boolean; + if (is_dns_expression (expr)) + return context_dns; + return context_any; +} + +enum expression_context op_context (op) + enum expr_op op; +{ + switch (op) { +/* XXX Why aren't these specific? */ + case expr_none: + case expr_match: + case expr_static: + case expr_check: + case expr_substring: + case expr_suffix: + case expr_concat: + case expr_encapsulate: + case expr_host_lookup: + case expr_not: + case expr_option: + case expr_hardware: + case expr_packet: + case expr_const_data: + case expr_extract_int8: + case expr_extract_int16: + case expr_extract_int32: + case expr_encode_int8: + case expr_encode_int16: + case expr_encode_int32: + case expr_const_int: + case expr_exists: + case expr_variable_exists: + case expr_known: + case expr_binary_to_ascii: + case expr_reverse: + case expr_filename: + case expr_sname: + case expr_pick_first_value: + case expr_host_decl_name: + case expr_config_option: + case expr_leased_address: + case expr_lease_time: + case expr_null: + case expr_variable_reference: + case expr_ns_add: + case expr_ns_delete: + case expr_ns_exists: + case expr_ns_not_exists: + case expr_dns_transaction: + case expr_arg: + case expr_funcall: + case expr_function: + return context_any; + + case expr_equal: + case expr_not_equal: + return context_data; + + case expr_and: + return context_boolean; + + case expr_or: + return context_boolean; + + case expr_add: + case expr_subtract: + case expr_multiply: + case expr_divide: + case expr_remainder: + case expr_binary_and: + case expr_binary_or: + case expr_binary_xor: + case expr_client_state: + return context_numeric; + } + return context_any; +} + +int write_expression (file, expr, col, indent, firstp) + FILE *file; + struct expression *expr; + int col; + int indent; + int firstp; +{ + struct expression *e; + const char *s; + char obuf [65]; + int scol; + int width; + + /* If this promises to be a fat expression, start a new line. */ + if (!firstp && is_compound_expression (expr)) { + indent_spaces (file, indent); + col = indent; + } + + switch (expr -> op) { + case expr_none: + col = token_print_indent (file, col, indent, "", "", "null"); + break; + + case expr_check: + col = token_print_indent (file, col, indent, "", "", "check"); + col = token_print_indent_concat (file, col, indent, + " ", "", "\"", + expr -> data.check -> name, + "\"", (char *)0); + break; + + case expr_not_equal: + s = "!="; + goto binary; + + case expr_equal: + s = "="; + binary: + col = write_expression (file, expr -> data.equal [0], + col, indent, 1); + col = token_print_indent (file, col, indent, " ", " ", s); + col = write_expression (file, expr -> data.equal [1], + col, indent + 2, 0); + break; + + case expr_substring: + col = token_print_indent (file, col, indent, "", "", + "substring"); + col = token_print_indent (file, col, indent, " ", "", "("); + scol = col; + col = write_expression (file, expr -> data.substring.expr, + col, scol, 1); + col = token_print_indent (file, col, indent, "", " ", ","); + col = write_expression (file, expr -> data.substring.offset, + col, indent, 0); + col = token_print_indent (file, col, scol, "", " ", ","); + col = write_expression (file, expr -> data.substring.len, + col, scol, 0); + col = token_print_indent (file, col, indent, "", "", ")"); + break; + + case expr_suffix: + col = token_print_indent (file, col, indent, "", "", "suffix"); + col = token_print_indent (file, col, indent, " ", "", "("); + scol = col; + col = write_expression (file, expr -> data.suffix.expr, + col, scol, 1); + col = token_print_indent (file, col, scol, "", " ", ","); + col = write_expression (file, expr -> data.suffix.len, + col, scol, 0); + col = token_print_indent (file, col, indent, "", "", ")"); + break; + + case expr_concat: + e = expr; + col = token_print_indent (file, col, indent, "", "", + "concat"); + col = token_print_indent (file, col, indent, " ", "", "("); + scol = col; + firstp = 1; + concat_again: + col = write_expression (file, e -> data.concat [0], + col, scol, firstp); + firstp = 0; + if (!e -> data.concat [1]) + goto no_concat_cdr; + col = token_print_indent (file, col, scol, "", " ", ","); + if (e -> data.concat [1] -> op == expr_concat) { + e = e -> data.concat [1]; + goto concat_again; + } + col = write_expression (file, e -> data.concat [1], + col, scol, 0); + no_concat_cdr: + col = token_print_indent (file, col, indent, "", "", ")"); + break; + + case expr_host_lookup: + col = token_print_indent (file, col, indent, "", "", + "gethostbyname"); + col = token_print_indent (file, col, indent, " ", "", "("); + col = token_print_indent_concat + (file, col, indent, "", "", + "\"", expr -> data.host_lookup -> hostname, "\"", + (char *)0); + col = token_print_indent (file, col, indent, "", "", ")"); + break; + + case expr_add: + s = "+"; + goto binary; + + case expr_subtract: + s = "-"; + goto binary; + + case expr_multiply: + s = "*"; + goto binary; + + case expr_divide: + s = "/"; + goto binary; + + case expr_remainder: + s = "%"; + goto binary; + + case expr_binary_and: + s = "&"; + goto binary; + + case expr_binary_or: + s = "|"; + goto binary; + + case expr_binary_xor: + s = "^"; + goto binary; + + case expr_and: + s = "and"; + goto binary; + + case expr_or: + s = "or"; + goto binary; + + case expr_not: + col = token_print_indent (file, col, indent, "", " ", "not"); + col = write_expression (file, + expr -> data.not, col, indent + 2, 1); + break; + + case expr_option: + s = "option"; + + print_option_name: + col = token_print_indent (file, col, indent, "", "", s); + + if (expr -> data.option -> universe != &dhcp_universe) { + col = token_print_indent (file, col, indent, + " ", "", + (expr -> data.option -> + universe -> name)); + col = token_print_indent (file, col, indent, "", "", + "."); + col = token_print_indent (file, col, indent, "", "", + expr -> data.option -> name); + } else { + col = token_print_indent (file, col, indent, " ", "", + expr -> data.option -> name); + } + break; + + case expr_hardware: + col = token_print_indent (file, col, indent, "", "", + "hardware"); + break; + + case expr_packet: + col = token_print_indent (file, col, indent, "", "", + "packet"); + col = token_print_indent (file, col, indent, " ", "", "("); + scol = col; + col = write_expression (file, expr -> data.packet.offset, + col, indent, 1); + col = token_print_indent (file, col, scol, "", " ", ","); + col = write_expression (file, expr -> data.packet.len, + col, scol, 0); + col = token_print_indent (file, col, indent, "", "", ")"); + break; + + case expr_const_data: + col = token_indent_data_string (file, col, indent, "", "", + &expr -> data.const_data); + break; + + case expr_extract_int8: + width = 8; + extract_int: + col = token_print_indent (file, col, indent, "", "", + "extract-int"); + col = token_print_indent (file, col, indent, " ", "", "("); + scol = col; + col = write_expression (file, expr -> data.extract_int, + col, indent, 1); + col = token_print_indent (file, col, scol, "", " ", ","); + sprintf (obuf, "%d", width); + col = token_print_indent (file, col, scol, " ", "", obuf); + col = token_print_indent (file, col, indent, "", "", ")"); + break; + + case expr_extract_int16: + width = 16; + goto extract_int; + + case expr_extract_int32: + width = 32; + goto extract_int; + + case expr_encode_int8: + width = 8; + encode_int: + col = token_print_indent (file, col, indent, "", "", + "encode-int"); + col = token_print_indent (file, col, indent, " ", "", "("); + scol = col; + col = write_expression (file, expr -> data.extract_int, + col, indent, 1); + col = token_print_indent (file, col, scol, "", " ", ","); + sprintf (obuf, "%d", width); + col = token_print_indent (file, col, scol, " ", "", obuf); + col = token_print_indent (file, col, indent, "", "", + ")"); + break; + + case expr_encode_int16: + width = 16; + goto encode_int; + + case expr_encode_int32: + width = 32; + goto encode_int; + + case expr_const_int: + sprintf (obuf, "%lu", expr -> data.const_int); + col = token_print_indent (file, col, indent, "", "", obuf); + break; + + case expr_exists: + s = "exists"; + goto print_option_name; + + case expr_encapsulate: + col = token_print_indent (file, col, indent, "", "", + "encapsulate"); + col = token_indent_data_string (file, col, indent, " ", "", + &expr -> data.encapsulate); + break; + + case expr_known: + col = token_print_indent (file, col, indent, "", "", "known"); + break; + + case expr_reverse: + col = token_print_indent (file, col, indent, "", "", + "reverse"); + col = token_print_indent (file, col, indent, " ", "", "("); + scol = col; + col = write_expression (file, expr -> data.reverse.width, + col, scol, 1); + col = token_print_indent (file, col, scol, "", " ", ","); + col = write_expression (file, expr -> data.reverse.buffer, + col, scol, 0); + col = token_print_indent (file, col, indent, "", "", + ")"); + break; + + case expr_leased_address: + col = token_print_indent (file, col, indent, "", "", + "leased-address"); + break; + + case expr_client_state: + col = token_print_indent (file, col, indent, "", "", + "client-state"); + break; + + case expr_binary_to_ascii: + col = token_print_indent (file, col, indent, "", "", + "binary-to-ascii"); + col = token_print_indent (file, col, indent, " ", "", + "("); + scol = col; + col = write_expression (file, expr -> data.b2a.base, + col, scol, 1); + col = token_print_indent (file, col, scol, "", " ", + ","); + col = write_expression (file, expr -> data.b2a.width, + col, scol, 0); + col = token_print_indent (file, col, scol, "", " ", + ","); + col = write_expression (file, expr -> data.b2a.seperator, + col, scol, 0); + col = token_print_indent (file, col, scol, "", " ", + ","); + col = write_expression (file, expr -> data.b2a.buffer, + col, scol, 0); + col = token_print_indent (file, col, indent, "", "", + ")"); + break; + + case expr_config_option: + s = "config-option"; + goto print_option_name; + + case expr_host_decl_name: + col = token_print_indent (file, col, indent, "", "", + "host-decl-name"); + break; + + case expr_pick_first_value: + e = expr; + col = token_print_indent (file, col, indent, "", "", + "concat"); + col = token_print_indent (file, col, indent, " ", "", + "("); + scol = col; + firstp = 1; + pick_again: + col = write_expression (file, + e -> data.pick_first_value.car, + col, scol, firstp); + firstp = 0; + /* We're being very lisp-like right now - instead of + representing this expression as (first middle . last) we're + representing it as (first middle last), which means that the + tail cdr is always nil. Apologies to non-wisp-lizards - may + this obscure way of describing the problem motivate you to + learn more about the one true computing language. */ + if (!e -> data.pick_first_value.cdr) + goto no_pick_cdr; + col = token_print_indent (file, col, scol, "", " ", + ","); + if (e -> data.pick_first_value.cdr -> op == + expr_pick_first_value) { + e = e -> data.pick_first_value.cdr; + goto pick_again; + } + col = write_expression (file, + e -> data.pick_first_value.cdr, + col, scol, 0); + no_pick_cdr: + col = token_print_indent (file, col, indent, "", "", + ")"); + break; + + case expr_lease_time: + col = token_print_indent (file, col, indent, "", "", + "lease-time"); + break; + + case expr_dns_transaction: + col = token_print_indent (file, col, indent, "", "", + "ns-update"); + col = token_print_indent (file, col, indent, " ", "", + "("); + scol = 0; + for (e = expr; + e && e -> op == expr_dns_transaction; + e = e -> data.dns_transaction.cdr) { + if (!scol) { + scol = col; + firstp = 1; + } else + firstp = 0; + col = write_expression (file, + e -> data.dns_transaction.car, + col, scol, firstp); + if (e -> data.dns_transaction.cdr) + col = token_print_indent (file, col, scol, + "", " ", ","); + } + if (e) + col = write_expression (file, e, col, scol, 0); + col = token_print_indent (file, col, indent, "", "", ")"); + break; + + case expr_ns_add: + col = token_print_indent (file, col, indent, "", "", + "update"); + col = token_print_indent (file, col, indent, " ", "", + "("); + scol = col; + sprintf (obuf, "%d", expr -> data.ns_add.rrclass); + col = token_print_indent (file, col, scol, "", "", obuf); + col = token_print_indent (file, col, scol, "", " ", + ","); + sprintf (obuf, "%d", expr -> data.ns_add.rrtype); + col = token_print_indent (file, col, scol, "", "", obuf); + col = token_print_indent (file, col, scol, "", " ", + ","); + col = write_expression (file, expr -> data.ns_add.rrname, + col, scol, 0); + col = token_print_indent (file, col, scol, "", " ", + ","); + col = write_expression (file, expr -> data.ns_add.rrdata, + col, scol, 0); + col = token_print_indent (file, col, scol, "", " ", + ","); + col = write_expression (file, expr -> data.ns_add.ttl, + col, scol, 0); + col = token_print_indent (file, col, indent, "", "", + ")"); + break; + + case expr_ns_delete: + col = token_print_indent (file, col, indent, "", "", + "delete"); + col = token_print_indent (file, col, indent, " ", "", + "("); + finish_ns_small: + scol = col; + sprintf (obuf, "%d", expr -> data.ns_add.rrclass); + col = token_print_indent (file, col, scol, "", "", obuf); + col = token_print_indent (file, col, scol, "", " ", + ","); + sprintf (obuf, "%d", expr -> data.ns_add.rrtype); + col = token_print_indent (file, col, scol, "", "", obuf); + col = token_print_indent (file, col, scol, "", " ", + ","); + col = write_expression (file, expr -> data.ns_add.rrname, + col, scol, 0); + col = token_print_indent (file, col, scol, "", " ", + ","); + col = write_expression (file, expr -> data.ns_add.rrdata, + col, scol, 0); + col = token_print_indent (file, col, indent, "", "", + ")"); + break; + + case expr_ns_exists: + col = token_print_indent (file, col, indent, "", "", + "exists"); + col = token_print_indent (file, col, indent, " ", "", + "("); + goto finish_ns_small; + + case expr_ns_not_exists: + col = token_print_indent (file, col, indent, "", "", + "not exists"); + col = token_print_indent (file, col, indent, " ", "", + "("); + goto finish_ns_small; + + case expr_static: + col = token_print_indent (file, col, indent, "", "", + "static"); + break; + + case expr_null: + col = token_print_indent (file, col, indent, "", "", "null"); + break; + + case expr_variable_reference: + col = token_print_indent (file, indent, indent, "", "", + expr -> data.variable); + break; + + case expr_variable_exists: + col = token_print_indent (file, indent, indent, "", "", + "defined"); + col = token_print_indent (file, col, indent, " ", "", "("); + col = token_print_indent (file, col, indent, "", "", + expr -> data.variable); + col = token_print_indent (file, col, indent, "", "", ")"); + break; + + default: + log_fatal ("invalid expression type in print_expression: %d", + expr -> op); + } + return col; +} + +struct binding *find_binding (struct binding_scope *scope, const char *name) +{ + struct binding *bp; + struct binding_scope *s; + + for (s = scope; s; s = s -> outer) { + for (bp = s -> bindings; bp; bp = bp -> next) { + if (!strcasecmp (name, bp -> name)) { + return bp; + } + } + } + return (struct binding *)0; +} + +int free_bindings (struct binding_scope *scope, const char *file, int line) +{ + struct binding *bp, *next; + + for (bp = scope -> bindings; bp; bp = next) { + next = bp -> next; + if (bp -> name) + dfree (bp -> name, file, line); + if (bp -> value) + binding_value_dereference (&bp -> value, file, line); + dfree (bp, file, line); + } + scope -> bindings = (struct binding *)0; + return 1; +} + +int binding_scope_dereference (ptr, file, line) + struct binding_scope **ptr; + const char *file; + int line; +{ + int i; + struct binding_scope *binding_scope; + + if (!ptr || !*ptr) { + log_error ("%s(%d): null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + + binding_scope = *ptr; + *ptr = (struct binding_scope *)0; + --binding_scope -> refcnt; + rc_register (file, line, ptr, + binding_scope, binding_scope -> refcnt, 1, RC_MISC); + if (binding_scope -> refcnt > 0) + return 1; + + if (binding_scope -> refcnt < 0) { + log_error ("%s(%d): negative refcnt!", file, line); +#if defined (DEBUG_RC_HISTORY) + dump_rc_history (binding_scope); +#endif +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + + free_bindings (binding_scope, file, line); + if (binding_scope -> outer) + binding_scope_dereference (&binding_scope -> outer, MDL); + dfree (binding_scope, file, line); + return 1; +} + +int fundef_dereference (ptr, file, line) + struct fundef **ptr; + const char *file; + int line; +{ + struct fundef *bp = *ptr; + struct string_list *sp, *next; + + if (!ptr) { + log_error ("%s(%d): null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + + if (!bp) { + log_error ("%s(%d): null pointer", file, line); +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + + bp -> refcnt--; + rc_register (file, line, ptr, bp, bp -> refcnt, 1, RC_MISC); + if (bp -> refcnt < 0) { + log_error ("%s(%d): negative refcnt!", file, line); +#if defined (DEBUG_RC_HISTORY) + dump_rc_history (bp); +#endif +#if defined (POINTER_DEBUG) + abort (); +#else + return 0; +#endif + } + if (!bp -> refcnt) { + for (sp = bp -> args; sp; sp = next) { + next = sp -> next; + dfree (sp, file, line); + } + if (bp -> statements) + executable_statement_dereference (&bp -> statements, + file, line); + dfree (bp, file, line); + } + *ptr = (struct fundef *)0; + return 1; +} + +#if defined (NOTYET) /* Post 3.0 final. */ +int data_subexpression_length (int *rv, + struct expression *expr) +{ + int crhs, clhs, llhs, lrhs; + switch (expr -> op) { + case expr_substring: + if (expr -> data.substring.len && + expr -> data.substring.len -> op == expr_const_int) { + (*rv = + (int)expr -> data.substring.len -> data.const_int); + return 1; + } + return 0; + + case expr_packet: + case expr_suffix: + if (expr -> data.suffix.len && + expr -> data.suffix.len -> op == expr_const_int) { + (*rv = + (int)expr -> data.suffix.len -> data.const_int); + return 1; + } + return 0; + + case expr_concat: + clhs = data_subexpression_length (&llhs, + expr -> data.concat [0]); + crhs = data_subexpression_length (&lrhs, + expr -> data.concat [1]); + if (crhs == 0 || clhs == 0) + return 0; + *rv = llhs + lrhs; + return 1; + break; + + case expr_hardware: + return 0; + + case expr_const_data: + *rv = expr -> data.const_data.len; + return 2; + + case expr_reverse: + return data_subexpression_length (rv, + expr -> data.reverse.buffer); + + case expr_leased_address: + case expr_lease_time: + *rv = 4; + return 2; + + case expr_pick_first_value: + clhs = data_subexpression_length (&llhs, + expr -> data.concat [0]); + crhs = data_subexpression_length (&lrhs, + expr -> data.concat [1]); + if (crhs == 0 || clhs == 0) + return 0; + if (llhs > lrhs) + *rv = llhs; + else + *rv = lrhs; + return 1; + + case expr_binary_to_ascii: + case expr_config_option: + case expr_host_decl_name: + case expr_encapsulate: + case expr_filename: + case expr_sname: + case expr_host_lookup: + case expr_option: + case expr_none: + case expr_match: + case expr_check: + case expr_equal: + case expr_and: + case expr_or: + case expr_not: + case expr_extract_int8: + case expr_extract_int16: + case expr_extract_int32: + case expr_encode_int8: + case expr_encode_int16: + case expr_encode_int32: + case expr_const_int: + case expr_exists: + case expr_known: + case expr_dns_transaction: + case expr_static: + case expr_ns_add: + case expr_ns_delete: + case expr_ns_exists: + case expr_ns_not_exists: + case expr_not_equal: + case expr_null: + case expr_variable_exists: + case expr_variable_reference: + case expr_arg: + case expr_funcall: + case expr_function: + case expr_add: + case expr_subtract: + case expr_multiply: + case expr_divide: + case expr_remainder: + case expr_binary_and: + case expr_binary_or: + case expr_binary_xor: + case expr_client_state: + return 0; + } + return 0; +} + +int expr_valid_for_context (struct expression *expr, + enum expression_context context) +{ + /* We don't know at parse time what type of value a function may + return, so we can't flag an error on it. */ + if (expr -> op == expr_funcall || + expr -> op == expr_variable_reference) + return 1; + + switch (context) { + case context_any: + return 1; + + case context_boolean: + if (is_boolean_expression (expr)) + return 1; + return 0; + + case context_data: + if (is_data_expression (expr)) + return 1; + return 0; + + case context_numeric: + if (is_numeric_expression (expr)) + return 1; + return 0; + + case context_dns: + if (is_dns_expression (expr)) { + return 1; + } + return 0; + + case context_data_or_numeric: + if (is_numeric_expression (expr) || + is_data_expression (expr)) { + return 1; + } + return 0; + + case context_function: + if (expr -> op == expr_function) + return 1; + return 0; + } + return 0; +} +#endif /* NOTYET */ + +struct binding *create_binding (struct binding_scope **scope, const char *name) +{ + struct binding *binding; + + if (!*scope) { + if (!binding_scope_allocate (scope, MDL)) + return (struct binding *)0; + } + + binding = find_binding (*scope, name); + if (!binding) { + binding = dmalloc (sizeof *binding, MDL); + if (!binding) + return (struct binding *)0; + + memset (binding, 0, sizeof *binding); + binding -> name = dmalloc (strlen (name) + 1, MDL); + if (!binding -> name) { + dfree (binding, MDL); + return (struct binding *)0; + } + strcpy (binding -> name, name); + + binding -> next = (*scope) -> bindings; + (*scope) -> bindings = binding; + } + + return binding; +} + + +int bind_ds_value (struct binding_scope **scope, + const char *name, + struct data_string *value) +{ + struct binding *binding; + + binding = create_binding (scope, name); + if (!binding) + return 0; + + if (binding -> value) + binding_value_dereference (&binding -> value, MDL); + + if (!binding_value_allocate (&binding -> value, MDL)) + return 0; + + data_string_copy (&binding -> value -> value.data, value, MDL); + binding -> value -> type = binding_data; + + return 1; +} + + +int find_bound_string (struct data_string *value, + struct binding_scope *scope, + const char *name) +{ + struct binding *binding; + + binding = find_binding (scope, name); + if (!binding || + !binding -> value || + binding -> value -> type != binding_data) + return 0; + + if (binding -> value -> value.data.terminated) { + data_string_copy (value, &binding -> value -> value.data, MDL); + } else { + buffer_allocate (&value -> buffer, + binding -> value -> value.data.len, + MDL); + if (!value -> buffer) + return 0; + + memcpy (value -> buffer -> data, + binding -> value -> value.data.data, + binding -> value -> value.data.len); + value -> data = value -> buffer -> data; + value -> len = binding -> value -> value.data.len; + } + + return 1; +} + +int unset (struct binding_scope *scope, const char *name) +{ + struct binding *binding; + + binding = find_binding (scope, name); + if (binding) { + if (binding -> value) + binding_value_dereference + (&binding -> value, MDL); + return 1; + } + return 0; +} + +/* vim: set tabstop=8: */ diff --git a/contrib/isc-dhcp/common/upf.c b/contrib/isc-dhcp/common/upf.c index 70f8eff..a737d57 100644 --- a/contrib/isc-dhcp/common/upf.c +++ b/contrib/isc-dhcp/common/upf.c @@ -3,8 +3,8 @@ Ultrix PacketFilter interface code. */ /* - * Copyright (c) 1995, 1996, 1997, 1998, 1999 - * The Internet Software Consortium. All rights reserved. + * Copyright (c) 1996-2000 Internet Software Consortium. + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -34,15 +34,16 @@ * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium - * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie - * Enterprises. To learn more about the Internet Software Consortium, - * see ``http://www.vix.com/isc''. To learn more about Vixie - * Enterprises, see ``http://www.vix.com''. + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. */ #ifndef lint static char copyright[] = -"$Id: upf.c,v 1.3.2.5 1999/03/29 22:07:13 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium. All rights reserved.\n"; +"$Id: upf.c,v 1.21 2000/09/01 23:03:39 mellon Exp $ Copyright (c) 1996-2000 The Internet Software Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -97,7 +98,7 @@ int if_register_upf (info) if (errno == EBUSY) { continue; } else { - error ("Can't find free upf: %m"); + log_fatal ("Can't find free upf: %m"); } } else { break; @@ -106,26 +107,26 @@ int if_register_upf (info) /* Set the UPF device to point at this interface. */ if (ioctl (sock, EIOCSETIF, info -> ifp) < 0) - error ("Can't attach interface %s to upf device %s: %m", + log_fatal ("Can't attach interface %s to upf device %s: %m", info -> name, filename); /* Get the hardware address. */ if (ioctl (sock, EIOCDEVP, ¶m) < 0) - error ("Can't get interface %s hardware address: %m", + log_fatal ("Can't get interface %s hardware address: %m", info -> name); /* We only know how to do ethernet. */ if (param.end_dev_type != ENDT_10MB) - error ("Invalid device type on network interface %s: %d", + log_fatal ("Invalid device type on network interface %s: %d", info -> name, param.end_dev_type); if (param.end_addr_len != 6) - error ("Invalid hardware address length on %s: %d", + log_fatal ("Invalid hardware address length on %s: %d", info -> name, param.end_addr_len); - info -> hw_address.hlen = 6; - info -> hw_address.htype = ARPHRD_ETHER; - memcpy (&info -> hw_address.haddr [0], param.end_addr, 6); + info -> hw_address.hlen = 7; + info -> hw_address.hbuf [0] = ARPHRD_ETHER; + memcpy (&info -> hw_address.hbuf [1], param.end_addr, 6); return sock; } @@ -143,11 +144,29 @@ void if_register_send (info) info -> wfdesc = info -> rfdesc; #endif if (!quiet_interface_discovery) - note ("Sending on UPF/%s/%s%s%s", + log_info ("Sending on UPF/%s/%s%s%s", info -> name, - print_hw_addr (info -> hw_address.htype, - info -> hw_address.hlen, - info -> hw_address.haddr), + print_hw_addr (info -> hw_address.hbuf [0], + info -> hw_address.hlen - 1, + &info -> hw_address.hbuf [1]), + (info -> shared_network ? "/" : ""), + (info -> shared_network ? + info -> shared_network -> name : "")); +} + +void if_deregister_send (info) + struct interface_info *info; +{ +#ifndef USE_UPF_RECEIVE + close (info -> wfdesc); +#endif + info -> wfdesc = -1; + if (!quiet_interface_discovery) + log_info ("Disabling output on UPF/%s/%s%s%s", + info -> name, + print_hw_addr (info -> hw_address.hbuf [0], + info -> hw_address.hlen - 1, + &info -> hw_address.hbuf [1]), (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : "")); @@ -173,18 +192,18 @@ void if_register_receive (info) /* Allow the copyall flag to be set... */ if (ioctl(info -> rfdesc, EIOCALLOWCOPYALL, &flag) < 0) - error ("Can't set ALLOWCOPYALL: %m"); + log_fatal ("Can't set ALLOWCOPYALL: %m"); /* Clear all the packet filter mode bits first... */ flag = (ENHOLDSIG | ENBATCH | ENTSTAMP | ENPROMISC | ENNONEXCL | ENCOPYALL); if (ioctl (info -> rfdesc, EIOCMBIC, &flag) < 0) - error ("Can't clear pfilt bits: %m"); + log_fatal ("Can't clear pfilt bits: %m"); /* Set the ENBATCH and ENCOPYALL bits... */ bits = ENBATCH | ENCOPYALL; if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0) - error ("Can't set ENBATCH|ENCOPYALL: %m"); + log_fatal ("Can't set ENBATCH|ENCOPYALL: %m"); /* Set up the UPF filter program. */ /* XXX Unlike the BPF filter program, this one won't work if the @@ -207,13 +226,29 @@ void if_register_receive (info) pf.enf_Filter [pf.enf_FilterLen++] = local_port; if (ioctl (info -> rfdesc, EIOCSETF, &pf) < 0) - error ("Can't install packet filter program: %m"); + log_fatal ("Can't install packet filter program: %m"); if (!quiet_interface_discovery) - note ("Listening on UPF/%s/%s%s%s", + log_info ("Listening on UPF/%s/%s%s%s", info -> name, - print_hw_addr (info -> hw_address.htype, - info -> hw_address.hlen, - info -> hw_address.haddr), + print_hw_addr (info -> hw_address.hbuf [0], + info -> hw_address.hlen - 1, + &info -> hw_address.hbuf [1]), + (info -> shared_network ? "/" : ""), + (info -> shared_network ? + info -> shared_network -> name : "")); +} + +void if_deregister_receive (info) + struct interface_info *info; +{ + close (info -> rfdesc); + info -> rfdesc = -1; + if (!quiet_interface_discovery) + log_info ("Disabling input on UPF/%s/%s%s%s", + info -> name, + print_hw_addr (info -> hw_address.hbuf [0], + info -> hw_address.hlen - 1, + &info -> hw_address.hbuf [1]), (info -> shared_network ? "/" : ""), (info -> shared_network ? info -> shared_network -> name : "")); @@ -230,30 +265,35 @@ ssize_t send_packet (interface, packet, raw, len, from, to, hto) struct sockaddr_in *to; struct hardware *hto; { - int bufp = 0; - unsigned char buf [256]; - struct iovec iov [2]; + unsigned hbufp = 0, ibufp = 0; + double hw [4]; + double ip [32]; + struct iovec iov [3]; int result; + int fudge; if (!strcmp (interface -> name, "fallback")) return send_fallback (interface, packet, raw, len, from, to, hto); /* Assemble the headers... */ - assemble_hw_header (interface, buf, &bufp, hto); - assemble_udp_ip_header (interface, buf, &bufp, from.s_addr, + assemble_hw_header (interface, (unsigned char *)hw, &hbufp, hto); + assemble_udp_ip_header (interface, + (unsigned char *)ip, &ibufp, from.s_addr, to -> sin_addr.s_addr, to -> sin_port, (unsigned char *)raw, len); /* Fire it off */ - iov [0].iov_base = (char *)buf; - iov [0].iov_len = bufp; - iov [1].iov_base = (char *)raw; - iov [1].iov_len = len; - - result = writev(interface -> wfdesc, iov, 2); + iov [0].iov_base = ((char *)hw); + iov [0].iov_len = hbufp; + iov [1].iov_base = ((char *)ip); + iov [1].iov_len = ibufp; + iov [2].iov_base = (char *)raw; + iov [2].iov_len = len; + + result = writev(interface -> wfdesc, iov, 3); if (result < 0) - warn ("send_packet: %m"); + log_error ("send_packet: %m"); return result; } #endif /* USE_UPF_SEND */ @@ -306,7 +346,8 @@ ssize_t receive_packet (interface, buf, len, from, hfrom) return length; } -int can_unicast_without_arp () +int can_unicast_without_arp (ip) + struct interface_info *ip; { return 1; } @@ -317,14 +358,25 @@ int can_receive_unicast_unconfigured (ip) return 1; } +int supports_multiple_interfaces (ip) + struct interface_info *ip; +{ + return 1; +} + void maybe_setup_fallback () { - struct interface_info *fbi; - fbi = setup_fallback (); - if (fbi) { + isc_result_t status; + struct interface_info *fbi = (struct interface_info *)0; + if (setup_fallback (&fbi, MDL)) { if_register_fallback (fbi); - add_protocol ("fallback", fallback_interface -> wfdesc, - fallback_discard, fallback_interface); + status = omapi_register_io_object ((omapi_object_t *)fbi, + if_readsocket, 0, + fallback_discard, 0, 0); + if (status != ISC_R_SUCCESS) + log_fatal ("Can't register I/O handle for %s: %s", + fbi -> name, isc_result_totext (status)); + interface_dereference (&fbi, MDL); } } #endif diff --git a/contrib/isc-dhcp/configure b/contrib/isc-dhcp/configure index 190b3c5..3f504be 100755 --- a/contrib/isc-dhcp/configure +++ b/contrib/isc-dhcp/configure @@ -1,20 +1,72 @@ #!/bin/sh -sysname=$1 +#sysname=$1 + +while [ $# != 0 ]; do + if [ x$1 = x--with-nsupdate ]; then + echo "nsupdate is always built now." + elif [ x$1 = x--print-sysname ]; then + print_sysname=yes + elif [ x$1 = x--work-dir ]; then + workname=$2 + shift + elif [ x$1 = x--dirs ]; then + dirs=$2 + shift + elif [ x$1 = x--no-links ]; then + nolinks=YES + elif [ x$1 = x--copts ]; then + copts=$2 + shift + elif [ x$sysname = x ]; then + sysname=$1 + else + echo "Unexpected argument: $1" + fi + shift +done uname=`uname -s` machine=`uname -m` if [ "$sysname" = "" ]; then case $uname in + SCO_SV) + IFS=":" + for foo in $PATH; do + if [ x$gcc_path = x ] && [ -x $foo/gcc ]; then + gcc_path=$foo/gcc + fi + done + IFS=" " + if [ x$gcc_path = x ]; then + sysname=sco-cc + sysname_print=sco + else + sysname=sco-gcc + sysname_print=sco + fi + ;; AIX) sysname=aix;; + Darwin) + sysname=darwin;; Rhapsody) sysname=rhapsody;; ULTRIX) sysname=ultrix;; BSD/OS) - sysname=bsdos;; + release=`uname -r` + minor=`echo $release |sed -e 's/[0-9]*\.\([0-9][0-9]*\)\(\..*\)*$/\1/'` + major=`echo $release |sed -e 's/\([0-9][0-9]*\)\..*$/\1/'` + + case $major in + [123]) sysname=bsdos ;; + *) case $minor in + 0) sysname=bsdos ;; + *) sysname=bsdos-4.1 ;; + esac;; + esac;; OSF1) if [ $machine = 'alpha' ]; then sysname=alphaosf @@ -34,53 +86,137 @@ if [ "$sysname" = "" ]; then esac;; esac;; SunOS) - case `uname -r` in - 4*) sysname=sunos4;; - 5*) - set `which gcc` - if [ $# = 1 ]; then - sysname=sunos5-gcc - else + release=`uname -r` + minor=`echo $release |sed -e 's/.*[0-9]*\.\([0-9][0-9]*\).*$/\1/'` + major=`echo $release |sed -e 's/\([0-9][0-9]*\)\..*$/\1/'` + IFS=":" + for foo in $PATH; do + if [ x$gcc_path = x ] && [ -x $foo/gcc ]; then + gcc_path=$foo/gcc + fi + done + IFS=" " + + case $major in + 4) + if [ x$gcc_path = x ]; then + echo SunOS 4 build will not work without the GNU C Compiler. + exit 1 + fi + sysname=sunos4;; + 5) + if [ x$gcc_path = x ]; then sysname=sunos5-cc + sysname_print=sunos5 + else + sysname=sunos5-gcc + sysname_print=sunos5 fi;; esac;; NetBSD) - sysname=netbsd;; + hw=`uname -m` + case $hw in + arm32) sysname=netbsd-nocast;; + alpha) sysname=netbsd-nocast;; + *) sysname=netbsd;; + esac;; + OpenBSD) + sysname=openbsd;; FreeBSD) sysname=freebsd;; hpux) - sysname=hpux;; + IFS=":" + for foo in $PATH; do + if [ x$gcc_path = x ] && [ -x $foo/gcc ]; then + gcc_path=$foo/gcc + fi + done + IFS=" " + + if [ x$gcc_path = x ]; then + sysname=hpux-cc + sysname_print=hpux + else + sysname=hpux-gcc + sysname_print=hpux + fi;; HP-UX) - sysname=hpux;; + IFS=":" + for foo in $PATH; do + if [ x$gcc_path = x ] && [ -x $foo/gcc ]; then + gcc_path=$foo/gcc + fi + done + IFS=" " + + if [ x$gcc_path = x ]; then + sysname=hpux-cc + sysname_print=hpux + else + sysname=hpux-gcc + sysname_print=hpux + fi;; QNX) - sysname=qnx;; + release=`uname -r` + major=`echo $release |sed -e 's/\([0-9][0-9]*\)\..*$/\1/'` + case $major in + 6) + sysname=qnxnto;; + *) + sysname=qnx;; + esac;; NEXTSTEP) sysname=nextstep;; + UnixWare) + sysname=uw7;; esac fi if [ "$sysname" = "" ]; then - echo "UNIX name: $uname machine: $machine" - echo - echo "Unknown system. If this is an SCO system running ODT 3.0 or" - echo "higher, type \`\`./configure sco''. Otherwise, this is a" - echo "configuration that isn't supported or hasn't been tested." - echo - echo "Supported configurations are:" - echo " aix AIX 4.1.5.0" - echo " ultrix ULTRIX 4.2A or higher" - echo " bsdos BSDI BSD/OS 2.1" - echo " alphaosf DEC Alpha OSF/1" - echo " linux Linux" - echo " sunos4 Sunos 4.1.4 (earlier releases may work)" - echo " sunos5-cc Solaris 2.4 or higher with Sun cc" - echo " sunos5-gcc Solaris 2.4 or higher with gcc" - echo " netbsd NetBSD 1.1 or higher" - echo " freebsd FreeBSD" - echo " hpux HP-UX" - echo " qnx QNX 4.2 or higher" - echo " NEXTSTEP NeXTSTEP" - exit 1; + if [ x$print_sysname = xyes ]; then + echo "unknown" + else + echo "UNIX name: $uname machine: $machine" + echo + echo "Unknown system. If this is an SCO system running ODT 3.0 or" + echo "higher, type \`\`./configure sco''. Otherwise, this is a" + echo "configuration that isn't supported or hasn't been tested." + echo + echo "Supported configurations are:" + echo " aix AIX 4.1.5.0" + echo " ultrix ULTRIX 4.2A or higher" + echo " bsdos BSDI BSD/OS 2.1" + echo " alphaosf DEC Alpha OSF/1" + echo " linux Linux" + echo " sunos4 Sunos 4.1.4 (earlier releases may work)" + echo " sunos5-cc Solaris 2.4 or higher with Sun cc" + echo " sunos5-gcc Solaris 2.4 or higher with gcc" + echo " netbsd NetBSD 1.1 or higher" + echo " freebsd FreeBSD" + echo " openbsd OpenBSD (i386/alpha)" + echo " hpux HP-UX" + echo " qnx QNX 4.2 or higher" + echo " NEXTSTEP NeXTSTEP" + echo " sco SCO Open Server" + exit 1; + fi +fi + +if [ x$print_sysname = xyes ]; then + if [ x$sysname_print != x ]; then + echo $sysname_print + else + echo $sysname + fi + exit 0 +fi + +if [ x$workname = x ]; then + if [ x$sysname_print != x ]; then + workname=work.${sysname_print} + else + workname=work.${sysname} + fi fi echo "System Type: $sysname" @@ -90,11 +226,32 @@ if [ x$major != x ] && [ x$minor != x ]; then minversubst="-e /^##--minver--/,/^##--minver--/s/MinorVersion/$minor/" fi -for foo in . client server relay common; do - (sed $majversubst $minversubst \ +if [ ! -d $workname ]; then + mkdir $workname +fi + +if [ x"$dirs" = x ]; then + dirs=". client server relay common omapip dhcpctl minires dst" +fi + +for foo in $dirs; do + bar=`basename $foo` + if [ ! -d ${workname}/$bar ]; then + mkdir ${workname}/$bar + fi + (sed $majversubst $minversubst \ -e "/^##--${sysname}--/,/^##--${sysname}--/s/^#//" \ - <Makefile.conf; cat $foo/Makefile.dist) \ - >$foo/Makefile + <Makefile.conf; \ + cat site.conf; \ + echo "TOP = `pwd`"; \ + echo CC_OPTIONS = $copts; \ + cat $foo/Makefile.dist) \ + >${workname}/$bar/Makefile done +# Make the link tree in which to actually build. +if [ x$nolinks = x ]; then + make links +fi + exit 0 diff --git a/contrib/isc-dhcp/contrib/3.0b1-lease-convert b/contrib/isc-dhcp/contrib/3.0b1-lease-convert new file mode 100755 index 0000000..049a3a7 --- /dev/null +++ b/contrib/isc-dhcp/contrib/3.0b1-lease-convert @@ -0,0 +1,126 @@ +#!/usr/bin/perl +# +# Start Date: Mon, 26 Mar 2001 14:24:09 +0200 +# Time-stamp: <Monday, 26 March 2001 16:09:44 by brister> +# File: leaseconvertor.pl +# RCSId: $Id: 3.0b1-lease-convert,v 1.1 2001/04/18 19:17:34 mellon Exp $ +# +# Description: Convert 3.0b1 to 3.0b2/final lease file format +# + +require 5.004; + +my $rcsID =<<'EOM'; +$Id: 3.0b1-lease-convert,v 1.1 2001/04/18 19:17:34 mellon Exp $ +EOM + +use strict; + +my $revstatement =<<'EOS'; + switch (ns-update (delete (1, 12, ddns-rev-name, null))) { + case 0: + unset ddns-rev-name; + break; + } +EOS + +my $fwdstatement =<<'EOS'; + switch (ns-update (delete (1, 1, ddns-fwd-name, leased-address))) { + case 0: + unset ddns-fwd-name; + break; + } +EOS + + +if (@ARGV && $ARGV[0] =~ m!^-!) { + usage(); +} + + + +# read stdin and write stdout. +while (<>) { + if (! /^lease\s/) { + print; + } else { + my $lease = $_; + while (<>) { + $lease .= $_; + # in a b1 file we should only see a left curly brace on a lease + # lines. Seening it anywhere else means the user is probably + # running a b2 or later file through this. + # Ditto for a 'set' statement. + if (m!\{! || m!^\s*set\s!) { + warn "this doesn't look like a 3.0b1 file. Ignoring rest.\n"; + print $lease; + dumpRestAndExit(); + } + + last if m!^\}\s*$!; + } + + # $lease contains all the lines for the lease entry. + $lease = makeNewLease($lease); + print $lease; + } +} + + + +sub usage { + my $prog = $0; + $prog =~ s!.*/!!; + + print STDERR <<EOM; +usage: $prog [ file ] + +Reads from the lease file listed on the command line (or stdin if not filename +given) and writes to stdout. Converts a 3.0b1-style leases file to a 3.0b2 +style (for ad-hoc ddns updates). +EOM + + exit (0); +} + + + +# takes a string that's the lines of a lease entry and converts it, if +# necessary to a b2 style lease entry. Returns the new lease in printable form. +sub makeNewLease { + my ($lease) = @_; + + my $convertedfwd; + my $convertedrev; + my $newlease = ""; + foreach (split "\n", $lease) { + if (m!^(\s+)(ddns-fwd-name|ddns-rev-name)\s+(\"[^\"]+\"\s*;)!) { + $newlease .= $1 . "set " . $2 . " = " . $3 . "\n"; + + # If there's one of them, then it will always be the -fwd-. There + # may not always be a -rev-. + $convertedfwd++; + $convertedrev++ if ($2 eq "ddns-rev-name"); + } elsif (m!^\s*\}!) { + if ($convertedfwd) { + $newlease .= "\ton expiry or release {\n"; + $newlease .= $revstatement if $convertedrev; + $newlease .= $fwdstatement; + $newlease .= "\t on expiry or release;\n\t}\n"; + } + $newlease .= "}\n"; + } else { + $newlease .= $_ . "\n"; + } + } + + return $newlease; +} + + +sub dumpRestAndExit { + while (<>) { + print; + } + exit (0); +} diff --git a/contrib/isc-dhcp/contrib/sethostname.sh b/contrib/isc-dhcp/contrib/sethostname.sh new file mode 100644 index 0000000..7088c00 --- /dev/null +++ b/contrib/isc-dhcp/contrib/sethostname.sh @@ -0,0 +1,29 @@ +#!/bin/sh + +# This script can be installed in /etc/dhclient-enter-hooks to set the client's +# hostname based either on the hostname that the DHCP server supplied or the +# hostname in whatever ptr record exists for the assigned IP address. + +if [ x$new_host_name = x ]; then + ptrname=`echo $new_ip_address \ + |sed -e \ + 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\4.\3.\2.\1.in-addr.arpa/'` + (echo "set type=ptr"; echo "$ptrname") |nslookup >/tmp/nslookup.$$ + set `sed -n -e "s/$ptrname[ ]*\(canonical \)*name *= *\(.*\)/\2 \1/p" \ + < /tmp/nslookup.$$` _ + if [ x$1 = x_ ]; then + new_host_name="" + else + if [ $# -gt 1 ] && [ x$2 = xcanonical ]; then + new_host_name=`sed -n -e "s/$1[ ]*name *= *\(.*\)/\1/p" \ + </tmp/nslookup.$$` + else + new_host_name=$1 + fi + fi + rm /tmp/nslookup.$$ +fi +if [ x$new_host_name != x ]; then + hostname $new_host_name +fi + diff --git a/contrib/isc-dhcp/dst/Makefile.dist b/contrib/isc-dhcp/dst/Makefile.dist new file mode 100644 index 0000000..2bd3369 --- /dev/null +++ b/contrib/isc-dhcp/dst/Makefile.dist @@ -0,0 +1,55 @@ +# Makefile.dist +# +# Copyright (c) 1996-2000 Internet Software Consortium. +# Use is subject to license terms which appear in the file named +# ISC-LICENSE that should have accompanied this file when you +# received it. If a file named ISC-LICENSE did not accompany this +# file, or you are not sure the one you have is correct, you may +# obtain an applicable copy of the license at: +# +# http://www.isc.org/isc-license-1.0.html. +# +# This file is part of the ISC DHCP distribution. The documentation +# associated with this file is listed in the file DOCUMENTATION, +# included in the top-level directory of this release. +# +# Support and other services are available for ISC products - see +# http://www.isc.org for more information. +# + +SRC = dst_support.c dst_api.c hmac_link.c md5_dgst.c base64.c prandom.c +OBJ = dst_support.o dst_api.o hmac_link.o md5_dgst.o base64.o prandom.o +HDRS = dst_internal.h md5.h md5_locl.h + +INCLUDES = $(BINDINC) -I$(TOP)/includes +CFLAGS = $(DEBUG) $(PREDEFINES) $(INCLUDES) $(COPTS) -DHMAC_MD5 -DMINIRES_LIB + +all: libdst.a + +install: + +libdst.a: $(OBJ) + rm -f dst.a + ar cruv libdst.a $(OBJ) + $(RANLIB) libdst.a + +depend: + $(MKDEP) $(INCLUDES) $(PREDEFINES) $(SRC) + +clean: + -rm -f $(OBJ) libdst.a + +realclean: clean + -rm -f *~ $(CATMANPAGES) $(SEDMANPAGES) + +distclean: realclean + -rm -f Makefile + +links: + @for foo in $(SRC) $(MAN) $(HDRS); do \ + if [ ! -b $$foo ]; then \ + rm -f $$foo; \ + fi; \ + ln -s $(TOP)/dst/$$foo $$foo; \ + done +# Dependencies (semi-automatically-generated) diff --git a/contrib/isc-dhcp/dst/base64.c b/contrib/isc-dhcp/dst/base64.c new file mode 100644 index 0000000..dff9412 --- /dev/null +++ b/contrib/isc-dhcp/dst/base64.c @@ -0,0 +1,319 @@ +/* + * Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, 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. + */ + +/* + * Portions Copyright (c) 1995 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * To the extent it has a right to do so, IBM grants an immunity from suit + * under its patents, if any, for the use, sale or manufacture of products to + * the extent that such products are used for performing Domain Name System + * dynamic updates in TCP/IP networks by means of the Software. No immunity is + * granted for any product per se or for any other function of any product. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +#if !defined(LINT) && !defined(CODECENTER) +static const char rcsid[] = "$Id: base64.c,v 1.1 2001/02/22 07:22:08 mellon Exp $"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <sys/socket.h> + +#include "minires/minires.h" +#include "arpa/nameser.h" + +#define Assert(Cond) if (!(Cond)) abort() + +static const char Base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char Pad64 = '='; + +/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) + The following encoding technique is taken from RFC 1521 by Borenstein + and Freed. It is reproduced here in a slightly edited form for + convenience. + + A 65-character subset of US-ASCII is used, enabling 6 bits to be + represented per printable character. (The extra 65th character, "=", + is used to signify a special processing function.) + + The encoding process represents 24-bit groups of input bits as output + strings of 4 encoded characters. Proceeding from left to right, a + 24-bit input group is formed by concatenating 3 8-bit input groups. + These 24 bits are then treated as 4 concatenated 6-bit groups, each + of which is translated into a single digit in the base64 alphabet. + + Each 6-bit group is used as an index into an array of 64 printable + characters. The character referenced by the index is placed in the + output string. + + Table 1: The Base64 Alphabet + + Value Encoding Value Encoding Value Encoding Value Encoding + 0 A 17 R 34 i 51 z + 1 B 18 S 35 j 52 0 + 2 C 19 T 36 k 53 1 + 3 D 20 U 37 l 54 2 + 4 E 21 V 38 m 55 3 + 5 F 22 W 39 n 56 4 + 6 G 23 X 40 o 57 5 + 7 H 24 Y 41 p 58 6 + 8 I 25 Z 42 q 59 7 + 9 J 26 a 43 r 60 8 + 10 K 27 b 44 s 61 9 + 11 L 28 c 45 t 62 + + 12 M 29 d 46 u 63 / + 13 N 30 e 47 v + 14 O 31 f 48 w (pad) = + 15 P 32 g 49 x + 16 Q 33 h 50 y + + Special processing is performed if fewer than 24 bits are available + at the end of the data being encoded. A full encoding quantum is + always completed at the end of a quantity. When fewer than 24 input + bits are available in an input group, zero bits are added (on the + right) to form an integral number of 6-bit groups. Padding at the + end of the data is performed using the '=' character. + + Since all base64 input is an integral number of octets, only the + ------------------------------------------------- + following cases can arise: + + (1) the final quantum of encoding input is an integral + multiple of 24 bits; here, the final unit of encoded + output will be an integral multiple of 4 characters + with no "=" padding, + (2) the final quantum of encoding input is exactly 8 bits; + here, the final unit of encoded output will be two + characters followed by two "=" padding characters, or + (3) the final quantum of encoding input is exactly 16 bits; + here, the final unit of encoded output will be three + characters followed by one "=" padding character. + */ + +int +b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize) { + size_t datalength = 0; + u_char input[3]; + u_char output[4]; + size_t i; + + while (2 < srclength) { + input[0] = *src++; + input[1] = *src++; + input[2] = *src++; + srclength -= 3; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + output[3] = input[2] & 0x3f; + Assert(output[0] < 64); + Assert(output[1] < 64); + Assert(output[2] < 64); + Assert(output[3] < 64); + + if (datalength + 4 > targsize) + return (-1); + target[datalength++] = Base64[output[0]]; + target[datalength++] = Base64[output[1]]; + target[datalength++] = Base64[output[2]]; + target[datalength++] = Base64[output[3]]; + } + + /* Now we worry about padding. */ + if (0 != srclength) { + /* Get what's left. */ + input[0] = input[1] = input[2] = '\0'; + for (i = 0; i < srclength; i++) + input[i] = *src++; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + Assert(output[0] < 64); + Assert(output[1] < 64); + Assert(output[2] < 64); + + if (datalength + 4 > targsize) + return (-1); + target[datalength++] = Base64[output[0]]; + target[datalength++] = Base64[output[1]]; + if (srclength == 1) + target[datalength++] = Pad64; + else + target[datalength++] = Base64[output[2]]; + target[datalength++] = Pad64; + } + if (datalength >= targsize) + return (-1); + target[datalength] = '\0'; /* Returned value doesn't count \0. */ + return (datalength); +} + +/* skips all whitespace anywhere. + converts characters, four at a time, starting at (or after) + src from base - 64 numbers into three 8 bit bytes in the target area. + it returns the number of data bytes stored at the target, or -1 on error. + */ + +int +b64_pton(src, target, targsize) + char const *src; + u_char *target; + size_t targsize; +{ + int tarindex, state, ch; + char *pos; + + state = 0; + tarindex = 0; + + while ((ch = *src++) != '\0') { + if (isspace(ch)) /* Skip whitespace anywhere. */ + continue; + + if (ch == Pad64) + break; + + pos = strchr(Base64, ch); + if (pos == 0) /* A non-base64 character. */ + return (-1); + + switch (state) { + case 0: + if (target) { + if ((size_t)tarindex >= targsize) + return (-1); + target[tarindex] = (pos - Base64) << 2; + } + state = 1; + break; + case 1: + if (target) { + if ((size_t)tarindex + 1 >= targsize) + return (-1); + target[tarindex] |= (pos - Base64) >> 4; + target[tarindex+1] = ((pos - Base64) & 0x0f) + << 4 ; + } + tarindex++; + state = 2; + break; + case 2: + if (target) { + if ((size_t)tarindex + 1 >= targsize) + return (-1); + target[tarindex] |= (pos - Base64) >> 2; + target[tarindex+1] = ((pos - Base64) & 0x03) + << 6; + } + tarindex++; + state = 3; + break; + case 3: + if (target) { + if ((size_t)tarindex >= targsize) + return (-1); + target[tarindex] |= (pos - Base64); + } + tarindex++; + state = 0; + break; + default: + abort(); + } + } + + /* + * We are done decoding Base-64 chars. Let's see if we ended + * on a byte boundary, and/or with erroneous trailing characters. + */ + + if (ch == Pad64) { /* We got a pad char. */ + ch = *src++; /* Skip it, get next. */ + switch (state) { + case 0: /* Invalid = in first position */ + case 1: /* Invalid = in second position */ + return (-1); + + case 2: /* Valid, means one byte of info */ + /* Skip any number of spaces. */ + for ((void)NULL; ch != '\0'; ch = *src++) + if (!isspace(ch)) + break; + /* Make sure there is another trailing = sign. */ + if (ch != Pad64) + return (-1); + ch = *src++; /* Skip the = */ + /* Fall through to "single trailing =" case. */ + /* FALLTHROUGH */ + + case 3: /* Valid, means two bytes of info */ + /* + * We know this char is an =. Is there anything but + * whitespace after it? + */ + for ((void)NULL; ch != '\0'; ch = *src++) + if (!isspace(ch)) + return (-1); + + /* + * Now make sure for cases 2 and 3 that the "extra" + * bits that slopped past the last full byte were + * zeros. If we don't check them, they become a + * subliminal channel. + */ + if (target && target[tarindex] != 0) + return (-1); + } + } else { + /* + * We ended by seeing the end of the string. Make sure we + * have no partial bytes lying around. + */ + if (state != 0) + return (-1); + } + + return (tarindex); +} diff --git a/contrib/isc-dhcp/dst/dst_api.c b/contrib/isc-dhcp/dst/dst_api.c new file mode 100644 index 0000000..d98b36a --- /dev/null +++ b/contrib/isc-dhcp/dst/dst_api.c @@ -0,0 +1,1081 @@ +#ifndef LINT +static const char rcsid[] = "$Header: /proj/cvs/isc/DHCP/dst/dst_api.c,v 1.1 2001/02/22 07:22:08 mellon Exp $"; +#endif + +/* + * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc. + * + * Permission to use, copy modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS + * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * TRUSTED INFORMATION SYSTEMS BE LIABLE FOR ANY SPECIAL, DIRECT, + * 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 THE SOFTWARE. + */ +/* + * This file contains the interface between the DST API and the crypto API. + * This is the only file that needs to be changed if the crypto system is + * changed. Exported functions are: + * void dst_init() Initialize the toolkit + * int dst_check_algorithm() Function to determines if alg is suppored. + * int dst_compare_keys() Function to compare two keys for equality. + * int dst_sign_data() Incremental signing routine. + * int dst_verify_data() Incremental verify routine. + * int dst_generate_key() Function to generate new KEY + * DST_KEY *dst_read_key() Function to retrieve private/public KEY. + * void dst_write_key() Function to write out a key. + * DST_KEY *dst_dnskey_to_key() Function to convert DNS KEY RR to a DST + * KEY structure. + * int dst_key_to_dnskey() Function to return a public key in DNS + * format binary + * DST_KEY *dst_buffer_to_key() Converst a data in buffer to KEY + * int *dst_key_to_buffer() Writes out DST_KEY key matterial in buffer + * void dst_free_key() Releases all memory referenced by key structure + */ + +#include <stdio.h> +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <memory.h> +#include <ctype.h> +#include <time.h> +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <netinet/in.h> + +#include "minires/minires.h" +#include "arpa/nameser.h" + +#include "dst_internal.h" + +/* static variables */ +static int done_init = 0; +dst_func *dst_t_func[DST_MAX_ALGS]; +const char *key_file_fmt_str = "Private-key-format: v%s\nAlgorithm: %d (%s)\n"; +const char *dst_path = ""; + +/* internal I/O functions */ +static DST_KEY *dst_s_read_public_key(const char *in_name, + const unsigned in_id, int in_alg); +static int dst_s_read_private_key_file(char *name, DST_KEY *pk_key, + unsigned in_id, int in_alg); +static int dst_s_write_public_key(const DST_KEY *key); +static int dst_s_write_private_key(const DST_KEY *key); + +/* internal function to set up data structure */ +static DST_KEY *dst_s_get_key_struct(const char *name, const int alg, + const u_int32_t flags, const int protocol, + const int bits); + +/* + * dst_init + * This function initializes the Digital Signature Toolkit. + * Right now, it just checks the DSTKEYPATH environment variable. + * Parameters + * none + * Returns + * none + */ +void +dst_init() +{ + char *s; + unsigned len; + + if (done_init != 0) + return; + done_init = 1; + + s = getenv("DSTKEYPATH"); + len = 0; + if (s) { + struct stat statbuf; + + len = strlen(s); + if (len > PATH_MAX) { + EREPORT(("%s is longer than %d characters, ignoring\n", + s, PATH_MAX)); + } else if (stat(s, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) { + EREPORT(("%s is not a valid directory\n", s)); + } else { + char *dp = (char *) malloc(len + 2); + int l; + memcpy(dp, s, len + 1); + l = strlen (dp); + if (dp[l - 1] != '/') { + dp[l + 1] = 0; + dp[l] = '/'; + } + dst_path = dp; + } + } + memset(dst_t_func, 0, sizeof(dst_t_func)); + /* first one is selected */ +#if 0 + dst_bsafe_init(); + dst_rsaref_init(); +#endif + dst_hmac_md5_init(); +#if 0 + dst_eay_dss_init(); + dst_cylink_init(); +#endif +} + +/* + * dst_check_algorithm + * This function determines if the crypto system for the specified + * algorithm is present. + * Parameters + * alg 1 KEY_RSA + * 3 KEY_DSA + * 157 KEY_HMAC_MD5 + * future algorithms TBD and registered with IANA. + * Returns + * 1 - The algorithm is available. + * 0 - The algorithm is not available. + */ +int +dst_check_algorithm(const int alg) +{ + return (dst_t_func[alg] != NULL); +} + +/* + * dst_s_get_key_struct + * This function allocates key structure and fills in some of the + * fields of the structure. + * Parameters: + * name: the name of the key + * alg: the algorithm number + * flags: the dns flags of the key + * protocol: the dns protocol of the key + * bits: the size of the key + * Returns: + * NULL if error + * valid pointer otherwise + */ +static DST_KEY * +dst_s_get_key_struct(const char *name, const int alg, const u_int32_t flags, + const int protocol, const int bits) +{ + DST_KEY *new_key = NULL; + + if (dst_check_algorithm(alg)) /* make sure alg is available */ + new_key = (DST_KEY *) malloc(sizeof(*new_key)); + if (new_key == NULL) + return (NULL); + + memset(new_key, 0, sizeof(*new_key)); + new_key->dk_key_name = strdup(name); + new_key->dk_alg = alg; + new_key->dk_flags = flags; + new_key->dk_proto = protocol; + new_key->dk_KEY_struct = NULL; + new_key->dk_key_size = bits; + new_key->dk_func = dst_t_func[alg]; + return (new_key); +} + +/* + * dst_compare_keys + * Compares two keys for equality. + * Parameters + * key1, key2 Two keys to be compared. + * Returns + * 0 The keys are equal. + * non-zero The keys are not equal. + */ + +int +dst_compare_keys(const DST_KEY *key1, const DST_KEY *key2) +{ + if (key1 == key2) + return (0); + if (key1 == NULL || key2 == NULL) + return (4); + if (key1->dk_alg != key2->dk_alg) + return (1); + if (key1->dk_key_size != key2->dk_key_size) + return (2); + if (key1->dk_id != key2->dk_id) + return (3); + return (key1->dk_func->compare(key1, key2)); +} + + +/* + * dst_sign_data + * An incremental signing function. Data is signed in steps. + * First the context must be initialized (SIG_MODE_INIT). + * Then data is hashed (SIG_MODE_UPDATE). Finally the signature + * itself is created (SIG_MODE_FINAL). This function can be called + * once with INIT, UPDATE and FINAL modes all set, or it can be + + * called separately with a different mode set for each step. The + * UPDATE step can be repeated. + * Parameters + * mode A bit mask used to specify operation(s) to be performed. + * SIG_MODE_INIT 1 Initialize digest + * SIG_MODE_UPDATE 2 Add data to digest + * SIG_MODE_FINAL 4 Generate signature + * from signature + * SIG_MODE_ALL (SIG_MODE_INIT,SIG_MODE_UPDATE,SIG_MODE_FINAL + * data Data to be signed. + * len The length in bytes of data to be signed. + * in_key Contains a private key to sign with. + * KEY structures should be handled (created, converted, + * compared, stored, freed) by the DST. + * signature + * The location to which the signature will be written. + * sig_len Length of the signature field in bytes. + * Return + * 0 Successfull INIT or Update operation + * >0 success FINAL (sign) operation + * <0 failure + */ + +int +dst_sign_data(const int mode, DST_KEY *in_key, void **context, + const u_char *data, const unsigned len, + u_char *signature, const unsigned sig_len) +{ + DUMP(data, mode, len, "dst_sign_data()"); + + if (mode & SIG_MODE_FINAL && + (in_key->dk_KEY_struct == NULL || signature == NULL)) + return (MISSING_KEY_OR_SIGNATURE); + + if (in_key->dk_func && in_key->dk_func->sign) + return (in_key->dk_func->sign(mode, in_key, context, data, len, + signature, sig_len)); + return (UNKNOWN_KEYALG); +} + + +/* + * dst_verify_data + * An incremental verify function. Data is verified in steps. + * First the context must be initialized (SIG_MODE_INIT). + * Then data is hashed (SIG_MODE_UPDATE). Finally the signature + * is verified (SIG_MODE_FINAL). This function can be called + * once with INIT, UPDATE and FINAL modes all set, or it can be + * called separately with a different mode set for each step. The + * UPDATE step can be repeated. + * Parameters + * mode Operations to perform this time. + * SIG_MODE_INIT 1 Initialize digest + * SIG_MODE_UPDATE 2 add data to digest + * SIG_MODE_FINAL 4 verify signature + * SIG_MODE_ALL + * (SIG_MODE_INIT,SIG_MODE_UPDATE,SIG_MODE_FINAL) + * data Data to pass through the hash function. + * len Length of the data in bytes. + * in_key Key for verification. + * signature Location of signature. + * sig_len Length of the signature in bytes. + * Returns + * 0 Verify success + * Non-Zero Verify Failure + */ + +int +dst_verify_data(const int mode, DST_KEY *in_key, void **context, + const u_char *data, const unsigned len, + const u_char *signature, const unsigned sig_len) +{ + DUMP(data, mode, len, "dst_verify_data()"); + if (mode & SIG_MODE_FINAL && + (in_key->dk_KEY_struct == NULL || signature == NULL)) + return (MISSING_KEY_OR_SIGNATURE); + + if (in_key->dk_func == NULL || in_key->dk_func->verify == NULL) + return (UNSUPPORTED_KEYALG); + return (in_key->dk_func->verify(mode, in_key, context, data, len, + signature, sig_len)); +} + + +/* + * dst_read_private_key + * Access a private key. First the list of private keys that have + * already been read in is searched, then the key accessed on disk. + * If the private key can be found, it is returned. If the key cannot + * be found, a null pointer is returned. The options specify required + * key characteristics. If the private key requested does not have + * these characteristics, it will not be read. + * Parameters + * in_keyname The private key name. + * in_id The id of the private key. + * options DST_FORCE_READ Read from disk - don't use a previously + * read key. + * DST_CAN_SIGN The key must be useable for signing. + * DST_NO_AUTHEN The key must be useable for authentication. + * DST_STANDARD Return any key + * Returns + * NULL If there is no key found in the current directory or + * this key has not been loaded before. + * !NULL Success - KEY structure returned. + */ + +DST_KEY * +dst_read_key(const char *in_keyname, const unsigned in_id, + const int in_alg, const int type) +{ + char keyname[PATH_MAX]; + DST_KEY *dg_key = NULL, *pubkey = NULL; + + if (!dst_check_algorithm(in_alg)) { /* make sure alg is available */ + EREPORT(("dst_read_private_key(): Algorithm %d not suppored\n", + in_alg)); + return (NULL); + } + if ((type && (DST_PUBLIC | DST_PRIVATE)) == 0) + return (NULL); + if (in_keyname == NULL) { + EREPORT(("dst_read_private_key(): Null key name passed in\n")); + return (NULL); + } else + strcpy(keyname, in_keyname); + + /* before I read in the public key, check if it is allowed to sign */ + if ((pubkey = dst_s_read_public_key(keyname, in_id, in_alg)) == NULL) + return (NULL); + + if (type == DST_PUBLIC) + return pubkey; + + if (!(dg_key = dst_s_get_key_struct(keyname, pubkey->dk_alg, + pubkey->dk_flags, pubkey->dk_proto, + 0))) + return (dg_key); + /* Fill in private key and some fields in the general key structure */ + if (dst_s_read_private_key_file(keyname, dg_key, pubkey->dk_id, + pubkey->dk_alg) == 0) + dg_key = dst_free_key(dg_key); + + pubkey = dst_free_key(pubkey); + return (dg_key); +} + +int +dst_write_key(const DST_KEY *key, const int type) +{ + int pub = 0, priv = 0; + + if (key == NULL) + return (0); + if (!dst_check_algorithm(key->dk_alg)) { /* make sure alg is available */ + EREPORT(("dst_write_key(): Algorithm %d not suppored\n", + key->dk_alg)); + return (UNSUPPORTED_KEYALG); + } + if ((type & (DST_PRIVATE|DST_PUBLIC)) == 0) + return (0); + + if (type & DST_PUBLIC) + if ((pub = dst_s_write_public_key(key)) < 0) + return (pub); + if (type & DST_PRIVATE) + if ((priv = dst_s_write_private_key(key)) < 0) + return (priv); + return (priv+pub); +} + +/* + * dst_write_private_key + * Write a private key to disk. The filename will be of the form: + * K<key->dk_name>+<key->dk_alg>+<key->dk_id>.<private key suffix>. + * If there is already a file with this name, an error is returned. + * + * Parameters + * key A DST managed key structure that contains + * all information needed about a key. + * Return + * >= 0 Correct behavior. Returns length of encoded key value + * written to disk. + * < 0 error. + */ + +static int +dst_s_write_private_key(const DST_KEY *key) +{ + u_char encoded_block[RAW_KEY_SIZE]; + char file[PATH_MAX]; + unsigned len; + FILE *fp; + + /* First encode the key into the portable key format */ + if (key == NULL) + return (-1); + if (key->dk_KEY_struct == NULL) + return (0); /* null key has no private key */ + + if (key->dk_func == NULL || key->dk_func->to_file_fmt == NULL) { + EREPORT(("dst_write_private_key(): Unsupported operation %d\n", + key->dk_alg)); + return (-5); + } else if ((len = key->dk_func->to_file_fmt(key, (char *)encoded_block, + sizeof(encoded_block))) <= 0) { + EREPORT(("dst_write_private_key(): Failed encoding private RSA bsafe key %d\n", len)); + return (-8); + } + /* Now I can create the file I want to use */ + dst_s_build_filename(file, key->dk_key_name, key->dk_id, key->dk_alg, + PRIVATE_KEY, PATH_MAX); + + /* Do not overwrite an existing file */ + if ((fp = dst_s_fopen(file, "w", 0600)) != NULL) { + int nn; + if ((nn = fwrite(encoded_block, 1, len, fp)) != len) { + EREPORT(("dst_write_private_key(): Write failure on %s %d != %d errno=%d\n", + file, out_len, nn, errno)); + return (-5); + } + fclose(fp); + } else { + EREPORT(("dst_write_private_key(): Can not create file %s\n" + ,file)); + return (-6); + } + memset(encoded_block, 0, len); + return (len); +} + +/* +* + * dst_read_public_key + * Read a public key from disk and store in a DST key structure. + * Parameters + * in_name K<in_name><in_id>.<public key suffix> is the + * filename of the key file to be read. + * Returns + * NULL If the key does not exist or no name is supplied. + * NON-NULL Initalized key structure if the key exists. + */ + +static DST_KEY * +dst_s_read_public_key(const char *in_name, const unsigned in_id, int in_alg) +{ + unsigned flags, len; + int proto, alg, dlen; + int c; + char name[PATH_MAX], enckey[RAW_KEY_SIZE], *notspace; + u_char deckey[RAW_KEY_SIZE]; + FILE *fp; + + if (in_name == NULL) { + EREPORT(("dst_read_public_key(): No key name given\n")); + return (NULL); + } + if (dst_s_build_filename(name, in_name, in_id, in_alg, PUBLIC_KEY, + PATH_MAX) == -1) { + EREPORT(("dst_read_public_key(): Cannot make filename from %s, %d, and %s\n", + in_name, in_id, PUBLIC_KEY)); + return (NULL); + } + /* + * Open the file and read it's formatted contents up to key + * File format: + * domain.name [ttl] [IN] KEY <flags> <protocol> <algorithm> <key> + * flags, proto, alg stored as decimal (or hex numbers FIXME). + * (FIXME: handle parentheses for line continuation.) + */ + if ((fp = dst_s_fopen(name, "r", 0)) == NULL) { + EREPORT(("dst_read_public_key(): Public Key not found %s\n", + name)); + return (NULL); + } + /* Skip domain name, which ends at first blank */ + while ((c = getc(fp)) != EOF) + if (isspace(c)) + break; + /* Skip blank to get to next field */ + while ((c = getc(fp)) != EOF) + if (!isspace(c)) + break; + + /* Skip optional TTL -- if initial digit, skip whole word. */ + if (isdigit(c)) { + while ((c = getc(fp)) != EOF) + if (isspace(c)) + break; + while ((c = getc(fp)) != EOF) + if (!isspace(c)) + break; + } + /* Skip optional "IN" */ + if (c == 'I' || c == 'i') { + while ((c = getc(fp)) != EOF) + if (isspace(c)) + break; + while ((c = getc(fp)) != EOF) + if (!isspace(c)) + break; + } + /* Locate and skip "KEY" */ + if (c != 'K' && c != 'k') { + EREPORT(("\"KEY\" doesn't appear in file: %s", name)); + return NULL; + } + while ((c = getc(fp)) != EOF) + if (isspace(c)) + break; + while ((c = getc(fp)) != EOF) + if (!isspace(c)) + break; + ungetc(c, fp); /* return the charcter to the input field */ + /* Handle hex!! FIXME. */ + + if (fscanf(fp, "%d %d %d", &flags, &proto, &alg) != 3) { + EREPORT(("dst_read_public_key(): Can not read flag/proto/alg field from %s\n" + ,name)); + return (NULL); + } + /* read in the key string */ + fgets(enckey, sizeof(enckey), fp); + + /* If we aren't at end-of-file, something is wrong. */ + while ((c = getc(fp)) != EOF) + if (!isspace(c)) + break; + if (!feof(fp)) { + EREPORT(("Key too long in file: %s", name)); + return NULL; + } + fclose(fp); + + if ((len = strlen(enckey)) <= 0) + return (NULL); + + /* discard \n */ + enckey[--len] = '\0'; + + /* remove leading spaces */ + for (notspace = (char *) enckey; isspace(*notspace); len--) + notspace++; + + dlen = b64_pton(notspace, deckey, sizeof(deckey)); + if (dlen < 0) { + EREPORT(("dst_read_public_key: bad return from b64_pton = %d", + dlen)); + return (NULL); + } + /* store key and info in a key structure that is returned */ +/* return dst_store_public_key(in_name, alg, proto, 666, flags, deckey, + dlen);*/ + return dst_buffer_to_key(in_name, alg, + flags, proto, deckey, (unsigned)dlen); +} + + +/* + * dst_write_public_key + * Write a key to disk in DNS format. + * Parameters + * key Pointer to a DST key structure. + * Returns + * 0 Failure + * 1 Success + */ + +static int +dst_s_write_public_key(const DST_KEY *key) +{ + FILE *fp; + char filename[PATH_MAX]; + u_char out_key[RAW_KEY_SIZE]; + char enc_key[RAW_KEY_SIZE]; + int len = 0; + + memset(out_key, 0, sizeof(out_key)); + if (key == NULL) { + EREPORT(("dst_write_public_key(): No key specified \n")); + return (0); + } else if ((len = dst_key_to_dnskey(key, out_key, sizeof(out_key)))< 0) + return (0); + + /* Make the filename */ + if (dst_s_build_filename(filename, key->dk_key_name, key->dk_id, + key->dk_alg, PUBLIC_KEY, PATH_MAX) == -1) { + EREPORT(("dst_write_public_key(): Cannot make filename from %s, %d, and %s\n", + key->dk_key_name, key->dk_id, PUBLIC_KEY)); + return (0); + } + /* create public key file */ + if ((fp = dst_s_fopen(filename, "w+", 0644)) == NULL) { + EREPORT(("DST_write_public_key: open of file:%s failed (errno=%d)\n", + filename, errno)); + return (0); + } + /*write out key first base64 the key data */ + if (key->dk_flags & DST_EXTEND_FLAG) + b64_ntop(&out_key[6], + (unsigned)(len - 6), enc_key, sizeof(enc_key)); + else + b64_ntop(&out_key[4], + (unsigned)(len - 4), enc_key, sizeof(enc_key)); + fprintf(fp, "%s IN KEY %d %d %d %s\n", + key->dk_key_name, + key->dk_flags, key->dk_proto, key->dk_alg, enc_key); + fclose(fp); + return (1); +} + + +/* + * dst_dnskey_to_public_key + * This function converts the contents of a DNS KEY RR into a DST + * key structure. + * Paramters + * len Length of the RDATA of the KEY RR RDATA + * rdata A pointer to the the KEY RR RDATA. + * in_name Key name to be stored in key structure. + * Returns + * NULL Failure + * NON-NULL Success. Pointer to key structure. + * Caller's responsibility to free() it. + */ + +DST_KEY * +dst_dnskey_to_key(const char *in_name, + const u_char *rdata, const unsigned len) +{ + DST_KEY *key_st; + int alg ; + int start = DST_KEY_START; + + if (rdata == NULL || len <= DST_KEY_ALG) /* no data */ + return (NULL); + alg = (u_int8_t) rdata[DST_KEY_ALG]; + if (!dst_check_algorithm(alg)) { /* make sure alg is available */ + EREPORT(("dst_dnskey_to_key(): Algorithm %d not suppored\n", + alg)); + return (NULL); + } + if ((key_st = dst_s_get_key_struct(in_name, alg, 0, 0, 0)) == NULL) + return (NULL); + + if (in_name == NULL) + return (NULL); + key_st->dk_flags = dst_s_get_int16(rdata); + key_st->dk_proto = (u_int16_t) rdata[DST_KEY_PROT]; + if (key_st->dk_flags & DST_EXTEND_FLAG) { + u_int32_t ext_flags; + ext_flags = (u_int32_t) dst_s_get_int16(&rdata[DST_EXT_FLAG]); + key_st->dk_flags = key_st->dk_flags | (ext_flags << 16); + start += 2; + } + /* + * now point to the begining of the data representing the encoding + * of the key + */ + if (key_st->dk_func && key_st->dk_func->from_dns_key) { + if (key_st->dk_func->from_dns_key(key_st, &rdata[start], + len - start) > 0) + return (key_st); + } else + EREPORT(("dst_dnskey_to_public_key(): unsuppored alg %d\n", + alg)); + + SAFE_FREE(key_st); + return (key_st); +} + + +/* + * dst_public_key_to_dnskey + * Function to encode a public key into DNS KEY wire format + * Parameters + * key Key structure to encode. + * out_storage Location to write the encoded key to. + * out_len Size of the output array. + * Returns + * <0 Failure + * >=0 Number of bytes written to out_storage + */ + +int +dst_key_to_dnskey(const DST_KEY *key, u_char *out_storage, + const unsigned out_len) +{ + u_int16_t val; + int loc = 0; + int enc_len = 0; + if (key == NULL) + return (-1); + + if (!dst_check_algorithm(key->dk_alg)) { /* make sure alg is available */ + EREPORT(("dst_key_to_dnskey(): Algorithm %d not suppored\n", + key->dk_alg)); + return (UNSUPPORTED_KEYALG); + } + memset(out_storage, 0, out_len); + val = (u_int16_t)(key->dk_flags & 0xffff); + out_storage[0] = (val >> 8) & 0xff; + out_storage[1] = val & 0xff; + loc += 2; + + out_storage[loc++] = (u_char) key->dk_proto; + out_storage[loc++] = (u_char) key->dk_alg; + + if (key->dk_flags > 0xffff) { /* Extended flags */ + val = (u_int16_t)((key->dk_flags >> 16) & 0xffff); + out_storage[loc] = (val >> 8) & 0xff; + out_storage[loc+1] = val & 0xff; + loc += 2; + } + if (key->dk_KEY_struct == NULL) + return (loc); + if (key->dk_func && key->dk_func->to_dns_key) { + enc_len = key->dk_func->to_dns_key(key, + (u_char *) &out_storage[loc], + out_len - loc); + if (enc_len > 0) + return (enc_len + loc); + else + return (-1); + } else + EREPORT(("dst_key_to_dnskey(): Unsupported ALG %d\n", + key->dk_alg)); + return (-1); +} + + +/* + * dst_buffer_to_key + * Function to encode a string of raw data into a DST key + * Parameters + * alg The algorithm (HMAC only) + * key A pointer to the data + * keylen The length of the data + * Returns + * NULL an error occurred + * NON-NULL the DST key + */ +DST_KEY * +dst_buffer_to_key(const char *key_name, /* name of the key */ + const int alg, /* algorithm */ + const unsigned flags, /* dns flags */ + const int protocol, /* dns protocol */ + const u_char *key_buf, /* key in dns wire fmt */ + const unsigned key_len) /* size of key */ +{ + + DST_KEY *dkey = NULL; + + if (!dst_check_algorithm(alg)) { /* make sure alg is available */ + EREPORT(("dst_buffer_to_key(): Algorithm %d not suppored\n", alg)); + return (NULL); + } + + dkey = dst_s_get_key_struct(key_name, alg, flags, protocol, -1); + + if (dkey == NULL) + return (NULL); + if (dkey->dk_func != NULL && + dkey->dk_func->from_dns_key != NULL) { + if (dkey->dk_func->from_dns_key(dkey, key_buf, key_len) < 0) { + EREPORT(("dst_buffer_to_key(): dst_buffer_to_hmac failed\n")); + return (dst_free_key(dkey)); + } + return (dkey); + } + return (NULL); +} + +int +dst_key_to_buffer(DST_KEY *key, u_char *out_buff, unsigned buf_len) +{ + int len; + /* this function will extrac the secret of HMAC into a buffer */ + if(key == NULL) + return (0); + if(key->dk_func != NULL && key->dk_func != NULL) { + len = key->dk_func->to_dns_key(key, out_buff, buf_len); + if (len < 0) + return (0); + return (len); + } + return (0); +} + + +/* + * dst_s_read_private_key_file + * Function reads in private key from a file. + * Fills out the KEY structure. + * Parameters + * name Name of the key to be read. + * pk_key Structure that the key is returned in. + * in_id Key identifier (tag) + * Return + * 1 if everthing works + * 0 if there is any problem + */ + +static int +dst_s_read_private_key_file(char *name, DST_KEY *pk_key, unsigned in_id, + int in_alg) +{ + int cnt, alg, len, major, minor, file_major, file_minor; + int id; + char filename[PATH_MAX]; + u_char in_buff[RAW_KEY_SIZE], *p; + FILE *fp; + + if (name == NULL || pk_key == NULL) { + EREPORT(("dst_read_private_key_file(): No key name given\n")); + return (0); + } + /* Make the filename */ + if (dst_s_build_filename(filename, name, in_id, in_alg, PRIVATE_KEY, + PATH_MAX) == -1) { + EREPORT(("dst_read_private_key(): Cannot make filename from %s, %d, and %s\n", + name, in_id, PRIVATE_KEY)); + return (0); + } + /* first check if we can find the key file */ + if ((fp = dst_s_fopen(filename, "r", 0)) == NULL) { + EREPORT(("dst_s_read_private_key_file: Could not open file %s in directory %s\n", + filename, dst_path[0] ? dst_path : + (char *) getcwd(NULL, PATH_MAX - 1))); + return (0); + } + /* now read the header info from the file */ + if ((cnt = fread(in_buff, 1, sizeof(in_buff), fp)) < 5) { + fclose(fp); + EREPORT(("dst_s_read_private_key_file: error reading file %s (empty file)\n", + filename)); + return (0); + } + /* decrypt key */ + fclose(fp); + if (memcmp(in_buff, "Private-key-format: v", 20) != 0) + goto fail; + len = cnt; + p = in_buff; + + if (!dst_s_verify_str((const char **) &p, "Private-key-format: v")) { + EREPORT(("dst_s_read_private_key_file(): Not a Key file/Decrypt failed %s\n", name)); + goto fail; + } + /* read in file format */ + sscanf((char *)p, "%d.%d", &file_major, &file_minor); + sscanf(KEY_FILE_FORMAT, "%d.%d", &major, &minor); + if (file_major < 1) { + EREPORT(("dst_s_read_private_key_file(): Unknown keyfile %d.%d version for %s\n", + file_major, file_minor, name)); + goto fail; + } else if (file_major > major || file_minor > minor) + EREPORT(( + "dst_s_read_private_key_file(): Keyfile %s version higher than mine %d.%d MAY FAIL\n", + name, file_major, file_minor)); + + while (*p++ != '\n') ; /* skip to end of line */ + + if (!dst_s_verify_str((const char **) &p, "Algorithm: ")) + goto fail; + + if (sscanf((char *)p, "%d", &alg) != 1) + goto fail; + while (*p++ != '\n') ; /* skip to end of line */ + + if (pk_key->dk_key_name && !strcmp(pk_key->dk_key_name, name)) + SAFE_FREE2(pk_key->dk_key_name, strlen(pk_key->dk_key_name)); + pk_key->dk_key_name = (char *) strdup(name); + + /* allocate and fill in key structure */ + if (pk_key->dk_func == NULL || pk_key->dk_func->from_file_fmt == NULL) + goto fail; + + id = pk_key->dk_func->from_file_fmt(pk_key, (char *)p, + (unsigned)(&in_buff[len] - p)); + if (id < 0) + goto fail; + + /* Make sure the actual key tag matches the input tag used in the filename + */ + if (id != in_id) { + EREPORT(("dst_s_read_private_key_file(): actual tag of key read %d != input tag used to build filename %d.\n", id, in_id)); + goto fail; + } + pk_key->dk_id = (u_int16_t) id; + pk_key->dk_alg = alg; + memset(in_buff, 0, (unsigned)cnt); + return (1); + + fail: + memset(in_buff, 0, (unsigned)cnt); + return (0); +} + + +/* + * dst_generate_key + * Generate and store a public/private keypair. + * Keys will be stored in formatted files. + * Parameters + * name Name of the new key. Used to create key files + * K<name>+<alg>+<id>.public and K<name>+<alg>+<id>.private. + * bits Size of the new key in bits. + * exp What exponent to use: + * 0 use exponent 3 + * non-zero use Fermant4 + * flags The default value of the DNS Key flags. + * The DNS Key RR Flag field is defined in RFC 2065, + * section 3.3. The field has 16 bits. + * protocol + * Default value of the DNS Key protocol field. + * The DNS Key protocol field is defined in RFC 2065, + * section 3.4. The field has 8 bits. + * alg What algorithm to use. Currently defined: + * KEY_RSA 1 + * KEY_DSA 3 + * KEY_HMAC 157 + * out_id The key tag is returned. + * + * Return + * NULL Failure + * non-NULL the generated key pair + * Caller frees the result, and its dk_name pointer. + */ +DST_KEY * +dst_generate_key(const char *name, const int bits, const int exp, + const unsigned flags, const int protocol, const int alg) +{ + DST_KEY *new_key = NULL; + int res; + if (name == NULL) + return (NULL); + + if (!dst_check_algorithm(alg)) { /* make sure alg is available */ + EREPORT(("dst_generate_key(): Algorithm %d not suppored\n", alg)); + return (NULL); + } + + new_key = dst_s_get_key_struct(name, alg, flags, protocol, bits); + if (new_key == NULL) + return (NULL); + if (bits == 0) /* null key we are done */ + return (new_key); + if (new_key->dk_func == NULL || new_key->dk_func->generate == NULL) { + EREPORT(("dst_generate_key_pair():Unsupported algorithm %d\n", + alg)); + return (dst_free_key(new_key)); + } + if ((res = new_key->dk_func->generate(new_key, exp)) <= 0) { + EREPORT(("dst_generate_key_pair(): Key generation failure %s %d %d %d\n", + new_key->dk_key_name, new_key->dk_alg, + new_key->dk_key_size, exp)); + return (dst_free_key(new_key)); + } + return (new_key); +} + + +/* + * dst_free_key + * Release all data structures pointed to by a key structure. + * Parameters + * f_key Key structure to be freed. + */ + +DST_KEY * +dst_free_key(DST_KEY *f_key) +{ + + if (f_key == NULL) + return (f_key); + if (f_key->dk_func && f_key->dk_func->destroy) + f_key->dk_KEY_struct = + f_key->dk_func->destroy(f_key->dk_KEY_struct); + else { + EREPORT(("dst_free_key(): Unknown key alg %d\n", + f_key->dk_alg)); + free(f_key->dk_KEY_struct); /* SHOULD NOT happen */ + } + if (f_key->dk_KEY_struct) { + free(f_key->dk_KEY_struct); + f_key->dk_KEY_struct = NULL; + } + if (f_key->dk_key_name) + SAFE_FREE(f_key->dk_key_name); + SAFE_FREE(f_key); + return (NULL); +} + +/* + * dst_sig_size + * Return the maximim size of signature from the key specified in bytes + * Parameters + * key + * Returns + * bytes + */ +int +dst_sig_size(DST_KEY *key) { + switch (key->dk_alg) { + case KEY_HMAC_MD5: + return (16); + case KEY_HMAC_SHA1: + return (20); + case KEY_RSA: + return (key->dk_key_size + 7) / 8; + case KEY_DSA: + return (40); + default: + EREPORT(("dst_sig_size(): Unknown key alg %d\n", key->dk_alg)); + return -1; + } +} + +/* + * dst_random + * function that multiplexes number of random number generators + * Parameters + * mode: select the random number generator + * wanted is how many bytes of random data are requested + * outran is a buffer of size at least wanted for the output data + * + * Returns + * number of bytes written to outran + */ +int +dst_random(const int mode, unsigned wanted, u_char *outran) +{ + u_int32_t *buff = NULL, *bp = NULL; + int i; + if (wanted <= 0 || outran == NULL) + return (0); + + switch (mode) { + case DST_RAND_SEMI: + bp = buff = (u_int32_t *) malloc(wanted+sizeof(u_int32_t)); + for (i = 0; i < wanted; i+= sizeof(u_int32_t), bp++) { + *bp = dst_s_quick_random(i); + } + memcpy(outran, buff, (unsigned)wanted); + SAFE_FREE(buff); + return (wanted); + case DST_RAND_STD: + return (dst_s_semi_random(outran, wanted)); + case DST_RAND_KEY: + return (dst_s_random(outran, wanted)); + case DST_RAND_DSS: + default: + /* need error case here XXX OG */ + return (0); + } +} + diff --git a/contrib/isc-dhcp/dst/dst_internal.h b/contrib/isc-dhcp/dst/dst_internal.h new file mode 100644 index 0000000..0890d80 --- /dev/null +++ b/contrib/isc-dhcp/dst/dst_internal.h @@ -0,0 +1,160 @@ +#ifndef DST_INTERNAL_H +#define DST_INTERNAL_H + +/* + * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc. + * + * Permission to use, copy modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS + * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * TRUSTED INFORMATION SYSTEMS BE LIABLE FOR ANY SPECIAL, DIRECT, + * 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 THE SOFTWARE. + */ +#include <limits.h> +#include <sys/param.h> + +#ifndef PATH_MAX +# ifdef POSIX_PATH_MAX +# define PATH_MAX POSIX_PATH_MAX +# else +# define PATH_MAX 255 /* this is the value of POSIX_PATH_MAX */ +# endif +#endif + +typedef struct dst_key { + char *dk_key_name; /* name of the key */ + int dk_key_size; /* this is the size of the key in bits */ + int dk_proto; /* what protocols this key can be used for */ + int dk_alg; /* algorithm number from key record */ + unsigned dk_flags; /* and the flags of the public key */ + unsigned dk_id; /* identifier of the key */ + void *dk_KEY_struct; /* pointer to key in crypto pkg fmt */ + struct dst_func *dk_func; /* point to cryptto pgk specific function table */ +} DST_KEY; +#define HAS_DST_KEY + +#include <isc-dhcp/dst.h> +/* + * define what crypto systems are supported for RSA, + * BSAFE is prefered over RSAREF; only one can be set at any time + */ +#if defined(BSAFE) && defined(RSAREF) +# error "Cannot have both BSAFE and RSAREF defined" +#endif + +/* Declare dst_lib specific constants */ +#define KEY_FILE_FORMAT "1.2" + +/* suffixes for key file names */ +#define PRIVATE_KEY "private" +#define PUBLIC_KEY "key" + +/* error handling */ +#ifdef REPORT_ERRORS +#define EREPORT(str) printf str +#else +#define EREPORT(str) +#endif + +/* use our own special macro to FRRE memory */ + +#ifndef SAFE_FREE +#define SAFE_FREE(a) if(a != NULL){memset(a,0, sizeof(*a)); free(a); a=NULL;} +#define SAFE_FREE2(a,s) if (a != NULL && s > 0){memset(a,0, s);free(a); a=NULL;} +#endif + +typedef struct dst_func { + int (*sign)(const int mode, DST_KEY *key, void **context, + const u_int8_t *data, const unsigned len, + u_int8_t *signature, const unsigned sig_len); + int (*verify)(const int mode, DST_KEY *key, void **context, + const u_int8_t *data, const unsigned len, + const u_int8_t *signature, const unsigned sig_len); + int (*compare)(const DST_KEY *key1, const DST_KEY *key2); + int (*generate)(DST_KEY *key, int parms); + void *(*destroy)(void *key); + /* conversion functions */ + int (*to_dns_key)(const DST_KEY *key, u_int8_t *out, + const unsigned out_len); + int (*from_dns_key)(DST_KEY *key, const u_int8_t *str, + const unsigned str_len); + int (*to_file_fmt)(const DST_KEY *key, char *out, + const unsigned out_len); + int (*from_file_fmt)(DST_KEY *key, const char *out, + const unsigned out_len); + +} dst_func; + +extern dst_func *dst_t_func[DST_MAX_ALGS]; +extern const char *key_file_fmt_str; +extern const char *dst_path; + +#ifndef DST_HASH_SIZE +#define DST_HASH_SIZE 20 /* RIPEMD160 and SHA-1 are 20 bytes MD5 is 16 */ +#endif + +#if 0 +int dst_bsafe_init(void); +int dst_rsaref_init(void); +#endif + +int dst_hmac_md5_init(void); + +#if 0 +int dst_cylink_init(void); +int dst_eay_dss_init(void); +#endif + +/* support functions */ +/* base64 to bignum conversion routines */ +int dst_s_conv_bignum_u8_to_b64( char *out_buf, const unsigned out_len, + const char *header, + const u_int8_t *bin_data, + const unsigned bin_len); +int dst_s_conv_bignum_b64_to_u8( const char **buf, u_int8_t *loc, + const unsigned loclen) ; +/* from higher level support routines */ +int dst_s_calculate_bits( const u_int8_t *str, const int max_bits); +int dst_s_verify_str( const char **buf, const char *str); + + +/* conversion between dns names and key file names */ +size_t dst_s_filename_length( const char *name, const char *suffix); +int dst_s_build_filename( char *filename, const char *name, + unsigned id, int alg, const char *suffix, + size_t filename_length); + +FILE *dst_s_fopen (const char *filename, const char *mode, unsigned perm); + +/* from file prandom.c */ +int dst_s_random( u_int8_t *output, unsigned size); +int dst_s_semi_random( u_int8_t *output, unsigned size); +u_int32_t dst_s_quick_random( int inc); +void dst_s_quick_random_set( u_int32_t val, u_int32_t cnt); + +/* + * read and write network byte order into u_int?_t + * all of these should be retired + */ +u_int16_t dst_s_get_int16( const u_int8_t *buf); +void dst_s_put_int16( u_int8_t *buf, const u_int16_t val); + +u_int32_t dst_s_get_int32( const u_int8_t *buf); +void dst_s_put_int32( u_int8_t *buf, const u_int32_t val); + +#ifdef DUMP +# undef DUMP +# define DUMP(a,b,c,d) dst_s_dump(a,b,c,d) +#else +# define DUMP(a,b,c,d) +#endif + + +#endif /* DST_INTERNAL_H */ diff --git a/contrib/isc-dhcp/dst/dst_support.c b/contrib/isc-dhcp/dst/dst_support.c new file mode 100644 index 0000000..a81ed53 --- /dev/null +++ b/contrib/isc-dhcp/dst/dst_support.c @@ -0,0 +1,463 @@ +static const char rcsid[] = "$Header: /proj/cvs/isc/DHCP/dst/dst_support.c,v 1.1 2001/02/22 07:22:08 mellon Exp $"; + + +/* + * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc. + * + * Permission to use, copy modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS + * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * TRUSTED INFORMATION SYSTEMS BE LIABLE FOR ANY SPECIAL, DIRECT, + * 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 THE SOFTWARE. + */ + +#include <stdio.h> +#include <unistd.h> +#include <memory.h> +#include <string.h> +#include <errno.h> +#include <sys/stat.h> +#include <netinet/in.h> +#include <sys/socket.h> + +#include "minires/minires.h" +#include "arpa/nameser.h" + +#include "dst_internal.h" + +/* + * dst_s_conv_bignum_u8_to_b64 + * This function converts binary data stored as a u_char[] to a + * base-64 string. Leading zeroes are discarded. If a header is + * supplied, it is prefixed to the input prior to encoding. The + * output is \n\0 terminated (the \0 is not included in output length). + * Parameters + * out_buf binary data to convert + * header character string to prefix to the output (label) + * bin_data binary data + * bin_len size of binary data + * Return + * -1 not enough space in output work area + * 0 no output + * >0 number of bytes written to output work area + */ + +int +dst_s_conv_bignum_u8_to_b64(char *out_buf, const unsigned out_len, + const char *header, const u_char *bin_data, + const unsigned bin_len) +{ + const u_char *bp = bin_data; + char *op = out_buf; + unsigned lenh = 0, len64 = 0; + unsigned local_in_len = bin_len; + unsigned local_out_len = out_len; + + if (bin_data == NULL) /* no data no */ + return (0); + + if (out_buf == NULL || out_len <= 0) /* no output_work area */ + return (-1); + + /* suppress leading \0 */ + for (; (*bp == 0x0) && (local_in_len > 0); local_in_len--) + bp++; + + if (header) { /* add header to output string */ + lenh = strlen(header); + if (lenh < out_len) + memcpy(op, header, lenh); + else + return (-1); + local_out_len -= lenh; + op += lenh; + } + len64 = b64_ntop(bp, local_in_len, op, local_out_len - 2); + if (len64 < 0) + return (-1); + op += len64++; + *(op++) = '\n'; /* put CR in the output */ + *op = '\0'; /* make sure output is 0 terminated */ + return (lenh + len64); +} + + +/* + * dst_s_verify_str() + * Validate that the input string(*str) is at the head of the input + * buffer(**buf). If so, move the buffer head pointer (*buf) to + * the first byte of data following the string(*str). + * Parameters + * buf Input buffer. + * str Input string. + * Return + * 0 *str is not the head of **buff + * 1 *str is the head of **buff, *buf is is advanced to + * the tail of **buf. + */ + +int +dst_s_verify_str(const char **buf, const char *str) +{ + unsigned b, s; + if (*buf == NULL) /* error checks */ + return (0); + if (str == NULL || *str == '\0') + return (1); + + b = strlen(*buf); /* get length of strings */ + s = strlen(str); + if (s > b || strncmp(*buf, str, s)) /* check if same */ + return (0); /* not a match */ + (*buf) += s; /* advance pointer */ + return (1); +} + + +/* + * dst_s_conv_bignum_b64_to_u8 + * Read a line of base-64 encoded string from the input buffer, + * convert it to binary, and store it in an output area. The + * input buffer is read until reaching a newline marker or the + * end of the buffer. The binary data is stored in the last X + * number of bytes of the output area where X is the size of the + * binary output. If the operation is successful, the input buffer + * pointer is advanced. This procedure does not do network to host + * byte order conversion. + * Parameters + * buf Pointer to encoded input string. Pointer is updated if + * function is successfull. + * loc Output area. + * loclen Size in bytes of output area. + * Return + * >0 Return = number of bytes of binary data stored in loc. + * 0 Failure. + */ + +int +dst_s_conv_bignum_b64_to_u8(const char **buf, + u_char *loc, const unsigned loclen) +{ + unsigned blen; + char *bp; + u_char bstr[RAW_KEY_SIZE]; + + if (buf == NULL || *buf == NULL) { /* error checks */ + EREPORT(("dst_s_conv_bignum_b64_to_u8: null input buffer.\n")); + return (0); + } + bp = strchr(*buf, '\n'); /* find length of input line */ + if (bp != NULL) + *bp = (u_char) NULL; + + blen = b64_pton(*buf, bstr, sizeof(bstr)); + if (blen <= 0) { + EREPORT(("dst_s_conv_bignum_b64_to_u8: decoded value is null.\n")); + return (0); + } + else if (loclen < blen) { + EREPORT(("dst_s_conv_bignum_b64_to_u8: decoded value is longer than output buffer.\n")); + return (0); + } + if (bp) + *buf = bp; /* advancing buffer past \n */ + memset(loc, 0, loclen - blen); /* clearing unused output area */ + memcpy(loc + loclen - blen, bstr, blen); /* write last blen bytes */ + return (blen); +} + + +/* + * dst_s_calculate_bits + * Given a binary number represented in a u_char[], determine + * the number of significant bits used. + * Parameters + * str An input character string containing a binary number. + * max_bits The maximum possible significant bits. + * Return + * N The number of significant bits in str. + */ + +int +dst_s_calculate_bits(const u_char *str, const int max_bits) +{ + const u_char *p = str; + u_char i, j = 0x80; + int bits; + for (bits = max_bits; *p == 0x00 && bits > 0; p++) + bits -= 8; + for (i = *p; (i & j) != j; j >>= 1) + bits--; + return (bits); +} + + +/* + * calculates a checksum used in kmt for a id. + * takes an array of bytes and a length. + * returns a 16 bit checksum. + */ +u_int16_t +dst_s_id_calc(const u_char *key, const unsigned keysize) +{ + u_int32_t ac; + const u_char *kp = key; + unsigned size = keysize; + + if (!key) + return 0; + + for (ac = 0; size > 1; size -= 2, kp += 2) + ac += ((*kp) << 8) + *(kp + 1); + + if (size > 0) + ac += ((*kp) << 8); + ac += (ac >> 16) & 0xffff; + + return (ac & 0xffff); +} + +/* + * dst_s_dns_key_id() Function to calculated DNSSEC footprint from KEY reocrd + * rdata (all of record) + * Input: + * dns_key_rdata: the raw data in wire format + * rdata_len: the size of the input data + * Output: + * the key footprint/id calcuated from the key data + */ +u_int16_t +dst_s_dns_key_id(const u_char *dns_key_rdata, const unsigned rdata_len) +{ + unsigned key_data = 4; + + if (!dns_key_rdata || (rdata_len < key_data)) + return 0; + + /* check the extended parameters bit in the DNS Key RR flags */ + if (dst_s_get_int16(dns_key_rdata) & DST_EXTEND_FLAG) + key_data += 2; + + /* compute id */ + if (dns_key_rdata[3] == KEY_RSA) /* Algorithm RSA */ + return dst_s_get_int16((const u_char *) + &dns_key_rdata[rdata_len - 3]); + else + /* compute a checksum on the key part of the key rr */ + return dst_s_id_calc(&dns_key_rdata[key_data], + (rdata_len - key_data)); +} + +/* + * dst_s_get_int16 + * This routine extracts a 16 bit integer from a two byte character + * string. The character string is assumed to be in network byte + * order and may be unaligned. The number returned is in host order. + * Parameter + * buf A two byte character string. + * Return + * The converted integer value. + */ + +u_int16_t +dst_s_get_int16(const u_char *buf) +{ + register u_int16_t a = 0; + a = ((u_int16_t)(buf[0] << 8)) | ((u_int16_t)(buf[1])); + return (a); +} + + +/* + * dst_s_get_int32 + * This routine extracts a 32 bit integer from a four byte character + * string. The character string is assumed to be in network byte + * order and may be unaligned. The number returned is in host order. + * Parameter + * buf A four byte character string. + * Return + * The converted integer value. + */ + +u_int32_t +dst_s_get_int32(const u_char *buf) +{ + register u_int32_t a = 0; + a = ((u_int32_t)(buf[0] << 24)) | ((u_int32_t)(buf[1] << 16)) | + ((u_int32_t)(buf[2] << 8)) | ((u_int32_t)(buf[3])); + return (a); +} + + +/* + * dst_s_put_int16 + * Take a 16 bit integer and store the value in a two byte + * character string. The integer is assumed to be in network + * order and the string is returned in host order. + * + * Parameters + * buf Storage for a two byte character string. + * val 16 bit integer. + */ + +void +dst_s_put_int16(u_int8_t *buf, const u_int16_t val) +{ + buf[0] = (u_int8_t)(val >> 8); + buf[1] = (u_int8_t)(val); +} + + +/* + * dst_s_put_int32 + * Take a 32 bit integer and store the value in a four byte + * character string. The integer is assumed to be in network + * order and the string is returned in host order. + * + * Parameters + * buf Storage for a four byte character string. + * val 32 bit integer. + */ + +void +dst_s_put_int32(u_int8_t *buf, const u_int32_t val) +{ + buf[0] = (u_int8_t)(val >> 24); + buf[1] = (u_int8_t)(val >> 16); + buf[2] = (u_int8_t)(val >> 8); + buf[3] = (u_int8_t)(val); +} + + +/* + * dst_s_filename_length + * + * This function returns the number of bytes needed to hold the + * filename for a key file. '/', '\' and ':' are not allowed. + * form: K<keyname>+<alg>+<id>.<suffix> + * + * Returns 0 if the filename would contain either '\', '/' or ':' + */ +size_t +dst_s_filename_length(const char *name, const char *suffix) +{ + if (name == NULL) + return (0); + if (strrchr(name, '\\')) + return (0); + if (strrchr(name, '/')) + return (0); + if (strrchr(name, ':')) + return (0); + if (suffix == NULL) + return (0); + if (strrchr(suffix, '\\')) + return (0); + if (strrchr(suffix, '/')) + return (0); + if (strrchr(suffix, ':')) + return (0); + return (1 + strlen(name) + 6 + strlen(suffix)); +} + + +/* + * dst_s_build_filename () + * Builds a key filename from the key name, it's id, and a + * suffix. '\', '/' and ':' are not allowed. fA filename is of the + * form: K<keyname><id>.<suffix> + * form: K<keyname>+<alg>+<id>.<suffix> + * + * Returns -1 if the conversion fails: + * if the filename would be too long for space allotted + * if the filename would contain a '\', '/' or ':' + * Returns 0 on success + */ + +int +dst_s_build_filename(char *filename, const char *name, unsigned id, + int alg, const char *suffix, size_t filename_length) +{ + unsigned my_id; + if (filename == NULL) + return (-1); + memset(filename, 0, filename_length); + if (name == NULL) + return (-1); + if (suffix == NULL) + return (-1); + if (filename_length < 1 + strlen(name) + 4 + 6 + 1 + strlen(suffix)) + return (-1); + my_id = id; + sprintf(filename, "K%s+%03d+%05d.%s", name, alg, my_id, + (const char *) suffix); + if (strrchr(filename, '/')) + return (-1); + if (strrchr(filename, '\\')) + return (-1); + if (strrchr(filename, ':')) + return (-1); + return (0); +} + +/* + * dst_s_fopen () + * Open a file in the dst_path directory. If perm is specified, the + * file is checked for existence first, and not opened if it exists. + * Parameters + * filename File to open + * mode Mode to open the file (passed directly to fopen) + * perm File permission, if creating a new file. + * Returns + * NULL Failure + * NON-NULL (FILE *) of opened file. + */ +FILE * +dst_s_fopen(const char *filename, const char *mode, unsigned perm) +{ + FILE *fp; + char pathname[PATH_MAX]; + unsigned plen = sizeof(pathname); + + if (*dst_path != '\0') { + strcpy(pathname, dst_path); + plen -= strlen(pathname); + } + else + pathname[0] = '\0'; + + if (plen > strlen(filename)) + strncpy(&pathname[PATH_MAX - plen], filename, plen-1); + else + return (NULL); + + fp = fopen(pathname, mode); + if (perm) + chmod(pathname, perm); + return (fp); +} + +#if 0 +void +dst_s_dump(const int mode, const u_char *data, const int size, + const char *msg) +{ + if (size > 0) { +#ifdef LONG_TEST + static u_char scratch[1000]; + int n ; + n = b64_ntop(data, scratch, size, sizeof(scratch)); + printf("%s: %x %d %s\n", msg, mode, n, scratch); +#else + printf("%s,%x %d\n", msg, mode, size); +#endif + } +} +#endif diff --git a/contrib/isc-dhcp/dst/hmac_link.c b/contrib/isc-dhcp/dst/hmac_link.c new file mode 100644 index 0000000..5c67633 --- /dev/null +++ b/contrib/isc-dhcp/dst/hmac_link.c @@ -0,0 +1,494 @@ +#ifdef HMAC_MD5 +#ifndef LINT +static const char rcsid[] = "$Header: /proj/cvs/isc/DHCP/dst/hmac_link.c,v 1.1 2001/02/22 07:22:08 mellon Exp $"; +#endif +/* + * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc. + * + * Permission to use, copy modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS + * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * TRUSTED INFORMATION SYSTEMS BE LIABLE FOR ANY SPECIAL, DIRECT, + * 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 THE SOFTWARE. + */ + +/* + * This file contains an implementation of the HMAC-MD5 algorithm. + */ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <memory.h> +#include <sys/param.h> +#include <sys/time.h> +#include <netinet/in.h> +#include <sys/socket.h> + +#include "minires/minires.h" +#include "arpa/nameser.h" + +#include "dst_internal.h" + +#ifdef USE_MD5 +# include "md5.h" +# ifndef _MD5_H_ +# define _MD5_H_ 1 /* make sure we do not include rsaref md5.h file */ +# endif +#endif + +#define HMAC_LEN 64 +#define HMAC_IPAD 0x36 +#define HMAC_OPAD 0x5c +#define MD5_LEN 16 + + +typedef struct hmackey { + u_char hk_ipad[64], hk_opad[64]; +} HMAC_Key; + + +/************************************************************************** + * dst_hmac_md5_sign + * Call HMAC signing functions to sign a block of data. + * There are three steps to signing, INIT (initialize structures), + * UPDATE (hash (more) data), FINAL (generate a signature). This + * routine performs one or more of these steps. + * Parameters + * mode SIG_MODE_INIT, SIG_MODE_UPDATE and/or SIG_MODE_FINAL. + * priv_key key to use for signing. + * context the context to be used in this digest + * data data to be signed. + * len length in bytes of data. + * signature location to store signature. + * sig_len size of the signature location + * returns + * N Success on SIG_MODE_FINAL = returns signature length in bytes + * 0 Success on SIG_MODE_INIT and UPDATE + * <0 Failure + */ + +static int +dst_hmac_md5_sign(const int mode, DST_KEY *d_key, void **context, + const u_char *data, const unsigned len, + u_char *signature, const unsigned sig_len) +{ + HMAC_Key *key; + int sign_len = 0; + MD5_CTX *ctx = NULL; + + if (mode & SIG_MODE_INIT) + ctx = (MD5_CTX *) malloc(sizeof(*ctx)); + else if (context) + ctx = (MD5_CTX *) *context; + if (ctx == NULL) + return (-1); + + if (d_key == NULL || d_key->dk_KEY_struct == NULL) + return (-1); + key = (HMAC_Key *) d_key->dk_KEY_struct; + + if (mode & SIG_MODE_INIT) { + MD5Init(ctx); + MD5Update(ctx, key->hk_ipad, HMAC_LEN); + } + + if ((mode & SIG_MODE_UPDATE) && (data && len > 0)) + MD5Update(ctx, (const unsigned char *)data, len); + + if (mode & SIG_MODE_FINAL) { + if (signature == NULL || sig_len < MD5_LEN) + return (SIGN_FINAL_FAILURE); + MD5Final(signature, ctx); + + /* perform outer MD5 */ + MD5Init(ctx); + MD5Update(ctx, key->hk_opad, HMAC_LEN); + MD5Update(ctx, signature, MD5_LEN); + MD5Final(signature, ctx); + sign_len = MD5_LEN; + SAFE_FREE(ctx); + } + else { + if (context == NULL) + return (-1); + *context = (void *) ctx; + } + return (sign_len); +} + + +/************************************************************************** + * dst_hmac_md5_verify() + * Calls HMAC verification routines. There are three steps to + * verification, INIT (initialize structures), UPDATE (hash (more) data), + * FINAL (generate a signature). This routine performs one or more of + * these steps. + * Parameters + * mode SIG_MODE_INIT, SIG_MODE_UPDATE and/or SIG_MODE_FINAL. + * dkey key to use for verify. + * data data signed. + * len length in bytes of data. + * signature signature. + * sig_len length in bytes of signature. + * returns + * 0 Success + * <0 Failure + */ + +static int +dst_hmac_md5_verify(const int mode, DST_KEY *d_key, void **context, + const u_char *data, const unsigned len, + const u_char *signature, const unsigned sig_len) +{ + HMAC_Key *key; + MD5_CTX *ctx = NULL; + + if (mode & SIG_MODE_INIT) + ctx = (MD5_CTX *) malloc(sizeof(*ctx)); + else if (context) + ctx = (MD5_CTX *) *context; + if (ctx == NULL) + return (-1); + + if (d_key == NULL || d_key->dk_KEY_struct == NULL) + return (-1); + + key = (HMAC_Key *) d_key->dk_KEY_struct; + if (mode & SIG_MODE_INIT) { + MD5Init(ctx); + MD5Update(ctx, key->hk_ipad, HMAC_LEN); + } + if ((mode & SIG_MODE_UPDATE) && (data && len > 0)) + MD5Update(ctx, (const unsigned char *)data, len); + + if (mode & SIG_MODE_FINAL) { + u_char digest[MD5_LEN]; + if (signature == NULL || key == NULL || sig_len != MD5_LEN) + return (VERIFY_FINAL_FAILURE); + MD5Final(digest, ctx); + + /* perform outer MD5 */ + MD5Init(ctx); + MD5Update(ctx, key->hk_opad, HMAC_LEN); + MD5Update(ctx, digest, MD5_LEN); + MD5Final(digest, ctx); + + SAFE_FREE(ctx); + if (memcmp(digest, signature, MD5_LEN) != 0) + return (VERIFY_FINAL_FAILURE); + } + else { + if (context == NULL) + return (-1); + *context = (void *) ctx; + } + return (0); +} + + +/************************************************************************** + * dst_buffer_to_hmac_md5 + * Converts key from raw data to an HMAC Key + * This function gets in a pointer to the data + * Parameters + * hkey the HMAC key to be filled in + * key the key in raw format + * keylen the length of the key + * Return + * 0 Success + * <0 Failure + */ +static int +dst_buffer_to_hmac_md5(DST_KEY *dkey, const u_char *key, const unsigned keylen) +{ + int i; + HMAC_Key *hkey = NULL; + MD5_CTX ctx; + unsigned local_keylen = keylen; + + if (dkey == NULL || key == NULL || keylen < 0) + return (-1); + + if ((hkey = (HMAC_Key *) malloc(sizeof(HMAC_Key))) == NULL) + return (-2); + + memset(hkey->hk_ipad, 0, sizeof(hkey->hk_ipad)); + memset(hkey->hk_opad, 0, sizeof(hkey->hk_opad)); + + /* if key is longer than HMAC_LEN bytes reset it to key=MD5(key) */ + if (keylen > HMAC_LEN) { + u_char tk[MD5_LEN]; + MD5Init(&ctx); + MD5Update(&ctx, (const unsigned char *)key, keylen); + MD5Final(tk, &ctx); + memset((void *) &ctx, 0, sizeof(ctx)); + key = tk; + local_keylen = MD5_LEN; + } + /* start out by storing key in pads */ + memcpy(hkey->hk_ipad, key, local_keylen); + memcpy(hkey->hk_opad, key, local_keylen); + + /* XOR key with hk_ipad and opad values */ + for (i = 0; i < HMAC_LEN; i++) { + hkey->hk_ipad[i] ^= HMAC_IPAD; + hkey->hk_opad[i] ^= HMAC_OPAD; + } + dkey->dk_key_size = local_keylen; + dkey->dk_KEY_struct = (void *) hkey; + return (1); +} + + +/************************************************************************** + * dst_hmac_md5_key_to_file_format + * Encodes an HMAC Key into the portable file format. + * Parameters + * hkey HMAC KEY structure + * buff output buffer + * buff_len size of output buffer + * Return + * 0 Failure - null input hkey + * -1 Failure - not enough space in output area + * N Success - Length of data returned in buff + */ + +static int +dst_hmac_md5_key_to_file_format(const DST_KEY *dkey, char *buff, + const unsigned buff_len) +{ + char *bp; + int i; + unsigned len, b_len, key_len; + u_char key[HMAC_LEN]; + HMAC_Key *hkey; + + if (dkey == NULL || dkey->dk_KEY_struct == NULL) + return (0); + if (buff == NULL || buff_len <= (int) strlen(key_file_fmt_str)) + return (-1); /* no OR not enough space in output area */ + + hkey = (HMAC_Key *) dkey->dk_KEY_struct; + memset(buff, 0, buff_len); /* just in case */ + /* write file header */ + sprintf(buff, key_file_fmt_str, KEY_FILE_FORMAT, KEY_HMAC_MD5, "HMAC"); + + bp = (char *) strchr(buff, '\0'); + b_len = buff_len - (bp - buff); + + memset(key, 0, HMAC_LEN); + for (i = 0; i < HMAC_LEN; i++) + key[i] = hkey->hk_ipad[i] ^ HMAC_IPAD; + for (i = HMAC_LEN - 1; i >= 0; i--) + if (key[i] != 0) + break; + key_len = i + 1; + + strcat(bp, "Key: "); + bp += strlen("Key: "); + b_len = buff_len - (bp - buff); + + len = b64_ntop(key, key_len, bp, b_len); + if (len < 0) + return (-1); + bp += len; + *(bp++) = '\n'; + *bp = '\0'; + b_len = buff_len - (bp - buff); + + return (buff_len - b_len); +} + + +/************************************************************************** + * dst_hmac_md5_key_from_file_format + * Converts contents of a key file into an HMAC key. + * Parameters + * hkey structure to put key into + * buff buffer containing the encoded key + * buff_len the length of the buffer + * Return + * n >= 0 Foot print of the key converted + * n < 0 Error in conversion + */ + +static int +dst_hmac_md5_key_from_file_format(DST_KEY *dkey, const char *buff, + const unsigned buff_len) +{ + const char *p = buff, *eol; + u_char key[HMAC_LEN+1]; /* b64_pton needs more than 64 bytes do decode + * it should probably be fixed rather than doing + * this + */ + u_char *tmp; + unsigned key_len, len; + + if (dkey == NULL) + return (-2); + if (buff == NULL) + return (-1); + + memset(key, 0, sizeof(key)); + + if (!dst_s_verify_str(&p, "Key: ")) + return (-3); + + eol = strchr(p, '\n'); + if (eol == NULL) + return (-4); + len = eol - p; + tmp = malloc(len + 2); + memcpy(tmp, p, len); + *(tmp + len) = 0x0; + key_len = b64_pton((char *)tmp, key, HMAC_LEN+1); /* see above */ + SAFE_FREE2(tmp, len + 2); + + if (dst_buffer_to_hmac_md5(dkey, key, key_len) < 0) { + return (-6); + } + return (0); +} + +/* + * dst_hmac_md5_to_dns_key() + * function to extract hmac key from DST_KEY structure + * intput: + * in_key: HMAC-MD5 key + * output: + * out_str: buffer to write ot + * out_len: size of output buffer + * returns: + * number of bytes written to output buffer + */ +static int +dst_hmac_md5_to_dns_key(const DST_KEY *in_key, u_char *out_str, + const unsigned out_len) +{ + + HMAC_Key *hkey; + int i; + + if (in_key == NULL || in_key->dk_KEY_struct == NULL || + out_len <= in_key->dk_key_size || out_str == NULL) + return (-1); + + hkey = (HMAC_Key *) in_key->dk_KEY_struct; + for (i = 0; i < in_key->dk_key_size; i++) + out_str[i] = hkey->hk_ipad[i] ^ HMAC_IPAD; + return (i); +} + +/************************************************************************** + * dst_hmac_md5_compare_keys + * Compare two keys for equality. + * Return + * 0 The keys are equal + * NON-ZERO The keys are not equal + */ + +static int +dst_hmac_md5_compare_keys(const DST_KEY *key1, const DST_KEY *key2) +{ + HMAC_Key *hkey1 = (HMAC_Key *) key1->dk_KEY_struct; + HMAC_Key *hkey2 = (HMAC_Key *) key2->dk_KEY_struct; + return memcmp(hkey1->hk_ipad, hkey2->hk_ipad, HMAC_LEN); +} + +/************************************************************************** + * dst_hmac_md5_free_key_structure + * Frees all (none) dynamically allocated structures in hkey + */ + +static void * +dst_hmac_md5_free_key_structure(void *key) +{ + HMAC_Key *hkey = key; + SAFE_FREE(hkey); + return (NULL); +} + + +/*************************************************************************** + * dst_hmac_md5_generate_key + * Creates a HMAC key of size size with a maximum size of 63 bytes + * generating a HMAC key larger than 63 bytes makes no sense as that key + * is digested before use. + */ + +static int +dst_hmac_md5_generate_key(DST_KEY *key, const int nothing) +{ + u_char *buff; + int n; + unsigned size, len; + + if (key == NULL || key->dk_alg != KEY_HMAC_MD5) + return (0); + size = (key->dk_key_size + 7) / 8; /* convert to bytes */ + if (size <= 0) + return(0); + + len = size > 64 ? 64 : size; + buff = malloc(len+8); + + n = dst_random(DST_RAND_SEMI, len, buff); + n += dst_random(DST_RAND_KEY, len, buff); + if (n <= len) { /* failed getting anything */ + SAFE_FREE2(buff, len); + return (-1); + } + n = dst_buffer_to_hmac_md5(key, buff, len); + SAFE_FREE2(buff, len); + if (n <= 0) + return (n); + return (1); +} + +/* + * dst_hmac_md5_init() Function to answer set up function pointers for HMAC + * related functions + */ +int +dst_hmac_md5_init() +{ + if (dst_t_func[KEY_HMAC_MD5] != NULL) + return (1); + dst_t_func[KEY_HMAC_MD5] = malloc(sizeof(struct dst_func)); + if (dst_t_func[KEY_HMAC_MD5] == NULL) + return (0); + memset(dst_t_func[KEY_HMAC_MD5], 0, sizeof(struct dst_func)); + dst_t_func[KEY_HMAC_MD5]->sign = dst_hmac_md5_sign; + dst_t_func[KEY_HMAC_MD5]->verify = dst_hmac_md5_verify; + dst_t_func[KEY_HMAC_MD5]->compare = dst_hmac_md5_compare_keys; + dst_t_func[KEY_HMAC_MD5]->generate = dst_hmac_md5_generate_key; + dst_t_func[KEY_HMAC_MD5]->destroy = dst_hmac_md5_free_key_structure; + dst_t_func[KEY_HMAC_MD5]->to_dns_key = dst_hmac_md5_to_dns_key; + dst_t_func[KEY_HMAC_MD5]->from_dns_key = dst_buffer_to_hmac_md5; + dst_t_func[KEY_HMAC_MD5]->to_file_fmt = dst_hmac_md5_key_to_file_format; + dst_t_func[KEY_HMAC_MD5]->from_file_fmt = dst_hmac_md5_key_from_file_format; + return (1); +} + +#else +int +dst_hmac_md5_init(){ + return (0); +} +#endif + + + + + + + diff --git a/contrib/isc-dhcp/dst/md5.h b/contrib/isc-dhcp/dst/md5.h new file mode 100644 index 0000000..c886d17 --- /dev/null +++ b/contrib/isc-dhcp/dst/md5.h @@ -0,0 +1,101 @@ +/* crypto/md/md5.h */ +/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_MD5_H +#define HEADER_MD5_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MD5_CBLOCK 64 +#define MD5_LBLOCK 16 +#define MD5_BLOCK 16 +#define MD5_LAST_BLOCK 56 +#define MD5_LENGTH_BLOCK 8 +#define MD5_DIGEST_LENGTH 16 + +typedef struct MD5state_st + { + unsigned long A,B,C,D; + unsigned long Nl,Nh; + unsigned long data[MD5_LBLOCK]; + int num; + } MD5_CTX; + +#ifndef NOPROTO +void MD5_Init(MD5_CTX *c); +void MD5_Update(MD5_CTX *c, const unsigned char *data, unsigned long len); +void MD5_Final(unsigned char *md, MD5_CTX *c); +unsigned char *MD5(unsigned char *d, unsigned long n, unsigned char *md); +#else +void MD5_Init(); +void MD5_Update(); +void MD5_Final(); +unsigned char *MD5(); +#endif + +/* to provide backward compatabilty to RSAREF calls ogud@tis.com 1997/11/14 */ +#define MD5Init(c) MD5_Init(c) +#define MD5Update(c,data, len) MD5_Update(c,data,len) +#define MD5Final(md, c) MD5_Final(md, c) +#ifdef __cplusplus +} +#endif + +#endif diff --git a/contrib/isc-dhcp/dst/md5_dgst.c b/contrib/isc-dhcp/dst/md5_dgst.c new file mode 100644 index 0000000..2a714ce --- /dev/null +++ b/contrib/isc-dhcp/dst/md5_dgst.c @@ -0,0 +1,373 @@ +/* crypto/md/md5_dgst.c */ +/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#include <stdio.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include "md5_locl.h" +#include "minires/minires.h" + +#ifdef USE_MD5 /* Added by ogud@tis.com 1998/1/26 */ + +const char *MD5_version="MD5 part of SSLeay 0.8.1 19-Jul-1997"; + +/* Implemented from RFC1321 The MD5 Message-Digest Algorithm + */ + +#define INIT_DATA_A (unsigned long)0x67452301L +#define INIT_DATA_B (unsigned long)0xefcdab89L +#define INIT_DATA_C (unsigned long)0x98badcfeL +#define INIT_DATA_D (unsigned long)0x10325476L + +#ifndef NOPROTO +static void md5_block(MD5_CTX *c, unsigned long *p); +#else +static void md5_block(); +#endif + +void MD5_Init(c) +MD5_CTX *c; + { + c->A=INIT_DATA_A; + c->B=INIT_DATA_B; + c->C=INIT_DATA_C; + c->D=INIT_DATA_D; + c->Nl=0; + c->Nh=0; + c->num=0; + } + +void MD5_Update(c, data, len) +MD5_CTX *c; +const register unsigned char *data; +unsigned long len; + { + register ULONG *p; + int sw,sc; + ULONG l; + + if (len == 0) return; + + l=(c->Nl+(len<<3))&0xffffffffL; + /* 95-05-24 eay Fixed a bug with the overflow handling, thanks to + * Wei Dai <weidai@eskimo.com> for pointing it out. */ + if (l < c->Nl) /* overflow */ + c->Nh++; + c->Nh+=(len>>29); + c->Nl=l; + + if (c->num != 0) + { + p=c->data; + sw=c->num>>2; + sc=c->num&0x03; + + if ((c->num+len) >= MD5_CBLOCK) + { + l= p[sw]; + p_c2l(data,l,sc); + p[sw++]=l; + for (; sw<MD5_LBLOCK; sw++) + { + c2l(data,l); + p[sw]=l; + } + len-=(MD5_CBLOCK-c->num); + + md5_block(c,p); + c->num=0; + /* drop through and do the rest */ + } + else + { + int ew,ec; + + c->num+=(int)len; + if ((sc+len) < 4) /* ugly, add char's to a word */ + { + l= p[sw]; + p_c2l_p(data,l,sc,len); + p[sw]=l; + } + else + { + ew=(c->num>>2); + ec=(c->num&0x03); + l= p[sw]; + p_c2l(data,l,sc); + p[sw++]=l; + for (; sw < ew; sw++) + { c2l(data,l); p[sw]=l; } + if (ec) + { + c2l_p(data,l,ec); + p[sw]=l; + } + } + return; + } + } + /* we now can process the input data in blocks of MD5_CBLOCK + * chars and save the leftovers to c->data. */ + p=c->data; + while (len >= MD5_CBLOCK) + { +#if defined(L_ENDIAN) || defined(B_ENDIAN) + memcpy(p,data,MD5_CBLOCK); + data+=MD5_CBLOCK; +#ifdef B_ENDIAN + for (sw=(MD5_LBLOCK/4); sw; sw--) + { + Endian_Reverse32(p[0]); + Endian_Reverse32(p[1]); + Endian_Reverse32(p[2]); + Endian_Reverse32(p[3]); + p+=4; + } +#endif +#else + for (sw=(MD5_LBLOCK/4); sw; sw--) + { + c2l(data,l); *(p++)=l; + c2l(data,l); *(p++)=l; + c2l(data,l); *(p++)=l; + c2l(data,l); *(p++)=l; + } +#endif + p=c->data; + md5_block(c,p); + len-=MD5_CBLOCK; + } + sc=(int)len; + c->num=sc; + if (sc) + { + sw=sc>>2; /* words to copy */ +#ifdef L_ENDIAN + p[sw]=0; + memcpy(p,data,sc); +#else + sc&=0x03; + for ( ; sw; sw--) + { c2l(data,l); *(p++)=l; } + c2l_p(data,l,sc); + *p=l; +#endif + } + } + +static void md5_block(c, X) +MD5_CTX *c; +register ULONG *X; + { + register ULONG A,B,C,D; + + A=c->A; + B=c->B; + C=c->C; + D=c->D; + + /* Round 0 */ + R0(A,B,C,D,X[ 0], 7,0xd76aa478L); + R0(D,A,B,C,X[ 1],12,0xe8c7b756L); + R0(C,D,A,B,X[ 2],17,0x242070dbL); + R0(B,C,D,A,X[ 3],22,0xc1bdceeeL); + R0(A,B,C,D,X[ 4], 7,0xf57c0fafL); + R0(D,A,B,C,X[ 5],12,0x4787c62aL); + R0(C,D,A,B,X[ 6],17,0xa8304613L); + R0(B,C,D,A,X[ 7],22,0xfd469501L); + R0(A,B,C,D,X[ 8], 7,0x698098d8L); + R0(D,A,B,C,X[ 9],12,0x8b44f7afL); + R0(C,D,A,B,X[10],17,0xffff5bb1L); + R0(B,C,D,A,X[11],22,0x895cd7beL); + R0(A,B,C,D,X[12], 7,0x6b901122L); + R0(D,A,B,C,X[13],12,0xfd987193L); + R0(C,D,A,B,X[14],17,0xa679438eL); + R0(B,C,D,A,X[15],22,0x49b40821L); + /* Round 1 */ + R1(A,B,C,D,X[ 1], 5,0xf61e2562L); + R1(D,A,B,C,X[ 6], 9,0xc040b340L); + R1(C,D,A,B,X[11],14,0x265e5a51L); + R1(B,C,D,A,X[ 0],20,0xe9b6c7aaL); + R1(A,B,C,D,X[ 5], 5,0xd62f105dL); + R1(D,A,B,C,X[10], 9,0x02441453L); + R1(C,D,A,B,X[15],14,0xd8a1e681L); + R1(B,C,D,A,X[ 4],20,0xe7d3fbc8L); + R1(A,B,C,D,X[ 9], 5,0x21e1cde6L); + R1(D,A,B,C,X[14], 9,0xc33707d6L); + R1(C,D,A,B,X[ 3],14,0xf4d50d87L); + R1(B,C,D,A,X[ 8],20,0x455a14edL); + R1(A,B,C,D,X[13], 5,0xa9e3e905L); + R1(D,A,B,C,X[ 2], 9,0xfcefa3f8L); + R1(C,D,A,B,X[ 7],14,0x676f02d9L); + R1(B,C,D,A,X[12],20,0x8d2a4c8aL); + /* Round 2 */ + R2(A,B,C,D,X[ 5], 4,0xfffa3942L); + R2(D,A,B,C,X[ 8],11,0x8771f681L); + R2(C,D,A,B,X[11],16,0x6d9d6122L); + R2(B,C,D,A,X[14],23,0xfde5380cL); + R2(A,B,C,D,X[ 1], 4,0xa4beea44L); + R2(D,A,B,C,X[ 4],11,0x4bdecfa9L); + R2(C,D,A,B,X[ 7],16,0xf6bb4b60L); + R2(B,C,D,A,X[10],23,0xbebfbc70L); + R2(A,B,C,D,X[13], 4,0x289b7ec6L); + R2(D,A,B,C,X[ 0],11,0xeaa127faL); + R2(C,D,A,B,X[ 3],16,0xd4ef3085L); + R2(B,C,D,A,X[ 6],23,0x04881d05L); + R2(A,B,C,D,X[ 9], 4,0xd9d4d039L); + R2(D,A,B,C,X[12],11,0xe6db99e5L); + R2(C,D,A,B,X[15],16,0x1fa27cf8L); + R2(B,C,D,A,X[ 2],23,0xc4ac5665L); + /* Round 3 */ + R3(A,B,C,D,X[ 0], 6,0xf4292244L); + R3(D,A,B,C,X[ 7],10,0x432aff97L); + R3(C,D,A,B,X[14],15,0xab9423a7L); + R3(B,C,D,A,X[ 5],21,0xfc93a039L); + R3(A,B,C,D,X[12], 6,0x655b59c3L); + R3(D,A,B,C,X[ 3],10,0x8f0ccc92L); + R3(C,D,A,B,X[10],15,0xffeff47dL); + R3(B,C,D,A,X[ 1],21,0x85845dd1L); + R3(A,B,C,D,X[ 8], 6,0x6fa87e4fL); + R3(D,A,B,C,X[15],10,0xfe2ce6e0L); + R3(C,D,A,B,X[ 6],15,0xa3014314L); + R3(B,C,D,A,X[13],21,0x4e0811a1L); + R3(A,B,C,D,X[ 4], 6,0xf7537e82L); + R3(D,A,B,C,X[11],10,0xbd3af235L); + R3(C,D,A,B,X[ 2],15,0x2ad7d2bbL); + R3(B,C,D,A,X[ 9],21,0xeb86d391L); + + c->A+=A&0xffffffffL; + c->B+=B&0xffffffffL; + c->C+=C&0xffffffffL; + c->D+=D&0xffffffffL; + } + +void MD5_Final(md, c) +unsigned char *md; +MD5_CTX *c; + { + register int i,j; + register ULONG l; + register ULONG *p; + static unsigned char end[4]={0x80,0x00,0x00,0x00}; + unsigned char *cp=end; + + /* c->num should definitly have room for at least one more byte. */ + p=c->data; + j=c->num; + i=j>>2; + + /* purify often complains about the following line as an + * Uninitialized Memory Read. While this can be true, the + * following p_c2l macro will reset l when that case is true. + * This is because j&0x03 contains the number of 'valid' bytes + * already in p[i]. If and only if j&0x03 == 0, the UMR will + * occur but this is also the only time p_c2l will do + * l= *(cp++) instead of l|= *(cp++) + * Many thanks to Alex Tang <altitude@cic.net> for pickup this + * 'potential bug' */ +#ifdef PURIFY + if ((j&0x03) == 0) p[i]=0; +#endif + l=p[i]; + p_c2l(cp,l,j&0x03); + p[i]=l; + i++; + /* i is the next 'undefined word' */ + if (c->num >= MD5_LAST_BLOCK) + { + for (; i<MD5_LBLOCK; i++) + p[i]=0; + md5_block(c,p); + i=0; + } + for (; i<(MD5_LBLOCK-2); i++) + p[i]=0; + p[MD5_LBLOCK-2]=c->Nl; + p[MD5_LBLOCK-1]=c->Nh; + md5_block(c,p); + cp=md; + l=c->A; l2c(l,cp); + l=c->B; l2c(l,cp); + l=c->C; l2c(l,cp); + l=c->D; l2c(l,cp); + + /* clear stuff, md5_block may be leaving some stuff on the stack + * but I'm not worried :-) */ + c->num=0; +/* memset((char *)&c,0,sizeof(c));*/ + } + +#ifdef undef +int printit(l) +unsigned long *l; + { + int i,ii; + + for (i=0; i<2; i++) + { + for (ii=0; ii<8; ii++) + { + fprintf(stderr,"%08lx ",l[i*8+ii]); + } + fprintf(stderr,"\n"); + } + } +#endif +#endif /* USE_MD5 */ diff --git a/contrib/isc-dhcp/dst/md5_locl.h b/contrib/isc-dhcp/dst/md5_locl.h new file mode 100644 index 0000000..b2f0028 --- /dev/null +++ b/contrib/isc-dhcp/dst/md5_locl.h @@ -0,0 +1,190 @@ +/* crypto/md/md5_locl.h */ +/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#include <stdlib.h> +#include <string.h> +#include "md5.h" + +#define ULONG unsigned long +#define UCHAR unsigned char +#define UINT unsigned int + +#if defined(NOCONST) +#define const +#endif + +#undef c2l +#define c2l(c,l) (l = ((unsigned long)(*((c)++))) , \ + l|=(((unsigned long)(*((c)++)))<< 8), \ + l|=(((unsigned long)(*((c)++)))<<16), \ + l|=(((unsigned long)(*((c)++)))<<24)) + +#undef p_c2l +#define p_c2l(c,l,n) { \ + switch (n) { \ + case 0: l =((unsigned long)(*((c)++))); \ + case 1: l|=((unsigned long)(*((c)++)))<< 8; \ + case 2: l|=((unsigned long)(*((c)++)))<<16; \ + case 3: l|=((unsigned long)(*((c)++)))<<24; \ + } \ + } + +/* NOTE the pointer is not incremented at the end of this */ +#undef c2l_p +#define c2l_p(c,l,n) { \ + l=0; \ + (c)+=n; \ + switch (n) { \ + case 3: l =((unsigned long)(*(--(c))))<<16; \ + case 2: l|=((unsigned long)(*(--(c))))<< 8; \ + case 1: l|=((unsigned long)(*(--(c)))) ; \ + } \ + } + +#undef p_c2l_p +#define p_c2l_p(c,l,sc,len) { \ + switch (sc) \ + { \ + case 0: l =((unsigned long)(*((c)++))); \ + if (--len == 0) break; \ + case 1: l|=((unsigned long)(*((c)++)))<< 8; \ + if (--len == 0) break; \ + case 2: l|=((unsigned long)(*((c)++)))<<16; \ + } \ + } + +#undef l2c +#define l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \ + *((c)++)=(unsigned char)(((l)>> 8)&0xff), \ + *((c)++)=(unsigned char)(((l)>>16)&0xff), \ + *((c)++)=(unsigned char)(((l)>>24)&0xff)) + +/* NOTE - c is not incremented as per l2c */ +#undef l2cn +#define l2cn(l1,l2,c,n) { \ + c+=n; \ + switch (n) { \ + case 8: *(--(c))=(unsigned char)(((l2)>>24)&0xff); \ + case 7: *(--(c))=(unsigned char)(((l2)>>16)&0xff); \ + case 6: *(--(c))=(unsigned char)(((l2)>> 8)&0xff); \ + case 5: *(--(c))=(unsigned char)(((l2) )&0xff); \ + case 4: *(--(c))=(unsigned char)(((l1)>>24)&0xff); \ + case 3: *(--(c))=(unsigned char)(((l1)>>16)&0xff); \ + case 2: *(--(c))=(unsigned char)(((l1)>> 8)&0xff); \ + case 1: *(--(c))=(unsigned char)(((l1) )&0xff); \ + } \ + } + +/* A nice byte order reversal from Wei Dai <weidai@eskimo.com> */ +#if defined(WIN32) +/* 5 instructions with rotate instruction, else 9 */ +#define Endian_Reverse32(a) \ + { \ + unsigned long l=(a); \ + (a)=((ROTATE(l,8)&0x00FF00FF)|(ROTATE(l,24)&0xFF00FF00)); \ + } +#else +/* 6 instructions with rotate instruction, else 8 */ +#define Endian_Reverse32(a) \ + { \ + unsigned long l=(a); \ + l=(((l&0xFF00FF00)>>8L)|((l&0x00FF00FF)<<8L)); \ + (a)=ROTATE(l,16L); \ + } +#endif +/* +#define F(x,y,z) (((x) & (y)) | ((~(x)) & (z))) +#define G(x,y,z) (((x) & (z)) | ((y) & (~(z)))) +*/ + +/* As pointed out by Wei Dai <weidai@eskimo.com>, the above can be + * simplified to the code below. Wei attributes these optimisations + * to Peter Gutmann's SHS code, and he attributes it to Rich Schroeppel. + */ +#define F(x,y,z) ((((y) ^ (z)) & (x)) ^ (z)) +#define G(x,y,z) ((((x) ^ (y)) & (z)) ^ (y)) +#define H(x,y,z) ((x) ^ (y) ^ (z)) +#define I(x,y,z) (((x) | (~(z))) ^ (y)) + +#undef ROTATE +#if defined(WIN32) +#define ROTATE(a,n) _lrotl(a,n) +#else +#define ROTATE(a,n) (((a)<<(n))|(((a)&0xffffffff)>>(32-(n)))) +#endif + + +#define R0(a,b,c,d,k,s,t) { \ + a+=((k)+(t)+F((b),(c),(d))); \ + a=ROTATE(a,s); \ + a+=b; };\ + +#define R1(a,b,c,d,k,s,t) { \ + a+=((k)+(t)+G((b),(c),(d))); \ + a=ROTATE(a,s); \ + a+=b; }; + +#define R2(a,b,c,d,k,s,t) { \ + a+=((k)+(t)+H((b),(c),(d))); \ + a=ROTATE(a,s); \ + a+=b; }; + +#define R3(a,b,c,d,k,s,t) { \ + a+=((k)+(t)+I((b),(c),(d))); \ + a=ROTATE(a,s); \ + a+=b; }; diff --git a/contrib/isc-dhcp/dst/prandom.c b/contrib/isc-dhcp/dst/prandom.c new file mode 100644 index 0000000..eaa1071 --- /dev/null +++ b/contrib/isc-dhcp/dst/prandom.c @@ -0,0 +1,862 @@ +#ifndef LINT +static const char rcsid[] = "$Header: /proj/cvs/isc/DHCP/dst/prandom.c,v 1.1 2001/02/22 07:22:09 mellon Exp $"; +#endif +/* + * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc. + * + * Permission to use, copy modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS + * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * TRUSTED INFORMATION SYSTEMS BE LIABLE FOR ANY SPECIAL, DIRECT, + * 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 THE SOFTWARE. + */ + +#include <stdio.h> +#include <sys/types.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <time.h> +#include <dirent.h> +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/time.h> + +#include <netinet/in.h> +#include <sys/socket.h> +#define NEED_PRAND_CONF +#include "minires/minires.h" +#include "dst_internal.h" +#include "arpa/nameser.h" + + +#ifndef DST_NUM_HASHES +#define DST_NUM_HASHES 4 +#endif +#ifndef DST_NUMBER_OF_COUNTERS +#define DST_NUMBER_OF_COUNTERS 5 /* 32 * 5 == 160 == SHA(1) > MD5 */ +#endif + +/* + * the constant below is a prime number to make fixed data structues like + * stat and time wrap over blocks. This adds certain uncertanty to what is + * in each digested block. + * The prime number 2879 has the special property that when + * divided by 2,4 and 6 the result is also a prime numbers + */ + +#ifndef DST_RANDOM_BLOCK_SIZE +#define DST_RANDOM_BLOCK_SIZE 2879 +#endif + +/* + * This constant dictatates how many bits we shift to the right before using a + */ +#ifndef DST_SHIFT +#define DST_SHIFT 9 +#endif + +/* + * An initalizer that is as bad as any other with half the bits set + */ +#ifndef DST_RANDOM_PATTERN +#define DST_RANDOM_PATTERN 0x8765CA93 +#endif +/* + * things must have changed in the last 3600 seconds to be used + */ +#define MAX_OLD 3600 + + +/* + * these two data structure are used to process input data into digests, + * + * The first structure is containts a pointer to a DST HMAC key + * the variables accompanying are used for + * step : select every step byte from input data for the hash + * block: number of data elements going into each hash + * digested: number of data elements digested so far + * curr: offset into the next input data for the first byte. + */ +typedef struct hash { + DST_KEY *key; + void *ctx; + int digested, block, step, curr; +} prand_hash; + +/* + * This data structure controlls number of hashes and keeps track of + * overall progress in generating correct number of bytes of output. + * output : array to store the output data in + * needed : how many bytes of output are needed + * filled : number of bytes in output so far. + * bytes : total number of bytes processed by this structure + * file_digest : the HMAC key used to digest files. + */ +typedef struct work { + unsigned needed, filled, bytes; + u_char *output; + prand_hash *hash[DST_NUM_HASHES]; + DST_KEY *file_digest; +} dst_work; + + +/* + * forward function declarations + */ +static int get_dev_random(u_char *output, unsigned size); +static int do_time(dst_work *work); +static int do_ls(dst_work *work); +static int unix_cmd(dst_work *work); +static int digest_file(dst_work *work); + +static void force_hash(dst_work *work, prand_hash *hash); +static int do_hash(dst_work *work, prand_hash *hash, const u_char *input, + unsigned size); +static int my_digest(dst_work *tmp, const u_char *input, unsigned size); +static prand_hash *get_hmac_key(int step, int block); + +static unsigned own_random(dst_work *work); + + +/* + * variables used in the quick random number generator + */ +static u_int32_t ran_val = DST_RANDOM_PATTERN; +static u_int32_t ran_cnt = (DST_RANDOM_PATTERN >> 10); + +/* + * setting the quick_random generator to particular values or if both + * input parameters are 0 then set it to initial vlaues + */ + +void +dst_s_quick_random_set(u_int32_t val, u_int32_t cnt) +{ + ran_val = (val == 0) ? DST_RANDOM_PATTERN : val; + ran_cnt = (cnt == 0) ? (DST_RANDOM_PATTERN >> 10) : cnt; +} + +/* + * this is a quick and random number generator that seems to generate quite + * good distribution of data + */ +u_int32_t +dst_s_quick_random(int inc) +{ + ran_val = ((ran_val >> 13) ^ (ran_val << 19)) ^ + ((ran_val >> 7) ^ (ran_val << 25)); + if (inc > 0) /* only increasing values accepted */ + ran_cnt += inc; + ran_val += ran_cnt++; + return (ran_val); +} + +/* + * get_dev_random: Function to read /dev/random reliably + * this function returns how many bytes where read from the device. + * port_after.h should set the control variable HAVE_DEV_RANDOM + */ +static int +get_dev_random(u_char *output, unsigned size) +{ +#ifdef HAVE_DEV_RANDOM + struct stat st; + int n = 0, fd = -1, s; + + s = stat("/dev/random", &st); + if (s == 0 && S_ISCHR(st.st_mode)) { + if ((fd = open("/dev/random", O_RDONLY | O_NONBLOCK)) != -1) { + if ((n = read(fd, output, size)) < 0) + n = 0; + close(fd); + } + return (n); + } +#endif + return (0); +} + +/* + * Portable way of getting the time values if gettimeofday is missing + * then compile with -DMISSING_GETTIMEOFDAY time() is POSIX compliant but + * gettimeofday() is not. + * Time of day is predictable, we are looking for the randomness that comes + * the last few bits in the microseconds in the timer are hard to predict when + * this is invoked at the end of other operations + */ +struct timeval *mtime; +static int +do_time(dst_work *work) +{ + int cnt = 0; + static u_char tmp[sizeof(struct timeval) + sizeof(struct timezone)]; + struct timezone *zone; + + zone = (struct timezone *) tmp; + mtime = (struct timeval *)(tmp + sizeof(struct timezone)); + gettimeofday(mtime, zone); + cnt = sizeof(tmp); + my_digest(work, tmp, sizeof(tmp)); + + return (cnt); +} + +/* + * this function simulates the ls command, but it uses stat which gives more + * information and is harder to guess + * Each call to this function will visit the next directory on the list of + * directories, in a circular manner. + * return value is the number of bytes added to the temp buffer + * + * do_ls() does not visit subdirectories + * if attacker has access to machine it can guess most of the values seen + * thus it is important to only visit directories that are freqently updated + * Attacker that has access to the network can see network traffic + * when NFS mounted directories are accessed and know exactly the data used + * but may not know exactly in what order data is used. + * Returns the number of bytes that where returned in stat structures + */ +static int +do_ls(dst_work *work) +{ + struct dir_info { + uid_t uid; + gid_t gid; + off_t size; + time_t atime, mtime, ctime; + }; + static struct dir_info dir_info; + struct stat buf; + struct dirent *entry; + static int i = 0; + static unsigned long d_round = 0; + struct timeval tv; + int n = 0, tb_i = 0, out = 0; + unsigned dir_len; + + char file_name[1024]; + u_char tmp_buff[1024]; + DIR *dir = NULL; + + if (dirs[i] == NULL) /* if at the end of the list start over */ + i = 0; + if (stat(dirs[i++], &buf)) /* directory does not exist */ + return (0); + + gettimeofday(&tv,NULL); + if (d_round == 0) + d_round = tv.tv_sec - MAX_OLD; + else if (i==1) /* if starting a new round cut what we accept */ + d_round += (tv.tv_sec - d_round)/2; + + if (buf.st_atime < d_round) + return (0); + + EREPORT(("do_ls i %d filled %4d in_temp %4d\n", + i-1, work->filled, work->in_temp)); + memcpy(tmp_buff, &buf, sizeof(buf)); + tb_i += sizeof(buf); + + + if ((dir = opendir(dirs[i-1])) == NULL)/* open it for read */ + return (0); + strcpy(file_name, dirs[i-1]); + dir_len = strlen(file_name); + file_name[dir_len++] = '/'; + while ((entry = readdir(dir))) { + unsigned len = strlen(entry->d_name); + out += len; + if (my_digest(work, (u_char *)entry->d_name, len)) + break; + + memcpy(&file_name[dir_len], entry->d_name, len); + file_name[dir_len + len] = 0x0; + /* for all entries in dir get the stats */ + if (stat(file_name, &buf) == 0) { + n++; /* count successfull stat calls */ + /* copy non static fields */ + dir_info.uid += buf.st_uid; + dir_info.gid += buf.st_gid; + dir_info.size += buf.st_size; + dir_info.atime += buf.st_atime; + dir_info.mtime += buf.st_mtime; + dir_info.ctime += buf.st_ctime; + out += sizeof(dir_info); + if(my_digest(work, (u_char *)&dir_info, + sizeof(dir_info))) + break; + } + } + closedir(dir); /* done */ + out += do_time(work); /* add a time stamp */ + return (out); +} + + +/* + * unix_cmd() + * this function executes the a command from the cmds[] list of unix commands + * configured in the prand_conf.h file + * return value is the number of bytes added to the randomness temp buffer + * + * it returns the number of bytes that where read in + * if more data is needed at the end time is added to the data. + * This function maintains a state to selects the next command to run + * returns the number of bytes read in from the command + */ +static int +unix_cmd(dst_work *work) +{ + static int cmd_index = 0; + int cnt = 0, n; + FILE *pipe; + u_char buffer[4096]; + + if (cmds[cmd_index] == NULL) + cmd_index = 0; + EREPORT(("unix_cmd() i %d filled %4d in_temp %4d\n", + cmd_index, work->filled, work->in_temp)); + pipe = popen(cmds[cmd_index++], "r"); /* execute the command */ + + while ((n = fread(buffer, sizeof(char), sizeof(buffer), pipe)) > 0) { + cnt += n; /* process the output */ + if (my_digest(work, buffer, (unsigned)n)) + break; + /* this adds some randomness to the output */ + cnt += do_time(work); + } + while ((n = fread(buffer, sizeof(char), sizeof(buffer), pipe)) > 0) + NULL; /* drain the pipe */ + pclose(pipe); + return (cnt); /* read how many bytes where read in */ +} + +/* + * digest_file() This function will read a file and run hash over it + * input is a file name + */ +static int +digest_file(dst_work *work) +{ + static int f_cnt = 0; + static unsigned long f_round = 0; + FILE *fp; + void *ctx; + const char *name; + int no, i; + struct stat st; + struct timeval tv; + u_char buf[1024]; + + if (f_round == 0 || files[f_cnt] == NULL || work->file_digest == NULL) + if (gettimeofday(&tv, NULL)) /* only do this if needed */ + return (0); + if (f_round == 0) /* first time called set to one hour ago */ + f_round = (tv.tv_sec - MAX_OLD); + name = files[f_cnt++]; + if (files[f_cnt] == NULL) { /* end of list of files */ + if(f_cnt <= 1) /* list is too short */ + return (0); + f_cnt = 0; /* start again on list */ + f_round += (tv.tv_sec - f_round)/2; /* set new cutoff */ + work->file_digest = dst_free_key(work->file_digest); + } + if (work->file_digest == NULL) { + work->file_digest = dst_buffer_to_key("", KEY_HMAC_MD5, 0, 0, + (u_char *)&tv, sizeof(tv)); + if (work->file_digest == NULL) + return (0); + } + if (access(name, R_OK) || stat(name, &st)) + return (0); /* no such file or not allowed to read it */ + if (strncmp(name, "/proc/", 6) && st.st_mtime < f_round) + return(0); /* file has not changed recently enough */ + if (dst_sign_data(SIG_MODE_INIT, work->file_digest, &ctx, + NULL, 0, NULL, 0)) { + work->file_digest = dst_free_key(work->file_digest); + return (0); + } + if ((fp = fopen(name, "r")) == NULL) + return (0); + for (no = 0; (i = fread(buf, sizeof(*buf), sizeof(buf), fp)) > 0; + no += i) + dst_sign_data(SIG_MODE_UPDATE, work->file_digest, &ctx, + buf, (unsigned)i, NULL, 0); + + fclose(fp); + if (no >= 64) { + i = dst_sign_data(SIG_MODE_FINAL, work->file_digest, &ctx, + NULL, 0, &work->output[work->filled], + DST_HASH_SIZE); + if (i > 0) + work->filled += i; + } + else if (i > 0) + my_digest(work, buf, (unsigned)i); + my_digest(work, (const u_char *)name, strlen(name)); + return (no + strlen(name)); +} + +/* + * function to perform the FINAL and INIT operation on a hash if allowed + */ +static void +force_hash(dst_work *work, prand_hash *hash) +{ + int i = 0; + + /* + * if more than half a block then add data to output + * otherwise adde the digest to the next hash + */ + if ((hash->digested * 2) > hash->block) { + i = dst_sign_data(SIG_MODE_FINAL, hash->key, &hash->ctx, + NULL, 0, &work->output[work->filled], + DST_HASH_SIZE); + + hash->digested = 0; + dst_sign_data(SIG_MODE_INIT, hash->key, &hash->ctx, + NULL, 0, NULL, 0); + if (i > 0) + work->filled += i; + } + return; +} + +/* + * This function takes the input data does the selection of data specified + * by the hash control block. + * The step varialbe in the work sturcture determines which 1/step bytes + * are used, + * + */ +static int +do_hash(dst_work *work, prand_hash *hash, const u_char *input, unsigned size) +{ + const u_char *tmp = input; + u_char *tp, *abuf = (u_char *)0; + int i, n; + unsigned needed, avail, dig, cnt = size; + unsigned tmp_size = 0; + + if (cnt <= 0 || input == NULL) + return (0); + + if (hash->step > 1) { /* if using subset of input data */ + tmp_size = size / hash->step + 2; + abuf = tp = malloc(tmp_size); + tmp = tp; + for (cnt = 0, i = hash->curr; i < size; i += hash->step, cnt++) + *(tp++) = input[i]; + /* calcutate the starting point in the next input set */ + hash->curr = (hash->step - (i - size)) % hash->step; + } + /* digest the data in block sizes */ + for (n = 0; n < cnt; n += needed) { + avail = (cnt - n); + needed = hash->block - hash->digested; + dig = (avail < needed) ? avail : needed; + dst_sign_data(SIG_MODE_UPDATE, hash->key, &hash->ctx, + &tmp[n], dig, NULL, 0); + hash->digested += dig; + if (hash->digested >= hash->block) + force_hash(work, hash); + if (work->needed < work->filled) { + if (abuf) + SAFE_FREE2(abuf, tmp_size); + return (1); + } + } + if (tmp_size > 0) + SAFE_FREE2(abuf, tmp_size); + return (0); +} + +/* + * Copy data from INPUT for length SIZE into the work-block TMP. + * If we fill the work-block, digest it; then, + * if work-block needs more data, keep filling with the rest of the input. + */ +static int +my_digest(dst_work *work, const u_char *input, unsigned size) +{ + + int i, full = 0; + static unsigned counter; + + counter += size; + /* first do each one of the hashes */ + for (i = 0; i < DST_NUM_HASHES && full == 0; i++) + full = do_hash(work, work->hash[i], input, size) + + do_hash(work, work->hash[i], (u_char *) &counter, + sizeof(counter)); +/* + * if enough data has be generated do final operation on all hashes + * that have enough date for that + */ + for (i = 0; full && (i < DST_NUM_HASHES); i++) + force_hash(work, work->hash[i]); + + return (full); +} + +/* + * this function gets some semi random data and sets that as an HMAC key + * If we get a valid key this function returns that key initalized + * otherwise it returns NULL; + */ +static prand_hash * +get_hmac_key(int step, int block) +{ + + u_char *buff; + int temp = 0, n = 0; + unsigned size = 70; + DST_KEY *new_key = NULL; + prand_hash *new = NULL; + + /* use key that is larger than digest algorithms (64) for key size */ + buff = malloc(size); + if (buff == NULL) + return (NULL); + /* do not memset the allocated memory to get random bytes there */ + /* time of day is somewhat random expecialy in the last bytes */ + gettimeofday((struct timeval *) &buff[n], NULL); + n += sizeof(struct timeval); + +/* get some semi random stuff in here stir it with micro seconds */ + if (n < size) { + temp = dst_s_quick_random((int) buff[n - 1]); + memcpy(&buff[n], &temp, sizeof(temp)); + n += sizeof(temp); + } +/* get the pid of this process and its parent */ + if (n < size) { + temp = (int) getpid(); + memcpy(&buff[n], &temp, sizeof(temp)); + n += sizeof(temp); + } + if (n < size) { + temp = (int) getppid(); + memcpy(&buff[n], &temp, sizeof(temp)); + n += sizeof(temp); + } +/* get the user ID */ + if (n < size) { + temp = (int) getuid(); + memcpy(&buff[n], &temp, sizeof(temp)); + n += sizeof(temp); + } +#ifndef GET_HOST_ID_MISSING + if (n < size) { + temp = (int) gethostid(); + memcpy(&buff[n], &temp, sizeof(temp)); + n += sizeof(temp); + } +#endif +/* get some more random data */ + if (n < size) { + temp = dst_s_quick_random((int) buff[n - 1]); + memcpy(&buff[n], &temp, sizeof(temp)); + n += sizeof(temp); + } +/* covert this into a HMAC key */ + new_key = dst_buffer_to_key("", KEY_HMAC_MD5, 0, 0, buff, size); + SAFE_FREE(buff); + +/* get the control structure */ + if ((new = malloc(sizeof(prand_hash))) == NULL) + return (NULL); + new->digested = new->curr = 0; + new->step = step; + new->block = block; + new->key = new_key; + if (dst_sign_data(SIG_MODE_INIT, new_key, &new->ctx, NULL, 0, NULL, 0)) + return (NULL); + + return (new); +} + +/* + * own_random() + * This function goes out and from various sources tries to generate enough + * semi random data that a hash function can generate a random data. + * This function will iterate between the two main random source sources, + * information from programs and directores in random order. + * This function return the number of bytes added to the random output buffer. + */ +static unsigned +own_random(dst_work *work) +{ + int dir = 0, b; + int bytes, n, cmd = 0, dig = 0; + int start =0; +/* + * now get the initial seed to put into the quick random function from + * the address of the work structure + */ + bytes = (int) getpid(); +/* + * proceed while needed + */ + while (work->filled < work->needed) { + EREPORT(("own_random r %08x b %6d t %6d f %6d\n", + ran_val, bytes, work->in_temp, work->filled)); +/* pick a random number in the range of 0..7 based on that random number + * perform some operations that yield random data + */ + start = work->filled; + n = (dst_s_quick_random(bytes) >> DST_SHIFT) & 0x07; + switch (n) { + case 0: + case 3: + if (sizeof(cmds) > 2 *sizeof(*cmds)) { + b = unix_cmd(work); + cmd += b; + } + break; + + case 1: + case 7: + if (sizeof(dirs) > 2 *sizeof(*dirs)) { + b = do_ls(work); + dir += b; + } + break; + + case 4: + case 5: + /* retry getting data from /dev/random */ + b = get_dev_random(&work->output[work->filled], + work->needed - work->filled); + if (b > 0) + work->filled += b; + break; + + case 6: + if (sizeof(files) > 2 * sizeof(*files)) { + b = digest_file(work); + dig += b; + } + break; + + case 2: + default: /* to make sure we make some progress */ + work->output[work->filled++] = 0xff & + dst_s_quick_random(bytes); + b = 1; + break; + } + if (b > 0) + bytes += b; + } + return (work->filled); +} + + +/* + * dst_s_random() This function will return the requested number of bytes + * of randomness to the caller it will use the best available sources of + * randomness. + * The current order is to use /dev/random, precalculated randomness, and + * finaly use some system calls and programs to generate semi random data that + * is then digested to generate randomness. + * This function is thread safe as each thread uses its own context, but + * concurrent treads will affect each other as they update shared state + * information. + * It is strongly recommended that this function be called requesting a size + * that is not a multiple of the output of the hash function used. + * + * If /dev/random is not available this function is not suitable to generate + * large ammounts of data, rather it is suitable to seed a pseudo-random + * generator + * Returns the number of bytes put in the output buffer + */ +int +dst_s_random(u_char *output, unsigned size) +{ + int n = 0, i; + unsigned s; + static u_char old_unused[DST_HASH_SIZE * DST_NUM_HASHES]; + static unsigned unused = 0; + + if (size <= 0 || output == NULL) + return (0); + + if (size >= 2048) + return (-1); + /* + * Read from /dev/random + */ + n = get_dev_random(output, size); + /* + * If old data is available and needed use it + */ + if (n < size && unused > 0) { + unsigned need = size - n; + if (unused <= need) { + memcpy(output, old_unused, unused); + n += unused; + unused = 0; + } else { + memcpy(output, old_unused, need); + n += need; + unused -= need; + memcpy(old_unused, &old_unused[need], unused); + } + } + /* + * If we need more use the simulated randomness here. + */ + if (n < size) { + dst_work *my_work = (dst_work *) malloc(sizeof(dst_work)); + if (my_work == NULL) + return (n); + my_work->needed = size - n; + my_work->filled = 0; + my_work->output = (u_char *) malloc(my_work->needed + + DST_HASH_SIZE * + DST_NUM_HASHES); + my_work->file_digest = NULL; + if (my_work->output == NULL) + return (n); + memset(my_work->output, 0x0, my_work->needed); +/* allocate upto 4 different HMAC hash functions out of order */ +#if DST_NUM_HASHES >= 3 + my_work->hash[2] = get_hmac_key(3, DST_RANDOM_BLOCK_SIZE / 2); +#endif +#if DST_NUM_HASHES >= 2 + my_work->hash[1] = get_hmac_key(7, DST_RANDOM_BLOCK_SIZE / 6); +#endif +#if DST_NUM_HASHES >= 4 + my_work->hash[3] = get_hmac_key(5, DST_RANDOM_BLOCK_SIZE / 4); +#endif + my_work->hash[0] = get_hmac_key(1, DST_RANDOM_BLOCK_SIZE); + if (my_work->hash[0] == NULL) /* if failure bail out */ + return (n); + s = own_random(my_work); +/* if more generated than needed store it for future use */ + if (s >= my_work->needed) { + EREPORT(("dst_s_random(): More than needed %d >= %d\n", + s, my_work->needed)); + memcpy(&output[n], my_work->output, my_work->needed); + n += my_work->needed; + /* saving unused data for next time */ + unused = s - my_work->needed; + memcpy(old_unused, &my_work->output[my_work->needed], + unused); + } else { + /* XXXX This should not happen */ + EREPORT(("Not enough %d >= %d\n", s, my_work->needed)); + memcpy(&output[n], my_work->output, s); + n += my_work->needed; + } + +/* delete the allocated work area */ + for (i = 0; i < DST_NUM_HASHES; i++) { + dst_free_key(my_work->hash[i]->key); + SAFE_FREE(my_work->hash[i]); + } + SAFE_FREE(my_work->output); + SAFE_FREE(my_work); + } + return (n); +} + +/* + * A random number generator that is fast and strong + * this random number generator is based on HASHing data, + * the input to the digest function is a collection of <NUMBER_OF_COUNTERS> + * counters that is incremented between digest operations + * each increment operation amortizes to 2 bits changed in that value + * for 5 counters thus the input will amortize to have 10 bits changed + * The counters are initaly set using the strong random function above + * the HMAC key is selected by the same methold as the HMAC keys for the + * strong random function. + * Each set of counters is used for 2^25 operations + * + * returns the number of bytes written to the output buffer + * or negative number in case of error + */ +int +dst_s_semi_random(u_char *output, unsigned size) +{ + static u_int32_t counter[DST_NUMBER_OF_COUNTERS]; + static u_char semi_old[DST_HASH_SIZE]; + static int semi_loc = 0, cnt = 0; + static unsigned hb_size = 0; + static DST_KEY *my_key = NULL; + prand_hash *hash; + unsigned out = 0; + unsigned i; + int n; + + if (output == NULL || size <= 0) + return (-2); + +/* check if we need a new key */ + if (my_key == NULL || cnt > (1 << 25)) { /* get HMAC KEY */ + if (my_key) + my_key->dk_func->destroy(my_key); + if ((hash = get_hmac_key(1, DST_RANDOM_BLOCK_SIZE)) == NULL) + return (0); + my_key = hash->key; +/* check if the key works stir the new key using some old random data */ + hb_size = dst_sign_data(SIG_MODE_ALL, my_key, NULL, + (u_char *) counter, sizeof(counter), + semi_old, sizeof(semi_old)); + if (hb_size <= 0) { + EREPORT(("dst_s_semi_random() Sign of alg %d failed %d\n", + my_key->dk_alg, hb_size)); + return (-1); + } +/* new set the counters to random values */ + dst_s_random((u_char *) counter, sizeof(counter)); + cnt = 0; + } +/* if old data around use it first */ + if (semi_loc < hb_size) { + if (size <= hb_size - semi_loc) { /* need less */ + memcpy(output, &semi_old[semi_loc], size); + semi_loc += size; + return (size); /* DONE */ + } else { + out = hb_size - semi_loc; + memcpy(output, &semi_old[semi_loc], out); + semi_loc += out; + } + } +/* generate more randome stuff */ + while (out < size) { + /* + * modify at least one bit by incrementing at least one counter + * based on the last bit of the last counter updated update + * the next one. + * minimaly this operation will modify at least 1 bit, + * amortized 2 bits + */ + for (n = 0; n < DST_NUMBER_OF_COUNTERS; n++) + i = (int) counter[n]++; + + i = dst_sign_data(SIG_MODE_ALL, my_key, NULL, + (u_char *) counter, hb_size, + semi_old, sizeof(semi_old)); + if (i != hb_size) + EREPORT(("HMAC SIGNATURE FAILURE %d\n", i)); + cnt++; + if (size - out < i) /* Not all data is needed */ + semi_loc = i = size - out; + memcpy(&output[out], semi_old, i); + out += i; + } + return (out); +} diff --git a/contrib/isc-dhcp/includes/arpa/nameser.h b/contrib/isc-dhcp/includes/arpa/nameser.h index 5b38997..19c9d5d 100644 --- a/contrib/isc-dhcp/includes/arpa/nameser.h +++ b/contrib/isc-dhcp/includes/arpa/nameser.h @@ -1,6 +1,4 @@ /* - * ++Copyright++ 1983, 1989, 1993 - * - * Copyright (c) 1983, 1989, 1993 * The Regents of the University of California. All rights reserved. * @@ -31,207 +29,433 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - - * Portions Copyright (c) 1993 by Digital Equipment Corporation. - * + */ + +/* + * Copyright (c) 1996-1999 by Internet Software Consortium. + * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies, and that - * the name of Digital Equipment Corporation not be used in advertising or - * publicity pertaining to distribution of the document or software without - * specific, written prior permission. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT - * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, 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. - * - - * --Copyright-- - */ - -/* - * @(#)nameser.h 8.1 (Berkeley) 6/2/93 - * $Id: nameser.h,v 8.3 1995/08/21 01:27:12 vixie Exp - */ - -#ifndef _NAMESER_H_ -#define _NAMESER_H_ - -/* - * Define constants based on rfc883 - */ -#define PACKETSZ 512 /* maximum packet size */ -#define MAXDNAME 256 /* maximum domain name */ -#define MAXCDNAME 255 /* maximum compressed domain name */ -#define MAXLABEL 63 /* maximum length of domain label */ -#define HFIXEDSZ 12 /* #/bytes of fixed data in header */ -#define QFIXEDSZ 4 /* #/bytes of fixed data in query */ -#define RRFIXEDSZ 10 /* #/bytes of fixed data in r record */ -#define INT32SZ 4 /* for systems without 32-bit ints */ -#define INT16SZ 2 /* for systems without 16-bit ints */ -#define INADDRSZ 4 /* for sizeof(struct inaddr) != 4 */ - -/* - * Internet nameserver port number - */ -#define NAMESERVER_PORT 53 - -/* - * Currently defined opcodes - */ -#define QUERY 0x0 /* standard query */ -#define IQUERY 0x1 /* inverse query */ -#define STATUS 0x2 /* nameserver status query */ -/*#define xxx 0x3*/ /* 0x3 reserved */ -#define NS_NOTIFY_OP 0x4 /* notify secondary of SOA change */ -#ifdef ALLOW_UPDATES - /* non standard - supports ALLOW_UPDATES stuff from Mike Schwartz */ -# define UPDATEA 0x9 /* add resource record */ -# define UPDATED 0xa /* delete a specific resource record */ -# define UPDATEDA 0xb /* delete all named resource record */ -# define UPDATEM 0xc /* modify a specific resource record */ -# define UPDATEMA 0xd /* modify all named resource record */ -# define ZONEINIT 0xe /* initial zone transfer */ -# define ZONEREF 0xf /* incremental zone referesh */ -#endif - -/* - * Currently defined response codes - */ -#define NOERROR 0 /* no error */ -#define FORMERR 1 /* format error */ -#define SERVFAIL 2 /* server failure */ -#define NXDOMAIN 3 /* non existent domain */ -#define NOTIMP 4 /* not implemented */ -#define REFUSED 5 /* query refused */ -#ifdef ALLOW_UPDATES - /* non standard */ -# define NOCHANGE 0xf /* update failed to change db */ -#endif - -/* - * Type values for resources and queries - */ -#define T_A 1 /* host address */ -#define T_NS 2 /* authoritative server */ -#define T_MD 3 /* mail destination */ -#define T_MF 4 /* mail forwarder */ -#define T_CNAME 5 /* canonical name */ -#define T_SOA 6 /* start of authority zone */ -#define T_MB 7 /* mailbox domain name */ -#define T_MG 8 /* mail group member */ -#define T_MR 9 /* mail rename name */ -#define T_NULL 10 /* null resource record */ -#define T_WKS 11 /* well known service */ -#define T_PTR 12 /* domain name pointer */ -#define T_HINFO 13 /* host information */ -#define T_MINFO 14 /* mailbox information */ -#define T_MX 15 /* mail routing information */ -#define T_TXT 16 /* text strings */ -#define T_RP 17 /* responsible person */ -#define T_AFSDB 18 /* AFS cell database */ -#define T_X25 19 /* X_25 calling address */ -#define T_ISDN 20 /* ISDN calling address */ -#define T_RT 21 /* router */ -#define T_NSAP 22 /* NSAP address */ -#define T_NSAP_PTR 23 /* reverse NSAP lookup (deprecated) */ -#define T_SIG 24 /* security signature */ -#define T_KEY 25 /* security key */ -#define T_PX 26 /* X.400 mail mapping */ -#define T_GPOS 27 /* geographical position (withdrawn) */ -#define T_AAAA 28 /* IP6 Address */ -#define T_LOC 29 /* Location Information */ - /* non standard */ -#define T_UINFO 100 /* user (finger) information */ -#define T_UID 101 /* user ID */ -#define T_GID 102 /* group ID */ -#define T_UNSPEC 103 /* Unspecified format (binary data) */ - /* Query type values which do not appear in resource records */ -#define T_AXFR 252 /* transfer zone of authority */ -#define T_MAILB 253 /* transfer mailbox records */ -#define T_MAILA 254 /* transfer mail agent records */ -#define T_ANY 255 /* wildcard match */ + */ /* - * Values for class field + * $Id: nameser.h,v 1.4 2000/02/02 07:23:18 mellon Exp $ */ -#define C_IN 1 /* the arpa internet */ -#define C_CHAOS 3 /* for chaos net (MIT) */ -#define C_HS 4 /* for Hesiod name server (MIT) (XXX) */ - /* Query class values which do not appear in resource records */ -#define C_ANY 255 /* wildcard match */ - -/* - * Status return codes for T_UNSPEC conversion routines - */ -#define CONV_SUCCESS 0 -#define CONV_OVERFLOW (-1) -#define CONV_BADFMT (-2) -#define CONV_BADCKSUM (-3) -#define CONV_BADBUFLEN (-4) - -/* - * Structure for query header. The order of the fields is machine- and - * compiler-dependent, depending on the byte/bit order and the layout - * of bit fields. We use bit fields only in int variables, as this - * is all ANSI requires. This requires a somewhat confusing rearrangement. - */ - -typedef struct { - unsigned id :16; /* query identification number */ -#if BYTE_ORDER == BIG_ENDIAN - /* fields in third byte */ - unsigned qr: 1; /* response flag */ - unsigned opcode: 4; /* purpose of message */ - unsigned aa: 1; /* authoritive answer */ - unsigned tc: 1; /* truncated message */ - unsigned rd: 1; /* recursion desired */ - /* fields in fourth byte */ - unsigned ra: 1; /* recursion available */ - unsigned pr:1; /* primary server required (non standard) */ - unsigned unused :2; /* unused bits (MBZ as of 4.9.3a3) */ - unsigned rcode :4; /* response code */ -#endif -#if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN - /* fields in third byte */ - unsigned rd :1; /* recursion desired */ - unsigned tc :1; /* truncated message */ - unsigned aa :1; /* authoritive answer */ - unsigned opcode :4; /* purpose of message */ - unsigned qr :1; /* response flag */ - /* fields in fourth byte */ - unsigned rcode :4; /* response code */ - unsigned unused :2; /* unused bits (MBZ as of 4.9.3a3) */ - unsigned pr:1; /* primary server required (non standard) */ - unsigned ra :1; /* recursion available */ -#endif - /* remaining bytes */ - unsigned qdcount :16; /* number of question entries */ - unsigned ancount :16; /* number of answer entries */ - unsigned nscount :16; /* number of authority entries */ - unsigned arcount :16; /* number of resource entries */ -} HEADER; - -/* - * Defines for handling compressed domain names - */ -#define INDIR_MASK 0xc0 - -/* - * Structure for passing resource records around. - */ -struct rrec { - int16_t r_zone; /* zone number */ - int16_t r_class; /* class number */ - int16_t r_type; /* type number */ - u_int32_t r_ttl; /* time to live */ - int r_size; /* size of data area */ - char *r_data; /* pointer to data */ +#ifndef _ARPA_NAMESER_H_ +#define _ARPA_NAMESER_H_ + +/* + * Revision information. This is the release date in YYYYMMDD format. + * It can change every day so the right thing to do with it is use it + * in preprocessor commands such as "#if (__NAMESER > 19931104)". Do not + * compare for equality; rather, use it to determine whether your libbind.a + * contains a new enough lib/nameser/ to support the feature you need. + */ + +#define __NAMESER 19991006 /* New interface version stamp. */ + +/* + * Define constants based on RFC 883, RFC 1034, RFC 1035 + */ +#define NS_PACKETSZ 512 /* maximum packet size */ +#define NS_MAXDNAME 1025 /* maximum domain name */ +#define NS_MAXCDNAME 255 /* maximum compressed domain name */ +#define NS_MAXLABEL 63 /* maximum length of domain label */ +#define NS_HFIXEDSZ 12 /* #/bytes of fixed data in header */ +#define NS_QFIXEDSZ 4 /* #/bytes of fixed data in query */ +#define NS_RRFIXEDSZ 10 /* #/bytes of fixed data in r record */ +#define NS_INT32SZ 4 /* #/bytes of data in a u_int32_t */ +#define NS_INT16SZ 2 /* #/bytes of data in a u_int16_t */ +#define NS_INT8SZ 1 /* #/bytes of data in a u_int8_t */ +#define NS_INADDRSZ 4 /* IPv4 T_A */ +#define NS_IN6ADDRSZ 16 /* IPv6 T_AAAA */ +#define NS_CMPRSFLGS 0xc0 /* Flag bits indicating name compression. */ +#define NS_DEFAULTPORT 53 /* For both TCP and UDP. */ + +/* + * These can be expanded with synonyms, just keep ns_parse.c:ns_parserecord() + * in synch with it. + */ +typedef enum __ns_sect { + ns_s_qd = 0, /* Query: Question. */ + ns_s_zn = 0, /* Update: Zone. */ + ns_s_an = 1, /* Query: Answer. */ + ns_s_pr = 1, /* Update: Prerequisites. */ + ns_s_ns = 2, /* Query: Name servers. */ + ns_s_ud = 2, /* Update: Update. */ + ns_s_ar = 3, /* Query|Update: Additional records. */ + ns_s_max = 4 +} ns_sect; + +/* + * This is a message handle. It is caller allocated and has no dynamic data. + * This structure is intended to be opaque to all but ns_parse.c, thus the + * leading _'s on the member names. Use the accessor functions, not the _'s. + */ +typedef struct __ns_msg { + const u_int8_t *_msg, *_eom; + u_int16_t _id, _flags, _counts[ns_s_max]; + const u_int8_t *_sections[ns_s_max]; + ns_sect _sect; + int _rrnum; + const u_int8_t *_ptr; +} ns_msg; + +/* Private data structure - do not use from outside library. */ +struct _ns_flagdata { int mask, shift; }; +extern struct _ns_flagdata _ns_flagdata[]; + +/* Accessor macros - this is part of the public interface. */ +#define ns_msg_getflag(handle, flag) ( \ + ((handle)._flags & _ns_flagdata[flag].mask) \ + >> _ns_flagdata[flag].shift \ + ) +#define ns_msg_id(handle) ((handle)._id + 0) +#define ns_msg_base(handle) ((handle)._msg + 0) +#define ns_msg_end(handle) ((handle)._eom + 0) +#define ns_msg_size(handle) ((handle)._eom - (handle)._msg) +#define ns_msg_count(handle, section) ((handle)._counts[section] + 0) + +/* + * This is a parsed record. It is caller allocated and has no dynamic data. + */ +typedef struct __ns_rr { + char name[NS_MAXDNAME]; + u_int16_t type; + u_int16_t rr_class; + u_int32_t ttl; + u_int16_t rdlength; + const u_int8_t *rdata; +} ns_rr; + +/* Accessor macros - this is part of the public interface. */ +#define ns_rr_name(rr) (((rr).name[0] != '\0') ? (rr).name : ".") +#define ns_rr_type(rr) ((ns_type)((rr).type + 0)) +#define ns_rr_class(rr) ((ns_class)((rr).rr_class + 0)) +#define ns_rr_ttl(rr) ((rr).ttl + 0) +#define ns_rr_rdlen(rr) ((rr).rdlength + 0) +#define ns_rr_rdata(rr) ((rr).rdata + 0) + +/* + * These don't have to be in the same order as in the packet flags word, + * and they can even overlap in some cases, but they will need to be kept + * in synch with ns_parse.c:ns_flagdata[]. + */ +typedef enum __ns_flag { + ns_f_qr, /* Question/Response. */ + ns_f_opcode, /* Operation code. */ + ns_f_aa, /* Authoritative Answer. */ + ns_f_tc, /* Truncation occurred. */ + ns_f_rd, /* Recursion Desired. */ + ns_f_ra, /* Recursion Available. */ + ns_f_z, /* MBZ. */ + ns_f_ad, /* Authentic Data (DNSSEC). */ + ns_f_cd, /* Checking Disabled (DNSSEC). */ + ns_f_rcode, /* Response code. */ + ns_f_max +} ns_flag; + +/* + * Currently defined opcodes. + */ +typedef enum __ns_opcode { + ns_o_query = 0, /* Standard query. */ + ns_o_iquery = 1, /* Inverse query (deprecated/unsupported). */ + ns_o_status = 2, /* Name server status query (unsupported). */ + /* Opcode 3 is undefined/reserved. */ + ns_o_notify = 4, /* Zone change notification. */ + ns_o_update = 5, /* Zone update message. */ + ns_o_max = 6 +} ns_opcode; + +/* + * Currently defined response codes. + */ +typedef enum __ns_rcode { + ns_r_noerror = 0, /* No error occurred. */ + ns_r_formerr = 1, /* Format error. */ + ns_r_servfail = 2, /* Server failure. */ + ns_r_nxdomain = 3, /* Name error. */ + ns_r_notimpl = 4, /* Unimplemented. */ + ns_r_refused = 5, /* Operation refused. */ + /* these are for BIND_UPDATE */ + ns_r_yxdomain = 6, /* Name exists */ + ns_r_yxrrset = 7, /* RRset exists */ + ns_r_nxrrset = 8, /* RRset does not exist */ + ns_r_notauth = 9, /* Not authoritative for zone */ + ns_r_notzone = 10, /* Zone of record different from zone section */ + ns_r_max = 11, + /* The following are TSIG extended errors */ + ns_r_badsig = 16, + ns_r_badkey = 17, + ns_r_badtime = 18 +} ns_rcode; + +/* BIND_UPDATE */ +typedef enum __ns_update_operation { + ns_uop_delete = 0, + ns_uop_add = 1, + ns_uop_max = 2 +} ns_update_operation; + +/* + * This structure is used for TSIG authenticated messages + */ +struct ns_tsig_key { + char name[NS_MAXDNAME], alg[NS_MAXDNAME]; + unsigned char *data; + unsigned len; }; +typedef struct ns_tsig_key ns_tsig_key; + +/* + * This structure is used for TSIG authenticated TCP messages + */ +struct ns_tcp_tsig_state { + int counter; + struct dst_key *key; + void *ctx; + unsigned char sig[NS_PACKETSZ]; + unsigned siglen; +}; +typedef struct ns_tcp_tsig_state ns_tcp_tsig_state; + +#define NS_TSIG_FUDGE 300 +#define NS_TSIG_TCP_COUNT 100 +#define NS_TSIG_ALG_HMAC_MD5 "HMAC-MD5.SIG-ALG.REG.INT" + +#define NS_TSIG_ERROR_NO_TSIG -10 +#define NS_TSIG_ERROR_NO_SPACE -11 +#define NS_TSIG_ERROR_FORMERR -12 + +/* + * Currently defined type values for resources and queries. + */ +typedef enum __ns_type { + ns_t_invalid = 0, /* Cookie. */ + ns_t_a = 1, /* Host address. */ + ns_t_ns = 2, /* Authoritative server. */ + ns_t_md = 3, /* Mail destination. */ + ns_t_mf = 4, /* Mail forwarder. */ + ns_t_cname = 5, /* Canonical name. */ + ns_t_soa = 6, /* Start of authority zone. */ + ns_t_mb = 7, /* Mailbox domain name. */ + ns_t_mg = 8, /* Mail group member. */ + ns_t_mr = 9, /* Mail rename name. */ + ns_t_null = 10, /* Null resource record. */ + ns_t_wks = 11, /* Well known service. */ + ns_t_ptr = 12, /* Domain name pointer. */ + ns_t_hinfo = 13, /* Host information. */ + ns_t_minfo = 14, /* Mailbox information. */ + ns_t_mx = 15, /* Mail routing information. */ + ns_t_txt = 16, /* Text strings. */ + ns_t_rp = 17, /* Responsible person. */ + ns_t_afsdb = 18, /* AFS cell database. */ + ns_t_x25 = 19, /* X_25 calling address. */ + ns_t_isdn = 20, /* ISDN calling address. */ + ns_t_rt = 21, /* Router. */ + ns_t_nsap = 22, /* NSAP address. */ + ns_t_nsap_ptr = 23, /* Reverse NSAP lookup (deprecated). */ + ns_t_sig = 24, /* Security signature. */ + ns_t_key = 25, /* Security key. */ + ns_t_px = 26, /* X.400 mail mapping. */ + ns_t_gpos = 27, /* Geographical position (withdrawn). */ + ns_t_aaaa = 28, /* Ip6 Address. */ + ns_t_loc = 29, /* Location Information. */ + ns_t_nxt = 30, /* Next domain (security). */ + ns_t_eid = 31, /* Endpoint identifier. */ + ns_t_nimloc = 32, /* Nimrod Locator. */ + ns_t_srv = 33, /* Server Selection. */ + ns_t_atma = 34, /* ATM Address */ + ns_t_naptr = 35, /* Naming Authority PoinTeR */ + ns_t_kx = 36, /* Key Exchange */ + ns_t_cert = 37, /* Certification record */ + ns_t_a6 = 38, /* IPv6 address (deprecates AAAA) */ + ns_t_dname = 39, /* Non-terminal DNAME (for IPv6) */ + ns_t_sink = 40, /* Kitchen sink (experimentatl) */ + ns_t_opt = 41, /* EDNS0 option (meta-RR) */ + ns_t_tsig = 250, /* Transaction signature. */ + ns_t_ixfr = 251, /* Incremental zone transfer. */ + ns_t_axfr = 252, /* Transfer zone of authority. */ + ns_t_mailb = 253, /* Transfer mailbox records. */ + ns_t_maila = 254, /* Transfer mail agent records. */ + ns_t_any = 255, /* Wildcard match. */ + ns_t_zxfr = 256, /* BIND-specific, nonstandard. */ + ns_t_max = 65536 +} ns_type; + +/* Exclusively a QTYPE? (not also an RTYPE) */ +#define ns_t_qt_p(t) (ns_t_xfr_p(t) || (t) == ns_t_any || \ + (t) == ns_t_mailb || (t) == ns_t_maila) +/* Some kind of meta-RR? (not a QTYPE, but also not an RTYPE) */ +#define ns_t_mrr_p(t) ((t) == ns_t_tsig || (t) == ns_t_opt) +/* Exclusively an RTYPE? (not also a QTYPE or a meta-RR) */ +#define ns_t_rr_p(t) (!ns_t_qt_p(t) && !ns_t_mrr_p(t)) +#define ns_t_udp_p(t) ((t) != ns_t_axfr && (t) != ns_t_zxfr) +#define ns_t_xfr_p(t) ((t) == ns_t_axfr || (t) == ns_t_ixfr || \ + (t) == ns_t_zxfr) + +/* + * Values for class field + */ +typedef enum __ns_class { + ns_c_invalid = 0, /* Cookie. */ + ns_c_in = 1, /* Internet. */ + ns_c_2 = 2, /* unallocated/unsupported. */ + ns_c_chaos = 3, /* MIT Chaos-net. */ + ns_c_hs = 4, /* MIT Hesiod. */ + /* Query class values which do not appear in resource records */ + ns_c_none = 254, /* for prereq. sections in update requests */ + ns_c_any = 255, /* Wildcard match. */ + ns_c_max = 65536 +} ns_class; + +/* DNSSEC constants. */ + +typedef enum __ns_key_types { + ns_kt_rsa = 1, /* key type RSA/MD5 */ + ns_kt_dh = 2, /* Diffie Hellman */ + ns_kt_dsa = 3, /* Digital Signature Standard (MANDATORY) */ + ns_kt_private = 254 /* Private key type starts with OID */ +} ns_key_types; + +typedef enum __ns_cert_types { + cert_t_pkix = 1, /* PKIX (X.509v3) */ + cert_t_spki = 2, /* SPKI */ + cert_t_pgp = 3, /* PGP */ + cert_t_url = 253, /* URL private type */ + cert_t_oid = 254 /* OID private type */ +} ns_cert_types; + +/* Flags field of the KEY RR rdata. */ +#define NS_KEY_TYPEMASK 0xC000 /* Mask for "type" bits */ +#define NS_KEY_TYPE_AUTH_CONF 0x0000 /* Key usable for both */ +#define NS_KEY_TYPE_CONF_ONLY 0x8000 /* Key usable for confidentiality */ +#define NS_KEY_TYPE_AUTH_ONLY 0x4000 /* Key usable for authentication */ +#define NS_KEY_TYPE_NO_KEY 0xC000 /* No key usable for either; no key */ +/* The type bits can also be interpreted independently, as single bits: */ +#define NS_KEY_NO_AUTH 0x8000 /* Key unusable for authentication */ +#define NS_KEY_NO_CONF 0x4000 /* Key unusable for confidentiality */ +#define NS_KEY_RESERVED2 0x2000 /* Security is *mandatory* if bit=0 */ +#define NS_KEY_EXTENDED_FLAGS 0x1000 /* reserved - must be zero */ +#define NS_KEY_RESERVED4 0x0800 /* reserved - must be zero */ +#define NS_KEY_RESERVED5 0x0400 /* reserved - must be zero */ +#define NS_KEY_NAME_TYPE 0x0300 /* these bits determine the type */ +#define NS_KEY_NAME_USER 0x0000 /* key is assoc. with user */ +#define NS_KEY_NAME_ENTITY 0x0200 /* key is assoc. with entity eg host */ +#define NS_KEY_NAME_ZONE 0x0100 /* key is zone key */ +#define NS_KEY_NAME_RESERVED 0x0300 /* reserved meaning */ +#define NS_KEY_RESERVED8 0x0080 /* reserved - must be zero */ +#define NS_KEY_RESERVED9 0x0040 /* reserved - must be zero */ +#define NS_KEY_RESERVED10 0x0020 /* reserved - must be zero */ +#define NS_KEY_RESERVED11 0x0010 /* reserved - must be zero */ +#define NS_KEY_SIGNATORYMASK 0x000F /* key can sign RR's of same name */ +#define NS_KEY_RESERVED_BITMASK ( NS_KEY_RESERVED2 | \ + NS_KEY_RESERVED4 | \ + NS_KEY_RESERVED5 | \ + NS_KEY_RESERVED8 | \ + NS_KEY_RESERVED9 | \ + NS_KEY_RESERVED10 | \ + NS_KEY_RESERVED11 ) +#define NS_KEY_RESERVED_BITMASK2 0xFFFF /* no bits defined here */ + +/* The Algorithm field of the KEY and SIG RR's is an integer, {1..254} */ +#define NS_ALG_MD5RSA 1 /* MD5 with RSA */ +#define NS_ALG_DH 2 /* Diffie Hellman KEY */ +#define NS_ALG_DSA 3 /* DSA KEY */ +#define NS_ALG_DSS NS_ALG_DSA +#define NS_ALG_EXPIRE_ONLY 253 /* No alg, no security */ +#define NS_ALG_PRIVATE_OID 254 /* Key begins with OID giving alg */ + +/* Protocol values */ +/* value 0 is reserved */ +#define NS_KEY_PROT_TLS 1 +#define NS_KEY_PROT_EMAIL 2 +#define NS_KEY_PROT_DNSSEC 3 +#define NS_KEY_PROT_IPSEC 4 +#define NS_KEY_PROT_ANY 255 + +/* Signatures */ +#define NS_MD5RSA_MIN_BITS 512 /* Size of a mod or exp in bits */ +#define NS_MD5RSA_MAX_BITS 2552 + /* Total of binary mod and exp */ +#define NS_MD5RSA_MAX_BYTES ((NS_MD5RSA_MAX_BITS+7/8)*2+3) + /* Max length of text sig block */ +#define NS_MD5RSA_MAX_BASE64 (((NS_MD5RSA_MAX_BYTES+2)/3)*4) +#define NS_MD5RSA_MIN_SIZE ((NS_MD5RSA_MIN_BITS+7)/8) +#define NS_MD5RSA_MAX_SIZE ((NS_MD5RSA_MAX_BITS+7)/8) + +#define NS_DSA_SIG_SIZE 41 +#define NS_DSA_MIN_SIZE 213 +#define NS_DSA_MAX_BYTES 405 + +/* Offsets into SIG record rdata to find various values */ +#define NS_SIG_TYPE 0 /* Type flags */ +#define NS_SIG_ALG 2 /* Algorithm */ +#define NS_SIG_LABELS 3 /* How many labels in name */ +#define NS_SIG_OTTL 4 /* Original TTL */ +#define NS_SIG_EXPIR 8 /* Expiration time */ +#define NS_SIG_SIGNED 12 /* Signature time */ +#define NS_SIG_FOOT 16 /* Key footprint */ +#define NS_SIG_SIGNER 18 /* Domain name of who signed it */ + +/* How RR types are represented as bit-flags in NXT records */ +#define NS_NXT_BITS 8 +#define NS_NXT_BIT_SET( n,p) (p[(n)/NS_NXT_BITS] |= (0x80>>((n)%NS_NXT_BITS))) +#define NS_NXT_BIT_CLEAR(n,p) (p[(n)/NS_NXT_BITS] &= ~(0x80>>((n)%NS_NXT_BITS))) +#define NS_NXT_BIT_ISSET(n,p) (p[(n)/NS_NXT_BITS] & (0x80>>((n)%NS_NXT_BITS))) +#define NS_NXT_MAX 127 + +/* + * Inline versions of get/put short/long. Pointer is advanced. + */ +#define NS_GET16(s, cp) do { \ + register u_int8_t *t_cp = (u_int8_t *)(cp); \ + (s) = ((u_int16_t)t_cp[0] << 8) \ + | ((u_int16_t)t_cp[1]) \ + ; \ + (cp) += NS_INT16SZ; \ +} while (0) + +#define NS_GET32(l, cp) do { \ + register u_int8_t *t_cp = (u_int8_t *)(cp); \ + (l) = ((u_int32_t)t_cp[0] << 24) \ + | ((u_int32_t)t_cp[1] << 16) \ + | ((u_int32_t)t_cp[2] << 8) \ + | ((u_int32_t)t_cp[3]) \ + ; \ + (cp) += NS_INT32SZ; \ +} while (0) + +#define NS_PUT16(s, cp) do { \ + register u_int16_t t_s = (u_int16_t)(s); \ + register u_int8_t *t_cp = (u_int8_t *)(cp); \ + *t_cp++ = t_s >> 8; \ + *t_cp = t_s; \ + (cp) += NS_INT16SZ; \ +} while (0) + +#define NS_PUT32(l, cp) do { \ + register u_int32_t t_l = (u_int32_t)(l); \ + register u_int8_t *t_cp = (u_int8_t *)(cp); \ + *t_cp++ = t_l >> 24; \ + *t_cp++ = t_l >> 16; \ + *t_cp++ = t_l >> 8; \ + *t_cp = t_l; \ + (cp) += NS_INT32SZ; \ +} while (0) + +#include <arpa/nameser_compat.h> -#endif /* !_NAMESER_H_ */ +#endif /* !_ARPA_NAMESER_H_ */ diff --git a/contrib/isc-dhcp/includes/arpa/nameser_compat.h b/contrib/isc-dhcp/includes/arpa/nameser_compat.h new file mode 100644 index 0000000..3ae17f0 --- /dev/null +++ b/contrib/isc-dhcp/includes/arpa/nameser_compat.h @@ -0,0 +1,183 @@ +/* Copyright (c) 1983, 1989 + * 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 the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * from nameser.h 8.1 (Berkeley) 6/2/93 + * $Id: nameser_compat.h,v 1.2 2000/01/27 23:28:08 mellon Exp $ + */ + +#ifndef _ARPA_NAMESER_COMPAT_ +#define _ARPA_NAMESER_COMPAT_ + +/* + * Structure for query header. The order of the fields is machine- and + * compiler-dependent, depending on the byte/bit order and the layout + * of bit fields. We use bit fields only in int variables, as this + * is all ANSI requires. This requires a somewhat confusing rearrangement. + */ + +typedef struct { + unsigned id :16; /* query identification number */ +#if BYTE_ORDER == BIG_ENDIAN + /* fields in third byte */ + unsigned qr: 1; /* response flag */ + unsigned opcode: 4; /* purpose of message */ + unsigned aa: 1; /* authoritive answer */ + unsigned tc: 1; /* truncated message */ + unsigned rd: 1; /* recursion desired */ + /* fields in fourth byte */ + unsigned ra: 1; /* recursion available */ + unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */ + unsigned ad: 1; /* authentic data from named */ + unsigned cd: 1; /* checking disabled by resolver */ + unsigned rcode :4; /* response code */ +#endif +#if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN + /* fields in third byte */ + unsigned rd :1; /* recursion desired */ + unsigned tc :1; /* truncated message */ + unsigned aa :1; /* authoritive answer */ + unsigned opcode :4; /* purpose of message */ + unsigned qr :1; /* response flag */ + /* fields in fourth byte */ + unsigned rcode :4; /* response code */ + unsigned cd: 1; /* checking disabled by resolver */ + unsigned ad: 1; /* authentic data from named */ + unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */ + unsigned ra :1; /* recursion available */ +#endif + /* remaining bytes */ + unsigned qdcount :16; /* number of question entries */ + unsigned ancount :16; /* number of answer entries */ + unsigned nscount :16; /* number of authority entries */ + unsigned arcount :16; /* number of resource entries */ +} HEADER; + +#define PACKETSZ NS_PACKETSZ +#define MAXDNAME NS_MAXDNAME +#define MAXCDNAME NS_MAXCDNAME +#define MAXLABEL NS_MAXLABEL +#define HFIXEDSZ NS_HFIXEDSZ +#define QFIXEDSZ NS_QFIXEDSZ +#define RRFIXEDSZ NS_RRFIXEDSZ +#define INT32SZ NS_INT32SZ +#define INT16SZ NS_INT16SZ +#define INADDRSZ NS_INADDRSZ +#define IN6ADDRSZ NS_IN6ADDRSZ +#define INDIR_MASK NS_CMPRSFLGS +#define NAMESERVER_PORT NS_DEFAULTPORT + +#define S_ZONE ns_s_zn +#define S_PREREQ ns_s_pr +#define S_UPDATE ns_s_ud +#define S_ADDT ns_s_ar + +#define QUERY ns_o_query +#define IQUERY ns_o_iquery +#define STATUS ns_o_status +#define NS_NOTIFY_OP ns_o_notify +#define NS_UPDATE_OP ns_o_update + +#define NOERROR ns_r_noerror +#define FORMERR ns_r_formerr +#define SERVFAIL ns_r_servfail +#define NXDOMAIN ns_r_nxdomain +#define NOTIMP ns_r_notimpl +#define REFUSED ns_r_refused +#define YXDOMAIN ns_r_yxdomain +#define YXRRSET ns_r_yxrrset +#define NXRRSET ns_r_nxrrset +#define NOTAUTH ns_r_notauth +#define NOTZONE ns_r_notzone +/*#define BADSIG ns_r_badsig*/ +/*#define BADKEY ns_r_badkey*/ +/*#define BADTIME ns_r_badtime*/ + + +#define DELETE ns_uop_delete +#define ADD ns_uop_add + +#define T_A ns_t_a +#define T_NS ns_t_ns +#define T_MD ns_t_md +#define T_MF ns_t_mf +#define T_CNAME ns_t_cname +#define T_SOA ns_t_soa +#define T_MB ns_t_mb +#define T_MG ns_t_mg +#define T_MR ns_t_mr +#define T_NULL ns_t_null +#define T_WKS ns_t_wks +#define T_PTR ns_t_ptr +#define T_HINFO ns_t_hinfo +#define T_MINFO ns_t_minfo +#define T_MX ns_t_mx +#define T_TXT ns_t_txt +#define T_RP ns_t_rp +#define T_AFSDB ns_t_afsdb +#define T_X25 ns_t_x25 +#define T_ISDN ns_t_isdn +#define T_RT ns_t_rt +#define T_NSAP ns_t_nsap +#define T_NSAP_PTR ns_t_nsap_ptr +#define T_SIG ns_t_sig +#define T_KEY ns_t_key +#define T_PX ns_t_px +#define T_GPOS ns_t_gpos +#define T_AAAA ns_t_aaaa +#define T_LOC ns_t_loc +#define T_NXT ns_t_nxt +#define T_EID ns_t_eid +#define T_NIMLOC ns_t_nimloc +#define T_SRV ns_t_srv +#define T_ATMA ns_t_atma +#define T_NAPTR ns_t_naptr +#define T_TSIG ns_t_tsig +#define T_IXFR ns_t_ixfr +#define T_AXFR ns_t_axfr +#define T_MAILB ns_t_mailb +#define T_MAILA ns_t_maila +#define T_ANY ns_t_any + +#define C_IN ns_c_in +#define C_CHAOS ns_c_chaos +#define C_HS ns_c_hs +/* BIND_UPDATE */ +#define C_NONE ns_c_none +#define C_ANY ns_c_any + +#define GETSHORT NS_GET16 +#define GETLONG NS_GET32 +#define PUTSHORT NS_PUT16 +#define PUTLONG NS_PUT32 + +#endif /* _ARPA_NAMESER_COMPAT_ */ diff --git a/contrib/isc-dhcp/includes/cdefs.h b/contrib/isc-dhcp/includes/cdefs.h index 2bc67a5..4aadc0a 100644 --- a/contrib/isc-dhcp/includes/cdefs.h +++ b/contrib/isc-dhcp/includes/cdefs.h @@ -3,9 +3,9 @@ Standard C definitions... */ /* - * Copyright (c) 1996 The Internet Software Consortium. - * All Rights Reserved. * Copyright (c) 1995 RadioMail Corporation. All rights reserved. + * Copyright (c) 1996-1999 Internet Software Consortium. + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -16,23 +16,23 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of RadioMail Corporation, the Internet Software - * Consortium nor the names of its contributors may be used to endorse - * or promote products derived from this software without specific - * prior written permission. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY RADIOMAIL CORPORATION, THE INTERNET - * SOFTWARE CONSORTIUM AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL RADIOMAIL CORPORATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. * * This software was written for RadioMail Corporation by Ted Lemon * under a contract with Vixie Enterprises. Further modifications have @@ -40,6 +40,14 @@ * with Vixie Laboratories. */ +#if !defined (__ISC_DHCP_CDEFS_H__) +#define __ISC_DHCP_CDEFS_H__ +/* Delete attributes if not gcc or not the right version of gcc. */ +#if !defined(__GNUC__) || __GNUC__ < 2 || \ + (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || defined (darwin) +#define __attribute__(x) +#endif + #if (defined (__GNUC__) || defined (__STDC__)) && !defined (BROKEN_ANSI) #define PROTO(x) x #define KandR(x) @@ -55,3 +63,4 @@ #define ANSI_DECL(x) #define INLINE #endif /* __GNUC__ || __STDC__ */ +#endif /* __ISC_DHCP_CDEFS_H__ */ diff --git a/contrib/isc-dhcp/includes/cf/freebsd.h b/contrib/isc-dhcp/includes/cf/freebsd.h index 032d52c..590d0e8 100644 --- a/contrib/isc-dhcp/includes/cf/freebsd.h +++ b/contrib/isc-dhcp/includes/cf/freebsd.h @@ -3,7 +3,7 @@ System dependencies for FreeBSD... */ /* - * Copyright (c) 1996, 1998 The Internet Software Consortium. + * Copyright (c) 1996-1999 Internet Software Consortium. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -15,25 +15,30 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of The Internet Software Consortium nor the names of its - * contributors may be used to endorse or promote products derived + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND - * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE INTERNET SOFTWARE CONSORTIUM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. * - * This software was written for the Internet Software Consortium by Ted Lemon - * under a contract with Vixie Laboratories. + * This software has been written for the Internet Software Consortium + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. */ #define _ANSI_SOURCE @@ -88,6 +93,56 @@ extern int h_errno; #define HAVE_SA_LEN +/* socklen_t was first defined on November 24 in sys/socket.h, and + __FreeBSD_version was changed to 400013 on December 4, so if you + get a compile error on this, and you updated between those dates, + that's why. Also, it may be that some 3.x version after 3.4 will + have socklen_t, but no such change has been made so far. */ + +#if __FreeBSD_version < 400013 +#define SOCKLEN_T int +#endif + #if defined (USE_DEFAULT_NETWORK) # define USE_BPF #endif +#define HAVE_MKSTEMP +#ifdef NEED_PRAND_CONF +#ifndef HAVE_DEV_RANDOM + # define HAVE_DEV_RANDOM 1 + #endif /* HAVE_DEV_RANDOM */ + +const char *cmds[] = { + "/bin/ps -axlw 2>&1", + "/usr/sbin/arp -an 2>&1", + "/usr/bin/netstat -an 2>&1", + "/bin/df 2>&1", + "/usr/bin/dig com. soa +ti=1 +retry=0 2>&1", + "/usr/bin/netstat -an 2>&1", + "/usr/bin/dig . soa +ti=1 +retry=0 2>&1", + "/usr/sbin/iostat 2>&1", + "/usr/bin/vmstat 2>&1", + "/usr/bin/w 2>&1", + NULL +}; + +const char *dirs[] = { + "/tmp", + "/usr/tmp", + ".", + "/", + "/var/spool", + "/dev", + "/var/mail", + "/home", + "/usr/home", + NULL +}; + +const char *files[] = { + "/var/log/messages", + "/var/log/wtmp", + "/var/log/lastlog", + NULL +}; +#endif /* NEED_PRAND_CONF */ diff --git a/contrib/isc-dhcp/includes/ctrace.h b/contrib/isc-dhcp/includes/ctrace.h new file mode 100644 index 0000000..a0a7ef8 --- /dev/null +++ b/contrib/isc-dhcp/includes/ctrace.h @@ -0,0 +1,86 @@ +/* trace.h + + Definitions for dhcp tracing facility... */ + +/* + * Copyright (c) 2001 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon, as part of a project for Nominum, Inc. To learn more + * about the Internet Software Consortium, see http://www.isc.org/. To + * learn more about Nominum, Inc., see ``http://www.nominum.com''. + */ + +typedef struct { + struct in_addr primary_address; + u_int32_t index; + struct hardware hw_address; + char name [IFNAMSIZ]; +} trace_interface_packet_t; + +typedef struct { + u_int32_t index; + struct iaddr from; + u_int16_t from_port; + struct hardware hfrom; + u_int8_t havehfrom; +} trace_inpacket_t; + +typedef struct { + u_int32_t index; + struct iaddr from; + struct iaddr to; + u_int16_t to_port; + struct hardware hto; + u_int8_t havehto; +} trace_outpacket_t; + +void trace_interface_register (trace_type_t *, struct interface_info *); +void trace_interface_input (trace_type_t *, unsigned, char *); +void trace_interface_stop (trace_type_t *); +void trace_inpacket_stash (struct interface_info *, + struct dhcp_packet *, unsigned, unsigned int, + struct iaddr, struct hardware *); +void trace_inpacket_input (trace_type_t *, unsigned, char *); +void trace_inpacket_stop (trace_type_t *); +void trace_outpacket_input (trace_type_t *, unsigned, char *); +void trace_outpacket_stop (trace_type_t *); +ssize_t trace_packet_send (struct interface_info *, + struct packet *, struct dhcp_packet *, size_t, + struct in_addr, + struct sockaddr_in *, struct hardware *); +void trace_icmp_input_input (trace_type_t *, unsigned, char *); +void trace_icmp_input_stop (trace_type_t *); +void trace_icmp_output_input (trace_type_t *, unsigned, char *); +void trace_icmp_output_stop (trace_type_t *); +void trace_seed_stash (trace_type_t *, unsigned); +void trace_seed_input (trace_type_t *, unsigned, char *); +void trace_seed_stop (trace_type_t *); diff --git a/contrib/isc-dhcp/includes/dhcp.h b/contrib/isc-dhcp/includes/dhcp.h index b96ec3d..9b6683a 100644 --- a/contrib/isc-dhcp/includes/dhcp.h +++ b/contrib/isc-dhcp/includes/dhcp.h @@ -3,7 +3,7 @@ Protocol structures... */ /* - * Copyright (c) 1995, 1996 The Internet Software Consortium. + * Copyright (c) 1995-2001 The Internet Software Consortium. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,10 +34,9 @@ * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium - * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie - * Enterprises. To learn more about the Internet Software Consortium, - * see ``http://www.vix.com/isc''. To learn more about Vixie - * Enterprises, see ``http://www.vix.com''. + * by Ted Lemon in cooperation with Vixie Enterprises. To learn more + * about the Internet Software Consortium, see ``http://www.isc.org''. + * To learn more about Vixie Enterprises, see ``http://www.vix.com''. */ #define DHCP_UDP_OVERHEAD (14 + /* Ethernet header */ \ @@ -55,22 +54,22 @@ #define DHCP_MIN_LEN 548 struct dhcp_packet { - u_int8_t op; /* Message opcode/type */ - u_int8_t htype; /* Hardware addr type (see net/if_types.h) */ - u_int8_t hlen; /* Hardware addr length */ - u_int8_t hops; /* Number of relay agent hops from client */ - u_int32_t xid; /* Transaction ID */ - u_int16_t secs; /* Seconds since client started looking */ - u_int16_t flags; /* Flag bits */ - struct in_addr ciaddr; /* Client IP address (if already in use) */ - struct in_addr yiaddr; /* Client IP address */ - struct in_addr siaddr; /* IP address of next server to talk to */ - struct in_addr giaddr; /* DHCP relay agent IP address */ - unsigned char chaddr [16]; /* Client hardware address */ - char sname [DHCP_SNAME_LEN]; /* Server name */ - char file [DHCP_FILE_LEN]; /* Boot filename */ + u_int8_t op; /* 0: Message opcode/type */ + u_int8_t htype; /* 1: Hardware addr type (net/if_types.h) */ + u_int8_t hlen; /* 2: Hardware addr length */ + u_int8_t hops; /* 3: Number of relay agent hops from client */ + u_int32_t xid; /* 4: Transaction ID */ + u_int16_t secs; /* 8: Seconds since client started looking */ + u_int16_t flags; /* 10: Flag bits */ + struct in_addr ciaddr; /* 12: Client IP address (if already in use) */ + struct in_addr yiaddr; /* 16: Client IP address */ + struct in_addr siaddr; /* 18: IP address of next server to talk to */ + struct in_addr giaddr; /* 20: DHCP relay agent IP address */ + unsigned char chaddr [16]; /* 24: Client hardware address */ + char sname [DHCP_SNAME_LEN]; /* 40: Server name */ + char file [DHCP_FILE_LEN]; /* 104: Boot filename */ unsigned char options [DHCP_OPTION_LEN]; - /* Optional parameters + /* 212: Optional parameters (actual length dependent on MTU). */ }; @@ -152,9 +151,21 @@ struct dhcp_packet { #define DHO_DHCP_MAX_MESSAGE_SIZE 57 #define DHO_DHCP_RENEWAL_TIME 58 #define DHO_DHCP_REBINDING_TIME 59 -#define DHO_DHCP_CLASS_IDENTIFIER 60 +#define DHO_VENDOR_CLASS_IDENTIFIER 60 #define DHO_DHCP_CLIENT_IDENTIFIER 61 -#define DHO_DHCP_USER_CLASS_ID 77 +#define DHO_NWIP_DOMAIN_NAME 62 +#define DHO_NWIP_SUBOPTIONS 63 +#define DHO_USER_CLASS 77 +#define DHO_FQDN 81 +#define DHO_DHCP_AGENT_OPTIONS 82 +#define DHO_SUBNET_SELECTION 118 /* RFC3011! */ +/* The DHO_AUTHENTICATE option is not a standard yet, so I've + allocated an option out of the "local" option space for it on a + temporary basis. Once an option code number is assigned, I will + immediately and shamelessly break this, so don't count on it + continuing to work. */ +#define DHO_AUTHENTICATE 210 + #define DHO_END 255 /* DHCP message types. */ @@ -166,3 +177,19 @@ struct dhcp_packet { #define DHCPNAK 6 #define DHCPRELEASE 7 #define DHCPINFORM 8 + +/* Relay Agent Information option subtypes: */ +#define RAI_CIRCUIT_ID 1 +#define RAI_REMOTE_ID 2 +#define RAI_AGENT_ID 3 + +/* FQDN suboptions: */ +#define FQDN_NO_CLIENT_UPDATE 1 +#define FQDN_SERVER_UPDATE 2 +#define FQDN_ENCODED 3 +#define FQDN_RCODE1 4 +#define FQDN_RCODE2 5 +#define FQDN_HOSTNAME 6 +#define FQDN_DOMAINNAME 7 +#define FQDN_FQDN 8 +#define FQDN_SUBOPTION_COUNT 8 diff --git a/contrib/isc-dhcp/includes/dhcpd.h b/contrib/isc-dhcp/includes/dhcpd.h index d46ddf1..dc76d0e 100644 --- a/contrib/isc-dhcp/includes/dhcpd.h +++ b/contrib/isc-dhcp/includes/dhcpd.h @@ -3,8 +3,8 @@ Definitions for dhcpd... */ /* - * Copyright (c) 1995, 1996, 1997, 1998, 1999 - * The Internet Software Consortium. All rights reserved. + * Copyright (c) 1996-2001 Internet Software Consortium. + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -34,10 +34,11 @@ * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium - * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie - * Enterprises. To learn more about the Internet Software Consortium, - * see ``http://www.vix.com/isc''. To learn more about Vixie - * Enterprises, see ``http://www.vix.com''. + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. */ #ifndef __CYGWIN32__ @@ -46,6 +47,7 @@ #include <sys/socket.h> #include <sys/un.h> #include <arpa/inet.h> + #include <netdb.h> #else #define fd_set cygwin_fd_set @@ -62,17 +64,94 @@ #include "cdefs.h" #include "osdep.h" + +#include "arpa/nameser.h" +#if defined (NSUPDATE) +# include "minires/minires.h" +#endif + +struct hash_table; +typedef struct hash_table group_hash_t; +typedef struct hash_table universe_hash_t; +typedef struct hash_table option_hash_t; +typedef struct hash_table dns_zone_hash_t; +typedef struct hash_table lease_hash_t; +typedef struct hash_table host_hash_t; +typedef struct hash_table class_hash_t; + #include "dhcp.h" +#include "statement.h" #include "tree.h" -#include "hash.h" #include "inet.h" -#include "sysconf.h" +#include "dhctoken.h" + +#include <isc-dhcp/result.h> +#include <omapip/omapip_p.h> -struct option_data { - int len; +#if !defined (OPTION_HASH_SIZE) +# define OPTION_HASH_SIZE 17 +# define OPTION_HASH_PTWO 32 /* Next power of two above option hash. */ +# define OPTION_HASH_EXP 5 /* The exponent for that power of two. */ +#endif + +#define compute_option_hash(x) \ + (((x) & (OPTION_HASH_PTWO - 1)) + \ + (((x) >> OPTION_HASH_EXP) & \ + (OPTION_HASH_PTWO - 1))) % OPTION_HASH_SIZE; + +enum dhcp_shutdown_state { + shutdown_listeners, + shutdown_omapi_connections, + shutdown_drop_omapi_connections, + shutdown_dhcp, + shutdown_done +}; + +/* Client FQDN option, failover FQDN option, etc. */ +typedef struct { + u_int8_t codes [2]; + unsigned length; u_int8_t *data; +} ddns_fqdn_t; + +#include "failover.h" + +/* A parsing context. */ + +struct parse { + int lexline; + int lexchar; + char *token_line; + char *prev_line; + char *cur_line; + const char *tlname; + int eol_token; + + char line1 [81]; + char line2 [81]; + int lpos; + int line; + int tlpos; + int tline; + enum dhcp_token token; + int ugflag; + char *tval; + int tlen; + char tokbuf [1500]; + +#ifdef OLD_LEXER + char comments [4096]; + int comment_index; +#endif + int warnings_occurred; + int file; + char *inbuf; + unsigned bufix, buflen; + unsigned bufsiz; }; +/* Variable-length array of data. */ + struct string_list { struct string_list *next; char string [1]; @@ -92,10 +171,46 @@ struct domain_search_list { TIME rcdate; }; +/* Option tag structures are used to build chains of option tags, for + when we're sure we're not going to have enough of them to justify + maintaining an array. */ + +struct option_tag { + struct option_tag *next; + u_int8_t data [1]; +}; + +/* An agent option structure. We need a special structure for the + Relay Agent Information option because if more than one appears in + a message, we have to keep them seperate. */ + +struct agent_options { + struct agent_options *next; + int length; + struct option_tag *first; +}; + +struct option_cache { + int refcnt; + struct option_cache *next; + struct expression *expression; + struct option *option; + struct data_string data; +}; + +struct option_state { + int refcnt; + int universe_count; + int site_universe; + int site_code_min; + VOIDPTR universes [1]; +}; + /* A dhcp packet and the pointers to its option values. */ struct packet { struct dhcp_packet *raw; - int packet_length; + int refcnt; + unsigned packet_length; int packet_type; int options_valid; int client_port; @@ -104,48 +219,108 @@ struct packet { was received. */ struct hardware *haddr; /* Physical link address of local sender (maybe gateway). */ - struct shared_network *shared_network; - struct option_data options [256]; + + /* Information for relay agent options (see + draft-ietf-dhc-agent-options-xx.txt). */ + u_int8_t *circuit_id; /* Circuit ID of client connection. */ + int circuit_id_len; + u_int8_t *remote_id; /* Remote ID of client. */ + int remote_id_len; + int got_requested_address; /* True if client sent the dhcp-requested-address option. */ + + struct shared_network *shared_network; + struct option_state *options; + +#if !defined (PACKET_MAX_CLASSES) +# define PACKET_MAX_CLASSES 5 +#endif + int class_count; + struct class *classes [PACKET_MAX_CLASSES]; + + int known; + int authenticated; }; +/* A network interface's MAC address. */ + struct hardware { - u_int8_t htype; u_int8_t hlen; - u_int8_t haddr [16]; + u_int8_t hbuf [17]; }; +typedef enum { + server_startup = 0, + server_running = 1, + server_shutdown = 2, + server_hibernate = 3, + server_awaken = 4 +} control_object_state_t; + +typedef struct { + OMAPI_OBJECT_PREAMBLE; + control_object_state_t state; +} dhcp_control_object_t; + +/* Lease states: */ +typedef enum { + FTS_FREE = 1, + FTS_ACTIVE = 2, + FTS_EXPIRED = 3, + FTS_RELEASED = 4, + FTS_ABANDONED = 5, + FTS_RESET = 6, + FTS_BACKUP = 7, + FTS_RESERVED = 8, + FTS_BOOTP = 9 +} binding_state_t; + /* A dhcp lease declaration structure. */ struct lease { + OMAPI_OBJECT_PREAMBLE; struct lease *next; - struct lease *prev; struct lease *n_uid, *n_hw; - struct lease *waitq_next; struct iaddr ip_addr; - TIME starts, ends, timestamp; - unsigned char *uid; - int uid_len; - int uid_max; - unsigned char uid_buf [32]; - char *hostname; + TIME starts, ends, timestamp, sort_time; char *client_hostname; + struct binding_scope *scope; struct host_decl *host; struct subnet *subnet; - struct shared_network *shared_network; + struct pool *pool; + struct class *billing_class; + struct option_chain_head *agent_options; + + struct executable_statement *on_expiry; + struct executable_statement *on_commit; + struct executable_statement *on_release; + + unsigned char *uid; + unsigned short uid_len; + unsigned short uid_max; + unsigned char uid_buf [7]; struct hardware hardware_addr; - int flags; + u_int8_t flags; # define STATIC_LEASE 1 -# define BOOTP_LEASE 2 -# define DYNAMIC_BOOTP_OK 4 -# define PERSISTENT_FLAGS (DYNAMIC_BOOTP_OK) -# define EPHEMERAL_FLAGS (BOOTP_LEASE) +# define PERSISTENT_FLAGS (ON_ACK_QUEUE | ON_UPDATE_QUEUE) # define MS_NULL_TERMINATION 8 -# define ABANDONED_LEASE 16 - +# define ON_UPDATE_QUEUE 16 +# define ON_ACK_QUEUE 32 +# define UNICAST_BROADCAST_HACK 64 +# define EPHEMERAL_FLAGS (MS_NULL_TERMINATION | \ + UNICAST_BROADCAST_HACK) + + binding_state_t __attribute__ ((mode (__byte__))) binding_state; + binding_state_t __attribute__ ((mode (__byte__))) next_binding_state; + struct lease_state *state; + + TIME tstp; /* Time sent to partner. */ + TIME tsfp; /* Time sent from partner. */ + TIME cltt; /* Client last transaction time. */ + struct lease *next_pending; }; struct lease_state { @@ -153,22 +328,17 @@ struct lease_state { struct interface_info *ip; - TIME offered_expiry; - - struct tree_cache *options [256]; - u_int32_t expiry, renewal, rebind; - char filename [DHCP_FILE_LEN]; - char *server_name; + struct packet *packet; /* The incoming packet. */ - struct iaddr from; + TIME offered_expiry; + struct option_state *options; + struct data_string parameter_request_list; int max_message_size; - u_int8_t *prl; - int prl_len; - int got_requested_address; /* True if client sent the - dhcp-requested-address option. */ - int got_server_identifier; /* True if client sent the - dhcp-server-identifier option. */ + u_int32_t expiry, renewal, rebind; + struct data_string filename, server_name; + int got_requested_address; + int got_server_identifier; struct shared_network *shared_network; /* Shared network of interface on which request arrived. */ @@ -176,9 +346,11 @@ struct lease_state { u_int16_t secs; u_int16_t bootp_flags; struct in_addr ciaddr; + struct in_addr siaddr; struct in_addr giaddr; u_int8_t hops; u_int8_t offer; + struct iaddr from; }; #define ROOT_GROUP 0 @@ -187,6 +359,7 @@ struct lease_state { #define SUBNET_DECL 3 #define CLASS_DECL 4 #define GROUP_DECL 5 +#define POOL_DECL 6 /* Possible modes in which discover_interfaces can run. */ @@ -196,58 +369,217 @@ struct lease_state { #define DISCOVER_RELAY 3 #define DISCOVER_REQUESTED 4 +/* Server option names. */ + +#define SV_DEFAULT_LEASE_TIME 1 +#define SV_MAX_LEASE_TIME 2 +#define SV_MIN_LEASE_TIME 3 +#define SV_BOOTP_LEASE_CUTOFF 4 +#define SV_BOOTP_LEASE_LENGTH 5 +#define SV_BOOT_UNKNOWN_CLIENTS 6 +#define SV_DYNAMIC_BOOTP 7 +#define SV_ALLOW_BOOTP 8 +#define SV_ALLOW_BOOTING 9 +#define SV_ONE_LEASE_PER_CLIENT 10 +#define SV_GET_LEASE_HOSTNAMES 11 +#define SV_USE_HOST_DECL_NAMES 12 +#define SV_USE_LEASE_ADDR_FOR_DEFAULT_ROUTE 13 +#define SV_MIN_SECS 14 +#define SV_FILENAME 15 +#define SV_SERVER_NAME 16 +#define SV_NEXT_SERVER 17 +#define SV_AUTHORITATIVE 18 +#define SV_VENDOR_OPTION_SPACE 19 +#define SV_ALWAYS_REPLY_RFC1048 20 +#define SV_SITE_OPTION_SPACE 21 +#define SV_ALWAYS_BROADCAST 22 +#define SV_DDNS_DOMAIN_NAME 23 +#define SV_DDNS_HOST_NAME 24 +#define SV_DDNS_REV_DOMAIN_NAME 25 +#define SV_LEASE_FILE_NAME 26 +#define SV_PID_FILE_NAME 27 +#define SV_DUPLICATES 28 +#define SV_DECLINES 29 +#define SV_DDNS_UPDATES 30 +#define SV_OMAPI_PORT 31 +#define SV_LOCAL_PORT 32 +#define SV_LIMITED_BROADCAST_ADDRESS 33 +#define SV_REMOTE_PORT 34 +#define SV_LOCAL_ADDRESS 35 +#define SV_OMAPI_KEY 36 +#define SV_STASH_AGENT_OPTIONS 37 +#define SV_DDNS_TTL 38 +#define SV_DDNS_UPDATE_STYLE 39 +#define SV_CLIENT_UPDATES 40 +#define SV_UPDATE_OPTIMIZATION 41 +#define SV_PING_CHECKS 42 +#define SV_UPDATE_STATIC_LEASES 43 +#define SV_LOG_FACILITY 44 + +#if !defined (DEFAULT_DEFAULT_LEASE_TIME) +# define DEFAULT_DEFAULT_LEASE_TIME 43200 +#endif + +#if !defined (DEFAULT_MIN_LEASE_TIME) +# define DEFAULT_MIN_LEASE_TIME 0 +#endif + +#if !defined (DEFAULT_MAX_LEASE_TIME) +# define DEFAULT_MAX_LEASE_TIME 86400 +#endif + +#if !defined (DEFAULT_DDNS_TTL) +# define DEFAULT_DDNS_TTL 3600 +#endif + +/* Client option names */ + +#define CL_TIMEOUT 1 +#define CL_SELECT_INTERVAL 2 +#define CL_REBOOT_TIMEOUT 3 +#define CL_RETRY_INTERVAL 4 +#define CL_BACKOFF_CUTOFF 5 +#define CL_INITIAL_INTERVAL 6 +#define CL_BOOTP_POLICY 7 +#define CL_SCRIPT_NAME 8 +#define CL_REQUESTED_OPTIONS 9 +#define CL_REQUESTED_LEASE_TIME 10 +#define CL_SEND_OPTIONS 11 +#define CL_MEDIA 12 +#define CL_REJECT_LIST 13 + +#ifndef CL_DEFAULT_TIMEOUT +# define CL_DEFAULT_TIMEOUT 60 +#endif + +#ifndef CL_DEFAULT_SELECT_INTERVAL +# define CL_DEFAULT_SELECT_INTERVAL 0 +#endif + +#ifndef CL_DEFAULT_REBOOT_TIMEOUT +# define CL_DEFAULT_REBOOT_TIMEOUT 10 +#endif + +#ifndef CL_DEFAULT_RETRY_INTERVAL +# define CL_DEFAULT_RETRY_INTERVAL 300 +#endif + +#ifndef CL_DEFAULT_BACKOFF_CUTOFF +# define CL_DEFAULT_BACKOFF_CUTOFF 120 +#endif + +#ifndef CL_DEFAULT_INITIAL_INTERVAL +# define CL_DEFAULT_INITIAL_INTERVAL 10 +#endif + +#ifndef CL_DEFAULT_BOOTP_POLICY +# define CL_DEFAULT_BOOTP_POLICY P_ACCEPT +#endif + +#ifndef CL_DEFAULT_REQUESTED_OPTIONS +# define CL_DEFAULT_REQUESTED_OPTIONS \ + { DHO_SUBNET_MASK, \ + DHO_BROADCAST_ADDRESS, \ + DHO_TIME_OFFSET, \ + DHO_ROUTERS, \ + DHO_DOMAIN_NAME, \ + DHO_DOMAIN_NAME_SERVERS, \ + DHO_HOST_NAME } +#endif + +struct group_object { + OMAPI_OBJECT_PREAMBLE; + + struct group_object *n_dynamic; + struct group *group; + char *name; + int flags; +#define GROUP_OBJECT_DELETED 1 +#define GROUP_OBJECT_DYNAMIC 2 +#define GROUP_OBJECT_STATIC 4 +}; + /* Group of declarations that share common parameters. */ struct group { struct group *next; + int refcnt; + struct group_object *object; struct subnet *subnet; struct shared_network *shared_network; - - TIME default_lease_time; - TIME max_lease_time; - TIME bootp_lease_cutoff; - TIME bootp_lease_length; - - char *filename; - char *server_name; - struct iaddr next_server; - - int boot_unknown_clients; - int dynamic_bootp; - int allow_bootp; - int allow_booting; - int one_lease_per_client; - int get_lease_hostnames; - int use_host_decl_names; - int use_lease_addr_for_default_route; int authoritative; - int always_reply_rfc1048; - - struct tree_cache *options [256]; + struct executable_statement *statements; }; /* A dhcp host declaration structure. */ struct host_decl { + OMAPI_OBJECT_PREAMBLE; struct host_decl *n_ipaddr; + struct host_decl *n_dynamic; char *name; struct hardware interface; - struct tree_cache *fixed_addr; + struct data_string client_identifier; + struct option_cache *fixed_addr; struct group *group; + struct group_object *named_group; + struct data_string auth_key_id; + int flags; +#define HOST_DECL_DELETED 1 +#define HOST_DECL_DYNAMIC 2 +#define HOST_DECL_STATIC 4 +}; + +struct permit { + struct permit *next; + enum { + permit_unknown_clients, + permit_known_clients, + permit_authenticated_clients, + permit_unauthenticated_clients, + permit_all_clients, + permit_dynamic_bootp_clients, + permit_class + } type; + struct class *class; +}; + +struct pool { + OMAPI_OBJECT_PREAMBLE; + struct pool *next; + struct group *group; + struct shared_network *shared_network; + struct permit *permit_list; + struct permit *prohibit_list; + struct lease *active; + struct lease *expired; + struct lease *free; + struct lease *backup; + struct lease *abandoned; + TIME next_event_time; + int lease_count; + int free_leases; + int backup_leases; + int index; +#if defined (FAILOVER_PROTOCOL) + dhcp_failover_state_t *failover_peer; +#endif }; struct shared_network { + OMAPI_OBJECT_PREAMBLE; struct shared_network *next; char *name; struct subnet *subnets; struct interface_info *interface; - struct lease *leases; - struct lease *insertion_point; - struct lease *last_lease; - + struct pool *pools; struct group *group; +#if defined (FAILOVER_PROTOCOL) + dhcp_failover_state_t *failover_peer; +#endif }; struct subnet { + OMAPI_OBJECT_PREAMBLE; struct subnet *next_subnet; struct subnet *next_sibling; struct shared_network *shared_network; @@ -259,10 +591,45 @@ struct subnet { struct group *group; }; -struct class { - char *name; +struct collection { + struct collection *next; + + const char *name; + struct class *classes; +}; +/* XXX classes must be reference-counted. */ +struct class { + OMAPI_OBJECT_PREAMBLE; + struct class *nic; /* Next in collection. */ + struct class *superclass; /* Set for spawned classes only. */ + char *name; /* Not set for spawned classes. */ + + /* A class may be configured to permit a limited number of leases. */ + int lease_limit; + int leases_consumed; + struct lease **billed_leases; + + /* If nonzero, class has not been saved since it was last + modified. */ + int dirty; + + /* Hash table containing subclasses. */ + class_hash_t *hash; + struct data_string hash_string; + + /* Expression used to match class. */ + struct expression *expr; + + /* Expression used to compute subclass identifiers for spawning + and to do subclass matching. */ + struct expression *submatch; + int spawning; + struct group *group; + + /* Statements to execute if class matches. */ + struct executable_statement *statements; }; /* DHCP client lease structure... */ @@ -273,39 +640,46 @@ struct client_lease { char *server_name; /* Name of boot server. */ char *filename; /* Name of file we're supposed to boot. */ struct string_list *medium; /* Network medium. */ + struct auth_key *key; /* Key used in basic DHCP authentication. */ unsigned int is_static : 1; /* If set, lease is from config file. */ unsigned int is_bootp: 1; /* If set, lease was aquired with BOOTP. */ - struct option_data options [256]; /* Options supplied with lease. */ + struct option_state *options; /* Options supplied with lease. */ }; /* Possible states in which the client can be. */ enum dhcp_state { - S_REBOOTING, - S_INIT, - S_SELECTING, - S_REQUESTING, - S_BOUND, - S_RENEWING, - S_REBINDING + S_REBOOTING = 1, + S_INIT = 2, + S_SELECTING = 3, + S_REQUESTING = 4, + S_BOUND = 5, + S_RENEWING = 6, + S_REBINDING = 7, + S_STOPPED = 8 }; +/* Authentication and BOOTP policy possibilities (not all values work + for each). */ +enum policy { P_IGNORE, P_ACCEPT, P_PREFER, P_REQUIRE, P_DONT }; + /* Configuration information from the config file... */ struct client_config { - struct option_data defaults [256]; /* Default values for options. */ - enum { - ACTION_DEFAULT, /* Use server value if present, - otherwise default. */ - ACTION_SUPERSEDE, /* Always use default. */ - ACTION_PREPEND, /* Prepend default to server. */ - ACTION_APPEND, /* Append default to server. */ - } default_actions [256]; - - struct option_data send_options [256]; /* Send these to server. */ - u_int8_t required_options [256]; /* Options server must supply. */ - u_int8_t requested_options [256]; /* Options to request from server. */ - int requested_option_count; /* Number of requested options. */ + /* + * When a message has been received, run these statements + * over it. + */ + struct group *on_receipt; + + /* + * When a message is sent, run these statements. + */ + struct group *on_transmission; + + u_int32_t *required_options; /* Options server must supply. */ + u_int32_t *requested_options; /* Options to request from server. */ + TIME timeout; /* Start to panic if we don't get a lease in this time period when SELECTING. */ @@ -324,18 +698,33 @@ struct client_config { TIME backoff_cutoff; /* When doing exponential backoff, never back off to an interval longer than this amount. */ + u_int32_t requested_lease; /* Requested lease time, if user + doesn't configure one. */ struct string_list *media; /* Possible network media values. */ char *script_name; /* Name of config script. */ - enum { IGNORE, ACCEPT, PREFER } bootp_policy; + char *vendor_space_name; /* Name of config script. */ + enum policy bootp_policy; /* Ignore, accept or prefer BOOTP responses. */ + enum policy auth_policy; + /* Require authentication, prefer + authentication, or don't try to + authenticate. */ struct string_list *medium; /* Current network medium. */ struct iaddrlist *reject_list; /* Servers to reject. */ + + int omapi_port; /* port on which to accept OMAPI + connections, or -1 for no + listener. */ }; /* Per-interface state used in the dhcp client... */ struct client_state { + struct client_state *next; + struct interface_info *interface; + char *name; + struct client_lease *active; /* Currently active lease. */ struct client_lease *new; /* New lease. */ struct client_lease *offered_leases; /* Leases offered to us. */ @@ -349,27 +738,38 @@ struct client_state { TIME first_sending; /* When was first copy sent? */ TIME interval; /* What's the current resend interval? */ struct string_list *medium; /* Last media type tried. */ - struct dhcp_packet packet; /* Outgoing DHCP packet. */ - int packet_length; /* Actual length of generated packet. */ + unsigned packet_length; /* Actual length of generated packet. */ struct iaddr requested_address; /* Address we would like to get. */ - struct client_config *config; /* Information from config file. */ - + struct client_config *config; /* Client configuration. */ struct string_list *env; /* Client script environment. */ int envc; /* Number of entries in environment. */ + + struct option_state *sent_options; /* Options we sent. */ }; /* Information about each network interface. */ struct interface_info { + OMAPI_OBJECT_PREAMBLE; struct interface_info *next; /* Next interface in list... */ struct shared_network *shared_network; /* Networks connected to this interface. */ struct hardware hw_address; /* Its physical address. */ struct in_addr primary_address; /* Primary interface address. */ + + u_int8_t *circuit_id; /* Circuit ID associated with this + interface. */ + unsigned circuit_id_len; /* Length of Circuit ID, if there + is one. */ + u_int8_t *remote_id; /* Remote ID associated with this + interface (if any). */ + unsigned remote_id_len; /* Length of Remote ID. */ + char name [IFNAMSIZ]; /* Its name... */ + int index; /* Its index. */ int rfdesc; /* Its read file descriptor. */ int wfdesc; /* Its write file descriptor, if different. */ @@ -382,9 +782,14 @@ struct interface_info { u_int32_t flags; /* Control flags... */ #define INTERFACE_REQUESTED 1 #define INTERFACE_AUTOMATIC 2 +#define INTERFACE_RUNNING 4 /* Only used by DHCP client code. */ struct client_state *client; +# if defined (USE_DLPI_SEND) || defined (USE_DLPI_RECEIVE) + int dlpi_sap_length; + struct hardware dlpi_broadcast_addr; +# endif /* DLPI_SEND || DLPI_RECEIVE */ }; struct hardware_link { @@ -393,11 +798,15 @@ struct hardware_link { struct hardware address; }; +typedef void (*tvref_t)(void *, void *, const char *, int); +typedef void (*tvunref_t)(void *, const char *, int); struct timeout { struct timeout *next; TIME when; void (*func) PROTO ((void *)); void *what; + tvref_t ref; + tvunref_t unref; }; struct protocol { @@ -407,6 +816,64 @@ struct protocol { void *local; }; +struct dns_query; /* forward */ + +struct dns_wakeup { + struct dns_wakeup *next; /* Next wakeup in chain. */ + void (*func) PROTO ((struct dns_query *)); +}; + +struct dns_question { + u_int16_t type; /* Type of query. */ + u_int16_t class; /* Class of query. */ + unsigned char data [1]; /* Query data. */ +}; + +struct dns_answer { + u_int16_t type; /* Type of answer. */ + u_int16_t class; /* Class of answer. */ + int count; /* Number of answers. */ + unsigned char *answers[1]; /* Pointers to answers. */ +}; + +struct dns_query { + struct dns_query *next; /* Next query in hash bucket. */ + u_int32_t hash; /* Hash bucket index. */ + TIME expiry; /* Query expiry time (zero if not yet + answered. */ + u_int16_t id; /* Query ID (also hash table index) */ + caddr_t waiters; /* Pointer to list of things waiting + on this query. */ + + struct dns_question *question; /* Question, internal format. */ + struct dns_answer *answer; /* Answer, internal format. */ + + unsigned char *query; /* Query formatted for DNS server. */ + unsigned len; /* Length of entire query. */ + int sent; /* The query has been sent. */ + struct dns_wakeup *wakeups; /* Wakeups to call if this query is + answered. */ + struct name_server *next_server; /* Next server to try. */ + int backoff; /* Current backoff, in seconds. */ +}; + +struct dns_zone { + int refcnt; + TIME timeout; + char *name; + struct option_cache *primary; + struct option_cache *secondary; + struct auth_key *key; +}; + +struct icmp_state { + OMAPI_OBJECT_PREAMBLE; + int socket; + void (*icmp_handler) PROTO ((struct iaddr, u_int8_t *, int)); +}; + +#include "ctrace.h" + /* Bitmask of dhcp option codes. */ typedef unsigned char option_mask [16]; @@ -445,6 +912,10 @@ typedef unsigned char option_mask [16]; #define _PATH_DHCLIENT_CONF "/etc/dhclient.conf" #endif +#ifndef _PATH_DHCLIENT_SCRIPT +#define _PATH_DHCLIENT_SCRIPT "/sbin/dhclient-script" +#endif + #ifndef _PATH_DHCLIENT_PID #define _PATH_DHCLIENT_PID "/var/run/dhclient.pid" #endif @@ -470,192 +941,604 @@ typedef unsigned char option_mask [16]; /* External definitions... */ +HASH_FUNCTIONS_DECL (group, const char *, struct group_object, group_hash_t) +HASH_FUNCTIONS_DECL (universe, const char *, struct universe, universe_hash_t) +HASH_FUNCTIONS_DECL (option, const char *, struct option, option_hash_t) +HASH_FUNCTIONS_DECL (dns_zone, const char *, struct dns_zone, dns_zone_hash_t) +HASH_FUNCTIONS_DECL (lease, const unsigned char *, struct lease, lease_hash_t) +HASH_FUNCTIONS_DECL (host, const unsigned char *, struct host_decl, host_hash_t) +HASH_FUNCTIONS_DECL (class, const char *, struct class, class_hash_t) + /* options.c */ -void parse_options PROTO ((struct packet *)); -void parse_option_buffer PROTO ((struct packet *, unsigned char *, int)); -int cons_options PROTO ((struct packet *, struct dhcp_packet *, int, - struct tree_cache **, int, int, int, - u_int8_t *, int)); -int store_options PROTO ((unsigned char *, int, struct tree_cache **, - unsigned char *, int, int, int, int)); -char *pretty_print_option PROTO ((unsigned int, - unsigned char *, int, int, int)); +extern struct option *vendor_cfg_option; +int parse_options PROTO ((struct packet *)); +int parse_option_buffer PROTO ((struct option_state *, const unsigned char *, + unsigned, struct universe *)); +struct universe *find_option_universe (struct option *, const char *); +int parse_encapsulated_suboptions (struct option_state *, struct option *, + const unsigned char *, unsigned, + struct universe *, const char *); +int cons_options PROTO ((struct packet *, struct dhcp_packet *, struct lease *, + struct client_state *, + int, struct option_state *, struct option_state *, + struct binding_scope **, + int, int, int, struct data_string *, const char *)); +int fqdn_universe_decode (struct option_state *, + const unsigned char *, unsigned, struct universe *); +int store_options PROTO ((unsigned char *, unsigned, struct packet *, + struct lease *, struct client_state *, + struct option_state *, + struct option_state *, struct binding_scope **, + unsigned *, int, unsigned, unsigned, + int, const char *)); +const char *pretty_print_option PROTO ((struct option *, const unsigned char *, + unsigned, int, int)); +int get_option (struct data_string *, struct universe *, + struct packet *, struct lease *, struct client_state *, + struct option_state *, struct option_state *, + struct option_state *, struct binding_scope **, unsigned, + const char *, int); +void set_option (struct universe *, struct option_state *, + struct option_cache *, enum statement_op); +struct option_cache *lookup_option PROTO ((struct universe *, + struct option_state *, unsigned)); +struct option_cache *lookup_hashed_option PROTO ((struct universe *, + struct option_state *, + unsigned)); +int save_option_buffer (struct universe *, struct option_state *, + struct buffer *, unsigned char *, unsigned, + struct option *, int); +void save_option PROTO ((struct universe *, + struct option_state *, struct option_cache *)); +void save_hashed_option PROTO ((struct universe *, + struct option_state *, struct option_cache *)); +void delete_option PROTO ((struct universe *, struct option_state *, int)); +void delete_hashed_option PROTO ((struct universe *, + struct option_state *, int)); +int option_cache_dereference PROTO ((struct option_cache **, + const char *, int)); +int hashed_option_state_dereference PROTO ((struct universe *, + struct option_state *, + const char *, int)); +int store_option PROTO ((struct data_string *, + struct universe *, struct packet *, struct lease *, + struct client_state *, + struct option_state *, struct option_state *, + struct binding_scope **, struct option_cache *)); +int option_space_encapsulate PROTO ((struct data_string *, + struct packet *, struct lease *, + struct client_state *, + struct option_state *, + struct option_state *, + struct binding_scope **, + struct data_string *)); +int hashed_option_space_encapsulate PROTO ((struct data_string *, + struct packet *, struct lease *, + struct client_state *, + struct option_state *, + struct option_state *, + struct binding_scope **, + struct universe *)); +int nwip_option_space_encapsulate PROTO ((struct data_string *, + struct packet *, struct lease *, + struct client_state *, + struct option_state *, + struct option_state *, + struct binding_scope **, + struct universe *)); +int fqdn_option_space_encapsulate (struct data_string *, + struct packet *, struct lease *, + struct client_state *, + struct option_state *, + struct option_state *, + struct binding_scope **, + struct universe *); +void suboption_foreach (struct packet *, struct lease *, struct client_state *, + struct option_state *, struct option_state *, + struct binding_scope **, struct universe *, void *, + void (*) (struct option_cache *, struct packet *, + struct lease *, struct client_state *, + struct option_state *, struct option_state *, + struct binding_scope **, + struct universe *, void *), + struct option_cache *, const char *); +void option_space_foreach (struct packet *, struct lease *, + struct client_state *, + struct option_state *, + struct option_state *, + struct binding_scope **, + struct universe *, void *, + void (*) (struct option_cache *, + struct packet *, + struct lease *, struct client_state *, + struct option_state *, + struct option_state *, + struct binding_scope **, + struct universe *, void *)); +void hashed_option_space_foreach (struct packet *, struct lease *, + struct client_state *, + struct option_state *, + struct option_state *, + struct binding_scope **, + struct universe *, void *, + void (*) (struct option_cache *, + struct packet *, + struct lease *, + struct client_state *, + struct option_state *, + struct option_state *, + struct binding_scope **, + struct universe *, void *)); +int linked_option_get PROTO ((struct data_string *, struct universe *, + struct packet *, struct lease *, + struct client_state *, + struct option_state *, struct option_state *, + struct option_state *, struct binding_scope **, + unsigned)); +int linked_option_state_dereference PROTO ((struct universe *, + struct option_state *, + const char *, int)); +void save_linked_option (struct universe *, struct option_state *, + struct option_cache *); +void linked_option_space_foreach (struct packet *, struct lease *, + struct client_state *, + struct option_state *, + struct option_state *, + struct binding_scope **, + struct universe *, void *, + void (*) (struct option_cache *, + struct packet *, + struct lease *, + struct client_state *, + struct option_state *, + struct option_state *, + struct binding_scope **, + struct universe *, void *)); +int linked_option_space_encapsulate (struct data_string *, struct packet *, + struct lease *, struct client_state *, + struct option_state *, + struct option_state *, + struct binding_scope **, + struct universe *); +void delete_linked_option (struct universe *, struct option_state *, int); +struct option_cache *lookup_linked_option (struct universe *, + struct option_state *, unsigned); void do_packet PROTO ((struct interface_info *, - struct dhcp_packet *, int, + struct dhcp_packet *, unsigned, unsigned int, struct iaddr, struct hardware *)); -/* errwarn.c */ -extern int warnings_occurred; -void error PROTO ((char *, ...)); -int warn PROTO ((char *, ...)); -int note PROTO ((char *, ...)); -int debug PROTO ((char *, ...)); -int parse_warn PROTO ((char *, ...)); - /* dhcpd.c */ extern TIME cur_time; -extern struct group root_group; -extern u_int16_t local_port; -extern u_int16_t remote_port; -extern int log_priority; -extern int log_perror; +int ddns_update_style; + +extern const char *path_dhcpd_conf; +extern const char *path_dhcpd_db; +extern const char *path_dhcpd_pid; -extern char *path_dhcpd_conf; -extern char *path_dhcpd_db; -extern char *path_dhcpd_pid; +extern int dhcp_max_agent_option_packet_length; int main PROTO ((int, char **, char **)); +void postconf_initialization (int); +void postdb_startup (void); void cleanup PROTO ((void)); void lease_pinged PROTO ((struct iaddr, u_int8_t *, int)); void lease_ping_timeout PROTO ((void *)); +int dhcpd_interface_setup_hook (struct interface_info *ip, struct iaddr *ia); +enum dhcp_shutdown_state shutdown_state; +isc_result_t dhcp_io_shutdown (omapi_object_t *, void *); +isc_result_t dhcp_set_control_state (control_object_state_t oldstate, + control_object_state_t newstate); /* conflex.c */ -extern int lexline, lexchar; -extern char *token_line, *tlname; -extern char comments [4096]; -extern int comment_index; -extern int eol_token; -void new_parse PROTO ((char *)); -int next_token PROTO ((char **, FILE *)); -int peek_token PROTO ((char **, FILE *)); +isc_result_t new_parse PROTO ((struct parse **, int, + char *, unsigned, const char *, int)); +isc_result_t end_parse PROTO ((struct parse **)); +enum dhcp_token next_token PROTO ((const char **, unsigned *, struct parse *)); +enum dhcp_token peek_token PROTO ((const char **, unsigned *, struct parse *)); /* confpars.c */ -int readconf PROTO ((void)); -void read_leases PROTO ((void)); -int parse_statement PROTO ((FILE *, +void parse_trace_setup (void); +isc_result_t readconf PROTO ((void)); +isc_result_t read_conf_file (const char *, struct group *, int, int); +#if defined (TRACING) +void trace_conf_input (trace_type_t *, unsigned, char *); +void trace_conf_stop (trace_type_t *ttype); +#endif +isc_result_t conf_file_subparse (struct parse *, struct group *, int); +isc_result_t lease_file_subparse (struct parse *); +int parse_statement PROTO ((struct parse *, struct group *, int, struct host_decl *, int)); -void parse_allow_deny PROTO ((FILE *, struct group *, int)); -void skip_to_semi PROTO ((FILE *)); -int parse_boolean PROTO ((FILE *)); -int parse_semi PROTO ((FILE *)); -int parse_lbrace PROTO ((FILE *)); -void parse_host_declaration PROTO ((FILE *, struct group *)); -char *parse_host_name PROTO ((FILE *)); -void parse_class_declaration PROTO ((FILE *, struct group *, int)); -void parse_lease_time PROTO ((FILE *, TIME *)); -void parse_shared_net_declaration PROTO ((FILE *, struct group *)); -void parse_subnet_declaration PROTO ((FILE *, struct shared_network *)); -void parse_group_declaration PROTO ((FILE *, struct group *)); -void parse_hardware_param PROTO ((FILE *, struct hardware *)); -char *parse_string PROTO ((FILE *)); -struct tree *parse_ip_addr_or_hostname PROTO ((FILE *, int)); -struct tree_cache *parse_fixed_addr_param PROTO ((FILE *)); -void parse_option_param PROTO ((FILE *, struct group *)); -TIME parse_timestamp PROTO ((FILE *)); -struct lease *parse_lease_declaration PROTO ((FILE *)); -void parse_address_range PROTO ((FILE *, struct subnet *)); -TIME parse_date PROTO ((FILE *)); -unsigned char *parse_numeric_aggregate PROTO ((FILE *, - unsigned char *, int *, - int, int, int)); -void convert_num PROTO ((unsigned char *, char *, int, int)); +#if defined (FAILOVER_PROTOCOL) +void parse_failover_peer PROTO ((struct parse *, struct group *, int)); +void parse_failover_state_declaration (struct parse *, + dhcp_failover_state_t *); +void parse_failover_state PROTO ((struct parse *, + enum failover_state *, TIME *)); +#endif +int permit_list_match (struct permit *, struct permit *); +void parse_pool_statement PROTO ((struct parse *, struct group *, int)); +int parse_boolean PROTO ((struct parse *)); +int parse_lbrace PROTO ((struct parse *)); +void parse_host_declaration PROTO ((struct parse *, struct group *)); +int parse_class_declaration PROTO ((struct class **, struct parse *, + struct group *, int)); +void parse_shared_net_declaration PROTO ((struct parse *, struct group *)); +void parse_subnet_declaration PROTO ((struct parse *, + struct shared_network *)); +void parse_group_declaration PROTO ((struct parse *, struct group *)); +int parse_fixed_addr_param PROTO ((struct option_cache **, struct parse *)); +TIME parse_timestamp PROTO ((struct parse *)); +int parse_lease_declaration PROTO ((struct lease **, struct parse *)); +void parse_address_range PROTO ((struct parse *, struct group *, int, + struct pool *, struct lease **)); + +/* ddns.c */ +int ddns_updates PROTO ((struct packet *, struct lease *, struct lease *, + struct lease_state *)); +int ddns_removals PROTO ((struct lease *)); + +/* parse.c */ +void add_enumeration (struct enumeration *); +struct enumeration *find_enumeration (const char *, int); +struct enumeration_value *find_enumeration_value (const char *, int, + const char *); +void skip_to_semi PROTO ((struct parse *)); +void skip_to_rbrace PROTO ((struct parse *, int)); +int parse_semi PROTO ((struct parse *)); +int parse_string PROTO ((struct parse *, char **, unsigned *)); +char *parse_host_name PROTO ((struct parse *)); +int parse_ip_addr_or_hostname PROTO ((struct expression **, + struct parse *, int)); +void parse_hardware_param PROTO ((struct parse *, struct hardware *)); +void parse_lease_time PROTO ((struct parse *, TIME *)); +unsigned char *parse_numeric_aggregate PROTO ((struct parse *, + unsigned char *, unsigned *, + int, int, unsigned)); +void convert_num PROTO ((struct parse *, unsigned char *, const char *, + int, unsigned)); +TIME parse_date PROTO ((struct parse *)); +struct option *parse_option_name PROTO ((struct parse *, int, int *)); +void parse_option_space_decl PROTO ((struct parse *)); +int parse_option_code_definition PROTO ((struct parse *, struct option *)); +int parse_base64 (struct data_string *, struct parse *); +int parse_cshl PROTO ((struct data_string *, struct parse *)); +int parse_executable_statement PROTO ((struct executable_statement **, + struct parse *, int *, + enum expression_context)); +int parse_executable_statements PROTO ((struct executable_statement **, + struct parse *, int *, + enum expression_context)); +int parse_zone (struct dns_zone *, struct parse *); +int parse_key (struct parse *); +int parse_on_statement PROTO ((struct executable_statement **, + struct parse *, int *)); +int parse_switch_statement PROTO ((struct executable_statement **, + struct parse *, int *)); +int parse_case_statement PROTO ((struct executable_statement **, + struct parse *, int *, + enum expression_context)); +int parse_if_statement PROTO ((struct executable_statement **, + struct parse *, int *)); +int parse_boolean_expression PROTO ((struct expression **, + struct parse *, int *)); +int parse_data_expression PROTO ((struct expression **, + struct parse *, int *)); +int parse_numeric_expression PROTO ((struct expression **, + struct parse *, int *)); +int parse_dns_expression PROTO ((struct expression **, struct parse *, int *)); +int parse_non_binary PROTO ((struct expression **, struct parse *, int *, + enum expression_context)); +int parse_expression PROTO ((struct expression **, struct parse *, int *, + enum expression_context, + struct expression **, enum expr_op)); +int parse_option_statement PROTO ((struct executable_statement **, + struct parse *, int, + struct option *, enum statement_op)); +int parse_option_token PROTO ((struct expression **, struct parse *, + const char **, struct expression *, int, int)); +int parse_allow_deny PROTO ((struct option_cache **, struct parse *, int)); +int parse_auth_key PROTO ((struct data_string *, struct parse *)); +int parse_warn (struct parse *, const char *, ...) + __attribute__((__format__(__printf__,2,3))); /* tree.c */ +#if defined (NSUPDATE) +extern struct __res_state resolver_state; +extern int resolver_inited; +#endif + +extern struct binding_scope *global_scope; pair cons PROTO ((caddr_t, pair)); -struct tree_cache *tree_cache PROTO ((struct tree *)); -struct tree *tree_host_lookup PROTO ((char *)); -struct dns_host_entry *enter_dns_host PROTO ((char *)); -struct tree *tree_const PROTO ((unsigned char *, int)); -struct tree *tree_concat PROTO ((struct tree *, struct tree *)); -struct tree *tree_limit PROTO ((struct tree *, int)); -int tree_evaluate PROTO ((struct tree_cache *)); +int make_const_option_cache PROTO ((struct option_cache **, struct buffer **, + u_int8_t *, unsigned, struct option *, + const char *, int)); +int make_host_lookup PROTO ((struct expression **, const char *)); +int enter_dns_host PROTO ((struct dns_host_entry **, const char *)); +int make_const_data (struct expression **, + const unsigned char *, unsigned, int, int, + const char *, int); +int make_const_int PROTO ((struct expression **, unsigned long)); +int make_concat PROTO ((struct expression **, + struct expression *, struct expression *)); +int make_encapsulation PROTO ((struct expression **, struct data_string *)); +int make_substring PROTO ((struct expression **, struct expression *, + struct expression *, struct expression *)); +int make_limit PROTO ((struct expression **, struct expression *, int)); +int make_let PROTO ((struct executable_statement **, const char *)); +int option_cache PROTO ((struct option_cache **, struct data_string *, + struct expression *, struct option *, + const char *, int)); +int evaluate_expression (struct binding_value **, struct packet *, + struct lease *, struct client_state *, + struct option_state *, struct option_state *, + struct binding_scope **, struct expression *, + const char *, int); +int binding_value_dereference (struct binding_value **, const char *, int); +#if defined (NSUPDATE) +int evaluate_dns_expression PROTO ((ns_updrec **, struct packet *, + struct lease *, + struct client_state *, + struct option_state *, + struct option_state *, + struct binding_scope **, + struct expression *)); +#endif +int evaluate_boolean_expression PROTO ((int *, + struct packet *, struct lease *, + struct client_state *, + struct option_state *, + struct option_state *, + struct binding_scope **, + struct expression *)); +int evaluate_data_expression PROTO ((struct data_string *, + struct packet *, struct lease *, + struct client_state *, + struct option_state *, + struct option_state *, + struct binding_scope **, + struct expression *, const char *, int)); +int evaluate_numeric_expression (unsigned long *, struct packet *, + struct lease *, struct client_state *, + struct option_state *, struct option_state *, + struct binding_scope **, + struct expression *); +int evaluate_option_cache PROTO ((struct data_string *, + struct packet *, struct lease *, + struct client_state *, + struct option_state *, struct option_state *, + struct binding_scope **, + struct option_cache *, + const char *, int)); +int evaluate_boolean_option_cache PROTO ((int *, + struct packet *, struct lease *, + struct client_state *, + struct option_state *, + struct option_state *, + struct binding_scope **, + struct option_cache *, + const char *, int)); +int evaluate_boolean_expression_result PROTO ((int *, + struct packet *, struct lease *, + struct client_state *, + struct option_state *, + struct option_state *, + struct binding_scope **, + struct expression *)); +void expression_dereference PROTO ((struct expression **, const char *, int)); +int is_dns_expression PROTO ((struct expression *)); +int is_boolean_expression PROTO ((struct expression *)); +int is_data_expression PROTO ((struct expression *)); +int is_numeric_expression PROTO ((struct expression *)); +int is_compound_expression PROTO ((struct expression *)); +int op_precedence PROTO ((enum expr_op, enum expr_op)); +enum expression_context expression_context (struct expression *); +enum expression_context op_context PROTO ((enum expr_op)); +int write_expression PROTO ((FILE *, struct expression *, int, int, int)); +struct binding *find_binding PROTO ((struct binding_scope *, const char *)); +int free_bindings PROTO ((struct binding_scope *, const char *, int)); +int binding_scope_dereference PROTO ((struct binding_scope **, + const char *, int)); +int fundef_dereference (struct fundef **, const char *, int); +int data_subexpression_length (int *, struct expression *); +int expr_valid_for_context (struct expression *, enum expression_context); +struct binding *create_binding (struct binding_scope **, const char *); +int bind_ds_value (struct binding_scope **, + const char *, struct data_string *); +int find_bound_string (struct data_string *, + struct binding_scope *, const char *); +int unset (struct binding_scope *, const char *); /* dhcp.c */ extern int outstanding_pings; void dhcp PROTO ((struct packet *)); -void dhcpdiscover PROTO ((struct packet *)); -void dhcprequest PROTO ((struct packet *)); -void dhcprelease PROTO ((struct packet *)); -void dhcpdecline PROTO ((struct packet *)); -void dhcpinform PROTO ((struct packet *)); +void dhcpdiscover PROTO ((struct packet *, int)); +void dhcprequest PROTO ((struct packet *, int, struct lease *)); +void dhcprelease PROTO ((struct packet *, int)); +void dhcpdecline PROTO ((struct packet *, int)); +void dhcpinform PROTO ((struct packet *, int)); void nak_lease PROTO ((struct packet *, struct iaddr *cip)); -void ack_lease PROTO ((struct packet *, struct lease *, unsigned int, TIME)); +void ack_lease PROTO ((struct packet *, struct lease *, + unsigned int, TIME, char *, int)); void dhcp_reply PROTO ((struct lease *)); -struct lease *find_lease PROTO ((struct packet *, - struct shared_network *, int *)); -struct lease *mockup_lease PROTO ((struct packet *, - struct shared_network *, - struct host_decl *)); +int find_lease PROTO ((struct lease **, struct packet *, + struct shared_network *, int *, int *, struct lease *, + const char *, int)); +int mockup_lease PROTO ((struct lease **, struct packet *, + struct shared_network *, + struct host_decl *)); +void static_lease_dereference PROTO ((struct lease *, const char *, int)); + +int allocate_lease PROTO ((struct lease **, struct packet *, + struct pool *, int *)); +int permitted PROTO ((struct packet *, struct permit *)); +int locate_network PROTO ((struct packet *)); +int parse_agent_information_option PROTO ((struct packet *, int, u_int8_t *)); +unsigned cons_agent_information_options PROTO ((struct option_state *, + struct dhcp_packet *, + unsigned, unsigned)); /* bootp.c */ void bootp PROTO ((struct packet *)); /* memory.c */ -void enter_host PROTO ((struct host_decl *)); -struct host_decl *find_hosts_by_haddr PROTO ((int, unsigned char *, int)); -struct host_decl *find_hosts_by_uid PROTO ((unsigned char *, int)); -struct subnet *find_host_for_network PROTO ((struct host_decl **, - struct iaddr *, - struct shared_network *)); -void new_address_range PROTO ((struct iaddr, struct iaddr, - struct subnet *, int)); -extern struct subnet *find_grouped_subnet PROTO ((struct shared_network *, - struct iaddr)); -extern struct subnet *find_subnet PROTO ((struct iaddr)); -void enter_shared_network PROTO ((struct shared_network *)); -int subnet_inner_than PROTO ((struct subnet *, struct subnet *, int)); -void enter_subnet PROTO ((struct subnet *)); -void enter_lease PROTO ((struct lease *)); -int supersede_lease PROTO ((struct lease *, struct lease *, int)); -void release_lease PROTO ((struct lease *)); -void abandon_lease PROTO ((struct lease *, char *)); -struct lease *find_lease_by_uid PROTO ((unsigned char *, int)); -struct lease *find_lease_by_hw_addr PROTO ((unsigned char *, int)); -struct lease *find_lease_by_ip_addr PROTO ((struct iaddr)); -void uid_hash_add PROTO ((struct lease *)); -void uid_hash_delete PROTO ((struct lease *)); -void hw_hash_add PROTO ((struct lease *)); -void hw_hash_delete PROTO ((struct lease *)); -struct class *add_class PROTO ((int, char *)); -struct class *find_class PROTO ((int, unsigned char *, int)); -struct group *clone_group PROTO ((struct group *, char *)); -void write_leases PROTO ((void)); -void dump_subnets PROTO ((void)); +int (*group_write_hook) (struct group_object *); +extern struct group *root_group; +extern group_hash_t *group_name_hash; +isc_result_t delete_group (struct group_object *, int); +isc_result_t supersede_group (struct group_object *, int); +int clone_group (struct group **, struct group *, const char *, int); +int write_group PROTO ((struct group_object *)); + +/* salloc.c */ +void relinquish_lease_hunks (void); +struct lease *new_leases PROTO ((unsigned, const char *, int)); +#if defined (DEBUG_MEMORY_LEAKAGE) || \ + defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) +void relinquish_free_lease_states (void); +#endif +OMAPI_OBJECT_ALLOC_DECL (lease, struct lease, dhcp_type_lease) +OMAPI_OBJECT_ALLOC_DECL (class, struct class, dhcp_type_class) +OMAPI_OBJECT_ALLOC_DECL (pool, struct pool, dhcp_type_pool) +OMAPI_OBJECT_ALLOC_DECL (host, struct host_decl, dhcp_type_host) /* alloc.c */ -VOIDPTR dmalloc PROTO ((int, char *)); -void dfree PROTO ((VOIDPTR, char *)); -struct packet *new_packet PROTO ((char *)); -struct dhcp_packet *new_dhcp_packet PROTO ((char *)); -struct tree *new_tree PROTO ((char *)); -struct tree_cache *new_tree_cache PROTO ((char *)); -struct hash_table *new_hash_table PROTO ((int, char *)); -struct hash_bucket *new_hash_bucket PROTO ((char *)); -struct lease *new_lease PROTO ((char *)); -struct lease *new_leases PROTO ((int, char *)); -struct subnet *new_subnet PROTO ((char *)); -struct class *new_class PROTO ((char *)); -struct shared_network *new_shared_network PROTO ((char *)); -struct group *new_group PROTO ((char *)); -struct protocol *new_protocol PROTO ((char *)); -struct lease_state *new_lease_state PROTO ((char *)); -struct domain_search_list *new_domain_search_list PROTO ((char *)); -struct name_server *new_name_server PROTO ((char *)); -void free_name_server PROTO ((struct name_server *, char *)); -void free_domain_search_list PROTO ((struct domain_search_list *, char *)); -void free_lease_state PROTO ((struct lease_state *, char *)); -void free_protocol PROTO ((struct protocol *, char *)); -void free_group PROTO ((struct group *, char *)); -void free_shared_network PROTO ((struct shared_network *, char *)); -void free_class PROTO ((struct class *, char *)); -void free_subnet PROTO ((struct subnet *, char *)); -void free_lease PROTO ((struct lease *, char *)); -void free_hash_bucket PROTO ((struct hash_bucket *, char *)); -void free_hash_table PROTO ((struct hash_table *, char *)); -void free_tree_cache PROTO ((struct tree_cache *, char *)); -void free_packet PROTO ((struct packet *, char *)); -void free_dhcp_packet PROTO ((struct dhcp_packet *, char *)); -void free_tree PROTO ((struct tree *, char *)); +OMAPI_OBJECT_ALLOC_DECL (subnet, struct subnet, dhcp_type_subnet) +OMAPI_OBJECT_ALLOC_DECL (shared_network, struct shared_network, + dhcp_type_shared_network) +OMAPI_OBJECT_ALLOC_DECL (group_object, struct group_object, dhcp_type_group) +OMAPI_OBJECT_ALLOC_DECL (dhcp_control, + dhcp_control_object_t, dhcp_type_control) + +#if defined (DEBUG_MEMORY_LEAKAGE) || \ + defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) +void relinquish_free_pairs (void); +void relinquish_free_expressions (void); +void relinquish_free_binding_values (void); +void relinquish_free_option_caches (void); +void relinquish_free_packets (void); +#endif + +int option_chain_head_allocate (struct option_chain_head **, + const char *, int); +int option_chain_head_reference (struct option_chain_head **, + struct option_chain_head *, + const char *, int); +int option_chain_head_dereference (struct option_chain_head **, + const char *, int); +int group_allocate (struct group **, const char *, int); +int group_reference (struct group **, struct group *, const char *, int); +int group_dereference (struct group **, const char *, int); +struct dhcp_packet *new_dhcp_packet PROTO ((const char *, int)); +struct protocol *new_protocol PROTO ((const char *, int)); +struct lease_state *new_lease_state PROTO ((const char *, int)); +struct domain_search_list *new_domain_search_list PROTO ((const char *, int)); +struct name_server *new_name_server PROTO ((const char *, int)); +void free_name_server PROTO ((struct name_server *, const char *, int)); +struct option *new_option PROTO ((const char *, int)); +int group_allocate (struct group **, const char *, int); +int group_reference (struct group **, struct group *, const char *, int); +int group_dereference (struct group **, const char *, int); +void free_option PROTO ((struct option *, const char *, int)); +struct universe *new_universe PROTO ((const char *, int)); +void free_universe PROTO ((struct universe *, const char *, int)); +void free_domain_search_list PROTO ((struct domain_search_list *, + const char *, int)); +void free_lease_state PROTO ((struct lease_state *, const char *, int)); +void free_protocol PROTO ((struct protocol *, const char *, int)); +void free_dhcp_packet PROTO ((struct dhcp_packet *, const char *, int)); +struct client_lease *new_client_lease PROTO ((const char *, int)); +void free_client_lease PROTO ((struct client_lease *, const char *, int)); +struct permit *new_permit PROTO ((const char *, int)); +void free_permit PROTO ((struct permit *, const char *, int)); +pair new_pair PROTO ((const char *, int)); +void free_pair PROTO ((pair, const char *, int)); +int expression_allocate PROTO ((struct expression **, const char *, int)); +int expression_reference PROTO ((struct expression **, + struct expression *, const char *, int)); +void free_expression PROTO ((struct expression *, const char *, int)); +int binding_value_allocate PROTO ((struct binding_value **, + const char *, int)); +int binding_value_reference PROTO ((struct binding_value **, + struct binding_value *, + const char *, int)); +void free_binding_value PROTO ((struct binding_value *, const char *, int)); +int fundef_allocate PROTO ((struct fundef **, const char *, int)); +int fundef_reference PROTO ((struct fundef **, + struct fundef *, const char *, int)); +int option_cache_allocate PROTO ((struct option_cache **, const char *, int)); +int option_cache_reference PROTO ((struct option_cache **, + struct option_cache *, const char *, int)); +int buffer_allocate PROTO ((struct buffer **, unsigned, const char *, int)); +int buffer_reference PROTO ((struct buffer **, struct buffer *, + const char *, int)); +int buffer_dereference PROTO ((struct buffer **, const char *, int)); +int dns_host_entry_allocate PROTO ((struct dns_host_entry **, + const char *, const char *, int)); +int dns_host_entry_reference PROTO ((struct dns_host_entry **, + struct dns_host_entry *, + const char *, int)); +int dns_host_entry_dereference PROTO ((struct dns_host_entry **, + const char *, int)); +int option_state_allocate PROTO ((struct option_state **, const char *, int)); +int option_state_reference PROTO ((struct option_state **, + struct option_state *, const char *, int)); +int option_state_dereference PROTO ((struct option_state **, + const char *, int)); +void data_string_copy PROTO ((struct data_string *, + struct data_string *, const char *, int)); +void data_string_forget PROTO ((struct data_string *, const char *, int)); +void data_string_truncate PROTO ((struct data_string *, int)); +int executable_statement_allocate PROTO ((struct executable_statement **, + const char *, int)); +int executable_statement_reference PROTO ((struct executable_statement **, + struct executable_statement *, + const char *, int)); +int packet_allocate PROTO ((struct packet **, const char *, int)); +int packet_reference PROTO ((struct packet **, + struct packet *, const char *, int)); +int packet_dereference PROTO ((struct packet **, const char *, int)); +int binding_scope_allocate PROTO ((struct binding_scope **, + const char *, int)); +int binding_scope_reference PROTO ((struct binding_scope **, + struct binding_scope *, + const char *, int)); +int dns_zone_allocate PROTO ((struct dns_zone **, const char *, int)); +int dns_zone_reference PROTO ((struct dns_zone **, + struct dns_zone *, const char *, int)); /* print.c */ +char *quotify_string (const char *, const char *, int); +char *quotify_buf (const unsigned char *, unsigned, const char *, int); +char *print_base64 (const unsigned char *, unsigned, const char *, int); char *print_hw_addr PROTO ((int, int, unsigned char *)); void print_lease PROTO ((struct lease *)); -void dump_raw PROTO ((unsigned char *, int)); +void dump_raw PROTO ((const unsigned char *, unsigned)); +void dump_packet_option (struct option_cache *, struct packet *, + struct lease *, struct client_state *, + struct option_state *, struct option_state *, + struct binding_scope **, struct universe *, void *); void dump_packet PROTO ((struct packet *)); void hash_dump PROTO ((struct hash_table *)); +char *print_hex_1 PROTO ((unsigned, const u_int8_t *, unsigned)); +char *print_hex_2 PROTO ((unsigned, const u_int8_t *, unsigned)); +char *print_hex_3 PROTO ((unsigned, const u_int8_t *, unsigned)); +char *print_dotted_quads PROTO ((unsigned, const u_int8_t *)); +char *print_dec_1 PROTO ((unsigned long)); +char *print_dec_2 PROTO ((unsigned long)); +void print_expression PROTO ((const char *, struct expression *)); +int token_print_indent_concat (FILE *, int, int, + const char *, const char *, ...); +int token_indent_data_string (FILE *, int, int, const char *, const char *, + struct data_string *); +int token_print_indent (FILE *, int, int, + const char *, const char *, const char *); +void indent_spaces (FILE *, int); +#if defined (NSUPDATE) +void print_dns_status (int, ns_updque *); +#endif /* socket.c */ #if defined (USE_SOCKET_SEND) || defined (USE_SOCKET_RECEIVE) \ @@ -675,24 +1558,29 @@ ssize_t send_fallback PROTO ((struct interface_info *, #ifdef USE_SOCKET_SEND void if_reinitialize_send PROTO ((struct interface_info *)); void if_register_send PROTO ((struct interface_info *)); +void if_deregister_send PROTO ((struct interface_info *)); ssize_t send_packet PROTO ((struct interface_info *, struct packet *, struct dhcp_packet *, size_t, struct in_addr, struct sockaddr_in *, struct hardware *)); #endif -#if defined (USE_SOCKET_FALLBACK) -void fallback_discard PROTO ((struct protocol *)); -#endif #ifdef USE_SOCKET_RECEIVE void if_reinitialize_receive PROTO ((struct interface_info *)); void if_register_receive PROTO ((struct interface_info *)); +void if_deregister_receive PROTO ((struct interface_info *)); ssize_t receive_packet PROTO ((struct interface_info *, unsigned char *, size_t, struct sockaddr_in *, struct hardware *)); #endif + +#if defined (USE_SOCKET_FALLBACK) +isc_result_t fallback_discard PROTO ((omapi_object_t *)); +#endif + #if defined (USE_SOCKET_SEND) -int can_unicast_without_arp PROTO ((void)); +int can_unicast_without_arp PROTO ((struct interface_info *)); int can_receive_unicast_unconfigured PROTO ((struct interface_info *)); +int supports_multiple_interfaces (struct interface_info *); void maybe_setup_fallback PROTO ((void)); #endif @@ -703,6 +1591,7 @@ int if_register_bpf PROTO ( (struct interface_info *)); #ifdef USE_BPF_SEND void if_reinitialize_send PROTO ((struct interface_info *)); void if_register_send PROTO ((struct interface_info *)); +void if_deregister_send PROTO ((struct interface_info *)); ssize_t send_packet PROTO ((struct interface_info *, struct packet *, struct dhcp_packet *, size_t, struct in_addr, @@ -711,13 +1600,15 @@ ssize_t send_packet PROTO ((struct interface_info *, #ifdef USE_BPF_RECEIVE void if_reinitialize_receive PROTO ((struct interface_info *)); void if_register_receive PROTO ((struct interface_info *)); +void if_deregister_receive PROTO ((struct interface_info *)); ssize_t receive_packet PROTO ((struct interface_info *, unsigned char *, size_t, struct sockaddr_in *, struct hardware *)); #endif #if defined (USE_BPF_SEND) -int can_unicast_without_arp PROTO ((void)); +int can_unicast_without_arp PROTO ((struct interface_info *)); int can_receive_unicast_unconfigured PROTO ((struct interface_info *)); +int supports_multiple_interfaces (struct interface_info *); void maybe_setup_fallback PROTO ((void)); #endif @@ -728,6 +1619,7 @@ int if_register_lpf PROTO ( (struct interface_info *)); #ifdef USE_LPF_SEND void if_reinitialize_send PROTO ((struct interface_info *)); void if_register_send PROTO ((struct interface_info *)); +void if_deregister_send PROTO ((struct interface_info *)); ssize_t send_packet PROTO ((struct interface_info *, struct packet *, struct dhcp_packet *, size_t, struct in_addr, @@ -736,13 +1628,15 @@ ssize_t send_packet PROTO ((struct interface_info *, #ifdef USE_LPF_RECEIVE void if_reinitialize_receive PROTO ((struct interface_info *)); void if_register_receive PROTO ((struct interface_info *)); +void if_deregister_receive PROTO ((struct interface_info *)); ssize_t receive_packet PROTO ((struct interface_info *, unsigned char *, size_t, struct sockaddr_in *, struct hardware *)); #endif #if defined (USE_LPF_SEND) -int can_unicast_without_arp PROTO ((void)); +int can_unicast_without_arp PROTO ((struct interface_info *)); int can_receive_unicast_unconfigured PROTO ((struct interface_info *)); +int supports_multiple_interfaces (struct interface_info *); void maybe_setup_fallback PROTO ((void)); #endif @@ -754,6 +1648,7 @@ int if_register_nit PROTO ( (struct interface_info *)); #ifdef USE_NIT_SEND void if_reinitialize_send PROTO ((struct interface_info *)); void if_register_send PROTO ((struct interface_info *)); +void if_deregister_send PROTO ((struct interface_info *)); ssize_t send_packet PROTO ((struct interface_info *, struct packet *, struct dhcp_packet *, size_t, struct in_addr, @@ -762,19 +1657,27 @@ ssize_t send_packet PROTO ((struct interface_info *, #ifdef USE_NIT_RECEIVE void if_reinitialize_receive PROTO ((struct interface_info *)); void if_register_receive PROTO ((struct interface_info *)); +void if_deregister_receive PROTO ((struct interface_info *)); ssize_t receive_packet PROTO ((struct interface_info *, unsigned char *, size_t, struct sockaddr_in *, struct hardware *)); #endif #if defined (USE_NIT_SEND) -int can_unicast_without_arp PROTO ((void)); +int can_unicast_without_arp PROTO ((struct interface_info *)); int can_receive_unicast_unconfigured PROTO ((struct interface_info *)); +int supports_multiple_interfaces (struct interface_info *); void maybe_setup_fallback PROTO ((void)); #endif +/* dlpi.c */ +#if defined (USE_DLPI_SEND) || defined (USE_DLPI_RECEIVE) +int if_register_dlpi PROTO ( (struct interface_info *)); +#endif + #ifdef USE_DLPI_SEND void if_reinitialize_send PROTO ((struct interface_info *)); void if_register_send PROTO ((struct interface_info *)); +void if_deregister_send PROTO ((struct interface_info *)); ssize_t send_packet PROTO ((struct interface_info *, struct packet *, struct dhcp_packet *, size_t, struct in_addr, @@ -783,77 +1686,132 @@ ssize_t send_packet PROTO ((struct interface_info *, #ifdef USE_DLPI_RECEIVE void if_reinitialize_receive PROTO ((struct interface_info *)); void if_register_receive PROTO ((struct interface_info *)); +void if_deregister_receive PROTO ((struct interface_info *)); ssize_t receive_packet PROTO ((struct interface_info *, unsigned char *, size_t, struct sockaddr_in *, struct hardware *)); #endif -#if defined (USE_DLPI_SEND) -int can_unicast_without_arp PROTO ((void)); -int can_receive_unicast_unconfigured PROTO ((struct interface_info *)); -void maybe_setup_fallback PROTO ((void)); -#endif + /* raw.c */ #ifdef USE_RAW_SEND void if_reinitialize_send PROTO ((struct interface_info *)); void if_register_send PROTO ((struct interface_info *)); +void if_deregister_send PROTO ((struct interface_info *)); ssize_t send_packet PROTO ((struct interface_info *, struct packet *, struct dhcp_packet *, size_t, struct in_addr, struct sockaddr_in *, struct hardware *)); -int can_unicast_without_arp PROTO ((void)); +int can_unicast_without_arp PROTO ((struct interface_info *)); int can_receive_unicast_unconfigured PROTO ((struct interface_info *)); +int supports_multiple_interfaces (struct interface_info *); void maybe_setup_fallback PROTO ((void)); #endif -/* dispatch.c */ +/* discover.c */ extern struct interface_info *interfaces, *dummy_interfaces, *fallback_interface; extern struct protocol *protocols; extern int quiet_interface_discovery; +isc_result_t interface_setup (void); +void interface_trace_setup (void); + +extern struct in_addr limited_broadcast; +extern struct in_addr local_address; + +extern u_int16_t local_port; +extern u_int16_t remote_port; +extern int (*dhcp_interface_setup_hook) (struct interface_info *, + struct iaddr *); +extern int (*dhcp_interface_discovery_hook) (struct interface_info *); +isc_result_t (*dhcp_interface_startup_hook) (struct interface_info *); + extern void (*bootp_packet_handler) PROTO ((struct interface_info *, - struct dhcp_packet *, int, + struct dhcp_packet *, unsigned, unsigned int, struct iaddr, struct hardware *)); extern struct timeout *timeouts; +extern omapi_object_type_t *dhcp_type_interface; +#if defined (TRACING) +trace_type_t *interface_trace; +trace_type_t *inpacket_trace; +trace_type_t *outpacket_trace; +#endif +extern struct interface_info **interface_vector; +extern int interface_count; +extern int interface_max; +isc_result_t interface_initialize (omapi_object_t *, const char *, int); void discover_interfaces PROTO ((int)); -struct interface_info *setup_fallback PROTO ((void)); +int setup_fallback (struct interface_info **, const char *, int); +int if_readsocket PROTO ((omapi_object_t *)); void reinitialize_interfaces PROTO ((void)); + +/* dispatch.c */ +void set_time (u_int32_t); +struct timeval *process_outstanding_timeouts (struct timeval *); void dispatch PROTO ((void)); -int locate_network PROTO ((struct packet *)); -void got_one PROTO ((struct protocol *)); -void add_timeout PROTO ((TIME, void (*) PROTO ((void *)), void *)); +isc_result_t got_one PROTO ((omapi_object_t *)); +isc_result_t interface_set_value (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, omapi_typed_data_t *); +isc_result_t interface_get_value (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, omapi_value_t **); +isc_result_t interface_destroy (omapi_object_t *, const char *, int); +isc_result_t interface_signal_handler (omapi_object_t *, + const char *, va_list); +isc_result_t interface_stuff_values (omapi_object_t *, + omapi_object_t *, + omapi_object_t *); + +void add_timeout PROTO ((TIME, void (*) PROTO ((void *)), void *, + tvref_t, tvunref_t)); void cancel_timeout PROTO ((void (*) PROTO ((void *)), void *)); -void add_protocol PROTO ((char *, int, - void (*) PROTO ((struct protocol *)), void *)); +void cancel_all_timeouts (void); +void relinquish_timeouts (void); +#if 0 +struct protocol *add_protocol PROTO ((const char *, int, + void (*) PROTO ((struct protocol *)), + void *)); void remove_protocol PROTO ((struct protocol *)); - -/* hash.c */ -struct hash_table *new_hash PROTO ((void)); -void add_hash PROTO ((struct hash_table *, unsigned char *, - int, unsigned char *)); -void delete_hash_entry PROTO ((struct hash_table *, unsigned char *, int)); -unsigned char *hash_lookup PROTO ((struct hash_table *, unsigned char *, int)); +#endif +OMAPI_OBJECT_ALLOC_DECL (interface, + struct interface_info, dhcp_type_interface) /* tables.c */ -extern struct option dhcp_options [256]; -extern unsigned char dhcp_option_default_priority_list []; -extern int sizeof_dhcp_option_default_priority_list; -extern char *hardware_types [256]; -extern struct hash_table universe_hash; extern struct universe dhcp_universe; -void initialize_universes PROTO ((void)); - -/* convert.c */ -u_int32_t getULong PROTO ((unsigned char *)); -int32_t getLong PROTO ((unsigned char *)); -u_int16_t getUShort PROTO ((unsigned char *)); -int16_t getShort PROTO ((unsigned char *)); -void putULong PROTO ((unsigned char *, u_int32_t)); -void putLong PROTO ((unsigned char *, int32_t)); -void putUShort PROTO ((unsigned char *, unsigned int)); -void putShort PROTO ((unsigned char *, int)); +extern struct option dhcp_options [256]; +extern struct universe nwip_universe; +extern struct option nwip_options [256]; +extern struct universe fqdn_universe; +extern struct option fqdn_options [256]; +extern int dhcp_option_default_priority_list []; +extern int dhcp_option_default_priority_list_count; +extern const char *hardware_types [256]; +int universe_count, universe_max; +struct universe **universes; +extern universe_hash_t *universe_hash; +void initialize_common_option_spaces PROTO ((void)); +struct universe *config_universe; + +/* stables.c */ +#if defined (FAILOVER_PROTOCOL) +extern failover_option_t null_failover_option; +extern failover_option_t skip_failover_option; +extern struct failover_option_info ft_options []; +extern u_int32_t fto_allowed []; +extern int ft_sizes []; +extern const char *dhcp_flink_state_names []; +#endif +extern const char *binding_state_names []; + +extern struct universe agent_universe; +extern struct option agent_options [256]; +extern struct universe server_universe; +extern struct option server_options [256]; + +extern struct enumeration ddns_styles; +extern struct enumeration syslog_enum; +void initialize_server_option_spaces PROTO ((void)); /* inet.c */ struct iaddr subnet_number PROTO ((struct iaddr, struct iaddr)); @@ -862,11 +1820,14 @@ struct iaddr broadcast_addr PROTO ((struct iaddr, struct iaddr)); u_int32_t host_addr PROTO ((struct iaddr, struct iaddr)); int addr_eq PROTO ((struct iaddr, struct iaddr)); char *piaddr PROTO ((struct iaddr)); +char *piaddrmask (struct iaddr, struct iaddr, const char *, int); +char *piaddr1 PROTO ((struct iaddr)); /* dhclient.c */ -extern char *path_dhclient_conf; -extern char *path_dhclient_db; -extern char *path_dhclient_pid; +extern const char *path_dhclient_conf; +extern const char *path_dhclient_db; +extern const char *path_dhclient_pid; +extern char *path_dhclient_script; extern int interfaces_requested; extern struct client_config top_level_config; @@ -885,92 +1846,120 @@ void state_init PROTO ((void *)); void state_selecting PROTO ((void *)); void state_requesting PROTO ((void *)); void state_bound PROTO ((void *)); +void state_stop PROTO ((void *)); void state_panic PROTO ((void *)); -void bind_lease PROTO ((struct interface_info *)); +void bind_lease PROTO ((struct client_state *)); -void make_discover PROTO ((struct interface_info *, struct client_lease *)); -void make_request PROTO ((struct interface_info *, struct client_lease *)); -void make_decline PROTO ((struct interface_info *, struct client_lease *)); -void make_release PROTO ((struct interface_info *, struct client_lease *)); +void make_client_options PROTO ((struct client_state *, + struct client_lease *, u_int8_t *, + struct option_cache *, struct iaddr *, + u_int32_t *, struct option_state **)); +void make_discover PROTO ((struct client_state *, struct client_lease *)); +void make_request PROTO ((struct client_state *, struct client_lease *)); +void make_decline PROTO ((struct client_state *, struct client_lease *)); +void make_release PROTO ((struct client_state *, struct client_lease *)); -void free_client_lease PROTO ((struct client_lease *)); +void destroy_client_lease PROTO ((struct client_lease *)); void rewrite_client_leases PROTO ((void)); -void write_client_lease PROTO ((struct interface_info *, - struct client_lease *, int)); - -void script_init PROTO ((struct interface_info *, char *, - struct string_list *)); -void script_write_params PROTO ((struct interface_info *, - char *, struct client_lease *)); -int script_go PROTO ((struct interface_info *)); -void client_envadd PROTO ((struct client_state *, - const char *, const char *, const char *, ...)); +void write_lease_option (struct option_cache *, struct packet *, + struct lease *, struct client_state *, + struct option_state *, struct option_state *, + struct binding_scope **, struct universe *, void *); +int write_client_lease PROTO ((struct client_state *, + struct client_lease *, int, int)); int dhcp_option_ev_name (char *, size_t, struct option *); -struct client_lease *packet_to_lease PROTO ((struct packet *)); +void script_init PROTO ((struct client_state *, const char *, + struct string_list *)); +void client_option_envadd (struct option_cache *, struct packet *, + struct lease *, struct client_state *, + struct option_state *, struct option_state *, + struct binding_scope **, struct universe *, void *); +void script_write_params PROTO ((struct client_state *, + const char *, struct client_lease *)); +int script_go PROTO ((struct client_state *)); +void client_envadd (struct client_state *, + const char *, const char *, const char *, ...) + __attribute__((__format__(__printf__,4,5))); + +struct client_lease *packet_to_lease (struct packet *, struct client_state *); void go_daemon PROTO ((void)); void write_client_pid_file PROTO ((void)); -void status_message PROTO ((struct sysconf_header *, void *)); void client_location_changed PROTO ((void)); +void do_release PROTO ((struct client_state *)); +int dhclient_interface_shutdown_hook (struct interface_info *); +int dhclient_interface_discovery_hook (struct interface_info *); +isc_result_t dhclient_interface_startup_hook (struct interface_info *); +void client_dns_update (struct client_state *client, int); /* db.c */ int write_lease PROTO ((struct lease *)); +int write_host PROTO ((struct host_decl *)); +#if defined (FAILOVER_PROTOCOL) +int write_failover_state (dhcp_failover_state_t *); +#endif +int db_printable PROTO ((const char *)); +int db_printable_len PROTO ((const unsigned char *, unsigned)); +void write_named_billing_class (const char *, unsigned, struct class *); +void write_billing_classes (void); +int write_billing_class PROTO ((struct class *)); int commit_leases PROTO ((void)); -void db_startup PROTO ((void)); -void new_lease_file PROTO ((void)); +void db_startup PROTO ((int)); +int new_lease_file PROTO ((void)); +int group_writer (struct group_object *); /* packet.c */ -u_int32_t checksum PROTO ((unsigned char *, int, u_int32_t)); +u_int32_t checksum PROTO ((unsigned char *, unsigned, u_int32_t)); u_int32_t wrapsum PROTO ((u_int32_t)); void assemble_hw_header PROTO ((struct interface_info *, unsigned char *, - int *, struct hardware *)); + unsigned *, struct hardware *)); void assemble_udp_ip_header PROTO ((struct interface_info *, unsigned char *, - int *, u_int32_t, u_int32_t, unsigned int, - unsigned char *, int)); + unsigned *, u_int32_t, u_int32_t, + u_int32_t, unsigned char *, unsigned)); ssize_t decode_hw_header PROTO ((struct interface_info *, unsigned char *, - int, struct hardware *)); + unsigned, struct hardware *)); ssize_t decode_udp_ip_header PROTO ((struct interface_info *, unsigned char *, - int, struct sockaddr_in *, - unsigned char *, int)); + unsigned, struct sockaddr_in *, + unsigned char *, unsigned)); /* ethernet.c */ void assemble_ethernet_header PROTO ((struct interface_info *, unsigned char *, - int *, struct hardware *)); + unsigned *, struct hardware *)); ssize_t decode_ethernet_header PROTO ((struct interface_info *, unsigned char *, - int, struct hardware *)); + unsigned, struct hardware *)); /* tr.c */ void assemble_tr_header PROTO ((struct interface_info *, unsigned char *, - int *, struct hardware *)); + unsigned *, struct hardware *)); ssize_t decode_tr_header PROTO ((struct interface_info *, unsigned char *, - int, struct hardware *)); + unsigned, struct hardware *)); /* dhxpxlt.c */ -void convert_statement PROTO ((FILE *)); -void convert_host_statement PROTO ((FILE *, jrefproto)); -void convert_host_name PROTO ((FILE *, jrefproto)); -void convert_class_statement PROTO ((FILE *, jrefproto, int)); -void convert_class_decl PROTO ((FILE *, jrefproto)); -void convert_lease_time PROTO ((FILE *, jrefproto, char *)); -void convert_shared_net_statement PROTO ((FILE *, jrefproto)); -void convert_subnet_statement PROTO ((FILE *, jrefproto)); -void convert_subnet_decl PROTO ((FILE *, jrefproto)); -void convert_host_decl PROTO ((FILE *, jrefproto)); -void convert_hardware_decl PROTO ((FILE *, jrefproto)); -void convert_hardware_addr PROTO ((FILE *, jrefproto)); -void convert_filename_decl PROTO ((FILE *, jrefproto)); -void convert_servername_decl PROTO ((FILE *, jrefproto)); -void convert_ip_addr_or_hostname PROTO ((FILE *, jrefproto, int)); -void convert_fixed_addr_decl PROTO ((FILE *, jrefproto)); -void convert_option_decl PROTO ((FILE *, jrefproto)); -void convert_timestamp PROTO ((FILE *, jrefproto)); -void convert_lease_statement PROTO ((FILE *, jrefproto)); -void convert_address_range PROTO ((FILE *, jrefproto)); -void convert_date PROTO ((FILE *, jrefproto, char *)); -void convert_numeric_aggregate PROTO ((FILE *, jrefproto, int, int, int, int)); +void convert_statement PROTO ((struct parse *)); +void convert_host_statement PROTO ((struct parse *, jrefproto)); +void convert_host_name PROTO ((struct parse *, jrefproto)); +void convert_class_statement PROTO ((struct parse *, jrefproto, int)); +void convert_class_decl PROTO ((struct parse *, jrefproto)); +void convert_lease_time PROTO ((struct parse *, jrefproto, char *)); +void convert_shared_net_statement PROTO ((struct parse *, jrefproto)); +void convert_subnet_statement PROTO ((struct parse *, jrefproto)); +void convert_subnet_decl PROTO ((struct parse *, jrefproto)); +void convert_host_decl PROTO ((struct parse *, jrefproto)); +void convert_hardware_decl PROTO ((struct parse *, jrefproto)); +void convert_hardware_addr PROTO ((struct parse *, jrefproto)); +void convert_filename_decl PROTO ((struct parse *, jrefproto)); +void convert_servername_decl PROTO ((struct parse *, jrefproto)); +void convert_ip_addr_or_hostname PROTO ((struct parse *, jrefproto, int)); +void convert_fixed_addr_decl PROTO ((struct parse *, jrefproto)); +void convert_option_decl PROTO ((struct parse *, jrefproto)); +void convert_timestamp PROTO ((struct parse *, jrefproto)); +void convert_lease_statement PROTO ((struct parse *, jrefproto)); +void convert_address_range PROTO ((struct parse *, jrefproto)); +void convert_date PROTO ((struct parse *, jrefproto, char *)); +void convert_numeric_aggregate PROTO ((struct parse *, jrefproto, int, int, int, int)); void indent PROTO ((int)); /* route.c */ @@ -987,39 +1976,73 @@ void set_broadcast_addr PROTO ((struct interface_info *, struct in_addr)); void set_ip_address PROTO ((struct interface_info *, struct in_addr)); /* clparse.c */ -int read_client_conf PROTO ((void)); +isc_result_t read_client_conf PROTO ((void)); +int read_client_conf_file (const char *, + struct interface_info *, struct client_config *); void read_client_leases PROTO ((void)); -void parse_client_statement PROTO ((FILE *, struct interface_info *, +void parse_client_statement PROTO ((struct parse *, struct interface_info *, struct client_config *)); -int parse_X PROTO ((FILE *, u_int8_t *, int)); -int parse_option_list PROTO ((FILE *, u_int8_t *)); -void parse_interface_declaration PROTO ((FILE *, struct client_config *)); -struct interface_info *interface_or_dummy PROTO ((char *)); -void make_client_state PROTO ((struct interface_info *)); -void make_client_config PROTO ((struct interface_info *, +int parse_X PROTO ((struct parse *, u_int8_t *, unsigned)); +void parse_option_list PROTO ((struct parse *, u_int32_t **)); +void parse_interface_declaration PROTO ((struct parse *, + struct client_config *, char *)); +int interface_or_dummy PROTO ((struct interface_info **, const char *)); +void make_client_state PROTO ((struct client_state **)); +void make_client_config PROTO ((struct client_state *, struct client_config *)); -void parse_client_lease_statement PROTO ((FILE *, int)); -void parse_client_lease_declaration PROTO ((FILE *, struct client_lease *, - struct interface_info **)); -struct option *parse_option_decl PROTO ((FILE *, struct option_data *)); -void parse_string_list PROTO ((FILE *, struct string_list **, int)); -int parse_ip_addr PROTO ((FILE *, struct iaddr *)); -void parse_reject_statement PROTO ((FILE *, struct client_config *)); +void parse_client_lease_statement PROTO ((struct parse *, int)); +void parse_client_lease_declaration PROTO ((struct parse *, + struct client_lease *, + struct interface_info **, + struct client_state **)); +int parse_option_decl PROTO ((struct option_cache **, struct parse *)); +void parse_string_list PROTO ((struct parse *, struct string_list **, int)); +int parse_ip_addr PROTO ((struct parse *, struct iaddr *)); +void parse_reject_statement PROTO ((struct parse *, struct client_config *)); /* dhcrelay.c */ -void relay PROTO ((struct interface_info *, struct dhcp_packet *, int, +void relay PROTO ((struct interface_info *, struct dhcp_packet *, unsigned, unsigned int, struct iaddr, struct hardware *)); +int strip_relay_agent_options PROTO ((struct interface_info *, + struct interface_info **, + struct dhcp_packet *, unsigned)); +int find_interface_by_agent_option PROTO ((struct dhcp_packet *, + struct interface_info **, + u_int8_t *, int)); +int add_relay_agent_options PROTO ((struct interface_info *, + struct dhcp_packet *, + unsigned, struct in_addr)); /* icmp.c */ +OMAPI_OBJECT_ALLOC_DECL (icmp_state, struct icmp_state, dhcp_type_icmp) +extern struct icmp_state *icmp_state; void icmp_startup PROTO ((int, void (*) PROTO ((struct iaddr, u_int8_t *, int)))); +int icmp_readsocket PROTO ((omapi_object_t *)); int icmp_echorequest PROTO ((struct iaddr *)); -void icmp_echoreply PROTO ((struct protocol *)); +isc_result_t icmp_echoreply PROTO ((omapi_object_t *)); /* dns.c */ -void dns_startup PROTO ((void)); -int ns_inaddr_lookup PROTO ((u_int16_t, struct iaddr)); -void dns_packet PROTO ((struct protocol *)); +#if defined (NSUPDATE) +isc_result_t find_tsig_key (ns_tsig_key **, const char *, struct dns_zone *); +void tkey_free (ns_tsig_key **); +#endif +isc_result_t enter_dns_zone (struct dns_zone *); +isc_result_t dns_zone_lookup (struct dns_zone **, const char *); +int dns_zone_dereference PROTO ((struct dns_zone **, const char *, int)); +#if defined (NSUPDATE) +isc_result_t find_cached_zone (const char *, ns_class, char *, + size_t, struct in_addr *, int, int *, + struct dns_zone **); +void forget_zone (struct dns_zone **); +void repudiate_zone (struct dns_zone **); +void cache_found_zone (ns_class, char *, struct in_addr *, int); +int get_dhcid (struct data_string *, int, const u_int8_t *, unsigned); +isc_result_t ddns_update_a (struct data_string *, struct iaddr, + struct data_string *, unsigned long, int); +isc_result_t ddns_remove_a (struct data_string *, + struct iaddr, struct data_string *); +#endif /* NSUPDATE */ /* resolv.c */ extern char path_resolv_conf []; @@ -1027,14 +2050,566 @@ struct name_server *name_servers; struct domain_search_list *domains; void read_resolv_conf PROTO ((TIME)); -struct sockaddr_in *pick_name_server PROTO ((void)); +struct name_server *first_name_server PROTO ((void)); /* inet_addr.c */ #ifdef NEED_INET_ATON int inet_aton PROTO ((const char *, struct in_addr *)); #endif -/* sysconf.c */ -void sysconf_startup PROTO ((void (*) (struct sysconf_header *, void *))); -void sysconf_restart PROTO ((void *)); -void sysconf_message PROTO ((struct protocol *proto)); +/* class.c */ +extern int have_billing_classes; +struct class unknown_class; +struct class known_class; +struct collection default_collection; +struct collection *collections; +struct executable_statement *default_classification_rules; + +void classification_setup PROTO ((void)); +void classify_client PROTO ((struct packet *)); +int check_collection PROTO ((struct packet *, struct lease *, + struct collection *)); +void classify PROTO ((struct packet *, struct class *)); +isc_result_t find_class PROTO ((struct class **, const char *, + const char *, int)); +int unbill_class PROTO ((struct lease *, struct class *)); +int bill_class PROTO ((struct lease *, struct class *)); + +/* execute.c */ +int execute_statements PROTO ((struct binding_value **result, + struct packet *, struct lease *, + struct client_state *, + struct option_state *, struct option_state *, + struct binding_scope **, + struct executable_statement *)); +void execute_statements_in_scope PROTO ((struct binding_value **result, + struct packet *, struct lease *, + struct client_state *, + struct option_state *, + struct option_state *, + struct binding_scope **, + struct group *, struct group *)); +int executable_statement_dereference PROTO ((struct executable_statement **, + const char *, int)); +void write_statements (FILE *, struct executable_statement *, int); +int find_matching_case (struct executable_statement **, + struct packet *, struct lease *, struct client_state *, + struct option_state *, struct option_state *, + struct binding_scope **, + struct expression *, struct executable_statement *); +int executable_statement_foreach (struct executable_statement *, + int (*) (struct executable_statement *, + void *, int), void *, int); + +/* comapi.c */ +extern omapi_object_type_t *dhcp_type_interface; +extern omapi_object_type_t *dhcp_type_group; +extern omapi_object_type_t *dhcp_type_shared_network; +extern omapi_object_type_t *dhcp_type_subnet; +extern omapi_object_type_t *dhcp_type_control; +extern dhcp_control_object_t *dhcp_control_object; + +void dhcp_common_objects_setup (void); + +isc_result_t dhcp_group_set_value (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, + omapi_typed_data_t *); +isc_result_t dhcp_group_get_value (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, + omapi_value_t **); +isc_result_t dhcp_group_destroy (omapi_object_t *, const char *, int); +isc_result_t dhcp_group_signal_handler (omapi_object_t *, + const char *, va_list); +isc_result_t dhcp_group_stuff_values (omapi_object_t *, + omapi_object_t *, + omapi_object_t *); +isc_result_t dhcp_group_lookup (omapi_object_t **, + omapi_object_t *, omapi_object_t *); +isc_result_t dhcp_group_create (omapi_object_t **, + omapi_object_t *); +isc_result_t dhcp_group_remove (omapi_object_t *, + omapi_object_t *); + +isc_result_t dhcp_control_set_value (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, + omapi_typed_data_t *); +isc_result_t dhcp_control_get_value (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, + omapi_value_t **); +isc_result_t dhcp_control_destroy (omapi_object_t *, const char *, int); +isc_result_t dhcp_control_signal_handler (omapi_object_t *, + const char *, va_list); +isc_result_t dhcp_control_stuff_values (omapi_object_t *, + omapi_object_t *, + omapi_object_t *); +isc_result_t dhcp_control_lookup (omapi_object_t **, + omapi_object_t *, omapi_object_t *); +isc_result_t dhcp_control_create (omapi_object_t **, + omapi_object_t *); +isc_result_t dhcp_control_remove (omapi_object_t *, + omapi_object_t *); + +isc_result_t dhcp_subnet_set_value (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, + omapi_typed_data_t *); +isc_result_t dhcp_subnet_get_value (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, + omapi_value_t **); +isc_result_t dhcp_subnet_destroy (omapi_object_t *, const char *, int); +isc_result_t dhcp_subnet_signal_handler (omapi_object_t *, + const char *, va_list); +isc_result_t dhcp_subnet_stuff_values (omapi_object_t *, + omapi_object_t *, + omapi_object_t *); +isc_result_t dhcp_subnet_lookup (omapi_object_t **, + omapi_object_t *, omapi_object_t *); +isc_result_t dhcp_subnet_create (omapi_object_t **, + omapi_object_t *); +isc_result_t dhcp_subnet_remove (omapi_object_t *, + omapi_object_t *); + +isc_result_t dhcp_shared_network_set_value (omapi_object_t *, + omapi_object_t *, + omapi_data_string_t *, + omapi_typed_data_t *); +isc_result_t dhcp_shared_network_get_value (omapi_object_t *, + omapi_object_t *, + omapi_data_string_t *, + omapi_value_t **); +isc_result_t dhcp_shared_network_destroy (omapi_object_t *, const char *, int); +isc_result_t dhcp_shared_network_signal_handler (omapi_object_t *, + const char *, va_list); +isc_result_t dhcp_shared_network_stuff_values (omapi_object_t *, + omapi_object_t *, + omapi_object_t *); +isc_result_t dhcp_shared_network_lookup (omapi_object_t **, + omapi_object_t *, omapi_object_t *); +isc_result_t dhcp_shared_network_create (omapi_object_t **, + omapi_object_t *); +isc_result_t dhcp_shared_network_remove (omapi_object_t *, + omapi_object_t *); + +/* omapi.c */ +extern int (*dhcp_interface_shutdown_hook) (struct interface_info *); + +extern omapi_object_type_t *dhcp_type_lease; +extern omapi_object_type_t *dhcp_type_pool; +extern omapi_object_type_t *dhcp_type_class; + +#if defined (FAILOVER_PROTOCOL) +extern omapi_object_type_t *dhcp_type_failover_state; +extern omapi_object_type_t *dhcp_type_failover_link; +extern omapi_object_type_t *dhcp_type_failover_listener; +#endif + +void dhcp_db_objects_setup (void); + +isc_result_t dhcp_lease_set_value (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, + omapi_typed_data_t *); +isc_result_t dhcp_lease_get_value (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, + omapi_value_t **); +isc_result_t dhcp_lease_destroy (omapi_object_t *, const char *, int); +isc_result_t dhcp_lease_signal_handler (omapi_object_t *, + const char *, va_list); +isc_result_t dhcp_lease_stuff_values (omapi_object_t *, + omapi_object_t *, + omapi_object_t *); +isc_result_t dhcp_lease_lookup (omapi_object_t **, + omapi_object_t *, omapi_object_t *); +isc_result_t dhcp_lease_create (omapi_object_t **, + omapi_object_t *); +isc_result_t dhcp_lease_remove (omapi_object_t *, + omapi_object_t *); +isc_result_t dhcp_group_set_value (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, + omapi_typed_data_t *); +isc_result_t dhcp_group_get_value (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, + omapi_value_t **); +isc_result_t dhcp_group_destroy (omapi_object_t *, const char *, int); +isc_result_t dhcp_group_signal_handler (omapi_object_t *, + const char *, va_list); +isc_result_t dhcp_group_stuff_values (omapi_object_t *, + omapi_object_t *, + omapi_object_t *); +isc_result_t dhcp_group_lookup (omapi_object_t **, + omapi_object_t *, omapi_object_t *); +isc_result_t dhcp_group_create (omapi_object_t **, + omapi_object_t *); +isc_result_t dhcp_group_remove (omapi_object_t *, + omapi_object_t *); +isc_result_t dhcp_host_set_value (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, + omapi_typed_data_t *); +isc_result_t dhcp_host_get_value (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, + omapi_value_t **); +isc_result_t dhcp_host_destroy (omapi_object_t *, const char *, int); +isc_result_t dhcp_host_signal_handler (omapi_object_t *, + const char *, va_list); +isc_result_t dhcp_host_stuff_values (omapi_object_t *, + omapi_object_t *, + omapi_object_t *); +isc_result_t dhcp_host_lookup (omapi_object_t **, + omapi_object_t *, omapi_object_t *); +isc_result_t dhcp_host_create (omapi_object_t **, + omapi_object_t *); +isc_result_t dhcp_host_remove (omapi_object_t *, + omapi_object_t *); +isc_result_t dhcp_pool_set_value (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, + omapi_typed_data_t *); +isc_result_t dhcp_pool_get_value (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, + omapi_value_t **); +isc_result_t dhcp_pool_destroy (omapi_object_t *, const char *, int); +isc_result_t dhcp_pool_signal_handler (omapi_object_t *, + const char *, va_list); +isc_result_t dhcp_pool_stuff_values (omapi_object_t *, + omapi_object_t *, + omapi_object_t *); +isc_result_t dhcp_pool_lookup (omapi_object_t **, + omapi_object_t *, omapi_object_t *); +isc_result_t dhcp_pool_create (omapi_object_t **, + omapi_object_t *); +isc_result_t dhcp_pool_remove (omapi_object_t *, + omapi_object_t *); +isc_result_t dhcp_class_set_value (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, + omapi_typed_data_t *); +isc_result_t dhcp_class_get_value (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, + omapi_value_t **); +isc_result_t dhcp_class_destroy (omapi_object_t *, const char *, int); +isc_result_t dhcp_class_signal_handler (omapi_object_t *, + const char *, va_list); +isc_result_t dhcp_class_stuff_values (omapi_object_t *, + omapi_object_t *, + omapi_object_t *); +isc_result_t dhcp_class_lookup (omapi_object_t **, + omapi_object_t *, omapi_object_t *); +isc_result_t dhcp_class_create (omapi_object_t **, + omapi_object_t *); +isc_result_t dhcp_class_remove (omapi_object_t *, + omapi_object_t *); +isc_result_t dhcp_subclass_set_value (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, + omapi_typed_data_t *); +isc_result_t dhcp_subclass_get_value (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, + omapi_value_t **); +isc_result_t dhcp_subclass_destroy (omapi_object_t *, const char *, int); +isc_result_t dhcp_subclass_signal_handler (omapi_object_t *, + const char *, va_list); +isc_result_t dhcp_subclass_stuff_values (omapi_object_t *, + omapi_object_t *, + omapi_object_t *); +isc_result_t dhcp_subclass_lookup (omapi_object_t **, + omapi_object_t *, omapi_object_t *); +isc_result_t dhcp_subclass_create (omapi_object_t **, + omapi_object_t *); +isc_result_t dhcp_subclass_remove (omapi_object_t *, + omapi_object_t *); +isc_result_t dhcp_shared_network_set_value (omapi_object_t *, + omapi_object_t *, + omapi_data_string_t *, + omapi_typed_data_t *); +isc_result_t dhcp_shared_network_get_value (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, + omapi_value_t **); +isc_result_t dhcp_shared_network_destroy (omapi_object_t *, const char *, int); +isc_result_t dhcp_shared_network_signal_handler (omapi_object_t *, + const char *, va_list); +isc_result_t dhcp_shared_network_stuff_values (omapi_object_t *, + omapi_object_t *, + omapi_object_t *); +isc_result_t dhcp_shared_network_lookup (omapi_object_t **, + omapi_object_t *, omapi_object_t *); +isc_result_t dhcp_shared_network_create (omapi_object_t **, + omapi_object_t *); +isc_result_t dhcp_subnet_set_value (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, + omapi_typed_data_t *); +isc_result_t dhcp_subnet_get_value (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, + omapi_value_t **); +isc_result_t dhcp_subnet_destroy (omapi_object_t *, const char *, int); +isc_result_t dhcp_subnet_signal_handler (omapi_object_t *, + const char *, va_list); +isc_result_t dhcp_subnet_stuff_values (omapi_object_t *, + omapi_object_t *, + omapi_object_t *); +isc_result_t dhcp_subnet_lookup (omapi_object_t **, + omapi_object_t *, omapi_object_t *); +isc_result_t dhcp_subnet_create (omapi_object_t **, + omapi_object_t *); +isc_result_t dhcp_interface_set_value (omapi_object_t *, + omapi_object_t *, + omapi_data_string_t *, + omapi_typed_data_t *); +isc_result_t dhcp_interface_get_value (omapi_object_t *, + omapi_object_t *, + omapi_data_string_t *, + omapi_value_t **); +isc_result_t dhcp_interface_destroy (omapi_object_t *, + const char *, int); +isc_result_t dhcp_interface_signal_handler (omapi_object_t *, + const char *, + va_list ap); +isc_result_t dhcp_interface_stuff_values (omapi_object_t *, + omapi_object_t *, + omapi_object_t *); +isc_result_t dhcp_interface_lookup (omapi_object_t **, + omapi_object_t *, + omapi_object_t *); +isc_result_t dhcp_interface_create (omapi_object_t **, + omapi_object_t *); +isc_result_t dhcp_interface_remove (omapi_object_t *, + omapi_object_t *); +void interface_stash (struct interface_info *); +void interface_snorf (struct interface_info *, int); + +isc_result_t binding_scope_set_value (struct binding_scope *, int, + omapi_data_string_t *, + omapi_typed_data_t *); +isc_result_t binding_scope_get_value (omapi_value_t **, + struct binding_scope *, + omapi_data_string_t *); +isc_result_t binding_scope_stuff_values (omapi_object_t *, + struct binding_scope *); + +/* mdb.c */ + +extern struct subnet *subnets; +extern struct shared_network *shared_networks; +extern host_hash_t *host_hw_addr_hash; +extern host_hash_t *host_uid_hash; +extern host_hash_t *host_name_hash; +extern lease_hash_t *lease_uid_hash; +extern lease_hash_t *lease_ip_addr_hash; +extern lease_hash_t *lease_hw_addr_hash; + +extern omapi_object_type_t *dhcp_type_host; + +isc_result_t enter_host PROTO ((struct host_decl *, int, int)); +isc_result_t delete_host PROTO ((struct host_decl *, int)); +int find_hosts_by_haddr PROTO ((struct host_decl **, int, + const unsigned char *, unsigned, + const char *, int)); +int find_hosts_by_uid PROTO ((struct host_decl **, const unsigned char *, + unsigned, const char *, int)); +int find_host_for_network PROTO ((struct subnet **, struct host_decl **, + struct iaddr *, struct shared_network *)); +void new_address_range PROTO ((struct iaddr, struct iaddr, + struct subnet *, struct pool *, + struct lease **)); +isc_result_t dhcp_lease_free (omapi_object_t *, const char *, int); +isc_result_t dhcp_lease_get (omapi_object_t **, const char *, int); +int find_grouped_subnet PROTO ((struct subnet **, struct shared_network *, + struct iaddr, const char *, int)); +int find_subnet (struct subnet **, struct iaddr, const char *, int); +void enter_shared_network PROTO ((struct shared_network *)); +void new_shared_network_interface PROTO ((struct parse *, + struct shared_network *, + const char *)); +int subnet_inner_than PROTO ((struct subnet *, struct subnet *, int)); +void enter_subnet PROTO ((struct subnet *)); +void enter_lease PROTO ((struct lease *)); +int supersede_lease PROTO ((struct lease *, struct lease *, int, int, int)); +void make_binding_state_transition (struct lease *); +int lease_copy PROTO ((struct lease **, struct lease *, const char *, int)); +void release_lease PROTO ((struct lease *, struct packet *)); +void abandon_lease PROTO ((struct lease *, const char *)); +void dissociate_lease PROTO ((struct lease *)); +void pool_timer PROTO ((void *)); +int find_lease_by_uid PROTO ((struct lease **, const unsigned char *, + unsigned, const char *, int)); +int find_lease_by_hw_addr PROTO ((struct lease **, const unsigned char *, + unsigned, const char *, int)); +int find_lease_by_ip_addr PROTO ((struct lease **, struct iaddr, + const char *, int)); +void uid_hash_add PROTO ((struct lease *)); +void uid_hash_delete PROTO ((struct lease *)); +void hw_hash_add PROTO ((struct lease *)); +void hw_hash_delete PROTO ((struct lease *)); +int write_leases PROTO ((void)); +int lease_enqueue (struct lease *); +void lease_instantiate (const unsigned char *, unsigned, struct lease *); +void expire_all_pools PROTO ((void)); +void dump_subnets PROTO ((void)); +#if defined (DEBUG_MEMORY_LEAKAGE) || \ + defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) +void free_everything (void); +#endif + +/* nsupdate.c */ +char *ddns_rev_name (struct lease *, struct lease_state *, struct packet *); +char *ddns_fwd_name (struct lease *, struct lease_state *, struct packet *); +int nsupdateA (const char *, const unsigned char *, u_int32_t, int); +int nsupdatePTR (const char *, const unsigned char *, u_int32_t, int); +void nsupdate (struct lease *, struct lease_state *, struct packet *, int); +int updateA (const struct data_string *, const struct data_string *, + unsigned int, struct lease *); +int updatePTR (const struct data_string *, const struct data_string *, + unsigned int, struct lease *); +int deleteA (const struct data_string *, const struct data_string *, + struct lease *); +int deletePTR (const struct data_string *, const struct data_string *, + struct lease *); + +/* failover.c */ +#if defined (FAILOVER_PROTOCOL) +extern dhcp_failover_state_t *failover_states; +void dhcp_failover_startup PROTO ((void)); +int dhcp_failover_write_all_states (void); +isc_result_t enter_failover_peer PROTO ((dhcp_failover_state_t *)); +isc_result_t find_failover_peer PROTO ((dhcp_failover_state_t **, + const char *, const char *, int)); +isc_result_t dhcp_failover_link_initiate PROTO ((omapi_object_t *)); +isc_result_t dhcp_failover_link_signal PROTO ((omapi_object_t *, + const char *, va_list)); +isc_result_t dhcp_failover_link_set_value PROTO ((omapi_object_t *, + omapi_object_t *, + omapi_data_string_t *, + omapi_typed_data_t *)); +isc_result_t dhcp_failover_link_get_value PROTO ((omapi_object_t *, + omapi_object_t *, + omapi_data_string_t *, + omapi_value_t **)); +isc_result_t dhcp_failover_link_destroy PROTO ((omapi_object_t *, + const char *, int)); +isc_result_t dhcp_failover_link_stuff_values PROTO ((omapi_object_t *, + omapi_object_t *, + omapi_object_t *)); +isc_result_t dhcp_failover_listen PROTO ((omapi_object_t *)); + +isc_result_t dhcp_failover_listener_signal PROTO ((omapi_object_t *, + const char *, + va_list)); +isc_result_t dhcp_failover_listener_set_value PROTO ((omapi_object_t *, + omapi_object_t *, + omapi_data_string_t *, + omapi_typed_data_t *)); +isc_result_t dhcp_failover_listener_get_value PROTO ((omapi_object_t *, + omapi_object_t *, + omapi_data_string_t *, + omapi_value_t **)); +isc_result_t dhcp_failover_listener_destroy PROTO ((omapi_object_t *, + const char *, int)); +isc_result_t dhcp_failover_listener_stuff PROTO ((omapi_object_t *, + omapi_object_t *, + omapi_object_t *)); +isc_result_t dhcp_failover_register PROTO ((omapi_object_t *)); +isc_result_t dhcp_failover_state_signal PROTO ((omapi_object_t *, + const char *, va_list)); +isc_result_t dhcp_failover_state_transition (dhcp_failover_state_t *, + const char *); +isc_result_t dhcp_failover_set_service_state (dhcp_failover_state_t *state); +isc_result_t dhcp_failover_set_state (dhcp_failover_state_t *, + enum failover_state); +isc_result_t dhcp_failover_peer_state_changed (dhcp_failover_state_t *, + failover_message_t *); +int dhcp_failover_pool_rebalance (dhcp_failover_state_t *); +int dhcp_failover_pool_check (struct pool *); +int dhcp_failover_state_pool_check (dhcp_failover_state_t *); +void dhcp_failover_timeout (void *); +void dhcp_failover_send_contact (void *); +isc_result_t dhcp_failover_send_state (dhcp_failover_state_t *); +isc_result_t dhcp_failover_send_updates (dhcp_failover_state_t *); +int dhcp_failover_queue_update (struct lease *, int); +int dhcp_failover_send_acks (dhcp_failover_state_t *); +void dhcp_failover_toack_queue_timeout (void *); +int dhcp_failover_queue_ack (dhcp_failover_state_t *, failover_message_t *msg); +void dhcp_failover_ack_queue_remove (dhcp_failover_state_t *, struct lease *); +isc_result_t dhcp_failover_state_set_value PROTO ((omapi_object_t *, + omapi_object_t *, + omapi_data_string_t *, + omapi_typed_data_t *)); +void dhcp_failover_keepalive (void *); +void dhcp_failover_reconnect (void *); +void dhcp_failover_startup_timeout (void *); +void dhcp_failover_link_startup_timeout (void *); +void dhcp_failover_listener_restart (void *); +isc_result_t dhcp_failover_state_get_value PROTO ((omapi_object_t *, + omapi_object_t *, + omapi_data_string_t *, + omapi_value_t **)); +isc_result_t dhcp_failover_state_destroy PROTO ((omapi_object_t *, + const char *, int)); +isc_result_t dhcp_failover_state_stuff PROTO ((omapi_object_t *, + omapi_object_t *, + omapi_object_t *)); +isc_result_t dhcp_failover_state_lookup PROTO ((omapi_object_t **, + omapi_object_t *, + omapi_object_t *)); +isc_result_t dhcp_failover_state_create PROTO ((omapi_object_t **, + omapi_object_t *)); +isc_result_t dhcp_failover_state_remove PROTO ((omapi_object_t *, + omapi_object_t *)); +int dhcp_failover_state_match (dhcp_failover_state_t *, u_int8_t *, unsigned); +const char *dhcp_failover_reject_reason_print (int); +const char *dhcp_failover_state_name_print (enum failover_state); +const char *dhcp_failover_message_name (unsigned); +const char *dhcp_failover_option_name (unsigned); +failover_option_t *dhcp_failover_option_printf (unsigned, char *, + unsigned *, + unsigned, + const char *, ...) + __attribute__((__format__(__printf__,5,6))); +failover_option_t *dhcp_failover_make_option (unsigned, char *, + unsigned *, unsigned, ...); +isc_result_t dhcp_failover_put_message (dhcp_failover_link_t *, + omapi_object_t *, int, ...); +isc_result_t dhcp_failover_send_connect PROTO ((omapi_object_t *)); +isc_result_t dhcp_failover_send_connectack PROTO ((omapi_object_t *, + dhcp_failover_state_t *, + int, const char *)); +isc_result_t dhcp_failover_send_disconnect PROTO ((omapi_object_t *, + int, const char *)); +isc_result_t dhcp_failover_send_bind_update (dhcp_failover_state_t *, + struct lease *); +isc_result_t dhcp_failover_send_bind_ack (dhcp_failover_state_t *, + failover_message_t *, + int, const char *); +isc_result_t dhcp_failover_send_poolreq (dhcp_failover_state_t *); +isc_result_t dhcp_failover_send_poolresp (dhcp_failover_state_t *, int); +isc_result_t dhcp_failover_send_update_request (dhcp_failover_state_t *); +isc_result_t dhcp_failover_send_update_request_all (dhcp_failover_state_t *); +isc_result_t dhcp_failover_send_update_done (dhcp_failover_state_t *); +isc_result_t dhcp_failover_process_bind_update (dhcp_failover_state_t *, + failover_message_t *); +isc_result_t dhcp_failover_process_bind_ack (dhcp_failover_state_t *, + failover_message_t *); +isc_result_t dhcp_failover_generate_update_queue (dhcp_failover_state_t *, + int); +isc_result_t dhcp_failover_process_update_request (dhcp_failover_state_t *, + failover_message_t *); +isc_result_t dhcp_failover_process_update_request_all (dhcp_failover_state_t *, + failover_message_t *); +isc_result_t dhcp_failover_process_update_done (dhcp_failover_state_t *, + failover_message_t *); +void dhcp_failover_recover_done (void *); +void failover_print PROTO ((char *, unsigned *, unsigned, const char *)); +void update_partner PROTO ((struct lease *)); +int load_balance_mine (struct packet *, dhcp_failover_state_t *); +binding_state_t normal_binding_state_transition_check (struct lease *, + dhcp_failover_state_t *, + binding_state_t, + u_int32_t); +binding_state_t +conflict_binding_state_transition_check (struct lease *, + dhcp_failover_state_t *, + binding_state_t, u_int32_t); +int lease_mine_to_reallocate (struct lease *); + +OMAPI_OBJECT_ALLOC_DECL (dhcp_failover_state, dhcp_failover_state_t, + dhcp_type_failover_state) +OMAPI_OBJECT_ALLOC_DECL (dhcp_failover_listener, dhcp_failover_listener_t, + dhcp_type_failover_listener) +OMAPI_OBJECT_ALLOC_DECL (dhcp_failover_link, dhcp_failover_link_t, + dhcp_type_failover_link) +#endif /* FAILOVER_PROTOCOL */ + +const char *binding_state_print (enum failover_state); diff --git a/contrib/isc-dhcp/includes/dhctoken.h b/contrib/isc-dhcp/includes/dhctoken.h index 2aeb530..876d8f3 100644 --- a/contrib/isc-dhcp/includes/dhctoken.h +++ b/contrib/isc-dhcp/includes/dhctoken.h @@ -3,8 +3,8 @@ Tokens for config file lexer and parser. */ /* - * Copyright (c) 1995, 1996, 1997, 1998, 1999 - * The Internet Software Consortium. All rights reserved. + * Copyright (c) 1996-1999 Internet Software Consortium. + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -34,101 +34,289 @@ * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium - * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie - * Enterprises. To learn more about the Internet Software Consortium, - * see ``http://www.vix.com/isc''. To learn more about Vixie - * Enterprises, see ``http://www.vix.com''. + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. */ -#define SEMI ';' -#define DOT '.' -#define COLON ':' -#define COMMA ',' -#define SLASH '/' -#define LBRACE '{' -#define RBRACE '}' +enum dhcp_token { + SEMI = ';', + DOT = '.', + COLON = ':', + COMMA = ',', + SLASH = '/', + LBRACE = '{', + RBRACE = '}', + LPAREN = '(', + RPAREN = ')', + EQUAL = '=', + BANG = '!', + PERCENT = '%', + PLUS = '+', + MINUS = '-', + ASTERISK = '*', + AMPERSAND = '&', + PIPE = '|', + CARET = '^', -#define FIRST_TOKEN HOST -#define HOST 256 -#define HARDWARE 257 -#define FILENAME 258 -#define FIXED_ADDR 259 -#define OPTION 260 -#define ETHERNET 261 -#define STRING 262 -#define NUMBER 263 -#define NUMBER_OR_NAME 264 -#define NAME 265 -#define TIMESTAMP 266 -#define STARTS 267 -#define ENDS 268 -#define UID 269 -#define CLASS 270 -#define LEASE 271 -#define RANGE 272 -#define PACKET 273 -#define CIADDR 274 -#define YIADDR 275 -#define SIADDR 276 -#define GIADDR 277 -#define SUBNET 278 -#define NETMASK 279 -#define DEFAULT_LEASE_TIME 280 -#define MAX_LEASE_TIME 281 -#define VENDOR_CLASS 282 -#define USER_CLASS 283 -#define SHARED_NETWORK 284 -#define SERVER_NAME 285 -#define DYNAMIC_BOOTP 286 -#define SERVER_IDENTIFIER 287 -#define DYNAMIC_BOOTP_LEASE_CUTOFF 288 -#define DYNAMIC_BOOTP_LEASE_LENGTH 289 -#define BOOT_UNKNOWN_CLIENTS 290 -#define NEXT_SERVER 291 -#define TOKEN_RING 292 -#define GROUP 293 -#define ONE_LEASE_PER_CLIENT 294 -#define GET_LEASE_HOSTNAMES 295 -#define USE_HOST_DECL_NAMES 296 -#define SEND 297 -#define CLIENT_IDENTIFIER 298 -#define REQUEST 299 -#define REQUIRE 300 -#define TIMEOUT 301 -#define RETRY 302 -#define SELECT_TIMEOUT 303 -#define SCRIPT 304 -#define INTERFACE 305 -#define RENEW 306 -#define REBIND 307 -#define EXPIRE 308 -#define UNKNOWN_CLIENTS 309 -#define ALLOW 310 -#define BOOTP 311 -#define DENY 312 -#define BOOTING 313 -#define DEFAULT 314 -#define MEDIA 315 -#define MEDIUM 316 -#define ALIAS 317 -#define REBOOT 318 -#define ABANDONED 319 -#define BACKOFF_CUTOFF 320 -#define INITIAL_INTERVAL 321 -#define NAMESERVER 322 -#define DOMAIN 323 -#define SEARCH 324 -#define SUPERSEDE 325 -#define APPEND 326 -#define PREPEND 327 -#define HOSTNAME 328 -#define CLIENT_HOSTNAME 329 -#define REJECT 330 -#define FDDI 331 -#define USE_LEASE_ADDR_FOR_DEFAULT_ROUTE 332 -#define AUTHORITATIVE 333 -#define TOKEN_NOT 334 -#define ALWAYS_REPLY_RFC1048 335 + HOST = 256, + FIRST_TOKEN = HOST, + HARDWARE = 257, + FILENAME = 258, + FIXED_ADDR = 259, + OPTION = 260, + ETHERNET = 261, + STRING = 262, + NUMBER = 263, + NUMBER_OR_NAME = 264, + NAME = 265, + TIMESTAMP = 266, + STARTS = 267, + ENDS = 268, + UID = 269, + CLASS = 270, + LEASE = 271, + RANGE = 272, + PACKET = 273, + CIADDR = 274, + YIADDR = 275, + SIADDR = 276, + GIADDR = 277, + SUBNET = 278, + NETMASK = 279, + DEFAULT_LEASE_TIME = 280, + MAX_LEASE_TIME = 281, + VENDOR_CLASS = 282, + USER_CLASS = 283, + SHARED_NETWORK = 284, + SERVER_NAME = 285, + DYNAMIC_BOOTP = 286, + SERVER_IDENTIFIER = 287, + DYNAMIC_BOOTP_LEASE_CUTOFF = 288, + DYNAMIC_BOOTP_LEASE_LENGTH = 289, + BOOT_UNKNOWN_CLIENTS = 290, + NEXT_SERVER = 291, + TOKEN_RING = 292, + GROUP = 293, + ONE_LEASE_PER_CLIENT = 294, + GET_LEASE_HOSTNAMES = 295, + USE_HOST_DECL_NAMES = 296, + SEND = 297, + CLIENT_IDENTIFIER = 298, + REQUEST = 299, + REQUIRE = 300, + TIMEOUT = 301, + RETRY = 302, + SELECT_TIMEOUT = 303, + SCRIPT = 304, + INTERFACE = 305, + RENEW = 306, + REBIND = 307, + EXPIRE = 308, + UNKNOWN_CLIENTS = 309, + ALLOW = 310, + DENY = 312, + BOOTING = 313, + DEFAULT = 314, + MEDIA = 315, + MEDIUM = 316, + ALIAS = 317, + REBOOT = 318, + TOKEN_ABANDONED = 319, + BACKOFF_CUTOFF = 320, + INITIAL_INTERVAL = 321, + NAMESERVER = 322, + DOMAIN = 323, + SEARCH = 324, + SUPERSEDE = 325, + APPEND = 326, + PREPEND = 327, + HOSTNAME = 328, + CLIENT_HOSTNAME = 329, + REJECT = 330, + USE_LEASE_ADDR_FOR_DEFAULT_ROUTE = 331, + MIN_LEASE_TIME = 332, + MIN_SECS = 333, + AND = 334, + OR = 335, + SUBSTRING = 337, + SUFFIX = 338, + CHECK = 339, + EXTRACT_INT = 340, + IF = 341, + TOKEN_ADD = 342, + BREAK = 343, + ELSE = 344, + ELSIF = 345, + SUBCLASS = 346, + MATCH = 347, + SPAWN = 348, + WITH = 349, + EXISTS = 350, + POOL = 351, + UNKNOWN = 352, + CLIENTS = 353, + KNOWN = 354, + AUTHENTICATED = 355, + UNAUTHENTICATED = 356, + ALL = 357, + DYNAMIC = 358, + MEMBERS = 359, + OF = 360, + PSEUDO = 361, + LIMIT = 362, + BILLING = 363, + PEER = 364, + FAILOVER = 365, + MY = 366, + PARTNER = 367, + PRIMARY = 368, + SECONDARY = 369, + IDENTIFIER = 370, + PORT = 371, + MAX_TRANSMIT_IDLE = 372, + MAX_RESPONSE_DELAY = 373, + PARTNER_DOWN = 374, + NORMAL = 375, + COMMUNICATIONS_INTERRUPTED = 376, + POTENTIAL_CONFLICT = 377, + RECOVER = 378, + FDDI = 379, + AUTHORITATIVE = 380, + TOKEN_NOT = 381, + AUTHENTICATION = 383, + IGNORE = 384, + ACCEPT = 385, + PREFER = 386, + DONT = 387, + CODE = 388, + ARRAY = 389, + BOOLEAN = 390, + INTEGER = 391, + SIGNED = 392, + UNSIGNED = 393, + IP_ADDRESS = 394, + TEXT = 395, + STRING_TOKEN = 396, + SPACE = 397, + CONCAT = 398, + ENCODE_INT = 399, + REVERSE = 402, + LEASED_ADDRESS = 403, + BINARY_TO_ASCII = 404, + PICK = 405, + CONFIG_OPTION = 406, + HOST_DECL_NAME = 407, + ON = 408, + EXPIRY = 409, + RELEASE = 410, + COMMIT = 411, + DNS_UPDATE = 412, + LEASE_TIME = 413, + STATIC = 414, + NEVER = 415, + INFINITE = 416, + TOKEN_DELETED = 417, + UPDATED_DNS_RR = 418, + DNS_DELETE = 419, + DUPLICATES = 420, + DECLINES = 421, + TSTP = 422, + TSFP = 423, + OWNER = 424, + IS = 425, + HBA = 426, + MAX_UNACKED_UPDATES = 427, + MCLT = 428, + SPLIT = 429, + AT = 430, + NO = 431, + TOKEN_DELETE = 432, + NS_UPDATE = 433, + UPDATE = 434, + SWITCH = 435, + CASE = 436, + NS_FORMERR = 437, + NS_NOERROR = 438, + NS_NOTAUTH = 439, + NS_NOTIMP = 440, + NS_NOTZONE = 441, + NS_NXDOMAIN = 442, + NS_NXRRSET = 443, + NS_REFUSED = 444, + NS_SERVFAIL = 445, + NS_YXDOMAIN = 446, + NS_YXRRSET = 447, + TOKEN_NULL = 448, + TOKEN_SET = 449, + DEFINED = 450, + UNSET = 451, + EVAL = 452, + LET = 453, + FUNCTION = 454, + DEFINE = 455, + ZONE = 456, + KEY = 457, + SECRET = 458, + ALGORITHM = 459, + LOAD = 460, + BALANCE = 461, + TOKEN_MAX = 462, + SECONDS = 463, + ADDRESS = 464, + RESOLUTION_INTERRUPTED = 465, + STATE = 466, + UNKNOWN_STATE = 567, + CLTT = 568, + INCLUDE = 569, + BINDING = 570, + TOKEN_FREE = 571, + TOKEN_ACTIVE = 572, + TOKEN_EXPIRED = 573, + TOKEN_RELEASED = 574, + TOKEN_RESET = 575, + TOKEN_BACKUP = 576, + TOKEN_RESERVED = 577, + TOKEN_BOOTP = 578, + TOKEN_NEXT = 579, + OMAPI = 580, + LOG = 581, + FATAL = 582, + ERROR = 583, + TOKEN_DEBUG = 584, + INFO = 585, + RETURN = 586, + PAUSED = 587, + RECOVER_DONE = 588, + SHUTDOWN = 589, + STARTUP = 590, + ENCAPSULATE = 591, + VENDOR = 592, + CLIENT_STATE = 593, + INIT_REBOOT = 594, + TOKEN_INIT = 595, + SELECT = 596, + BOUND = 597, + RENEWING = 598, + REBINDING = 599, + RECONTACT_INTERVAL = 600, + CLIENT_UPDATES = 601, + TOKEN_NEW = 601, + TRANSMISSION = 602, + TOKEN_CLOSE = 603, + TOKEN_CREATE = 604, + TOKEN_OPEN = 605, + TOKEN_HELP = 606, + END_OF_FILE = 607, + RECOVER_WAIT = 608, + SERVER = 609, + CONNECT = 610, + REMOVE = 611, + REFRESH = 612, + DOMAIN_NAME = 613 +}; #define is_identifier(x) ((x) >= FIRST_TOKEN && \ (x) != STRING && \ diff --git a/contrib/isc-dhcp/includes/failover.h b/contrib/isc-dhcp/includes/failover.h new file mode 100644 index 0000000..e27a911 --- /dev/null +++ b/contrib/isc-dhcp/includes/failover.h @@ -0,0 +1,322 @@ +/* failover.h + + Definitions for address trees... */ + +/* + * Copyright (c) 2000-2001 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. + */ + +#if defined (FAILOVER_PROTOCOL) +struct failover_option_info { + int code; + const char *name; + enum { FT_UINT8, FT_IPADDR, FT_UINT32, FT_BYTES, FT_TEXT_OR_BYTES, + FT_DDNS, FT_DDNS1, FT_UINT16, FT_TEXT, + FT_UNDEF, FT_DIGEST } type; + int num_present; + int offset; + u_int32_t bit; +}; + +typedef struct { + unsigned count; + u_int8_t *data; +} failover_option_t; + +#define FM_OFFSET(x) (long)(&(((failover_message_t *)0) -> x)) + +/* Failover message options: */ +#define FTO_BINDING_STATUS 1 +#define FTB_BINDING_STATUS 0x00000002 +#define FTO_ASSIGNED_IP_ADDRESS 2 +#define FTB_ASSIGNED_IP_ADDRESS 0x00000004 +#define FTO_SERVER_ADDR 3 +#define FTB_SERVER_ADDR 0x00000008 +#define FTO_ADDRESSES_TRANSFERRED 4 +#define FTB_ADDRESSES_TRANSFERRED 0x00000010 +#define FTO_CLIENT_IDENTIFIER 5 +#define FTB_CLIENT_IDENTIFIER 0x00000020 +#define FTO_CHADDR 6 +#define FTB_CHADDR 0x00000040 +#define FTO_DDNS 7 +#define FTB_DDNS 0x00000080 +#define FTO_REJECT_REASON 8 +#define FTB_REJECT_REASON 0x00000100 +#define FTO_MESSAGE 9 +#define FTB_MESSAGE 0x00000200 +#define FTO_MCLT 10 +#define FTB_MCLT 0x00000400 +#define FTO_VENDOR_CLASS 11 +#define FTB_VENDOR_CLASS 0x00000800 +#define FTO_LEASE_EXPIRY 13 +#define FTB_LEASE_EXPIRY 0x00002000 +#define FTO_POTENTIAL_EXPIRY 14 +#define FTB_POTENTIAL_EXPIRY 0x00004000 +#define FTO_GRACE_EXPIRY 15 +#define FTB_GRACE_EXPIRY 0x00008000 +#define FTO_CLTT 16 +#define FTB_CLTT 0x00010000 +#define FTO_STOS 17 +#define FTB_STOS 0x00020000 +#define FTO_SERVER_STATE 18 +#define FTB_SERVER_STATE 0x00040000 +#define FTO_SERVER_FLAGS 19 +#define FTB_SERVER_FLAGS 0x00080000 +#define FTO_VENDOR_OPTIONS 20 +#define FTB_VENDOR_OPTIONS 0x00100000 +#define FTO_MAX_UNACKED 21 +#define FTB_MAX_UNACKED 0x00200000 +#define FTO_RECEIVE_TIMER 23 +#define FTB_RECEIVE_TIMER 0x00800000 +#define FTO_HBA 24 +#define FTB_HBA 0x01000000 +#define FTO_MESSAGE_DIGEST 25 +#define FTB_MESSAGE_DIGEST 0x02000000 +#define FTO_PROTOCOL_VERSION 26 +#define FTB_PROTOCOL_VERSION 0x04000000 +#define FTO_TLS_REQUEST 27 +#define FTB_TLS_REQUEST 0x08000000 +#define FTO_TLS_REPLY 28 +#define FTB_TLS_REPLY 0x10000000 +#define FTO_REQUEST_OPTIONS 29 +#define FTB_REQUEST_OPTIONS 0x20000000 +#define FTO_REPLY_OPTIONS 30 +#define FTB_REPLY_OPTIONS 0x40000000 +#define FTO_MAX FTO_REPLY_OPTIONS + +/* Failover protocol message types: */ +#define FTM_POOLREQ 1 +#define FTM_POOLRESP 2 +#define FTM_BNDUPD 3 +#define FTM_BNDACK 4 +#define FTM_CONNECT 5 +#define FTM_CONNECTACK 6 +#define FTM_UPDREQ 7 +#define FTM_UPDDONE 8 +#define FTM_UPDREQALL 9 +#define FTM_STATE 10 +#define FTM_CONTACT 11 +#define FTM_DISCONNECT 12 + +/* Reject reasons: */ + +#define FTR_ILLEGAL_IP_ADDR 1 +#define FTR_FATAL_CONFLICT 2 +#define FTR_MISSING_BINDINFO 3 +#define FTR_TIMEMISMATCH 4 +#define FTR_INVALID_MCLT 5 +#define FTR_MISC_REJECT 6 +#define FTR_DUP_CONNECTION 7 +#define FTR_INVALID_PARTNER 8 +#define FTR_TLS_UNSUPPORTED 9 +#define FTR_TLS_UNCONFIGURED 10 +#define FTR_TLS_REQUIRED 11 +#define FTR_DIGEST_UNSUPPORTED 12 +#define FTR_DIGEST_UNCONFIGURED 13 +#define FTR_VERSION_MISMATCH 14 +#define FTR_MISSING_BIND_INFO 15 +#define FTR_OUTDATED_BIND_INFO 16 +#define FTR_LESS_CRIT_BIND_INFO 17 +#define FTR_NO_TRAFFIC 18 +#define FTR_HBA_CONFLICT 19 +#define FTR_UNKNOWN 254 + +#define DHCP_FAILOVER_MAX_MESSAGE_SIZE 2048 + +/* Failover server flags. */ +#define FTF_STARTUP 1 + +typedef struct failover_message { + int refcnt; + struct failover_message *next; + + u_int8_t type; + + u_int8_t binding_status; + u_int8_t protocol_version; + u_int8_t reject_reason; + u_int8_t server_flags; + u_int8_t server_state; + u_int8_t tls_reply; + u_int8_t tls_request; + u_int32_t stos; + u_int32_t time; + u_int32_t xid; + u_int32_t addresses_transferred; + u_int32_t assigned_addr; + u_int32_t client_ltt; + u_int32_t expiry; + u_int32_t grace_expiry; + u_int32_t max_unacked; + u_int32_t mclt; + u_int32_t potential_expiry; + u_int32_t receive_timer; + u_int32_t server_addr; + failover_option_t chaddr; + failover_option_t client_identifier; + failover_option_t hba; + failover_option_t message; + failover_option_t reply_options; + failover_option_t request_options; + ddns_fqdn_t ddns; + failover_option_t vendor_class; + failover_option_t vendor_options; + + int options_present; +} failover_message_t; + +typedef struct { + OMAPI_OBJECT_PREAMBLE; + struct option_cache *peer_address; + unsigned peer_port; + int options_present; + enum dhcp_flink_state { + dhcp_flink_start, + dhcp_flink_message_length_wait, + dhcp_flink_message_wait, + dhcp_flink_disconnected, + dhcp_flink_state_max + } state; + failover_message_t *imsg; + struct _dhcp_failover_state *state_object; + u_int16_t imsg_len; + unsigned imsg_count; + u_int8_t imsg_payoff; /* Pay*load* offset. :') */ + u_int32_t xid; +} dhcp_failover_link_t; + +typedef struct _dhcp_failover_listener { + OMAPI_OBJECT_PREAMBLE; + struct _dhcp_failover_listener *next; + omapi_addr_t address; +} dhcp_failover_listener_t; +#endif /* FAILOVER_PROTOCOL */ + +/* A failover peer. */ +enum failover_state { + unknown_state, + partner_down, + normal, + communications_interrupted, + resolution_interrupted, + potential_conflict, + recover, + recover_done, + shut_down, + paused, + startup, + recover_wait +}; + +/* Service states are simplifications of failover states, particularly + useful because the startup state isn't actually implementable as a + seperate failover state without maintaining a state stack. */ + +enum service_state { + unknown_service_state, + cooperating, + not_cooperating, + service_partner_down, + not_responding, + service_startup +}; + +#if defined (FAILOVER_PROTOCOL) +typedef struct _dhcp_failover_config { + struct option_cache *address; + int port; + u_int32_t max_flying_updates; + enum failover_state state; + TIME stos; + u_int32_t max_response_delay; +} dhcp_failover_config_t; + +typedef struct _dhcp_failover_state { + OMAPI_OBJECT_PREAMBLE; + struct _dhcp_failover_state *next; + char *name; /* Name of this failover instance. */ + dhcp_failover_config_t me; /* My configuration. */ + dhcp_failover_config_t partner; /* Partner's configuration. */ + enum failover_state saved_state; /* Saved state during startup. */ + struct data_string server_identifier; /* Server identifier (IP addr) */ + u_int32_t mclt; + + u_int8_t *hba; /* Hash bucket array for load balancing. */ + int load_balance_max_secs; + + enum service_state service_state; + const char *nrr; /* Printable reason why we're in the + not_responding service state (empty + string if we are responding. */ + + dhcp_failover_link_t *link_to_peer; /* Currently-established link + to peer. */ + + enum { + primary, secondary + } i_am; /* We are primary or secondary in this relationship. */ + + TIME last_packet_sent; /* Timestamp on last packet we sent. */ + TIME last_timestamp_received; /* The last timestamp we sent that + has been returned by our partner. */ + TIME skew; /* The skew between our clock and our partner's. */ + struct lease *update_queue_head; /* List of leases we haven't sent + to peer. */ + struct lease *update_queue_tail; + + struct lease *ack_queue_head; /* List of lease updates the peer + hasn't yet acked. */ + struct lease *ack_queue_tail; + + struct lease *send_update_done; /* When we get a BNDACK for this + lease, send an UPDDONE message. */ + int cur_unacked_updates; /* Number of updates we've sent + that have not yet been acked. */ + + /* List of messages which we haven't + acked yet. */ + failover_message_t *toack_queue_head; + failover_message_t *toack_queue_tail; + int pending_acks; /* Number of messages in the toack + queue. */ + int pool_count; /* Number of pools referencing this + failover state object. */ +} dhcp_failover_state_t; + +#define DHCP_FAILOVER_VERSION 1 +#endif /* FAILOVER_PROTOCOL */ diff --git a/contrib/isc-dhcp/includes/inet.h b/contrib/isc-dhcp/includes/inet.h index 1cedc23..0154172 100644 --- a/contrib/isc-dhcp/includes/inet.h +++ b/contrib/isc-dhcp/includes/inet.h @@ -3,7 +3,8 @@ Portable definitions for internet addresses */ /* - * Copyright (c) 1996 The Internet Software Consortium. All rights reserved. + * Copyright (c) 1996-1999 Internet Software Consortium. + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,16 +34,17 @@ * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium - * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie - * Enterprises. To learn more about the Internet Software Consortium, - * see ``http://www.vix.com/isc''. To learn more about Vixie - * Enterprises, see ``http://www.vix.com''. + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. */ /* An internet address of up to 128 bits. */ struct iaddr { - int len; + unsigned len; unsigned char iabuf [16]; }; diff --git a/contrib/isc-dhcp/includes/isc-dhcp/boolean.h b/contrib/isc-dhcp/includes/isc-dhcp/boolean.h new file mode 100644 index 0000000..08d8c24 --- /dev/null +++ b/contrib/isc-dhcp/includes/isc-dhcp/boolean.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 1998, 1999 Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#ifndef ISC_BOOLEAN_H +#define ISC_BOOLEAN_H 1 + +#include <isc-dhcp/lang.h> + +ISC_LANG_BEGINDECLS + +typedef enum { isc_boolean_false = 0, isc_boolean_true = 1 } isc_boolean_t; + +#define ISC_FALSE isc_boolean_false +#define ISC_TRUE isc_boolean_true + +ISC_LANG_ENDDECLS + +#endif /* ISC_BOOLEAN_H */ diff --git a/contrib/isc-dhcp/includes/isc-dhcp/dst.h b/contrib/isc-dhcp/includes/isc-dhcp/dst.h new file mode 100644 index 0000000..65c54d2 --- /dev/null +++ b/contrib/isc-dhcp/includes/isc-dhcp/dst.h @@ -0,0 +1,142 @@ +#ifndef DST_H +#define DST_H + +#ifndef HAS_DST_KEY +typedef struct dst_key { + char *dk_key_name; /* name of the key */ + int dk_key_size; /* this is the size of the key in bits */ + int dk_proto; /* what protocols this key can be used for */ + int dk_alg; /* algorithm number from key record */ + unsigned dk_flags; /* and the flags of the public key */ + unsigned dk_id; /* identifier of the key */ +} DST_KEY; +#endif /* HAS_DST_KEY */ + +/* + * DST Crypto API defintions + */ +void dst_init(void); +int dst_check_algorithm(const int); + +int dst_sign_data(const int mode, /* specifies INIT/UPDATE/FINAL/ALL */ + DST_KEY *in_key, /* the key to use */ + void **context, /* pointer to state structure */ + const u_char *data, /* data to be signed */ + const unsigned len, /* length of input data */ + u_char *signature, /* buffer to write signature to */ + const unsigned sig_len); /* size of output buffer */ + +int dst_verify_data(const int mode, /* specifies INIT/UPDATE/FINAL/ALL */ + DST_KEY *in_key, /* the key to use */ + void **context, /* pointer to state structure */ + const u_char *data, /* data to be verified */ + const unsigned len, /* length of input data */ + const u_char *signature,/* buffer containing signature */ + const unsigned sig_len); /* length of signature */ + + +DST_KEY *dst_read_key(const char *in_name, /* name of key */ + const unsigned in_id, /* key tag identifier */ + const int in_alg, /* key algorithm */ + const int key_type); /* Private/PublicKey wanted*/ + +int dst_write_key(const DST_KEY *key, /* key to write out */ + const int key_type); /* Public/Private */ + +DST_KEY *dst_dnskey_to_key(const char *in_name, /* KEY record name */ + const u_char *key, /* KEY RDATA */ + const unsigned len); /* size of input buffer*/ + + +int dst_key_to_dnskey(const DST_KEY *key, /* key to translate */ + u_char *out_storage, /* output buffer */ + const unsigned out_len); /* size of out_storage*/ + + +DST_KEY *dst_buffer_to_key(const char *key_name, /* name of the key */ + const int alg, /* algorithm */ + const unsigned flags, /* dns flags */ + const int protocol, /* dns protocol */ + const u_char *key_buf, /* key in dns wire fmt */ + const unsigned key_len); /* size of key */ + + +int dst_key_to_buffer(DST_KEY *key, u_char *out_buff, unsigned buf_len); + +DST_KEY *dst_generate_key(const char *name, /* name of new key */ + const int bits, /* size of new key */ + const int exp, /* alg dependent parameter*/ + const unsigned flags, /* key DNS flags */ + const int protocol, /* key DNS protocol */ + const int alg); /* key algorithm to generate */ + +DST_KEY *dst_free_key(DST_KEY *f_key); +int dst_compare_keys(const DST_KEY *key1, const DST_KEY *key2); + +int dst_sig_size(DST_KEY *key); + +int dst_random(const int mode, unsigned wanted, u_char *outran); + + +/* support for dns key tags/ids */ +u_int16_t dst_s_dns_key_id(const u_char *dns_key_rdata, + const unsigned rdata_len); +u_int16_t dst_s_id_calc(const u_char *key_data, const unsigned key_len); + +/* Used by callers as well as by the library. */ +#define RAW_KEY_SIZE 8192 /* large enough to store any key */ + +/* DST_API control flags */ +/* These are used used in functions dst_sign_data and dst_verify_data */ +#define SIG_MODE_INIT 1 /* initalize digest */ +#define SIG_MODE_UPDATE 2 /* add data to digest */ +#define SIG_MODE_FINAL 4 /* generate/verify signature */ +#define SIG_MODE_ALL (SIG_MODE_INIT|SIG_MODE_UPDATE|SIG_MODE_FINAL) + +/* Flags for dst_read_private_key() */ +#define DST_FORCE_READ 0x1000000 +#define DST_CAN_SIGN 0x010F +#define DST_NO_AUTHEN 0x8000 +#define DST_EXTEND_FLAG 0x1000 +#define DST_STANDARD 0 +#define DST_PRIVATE 0x2000000 +#define DST_PUBLIC 0x4000000 +#define DST_RAND_SEMI 1 +#define DST_RAND_STD 2 +#define DST_RAND_KEY 3 +#define DST_RAND_DSS 4 + + +/* DST algorithm codes */ +#define KEY_RSA 1 +#define KEY_DH 2 +#define KEY_DSA 3 +#define KEY_PRIVATE 254 +#define KEY_EXPAND 255 +#define KEY_HMAC_MD5 157 +#define KEY_HMAC_SHA1 158 +#define UNKNOWN_KEYALG 0 +#define DST_MAX_ALGS KEY_HMAC_SHA1 + +/* DST constants to locations in KEY record changes in new KEY record */ +#define DST_FLAGS_SIZE 2 +#define DST_KEY_PROT 2 +#define DST_KEY_ALG 3 +#define DST_EXT_FLAG 4 +#define DST_KEY_START 4 + +#ifndef SIGN_F_NOKEY +#define SIGN_F_NOKEY 0xC000 +#endif + +/* error codes from dst routines */ +#define SIGN_INIT_FAILURE (-23) +#define SIGN_UPDATE_FAILURE (-24) +#define SIGN_FINAL_FAILURE (-25) +#define VERIFY_INIT_FAILURE (-26) +#define VERIFY_UPDATE_FAILURE (-27) +#define VERIFY_FINAL_FAILURE (-28) +#define MISSING_KEY_OR_SIGNATURE (-30) +#define UNSUPPORTED_KEYALG (-31) + +#endif /* DST_H */ diff --git a/contrib/isc-dhcp/includes/isc-dhcp/int.h b/contrib/isc-dhcp/includes/isc-dhcp/int.h new file mode 100644 index 0000000..98159f5 --- /dev/null +++ b/contrib/isc-dhcp/includes/isc-dhcp/int.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 1999 Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#ifndef ISC_INT_H +#define ISC_INT_H 1 + +#include <isc-dhcp/lang.h> + +ISC_LANG_BEGINDECLS + +typedef char isc_int8_t; +typedef unsigned char isc_uint8_t; +typedef short isc_int16_t; +typedef unsigned short isc_uint16_t; +typedef int isc_int32_t; +typedef unsigned int isc_uint32_t; +typedef long long isc_int64_t; +typedef unsigned long long isc_uint64_t; + +ISC_LANG_ENDDECLS + +#endif /* ISC_INT_H */ diff --git a/contrib/isc-dhcp/includes/isc-dhcp/lang.h b/contrib/isc-dhcp/includes/isc-dhcp/lang.h new file mode 100644 index 0000000..3edeb72 --- /dev/null +++ b/contrib/isc-dhcp/includes/isc-dhcp/lang.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 1999 Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#ifndef ISC_LANG_H +#define ISC_LANG_H 1 + +#ifdef __cplusplus +#define ISC_LANG_BEGINDECLS extern "C" { +#define ISC_LANG_ENDDECLS } +#else +#define ISC_LANG_BEGINDECLS +#define ISC_LANG_ENDDECLS +#endif + +#endif /* ISC_LANG_H */ diff --git a/contrib/isc-dhcp/includes/isc-dhcp/list.h b/contrib/isc-dhcp/includes/isc-dhcp/list.h new file mode 100644 index 0000000..d966008 --- /dev/null +++ b/contrib/isc-dhcp/includes/isc-dhcp/list.h @@ -0,0 +1,116 @@ +/* + * Copyright (C) 1997, 1999 Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#ifndef ISC_LIST_H +#define ISC_LIST_H 1 + +#define ISC_LIST(type) struct { type *head, *tail; } +#define ISC_LIST_INIT(list) \ + do { (list).head = NULL; (list).tail = NULL; } while (0) + +#define ISC_LINK(type) struct { type *prev, *next; } +#define ISC_LINK_INIT(elt, link) \ + do { \ + (elt)->link.prev = (void *)(-1); \ + (elt)->link.next = (void *)(-1); \ + } while (0) +#define ISC_LINK_LINKED(elt, link) ((elt)->link.prev != (void *)(-1)) + +#define ISC_LIST_HEAD(list) ((list).head) +#define ISC_LIST_TAIL(list) ((list).tail) +#define ISC_LIST_EMPTY(list) ((list).head == NULL) + +#define ISC_LIST_PREPEND(list, elt, link) \ + do { \ + if ((list).head != NULL) \ + (list).head->link.prev = (elt); \ + else \ + (list).tail = (elt); \ + (elt)->link.prev = NULL; \ + (elt)->link.next = (list).head; \ + (list).head = (elt); \ + } while (0) + +#define ISC_LIST_APPEND(list, elt, link) \ + do { \ + if ((list).tail != NULL) \ + (list).tail->link.next = (elt); \ + else \ + (list).head = (elt); \ + (elt)->link.prev = (list).tail; \ + (elt)->link.next = NULL; \ + (list).tail = (elt); \ + } while (0) + +#define ISC_LIST_UNLINK(list, elt, link) \ + do { \ + if ((elt)->link.next != NULL) \ + (elt)->link.next->link.prev = (elt)->link.prev; \ + else \ + (list).tail = (elt)->link.prev; \ + if ((elt)->link.prev != NULL) \ + (elt)->link.prev->link.next = (elt)->link.next; \ + else \ + (list).head = (elt)->link.next; \ + (elt)->link.prev = (void *)(-1); \ + (elt)->link.next = (void *)(-1); \ + } while (0) + +#define ISC_LIST_PREV(elt, link) ((elt)->link.prev) +#define ISC_LIST_NEXT(elt, link) ((elt)->link.next) + +#define ISC_LIST_INSERTBEFORE(list, before, elt, link) \ + do { \ + if ((before)->link.prev == NULL) \ + ISC_LIST_PREPEND(list, elt, link); \ + else { \ + (elt)->link.prev = (before)->link.prev; \ + (before)->link.prev = (elt); \ + (elt)->link.prev->link.next = (elt); \ + (elt)->link.next = (before); \ + } \ + } while (0) + +#define ISC_LIST_INSERTAFTER(list, after, elt, link) \ + do { \ + if ((after)->link.next == NULL) \ + ISC_LIST_APPEND(list, elt, link); \ + else { \ + (elt)->link.next = (after)->link.next; \ + (after)->link.next = (elt); \ + (elt)->link.next->link.prev = (elt); \ + (elt)->link.prev = (after); \ + } \ + } while (0) + +#define ISC_LIST_APPENDLIST(list1, list2, link) \ + do { \ + if (ISC_LIST_EMPTY(list1)) \ + (list1) = (list2); \ + else if (!ISC_LIST_EMPTY(list2)) { \ + (list1).tail->link.next = (list2).head; \ + (list2).head->link.prev = (list1).tail; \ + (list1).tail = (list2).tail; \ + (list2).head = NULL; \ + (list2).tail = NULL; \ + } \ + } while (0) + +#define ISC_LIST_ENQUEUE(list, elt, link) ISC_LIST_APPEND(list, elt, link) +#define ISC_LIST_DEQUEUE(list, elt, link) ISC_LIST_UNLINK(list, elt, link) + +#endif /* ISC_LIST_H */ diff --git a/contrib/isc-dhcp/includes/isc-dhcp/result.h b/contrib/isc-dhcp/includes/isc-dhcp/result.h new file mode 100644 index 0000000..a2de1fc --- /dev/null +++ b/contrib/isc-dhcp/includes/isc-dhcp/result.h @@ -0,0 +1,113 @@ +/* + * Copyright (C) 1998, 1999 Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#ifndef ISC_RESULT_H +#define ISC_RESULT_H 1 + +#include <isc-dhcp/boolean.h> +#include <isc-dhcp/lang.h> +#include <isc-dhcp/list.h> +#include <isc-dhcp/types.h> + +ISC_LANG_BEGINDECLS + +typedef enum { + ISC_R_SUCCESS = 0, + ISC_R_NOMEMORY = 1, + ISC_R_TIMEDOUT = 2, + ISC_R_NOTHREADS = 3, + ISC_R_ADDRNOTAVAIL = 4, + ISC_R_ADDRINUSE = 5, + ISC_R_NOPERM = 6, + ISC_R_NOCONN = 7, + ISC_R_NETUNREACH = 8, + ISC_R_HOSTUNREACH = 9, + ISC_R_NETDOWN = 10, + ISC_R_HOSTDOWN = 11, + ISC_R_CONNREFUSED = 12, + ISC_R_NORESOURCES = 13, + ISC_R_EOF = 14, + ISC_R_BOUND = 15, + ISC_R_TASKDONE = 16, + ISC_R_LOCKBUSY = 17, + ISC_R_EXISTS = 18, + ISC_R_NOSPACE = 19, + ISC_R_CANCELED = 20, + ISC_R_TASKNOSEND = 21, + ISC_R_SHUTTINGDOWN = 22, + ISC_R_NOTFOUND = 23, + ISC_R_UNEXPECTEDEND = 24, + ISC_R_FAILURE = 25, + ISC_R_IOERROR = 26, + ISC_R_NOTIMPLEMENTED = 27, + ISC_R_UNBALANCED = 28, + ISC_R_NOMORE = 29, + ISC_R_INVALIDFILE = 30, + ISC_R_BADBASE64 = 31, + ISC_R_UNEXPECTEDTOKEN = 32, + ISC_R_QUOTA = 33, + ISC_R_UNEXPECTED = 34, + ISC_R_ALREADYRUNNING = 35, + ISC_R_HOSTUNKNOWN = 36, + ISC_R_VERSIONMISMATCH = 37, + ISC_R_PROTOCOLERROR = 38, + ISC_R_INVALIDARG = 39, + ISC_R_NOTCONNECTED = 40, + ISC_R_NOTYET = 41, + ISC_R_UNCHANGED = 42, + ISC_R_MULTIPLE = 43, + ISC_R_KEYCONFLICT = 44, + ISC_R_BADPARSE = 45, + ISC_R_NOKEYS = 46, + ISC_R_KEY_UNKNOWN = 47, + ISC_R_INVALIDKEY = 48, + ISC_R_INCOMPLETE = 49, + ISC_R_FORMERR = 50, + ISC_R_SERVFAIL = 51, + ISC_R_NXDOMAIN = 52, + ISC_R_NOTIMPL = 53, + ISC_R_REFUSED = 54, + ISC_R_YXDOMAIN = 55, + ISC_R_YXRRSET = 56, + ISC_R_NXRRSET = 57, + ISC_R_NOTAUTH = 58, + ISC_R_NOTZONE = 59, + ISC_R_BADSIG = 60, + ISC_R_BADKEY = 61, + ISC_R_BADTIME = 62, + ISC_R_NOROOTZONE = 63, + ISC_R_DESTADDRREQ = 64, + ISC_R_CROSSZONE = 65, + ISC_R_NO_TSIG = 66, + ISC_R_NOT_EQUAL = 67, + ISC_R_CONNRESET = 68, + ISC_R_UNKNOWNATTRIBUTE = 69 +} isc_result_t; + + +#define ISC_R_NRESULTS 70 /* Number of results */ + +const char * isc_result_totext(isc_result_t); +isc_result_t isc_result_register(unsigned int base, + unsigned int nresults, + char **text, + isc_msgcat_t *msgcat, + int set); + +ISC_LANG_ENDDECLS + +#endif /* ISC_RESULT_H */ diff --git a/contrib/isc-dhcp/includes/isc-dhcp/types.h b/contrib/isc-dhcp/includes/isc-dhcp/types.h new file mode 100644 index 0000000..862bd37 --- /dev/null +++ b/contrib/isc-dhcp/includes/isc-dhcp/types.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 1999 Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#ifndef ISC_TYPES_H +#define ISC_TYPES_H 1 + +#include <isc-dhcp/int.h> +#include <isc-dhcp/boolean.h> +#include <isc-dhcp/list.h> + +/*** + *** Core Types. + ***/ + +typedef struct isc_mem isc_mem_t; +typedef struct isc_mempool isc_mempool_t; +typedef struct isc_msgcat isc_msgcat_t; +typedef unsigned int isc_eventtype_t; +typedef struct isc_event isc_event_t; +typedef struct isc_task isc_task_t; +typedef struct isc_taskmgr isc_taskmgr_t; +typedef struct isc_rwlock isc_rwlock_t; + +typedef void (*isc_taskaction_t)(isc_task_t *, isc_event_t *); + +#endif /* ISC_TYPES_H */ diff --git a/contrib/isc-dhcp/includes/minires/minires.h b/contrib/isc-dhcp/includes/minires/minires.h new file mode 100644 index 0000000..2a6a133 --- /dev/null +++ b/contrib/isc-dhcp/includes/minires/minires.h @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2001 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, 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. + */ + +#include "cdefs.h" +#include "osdep.h" + +#include "minires/resolv.h" +#include "minires/res_update.h" +#include "isc-dhcp/result.h" + +/* + * Based on the Dynamic DNS reference implementation by Viraj Bais + * <viraj_bais@ccm.fm.intel.com> + */ + +int minires_mkupdate (ns_updrec *, unsigned char *, unsigned); +int minires_update (ns_updrec *); +ns_updrec *minires_mkupdrec (int, const char *, unsigned int, + unsigned int, unsigned long); +void minires_freeupdrec (ns_updrec *); +int minires_nmkupdate (res_state, ns_updrec *, double *, unsigned *); +isc_result_t minires_nupdate (res_state, ns_updrec *); +int minires_ninit (res_state); +ns_rcode isc_rcode_to_ns (isc_result_t); + +#if defined (MINIRES_LIB) +#define res_update minires_update +#define res_mkupdate minires_mkupdate +#define res_mkupdrec minires_mkupdrec +#define res_freeupdrec minires_freeupdrec +#define res_nmkupdate minires_nmkupdate +#define res_nupdate minires_nupdate +#define __p_type_syms MR__p_type_syms +#define dn_comp MRdn_comp +#define loc_aton MRloc_aton +#define sym_ston MRsym_ston +#define res_buildservicelist MRres_buildservicelist +#define res_destroyservicelist MRres_destroyservicelist +#define res_buildprotolist MRres_buildprotolist +#define res_destroyprotolist MRres_destroyprotolist +#define res_servicenumber MRres_servicenumber +#define res_protocolnumber MRres_protocolnumber +#define res_protocolname MRres_protocolname +#define res_servicename MRres_servicename +#define ns_datetosecs MRns_datetosecs +#define b64_pton MRb64_pton +#define res_ninit minires_ninit +#define res_randomid MRres_randomid +#define res_findzonecut MRres_findzonecut +#define res_nsend MRres_nsend +#define res_nsendsigned MRres_nsendsigned +#define ns_samename MRns_samename +#define res_nameinquery MRres_nameinquery +#define res_queriesmatch MRres_queriesmatch +#define dn_expand MRdn_expand +#define ns_get16 MRns_get16 +#define res_close MRres_close +#define res_nclose MRres_nclose +#define res_ourserver_p MRres_ourserver_p +#define ns_sign MRns_sign +#define p_class MRp_class +#define p_section MRp_section +#define ns_makecanon MRns_makecanon +#define ns_parserr MRns_parserr +#define ns_samedomain MRns_samedomain +#define ns_name_uncompress MRns_name_uncompress +#define res_nmkquery MRres_nmkquery +#define ns_initparse MRns_initparse +#define res_nquery MRres_nquery +#define res_nsearch MRres_nsearch +#define res_hostalias MRres_hostalias +#define res_nquerydomain MRres_nquerydomain +#define ns_skiprr MRns_skiprr +#define dn_skipname MRdn_skipname +#define ns_name_ntol MRns_name_ntol +#define ns_sign_tcp_init MRns_sign_tcp_init +#define ns_sign_tcp MRns_sign_tcp +#define ns_name_ntop MRns_name_ntop +#define ns_name_pton MRns_name_pton +#define ns_name_unpack MRns_name_unpack +#define ns_name_pack MRns_name_pack +#define ns_name_compress MRns_name_compress +#define ns_name_skip MRns_name_skip +#define ns_subdomain MRns_subdomain +#define ns_find_tsig MRns_find_tsig +#define ns_verify MRns_verify +#define ns_verify_tcp_init MRns_verify_tcp_init +#define ns_verify_tcp MRns_verify_tcp +#define b64_ntop MRb64_ntop + +extern const struct res_sym __p_type_syms[]; +extern time_t cur_time; + +int dn_comp (const char *, + unsigned char *, unsigned, unsigned char **, unsigned char **); +int loc_aton (const char *, u_char *); +int sym_ston (const struct res_sym *, const char *, int *); +void res_buildservicelist (void); +void res_destroyservicelist (void); +void res_buildprotolist(void); +void res_destroyprotolist(void); +int res_servicenumber(const char *); +int res_protocolnumber(const char *); +const char *res_protocolname(int); +const char *res_servicename(u_int16_t, const char *); +u_int32_t ns_datetosecs (const char *cp, int *errp); +int b64_pton (char const *, unsigned char *, size_t); +unsigned int res_randomid (void); +isc_result_t res_findzonecut (res_state, const char *, ns_class, int, char *, + size_t, struct in_addr *, int, int *, void *); +isc_result_t res_nsend (res_state, + double *, unsigned, double *, unsigned, unsigned *); +isc_result_t res_nsendsigned (res_state, double *, unsigned, ns_tsig_key *, + double *, unsigned, unsigned *); +int ns_samename (const char *, const char *); +int res_nameinquery (const char *, int, int, + const unsigned char *, const unsigned char *); +int res_queriesmatch (const unsigned char *, const unsigned char *, + const unsigned char *, const unsigned char *); +int dn_expand (const unsigned char *, + const unsigned char *, const unsigned char *, char *, unsigned); +unsigned int ns_get16 (const unsigned char *); +void res_close (void); +void res_nclose (res_state); +int res_ourserver_p (const res_state, const struct sockaddr_in *); +isc_result_t ns_sign (unsigned char *, unsigned *, + unsigned, int, void *, const unsigned char *, + unsigned, unsigned char *, unsigned *, time_t); +const char *p_class (int); +const char *p_section (int section, int opcode); +isc_result_t ns_makecanon (const char *, char *, size_t); +isc_result_t ns_parserr (ns_msg *, ns_sect, int, ns_rr *); +int ns_samedomain (const char *, const char *); +int ns_name_uncompress (const u_char *, const u_char *, + const u_char *, char *, size_t); +isc_result_t res_nmkquery (res_state, int, const char *, ns_class, ns_type, + const unsigned char *, unsigned, + const unsigned char *, double *, + unsigned, unsigned *); +int ns_initparse (const unsigned char *, unsigned, ns_msg *); +isc_result_t res_nquery(res_state, const char *, + ns_class, ns_type, double *, unsigned, unsigned *); +isc_result_t res_nsearch(res_state, const char *, + ns_class, ns_type, double *, unsigned, unsigned *); +const char *res_hostalias (const res_state, const char *, char *, size_t); +isc_result_t res_nquerydomain(res_state, const char *, const char *, + ns_class class, ns_type type, + double *, unsigned, unsigned *); + +int ns_skiprr(const unsigned char *, const unsigned char *, ns_sect, int); +int dn_skipname (const unsigned char *, const unsigned char *); +u_int32_t getULong (const unsigned char *); +int32_t getLong (const unsigned char *); +u_int32_t getUShort (const unsigned char *); +int32_t getShort (const unsigned char *); +u_int32_t getUChar (const unsigned char *); +void putULong (unsigned char *, u_int32_t); +void putLong (unsigned char *, int32_t); +void putUShort (unsigned char *, u_int32_t); +void putShort (unsigned char *, int32_t); +void putUChar (unsigned char *, u_int32_t); +int ns_name_ntol (const unsigned char *, unsigned char *, size_t); +isc_result_t ns_sign_tcp_init (void *, const unsigned char *, + unsigned, ns_tcp_tsig_state *); +isc_result_t ns_sign_tcp (unsigned char *, + unsigned *, unsigned, int, ns_tcp_tsig_state *, int); +int ns_name_ntop (const unsigned char *, char *, size_t); +int ns_name_pton (const char *, unsigned char *, size_t); +int ns_name_unpack (const unsigned char *, const unsigned char *, + const unsigned char *, unsigned char *, size_t); +int ns_name_pack (const unsigned char *, unsigned char *, + unsigned, const unsigned char **, const unsigned char **); +int ns_name_compress (const char *, unsigned char *, + size_t, const unsigned char **, const unsigned char **); +int ns_name_skip (const unsigned char **, const unsigned char *); +int ns_subdomain (const char *, const char *); +unsigned char *ns_find_tsig (unsigned char *, unsigned char *); +isc_result_t ns_verify (unsigned char *, unsigned *, void *, + const unsigned char *, + unsigned, unsigned char *, unsigned *, time_t *, int); +isc_result_t ns_verify_tcp_init (void *, const unsigned char *, unsigned, + ns_tcp_tsig_state *); +isc_result_t ns_verify_tcp (unsigned char *, unsigned *, + ns_tcp_tsig_state *, int); +int b64_ntop (unsigned char const *, size_t, char *, size_t); + +ns_rcode find_cached_zone (const char *, ns_class, char *, + size_t, struct in_addr *, int, int *, void *); +int find_tsig_key (ns_tsig_key **, const char *, void *); +int forget_zone (void *); +int repudiate_zone (void *); +void cache_found_zone (ns_class, char *, struct in_addr *, int); +isc_result_t uerr2isc (int); +isc_result_t ns_rcode_to_isc (int); + +#define DprintQ(a,b,c,d) +#define Dprint(a,b) +#define Perror(a, b, c, d) +#define Aerror(a, b, c, d, e) +#define DPRINTF(x) + +#define USE_MD5 +#endif + +#if defined (TRACING) +void trace_mr_statp_setup (res_state); +#endif diff --git a/contrib/isc-dhcp/includes/minires/res_update.h b/contrib/isc-dhcp/includes/minires/res_update.h new file mode 100644 index 0000000..45a5ac3 --- /dev/null +++ b/contrib/isc-dhcp/includes/minires/res_update.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1999 by Internet Software Consortium, Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, 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. + */ + +/* + * $Id: res_update.h,v 1.2.2.1 2001/05/17 20:47:28 mellon Exp $ + */ + +#ifndef __RES_UPDATE_H +#define __RES_UPDATE_H + +#include <sys/types.h> +#include "arpa/nameser.h" +#include <isc-dhcp/list.h> + +/* + * This RR-like structure is particular to UPDATE. + */ +typedef struct ns_updrec { + ISC_LINK(struct ns_updrec) r_link, r_glink; + ns_sect r_section; /* ZONE/PREREQUISITE/UPDATE */ + char *r_dname; /* owner of the RR */ + ns_class r_class; /* class number */ + ns_type r_type; /* type number */ + u_int32_t r_ttl; /* time to live */ + const unsigned char *r_data; /* rdata fields as text string */ + unsigned char *r_data_ephem; /* pointer to freeable r_data */ + unsigned int r_size; /* size of r_data field */ + int r_opcode; /* type of operation */ + /* following fields for private use by the resolver/server + routines */ + struct databuf *r_dp; /* databuf to process */ + struct databuf *r_deldp; /* databuf's deleted/overwritten */ + unsigned int r_zone; /* zone number on server */ +} ns_updrec; +typedef ISC_LIST(ns_updrec) ns_updque; + +#endif /*__RES_UPDATE_H*/ diff --git a/contrib/isc-dhcp/includes/minires/resolv.h b/contrib/isc-dhcp/includes/minires/resolv.h new file mode 100644 index 0000000..233971d --- /dev/null +++ b/contrib/isc-dhcp/includes/minires/resolv.h @@ -0,0 +1,314 @@ +/* + * Copyright (c) 1983, 1987, 1989 + * 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 the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, 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. + */ + +/* + * @(#)resolv.h 8.1 (Berkeley) 6/2/93 + * $Id: resolv.h,v 1.3 2000/07/17 20:54:12 mellon Exp $ + */ + +#ifndef _RESOLV_H_ +#define _RESOLV_H_ + +/* + * This used to be defined in res_query.c, now it's in herror.c. + * [XXX no it's not. It's in irs/irs_data.c] + * It was + * never extern'd by any *.h file before it was placed here. For thread + * aware programs, the last h_errno value set is stored in res->h_errno. + * + * XXX: There doesn't seem to be a good reason for exposing RES_SET_H_ERRNO + * (and __h_errno_set) to the public via <resolv.h>. + * XXX: __h_errno_set is really part of IRS, not part of the resolver. + * If somebody wants to build and use a resolver that doesn't use IRS, + * what do they do? Perhaps something like + * #ifdef WANT_IRS + * # define RES_SET_H_ERRNO(r,x) __h_errno_set(r,x) + * #else + * # define RES_SET_H_ERRNO(r,x) (h_errno = (r)->res_h_errno = (x)) + * #endif + */ + +#define RES_SET_H_ERRNO(r,x) __h_errno_set(r,x) +struct __res_state; /* forward */ +void __h_errno_set(struct __res_state *res, int err); + +/* + * Resolver configuration file. + * Normally not present, but may contain the address of the + * inital name server(s) to query and the domain search list. + */ + +#ifndef _PATH_RESCONF +#define _PATH_RESCONF "/etc/resolv.conf" +#endif + +typedef enum { res_goahead, res_nextns, res_modified, res_done, res_error } + res_sendhookact; + +typedef res_sendhookact (*res_send_qhook) (struct sockaddr_in * const *ns, + double **query, + unsigned *querylen, + double *ans, + unsigned anssiz, + int *resplen); + +typedef res_sendhookact (*res_send_rhook) (const struct sockaddr_in *ns, + double *query, + unsigned querylen, + double *ans, + unsigned anssiz, + int *resplen); + +struct res_sym { + int number; /* Identifying number, like T_MX */ + char * name; /* Its symbolic name, like "MX" */ + char * humanname; /* Its fun name, like "mail exchanger" */ +}; + +/* + * Global defines and variables for resolver stub. + */ +#define MAXNS 3 /* max # name servers we'll track */ +#define MAXDFLSRCH 3 /* # default domain levels to try */ +#define MAXDNSRCH 6 /* max # domains in search path */ +#define LOCALDOMAINPARTS 2 /* min levels in name that is "local" */ + +#define RES_TIMEOUT 5 /* min. seconds between retries */ +#define MAXRESOLVSORT 10 /* number of net to sort on */ +#define RES_MAXNDOTS 15 /* should reflect bit field size */ +#define RES_MAXRETRANS 30 /* only for resolv.conf/RES_OPTIONS */ +#define RES_MAXRETRY 5 /* only for resolv.conf/RES_OPTIONS */ +#define RES_DFLRETRY 2 /* Default #/tries. */ + +struct __res_state { + int retrans; /* retransmition time interval */ + int retry; /* number of times to retransmit */ + u_long options; /* option flags - see below. */ + int nscount; /* number of name servers */ + struct sockaddr_in + nsaddr_list[MAXNS]; /* address of name server */ +#define nsaddr nsaddr_list[0] /* for backward compatibility */ + u_short id; /* current message id */ + char *dnsrch[MAXDNSRCH+1]; /* components of domain to search */ + char defdname[256]; /* default domain (deprecated) */ + u_long pfcode; /* RES_PRF_ flags - see below. */ + unsigned ndots:4; /* threshold for initial abs. query */ + unsigned nsort:4; /* number of elements in sort_list[] */ + char unused[3]; + struct { + struct in_addr addr; + u_int32_t mask; + } sort_list[MAXRESOLVSORT]; + res_send_qhook qhook; /* query hook */ + res_send_rhook rhook; /* response hook */ + int res_h_errno; /* last one set for this context */ + int _sock; /* PRIVATE: for res_send i/o */ + u_int _flags; /* PRIVATE: see below */ + char pad[52]; /* On an i386 this means 512b total. */ +}; + +typedef struct __res_state *res_state; + +/* + * Resolver flags (used to be discrete per-module statics ints). + */ +#define RES_F_VC 0x00000001 /* socket is TCP */ +#define RES_F_CONN 0x00000002 /* socket is connected */ + +/* res_findzonecut() options */ +#define RES_EXHAUSTIVE 0x00000001 /* always do all queries */ + +/* + * Resolver options (keep these in synch with res_debug.c, please) + */ +#define RES_INIT 0x00000001 /* address initialized */ +#define RES_DEBUG 0x00000002 /* print debug messages */ +#define RES_AAONLY 0x00000004 /* authoritative answers only (!IMPL)*/ +#define RES_USEVC 0x00000008 /* use virtual circuit */ +#define RES_PRIMARY 0x00000010 /* query primary server only (!IMPL) */ +#define RES_IGNTC 0x00000020 /* ignore trucation errors */ +#define RES_RECURSE 0x00000040 /* recursion desired */ +#define RES_DEFNAMES 0x00000080 /* use default domain name */ +#define RES_STAYOPEN 0x00000100 /* Keep TCP socket open */ +#define RES_DNSRCH 0x00000200 /* search up local domain tree */ +#define RES_INSECURE1 0x00000400 /* type 1 security disabled */ +#define RES_INSECURE2 0x00000800 /* type 2 security disabled */ +#define RES_NOALIASES 0x00001000 /* shuts off HOSTALIASES feature */ +#define RES_USE_INET6 0x00002000 /* use/map IPv6 in gethostbyname() */ +#define RES_ROTATE 0x00004000 /* rotate ns list after each query */ +#define RES_NOCHECKNAME 0x00008000 /* do not check names for sanity. */ +#define RES_KEEPTSIG 0x00010000 /* do not strip TSIG records */ + +#define RES_DEFAULT (RES_RECURSE | RES_DEFNAMES | RES_DNSRCH) + +/* + * Resolver "pfcode" values. Used by dig. + */ +#define RES_PRF_STATS 0x00000001 +#define RES_PRF_UPDATE 0x00000002 +#define RES_PRF_CLASS 0x00000004 +#define RES_PRF_CMD 0x00000008 +#define RES_PRF_QUES 0x00000010 +#define RES_PRF_ANS 0x00000020 +#define RES_PRF_AUTH 0x00000040 +#define RES_PRF_ADD 0x00000080 +#define RES_PRF_HEAD1 0x00000100 +#define RES_PRF_HEAD2 0x00000200 +#define RES_PRF_TTLID 0x00000400 +#define RES_PRF_HEADX 0x00000800 +#define RES_PRF_QUERY 0x00001000 +#define RES_PRF_REPLY 0x00002000 +#define RES_PRF_INIT 0x00004000 +/* 0x00008000 */ + +#if 0 +/* Things involving an internal (static) resolver context. */ +#ifdef _REENTRANT +extern struct __res_state *__res_state(void); +#define _res (*__res_state()) +#else +#ifndef __BIND_NOSTATIC +extern struct __res_state _res; +#endif +#endif + +void fp_nquery (const u_char *, int, FILE *); +void fp_query (const u_char *, FILE *); +const char * hostalias (const char *); +void p_query (const u_char *); +void res_close (void); +int res_init (void); +int res_isourserver (const struct sockaddr_in *); +int res_mkquery (int, const char *, int, int, const u_char *, + int, const u_char *, u_char *, int); +int res_query (const char *, int, int, u_char *, int); +int res_querydomain (const char *, const char *, int, int, + u_char *, int); +int res_search (const char *, int, int, u_char *, int); +int res_send (const u_char *, int, u_char *, int); +int res_sendsigned (const u_char *, int, ns_tsig_key *, + u_char *, int); + +#if !defined(SHARED_LIBBIND) || defined(LIB) +/* + * If libbind is a shared object (well, DLL anyway) + * these externs break the linker when resolv.h is + * included by a lib client (like named) + * Make them go away if a client is including this + * + */ +extern const struct res_sym __p_key_syms[]; +extern const struct res_sym __p_cert_syms[]; +extern const struct res_sym __p_class_syms[]; +extern const struct res_sym __p_type_syms[]; +extern const struct res_sym __p_rcode_syms[]; +#endif /* SHARED_LIBBIND */ + +int res_hnok (const char *); +int res_ownok (const char *); +int res_mailok (const char *); +int res_dnok (const char *); +int sym_ston (const struct res_sym *, const char *, int *); +const char * sym_ntos (const struct res_sym *, int, int *); +const char * sym_ntop (const struct res_sym *, int, int *); +int b64_ntop (u_char const *, size_t, char *, size_t); +int b64_pton (char const *, u_char *, size_t); +int loc_aton (const char *ascii, u_char *binary); +const char * loc_ntoa (const u_char *binary, char *ascii); +int dn_skipname (const u_char *, const u_char *); +void putlong (u_int32_t, u_char *); +void putshort (u_int16_t, u_char *); +const char * p_class (int); +const char * p_time (u_int32_t); +const char * p_type (int); +const char * p_rcode (int); +const u_char * p_cdnname (const u_char *, const u_char *, int, FILE *); +const u_char * p_cdname (const u_char *, const u_char *, FILE *); +const u_char * p_fqnname (const u_char *cp, const u_char *msg, + int, char *, int); +const u_char * p_fqname (const u_char *, const u_char *, FILE *); +const char * p_option (u_long option); +char * p_secstodate (u_long); +int dn_count_labels (const char *); +int dn_expand (const u_char *, const u_char *, const u_char *, + char *, int); +u_int res_randomid (void); +int res_nameinquery (const char *, int, int, + const u_char *, const u_char *); +int res_queriesmatch (const u_char *, const u_char *, + const u_char *, const u_char *); +const char * p_section (int section, int opcode); +/* Things involving a resolver context. */ +int res_ninit (res_state); +int res_nisourserver (const res_state, + const struct sockaddr_in *); +void fp_resstat (const res_state, FILE *); +void res_npquery (const res_state, const u_char *, int, FILE *); +const char * res_hostalias (const res_state, const char *, + char *, size_t); +int res_nquery (res_state, + const char *, int, int, u_char *, int); +int res_nsearch (res_state, const char *, int, + int, u_char *, int); +int res_nquerydomain (res_state, + const char *, const char *, int, int, + u_char *, int); +int res_nmkquery (res_state, + int, const char *, int, int, const u_char *, + int, const u_char *, u_char *, int); +int res_nsend (res_state, const u_char *, int, u_char *, int); +int res_nsendsigned (res_state, const u_char *, int, + ns_tsig_key *, u_char *, int); +int res_findzonecut (res_state, const char *, ns_class, int, + char *, size_t, struct in_addr *, int); +void res_nclose (res_state); + +#endif /* 0 */ +#endif /* !_RESOLV_H_ */ diff --git a/contrib/isc-dhcp/includes/netinet/if_ether.h b/contrib/isc-dhcp/includes/netinet/if_ether.h index f61b18b..e53b4c7 100644 --- a/contrib/isc-dhcp/includes/netinet/if_ether.h +++ b/contrib/isc-dhcp/includes/netinet/if_ether.h @@ -48,28 +48,14 @@ struct ether_addr { */ #define ETHER_ADDR_LEN 6 -struct ether_header { +struct isc_ether_header { u_int8_t ether_dhost[ETHER_ADDR_LEN]; u_int8_t ether_shost[ETHER_ADDR_LEN]; u_int16_t ether_type; }; -#define ETHERTYPE_PUP 0x0200 /* PUP protocol */ -#define ETHERTYPE_IP 0x0800 /* IP protocol */ -#define ETHERTYPE_ARP 0x0806 /* address resolution protocol */ -#define ETHERTYPE_REVARP 0x8035 /* reverse addr resolution protocol */ - -/* - * The ETHERTYPE_NTRAILER packet types starting at ETHERTYPE_TRAIL have - * (type-ETHERTYPE_TRAIL)*512 bytes of data followed - * by an ETHER type (as given above) and then the (variable-length) header. - */ -#define ETHERTYPE_TRAIL 0x1000 /* Trailer packet */ -#define ETHERTYPE_NTRAILER 16 - -#define ETHER_IS_MULTICAST(addr) (*(addr) & 0x01) /* is address mcast/bcast? */ - -#define ETHERMTU 1500 -#define ETHERMIN (60-14) +#define ETHERTYPE_PUP 0x0200 /* PUP protocol */ +#define ETHERTYPE_IP 0x0800 /* IP protocol */ +#define ETHERTYPE_ARP 0x0806 /* address resolution protocol */ #define ETHER_HEADER_SIZE (ETHER_ADDR_LEN * 2 + sizeof (u_int16_t)) diff --git a/contrib/isc-dhcp/includes/netinet/ip.h b/contrib/isc-dhcp/includes/netinet/ip.h index 233abd6..0a1e358 100644 --- a/contrib/isc-dhcp/includes/netinet/ip.h +++ b/contrib/isc-dhcp/includes/netinet/ip.h @@ -49,14 +49,7 @@ * against negative integers quite easily, and fail in subtle ways. */ struct ip { -#if BYTE_ORDER == LITTLE_ENDIAN - u_int8_t ip_hl:4, /* header length */ - ip_v:4; /* version */ -#endif -#if BYTE_ORDER == BIG_ENDIAN - u_int8_t ip_v:4, /* version */ - ip_hl:4; /* header length */ -#endif + u_int8_t ip_fvhl; /* header length, version */ u_int8_t ip_tos; /* type of service */ int16_t ip_len; /* total length */ u_int16_t ip_id; /* identification */ @@ -70,6 +63,12 @@ struct ip { struct in_addr ip_src, ip_dst; /* source and dest address */ }; +#define IP_V(iph) ((iph)->ip_fvhl >> 4) +#define IP_HL(iph) (((iph)->ip_fvhl & 0x0F) << 2) +#define IP_V_SET(iph,x) ((iph)->ip_fvhl = ((iph)->ip_fvhl & 0x0F) | ((x) << 4)) +#define IP_HL_SET(iph,x) ((iph)->ip_fvhl = \ + ((iph)->ip_fvhl & 0xF0) | (((x) >> 2) & 0x0F)) + #define IP_MAXPACKET 65535 /* maximum packet size */ /* @@ -129,14 +128,7 @@ struct ip_timestamp { u_int8_t ipt_code; /* IPOPT_TS */ u_int8_t ipt_len; /* size of structure (variable) */ u_int8_t ipt_ptr; /* index of current entry */ -#if BYTE_ORDER == LITTLE_ENDIAN - u_int8_t ipt_flg:4, /* flags, see below */ - ipt_oflw:4; /* overflow counter */ -#endif -#if BYTE_ORDER == BIG_ENDIAN - u_int8_t ipt_oflw:4, /* overflow counter */ - ipt_flg:4; /* flags, see below */ -#endif + u_int8_t ipt_flg_oflw; /* flags, see below, overflow counter */ union ipt_timestamp { u_int32_t ipt_time[1]; struct ipt_ta { diff --git a/contrib/isc-dhcp/includes/netinet/udp.h b/contrib/isc-dhcp/includes/netinet/udp.h index c7964df..95bc044 100644 --- a/contrib/isc-dhcp/includes/netinet/udp.h +++ b/contrib/isc-dhcp/includes/netinet/udp.h @@ -42,6 +42,6 @@ struct udphdr { u_int16_t uh_sport; /* source port */ u_int16_t uh_dport; /* destination port */ - int16_t uh_ulen; /* udp length */ + u_int16_t uh_ulen; /* udp length */ u_int16_t uh_sum; /* udp checksum */ }; diff --git a/contrib/isc-dhcp/includes/omapip/alloc.h b/contrib/isc-dhcp/includes/omapip/alloc.h new file mode 100644 index 0000000..0c1efbf --- /dev/null +++ b/contrib/isc-dhcp/includes/omapip/alloc.h @@ -0,0 +1,120 @@ +/* alloc.h + + Definitions for the object management API protocol memory allocation... */ + +/* + * Copyright (c) 1996-2001 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. + */ + +isc_result_t omapi_buffer_new (omapi_buffer_t **, const char *, int); +isc_result_t omapi_buffer_reference (omapi_buffer_t **, + omapi_buffer_t *, const char *, int); +isc_result_t omapi_buffer_dereference (omapi_buffer_t **, const char *, int); + +#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \ + defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) +#define DMDOFFSET (sizeof (struct dmalloc_preamble)) +#define DMLFSIZE 16 +#define DMUFSIZE 16 +#define DMDSIZE (DMDOFFSET + DMLFSIZE + DMUFSIZE) + +struct dmalloc_preamble { + struct dmalloc_preamble *prev, *next; + const char *file; + int line; + size_t size; + unsigned long generation; + unsigned char low_fence [DMLFSIZE]; +}; +#else +#define DMDOFFSET 0 +#define DMDSIZE 0 +#endif + +/* rc_history flags... */ +#define RC_LEASE 1 +#define RC_MISC 2 + +#if defined (DEBUG_RC_HISTORY) +#if !defined (RC_HISTORY_MAX) +# define RC_HISTORY_MAX 256 +#endif + +#if !defined (RC_HISTORY_FLAGS) +# define RC_HISTORY_FLAGS (RC_LEASE | RC_MISC) +#endif + +struct rc_history_entry { + const char *file; + int line; + void *reference; + void *addr; + int refcnt; +}; + +#define rc_register(x, l, r, y, z, d, f) do { \ + if (RC_HISTORY_FLAGS & ~(f)) { \ + rc_history [rc_history_index].file = (x); \ + rc_history [rc_history_index].line = (l); \ + rc_history [rc_history_index].reference = (r); \ + rc_history [rc_history_index].addr = (y); \ + rc_history [rc_history_index].refcnt = (z); \ + rc_history_next (d); \ + } \ + } while (0) +#define rc_register_mdl(r, y, z, d, f) \ + rc_register (__FILE__, __LINE__, r, y, z, d, f) +#else +#define rc_register(file, line, reference, addr, refcnt, d, f) +#define rc_register_mdl(reference, addr, refcnt, d, f) +#endif + +#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \ + defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) +extern struct dmalloc_preamble *dmalloc_list; +extern unsigned long dmalloc_outstanding; +extern unsigned long dmalloc_longterm; +extern unsigned long dmalloc_generation; +extern unsigned long dmalloc_cutoff_generation; +#endif + +#if defined (DEBUG_RC_HISTORY) +extern struct rc_history_entry rc_history [RC_HISTORY_MAX]; +extern int rc_history_index; +extern int rc_history_count; +#endif diff --git a/contrib/isc-dhcp/includes/omapip/buffer.h b/contrib/isc-dhcp/includes/omapip/buffer.h new file mode 100644 index 0000000..1670555 --- /dev/null +++ b/contrib/isc-dhcp/includes/omapip/buffer.h @@ -0,0 +1,92 @@ +/* buffer.h + + Definitions for the object management API protocol buffering... */ + +/* + * Copyright (c) 1996-1999 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. + */ + +/* OMAPI buffers are ring buffers, which means that the beginning of the + buffer and the end of the buffer chase each other around. As long as + the tail never catches up to the head, there's room in the buffer for + data. + + - If the tail and the head are equal, the buffer is empty. + + - If the tail is less than the head, the contents of the buffer + are the bytes from the head to the end of buffer, and in addition, + the bytes between the beginning of the buffer and the tail, not + including the byte addressed by the tail. + + - If the tail is greater than the head, then the buffer contains + valid bytes starting with the byte addressed by the head, and + ending with the byte before the byte addressed by the tail. + + There will always be at least one byte of waste, because the tail can't + increase so that it's equal to the head (that would represent an empty + buffer. */ +#define OMAPI_BUF_SIZE 4048 +typedef struct _omapi_buffer { + struct _omapi_buffer *next; /* Buffers can be chained. */ + u_int32_t refcnt; /* Buffers are reference counted. */ + u_int16_t head, tail; /* Buffers are organized in a ring. */ + char buf [OMAPI_BUF_SIZE]; /* The actual buffer is included in + the buffer data structure. */ +} omapi_buffer_t; + +#define BUFFER_BYTES_FREE(x) \ + ((x) -> tail > (x) -> head \ + ? sizeof ((x) -> buf) - ((x) -> tail - (x) -> head) \ + : (x) -> head - (x) -> tail) + +#define BYTES_IN_BUFFER(x) \ + ((x) -> tail > (x) -> head \ + ? (x) -> tail - (x) -> head - 1 \ + : sizeof ((x) -> buf) - ((x) -> head - (x) -> tail) - 1) + +isc_result_t omapi_connection_require (omapi_object_t *, unsigned); +isc_result_t omapi_connection_copyout (unsigned char *, + omapi_object_t *, unsigned); +isc_result_t omapi_connection_copyin (omapi_object_t *, + const unsigned char *, unsigned); +isc_result_t omapi_connection_flush (omapi_object_t *); +isc_result_t omapi_connection_get_uint32 (omapi_object_t *, u_int32_t *); +isc_result_t omapi_connection_put_uint32 (omapi_object_t *, u_int32_t); +isc_result_t omapi_connection_get_uint16 (omapi_object_t *, u_int16_t *); +isc_result_t omapi_connection_put_uint16 (omapi_object_t *, u_int32_t); + diff --git a/contrib/isc-dhcp/includes/omapip/convert.h b/contrib/isc-dhcp/includes/omapip/convert.h new file mode 100644 index 0000000..b6d2d9f --- /dev/null +++ b/contrib/isc-dhcp/includes/omapip/convert.h @@ -0,0 +1,61 @@ +/* convert.h + + Safe copying of integers into and out of a non-aligned memory buffer. */ + +/* + * Copyright (c) 1996-1999 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. + */ + +#ifndef OMAPI_CONVERT_H +#define OMAPI_CONVERT_H + +u_int32_t getULong (const unsigned char *); +int32_t getLong (const unsigned char *); +u_int32_t getUShort (const unsigned char *); +int32_t getShort (const unsigned char *); +u_int32_t getUChar (const unsigned char *); +void putULong (unsigned char *, u_int32_t); +void putLong (unsigned char *, int32_t); +void putUShort (unsigned char *, u_int32_t); +void putShort (unsigned char *, int32_t); +void putUChar (unsigned char *, u_int32_t); +int converted_length (const unsigned char *, unsigned int, unsigned int); +int binary_to_ascii (unsigned char *, const unsigned char *, + unsigned int, unsigned int); + +#endif /* OMAPI_CONVERT_H */ diff --git a/contrib/isc-dhcp/includes/omapip/hash.h b/contrib/isc-dhcp/includes/omapip/hash.h new file mode 100644 index 0000000..5ad2305 --- /dev/null +++ b/contrib/isc-dhcp/includes/omapip/hash.h @@ -0,0 +1,159 @@ +/* hash.h + + Definitions for hashing... */ + +/* + * Copyright (c) 1995-2001 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. + */ + +#ifndef OMAPI_HASH_H +#define OMAPI_HASH_H + +#define DEFAULT_HASH_SIZE 9973 + +/* The purpose of the hashed_object_t struct is to not match anything else. */ +typedef struct { + int foo; +} hashed_object_t; + +typedef void (*hash_foreach_func) (const unsigned char *, + unsigned, hashed_object_t *); +typedef int (*hash_reference) (hashed_object_t **, hashed_object_t *, + const char *, int); +typedef int (*hash_dereference) (hashed_object_t **, const char *, int); + +struct hash_bucket { + struct hash_bucket *next; + const unsigned char *name; + unsigned len; + hashed_object_t *value; +}; + +typedef int (*hash_comparator_t)(const void *, const void *, unsigned long); + +struct hash_table { + unsigned hash_count; + struct hash_bucket *buckets [DEFAULT_HASH_SIZE]; + hash_reference referencer; + hash_dereference dereferencer; + hash_comparator_t cmp; + int (*do_hash) (const unsigned char *, unsigned, unsigned); +}; + +struct named_hash { + struct named_hash *next; + const char *name; + struct hash_table *hash; +}; + +#define HASH_FUNCTIONS_DECL(name, bufarg, type, hashtype) \ +void name##_hash_add (hashtype *, bufarg, unsigned, type *, \ + const char *, int); \ +void name##_hash_delete (hashtype *, bufarg, unsigned, \ + const char *, int); \ +int name##_hash_lookup (type **, hashtype *, bufarg, unsigned, \ + const char *, int); \ +int name##_hash_foreach (hashtype *, \ + void (*) (bufarg, unsigned, type *)); \ +int name##_new_hash (hashtype **, int, const char *, int); \ +void name##_free_hash_table (hashtype **, const char *, int); + + +#define HASH_FUNCTIONS(name, bufarg, type, hashtype, ref, deref) \ +void name##_hash_add (hashtype *table, \ + bufarg buf, unsigned len, type *ptr, \ + const char *file, int line) \ +{ \ + add_hash ((struct hash_table *)table, \ + (const unsigned char *)buf, \ + len, (hashed_object_t *)ptr, file, line); \ +} \ + \ +void name##_hash_delete (hashtype *table, \ + bufarg buf, unsigned len, const char *file, int line)\ +{ \ + delete_hash_entry ((struct hash_table *)table, \ + (const unsigned char *)buf, \ + len, file, line); \ +} \ + \ +int name##_hash_lookup (type **ptr, hashtype *table, \ + bufarg buf, unsigned len, const char *file, int line) \ +{ \ + return hash_lookup ((hashed_object_t **)ptr, \ + (struct hash_table *)table, \ + (const unsigned char *)buf, len, file, line); \ +} \ + \ +int name##_hash_foreach (hashtype *table, \ + void (*func) (bufarg, unsigned, type *)) \ +{ \ + return hash_foreach ((struct hash_table *)table, \ + (hash_foreach_func)func); \ +} \ + \ +int name##_new_hash (hashtype **tp, int c, const char *file, int line) \ +{ \ + return new_hash ((struct hash_table **)tp, \ + (hash_reference)ref, (hash_dereference)deref, c, \ + file, line); \ +} \ + \ +void name##_free_hash_table (hashtype **table, const char *file, int line) \ +{ \ + free_hash_table ((struct hash_table **)table, file, line); \ +} + +void relinquish_hash_bucket_hunks (void); +int new_hash_table (struct hash_table **, int, const char *, int); +void free_hash_table (struct hash_table **, const char *, int); +struct hash_bucket *new_hash_bucket (const char *, int); +void free_hash_bucket (struct hash_bucket *, const char *, int); +int new_hash (struct hash_table **, + hash_reference, hash_dereference, int, const char *, int); +void add_hash (struct hash_table *, + const unsigned char *, unsigned, hashed_object_t *, + const char *, int); +void delete_hash_entry (struct hash_table *, const unsigned char *, + unsigned, const char *, int); +int hash_lookup (hashed_object_t **, struct hash_table *, + const unsigned char *, unsigned, const char *, int); +int hash_foreach (struct hash_table *, hash_foreach_func); +int casecmp (const void *s, const void *t, unsigned long len); + +#endif /* OMAPI_HASH_H */ diff --git a/contrib/isc-dhcp/includes/omapip/omapip.h b/contrib/isc-dhcp/includes/omapip/omapip.h new file mode 100644 index 0000000..7f51c3f --- /dev/null +++ b/contrib/isc-dhcp/includes/omapip/omapip.h @@ -0,0 +1,620 @@ +/* omapip.h + + Definitions for the object management API and protocol... */ + +/* + * Copyright (c) 1996-2001 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. + */ + +#ifndef _OMAPIP_H_ +#define _OMAPIP_H_ +#include <isc-dhcp/result.h> + +typedef unsigned int omapi_handle_t; + +struct __omapi_object; +typedef struct __omapi_object omapi_object_t; + +typedef enum { + omapi_datatype_int, + omapi_datatype_string, + omapi_datatype_data, + omapi_datatype_object +} omapi_datatype_t; + +typedef struct { + int refcnt; + omapi_datatype_t type; + union { + struct { + unsigned len; +#define OMAPI_TYPED_DATA_NOBUFFER_LEN (sizeof (int) + \ + sizeof (omapi_datatype_t) + \ + sizeof (int)) + unsigned char value [1]; + } buffer; +#define OMAPI_TYPED_DATA_OBJECT_LEN (sizeof (int) + \ + sizeof (omapi_datatype_t) + \ + sizeof (omapi_object_t *)) + omapi_object_t *object; +#define OMAPI_TYPED_DATA_REF_LEN (sizeof (int) + \ + sizeof (omapi_datatype_t) + \ + 3 * sizeof (void *)) + struct { + void *ptr; + isc_result_t (*reference) (void *, + void *, const char *, int); + isc_result_t (*dereference) (void *, + const char *, int); + } ref; +#define OMAPI_TYPED_DATA_INT_LEN (sizeof (int) + \ + sizeof (omapi_datatype_t) + \ + sizeof (int)) + int integer; + } u; +} omapi_typed_data_t; + +typedef struct { + int refcnt; + unsigned len; +#define OMAPI_DATA_STRING_EMPTY_SIZE (2 * sizeof (int)) + unsigned char value [1]; +} omapi_data_string_t; + +typedef struct { + int refcnt; + omapi_data_string_t *name; + omapi_typed_data_t *value; +} omapi_value_t; + +typedef struct __omapi_object_type_t { + const char *name; + struct __omapi_object_type_t *next; + + isc_result_t (*set_value) (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, + omapi_typed_data_t *); + isc_result_t (*get_value) (omapi_object_t *, + omapi_object_t *, + omapi_data_string_t *, omapi_value_t **); + isc_result_t (*destroy) (omapi_object_t *, const char *, int); + isc_result_t (*signal_handler) (omapi_object_t *, + const char *, va_list); + isc_result_t (*stuff_values) (omapi_object_t *, + omapi_object_t *, omapi_object_t *); + isc_result_t (*lookup) (omapi_object_t **, omapi_object_t *, + omapi_object_t *); + isc_result_t (*create) (omapi_object_t **, omapi_object_t *); + isc_result_t (*remove) (omapi_object_t *, omapi_object_t *); + isc_result_t (*freer) (omapi_object_t *, const char *, int); + isc_result_t (*allocator) (omapi_object_t **, const char *, int); + isc_result_t (*sizer) (size_t); + size_t size; + int rc_flag; + isc_result_t (*initialize) (omapi_object_t *, const char *, int); +} omapi_object_type_t; + +#define OMAPI_OBJECT_PREAMBLE \ + omapi_object_type_t *type; \ + int refcnt; \ + omapi_handle_t handle; \ + omapi_object_t *outer, *inner + +/* The omapi handle structure. */ +struct __omapi_object { + OMAPI_OBJECT_PREAMBLE; +}; + +/* The port on which applications should listen for OMAPI connections. */ +#define OMAPI_PROTOCOL_PORT 7911 + +typedef struct { + unsigned addrtype; + unsigned addrlen; + unsigned char address [16]; + unsigned port; +} omapi_addr_t; + +typedef struct { + int refcnt; + unsigned count; + omapi_addr_t *addresses; +} omapi_addr_list_t; + +typedef struct auth_key { + OMAPI_OBJECT_PREAMBLE; + char *name; + char *algorithm; + omapi_data_string_t *key; +} omapi_auth_key_t; + +#define OMAPI_CREATE 1 +#define OMAPI_UPDATE 2 +#define OMAPI_EXCL 4 +#define OMAPI_NOTIFY_PROTOCOL 8 + +#define OMAPI_OBJECT_ALLOC(name, stype, type) \ +isc_result_t name##_allocate (stype **p, const char *file, int line) \ +{ \ + return omapi_object_allocate ((omapi_object_t **)p, \ + type, 0, file, line); \ +} \ + \ +isc_result_t name##_reference (stype **pptr, stype *ptr, \ + const char *file, int line) \ +{ \ + return omapi_object_reference ((omapi_object_t **)pptr, \ + (omapi_object_t *)ptr, file, line); \ +} \ + \ +isc_result_t name##_dereference (stype **ptr, const char *file, int line) \ +{ \ + return omapi_object_dereference ((omapi_object_t **)ptr, file, line); \ +} + +#define OMAPI_OBJECT_ALLOC_DECL(name, stype, type) \ +isc_result_t name##_allocate (stype **p, const char *file, int line); \ +isc_result_t name##_reference (stype **pptr, stype *ptr, \ + const char *file, int line); \ +isc_result_t name##_dereference (stype **ptr, const char *file, int line); + +typedef isc_result_t (*omapi_array_ref_t) (char **, char *, const char *, int); +typedef isc_result_t (*omapi_array_deref_t) (char **, const char *, int); + +/* An extensible array type. */ +typedef struct { + char **data; + omapi_array_ref_t ref; + omapi_array_deref_t deref; + int count; + int max; +} omapi_array_t; + +#define OMAPI_ARRAY_TYPE(name, stype) \ +isc_result_t name##_array_allocate (omapi_array_t **p, \ + const char *file, int line) \ +{ \ + return (omapi_array_allocate \ + (p, \ + (omapi_array_ref_t)name##_reference, \ + (omapi_array_deref_t)name##_dereference, \ + file, line)); \ +} \ + \ +isc_result_t name##_array_free (omapi_array_t **p, \ + const char *file, int line) \ +{ \ + return omapi_array_free (p, file, line); \ +} \ + \ +isc_result_t name##_array_extend (omapi_array_t *pptr, stype *ptr, int *index,\ + const char *file, int line) \ +{ \ + return omapi_array_extend (pptr, (char *)ptr, index, file, line); \ +} \ + \ +isc_result_t name##_array_set (omapi_array_t *pptr, stype *ptr, int index, \ + const char *file, int line) \ +{ \ + return omapi_array_set (pptr, (char *)ptr, index, file, line); \ +} \ + \ +isc_result_t name##_array_lookup (stype **ptr, omapi_array_t *pptr, \ + int index, const char *file, int line) \ +{ \ + return omapi_array_lookup ((char **)ptr, pptr, index, file, line); \ +} + +#define OMAPI_ARRAY_TYPE_DECL(name, stype) \ +isc_result_t name##_array_allocate (omapi_array_t **, const char *, int); \ +isc_result_t name##_array_free (omapi_array_t **, const char *, int); \ +isc_result_t name##_array_extend (omapi_array_t *, stype *, int *, \ + const char *, int); \ +isc_result_t name##_array_set (omapi_array_t *, \ + stype *, int, const char *, int); \ +isc_result_t name##_array_lookup (stype **, \ + omapi_array_t *, int, const char *, int) + +#define omapi_array_foreach_begin(array, stype, var) \ + { \ + int omapi_array_foreach_index; \ + stype *var = (stype *)0; \ + for (omapi_array_foreach_index = 0; \ + array && \ + omapi_array_foreach_index < (array) -> count; \ + omapi_array_foreach_index++) { \ + if ((array) -> data [omapi_array_foreach_index]) { \ + ((*(array) -> ref) \ + ((char **)&var, \ + (array) -> data [omapi_array_foreach_index],\ + MDL)); + +#define omapi_array_foreach_end(array, stype, var) \ + (*(array) -> deref) ((char **)&var, MDL); \ + } \ + } \ + } + +isc_result_t omapi_protocol_connect (omapi_object_t *, + const char *, unsigned, omapi_object_t *); +isc_result_t omapi_connect_list (omapi_object_t *, omapi_addr_list_t *, + omapi_addr_t *); +isc_result_t omapi_protocol_listen (omapi_object_t *, unsigned, int); +isc_boolean_t omapi_protocol_authenticated (omapi_object_t *); +isc_result_t omapi_protocol_configure_security (omapi_object_t *, + isc_result_t (*) + (omapi_object_t *, + omapi_addr_t *), + isc_result_t (*) + (omapi_object_t *, + omapi_auth_key_t *)); +isc_result_t omapi_protocol_accept (omapi_object_t *); +isc_result_t omapi_protocol_send_intro (omapi_object_t *, unsigned, unsigned); +isc_result_t omapi_protocol_ready (omapi_object_t *); +isc_result_t omapi_protocol_add_auth (omapi_object_t *, omapi_object_t *, + omapi_handle_t); +isc_result_t omapi_protocol_lookup_auth (omapi_object_t **, omapi_object_t *, + omapi_handle_t); +isc_result_t omapi_protocol_set_value (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, + omapi_typed_data_t *); +isc_result_t omapi_protocol_get_value (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, + omapi_value_t **); +isc_result_t omapi_protocol_stuff_values (omapi_object_t *, + omapi_object_t *, + omapi_object_t *); + +isc_result_t omapi_protocol_destroy (omapi_object_t *, const char *, int); +isc_result_t omapi_protocol_send_message (omapi_object_t *, + omapi_object_t *, + omapi_object_t *, + omapi_object_t *); +isc_result_t omapi_protocol_signal_handler (omapi_object_t *, + const char *, va_list); +isc_result_t omapi_protocol_listener_set_value (omapi_object_t *, + omapi_object_t *, + omapi_data_string_t *, + omapi_typed_data_t *); +isc_result_t omapi_protocol_listener_get_value (omapi_object_t *, + omapi_object_t *, + omapi_data_string_t *, + omapi_value_t **); +isc_result_t omapi_protocol_listener_destroy (omapi_object_t *, + const char *, int); +isc_result_t omapi_protocol_listener_signal (omapi_object_t *, + const char *, va_list); +isc_result_t omapi_protocol_listener_stuff (omapi_object_t *, + omapi_object_t *, + omapi_object_t *); +isc_result_t omapi_protocol_send_status (omapi_object_t *, omapi_object_t *, + isc_result_t, unsigned, const char *); +isc_result_t omapi_protocol_send_open (omapi_object_t *, omapi_object_t *, + const char *, omapi_object_t *, + unsigned); +isc_result_t omapi_protocol_send_update (omapi_object_t *, omapi_object_t *, + unsigned, omapi_object_t *); + +isc_result_t omapi_connect (omapi_object_t *, const char *, unsigned); +isc_result_t omapi_disconnect (omapi_object_t *, int); +int omapi_connection_readfd (omapi_object_t *); +int omapi_connection_writefd (omapi_object_t *); +isc_result_t omapi_connection_connect (omapi_object_t *); +isc_result_t omapi_connection_reader (omapi_object_t *); +isc_result_t omapi_connection_writer (omapi_object_t *); +isc_result_t omapi_connection_reaper (omapi_object_t *); +isc_result_t omapi_connection_output_auth_length (omapi_object_t *, + unsigned *); +isc_result_t omapi_connection_set_value (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, + omapi_typed_data_t *); +isc_result_t omapi_connection_get_value (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, + omapi_value_t **); +isc_result_t omapi_connection_destroy (omapi_object_t *, const char *, int); +isc_result_t omapi_connection_signal_handler (omapi_object_t *, + const char *, va_list); +isc_result_t omapi_connection_stuff_values (omapi_object_t *, + omapi_object_t *, + omapi_object_t *); +isc_result_t omapi_connection_write_typed_data (omapi_object_t *, + omapi_typed_data_t *); +isc_result_t omapi_connection_put_name (omapi_object_t *, const char *); +isc_result_t omapi_connection_put_string (omapi_object_t *, const char *); +isc_result_t omapi_connection_put_handle (omapi_object_t *c, + omapi_object_t *h); + +isc_result_t omapi_listen (omapi_object_t *, unsigned, int); +isc_result_t omapi_listen_addr (omapi_object_t *, + omapi_addr_t *, int); +isc_result_t omapi_listener_accept (omapi_object_t *); +int omapi_listener_readfd (omapi_object_t *); +isc_result_t omapi_accept (omapi_object_t *); +isc_result_t omapi_listener_configure_security (omapi_object_t *, + isc_result_t (*) + (omapi_object_t *, + omapi_addr_t *)); +isc_result_t omapi_listener_set_value (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, + omapi_typed_data_t *); +isc_result_t omapi_listener_get_value (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, + omapi_value_t **); +isc_result_t omapi_listener_destroy (omapi_object_t *, const char *, int); +isc_result_t omapi_listener_signal_handler (omapi_object_t *, + const char *, va_list); +isc_result_t omapi_listener_stuff_values (omapi_object_t *, + omapi_object_t *, + omapi_object_t *); + +isc_result_t omapi_register_io_object (omapi_object_t *, + int (*)(omapi_object_t *), + int (*)(omapi_object_t *), + isc_result_t (*)(omapi_object_t *), + isc_result_t (*)(omapi_object_t *), + isc_result_t (*)(omapi_object_t *)); +isc_result_t omapi_unregister_io_object (omapi_object_t *); +isc_result_t omapi_dispatch (struct timeval *); +isc_result_t omapi_wait_for_completion (omapi_object_t *, struct timeval *); +isc_result_t omapi_one_dispatch (omapi_object_t *, struct timeval *); +isc_result_t omapi_io_set_value (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, + omapi_typed_data_t *); +isc_result_t omapi_io_get_value (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, omapi_value_t **); +isc_result_t omapi_io_destroy (omapi_object_t *, const char *, int); +isc_result_t omapi_io_signal_handler (omapi_object_t *, const char *, va_list); +isc_result_t omapi_io_stuff_values (omapi_object_t *, + omapi_object_t *, + omapi_object_t *); +isc_result_t omapi_waiter_signal_handler (omapi_object_t *, + const char *, va_list); +isc_result_t omapi_io_state_foreach (isc_result_t (*func) (omapi_object_t *, + void *), + void *p); + +isc_result_t omapi_generic_new (omapi_object_t **, const char *, int); +isc_result_t omapi_generic_set_value (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, + omapi_typed_data_t *); +isc_result_t omapi_generic_get_value (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, + omapi_value_t **); +isc_result_t omapi_generic_destroy (omapi_object_t *, const char *, int); +isc_result_t omapi_generic_signal_handler (omapi_object_t *, + const char *, va_list); +isc_result_t omapi_generic_stuff_values (omapi_object_t *, + omapi_object_t *, + omapi_object_t *); +isc_result_t omapi_generic_clear_flags (omapi_object_t *); + +isc_result_t omapi_message_new (omapi_object_t **, const char *, int); +isc_result_t omapi_message_set_value (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, + omapi_typed_data_t *); +isc_result_t omapi_message_get_value (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, + omapi_value_t **); +isc_result_t omapi_message_destroy (omapi_object_t *, const char *, int); +isc_result_t omapi_message_signal_handler (omapi_object_t *, + const char *, va_list); +isc_result_t omapi_message_stuff_values (omapi_object_t *, + omapi_object_t *, + omapi_object_t *); +isc_result_t omapi_message_register (omapi_object_t *); +isc_result_t omapi_message_unregister (omapi_object_t *); +isc_result_t omapi_message_process (omapi_object_t *, omapi_object_t *); + +OMAPI_OBJECT_ALLOC_DECL (omapi_auth_key, + omapi_auth_key_t, omapi_type_auth_key) +isc_result_t omapi_auth_key_new (omapi_auth_key_t **, const char *, int); +isc_result_t omapi_auth_key_destroy (omapi_object_t *, const char *, int); +isc_result_t omapi_auth_key_enter (omapi_auth_key_t *); +isc_result_t omapi_auth_key_lookup_name (omapi_auth_key_t **, const char *); +isc_result_t omapi_auth_key_lookup (omapi_object_t **, + omapi_object_t *, + omapi_object_t *); +isc_result_t omapi_auth_key_get_value (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, + omapi_value_t **); +isc_result_t omapi_auth_key_stuff_values (omapi_object_t *, + omapi_object_t *, + omapi_object_t *); + +extern omapi_object_type_t *omapi_type_connection; +extern omapi_object_type_t *omapi_type_listener; +extern omapi_object_type_t *omapi_type_io_object; +extern omapi_object_type_t *omapi_type_generic; +extern omapi_object_type_t *omapi_type_protocol; +extern omapi_object_type_t *omapi_type_protocol_listener; +extern omapi_object_type_t *omapi_type_waiter; +extern omapi_object_type_t *omapi_type_remote; +extern omapi_object_type_t *omapi_type_message; +extern omapi_object_type_t *omapi_type_auth_key; + +extern omapi_object_type_t *omapi_object_types; + +void omapi_type_relinquish (void); +isc_result_t omapi_init (void); +isc_result_t omapi_object_type_register (omapi_object_type_t **, + const char *, + isc_result_t (*) + (omapi_object_t *, + omapi_object_t *, + omapi_data_string_t *, + omapi_typed_data_t *), + isc_result_t (*) + (omapi_object_t *, + omapi_object_t *, + omapi_data_string_t *, + omapi_value_t **), + isc_result_t (*) (omapi_object_t *, + const char *, int), + isc_result_t (*) (omapi_object_t *, + const char *, + va_list), + isc_result_t (*) (omapi_object_t *, + omapi_object_t *, + omapi_object_t *), + isc_result_t (*) (omapi_object_t **, + omapi_object_t *, + omapi_object_t *), + isc_result_t (*) (omapi_object_t **, + omapi_object_t *), + isc_result_t (*) (omapi_object_t *, + omapi_object_t *), + isc_result_t (*) (omapi_object_t *, + const char *, int), + isc_result_t (*) (omapi_object_t **, + const char *, int), + isc_result_t (*) (size_t), size_t, + isc_result_t (*) (omapi_object_t *, + const char *, int), + int); +isc_result_t omapi_signal (omapi_object_t *, const char *, ...); +isc_result_t omapi_signal_in (omapi_object_t *, const char *, ...); +isc_result_t omapi_set_value (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, + omapi_typed_data_t *); +isc_result_t omapi_set_value_str (omapi_object_t *, omapi_object_t *, + const char *, omapi_typed_data_t *); +isc_result_t omapi_set_boolean_value (omapi_object_t *, omapi_object_t *, + const char *, int); +isc_result_t omapi_set_int_value (omapi_object_t *, omapi_object_t *, + const char *, int); +isc_result_t omapi_set_object_value (omapi_object_t *, omapi_object_t *, + const char *, omapi_object_t *); +isc_result_t omapi_set_string_value (omapi_object_t *, omapi_object_t *, + const char *, const char *); +isc_result_t omapi_get_value (omapi_object_t *, omapi_object_t *, + omapi_data_string_t *, + omapi_value_t **); +isc_result_t omapi_get_value_str (omapi_object_t *, omapi_object_t *, + const char *, omapi_value_t **); +isc_result_t omapi_stuff_values (omapi_object_t *, + omapi_object_t *, + omapi_object_t *); +isc_result_t omapi_object_create (omapi_object_t **, omapi_object_t *, + omapi_object_type_t *); +isc_result_t omapi_object_update (omapi_object_t *, omapi_object_t *, + omapi_object_t *, omapi_handle_t); +int omapi_data_string_cmp (omapi_data_string_t *, omapi_data_string_t *); +int omapi_ds_strcmp (omapi_data_string_t *, const char *); +int omapi_td_strcmp (omapi_typed_data_t *, const char *); +int omapi_td_strcasecmp (omapi_typed_data_t *, const char *); +isc_result_t omapi_make_value (omapi_value_t **, omapi_data_string_t *, + omapi_typed_data_t *, const char *, int); +isc_result_t omapi_make_const_value (omapi_value_t **, omapi_data_string_t *, + const unsigned char *, + unsigned, const char *, int); +isc_result_t omapi_make_int_value (omapi_value_t **, omapi_data_string_t *, + int, const char *, int); +isc_result_t omapi_make_uint_value (omapi_value_t **, omapi_data_string_t *, + unsigned int, const char *, int); +isc_result_t omapi_make_object_value (omapi_value_t **, omapi_data_string_t *, + omapi_object_t *, const char *, int); +isc_result_t omapi_make_handle_value (omapi_value_t **, omapi_data_string_t *, + omapi_object_t *, const char *, int); +isc_result_t omapi_make_string_value (omapi_value_t **, omapi_data_string_t *, + const char *, const char *, int); +isc_result_t omapi_get_int_value (unsigned long *, omapi_typed_data_t *); + +isc_result_t omapi_object_handle (omapi_handle_t *, omapi_object_t *); +isc_result_t omapi_handle_lookup (omapi_object_t **, omapi_handle_t); +isc_result_t omapi_handle_td_lookup (omapi_object_t **, omapi_typed_data_t *); + +void * dmalloc (unsigned, const char *, int); +void dfree (void *, const char *, int); +#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \ + defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) +void dmalloc_reuse (void *, const char *, int, int); +void dmalloc_dump_outstanding (void); +#else +#define dmalloc_reuse(x,y,l,z) +#endif +#define MDL __FILE__, __LINE__ +#if defined (DEBUG_RC_HISTORY) +void dump_rc_history (void *); +void rc_history_next (int); +#endif +void omapi_print_dmalloc_usage_by_caller (void); +isc_result_t omapi_object_allocate (omapi_object_t **, + omapi_object_type_t *, + size_t, const char *, int); +isc_result_t omapi_object_initialize (omapi_object_t *, + omapi_object_type_t *, + size_t, size_t, const char *, int); +isc_result_t omapi_object_reference (omapi_object_t **, + omapi_object_t *, const char *, int); +isc_result_t omapi_object_dereference (omapi_object_t **, const char *, int); +isc_result_t omapi_typed_data_new (const char *, int, omapi_typed_data_t **, + omapi_datatype_t, ...); +isc_result_t omapi_typed_data_reference (omapi_typed_data_t **, + omapi_typed_data_t *, + const char *, int); +isc_result_t omapi_typed_data_dereference (omapi_typed_data_t **, + const char *, int); +isc_result_t omapi_data_string_new (omapi_data_string_t **, + unsigned, const char *, int); +isc_result_t omapi_data_string_reference (omapi_data_string_t **, + omapi_data_string_t *, + const char *, int); +isc_result_t omapi_data_string_dereference (omapi_data_string_t **, + const char *, int); +isc_result_t omapi_value_new (omapi_value_t **, const char *, int); +isc_result_t omapi_value_reference (omapi_value_t **, + omapi_value_t *, const char *, int); +isc_result_t omapi_value_dereference (omapi_value_t **, const char *, int); +isc_result_t omapi_addr_list_new (omapi_addr_list_t **, unsigned, + const char *, int); +isc_result_t omapi_addr_list_reference (omapi_addr_list_t **, + omapi_addr_list_t *, + const char *, int); +isc_result_t omapi_addr_list_dereference (omapi_addr_list_t **, + const char *, int); + +isc_result_t omapi_array_allocate (omapi_array_t **, omapi_array_ref_t, + omapi_array_deref_t, const char *, int); +isc_result_t omapi_array_free (omapi_array_t **, const char *, int); +isc_result_t omapi_array_extend (omapi_array_t *, char *, int *, + const char *, int); +isc_result_t omapi_array_set (omapi_array_t *, void *, int, const char *, int); +isc_result_t omapi_array_lookup (char **, + omapi_array_t *, int, const char *, int); +OMAPI_ARRAY_TYPE_DECL(omapi_object, omapi_object_t); +#endif /* _OMAPIP_H_ */ diff --git a/contrib/isc-dhcp/includes/omapip/omapip_p.h b/contrib/isc-dhcp/includes/omapip/omapip_p.h new file mode 100644 index 0000000..d64df0e --- /dev/null +++ b/contrib/isc-dhcp/includes/omapip/omapip_p.h @@ -0,0 +1,302 @@ +/* omapip_p.h + + Private master include file for the OMAPI library. */ + +/* + * Copyright (c) 1996-2001 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. + */ + +#ifndef __OMAPIP_OMAPIP_P_H__ +#define __OMAPIP_OMAPIP_P_H__ + +#ifndef __CYGWIN32__ +#include <sys/types.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <arpa/inet.h> + +#include <netdb.h> +#else +#define fd_set cygwin_fd_set +#include <sys/types.h> +#endif +#include <fcntl.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <memory.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <ctype.h> +#include <time.h> + +#include "cdefs.h" +#include "osdep.h" + +#include <isc-dhcp/dst.h> +#include <isc-dhcp/result.h> + +#include <omapip/convert.h> +#include <omapip/hash.h> +#include <omapip/omapip.h> +#include <omapip/trace.h> + +/* OMAPI protocol header, version 1.00 */ +typedef struct { + u_int32_t authlen; /* Length of authenticator. */ + u_int32_t authid; /* Authenticator object ID. */ + u_int32_t op; /* Opcode. */ + omapi_handle_t handle; /* Handle of object being operated on, + or zero. */ + u_int32_t id; /* Transaction ID. */ + u_int32_t rid; /* ID of transaction to which this is a response. */ +} omapi_protocol_header_t; + +#define OMAPI_PROTOCOL_VERSION 100 + +#define OMAPI_OP_OPEN 1 +#define OMAPI_OP_REFRESH 2 +#define OMAPI_OP_UPDATE 3 +#define OMAPI_OP_NOTIFY 4 +#define OMAPI_OP_STATUS 5 +#define OMAPI_OP_DELETE 6 + +typedef enum { + omapi_connection_unconnected, + omapi_connection_connecting, + omapi_connection_connected, + omapi_connection_disconnecting, + omapi_connection_closed +} omapi_connection_state_t; + +typedef enum { + omapi_protocol_intro_wait, + omapi_protocol_header_wait, + omapi_protocol_signature_wait, + omapi_protocol_name_wait, + omapi_protocol_name_length_wait, + omapi_protocol_value_wait, + omapi_protocol_value_length_wait +} omapi_protocol_state_t; + +typedef struct __omapi_message_object { + OMAPI_OBJECT_PREAMBLE; + struct __omapi_message_object *next, *prev; + omapi_object_t *object; + omapi_object_t *notify_object; + struct __omapi_protocol_object *protocol_object; + u_int32_t authlen; + omapi_typed_data_t *authenticator; + u_int32_t authid; + omapi_object_t *id_object; + u_int32_t op; + u_int32_t h; + u_int32_t id; + u_int32_t rid; +} omapi_message_object_t; + +typedef struct __omapi_remote_auth { + struct __omapi_remote_auth *next; + omapi_handle_t remote_handle; + omapi_object_t *a; +} omapi_remote_auth_t; + +typedef struct __omapi_protocol_object { + OMAPI_OBJECT_PREAMBLE; + u_int32_t header_size; + u_int32_t protocol_version; + u_int32_t next_xid; + + omapi_protocol_state_t state; /* Input state. */ + int reading_message_values; /* True if reading message-specific + values. */ + omapi_message_object_t *message; /* Incoming message. */ + omapi_data_string_t *name; /* Incoming name. */ + omapi_typed_data_t *value; /* Incoming value. */ + isc_result_t verify_result; + omapi_remote_auth_t *default_auth; /* Default authinfo to use. */ + omapi_remote_auth_t *remote_auth_list; /* Authenticators active on + this connection. */ + + isc_boolean_t insecure; /* Set to allow unauthenticated + messages. */ + + isc_result_t (*verify_auth) (omapi_object_t *, omapi_auth_key_t *); +} omapi_protocol_object_t; + +typedef struct { + OMAPI_OBJECT_PREAMBLE; + + isc_boolean_t insecure; /* Set to allow unauthenticated + messages. */ + + isc_result_t (*verify_auth) (omapi_object_t *, omapi_auth_key_t *); +} omapi_protocol_listener_object_t; + +#include <omapip/buffer.h> + +typedef struct __omapi_listener_object { + OMAPI_OBJECT_PREAMBLE; + int socket; /* Connection socket. */ + int index; + struct sockaddr_in address; + isc_result_t (*verify_addr) (omapi_object_t *, omapi_addr_t *); +} omapi_listener_object_t; + +typedef struct __omapi_connection_object { + OMAPI_OBJECT_PREAMBLE; + int socket; /* Connection socket. */ + int32_t index; + omapi_connection_state_t state; + struct sockaddr_in remote_addr; + struct sockaddr_in local_addr; + omapi_addr_list_t *connect_list; /* List of addresses to which + to connect. */ + int cptr; /* Current element we are connecting to. */ + u_int32_t bytes_needed; /* Bytes of input needed before wakeup. */ + u_int32_t in_bytes; /* Bytes of input already buffered. */ + omapi_buffer_t *inbufs; + u_int32_t out_bytes; /* Bytes of output in buffers. */ + omapi_buffer_t *outbufs; + omapi_listener_object_t *listener; /* Listener that accepted this + connection, if any. */ + DST_KEY *in_key; /* Authenticator signing incoming + data. */ + void *in_context; /* Input hash context. */ + DST_KEY *out_key; /* Authenticator signing outgoing + data. */ + void *out_context; /* Output hash context. */ +} omapi_connection_object_t; + +typedef struct __omapi_io_object { + OMAPI_OBJECT_PREAMBLE; + struct __omapi_io_object *next; + int (*readfd) (omapi_object_t *); + int (*writefd) (omapi_object_t *); + isc_result_t (*reader) (omapi_object_t *); + isc_result_t (*writer) (omapi_object_t *); + isc_result_t (*reaper) (omapi_object_t *); +} omapi_io_object_t; + +typedef struct __omapi_generic_object { + OMAPI_OBJECT_PREAMBLE; + omapi_value_t **values; + u_int8_t *changed; + int nvalues, va_max; +} omapi_generic_object_t; + +typedef struct __omapi_waiter_object { + OMAPI_OBJECT_PREAMBLE; + int ready; + isc_result_t waitstatus; + struct __omapi_waiter_object *next; +} omapi_waiter_object_t; + +#define OMAPI_HANDLE_TABLE_SIZE 120 + +typedef struct __omapi_handle_table { + omapi_handle_t first, limit; + omapi_handle_t next; + int leafp; + union { + omapi_object_t *object; + struct __omapi_handle_table *table; + } children [OMAPI_HANDLE_TABLE_SIZE]; +} omapi_handle_table_t; + +#include <omapip/alloc.h> + +OMAPI_OBJECT_ALLOC_DECL (omapi_protocol, omapi_protocol_object_t, + omapi_type_protocol) +OMAPI_OBJECT_ALLOC_DECL (omapi_protocol_listener, + omapi_protocol_listener_object_t, + omapi_type_protocol_listener) +OMAPI_OBJECT_ALLOC_DECL (omapi_connection, + omapi_connection_object_t, omapi_type_connection) +OMAPI_OBJECT_ALLOC_DECL (omapi_listener, + omapi_listener_object_t, omapi_type_listener) +OMAPI_OBJECT_ALLOC_DECL (omapi_io, + omapi_io_object_t, omapi_type_io_object) +OMAPI_OBJECT_ALLOC_DECL (omapi_waiter, + omapi_waiter_object_t, omapi_type_waiter) +OMAPI_OBJECT_ALLOC_DECL (omapi_generic, + omapi_generic_object_t, omapi_type_generic) +OMAPI_OBJECT_ALLOC_DECL (omapi_message, + omapi_message_object_t, omapi_type_message) + +isc_result_t omapi_connection_sign_data (int mode, + DST_KEY *key, + void **context, + const unsigned char *data, + const unsigned len, + omapi_typed_data_t **result); +isc_result_t omapi_listener_connect (omapi_connection_object_t **obj, + omapi_listener_object_t *listener, + int socket, + struct sockaddr_in *remote_addr); +void omapi_listener_trace_setup (void); +void omapi_connection_trace_setup (void); +void omapi_buffer_trace_setup (void); +void omapi_connection_register (omapi_connection_object_t *, + const char *, int); +void trace_mr_init (void); + +OMAPI_ARRAY_TYPE_DECL(omapi_listener, omapi_listener_object_t); +OMAPI_ARRAY_TYPE_DECL(omapi_connection, omapi_connection_object_t); + +extern int log_priority; +extern int log_perror; +extern void (*log_cleanup) (void); + +void log_fatal (const char *, ...) + __attribute__((__format__(__printf__,1,2))); +int log_error (const char *, ...) + __attribute__((__format__(__printf__,1,2))); +int log_info (const char *, ...) + __attribute__((__format__(__printf__,1,2))); +int log_debug (const char *, ...) + __attribute__((__format__(__printf__,1,2))); +void do_percentm (char *obuf, const char *ibuf); + +isc_result_t uerr2isc (int); +isc_result_t ns_rcode_to_isc (int); + +extern omapi_message_object_t *omapi_registered_messages; + +#endif /* __OMAPIP_OMAPIP_P_H__ */ diff --git a/contrib/isc-dhcp/includes/omapip/trace.h b/contrib/isc-dhcp/includes/omapip/trace.h new file mode 100644 index 0000000..69cb3ed --- /dev/null +++ b/contrib/isc-dhcp/includes/omapip/trace.h @@ -0,0 +1,124 @@ +/* trace.h + + Definitions for omapi tracing facility... */ + +/* + * Copyright (c) 2001 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon, as part of a project for Nominum, Inc. To learn more + * about the Internet Software Consortium, see http://www.isc.org/. To + * learn more about Nominum, Inc., see ``http://www.nominum.com''. + */ + +#define TRACEFILE_MAGIC 0x64484370UL /* dHCp */ +#define TRACEFILE_VERSION 1 + +/* The first thing in a trace file is the header, which basically just + defines the version of the file. */ +typedef struct { + u_int32_t magic; /* Magic number for trace file. */ + u_int32_t version; /* Version of file. */ + int32_t hlen; /* Length of this header. */ + int32_t phlen; /* Length of packet headers. */ +} tracefile_header_t; + +/* The trace file is composed of a bunch of trace packets. Each such packet + has a type, followed by a length, followed by a timestamp, followed by + the actual contents of the packet. The type indexes are not fixed - + they are allocated either on readback or when writing a trace file. + One index type is reserved - type zero means that this record is a type + name to index mapping. */ +typedef struct { + u_int32_t type_index; /* Index to the type of handler that this + packet needs. */ + u_int32_t length; /* Length of the packet. This includes + everything except the fixed header. */ + u_int32_t when; /* When the packet was written. */ + u_int32_t pad; /* Round this out to a quad boundary. */ +} tracepacket_t; + +#define TRACE_INDEX_MAPPING_SIZE 4 /* trace_index_mapping_t less name. */ +typedef struct { + u_int32_t index; + char name [1]; +} trace_index_mapping_t; + +struct trace_type; /* forward */ +typedef struct trace_type trace_type_t; + +struct trace_type { + trace_type_t *next; + int index; + char *name; + void *baggage; + void (*have_packet) (trace_type_t *, unsigned, char *); + void (*stop_tracing) (trace_type_t *); +}; + +typedef struct trace_iov { + const char *buf; + unsigned len; +} trace_iov_t; + +typedef struct { + u_int16_t addrtype; + u_int16_t addrlen; + u_int8_t address [16]; + u_int16_t port; +} trace_addr_t; + +void trace_free_all (void); +int trace_playback (void); +int trace_record (void); +isc_result_t trace_init (void (*set_time) (u_int32_t), const char *, int); +isc_result_t trace_begin (const char *, const char *, int); +isc_result_t trace_write_packet (trace_type_t *, unsigned, const char *, + const char *, int); +isc_result_t trace_write_packet_iov (trace_type_t *, int, trace_iov_t *, + const char *, int); +void trace_type_stash (trace_type_t *); +trace_type_t *trace_type_register (const char *, void *, + void (*) (trace_type_t *, + unsigned, char *), + void (*) (trace_type_t *), + const char *, int); +void trace_stop (void); +void trace_index_map_input (trace_type_t *, unsigned, char *); +void trace_index_stop_tracing (trace_type_t *); +void trace_replay_init (void); +void trace_file_replay (const char *); +isc_result_t trace_get_next_packet (trace_type_t **, tracepacket_t *, + char **, unsigned *, unsigned *); +isc_result_t trace_get_file (trace_type_t *, + const char *, unsigned *, char **); +isc_result_t trace_get_packet (trace_type_t **, unsigned *, char **); +time_t trace_snoop_time (trace_type_t **); diff --git a/contrib/isc-dhcp/includes/osdep.h b/contrib/isc-dhcp/includes/osdep.h index 71a9859..c4486e8 100644 --- a/contrib/isc-dhcp/includes/osdep.h +++ b/contrib/isc-dhcp/includes/osdep.h @@ -3,7 +3,7 @@ Operating system dependencies... */ /* - * Copyright (c) 1996, 1997, 1998, 1999 The Internet Software Consortium. + * Copyright (c) 1996-1999 Internet Software Consortium. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -15,27 +15,35 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of The Internet Software Consortium nor the names of its - * contributors may be used to endorse or promote products derived + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND - * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE INTERNET SOFTWARE CONSORTIUM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. * - * This software was written for the Internet Software Consortium by Ted Lemon - * under a contract with Vixie Laboratories. + * This software has been written for the Internet Software Consortium + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. */ +#if !defined (__ISC_DHCP_OSDEP_H__) +#define __ISC_DHCP_OSDEP_H__ + #include "site.h" /* Porting:: @@ -62,6 +70,9 @@ # define USE_DEFAULT_NETWORK #endif +#if !defined (TIME_MAX) +# define TIME_MAX 2147483647 +#endif /* Porting:: @@ -91,6 +102,10 @@ # include "cf/freebsd.h" #endif +#ifdef OpenBSD +# include "cf/openbsd.h" +#endif + #if defined (__osf__) && defined (__alpha) # include "cf/alphaosf.h" #endif @@ -127,14 +142,6 @@ # endif #endif -#if defined(IRIX) || defined(__sgi) -# include "cf/irix.h" -#endif - -#if !defined (TIME_MAX) -# define TIME_MAX 2147483647 -#endif - /* Porting:: If you add a new network API, and have it set up so that it can be @@ -185,7 +192,9 @@ fallback. */ #if defined (USE_BPF_SEND) || defined (USE_NIT_SEND) || \ - defined (USE_DLPI_SEND) || defined (USE_UPF_SEND) || defined (USE_LPF_SEND) + defined (USE_DLPI_SEND) || defined (USE_UPF_SEND) || \ + defined (USE_LPF_SEND) || \ + (defined (USE_SOCKET_SEND) && defined (HAVE_SO_BINDTODEVICE)) # define USE_SOCKET_FALLBACK # define USE_FALLBACK #endif @@ -210,9 +219,7 @@ #if defined (USE_RAW_RECEIVE) || defined (USE_BPF_SEND) || \ defined (USE_NIT_RECEIVE) || defined (USE_UPF_RECEIVE) || \ - defined (USE_DLPI_RECEIVE) || \ - defined (USE_LPF_SEND) || \ - (defined (USE_SOCKET_SEND) && defined (SO_BINDTODEVICE)) + defined (USE_DLPI_RECEIVE) || defined (USE_LPF_RECEIVE) # define PACKET_DECODING #endif @@ -241,6 +248,10 @@ # define BPF_FORMAT "/dev/bpf%d" #endif +#if defined (F_SETFD) && !defined (HAVE_SETFD) +# define HAVE_SETFD +#endif + #if defined (IFF_POINTOPOINT) && !defined (HAVE_IFF_POINTOPOINT) # define HAVE_IFF_POINTOPOINT #endif @@ -285,10 +296,17 @@ # define HAVE_SO_BINDTODEVICE #endif -#if defined (SIOCGIFHWADDR) && !defined (HAVE_SIOCGIFHWADDR) -# define HAVE_SIOCGIFHWADDR -#endif - #if defined (AF_LINK) && !defined (HAVE_AF_LINK) # define HAVE_AF_LINK #endif + +/* Linux needs to define SHUT_* in /usr/include/sys/socket.h someday... */ +#if !defined (SHUT_RD) +# define SHUT_RD 0 +#endif + +#if !defined (SOCKLEN_T) +#define SOCKLEN_T socklen_t +#endif + +#endif /* __ISC_DHCP_OSDEP_H__ */ diff --git a/contrib/isc-dhcp/includes/site.h b/contrib/isc-dhcp/includes/site.h index 30fdb70..d103ef0 100644 --- a/contrib/isc-dhcp/includes/site.h +++ b/contrib/isc-dhcp/includes/site.h @@ -26,11 +26,74 @@ /* #define DEBUG_PACKET */ -/* Define this if you want to see dumps of tree evaluations. The most - common reason for doing this is to watch what happens with DNS name - lookups. */ +/* Define this if you want to see dumps of expression evaluation. */ -/* #define DEBUG_EVAL */ +/* #define DEBUG_EXPRESSIONS */ + +/* Define this if you want to see dumps of find_lease() in action. */ + +/* #define DEBUG_FIND_LEASE */ + +/* Define this if you want to see dumps of parsed expressions. */ + +/* #define DEBUG_EXPRESSION_PARSE */ + +/* Define this if you want to watch the class matching process. */ + +/* #define DEBUG_CLASS_MATCHING */ + +/* Define this if you want to track memory usage for the purpose of + noticing memory leaks quickly. */ + +/* #define DEBUG_MEMORY_LEAKAGE */ + +/* Define this if you want exhaustive (and very slow) checking of the + malloc pool for corruption. */ + +/* #define DEBUG_MALLOC_POOL */ + +/* Define this if you want to see a message every time a lease's state + changes. */ +/* #define DEBUG_LEASE_STATE_TRANSITIONS */ + +/* Define this if you want to maintain a history of the last N operations + that changed reference counts on objects. This can be used to debug + cases where an object is dereferenced too often, or not often enough. */ + +/* #define DEBUG_RC_HISTORY */ + +/* Define this if you want to see the history every cycle. */ + +/* #define DEBUG_RC_HISTORY_EXHAUSTIVELY */ + +/* This is the number of history entries to maintain - by default, 256. */ + +/* #define RC_HISTORY_MAX 10240 */ + +/* Define this if you want dhcpd to dump core when a non-fatal memory + allocation error is detected (i.e., something that would cause a + memory leak rather than a memory smash). */ + +/* #define POINTER_DEBUG */ + +/* Define this if you want debugging output for DHCP failover protocol + messages. */ + +/* #define DEBUG_FAILOVER_MESSAGES */ + +/* Define this if you want debugging output for DHCP failover protocol + lease assignment timing. */ + +/* #define DEBUG_FAILOVER_TIMING */ + +/* Define this if you want DHCP failover protocol support in the DHCP + server. */ + +#define FAILOVER_PROTOCOL + +/* Define this if you want DNS update functionality to be available. */ + +#define NSUPDATE /* Define this if you want the dhcpd.pid file to go somewhere other than the default (which varies from system to system, but is usually either @@ -98,3 +161,14 @@ /* Define this to change the logging facility used by dhcpd. */ /* #define DHCPD_LOG_FACILITY LOG_DAEMON */ + +/* Define this if you aren't debugging and you want to save memory + (potentially a _lot_ of memory) by allocating leases in chunks rather + than one at a time. */ + +#define COMPACT_LEASES + +/* Define this if you want to be able to save and playback server operational + traces. */ + +#define TRACING diff --git a/contrib/isc-dhcp/includes/statement.h b/contrib/isc-dhcp/includes/statement.h new file mode 100644 index 0000000..fa865f3 --- /dev/null +++ b/contrib/isc-dhcp/includes/statement.h @@ -0,0 +1,113 @@ +/* statement.h + + Definitions for executable statements... */ + +/* + * Copyright (c) 1996-1999 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. + */ + +struct executable_statement { + int refcnt; + struct executable_statement *next; + enum statement_op { + null_statement, + if_statement, + add_statement, + eval_statement, + break_statement, + default_option_statement, + supersede_option_statement, + append_option_statement, + prepend_option_statement, + send_option_statement, + statements_statement, + on_statement, + switch_statement, + case_statement, + default_statement, + set_statement, + unset_statement, + let_statement, + define_statement, + log_statement, + return_statement + } op; + union { + struct { + struct executable_statement *tc, *fc; + struct expression *expr; + } ie; + struct expression *eval; + struct expression *retval; + struct class *add; + struct option_cache *option; + struct option_cache *supersede; + struct option_cache *prepend; + struct option_cache *append; + struct executable_statement *statements; + struct { + int evtypes; +# define ON_COMMIT 1 +# define ON_EXPIRY 2 +# define ON_RELEASE 4 +# define ON_TRANSMISSION 8 + struct executable_statement *statements; + } on; + struct { + struct expression *expr; + struct executable_statement *statements; + } s_switch; + struct expression *c_case; + struct { + char *name; + struct expression *expr; + struct executable_statement *statements; + } set, let; + char *unset; + struct { + enum { + log_priority_fatal, + log_priority_error, + log_priority_debug, + log_priority_info + } priority; + struct expression *expr; + } log; + } data; +}; + diff --git a/contrib/isc-dhcp/includes/tree.h b/contrib/isc-dhcp/includes/tree.h index c2df41f..03047f3 100644 --- a/contrib/isc-dhcp/includes/tree.h +++ b/contrib/isc-dhcp/includes/tree.h @@ -3,7 +3,8 @@ Definitions for address trees... */ /* - * Copyright (c) 1995 The Internet Software Consortium. All rights reserved. + * Copyright (c) 1996-2001 Internet Software Consortium. + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,10 +34,11 @@ * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium - * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie - * Enterprises. To learn more about the Internet Software Consortium, - * see ``http://www.vix.com/isc''. To learn more about Vixie - * Enterprises, see ``http://www.vix.com''. + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. */ /* A pair of pointers, suitable for making a linked list. */ @@ -45,63 +47,300 @@ typedef struct _pair { struct _pair *cdr; } *pair; +struct option_chain_head { + int refcnt; + pair first; +}; + +struct enumeration_value { + const char *name; + u_int8_t value; +}; + +struct enumeration { + struct enumeration *next; + const char *name; + struct enumeration_value *values; +}; + /* Tree node types... */ #define TREE_CONCAT 1 #define TREE_HOST_LOOKUP 2 #define TREE_CONST 3 #define TREE_LIMIT 4 +#define TREE_DATA_EXPR 5 + +/* A data buffer with a reference count. */ +struct buffer { + int refcnt; + unsigned char data [1]; +}; + +/* XXX The mechanism by which data strings are returned is currently + XXX broken: rather than returning an ephemeral pointer, we create + XXX a reference to the data in the caller's space, which the caller + XXX then has to dereference - instead, the reference should be + XXX ephemeral by default and be made a persistent reference explicitly. */ +/* XXX on the other hand, it seems to work pretty nicely, so maybe the + XXX above comment is meshuggenah. */ + +/* A string of data bytes, possibly accompanied by a larger buffer. */ +struct data_string { + struct buffer *buffer; + const unsigned char *data; + unsigned len; /* Does not include NUL terminator, if any. */ + int terminated; +}; + +enum expression_context { + context_any, /* indefinite */ + context_boolean, + context_data, + context_numeric, + context_dns, + context_data_or_numeric, /* indefinite */ + context_function +}; + +struct fundef { + int refcnt; + struct string_list *args; + struct executable_statement *statements; +}; + +struct binding_value { + int refcnt; + enum { + binding_boolean, + binding_data, + binding_numeric, + binding_dns, + binding_function + } type; + union value { + struct data_string data; + unsigned long intval; + int boolean; +#if defined (NSUPDATE) + ns_updrec *dns; +#endif + struct fundef *fundef; + struct binding_value *bv; + } value; +}; -/* Tree structure for deferred evaluation of changing values. */ -struct tree { - int op; +struct binding { + struct binding *next; + char *name; + struct binding_value *value; +}; + +struct binding_scope { + int refcnt; + struct binding_scope *outer; + struct binding *bindings; +}; + +/* Expression tree structure. */ + +enum expr_op { + expr_none, + expr_match, + expr_check, + expr_equal, + expr_substring, + expr_suffix, + expr_concat, + expr_host_lookup, + expr_and, + expr_or, + expr_not, + expr_option, + expr_hardware, + expr_packet, + expr_const_data, + expr_extract_int8, + expr_extract_int16, + expr_extract_int32, + expr_encode_int8, + expr_encode_int16, + expr_encode_int32, + expr_const_int, + expr_exists, + expr_encapsulate, + expr_known, + expr_reverse, + expr_leased_address, + expr_binary_to_ascii, + expr_config_option, + expr_host_decl_name, + expr_pick_first_value, + expr_lease_time, + expr_dns_transaction, + expr_static, + expr_ns_add, + expr_ns_delete, + expr_ns_exists, + expr_ns_not_exists, + expr_not_equal, + expr_null, + expr_variable_exists, + expr_variable_reference, + expr_filename, + expr_sname, + expr_arg, + expr_funcall, + expr_function, + expr_add, + expr_subtract, + expr_multiply, + expr_divide, + expr_remainder, + expr_binary_and, + expr_binary_or, + expr_binary_xor, + expr_client_state +}; + +struct expression { + int refcnt; + enum expr_op op; union { - struct concat { - struct tree *left; - struct tree *right; - } concat; - struct host_lookup { - struct dns_host_entry *host; - } host_lookup; - struct const_val { - unsigned char *data; - int len; - } const_val; - struct limit { - struct tree *tree; - int limit; - } limit; + struct { + struct expression *expr; + struct expression *offset; + struct expression *len; + } substring; + struct expression *equal [2]; + struct expression *and [2]; + struct expression *or [2]; + struct expression *not; + struct expression *add; + struct expression *subtract; + struct expression *multiply; + struct expression *divide; + struct expression *remainder; + struct collection *check; + struct { + struct expression *expr; + struct expression *len; + } suffix; + struct option *option; + struct option *config_option; + struct { + struct expression *offset; + struct expression *len; + } packet; + struct data_string const_data; + struct expression *extract_int; + struct expression *encode_int; + unsigned long const_int; + struct expression *concat [2]; + struct dns_host_entry *host_lookup; + struct option *exists; + struct data_string encapsulate; + struct { + struct expression *base; + struct expression *width; + struct expression *seperator; + struct expression *buffer; + } b2a; + struct { + struct expression *width; + struct expression *buffer; + } reverse; + struct { + struct expression *car; + struct expression *cdr; + } pick_first_value; + struct { + struct expression *car; + struct expression *cdr; + } dns_transaction; + struct { + unsigned rrclass; + unsigned rrtype; + struct expression *rrname; + struct expression *rrdata; + struct expression *ttl; + } ns_add; + struct { + unsigned rrclass; + unsigned rrtype; + struct expression *rrname; + struct expression *rrdata; + } ns_delete, ns_exists, ns_not_exists; + char *variable; + struct { + struct expression *val; + struct expression *next; + } arg; + struct { + char *name; + struct expression *arglist; + } funcall; + struct fundef *func; } data; -}; + int flags; +# define EXPR_EPHEMERAL 1 +}; /* DNS host entry structure... */ struct dns_host_entry { - char *hostname; - unsigned char *data; - int data_len; - int buf_len; + int refcnt; TIME timeout; + struct data_string data; + char hostname [1]; }; -struct tree_cache { - unsigned char *value; - int len; - int buf_size; - TIME timeout; - struct tree *tree; - int flags; -#define TC_AWAITING_RESOLUTION 1 -#define TC_TEMPORARY 2 -}; +struct option_cache; /* forward */ +struct packet; /* forward */ +struct option_state; /* forward */ +struct decoded_option_state; /* forward */ +struct lease; /* forward */ +struct client_state; /* forward */ struct universe { - char *name; - struct hash_table *hash; + const char *name; + struct option_cache *(*lookup_func) (struct universe *, + struct option_state *, + unsigned); + void (*save_func) (struct universe *, struct option_state *, + struct option_cache *); + void (*foreach) (struct packet *, + struct lease *, struct client_state *, + struct option_state *, struct option_state *, + struct binding_scope **, struct universe *, void *, + void (*) (struct option_cache *, struct packet *, + struct lease *, struct client_state *, + struct option_state *, + struct option_state *, + struct binding_scope **, + struct universe *, void *)); + void (*delete_func) (struct universe *universe, + struct option_state *, int); + int (*option_state_dereference) (struct universe *, + struct option_state *, + const char *, int); + int (*decode) (struct option_state *, + const unsigned char *, unsigned, struct universe *); + int (*encapsulate) (struct data_string *, struct packet *, + struct lease *, struct client_state *, + struct option_state *, struct option_state *, + struct binding_scope **, + struct universe *); + void (*store_tag) PROTO ((unsigned char *, u_int32_t)); + void (*store_length) PROTO ((unsigned char *, u_int32_t)); + int tag_size, length_size; + option_hash_t *hash; struct option *options [256]; + struct option *enc_opt; + int index; }; struct option { - char *name; - char *format; + const char *name; + const char *format; struct universe *universe; - unsigned char code; + unsigned code; }; diff --git a/contrib/isc-dhcp/includes/version.h b/contrib/isc-dhcp/includes/version.h index 45b89ff..919ddc7 100644 --- a/contrib/isc-dhcp/includes/version.h +++ b/contrib/isc-dhcp/includes/version.h @@ -1,3 +1,3 @@ /* Current version of ISC DHCP Distribution. */ -#define DHCP_VERSION "2.0pl5+v3_fixes" +#define DHCP_VERSION "V3.0.1rc6" diff --git a/contrib/isc-dhcp/minires/Makefile.dist b/contrib/isc-dhcp/minires/Makefile.dist new file mode 100644 index 0000000..b6bf088 --- /dev/null +++ b/contrib/isc-dhcp/minires/Makefile.dist @@ -0,0 +1,69 @@ +# Makefile.dist +# +# Copyright (c) 1996-2000 Internet Software Consortium. +# Use is subject to license terms which appear in the file named +# ISC-LICENSE that should have accompanied this file when you +# received it. If a file named ISC-LICENSE did not accompany this +# file, or you are not sure the one you have is correct, you may +# obtain an applicable copy of the license at: +# +# http://www.isc.org/isc-license-1.0.html. +# +# This file is part of the ISC DHCP distribution. The documentation +# associated with this file is listed in the file DOCUMENTATION, +# included in the top-level directory of this release. +# +# Support and other services are available for ISC products - see +# http://www.isc.org for more information. +# + +CATMANPAGES = dhcpctl.cat3 +SEDMANPAGES = dhcpctl.man3 +MAN = dhcpctl.3 +SRC = res_mkupdate.c res_init.c res_update.c res_send.c res_comp.c \ + res_sendsigned.c res_findzonecut.c res_query.c res_mkquery.c \ + ns_date.c ns_parse.c ns_sign.c ns_name.c ns_samedomain.c ns_verify.c +OBJ = res_mkupdate.o res_init.o res_update.o res_send.o res_comp.o \ + res_sendsigned.o res_findzonecut.o res_query.o res_mkquery.o \ + ns_date.o ns_parse.o ns_sign.o ns_name.o ns_samedomain.o ns_verify.o + +INCLUDES = $(BINDINC) -I$(TOP)/includes +CFLAGS = $(DEBUG) $(PREDEFINES) $(INCLUDES) $(COPTS) -DHMAC_MD5 -DMINIRES_LIB + +all: libres.a + +install: + +libres.a: $(OBJ) + rm -f res.a + ar cruv libres.a $(OBJ) + $(RANLIB) libres.a + +depend: + $(MKDEP) $(INCLUDES) $(PREDEFINES) $(SRC) + +clean: + -rm -f $(OBJ) libres.a + +realclean: clean + -rm -f *~ $(CATMANPAGES) $(SEDMANPAGES) + +distclean: realclean + -rm -f Makefile + +links: + @for foo in $(SRC) $(MAN) $(HDRS); do \ + if [ ! -b $$foo ]; then \ + rm -f $$foo; \ + fi; \ + ln -s $(TOP)/minires/$$foo $$foo; \ + done + +dhcpctl.cat3: dhcpctl.man3 + nroff -man dhcpctl.man3 >dhcpctl.cat3 + +dhcpctl.man3: dhcpctl.3 + sed -e "s#ETCDIR#$(ETC)#g" -e "s#DBDIR#$(VARDB)#g" \ + -e "s#RUNDIR#$(VARRUN)#g" < dhcpctl.3 >dhcpctl.man3 + +# Dependencies (semi-automatically-generated) diff --git a/contrib/isc-dhcp/minires/ns_date.c b/contrib/isc-dhcp/minires/ns_date.c new file mode 100644 index 0000000..f5ef8c4 --- /dev/null +++ b/contrib/isc-dhcp/minires/ns_date.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#ifndef lint +static const char rcsid[] = "$Id: ns_date.c,v 1.2 2000/04/11 01:58:39 mellon Exp $"; +#endif + +/* Import. */ + +#include <ctype.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <time.h> + +#include <sys/types.h> +#include <netinet/in.h> +#include <sys/socket.h> + +#include "minires/minires.h" +#include "arpa/nameser.h" + +#ifdef SPRINTF_CHAR +# define SPRINTF(x) strlen(sprintf/**/x) +#else +# define SPRINTF(x) ((size_t)sprintf x) +#endif + +/* Forward. */ + +static int datepart(const char *, int, int, int, int *); + +/* Public. */ + +/* Convert a date in ASCII into the number of seconds since + 1 January 1970 (GMT assumed). Format is yyyymmddhhmmss, all + digits required, no spaces allowed. */ + +u_int32_t +ns_datetosecs(const char *cp, int *errp) { + struct tm time; + u_int32_t result; + int mdays, i; + static const int days_per_month[12] = + {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + + if (strlen(cp) != 14) { + *errp = 1; + return (0); + } + *errp = 0; + + memset(&time, 0, sizeof time); + time.tm_year = datepart(cp + 0, 4, 1990, 9999, errp) - 1900; + time.tm_mon = datepart(cp + 4, 2, 01, 12, errp) - 1; + time.tm_mday = datepart(cp + 6, 2, 01, 31, errp); + time.tm_hour = datepart(cp + 8, 2, 00, 23, errp); + time.tm_min = datepart(cp + 10, 2, 00, 59, errp); + time.tm_sec = datepart(cp + 12, 2, 00, 59, errp); + if (*errp) /* Any parse errors? */ + return (0); + + /* + * OK, now because timegm() is not available in all environments, + * we will do it by hand. Roll up sleeves, curse the gods, begin! + */ + +#define SECS_PER_DAY ((u_int32_t)24*60*60) +#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) + + result = time.tm_sec; /* Seconds */ + result += time.tm_min * 60; /* Minutes */ + result += time.tm_hour * (60*60); /* Hours */ + result += (time.tm_mday - 1) * SECS_PER_DAY; /* Days */ + + /* Months are trickier. Look without leaping, then leap */ + mdays = 0; + for (i = 0; i < time.tm_mon; i++) + mdays += days_per_month[i]; + result += mdays * SECS_PER_DAY; /* Months */ + if (time.tm_mon > 1 && isleap(1900+time.tm_year)) + result += SECS_PER_DAY; /* Add leapday for this year */ + + /* First figure years without leapdays, then add them in. */ + /* The loop is slow, FIXME, but simple and accurate. */ + result += (time.tm_year - 70) * (SECS_PER_DAY*365); /* Years */ + for (i = 70; i < time.tm_year; i++) + if (isleap(1900+i)) + result += SECS_PER_DAY; /* Add leapday for prev year */ + + return (result); +} + +/* Private. */ + +/* + * Parse part of a date. Set error flag if any error. + * Don't reset the flag if there is no error. + */ +static int +datepart(const char *buf, int size, int min, int max, int *errp) { + int result = 0; + int i; + + for (i = 0; i < size; i++) { + if (!isdigit(buf[i])) + *errp = 1; + result = (result * 10) + buf[i] - '0'; + } + if (result < min) + *errp = 1; + if (result > max) + *errp = 1; + return (result); +} diff --git a/contrib/isc-dhcp/minires/ns_name.c b/contrib/isc-dhcp/minires/ns_name.c new file mode 100644 index 0000000..e815d24 --- /dev/null +++ b/contrib/isc-dhcp/minires/ns_name.c @@ -0,0 +1,641 @@ +/* + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#ifndef lint +static const char rcsid[] = "$Id: ns_name.c,v 1.1 2000/02/02 07:28:14 mellon Exp $"; +#endif + +#include <sys/types.h> + +#include <netinet/in.h> +#include <sys/socket.h> + +#include <errno.h> +#include <string.h> +#include <ctype.h> + +#include "minires/minires.h" +#include "arpa/nameser.h" + +/* Data. */ + +static const char digits[] = "0123456789"; + +/* Forward. */ + +static int special(int); +static int printable(int); +static int dn_find(const u_char *, const u_char *, + const u_char * const *, + const u_char * const *); + +/* Public. */ + +/* + * ns_name_ntop(src, dst, dstsiz) + * Convert an encoded domain name to printable ascii as per RFC1035. + * return: + * Number of bytes written to buffer, or -1 (with errno set) + * notes: + * The root is returned as "." + * All other domains are returned in non absolute form + */ +int +ns_name_ntop(const u_char *src, char *dst, size_t dstsiz) { + const u_char *cp; + char *dn, *eom; + u_char c; + u_int n; + + cp = src; + dn = dst; + eom = dst + dstsiz; + + while ((n = *cp++) != 0) { + if ((n & NS_CMPRSFLGS) != 0) { + /* Some kind of compression pointer. */ + errno = EMSGSIZE; + return (-1); + } + if (dn != dst) { + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '.'; + } + if (dn + n >= eom) { + errno = EMSGSIZE; + return (-1); + } + for ((void)NULL; n > 0; n--) { + c = *cp++; + if (special(c)) { + if (dn + 1 >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '\\'; + *dn++ = (char)c; + } else if (!printable(c)) { + if (dn + 3 >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '\\'; + *dn++ = digits[c / 100]; + *dn++ = digits[(c % 100) / 10]; + *dn++ = digits[c % 10]; + } else { + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = (char)c; + } + } + } + if (dn == dst) { + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '.'; + } + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '\0'; + return (dn - dst); +} + +/* + * ns_name_pton(src, dst, dstsiz) + * Convert a ascii string into an encoded domain name as per RFC1035. + * return: + * -1 if it fails + * 1 if string was fully qualified + * 0 is string was not fully qualified + * notes: + * Enforces label and domain length limits. + */ + +int +ns_name_pton(const char *src, u_char *dst, size_t dstsiz) { + u_char *label, *bp, *eom; + int c, n, escaped; + char *cp; + + escaped = 0; + bp = dst; + eom = dst + dstsiz; + label = bp++; + + while ((c = *src++) != 0) { + if (escaped) { + if ((cp = strchr(digits, c)) != NULL) { + n = (cp - digits) * 100; + if ((c = *src++) == 0 || + (cp = strchr(digits, c)) == NULL) { + errno = EMSGSIZE; + return (-1); + } + n += (cp - digits) * 10; + if ((c = *src++) == 0 || + (cp = strchr(digits, c)) == NULL) { + errno = EMSGSIZE; + return (-1); + } + n += (cp - digits); + if (n > 255) { + errno = EMSGSIZE; + return (-1); + } + c = n; + } + escaped = 0; + } else if (c == '\\') { + escaped = 1; + continue; + } else if (c == '.') { + c = (bp - label - 1); + if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */ + errno = EMSGSIZE; + return (-1); + } + if (label >= eom) { + errno = EMSGSIZE; + return (-1); + } + *label = c; + /* Fully qualified ? */ + if (*src == '\0') { + if (c != 0) { + if (bp >= eom) { + errno = EMSGSIZE; + return (-1); + } + *bp++ = '\0'; + } + if ((bp - dst) > MAXCDNAME) { + errno = EMSGSIZE; + return (-1); + } + return (1); + } + if (c == 0 || *src == '.') { + errno = EMSGSIZE; + return (-1); + } + label = bp++; + continue; + } + if (bp >= eom) { + errno = EMSGSIZE; + return (-1); + } + *bp++ = (u_char)c; + } + c = (bp - label - 1); + if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */ + errno = EMSGSIZE; + return (-1); + } + if (label >= eom) { + errno = EMSGSIZE; + return (-1); + } + *label = c; + if (c != 0) { + if (bp >= eom) { + errno = EMSGSIZE; + return (-1); + } + *bp++ = 0; + } + if ((bp - dst) > MAXCDNAME) { /* src too big */ + errno = EMSGSIZE; + return (-1); + } + return (0); +} + +/* + * ns_name_ntol(src, dst, dstsiz) + * Convert a network strings labels into all lowercase. + * return: + * Number of bytes written to buffer, or -1 (with errno set) + * notes: + * Enforces label and domain length limits. + */ + +int +ns_name_ntol(const u_char *src, u_char *dst, size_t dstsiz) { + const u_char *cp; + u_char *dn, *eom; + u_char c; + u_int n; + + cp = src; + dn = dst; + eom = dst + dstsiz; + + while ((n = *cp++) != 0) { + if ((n & NS_CMPRSFLGS) != 0) { + /* Some kind of compression pointer. */ + errno = EMSGSIZE; + return (-1); + } + *dn++ = n; + if (dn + n >= eom) { + errno = EMSGSIZE; + return (-1); + } + for ((void)NULL; n > 0; n--) { + c = *cp++; + if (isupper(c)) + *dn++ = tolower(c); + else + *dn++ = c; + } + } + *dn++ = '\0'; + return (dn - dst); +} + +/* + * ns_name_unpack(msg, eom, src, dst, dstsiz) + * Unpack a domain name from a message, source may be compressed. + * return: + * -1 if it fails, or consumed octets if it succeeds. + */ +int +ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src, + u_char *dst, size_t dstsiz) +{ + const u_char *srcp, *dstlim; + u_char *dstp; + unsigned n; + int len; + int checked; + + len = -1; + checked = 0; + dstp = dst; + srcp = src; + dstlim = dst + dstsiz; + if (srcp < msg || srcp >= eom) { + errno = EMSGSIZE; + return (-1); + } + /* Fetch next label in domain name. */ + while ((n = *srcp++) != 0) { + /* Check for indirection. */ + switch (n & NS_CMPRSFLGS) { + case 0: + /* Limit checks. */ + if (dstp + n + 1 >= dstlim || srcp + n >= eom) { + errno = EMSGSIZE; + return (-1); + } + checked += n + 1; + *dstp++ = n; + memcpy(dstp, srcp, n); + dstp += n; + srcp += n; + break; + + case NS_CMPRSFLGS: + if (srcp >= eom) { + errno = EMSGSIZE; + return (-1); + } + if (len < 0) + len = srcp - src + 1; + srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff)); + if (srcp < msg || srcp >= eom) { /* Out of range. */ + errno = EMSGSIZE; + return (-1); + } + checked += 2; + /* + * Check for loops in the compressed name; + * if we've looked at the whole message, + * there must be a loop. + */ + if (checked >= eom - msg) { + errno = EMSGSIZE; + return (-1); + } + break; + + default: + errno = EMSGSIZE; + return (-1); /* flag error */ + } + } + *dstp = '\0'; + if (len < 0) + len = srcp - src; + return (len); +} + +/* + * ns_name_pack(src, dst, dstsiz, dnptrs, lastdnptr) + * Pack domain name 'domain' into 'comp_dn'. + * return: + * Size of the compressed name, or -1. + * notes: + * 'dnptrs' is an array of pointers to previous compressed names. + * dnptrs[0] is a pointer to the beginning of the message. The array + * ends with NULL. + * 'lastdnptr' is a pointer to the end of the array pointed to + * by 'dnptrs'. + * Side effects: + * The list of pointers in dnptrs is updated for labels inserted into + * the message as we compress the name. If 'dnptr' is NULL, we don't + * try to compress names. If 'lastdnptr' is NULL, we don't update the + * list. + */ +int +ns_name_pack(const u_char *src, u_char *dst, unsigned dstsiz, + const u_char **dnptrs, const u_char **lastdnptr) +{ + u_char *dstp; + const u_char **cpp, **lpp, *eob, *msg; + const u_char *srcp; + unsigned n; + int l; + + srcp = src; + dstp = dst; + eob = dstp + dstsiz; + lpp = cpp = NULL; + if (dnptrs != NULL) { + if ((msg = *dnptrs++) != NULL) { + for (cpp = dnptrs; *cpp != NULL; cpp++) + (void)NULL; + lpp = cpp; /* end of list to search */ + } + } else + msg = NULL; + + /* make sure the domain we are about to add is legal */ + l = 0; + do { + n = *srcp; + if ((n & NS_CMPRSFLGS) != 0) { + errno = EMSGSIZE; + return (-1); + } + l += n + 1; + if (l > MAXCDNAME) { + errno = EMSGSIZE; + return (-1); + } + srcp += n + 1; + } while (n != 0); + + /* from here on we need to reset compression pointer array on error */ + srcp = src; + do { + /* Look to see if we can use pointers. */ + n = *srcp; + if (n != 0 && msg != NULL) { + l = dn_find(srcp, msg, (const u_char * const *)dnptrs, + (const u_char * const *)lpp); + if (l >= 0) { + if (dstp + 1 >= eob) { + goto cleanup; + } + *dstp++ = (l >> 8) | NS_CMPRSFLGS; + *dstp++ = l % 256; + return (dstp - dst); + } + /* Not found, save it. */ + if (lastdnptr != NULL && cpp < lastdnptr - 1 && + (dstp - msg) < 0x4000) { + *cpp++ = dstp; + *cpp = NULL; + } + } + /* copy label to buffer */ + if (n & NS_CMPRSFLGS) { /* Should not happen. */ + goto cleanup; + } + if (dstp + 1 + n >= eob) { + goto cleanup; + } + memcpy(dstp, srcp, n + 1); + srcp += n + 1; + dstp += n + 1; + } while (n != 0); + + if (dstp > eob) { +cleanup: + if (msg != NULL) + *lpp = NULL; + errno = EMSGSIZE; + return (-1); + } + return (dstp - dst); +} + +/* + * ns_name_uncompress(msg, eom, src, dst, dstsiz) + * Expand compressed domain name to presentation format. + * return: + * Number of bytes read out of `src', or -1 (with errno set). + * note: + * Root domain returns as "." not "". + */ +int +ns_name_uncompress(const u_char *msg, const u_char *eom, const u_char *src, + char *dst, size_t dstsiz) +{ + u_char tmp[NS_MAXCDNAME]; + int n; + + if ((n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1) + return (-1); + if (ns_name_ntop(tmp, dst, dstsiz) == -1) + return (-1); + return (n); +} + +/* + * ns_name_compress(src, dst, dstsiz, dnptrs, lastdnptr) + * Compress a domain name into wire format, using compression pointers. + * return: + * Number of bytes consumed in `dst' or -1 (with errno set). + * notes: + * 'dnptrs' is an array of pointers to previous compressed names. + * dnptrs[0] is a pointer to the beginning of the message. + * The list ends with NULL. 'lastdnptr' is a pointer to the end of the + * array pointed to by 'dnptrs'. Side effect is to update the list of + * pointers for labels inserted into the message as we compress the name. + * If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr' + * is NULL, we don't update the list. + */ +int +ns_name_compress(const char *src, u_char *dst, size_t dstsiz, + const u_char **dnptrs, const u_char **lastdnptr) +{ + u_char tmp[NS_MAXCDNAME]; + + if (ns_name_pton(src, tmp, sizeof tmp) == -1) + return (-1); + return (ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr)); +} + +/* + * ns_name_skip(ptrptr, eom) + * Advance *ptrptr to skip over the compressed name it points at. + * return: + * 0 on success, -1 (with errno set) on failure. + */ +int +ns_name_skip(const u_char **ptrptr, const u_char *eom) { + const u_char *cp; + u_int n; + + cp = *ptrptr; + while (cp < eom && (n = *cp++) != 0) { + /* Check for indirection. */ + switch (n & NS_CMPRSFLGS) { + case 0: /* normal case, n == len */ + cp += n; + continue; + case NS_CMPRSFLGS: /* indirection */ + cp++; + break; + default: /* illegal type */ + errno = EMSGSIZE; + return (-1); + } + break; + } + if (cp > eom) { + errno = EMSGSIZE; + return (-1); + } + *ptrptr = cp; + return (0); +} + +/* Private. */ + +/* + * special(ch) + * Thinking in noninternationalized USASCII (per the DNS spec), + * is this characted special ("in need of quoting") ? + * return: + * boolean. + */ +static int +special(int ch) { + switch (ch) { + case 0x22: /* '"' */ + case 0x2E: /* '.' */ + case 0x3B: /* ';' */ + case 0x5C: /* '\\' */ + /* Special modifiers in zone files. */ + case 0x40: /* '@' */ + case 0x24: /* '$' */ + return (1); + default: + return (0); + } +} + +/* + * printable(ch) + * Thinking in noninternationalized USASCII (per the DNS spec), + * is this character visible and not a space when printed ? + * return: + * boolean. + */ +static int +printable(int ch) { + return (ch > 0x20 && ch < 0x7f); +} + +/* + * Thinking in noninternationalized USASCII (per the DNS spec), + * convert this character to lower case if it's upper case. + */ +static int +mklower(int ch) { + if (ch >= 0x41 && ch <= 0x5A) + return (ch + 0x20); + return (ch); +} + +/* + * dn_find(domain, msg, dnptrs, lastdnptr) + * Search for the counted-label name in an array of compressed names. + * return: + * offset from msg if found, or -1. + * notes: + * dnptrs is the pointer to the first name on the list, + * not the pointer to the start of the message. + */ +static int +dn_find(const u_char *domain, const u_char *msg, + const u_char * const *dnptrs, + const u_char * const *lastdnptr) +{ + const u_char *dn, *cp, *sp; + const u_char * const *cpp; + u_int n; + + for (cpp = dnptrs; cpp < lastdnptr; cpp++) { + dn = domain; + sp = cp = *cpp; + while ((n = *cp++) != 0) { + /* + * check for indirection + */ + switch (n & NS_CMPRSFLGS) { + case 0: /* normal case, n == len */ + if (n != *dn++) + goto next; + for ((void)NULL; n > 0; n--) + if (mklower(*dn++) != mklower(*cp++)) + goto next; + /* Is next root for both ? */ + if (*dn == '\0' && *cp == '\0') + return (sp - msg); + if (*dn) + continue; + goto next; + + case NS_CMPRSFLGS: /* indirection */ + cp = msg + (((n & 0x3f) << 8) | *cp); + break; + + default: /* illegal type */ + errno = EMSGSIZE; + return (-1); + } + } + next: ; + } + errno = ENOENT; + return (-1); +} diff --git a/contrib/isc-dhcp/minires/ns_parse.c b/contrib/isc-dhcp/minires/ns_parse.c new file mode 100644 index 0000000..27b06a1 --- /dev/null +++ b/contrib/isc-dhcp/minires/ns_parse.c @@ -0,0 +1,204 @@ +/* + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#ifndef lint +static const char rcsid[] = "$Id: ns_parse.c,v 1.2 2001/01/16 22:33:08 mellon Exp $"; +#endif + +/* Import. */ + +#include <sys/types.h> + +#include <netinet/in.h> +#include <sys/socket.h> + +#include <errno.h> +#include <string.h> + +#include "minires/minires.h" +#include "arpa/nameser.h" + +/* Forward. */ + +static void setsection(ns_msg *msg, ns_sect sect); + +/* Macros. */ + +#define RETERR(err) do { errno = (err); return (-1); } while (0) + +/* Public. */ + +/* These need to be in the same order as the nres.h:ns_flag enum. */ +struct _ns_flagdata _ns_flagdata[16] = { + { 0x8000, 15 }, /* qr. */ + { 0x7800, 11 }, /* opcode. */ + { 0x0400, 10 }, /* aa. */ + { 0x0200, 9 }, /* tc. */ + { 0x0100, 8 }, /* rd. */ + { 0x0080, 7 }, /* ra. */ + { 0x0040, 6 }, /* z. */ + { 0x0020, 5 }, /* ad. */ + { 0x0010, 4 }, /* cd. */ + { 0x000f, 0 }, /* rcode. */ + { 0x0000, 0 }, /* expansion (1/6). */ + { 0x0000, 0 }, /* expansion (2/6). */ + { 0x0000, 0 }, /* expansion (3/6). */ + { 0x0000, 0 }, /* expansion (4/6). */ + { 0x0000, 0 }, /* expansion (5/6). */ + { 0x0000, 0 }, /* expansion (6/6). */ +}; + +int +ns_skiprr(const u_char *ptr, const u_char *eom, ns_sect section, int count) { + const u_char *optr = ptr; + + for ((void)NULL; count > 0; count--) { + int b, rdlength; + + b = dn_skipname(ptr, eom); + if (b < 0) + RETERR(EMSGSIZE); + ptr += b/*Name*/ + NS_INT16SZ/*Type*/ + NS_INT16SZ/*Class*/; + if (section != ns_s_qd) { + if (ptr + NS_INT32SZ + NS_INT16SZ > eom) + RETERR(EMSGSIZE); + ptr += NS_INT32SZ/*TTL*/; + rdlength = getUShort(ptr); + ptr += 2; + ptr += rdlength/*RData*/; + } + } + if (ptr > eom) + RETERR(EMSGSIZE); + return (ptr - optr); +} + +int +ns_initparse(const u_char *msg, unsigned msglen, ns_msg *handle) { + const u_char *eom = msg + msglen; + int i; + + memset(handle, 0x5e, sizeof *handle); + handle->_msg = msg; + handle->_eom = eom; + if (msg + NS_INT16SZ > eom) + RETERR(EMSGSIZE); + handle->_id = getUShort (msg); + msg += 2; + if (msg + NS_INT16SZ > eom) + RETERR(EMSGSIZE); + handle->_flags = getUShort (msg); + msg += 2; + for (i = 0; i < ns_s_max; i++) { + if (msg + NS_INT16SZ > eom) + RETERR(EMSGSIZE); + handle->_counts[i] = getUShort (msg); + msg += 2; + } + for (i = 0; i < ns_s_max; i++) + if (handle->_counts[i] == 0) + handle->_sections[i] = NULL; + else { + int b = ns_skiprr(msg, eom, (ns_sect)i, + handle->_counts[i]); + + if (b < 0) + return (-1); + handle->_sections[i] = msg; + msg += b; + } + if (msg != eom) + RETERR(EMSGSIZE); + setsection(handle, ns_s_max); + return (0); +} + +isc_result_t +ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr) { + int b; + + /* Make section right. */ + if (section < 0 || section >= ns_s_max) + return ISC_R_NOTIMPLEMENTED; + if (section != handle->_sect) + setsection(handle, section); + + /* Make rrnum right. */ + if (rrnum == -1) + rrnum = handle->_rrnum; + if (rrnum < 0 || rrnum >= handle->_counts[(int)section]) + RETERR(ENODEV); + if (rrnum < handle->_rrnum) + setsection(handle, section); + if (rrnum > handle->_rrnum) { + b = ns_skiprr(handle->_ptr, handle->_eom, section, + rrnum - handle->_rrnum); + + if (b < 0) + return (-1); + handle->_ptr += b; + handle->_rrnum = rrnum; + } + + /* Do the parse. */ + b = dn_expand(handle->_msg, handle->_eom, + handle->_ptr, rr->name, NS_MAXDNAME); + if (b < 0) + return (-1); + handle->_ptr += b; + if (handle->_ptr + NS_INT16SZ + NS_INT16SZ > handle->_eom) + return ISC_R_NOSPACE; + rr->type = getUShort (handle->_ptr); + handle -> _ptr += 2; + rr->rr_class = getUShort (handle->_ptr); + handle -> _ptr += 2; + if (section == ns_s_qd) { + rr->ttl = 0; + rr->rdlength = 0; + rr->rdata = NULL; + } else { + if (handle->_ptr + NS_INT32SZ + NS_INT16SZ > handle->_eom) + return ISC_R_NOSPACE; + rr->ttl = getULong (handle->_ptr); + handle -> _ptr += 4; + rr->rdlength = getUShort (handle->_ptr); + handle -> _ptr += 2; + if (handle->_ptr + rr->rdlength > handle->_eom) + return ISC_R_NOSPACE; + rr->rdata = handle->_ptr; + handle->_ptr += rr->rdlength; + } + if (++handle->_rrnum > handle->_counts[(int)section]) + setsection(handle, (ns_sect)((int)section + 1)); + + /* All done. */ + return ISC_R_SUCCESS; +} + +/* Private. */ + +static void +setsection(ns_msg *msg, ns_sect sect) { + msg->_sect = sect; + if (sect == ns_s_max) { + msg->_rrnum = -1; + msg->_ptr = NULL; + } else { + msg->_rrnum = 0; + msg->_ptr = msg->_sections[(int)sect]; + } +} diff --git a/contrib/isc-dhcp/minires/ns_samedomain.c b/contrib/isc-dhcp/minires/ns_samedomain.c new file mode 100644 index 0000000..ac17a52 --- /dev/null +++ b/contrib/isc-dhcp/minires/ns_samedomain.c @@ -0,0 +1,210 @@ +/* + * Copyright (c) 1995,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#ifndef lint +static const char rcsid[] = "$Id: ns_samedomain.c,v 1.3 2001/01/16 22:33:09 mellon Exp $"; +#endif + +#include <sys/types.h> +#include <errno.h> +#include <string.h> + +#include <netinet/in.h> +#include <sys/socket.h> + +#include "minires/minires.h" +#include "arpa/nameser.h" + +/* + * int + * ns_samedomain(a, b) + * Check whether a name belongs to a domain. + * Inputs: + * a - the domain whose ancestory is being verified + * b - the potential ancestor we're checking against + * Return: + * boolean - is a at or below b? + * Notes: + * Trailing dots are first removed from name and domain. + * Always compare complete subdomains, not only whether the + * domain name is the trailing string of the given name. + * + * "host.foobar.top" lies in "foobar.top" and in "top" and in "" + * but NOT in "bar.top" + */ + +int +ns_samedomain(const char *a, const char *b) { + size_t la, lb; + int diff, i, escaped; + const char *cp; + + la = strlen(a); + lb = strlen(b); + + /* Ignore a trailing label separator (i.e. an unescaped dot) in 'a'. */ + if (la != 0 && a[la - 1] == '.') { + escaped = 0; + /* Note this loop doesn't get executed if la==1. */ + for (i = la - 2; i >= 0; i--) + if (a[i] == '\\') { + if (escaped) + escaped = 0; + else + escaped = 1; + } else + break; + if (!escaped) + la--; + } + + /* Ignore a trailing label separator (i.e. an unescaped dot) in 'b'. */ + if (lb != 0 && b[lb - 1] == '.') { + escaped = 0; + /* note this loop doesn't get executed if lb==1 */ + for (i = lb - 2; i >= 0; i--) + if (b[i] == '\\') { + if (escaped) + escaped = 0; + else + escaped = 1; + } else + break; + if (!escaped) + lb--; + } + + /* lb == 0 means 'b' is the root domain, so 'a' must be in 'b'. */ + if (lb == 0) + return (1); + + /* 'b' longer than 'a' means 'a' can't be in 'b'. */ + if (lb > la) + return (0); + + /* 'a' and 'b' being equal at this point indicates sameness. */ + if (lb == la) + return (strncasecmp(a, b, lb) == 0); + + /* Ok, we know la > lb. */ + + diff = la - lb; + + /* + * If 'a' is only 1 character longer than 'b', then it can't be + * a subdomain of 'b' (because of the need for the '.' label + * separator). + */ + if (diff < 2) + return (0); + + /* + * If the character before the last 'lb' characters of 'b' + * isn't '.', then it can't be a match (this lets us avoid + * having "foobar.com" match "bar.com"). + */ + if (a[diff - 1] != '.') + return (0); + + /* + * We're not sure about that '.', however. It could be escaped + * and thus not a really a label separator. + */ + escaped = 0; + for (i = diff - 2; i >= 0; i--) + if (a[i] == '\\') { + if (escaped) + escaped = 0; + else + escaped = 1; + } else + break; + if (escaped) + return (0); + + /* Now compare aligned trailing substring. */ + cp = a + diff; + return (strncasecmp(cp, b, lb) == 0); +} + +/* + * int + * ns_subdomain(a, b) + * is "a" a subdomain of "b"? + */ +int +ns_subdomain(const char *a, const char *b) { + return (ns_samename(a, b) != 1 && ns_samedomain(a, b)); +} + +/* + * int + * ns_makecanon(src, dst, dstsize) + * make a canonical copy of domain name "src" + * notes: + * foo -> foo. + * foo. -> foo. + * foo.. -> foo. + * foo\. -> foo\.. + * foo\\. -> foo\\. + */ + +isc_result_t +ns_makecanon(const char *src, char *dst, size_t dstsize) { + size_t n = strlen(src); + + if (n + sizeof "." > dstsize) { + ISC_R_NOSPACE; + } + strcpy(dst, src); + while (n > 0 && dst[n - 1] == '.') /* Ends in "." */ + if (n > 1 && dst[n - 2] == '\\' && /* Ends in "\." */ + (n < 2 || dst[n - 3] != '\\')) /* But not "\\." */ + break; + else + dst[--n] = '\0'; + dst[n++] = '.'; + dst[n] = '\0'; + return ISC_R_SUCCESS; +} + +/* + * int + * ns_samename(a, b) + * determine whether domain name "a" is the same as domain name "b" + * return: + * -1 on error + * 0 if names differ + * 1 if names are the same + */ + +int +ns_samename(const char *a, const char *b) { + char ta[NS_MAXDNAME], tb[NS_MAXDNAME]; + isc_result_t status; + + status = ns_makecanon(a, ta, sizeof ta); + if (status != ISC_R_SUCCESS) + return status; + status = ns_makecanon(b, tb, sizeof tb); + if (status != ISC_R_SUCCESS) + return (-1); + if (strcasecmp(ta, tb) == 0) + return (1); + else + return (0); +} diff --git a/contrib/isc-dhcp/minires/ns_sign.c b/contrib/isc-dhcp/minires/ns_sign.c new file mode 100644 index 0000000..6570c66 --- /dev/null +++ b/contrib/isc-dhcp/minires/ns_sign.c @@ -0,0 +1,356 @@ +/* + * Copyright (c) 1999-2001 by Internet Software Consortium, Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#ifndef lint +static const char rcsid[] = "$Id: ns_sign.c,v 1.4.2.1 2001/05/17 20:47:33 mellon Exp $"; +#endif + +#if defined (TRACING) +#define time(x) trace_mr_time (x) +time_t trace_mr_time (time_t *); +#endif + +/* Import. */ + +#include <sys/types.h> +#include <sys/param.h> + +#include <netinet/in.h> +#include <arpa/inet.h> +#include <sys/socket.h> + +#include <errno.h> +#include <netdb.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <time.h> + +#include "minires/minires.h" +#include "arpa/nameser.h" + +#include <isc-dhcp/dst.h> + +#define BOUNDS_CHECK(ptr, count) \ + do { \ + if ((ptr) + (count) > eob) { \ + return ISC_R_NOSPACE; \ + } \ + } while (0) + +/* ns_sign + * Parameters: + * msg message to be sent + * msglen input - length of message + * output - length of signed message + * msgsize length of buffer containing message + * error value to put in the error field + * key tsig key used for signing + * querysig (response), the signature in the query + * querysiglen (response), the length of the signature in the query + * sig a buffer to hold the generated signature + * siglen input - length of signature buffer + * output - length of signature + * + * Errors: + * - bad input data (-1) + * - bad key / sign failed (-BADKEY) + * - not enough space (NS_TSIG_ERROR_NO_SPACE) + */ +isc_result_t +ns_sign(u_char *msg, unsigned *msglen, unsigned msgsize, int error, void *k, + const u_char *querysig, unsigned querysiglen, u_char *sig, + unsigned *siglen, time_t in_timesigned) +{ + HEADER *hp = (HEADER *)msg; + DST_KEY *key = (DST_KEY *)k; + u_char *cp = msg + *msglen, *eob = msg + msgsize; + u_char *lenp; + u_char *name, *alg; + unsigned n; + time_t timesigned; + + dst_init(); + if (msg == NULL || msglen == NULL || sig == NULL || siglen == NULL) + ISC_R_INVALIDARG; + + /* Name. */ + if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) + n = dn_comp(key->dk_key_name, + cp, (unsigned)(eob - cp), NULL, NULL); + else + n = dn_comp("", cp, (unsigned)(eob - cp), NULL, NULL); + if (n < 0) + return ISC_R_NOSPACE; + name = cp; + cp += n; + + /* Type, class, ttl, length (not filled in yet). */ + BOUNDS_CHECK(cp, INT16SZ + INT16SZ + INT32SZ + INT16SZ); + PUTSHORT(ns_t_tsig, cp); + PUTSHORT(ns_c_any, cp); + PUTLONG(0, cp); /* TTL */ + lenp = cp; + cp += 2; + + /* Alg. */ + if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) { + if (key->dk_alg != KEY_HMAC_MD5) + return ISC_R_BADKEY; + n = dn_comp(NS_TSIG_ALG_HMAC_MD5, + cp, (unsigned)(eob - cp), NULL, NULL); + } + else + n = dn_comp("", cp, (unsigned)(eob - cp), NULL, NULL); + if (n < 0) + ISC_R_NOSPACE; + alg = cp; + cp += n; + + /* Time. */ + BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ); + PUTSHORT(0, cp); + timesigned = time(NULL); + if (error != ns_r_badtime) + PUTLONG(timesigned, cp); + else + PUTLONG(in_timesigned, cp); + PUTSHORT(NS_TSIG_FUDGE, cp); + + /* Compute the signature. */ + if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) { + void *ctx; + u_char buf[MAXDNAME], *cp2; + unsigned n; + + dst_sign_data(SIG_MODE_INIT, key, &ctx, NULL, 0, NULL, 0); + + /* Digest the query signature, if this is a response. */ + if (querysiglen > 0 && querysig != NULL) { + u_int16_t len_n = htons(querysiglen); + dst_sign_data(SIG_MODE_UPDATE, key, &ctx, + (u_char *)&len_n, INT16SZ, NULL, 0); + dst_sign_data(SIG_MODE_UPDATE, key, &ctx, + querysig, querysiglen, NULL, 0); + } + + /* Digest the message. */ + dst_sign_data(SIG_MODE_UPDATE, key, &ctx, msg, *msglen, + NULL, 0); + + /* Digest the key name. */ + n = ns_name_ntol(name, buf, sizeof(buf)); + dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0); + + /* Digest the class and TTL. */ + cp2 = buf; + PUTSHORT(ns_c_any, cp2); + PUTLONG(0, cp2); + dst_sign_data(SIG_MODE_UPDATE, key, &ctx, + buf, (unsigned)(cp2-buf), NULL, 0); + + /* Digest the algorithm. */ + n = ns_name_ntol(alg, buf, sizeof(buf)); + dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0); + + /* Digest the time signed, fudge, error, and other data */ + cp2 = buf; + PUTSHORT(0, cp2); /* Top 16 bits of time */ + if (error != ns_r_badtime) + PUTLONG(timesigned, cp2); + else + PUTLONG(in_timesigned, cp2); + PUTSHORT(NS_TSIG_FUDGE, cp2); + PUTSHORT(error, cp2); /* Error */ + if (error != ns_r_badtime) + PUTSHORT(0, cp2); /* Other data length */ + else { + PUTSHORT(INT16SZ+INT32SZ, cp2); /* Other data length */ + PUTSHORT(0, cp2); /* Top 16 bits of time */ + PUTLONG(timesigned, cp2); + } + dst_sign_data(SIG_MODE_UPDATE, key, &ctx, + buf, (unsigned)(cp2-buf), NULL, 0); + + n = dst_sign_data(SIG_MODE_FINAL, key, &ctx, NULL, 0, + sig, *siglen); + if (n < 0) + ISC_R_BADKEY; + *siglen = n; + } else + *siglen = 0; + + /* Add the signature. */ + BOUNDS_CHECK(cp, INT16SZ + (*siglen)); + PUTSHORT(*siglen, cp); + memcpy(cp, sig, *siglen); + cp += (*siglen); + + /* The original message ID & error. */ + BOUNDS_CHECK(cp, INT16SZ + INT16SZ); + PUTSHORT(ntohs(hp->id), cp); /* already in network order */ + PUTSHORT(error, cp); + + /* Other data. */ + BOUNDS_CHECK(cp, INT16SZ); + if (error != ns_r_badtime) + PUTSHORT(0, cp); /* Other data length */ + else { + PUTSHORT(INT16SZ+INT32SZ, cp); /* Other data length */ + BOUNDS_CHECK(cp, INT32SZ+INT16SZ); + PUTSHORT(0, cp); /* Top 16 bits of time */ + PUTLONG(timesigned, cp); + } + + /* Go back and fill in the length. */ + PUTSHORT(cp - lenp - INT16SZ, lenp); + + hp->arcount = htons(ntohs(hp->arcount) + 1); + *msglen = (cp - msg); + return ISC_R_SUCCESS; +} + +#if 0 +isc_result_t +ns_sign_tcp_init(void *k, const u_char *querysig, unsigned querysiglen, + ns_tcp_tsig_state *state) +{ + dst_init(); + if (state == NULL || k == NULL || querysig == NULL || querysiglen < 0) + return ISC_R_INVALIDARG; + state->counter = -1; + state->key = k; + if (state->key->dk_alg != KEY_HMAC_MD5) + return ISC_R_BADKEY; + if (querysiglen > sizeof(state->sig)) + return ISC_R_NOSPACE; + memcpy(state->sig, querysig, querysiglen); + state->siglen = querysiglen; + return ISC_R_SUCCESS; +} + +isc_result_t +ns_sign_tcp(u_char *msg, unsigned *msglen, unsigned msgsize, int error, + ns_tcp_tsig_state *state, int done) +{ + u_char *cp, *eob, *lenp; + u_char buf[MAXDNAME], *cp2; + HEADER *hp = (HEADER *)msg; + time_t timesigned; + int n; + + if (msg == NULL || msglen == NULL || state == NULL) + return ISC_R_INVALIDARG; + + state->counter++; + if (state->counter == 0) + return ns_sign(msg, msglen, msgsize, error, state->key, + state->sig, state->siglen, + state->sig, &state->siglen, 0); + + if (state->siglen > 0) { + u_int16_t siglen_n = htons(state->siglen); + dst_sign_data(SIG_MODE_INIT, state->key, &state->ctx, + NULL, 0, NULL, 0); + dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx, + (u_char *)&siglen_n, INT16SZ, NULL, 0); + dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx, + state->sig, state->siglen, NULL, 0); + state->siglen = 0; + } + + dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx, msg, *msglen, + NULL, 0); + + if (done == 0 && (state->counter % 100 != 0)) + return ISC_R_SUCCESS; + + cp = msg + *msglen; + eob = msg + msgsize; + + /* Name. */ + n = dn_comp(state->key->dk_key_name, + cp, (unsigned)(eob - cp), NULL, NULL); + if (n < 0) + return ISC_R_NOSPACE; + cp += n; + + /* Type, class, ttl, length (not filled in yet). */ + BOUNDS_CHECK(cp, INT16SZ + INT16SZ + INT32SZ + INT16SZ); + PUTSHORT(ns_t_tsig, cp); + PUTSHORT(ns_c_any, cp); + PUTLONG(0, cp); /* TTL */ + lenp = cp; + cp += 2; + + /* Alg. */ + n = dn_comp(NS_TSIG_ALG_HMAC_MD5, + cp, (unsigned)(eob - cp), NULL, NULL); + if (n < 0) + return ISC_R_NOSPACE; + cp += n; + + /* Time. */ + BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ); + PUTSHORT(0, cp); + timesigned = time(NULL); + PUTLONG(timesigned, cp); + PUTSHORT(NS_TSIG_FUDGE, cp); + + /* + * Compute the signature. + */ + + /* Digest the time signed and fudge. */ + cp2 = buf; + PUTSHORT(0, cp2); /* Top 16 bits of time */ + PUTLONG(timesigned, cp2); + PUTSHORT(NS_TSIG_FUDGE, cp2); + + dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx, + buf, (unsigned)(cp2 - buf), NULL, 0); + + n = dst_sign_data(SIG_MODE_FINAL, state->key, &state->ctx, NULL, 0, + state->sig, sizeof(state->sig)); + if (n < 0) + return ISC_R_BADKEY; + state->siglen = n; + + /* Add the signature. */ + BOUNDS_CHECK(cp, INT16SZ + state->siglen); + PUTSHORT(state->siglen, cp); + memcpy(cp, state->sig, state->siglen); + cp += state->siglen; + + /* The original message ID & error. */ + BOUNDS_CHECK(cp, INT16SZ + INT16SZ); + PUTSHORT(ntohs(hp->id), cp); /* already in network order */ + PUTSHORT(error, cp); + + /* Other data. */ + BOUNDS_CHECK(cp, INT16SZ); + PUTSHORT(0, cp); + + /* Go back and fill in the length. */ + PUTSHORT(cp - lenp - INT16SZ, lenp); + + hp->arcount = htons(ntohs(hp->arcount) + 1); + *msglen = (cp - msg); + return ISC_R_SUCCESS; +} +#endif diff --git a/contrib/isc-dhcp/minires/ns_verify.c b/contrib/isc-dhcp/minires/ns_verify.c new file mode 100644 index 0000000..1408da6 --- /dev/null +++ b/contrib/isc-dhcp/minires/ns_verify.c @@ -0,0 +1,475 @@ +/* + * Copyright (c) 1999-2001 by Internet Software Consortium, Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#ifndef lint +static const char rcsid[] = "$Id: ns_verify.c,v 1.5.2.1 2001/05/17 20:47:34 mellon Exp $"; +#endif + +#define time(x) trace_mr_time (x) + +/* Import. */ + +#include <sys/types.h> +#include <sys/param.h> + +#include <netinet/in.h> +#include <arpa/inet.h> +#include <sys/socket.h> + +#include <errno.h> +#include <netdb.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <time.h> + +#include "minires/minires.h" +#include "arpa/nameser.h" +#include <isc-dhcp/dst.h> + +time_t trace_mr_time (time_t *); + +/* Private. */ + +#define BOUNDS_CHECK(ptr, count) \ + do { \ + if ((ptr) + (count) > eom) { \ + return (NS_TSIG_ERROR_FORMERR); \ + } \ + } while (0) + +/* Public. */ + +u_char * +ns_find_tsig(u_char *msg, u_char *eom) { + HEADER *hp = (HEADER *)msg; + int n, type; + u_char *cp = msg, *start; + + if (msg == NULL || eom == NULL || msg > eom) + return (NULL); + + if (cp + HFIXEDSZ >= eom) + return (NULL); + + if (hp->arcount == 0) + return (NULL); + + cp += HFIXEDSZ; + + n = ns_skiprr(cp, eom, ns_s_qd, ntohs(hp->qdcount)); + if (n < 0) + return (NULL); + cp += n; + + n = ns_skiprr(cp, eom, ns_s_an, ntohs(hp->ancount)); + if (n < 0) + return (NULL); + cp += n; + + n = ns_skiprr(cp, eom, ns_s_ns, ntohs(hp->nscount)); + if (n < 0) + return (NULL); + cp += n; + + n = ns_skiprr(cp, eom, ns_s_ar, ntohs(hp->arcount) - 1); + if (n < 0) + return (NULL); + cp += n; + + start = cp; + n = dn_skipname(cp, eom); + if (n < 0) + return (NULL); + cp += n; + if (cp + INT16SZ >= eom) + return (NULL); + + GETSHORT(type, cp); + if (type != ns_t_tsig) + return (NULL); + return (start); +} + +/* ns_verify + * Parameters: + * statp res stuff + * msg received message + * msglen length of message + * key tsig key used for verifying. + * querysig (response), the signature in the query + * querysiglen (response), the length of the signature in the query + * sig (query), a buffer to hold the signature + * siglen (query), input - length of signature buffer + * output - length of signature + * + * Errors: + * - bad input (-1) + * - invalid dns message (NS_TSIG_ERROR_FORMERR) + * - TSIG is not present (NS_TSIG_ERROR_NO_TSIG) + * - key doesn't match (-ns_r_badkey) + * - TSIG verification fails with BADKEY (-ns_r_badkey) + * - TSIG verification fails with BADSIG (-ns_r_badsig) + * - TSIG verification fails with BADTIME (-ns_r_badtime) + * - TSIG verification succeeds, error set to BAKEY (ns_r_badkey) + * - TSIG verification succeeds, error set to BADSIG (ns_r_badsig) + * - TSIG verification succeeds, error set to BADTIME (ns_r_badtime) + */ +isc_result_t +ns_verify(u_char *msg, unsigned *msglen, void *k, + const u_char *querysig, unsigned querysiglen, + u_char *sig, unsigned *siglen, time_t *timesigned, int nostrip) +{ + HEADER *hp = (HEADER *)msg; + DST_KEY *key = (DST_KEY *)k; + u_char *cp = msg, *eom; + char name[MAXDNAME], alg[MAXDNAME]; + u_char *recstart, *rdatastart; + u_char *sigstart, *otherstart; + unsigned n; + int error; + u_int16_t type, length; + u_int16_t fudge, sigfieldlen, id, otherfieldlen; + + dst_init(); + if (msg == NULL || msglen == NULL || *msglen < 0) + return ISC_R_INVALIDARG; + + eom = msg + *msglen; + + recstart = ns_find_tsig(msg, eom); + if (recstart == NULL) + return ISC_R_NO_TSIG; + + cp = recstart; + + /* Read the key name. */ + n = dn_expand(msg, eom, cp, name, MAXDNAME); + if (n < 0) + return ISC_R_FORMERR; + cp += n; + + /* Read the type. */ + BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ); + GETSHORT(type, cp); + if (type != ns_t_tsig) + return ISC_R_NO_TSIG; + + /* Skip the class and TTL, save the length. */ + cp += INT16SZ + INT32SZ; + GETSHORT(length, cp); + if (eom - cp != length) + return ISC_R_FORMERR; + + /* Read the algorithm name. */ + rdatastart = cp; + n = dn_expand(msg, eom, cp, alg, MAXDNAME); + if (n < 0) + return ISC_R_FORMERR; + if (ns_samename(alg, NS_TSIG_ALG_HMAC_MD5) != 1) + return ISC_R_INVALIDKEY; + cp += n; + + /* Read the time signed and fudge. */ + BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ); + cp += INT16SZ; + GETLONG((*timesigned), cp); + GETSHORT(fudge, cp); + + /* Read the signature. */ + BOUNDS_CHECK(cp, INT16SZ); + GETSHORT(sigfieldlen, cp); + BOUNDS_CHECK(cp, sigfieldlen); + sigstart = cp; + cp += sigfieldlen; + + /* Read the original id and error. */ + BOUNDS_CHECK(cp, 2*INT16SZ); + GETSHORT(id, cp); + GETSHORT(error, cp); + + /* Parse the other data. */ + BOUNDS_CHECK(cp, INT16SZ); + GETSHORT(otherfieldlen, cp); + BOUNDS_CHECK(cp, otherfieldlen); + otherstart = cp; + cp += otherfieldlen; + + if (cp != eom) + return ISC_R_FORMERR; + + /* Verify that the key used is OK. */ + if (key != NULL) { + if (key->dk_alg != KEY_HMAC_MD5) + return ISC_R_INVALIDKEY; + if (error != ns_r_badsig && error != ns_r_badkey) { + if (ns_samename(key->dk_key_name, name) != 1) + return ISC_R_INVALIDKEY; + } + } + + hp->arcount = htons(ntohs(hp->arcount) - 1); + + /* + * Do the verification. + */ + + if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) { + void *ctx; + u_char buf[MAXDNAME]; + + /* Digest the query signature, if this is a response. */ + dst_verify_data(SIG_MODE_INIT, key, &ctx, NULL, 0, NULL, 0); + if (querysiglen > 0 && querysig != NULL) { + u_int16_t len_n = htons(querysiglen); + dst_verify_data(SIG_MODE_UPDATE, key, &ctx, + (u_char *)&len_n, INT16SZ, NULL, 0); + dst_verify_data(SIG_MODE_UPDATE, key, &ctx, + querysig, querysiglen, NULL, 0); + } + + /* Digest the message. */ + dst_verify_data(SIG_MODE_UPDATE, key, &ctx, msg, + (unsigned)(recstart - msg), NULL, 0); + + /* Digest the key name. */ + n = ns_name_ntol(recstart, buf, sizeof(buf)); + dst_verify_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0); + + /* Digest the class and TTL. */ + dst_verify_data(SIG_MODE_UPDATE, key, &ctx, + recstart + dn_skipname(recstart, eom) + INT16SZ, + INT16SZ + INT32SZ, NULL, 0); + + /* Digest the algorithm. */ + n = ns_name_ntol(rdatastart, buf, sizeof(buf)); + dst_verify_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0); + + /* Digest the time signed and fudge. */ + dst_verify_data(SIG_MODE_UPDATE, key, &ctx, + rdatastart + dn_skipname(rdatastart, eom), + INT16SZ + INT32SZ + INT16SZ, NULL, 0); + + /* Digest the error and other data. */ + dst_verify_data(SIG_MODE_UPDATE, key, &ctx, + otherstart - INT16SZ - INT16SZ, + (unsigned)otherfieldlen + INT16SZ + INT16SZ, + NULL, 0); + + n = dst_verify_data(SIG_MODE_FINAL, key, &ctx, NULL, 0, + sigstart, sigfieldlen); + + if (n < 0) + return ISC_R_BADSIG; + + if (sig != NULL && siglen != NULL) { + if (*siglen < sigfieldlen) + return ISC_R_NOSPACE; + memcpy(sig, sigstart, sigfieldlen); + *siglen = sigfieldlen; + } + } else { + if (sigfieldlen > 0) + return ISC_R_FORMERR; + if (sig != NULL && siglen != NULL) + *siglen = 0; + } + + /* Reset the counter, since we still need to check for badtime. */ + hp->arcount = htons(ntohs(hp->arcount) + 1); + + /* Verify the time. */ + if (abs((*timesigned) - time(NULL)) > fudge) + return ISC_R_BADTIME; + + if (nostrip == 0) { + *msglen = recstart - msg; + hp->arcount = htons(ntohs(hp->arcount) - 1); + } + + if (error != NOERROR) + return ns_rcode_to_isc (error); + + return ISC_R_SUCCESS; +} + +#if 0 +isc_result_t +ns_verify_tcp_init(void *k, const u_char *querysig, unsigned querysiglen, + ns_tcp_tsig_state *state) +{ + dst_init(); + if (state == NULL || k == NULL || querysig == NULL || querysiglen < 0) + return ISC_R_INVALIDARG; + state->counter = -1; + state->key = k; + if (state->key->dk_alg != KEY_HMAC_MD5) + return ISC_R_BADKEY; + if (querysiglen > sizeof(state->sig)) + return ISC_R_NOSPACE; + memcpy(state->sig, querysig, querysiglen); + state->siglen = querysiglen; + return ISC_R_SUCCESS; +} + +isc_result_t +ns_verify_tcp(u_char *msg, unsigned *msglen, ns_tcp_tsig_state *state, + int required) +{ + HEADER *hp = (HEADER *)msg; + u_char *recstart, *rdatastart, *sigstart; + unsigned sigfieldlen, otherfieldlen; + u_char *cp, *eom = msg + *msglen, *cp2; + char name[MAXDNAME], alg[MAXDNAME]; + u_char buf[MAXDNAME]; + int n, type, length, fudge, id, error; + time_t timesigned; + + if (msg == NULL || msglen == NULL || state == NULL) + return ISC_R_INVALIDARG; + + state->counter++; + if (state->counter == 0) + return (ns_verify(msg, msglen, state->key, + state->sig, state->siglen, + state->sig, &state->siglen, ×igned, 0)); + + if (state->siglen > 0) { + u_int16_t siglen_n = htons(state->siglen); + + dst_verify_data(SIG_MODE_INIT, state->key, &state->ctx, + NULL, 0, NULL, 0); + dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx, + (u_char *)&siglen_n, INT16SZ, NULL, 0); + dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx, + state->sig, state->siglen, NULL, 0); + state->siglen = 0; + } + + cp = recstart = ns_find_tsig(msg, eom); + + if (recstart == NULL) { + if (required) + return ISC_R_NO_TSIG; + dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx, + msg, *msglen, NULL, 0); + return ISC_R_SUCCESS; + } + + hp->arcount = htons(ntohs(hp->arcount) - 1); + dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx, + msg, (unsigned)(recstart - msg), NULL, 0); + + /* Read the key name. */ + n = dn_expand(msg, eom, cp, name, MAXDNAME); + if (n < 0) + return ISC_R_FORMERR; + cp += n; + + /* Read the type. */ + BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ); + GETSHORT(type, cp); + if (type != ns_t_tsig) + return ISC_R_NO_TSIG; + + /* Skip the class and TTL, save the length. */ + cp += INT16SZ + INT32SZ; + GETSHORT(length, cp); + if (eom - cp != length) + return ISC_R_FORMERR; + + /* Read the algorithm name. */ + rdatastart = cp; + n = dn_expand(msg, eom, cp, alg, MAXDNAME); + if (n < 0) + return ISC_R_FORMERR; + if (ns_samename(alg, NS_TSIG_ALG_HMAC_MD5) != 1) + return ISC_R_BADKEY; + cp += n; + + /* Verify that the key used is OK. */ + if ((ns_samename(state->key->dk_key_name, name) != 1 || + state->key->dk_alg != KEY_HMAC_MD5)) + return ISC_R_BADKEY; + + /* Read the time signed and fudge. */ + BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ); + cp += INT16SZ; + GETLONG(timesigned, cp); + GETSHORT(fudge, cp); + + /* Read the signature. */ + BOUNDS_CHECK(cp, INT16SZ); + GETSHORT(sigfieldlen, cp); + BOUNDS_CHECK(cp, sigfieldlen); + sigstart = cp; + cp += sigfieldlen; + + /* Read the original id and error. */ + BOUNDS_CHECK(cp, 2*INT16SZ); + GETSHORT(id, cp); + GETSHORT(error, cp); + + /* Parse the other data. */ + BOUNDS_CHECK(cp, INT16SZ); + GETSHORT(otherfieldlen, cp); + BOUNDS_CHECK(cp, otherfieldlen); + cp += otherfieldlen; + + if (cp != eom) + return ISC_R_FORMERR; + + /* + * Do the verification. + */ + + /* Digest the time signed and fudge. */ + cp2 = buf; + PUTSHORT(0, cp2); /* Top 16 bits of time. */ + PUTLONG(timesigned, cp2); + PUTSHORT(NS_TSIG_FUDGE, cp2); + + dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx, + buf, (unsigned)(cp2 - buf), NULL, 0); + + n = dst_verify_data(SIG_MODE_FINAL, state->key, &state->ctx, NULL, 0, + sigstart, sigfieldlen); + if (n < 0) + return ISC_R_BADSIG; + + if (sigfieldlen > sizeof(state->sig)) + return ISC_R_BADSIG; + + if (sigfieldlen > sizeof(state->sig)) + return ISC_R_NOSPACE; + + memcpy(state->sig, sigstart, sigfieldlen); + state->siglen = sigfieldlen; + + /* Verify the time. */ + if (abs(timesigned - time(NULL)) > fudge) + return ISC_R_BADTIME; + + *msglen = recstart - msg; + + if (error != NOERROR) + return ns_rcode_to_isc (error); + + return ISC_R_SUCCESS; +} +#endif diff --git a/contrib/isc-dhcp/minires/res_comp.c b/contrib/isc-dhcp/minires/res_comp.c new file mode 100644 index 0000000..4ca538e --- /dev/null +++ b/contrib/isc-dhcp/minires/res_comp.c @@ -0,0 +1,236 @@ +/* + * Copyright (c) 1985, 1993 + * 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 the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, 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. + */ + +/* + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char sccsid[] = "@(#)res_comp.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "$Id: res_comp.c,v 1.2 2000/02/02 19:59:16 mellon Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <sys/param.h> +#include <netinet/in.h> +#include <ctype.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <sys/socket.h> + +#include "minires/minires.h" +#include "arpa/nameser.h" + +/* + * Expand compressed domain name 'comp_dn' to full domain name. + * 'msg' is a pointer to the begining of the message, + * 'eomorig' points to the first location after the message, + * 'exp_dn' is a pointer to a buffer of size 'length' for the result. + * Return size of compressed name or -1 if there was an error. + */ +int +dn_expand(const u_char *msg, const u_char *eom, const u_char *src, + char *dst, unsigned dstsiz) +{ + int n = ns_name_uncompress(msg, eom, src, dst, (size_t)dstsiz); + + if (n > 0 && dst[0] == '.') + dst[0] = '\0'; + return (n); +} + +/* + * Pack domain name 'exp_dn' in presentation form into 'comp_dn'. + * Return the size of the compressed name or -1. + * 'length' is the size of the array pointed to by 'comp_dn'. + */ +int +dn_comp(const char *src, u_char *dst, unsigned dstsiz, + u_char **dnptrs, u_char **lastdnptr) +{ + return (ns_name_compress(src, dst, (size_t)dstsiz, + (const u_char **)dnptrs, + (const u_char **)lastdnptr)); +} + +/* + * Skip over a compressed domain name. Return the size or -1. + */ +int +dn_skipname(const u_char *ptr, const u_char *eom) { + const u_char *saveptr = ptr; + + if (ns_name_skip(&ptr, eom) == -1) + return (-1); + return (ptr - saveptr); +} + +/* + * Verify that a domain name uses an acceptable character set. + */ + +#if 0 +/* + * Note the conspicuous absence of ctype macros in these definitions. On + * non-ASCII hosts, we can't depend on string literals or ctype macros to + * tell us anything about network-format data. The rest of the BIND system + * is not careful about this, but for some reason, we're doing it right here. + */ +#define PERIOD 0x2e +#define hyphenchar(c) ((c) == 0x2d) +#define bslashchar(c) ((c) == 0x5c) +#define periodchar(c) ((c) == PERIOD) +#define asterchar(c) ((c) == 0x2a) +#define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) \ + || ((c) >= 0x61 && (c) <= 0x7a)) +#define digitchar(c) ((c) >= 0x30 && (c) <= 0x39) + +#define borderchar(c) (alphachar(c) || digitchar(c)) +#define middlechar(c) (borderchar(c) || hyphenchar(c)) +#define domainchar(c) ((c) > 0x20 && (c) < 0x7f) + +int +res_hnok(const char *dn) { + int ppch = '\0', pch = PERIOD, ch = *dn++; + + while (ch != '\0') { + int nch = *dn++; + + if (periodchar(ch)) { + (void)NULL; + } else if (periodchar(pch)) { + if (!borderchar(ch)) + return (0); + } else if (periodchar(nch) || nch == '\0') { + if (!borderchar(ch)) + return (0); + } else { + if (!middlechar(ch)) + return (0); + } + ppch = pch, pch = ch, ch = nch; + } + return (1); +} + +/* + * hostname-like (A, MX, WKS) owners can have "*" as their first label + * but must otherwise be as a host name. + */ +int +res_ownok(const char *dn) { + if (asterchar(dn[0])) { + if (periodchar(dn[1])) + return (res_hnok(dn+2)); + if (dn[1] == '\0') + return (1); + } + return (res_hnok(dn)); +} + +/* + * SOA RNAMEs and RP RNAMEs can have any printable character in their first + * label, but the rest of the name has to look like a host name. + */ +int +res_mailok(const char *dn) { + int ch, escaped = 0; + + /* "." is a valid missing representation */ + if (*dn == '\0') + return (1); + + /* otherwise <label>.<hostname> */ + while ((ch = *dn++) != '\0') { + if (!domainchar(ch)) + return (0); + if (!escaped && periodchar(ch)) + break; + if (escaped) + escaped = 0; + else if (bslashchar(ch)) + escaped = 1; + } + if (periodchar(ch)) + return (res_hnok(dn)); + return (0); +} + +/* + * This function is quite liberal, since RFC 1034's character sets are only + * recommendations. + */ +int +res_dnok(const char *dn) { + int ch; + + while ((ch = *dn++) != '\0') + if (!domainchar(ch)) + return (0); + return (1); +} +#endif diff --git a/contrib/isc-dhcp/minires/res_findzonecut.c b/contrib/isc-dhcp/minires/res_findzonecut.c new file mode 100644 index 0000000..fc86900 --- /dev/null +++ b/contrib/isc-dhcp/minires/res_findzonecut.c @@ -0,0 +1,608 @@ +#if !defined(lint) && !defined(SABER) +static const char rcsid[] = "$Id: res_findzonecut.c,v 1.14.2.1 2001/05/17 20:47:35 mellon Exp $"; +#endif /* not lint */ + +/* + * Copyright (c) 1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, 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. + */ + +/* Import. */ + +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/time.h> + +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <errno.h> +#include <limits.h> +#include <netdb.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <isc-dhcp/list.h> + +#include "minires/minires.h" +#include "arpa/nameser.h" + +/* Data structures. */ + +typedef struct rr_a { + ISC_LINK(struct rr_a) link; + struct in_addr addr; +} rr_a; +typedef ISC_LIST(rr_a) rrset_a; + +typedef struct rr_ns { + ISC_LINK(struct rr_ns) link; + char *name; + rrset_a addrs; +} rr_ns; +typedef ISC_LIST(rr_ns) rrset_ns; + +/* Forward. */ + +static int satisfy(res_state, + const char *, rrset_ns *, struct in_addr *, int); +static int add_addrs(res_state, rr_ns *, struct in_addr *, int); +static ns_rcode get_soa(res_state, const char *, ns_class, + char *, size_t, char *, size_t, + rrset_ns *); +static isc_result_t get_ns(res_state, const char *, ns_class, rrset_ns *); +static isc_result_t get_glue(res_state, ns_class, rrset_ns *); +static isc_result_t save_ns(res_state, ns_msg *, ns_sect, + const char *, ns_class, rrset_ns *); +static isc_result_t save_a(res_state, ns_msg *, ns_sect, + const char *, ns_class, rrset_a *); +static void free_nsrrset(rrset_ns *); +static void free_nsrr(rrset_ns *, rr_ns *); +static rr_ns * find_ns(rrset_ns *, const char *); +static isc_result_t do_query(res_state, const char *, ns_class, ns_type, + double *, ns_msg *, int *); + +/* Public. */ + +/* + * int + * res_findzonecut(res, dname, class, zname, zsize, addrs, naddrs) + * find enclosing zone for a <dname,class>, and some server addresses + * parameters: + * res - resolver context to work within (is modified) + * dname - domain name whose enclosing zone is desired + * class - class of dname (and its enclosing zone) + * zname - found zone name + * zsize - allocated size of zname + * addrs - found server addresses + * naddrs - max number of addrs + * return values: + * < 0 - an error occurred (check errno) + * = 0 - zname is now valid, but addrs[] wasn't changed + * > 0 - zname is now valid, and return value is number of addrs[] found + * notes: + * this function calls res_nsend() which means it depends on correctly + * functioning recursive nameservers (usually defined in /etc/resolv.conf + * or its local equivilent). + * + * we start by asking for an SOA<dname,class>. if we get one as an + * answer, that just means <dname,class> is a zone top, which is fine. + * more than likely we'll be told to go pound sand, in the form of a + * negative answer. + * + * note that we are not prepared to deal with referrals since that would + * only come from authority servers and our correctly functioning local + * recursive server would have followed the referral and got us something + * more definite. + * + * if the authority section contains an SOA, this SOA should also be the + * closest enclosing zone, since any intermediary zone cuts would've been + * returned as referrals and dealt with by our correctly functioning local + * recursive name server. but an SOA in the authority section should NOT + * match our dname (since that would have been returned in the answer + * section). an authority section SOA has to be "above" our dname. + * + * we cannot fail to find an SOA in this way. ultimately we'll return + * a zname indicating the root zone if that's the closest enclosing zone. + * however, since authority section SOA's were once optional, it's + * possible that we'll have to go hunting for the enclosing SOA by + * ripping labels off the front of our dname -- this is known as "doing + * it the hard way." + * + * ultimately we want some server addresses, which are ideally the ones + * pertaining to the SOA.MNAME, but only if there is a matching NS RR. + * so the second phase (after we find an SOA) is to go looking for the + * NS RRset for that SOA's zone. + * + * no answer section processed by this code is allowed to contain CNAME + * or DNAME RR's. for the SOA query this means we strip a label and + * keep going. for the NS and A queries this means we just give up. + */ + +isc_result_t +res_findzonecut(res_state statp, const char *dname, ns_class class, int opts, + char *zname, size_t zsize, struct in_addr *addrs, int naddrs, + int *count, void *zcookie) +{ + char mname[NS_MAXDNAME]; + u_long save_pfcode; + rrset_ns nsrrs; + int n = 0; + isc_result_t rcode; + + DPRINTF(("START dname='%s' class=%s, zsize=%ld, naddrs=%d", + dname, p_class(class), (long)zsize, naddrs)); + save_pfcode = statp->pfcode; + statp->pfcode |= RES_PRF_HEAD2 | RES_PRF_HEAD1 | RES_PRF_HEADX | + RES_PRF_QUES | RES_PRF_ANS | + RES_PRF_AUTH | RES_PRF_ADD; + ISC_LIST_INIT(nsrrs); + + DPRINTF (("look for a predefined zone statement")); + rcode = find_cached_zone (dname, class, zname, zsize, + addrs, naddrs, &n, zcookie); + if (rcode == ISC_R_SUCCESS) + goto done; + + DPRINTF(("get the soa, and see if it has enough glue")); + if ((rcode = get_soa(statp, dname, class, zname, zsize, + mname, sizeof mname, &nsrrs)) != ISC_R_SUCCESS || + ((opts & RES_EXHAUSTIVE) == 0 && + (n = satisfy(statp, mname, &nsrrs, addrs, naddrs)) > 0)) + goto done; + + DPRINTF(("get the ns rrset and see if it has enough glue")); + if ((rcode = get_ns(statp, zname, class, &nsrrs)) != ISC_R_SUCCESS || + ((opts & RES_EXHAUSTIVE) == 0 && + (n = satisfy(statp, mname, &nsrrs, addrs, naddrs)) > 0)) + goto done; + + DPRINTF(("get the missing glue and see if it's finally enough")); + if ((rcode = get_glue(statp, class, &nsrrs)) == ISC_R_SUCCESS) + n = satisfy(statp, mname, &nsrrs, addrs, naddrs); + + /* If we found the zone, cache it. */ + if (n > 0) + cache_found_zone (class, zname, addrs, n); + done: + DPRINTF(("FINISH n=%d (%s)", n, (n < 0) ? strerror(errno) : "OK")); + free_nsrrset(&nsrrs); + statp->pfcode = save_pfcode; + if (count) + *count = n; + return rcode; +} + +/* Private. */ + +static int +satisfy(res_state statp, + const char *mname, rrset_ns *nsrrsp, struct in_addr *addrs, int naddrs) +{ + rr_ns *nsrr; + int n, x; + + n = 0; + nsrr = find_ns(nsrrsp, mname); + if (nsrr != NULL) { + x = add_addrs(statp, nsrr, addrs, naddrs); + addrs += x; + naddrs -= x; + n += x; + } + for (nsrr = ISC_LIST_HEAD(*nsrrsp); + nsrr != NULL && naddrs > 0; + nsrr = ISC_LIST_NEXT(nsrr, link)) + if (ns_samename(nsrr->name, mname) != 1) { + x = add_addrs(statp, nsrr, addrs, naddrs); + addrs += x; + naddrs -= x; + n += x; + } + DPRINTF(("satisfy(%s): %d", mname, n)); + return (n); +} + +static int +add_addrs(res_state statp, rr_ns *nsrr, struct in_addr *addrs, int naddrs) { + rr_a *arr; + int n = 0; + + for (arr = ISC_LIST_HEAD(nsrr->addrs); + arr != NULL; arr = ISC_LIST_NEXT(arr, link)) { + if (naddrs <= 0) + return (0); + *addrs++ = arr->addr; + naddrs--; + n++; + } + DPRINTF(("add_addrs: %d", n)); + return (n); +} + +static ns_rcode +get_soa(res_state statp, const char *dname, ns_class class, + char *zname, size_t zsize, char *mname, size_t msize, + rrset_ns *nsrrsp) +{ + char tname[NS_MAXDNAME]; + double resp[NS_PACKETSZ / sizeof (double)]; + int n, i, ancount, nscount; + ns_sect sect; + ns_msg msg; + u_int rcode; + isc_result_t status; + + /* + * Find closest enclosing SOA, even if it's for the root zone. + */ + + /* First canonicalize dname (exactly one unescaped trailing "."). */ + status = ns_makecanon(dname, tname, sizeof tname); + if (status != ISC_R_SUCCESS) + return status; + dname = tname; + + /* Now grovel the subdomains, hunting for an SOA answer or auth. */ + for (;;) { + /* Leading or inter-label '.' are skipped here. */ + while (*dname == '.') + dname++; + + /* Is there an SOA? */ + rcode = do_query(statp, dname, class, ns_t_soa, + resp, &msg, &n); + if (rcode != ISC_R_SUCCESS) { + DPRINTF(("get_soa: do_query('%s', %s) failed (%d)", + dname, p_class(class), n)); + return rcode; + } + if (n > 0) { + DPRINTF(("get_soa: CNAME or DNAME found")); + sect = ns_s_max, n = 0; + } else { + ancount = ns_msg_count(msg, ns_s_an); + nscount = ns_msg_count(msg, ns_s_ns); + if (ancount > 0 && rcode == ISC_R_SUCCESS) + sect = ns_s_an, n = ancount; + else if (nscount > 0) + sect = ns_s_ns, n = nscount; + else + sect = ns_s_max, n = 0; + } + for (i = 0; i < n; i++) { + const char *t; + const u_char *rdata; + int rdlen; + ns_rr rr; + + rcode = ns_parserr(&msg, sect, i, &rr) < 0; + if (rcode != ISC_R_SUCCESS) { + DPRINTF(("get_soa: ns_parserr(%s, %d) failed", + p_section(sect, ns_o_query), i)); + return rcode; + } + if (ns_rr_type(rr) == ns_t_cname || + ns_rr_type(rr) == ns_t_dname) + break; + if (ns_rr_type(rr) != ns_t_soa || + ns_rr_class(rr) != class) + continue; + t = ns_rr_name(rr); + switch (sect) { + case ns_s_an: + if (ns_samedomain(dname, t) == 0) { + DPRINTF(("get_soa: %s'%s', '%s') == 0", + "ns_samedomain(", dname, t)); + return ISC_R_NOTZONE; + } + break; + case ns_s_ns: + if (ns_samename(dname, t) == 1 || + ns_samedomain(dname, t) == 0) { + DPRINTF(("get_soa: %smain('%s', '%s')", + "ns_samename() || !ns_samedo", + dname, t)); + return ISC_R_NOTZONE; + } + break; + default: + abort(); + } + if (strlen(t) + 1 > zsize) { + DPRINTF(("get_soa: zname(%d) too small (%d)", + zsize, strlen(t) + 1)); + return ISC_R_NOSPACE; + } + strcpy(zname, t); + rdata = ns_rr_rdata(rr); + rdlen = ns_rr_rdlen(rr); + if (ns_name_uncompress((u_char *)resp, + ns_msg_end(msg), rdata, + mname, msize) < 0) { + DPRINTF(("get_soa: %s failed", + "ns_name_uncompress")); + return ISC_R_NOMEMORY; + } + rcode = save_ns(statp, &msg, + ns_s_ns, zname, class, nsrrsp); + if (rcode != ISC_R_SUCCESS) { + DPRINTF(("get_soa: save_ns failed")); + return rcode; + } + return ISC_R_SUCCESS; + } + + /* If we're out of labels, then not even "." has an SOA! */ + if (*dname == '\0') + break; + + /* Find label-terminating "."; top of loop will skip it. */ + while (*dname != '.') { + if (*dname == '\\') + if (*++dname == '\0') { + ISC_R_NOSPACE; + } + dname++; + } + } + DPRINTF(("get_soa: out of labels")); + return ISC_R_DESTADDRREQ; +} + +static isc_result_t +get_ns(res_state statp, const char *zname, ns_class class, rrset_ns *nsrrsp) { + double resp[NS_PACKETSZ / sizeof (double)]; + ns_msg msg; + int n; + isc_result_t rcode; + + /* Go and get the NS RRs for this zone. */ + rcode = do_query(statp, zname, class, ns_t_ns, resp, &msg, &n); + if (rcode != ISC_R_SUCCESS) { + DPRINTF(("get_ns: do_query('zname', %s) failed (%d)", + zname, p_class(class), rcode)); + return rcode; + } + + /* Remember the NS RRs and associated A RRs that came back. */ + rcode = save_ns(statp, &msg, ns_s_an, zname, class, nsrrsp); + if (rcode != ISC_R_SUCCESS) { + DPRINTF(("get_ns save_ns('%s', %s) failed", + zname, p_class(class))); + return rcode; + } + + return ISC_R_SUCCESS; +} + +static isc_result_t +get_glue(res_state statp, ns_class class, rrset_ns *nsrrsp) { + rr_ns *nsrr, *nsrr_n; + + /* Go and get the A RRs for each empty NS RR on our list. */ + for (nsrr = ISC_LIST_HEAD(*nsrrsp); nsrr != NULL; nsrr = nsrr_n) { + double resp[NS_PACKETSZ / sizeof (double)]; + ns_msg msg; + int n; + isc_result_t rcode; + + nsrr_n = ISC_LIST_NEXT(nsrr, link); + + if (ISC_LIST_EMPTY(nsrr->addrs)) { + rcode = do_query(statp, nsrr->name, class, ns_t_a, + resp, &msg, &n); + if (rcode != ISC_R_SUCCESS) { + DPRINTF(("get_glue: do_query('%s', %s') failed", + nsrr->name, p_class(class))); + return rcode; + } + if (n > 0) { + DPRINTF(( + "get_glue: do_query('%s', %s') CNAME or DNAME found", + nsrr->name, p_class(class))); + } + rcode = save_a(statp, &msg, ns_s_an, nsrr->name, class, + &nsrr->addrs); + if (rcode != ISC_R_SUCCESS) { + DPRINTF(("get_glue: save_r('%s', %s) failed", + nsrr->name, p_class(class))); + return rcode; + } + /* If it's still empty, it's just chaff. */ + if (ISC_LIST_EMPTY(nsrr->addrs)) { + DPRINTF(("get_glue: removing empty '%s' NS", + nsrr->name)); + free_nsrr(nsrrsp, nsrr); + } + } + } + return ISC_R_SUCCESS; +} + +static isc_result_t +save_ns(res_state statp, ns_msg *msg, ns_sect sect, + const char *owner, ns_class class, + rrset_ns *nsrrsp) +{ + int i; + isc_result_t rcode; + + for (i = 0; i < ns_msg_count(*msg, sect); i++) { + char tname[MAXDNAME]; + const u_char *rdata; + rr_ns *nsrr; + ns_rr rr; + int rdlen; + + rcode = ns_parserr(msg, sect, i, &rr); + if (rcode != ISC_R_SUCCESS) { + DPRINTF(("save_ns: ns_parserr(%s, %d) failed", + p_section(sect, ns_o_query), i)); + return rcode; + } + if (ns_rr_type(rr) != ns_t_ns || + ns_rr_class(rr) != class || + ns_samename(ns_rr_name(rr), owner) != 1) + continue; + nsrr = find_ns(nsrrsp, ns_rr_name(rr)); + if (nsrr == NULL) { + nsrr = malloc(sizeof *nsrr); + if (nsrr == NULL) { + DPRINTF(("save_ns: malloc failed")); + return ISC_R_NOMEMORY; + } + rdata = ns_rr_rdata(rr); + rdlen = ns_rr_rdlen(rr); + if (ns_name_uncompress(ns_msg_base(*msg), + ns_msg_end(*msg), rdata, + tname, sizeof tname) < 0) { + DPRINTF(("save_ns: ns_name_uncompress failed")); + free(nsrr); + return ISC_R_NOMEMORY; + } + nsrr->name = strdup(tname); + if (nsrr->name == NULL) { + DPRINTF(("save_ns: strdup failed")); + free(nsrr); + return ISC_R_NOMEMORY; + } + ISC_LIST_INIT(nsrr->addrs); + ISC_LIST_APPEND(*nsrrsp, nsrr, link); + } + rcode = save_a(statp, msg, ns_s_ar, + nsrr->name, class, &nsrr->addrs); + if (rcode != ISC_R_SUCCESS) { + DPRINTF(("save_ns: save_r('%s', %s) failed", + nsrr->name, p_class(class))); + return rcode; + } + } + return ISC_R_SUCCESS; +} + +static isc_result_t +save_a(res_state statp, ns_msg *msg, ns_sect sect, + const char *owner, ns_class class, + rrset_a *arrsp) +{ + int i; + isc_result_t rcode; + + for (i = 0; i < ns_msg_count(*msg, sect); i++) { + ns_rr rr; + rr_a *arr; + + rcode = ns_parserr(msg, sect, i, &rr); + if (rcode != ISC_R_SUCCESS) { + DPRINTF(("save_a: ns_parserr(%s, %d) failed", + p_section(sect, ns_o_query), i)); + return rcode; + } + if (ns_rr_type(rr) != ns_t_a || + ns_rr_class(rr) != class || + ns_samename(ns_rr_name(rr), owner) != 1 || + ns_rr_rdlen(rr) != NS_INADDRSZ) + continue; + arr = malloc(sizeof *arr); + if (arr == NULL) { + DPRINTF(("save_a: malloc failed")); + return ISC_R_NOMEMORY; + } + memcpy(&arr->addr, ns_rr_rdata(rr), NS_INADDRSZ); + ISC_LIST_APPEND(*arrsp, arr, link); + } + return ISC_R_SUCCESS; +} + +static void +free_nsrrset(rrset_ns *nsrrsp) { + rr_ns *nsrr; + + while ((nsrr = ISC_LIST_HEAD(*nsrrsp)) != NULL) + free_nsrr(nsrrsp, nsrr); +} + +static void +free_nsrr(rrset_ns *nsrrsp, rr_ns *nsrr) { + rr_a *arr; + + while ((arr = ISC_LIST_HEAD(nsrr->addrs)) != NULL) { + ISC_LIST_UNLINK(nsrr->addrs, arr, link); + free(arr); + } + free((char *)nsrr->name); + ISC_LIST_UNLINK(*nsrrsp, nsrr, link); + free(nsrr); +} + +static rr_ns * +find_ns(rrset_ns *nsrrsp, const char *dname) { + rr_ns *nsrr; + + for (nsrr = ISC_LIST_HEAD(*nsrrsp); + nsrr != NULL; nsrr = ISC_LIST_NEXT(nsrr, link)) + if (ns_samename(nsrr->name, dname) == 1) + return (nsrr); + return (NULL); +} + +static isc_result_t +do_query(res_state statp, const char *dname, ns_class class, ns_type qtype, + double *resp, ns_msg *msg, int *alias_count) +{ + double req[NS_PACKETSZ / sizeof (double)]; + int i; + unsigned n; + isc_result_t status; + + status = res_nmkquery(statp, ns_o_query, dname, class, qtype, + NULL, 0, NULL, req, NS_PACKETSZ, &n); + if (status != ISC_R_SUCCESS) { + DPRINTF(("do_query: res_nmkquery failed")); + return status; + } + status = res_nsend(statp, req, n, resp, NS_PACKETSZ, &n); + if (status != ISC_R_SUCCESS) { + DPRINTF(("do_query: res_nsend failed")); + return status; + } + if (n == 0) { + DPRINTF(("do_query: res_nsend returned 0")); + return ISC_R_NOTFOUND; + } + if (ns_initparse((u_char *)resp, n, msg) < 0) { + DPRINTF(("do_query: ns_initparse failed")); + return ISC_R_NOSPACE; + } + n = 0; + for (i = 0; i < ns_msg_count(*msg, ns_s_an); i++) { + ns_rr rr; + + status = ns_parserr(msg, ns_s_an, i, &rr); + if (status != ISC_R_SUCCESS) { + DPRINTF(("do_query: ns_parserr failed")); + return status; + } + n += (ns_rr_class(rr) == class && + (ns_rr_type(rr) == ns_t_cname || + ns_rr_type(rr) == ns_t_dname)); + } + if (alias_count) + *alias_count = n; + return ISC_R_SUCCESS; +} diff --git a/contrib/isc-dhcp/minires/res_init.c b/contrib/isc-dhcp/minires/res_init.c new file mode 100644 index 0000000..b646b8e --- /dev/null +++ b/contrib/isc-dhcp/minires/res_init.c @@ -0,0 +1,486 @@ +/* + * Copyright (c) 1985, 1989, 1993 + * 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 the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, 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. + */ + +/* + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char sccsid[] = "@(#)res_init.c 8.1 (Berkeley) 6/7/93"; +static const char rcsid[] = "$Id: res_init.c,v 1.4.2.1 2001/06/22 02:57:54 mellon Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/time.h> + +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "minires/minires.h" +#include "arpa/nameser.h" + +/* Options. Should all be left alone. */ +#define RESOLVSORT +#define RFC1535 +#define DEBUG + +static void res_setoptions (res_state, const char *, const char *); + +#ifdef RESOLVSORT +static const char sort_mask[] = "/&"; +#define ISSORTMASK(ch) (strchr(sort_mask, ch) != NULL) +static u_int32_t net_mask (struct in_addr); +#endif + +#if !defined(isascii) /* XXX - could be a function */ +# define isascii(c) (!(c & 0200)) +#endif + +/* + * Resolver state default settings. + */ + +/* + * Set up default settings. If the configuration file exist, the values + * there will have precedence. Otherwise, the server address is set to + * INADDR_ANY and the default domain name comes from the gethostname(). + * + * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1 + * rather than INADDR_ANY ("0.0.0.0") as the default name server address + * since it was noted that INADDR_ANY actually meant ``the first interface + * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface, + * it had to be "up" in order for you to reach your own name server. It + * was later decided that since the recommended practice is to always + * install local static routes through 127.0.0.1 for all your network + * interfaces, that we could solve this problem without a code change. + * + * The configuration file should always be used, since it is the only way + * to specify a default domain. If you are running a server on your local + * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1" + * in the configuration file. + * + * Return 0 if completes successfully, -1 on error + */ +extern int minires_vinit(res_state, int); + +#if defined (TRACING) +u_int trace_mr_res_randomid(u_int); +#endif + +int +res_ninit(res_state statp) { + + return (minires_vinit(statp, 0)); +} + +/* This function has to be reachable by res_data.c but not publically. */ +int +minires_vinit(res_state statp, int preinit) { + register FILE *fp; + register char *cp, **pp; + register int n; + char buf[BUFSIZ]; + int nserv = 0; /* number of nameserver records read from file */ + int haveenv = 0; + int havesearch = 0; +#ifdef RESOLVSORT + int nsort = 0; + char *net; +#endif +#ifndef RFC1535 + int dots; +#endif + + if (!preinit) { + statp->retrans = RES_TIMEOUT; + statp->retry = RES_DFLRETRY; + statp->options = RES_DEFAULT; + statp->id = res_randomid(); +#if defined (TRACING) + statp->id = trace_mr_res_randomid (statp -> id); +#endif + } + +#ifdef USELOOPBACK + statp->nsaddr.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1); +#else + statp->nsaddr.sin_addr.s_addr = INADDR_ANY; +#endif + statp->nsaddr.sin_family = AF_INET; + statp->nsaddr.sin_port = htons(NAMESERVER_PORT); + statp->nscount = 1; + statp->ndots = 1; + statp->pfcode = 0; + statp->_sock = -1; + statp->_flags = 0; + statp->qhook = NULL; + statp->rhook = NULL; + + /* Allow user to override the local domain definition */ + if ((cp = getenv("LOCALDOMAIN")) != NULL) { + (void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); + statp->defdname[sizeof(statp->defdname) - 1] = '\0'; + haveenv++; + + /* + * Set search list to be blank-separated strings + * from rest of env value. Permits users of LOCALDOMAIN + * to still have a search list, and anyone to set the + * one that they want to use as an individual (even more + * important now that the rfc1535 stuff restricts searches) + */ + cp = statp->defdname; + pp = statp->dnsrch; + *pp++ = cp; + for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) { + if (*cp == '\n') /* silly backwards compat */ + break; + else if (*cp == ' ' || *cp == '\t') { + *cp = 0; + n = 1; + } else if (n) { + *pp++ = cp; + n = 0; + havesearch = 1; + } + } + /* null terminate last domain if there are excess */ + while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n') + cp++; + *cp = '\0'; + *pp++ = 0; + } + +#define MATCH(line, name) \ + (!strncmp(line, name, sizeof(name) - 1) && \ + (line[sizeof(name) - 1] == ' ' || \ + line[sizeof(name) - 1] == '\t')) + + if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) { + /* read the config file */ + while (fgets(buf, sizeof(buf), fp) != NULL) { + /* skip comments */ + if (*buf == ';' || *buf == '#') + continue; + /* read default domain name */ + if (MATCH(buf, "domain")) { + if (haveenv) /* skip if have from environ */ + continue; + cp = buf + sizeof("domain") - 1; + while (*cp == ' ' || *cp == '\t') + cp++; + if ((*cp == '\0') || (*cp == '\n')) + continue; + strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); + statp->defdname[sizeof(statp->defdname) - 1] = '\0'; + if ((cp = strpbrk(statp->defdname, " \t\n")) != NULL) + *cp = '\0'; + havesearch = 0; + continue; + } + /* set search list */ + if (MATCH(buf, "search")) { + if (haveenv) /* skip if have from environ */ + continue; + cp = buf + sizeof("search") - 1; + while (*cp == ' ' || *cp == '\t') + cp++; + if ((*cp == '\0') || (*cp == '\n')) + continue; + strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); + statp->defdname[sizeof(statp->defdname) - 1] = '\0'; + if ((cp = strchr(statp->defdname, '\n')) != NULL) + *cp = '\0'; + /* + * Set search list to be blank-separated strings + * on rest of line. + */ + cp = statp->defdname; + pp = statp->dnsrch; + *pp++ = cp; + for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) { + if (*cp == ' ' || *cp == '\t') { + *cp = 0; + n = 1; + } else if (n) { + *pp++ = cp; + n = 0; + } + } + /* null terminate last domain if there are excess */ + while (*cp != '\0' && *cp != ' ' && *cp != '\t') + cp++; + *cp = '\0'; + *pp++ = 0; + havesearch = 1; + continue; + } + /* read nameservers to query */ + if (MATCH(buf, "nameserver") && nserv < MAXNS) { + struct in_addr a; + + cp = buf + sizeof("nameserver") - 1; + while (*cp == ' ' || *cp == '\t') + cp++; + if ((*cp != '\0') && (*cp != '\n') && inet_aton(cp, &a)) { + statp->nsaddr_list[nserv].sin_addr = a; + statp->nsaddr_list[nserv].sin_family = AF_INET; + statp->nsaddr_list[nserv].sin_port = + htons(NAMESERVER_PORT); + nserv++; + } + continue; + } +#ifdef RESOLVSORT + if (MATCH(buf, "sortlist")) { + struct in_addr a; + + cp = buf + sizeof("sortlist") - 1; + while (nsort < MAXRESOLVSORT) { + while (*cp == ' ' || *cp == '\t') + cp++; + if (*cp == '\0' || *cp == '\n' || *cp == ';') + break; + net = cp; + while (*cp && !ISSORTMASK(*cp) && *cp != ';' && + isascii(*cp) && !isspace(*cp)) + cp++; + n = *cp; + *cp = 0; + if (inet_aton(net, &a)) { + statp->sort_list[nsort].addr = a; + if (ISSORTMASK(n)) { + *cp++ = n; + net = cp; + while (*cp && *cp != ';' && + isascii(*cp) && !isspace(*cp)) + cp++; + n = *cp; + *cp = 0; + if (inet_aton(net, &a)) { + statp->sort_list[nsort].mask = a.s_addr; + } else { + statp->sort_list[nsort].mask = + net_mask(statp->sort_list[nsort].addr); + } + } else { + statp->sort_list[nsort].mask = + net_mask(statp->sort_list[nsort].addr); + } + nsort++; + } + *cp = n; + } + continue; + } +#endif + if (MATCH(buf, "options")) { + res_setoptions(statp, buf + sizeof("options") - 1, "conf"); + continue; + } + } + if (nserv > 1) + statp->nscount = nserv; +#ifdef RESOLVSORT + statp->nsort = nsort; +#endif + (void) fclose(fp); + } + if (statp->defdname[0] == 0 && + gethostname(buf, sizeof(statp->defdname) - 1) == 0 && + (cp = strchr(buf, '.')) != NULL) + strcpy(statp->defdname, cp + 1); + + /* find components of local domain that might be searched */ + if (havesearch == 0) { + pp = statp->dnsrch; + *pp++ = statp->defdname; + *pp = NULL; + +#ifndef RFC1535 + dots = 0; + for (cp = statp->defdname; *cp; cp++) + dots += (*cp == '.'); + + cp = statp->defdname; + while (pp < statp->dnsrch + MAXDFLSRCH) { + if (dots < LOCALDOMAINPARTS) + break; + cp = strchr(cp, '.') + 1; /* we know there is one */ + *pp++ = cp; + dots--; + } + *pp = NULL; +#ifdef DEBUG + if (statp->options & RES_DEBUG) { + printf(";; res_init()... default dnsrch list:\n"); + for (pp = statp->dnsrch; *pp; pp++) + printf(";;\t%s\n", *pp); + printf(";;\t..END..\n"); + } +#endif +#endif /* !RFC1535 */ + } + + if ((cp = getenv("RES_OPTIONS")) != NULL) + res_setoptions(statp, cp, "env"); + statp->options |= RES_INIT; + return (0); +} + +static void +res_setoptions(res_state statp, const char *options, const char *source) { + const char *cp = options; + int i; + +#ifdef DEBUG + if (statp->options & RES_DEBUG) + printf(";; res_setoptions(\"%s\", \"%s\")...\n", + options, source); +#endif + while (*cp) { + /* skip leading and inner runs of spaces */ + while (*cp == ' ' || *cp == '\t') + cp++; + /* search for and process individual options */ + if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) { + i = atoi(cp + sizeof("ndots:") - 1); + if (i <= RES_MAXNDOTS) + statp->ndots = i; + else + statp->ndots = RES_MAXNDOTS; +#ifdef DEBUG + if (statp->options & RES_DEBUG) + printf(";;\tndots=%d\n", statp->ndots); +#endif + } else if (!strncmp(cp, "timeout:", sizeof("timeout:") - 1)) { + i = atoi(cp + sizeof("timeout:") - 1); + if (i <= RES_MAXRETRANS) + statp->retrans = i; + else + statp->retrans = RES_MAXRETRANS; + } else if (!strncmp(cp, "attempts:", sizeof("attempts:") - 1)){ + i = atoi(cp + sizeof("attempts:") - 1); + if (i <= RES_MAXRETRY) + statp->retry = i; + else + statp->retry = RES_MAXRETRY; + } else if (!strncmp(cp, "debug", sizeof("debug") - 1)) { +#ifdef DEBUG + if (!(statp->options & RES_DEBUG)) { + printf(";; res_setoptions(\"%s\", \"%s\")..\n", + options, source); + statp->options |= RES_DEBUG; + } + printf(";;\tdebug\n"); +#endif + } else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) { + statp->options |= RES_USE_INET6; + } else if (!strncmp(cp, "rotate", sizeof("rotate") - 1)) { + statp->options |= RES_ROTATE; + } else if (!strncmp(cp, "no-check-names", + sizeof("no-check-names") - 1)) { + statp->options |= RES_NOCHECKNAME; + } else { + /* XXX - print a warning here? */ + } + /* skip to next run of spaces */ + while (*cp && *cp != ' ' && *cp != '\t') + cp++; + } +} + +#ifdef RESOLVSORT +/* XXX - should really support CIDR which means explicit masks always. */ +static u_int32_t +net_mask(in) /* XXX - should really use system's version of this */ + struct in_addr in; +{ + register u_int32_t i = ntohl(in.s_addr); + + if (IN_CLASSA(i)) + return (htonl(IN_CLASSA_NET)); + else if (IN_CLASSB(i)) + return (htonl(IN_CLASSB_NET)); + return (htonl(IN_CLASSC_NET)); +} +#endif + +u_int +res_randomid(void) { + struct timeval now; + + gettimeofday(&now, NULL); + return (0xffff & (now.tv_sec ^ now.tv_usec ^ getpid())); +} diff --git a/contrib/isc-dhcp/minires/res_mkquery.c b/contrib/isc-dhcp/minires/res_mkquery.c new file mode 100644 index 0000000..88fe7e6 --- /dev/null +++ b/contrib/isc-dhcp/minires/res_mkquery.c @@ -0,0 +1,193 @@ +/* + * Copyright (c) 1985, 1993 + * 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 the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, 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. + */ + +/* + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char sccsid[] = "@(#)res_mkquery.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "$Id: res_mkquery.c,v 1.4 2001/01/16 22:33:14 mellon Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <sys/param.h> +#include <netinet/in.h> +#include <netdb.h> +#include <stdio.h> +#include <string.h> +#include <sys/socket.h> + +#include "minires/minires.h" +#include "arpa/nameser.h" + +extern const char *_res_opcodes[]; + +/* + * Form all types of queries. + * Returns the size of the result or -1. + */ +isc_result_t +res_nmkquery(res_state statp, + int op, /* opcode of query */ + const char *dname, /* domain name */ + ns_class class, ns_type type, /* class and type of query */ + const u_char *data, /* resource record data */ + unsigned datalen, /* length of data */ + const u_char *newrr_in, /* new rr for modify or append */ + double *buf, /* buffer to put query */ + unsigned buflen, /* size of buffer */ + unsigned *rbuflen) /* returned size of buffer */ +{ + register HEADER *hp; + register u_char *cp; + register int n; + u_char *dnptrs[20], **dpp, **lastdnptr; + + /* + * Initialize header fields. + */ + if ((buf == NULL) || (buflen < HFIXEDSZ)) + return ISC_R_INVALIDARG; + memset(buf, 0, HFIXEDSZ); + hp = (HEADER *) buf; + hp->id = htons(++statp->id); + hp->opcode = op; + hp->rd = (statp->options & RES_RECURSE) != 0; + hp->rcode = NOERROR; + cp = ((u_char *)buf) + HFIXEDSZ; + buflen -= HFIXEDSZ; + dpp = dnptrs; + *dpp++ = (u_char *)buf; + *dpp++ = NULL; + lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0]; + /* + * perform opcode specific processing + */ + switch (op) { + case QUERY: /*FALLTHROUGH*/ + case NS_NOTIFY_OP: + if ((buflen -= QFIXEDSZ) < 0) + return ISC_R_NOSPACE; + if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0) + return ISC_R_NOSPACE; + cp += n; + buflen -= n; + putUShort(cp, type); + cp += INT16SZ; + putUShort(cp, class); + cp += INT16SZ; + hp->qdcount = htons(1); + if (op == QUERY || data == NULL) + break; + /* + * Make an additional record for completion domain. + */ + buflen -= RRFIXEDSZ; + n = dn_comp((const char *)data, cp, buflen, dnptrs, lastdnptr); + if (n < 0) + return ISC_R_NOSPACE; + cp += n; + buflen -= n; + putUShort(cp, T_NULL); + cp += INT16SZ; + putUShort(cp, class); + cp += INT16SZ; + putULong(cp, 0); + cp += INT32SZ; + putUShort(cp, 0); + cp += INT16SZ; + hp->arcount = htons(1); + break; + + case IQUERY: + /* + * Initialize answer section + */ + if (buflen < 1 + RRFIXEDSZ + datalen) + return ISC_R_NOSPACE; + *cp++ = '\0'; /* no domain name */ + putUShort(cp, type); + cp += INT16SZ; + putUShort(cp, class); + cp += INT16SZ; + putULong(cp, 0); + cp += INT32SZ; + putUShort(cp, datalen); + cp += INT16SZ; + if (datalen) { + memcpy(cp, data, datalen); + cp += datalen; + } + hp->ancount = htons(1); + break; + + default: + return ISC_R_NOTIMPLEMENTED; + } + *rbuflen = cp - ((u_char *)buf); + return ISC_R_SUCCESS; +} diff --git a/contrib/isc-dhcp/minires/res_mkupdate.c b/contrib/isc-dhcp/minires/res_mkupdate.c new file mode 100644 index 0000000..5520a83 --- /dev/null +++ b/contrib/isc-dhcp/minires/res_mkupdate.c @@ -0,0 +1,1101 @@ +/* + * Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, 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. + */ + +/* + * Based on the Dynamic DNS reference implementation by Viraj Bais + * <viraj_bais@ccm.fm.intel.com> + */ + +#if !defined(lint) && !defined(SABER) +static const char rcsid[] = "$Id: res_mkupdate.c,v 1.7 2001/01/11 02:16:24 mellon Exp $"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/param.h> + +#include <netinet/in.h> +#include <arpa/inet.h> +#include <sys/socket.h> + +#include <errno.h> +#include <limits.h> +#include <netdb.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <ctype.h> + +#include "minires/minires.h" +#include "arpa/nameser.h" + +/* Options. Leave them on. */ +#define DEBUG +#define MAXPORT 1024 + +static int getnum_str(const u_char **, const u_char *); +static int gethexnum_str(const u_char **, const u_char *); +static int getword_str(char *, int, + const unsigned char **, + const unsigned char *); +static int getstr_str(char *, int, const u_char **, const u_char *); + +struct valuelist { + struct valuelist * next; + struct valuelist * prev; + char * name; + char * proto; + int port; +}; + +static int findservice(const char *, struct valuelist **); +static struct servent *cgetservbyport(unsigned, const char *); + +#define ShrinkBuffer(x) if ((buflen -= x) < 0) return (-2); + +/* Forward. */ + +int res_protocolnumber(const char *); +int res_servicenumber(const char *); +static struct protoent *cgetprotobynumber(int); + +/* + * Form update packets. + * Returns the size of the resulting packet if no error + * On error, + * returns -1 if error in reading a word/number in rdata + * portion for update packets + * -2 if length of buffer passed is insufficient + * -3 if zone section is not the first section in + * the linked list, or section order has a problem + * -4 on a number overflow + * -5 unknown operation or no records + */ +int +res_nmkupdate(res_state statp, + ns_updrec *rrecp_in, double *bp, unsigned *blp) { + ns_updrec *rrecp_start = rrecp_in; + HEADER *hp; + u_char *cp, *sp1, *sp2; + const unsigned char *startp, *endp; + int n, i, soanum, multiline; + ns_updrec *rrecp; + struct in_addr ina; + char buf2[MAXDNAME]; + u_char buf3[MAXDNAME]; + int section, numrrs = 0, counts[ns_s_max]; + u_int16_t rtype, rclass; + u_int32_t n1, rttl; + u_char *dnptrs[20], **dpp, **lastdnptr; + unsigned siglen, keylen, certlen; + unsigned buflen = *blp; + u_char *buf = (unsigned char *)bp; + + /* + * Initialize header fields. + */ + if ((buf == NULL) || (buflen < HFIXEDSZ)) + return -1; + memset(buf, 0, HFIXEDSZ); + hp = (HEADER *) buf; + hp->id = htons(++statp->id); + hp->opcode = ns_o_update; + hp->rcode = NOERROR; + sp1 = buf + 2*INT16SZ; /* save pointer to zocount */ + cp = buf + HFIXEDSZ; + buflen -= HFIXEDSZ; + dpp = dnptrs; + *dpp++ = buf; + *dpp++ = NULL; + lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0]; + + if (rrecp_start == NULL) + return (-5); + else if (rrecp_start->r_section != S_ZONE) + return (-3); + + memset(counts, 0, sizeof counts); + for (rrecp = rrecp_start; rrecp; rrecp = ISC_LIST_NEXT(rrecp, + r_glink)) { + numrrs++; + section = rrecp->r_section; + if (section < 0 || section >= ns_s_max) + return (-1); + counts[section]++; + for (i = section + 1; i < ns_s_max; i++) + if (counts[i]) + return (-3); + rtype = rrecp->r_type; + rclass = rrecp->r_class; + rttl = rrecp->r_ttl; + /* overload class and type */ + if (section == S_PREREQ) { + rttl = 0; + switch (rrecp->r_opcode) { + case YXDOMAIN: + rclass = C_ANY; + rtype = T_ANY; + rrecp->r_size = 0; + break; + case NXDOMAIN: + rclass = C_NONE; + rtype = T_ANY; + rrecp->r_size = 0; + break; + case NXRRSET: + rclass = C_NONE; + rrecp->r_size = 0; + break; + case YXRRSET: + if (rrecp->r_size == 0) + rclass = C_ANY; + break; + default: + fprintf(stderr, + "res_mkupdate: incorrect opcode: %d\n", + rrecp->r_opcode); + fflush(stderr); + return (-1); + } + } else if (section == S_UPDATE) { + switch (rrecp->r_opcode) { + case DELETE: + rclass = rrecp->r_size == 0 ? C_ANY : C_NONE; + break; + case ADD: + break; + default: + fprintf(stderr, + "res_mkupdate: incorrect opcode: %d\n", + rrecp->r_opcode); + fflush(stderr); + return (-1); + } + } + + /* + * XXX appending default domain to owner name is omitted, + * fqdn must be provided + */ + if ((n = dn_comp(rrecp->r_dname, cp, buflen, dnptrs, + lastdnptr)) < 0) + return (-1); + cp += n; + ShrinkBuffer(n + 2*INT16SZ); + PUTSHORT(rtype, cp); + PUTSHORT(rclass, cp); + if (section == S_ZONE) { + if (numrrs != 1 || rrecp->r_type != T_SOA) + return (-3); + continue; + } + ShrinkBuffer(INT32SZ + INT16SZ); + PUTLONG(rttl, cp); + sp2 = cp; /* save pointer to length byte */ + cp += INT16SZ; + if (rrecp->r_size == 0) { + if (section == S_UPDATE && rclass != C_ANY) + return (-1); + else { + PUTSHORT(0, sp2); + continue; + } + } + startp = rrecp->r_data; + endp = startp + rrecp->r_size - 1; + /* XXX this should be done centrally. */ + switch (rrecp->r_type) { + case T_A: + if (!getword_str(buf2, sizeof buf2, &startp, endp)) + return (-1); + if (!inet_aton(buf2, &ina)) + return (-1); + n1 = ntohl(ina.s_addr); + ShrinkBuffer(INT32SZ); + PUTLONG(n1, cp); + break; + case T_CNAME: + case T_MB: + case T_MG: + case T_MR: + case T_NS: + case T_PTR: + if (!getword_str(buf2, sizeof buf2, &startp, endp)) + return (-1); + n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); + if (n < 0) + return (-1); + cp += n; + ShrinkBuffer(n); + break; + case T_MINFO: + case T_SOA: + case T_RP: + for (i = 0; i < 2; i++) { + if (!getword_str(buf2, sizeof buf2, &startp, + endp)) + return (-1); + n = dn_comp(buf2, cp, buflen, + dnptrs, lastdnptr); + if (n < 0) + return (-1); + cp += n; + ShrinkBuffer(n); + } + if (rrecp->r_type == T_SOA) { + ShrinkBuffer(5 * INT32SZ); + while (isspace(*startp) || !*startp) + startp++; + if (*startp == '(') { + multiline = 1; + startp++; + } else + multiline = 0; + /* serial, refresh, retry, expire, minimum */ + for (i = 0; i < 5; i++) { + soanum = getnum_str(&startp, endp); + if (soanum < 0) + return (-1); + PUTLONG(soanum, cp); + } + if (multiline) { + while (isspace(*startp) || !*startp) + startp++; + if (*startp != ')') + return (-1); + } + } + break; + case T_MX: + case T_AFSDB: + case T_RT: + n = getnum_str(&startp, endp); + if (n < 0) + return (-1); + ShrinkBuffer(INT16SZ); + PUTSHORT(n, cp); + if (!getword_str(buf2, sizeof buf2, &startp, endp)) + return (-1); + n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); + if (n < 0) + return (-1); + cp += n; + ShrinkBuffer(n); + break; + case T_SRV: + n = getnum_str(&startp, endp); + if (n < 0) + return (-1); + ShrinkBuffer(INT16SZ); + PUTSHORT(n, cp); + + n = getnum_str(&startp, endp); + if (n < 0) + return (-1); + ShrinkBuffer(INT16SZ); + PUTSHORT(n, cp); + + n = getnum_str(&startp, endp); + if (n < 0) + return (-1); + ShrinkBuffer(INT16SZ); + PUTSHORT(n, cp); + + if (!getword_str(buf2, sizeof buf2, &startp, endp)) + return (-1); + n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); + if (n < 0) + return (-1); + cp += n; + ShrinkBuffer(n); + break; + case T_PX: + n = getnum_str(&startp, endp); + if (n < 0) + return (-1); + PUTSHORT(n, cp); + ShrinkBuffer(INT16SZ); + for (i = 0; i < 2; i++) { + if (!getword_str(buf2, sizeof buf2, &startp, + endp)) + return (-1); + n = dn_comp(buf2, cp, buflen, dnptrs, + lastdnptr); + if (n < 0) + return (-1); + cp += n; + ShrinkBuffer(n); + } + break; + case T_WKS: { + char bm[MAXPORT/8]; + unsigned maxbm = 0; + + if (!getword_str(buf2, sizeof buf2, &startp, endp)) + return (-1); + if (!inet_aton(buf2, &ina)) + return (-1); + n1 = ntohl(ina.s_addr); + ShrinkBuffer(INT32SZ); + PUTLONG(n1, cp); + + if (!getword_str(buf2, sizeof buf2, &startp, endp)) + return (-1); + if ((i = res_protocolnumber(buf2)) < 0) + return (-1); + ShrinkBuffer(1); + *cp++ = i & 0xff; + + for (i = 0; i < MAXPORT/8 ; i++) + bm[i] = 0; + + while (getword_str(buf2, sizeof buf2, &startp, endp)) { + if ((n1 = res_servicenumber(buf2)) <= 0) + return (-1); + + if (n1 < MAXPORT) { + bm[n1/8] |= (0x80>>(n1%8)); + if (n1 > maxbm) + maxbm = n1; + } else + return (-1); + } + maxbm = maxbm/8 + 1; + ShrinkBuffer(maxbm); + memcpy(cp, bm, maxbm); + cp += maxbm; + break; + } + case T_HINFO: + for (i = 0; i < 2; i++) { + if ((n = getstr_str(buf2, sizeof buf2, + &startp, endp)) < 0) + return (-1); + if (n > 255) + return (-1); + ShrinkBuffer(n+1); + *cp++ = n; + memcpy(cp, buf2, (unsigned)n); + cp += n; + } + break; + case T_TXT: + while (1) { + if ((n = getstr_str(buf2, sizeof buf2, + &startp, endp)) < 0) { + if (cp != (sp2 + INT16SZ)) + break; + return (-1); + } + if (n > 255) + return (-1); + ShrinkBuffer(n+1); + *cp++ = n; + memcpy(cp, buf2, (unsigned)n); + cp += n; + } + break; + case T_X25: + /* RFC 1183 */ + if ((n = getstr_str(buf2, sizeof buf2, &startp, + endp)) < 0) + return (-1); + if (n > 255) + return (-1); + ShrinkBuffer(n+1); + *cp++ = n; + memcpy(cp, buf2, (unsigned)n); + cp += n; + break; + case T_ISDN: + /* RFC 1183 */ + if ((n = getstr_str(buf2, sizeof buf2, &startp, + endp)) < 0) + return (-1); + if ((n > 255) || (n == 0)) + return (-1); + ShrinkBuffer(n+1); + *cp++ = n; + memcpy(cp, buf2, (unsigned)n); + cp += n; + if ((n = getstr_str(buf2, sizeof buf2, &startp, + endp)) < 0) + n = 0; + if (n > 255) + return (-1); + ShrinkBuffer(n+1); + *cp++ = n; + memcpy(cp, buf2, (unsigned)n); + cp += n; + break; +#if 0 + case T_NSAP: + if ((n = inet_nsap_addr((char *)startp, (u_char *)buf2, sizeof(buf2))) != 0) { + ShrinkBuffer(n); + memcpy(cp, buf2, n); + cp += n; + } else { + return (-1); + } + break; + case T_LOC: + if ((n = loc_aton((char *)startp, (u_char *)buf2)) != 0) { + ShrinkBuffer(n); + memcpy(cp, buf2, n); + cp += n; + } else + return (-1); + break; + case ns_t_sig: + { + int sig_type, success, dateerror; + u_int32_t exptime, timesigned; + + /* type */ + if ((n = getword_str(buf2, sizeof buf2, + &startp, endp)) < 0) + return (-1); + sig_type = sym_ston(__p_type_syms, buf2, &success); + if (!success || sig_type == ns_t_any) + return (-1); + ShrinkBuffer(INT16SZ); + PUTSHORT(sig_type, cp); + /* alg */ + n = getnum_str(&startp, endp); + if (n < 0) + return (-1); + ShrinkBuffer(1); + *cp++ = n; + /* labels */ + n = getnum_str(&startp, endp); + if (n <= 0 || n > 255) + return (-1); + ShrinkBuffer(1); + *cp++ = n; + /* ottl & expire */ + if (!getword_str(buf2, sizeof buf2, &startp, endp)) + return (-1); + exptime = ns_datetosecs(buf2, &dateerror); + if (!dateerror) { + ShrinkBuffer(INT32SZ); + PUTLONG(rttl, cp); + } + else { + char *ulendp; + u_int32_t ottl; + + ottl = strtoul(buf2, &ulendp, 10); + if (ulendp != NULL && *ulendp != '\0') + return (-1); + ShrinkBuffer(INT32SZ); + PUTLONG(ottl, cp); + if (!getword_str(buf2, sizeof buf2, &startp, + endp)) + return (-1); + exptime = ns_datetosecs(buf2, &dateerror); + if (dateerror) + return (-1); + } + /* expire */ + ShrinkBuffer(INT32SZ); + PUTLONG(exptime, cp); + /* timesigned */ + if (!getword_str(buf2, sizeof buf2, &startp, endp)) + return (-1); + timesigned = ns_datetosecs(buf2, &dateerror); + if (!dateerror) { + ShrinkBuffer(INT32SZ); + PUTLONG(timesigned, cp); + } + else + return (-1); + /* footprint */ + n = getnum_str(&startp, endp); + if (n < 0) + return (-1); + ShrinkBuffer(INT16SZ); + PUTSHORT(n, cp); + /* signer name */ + if (!getword_str(buf2, sizeof buf2, &startp, endp)) + return (-1); + n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); + if (n < 0) + return (-1); + cp += n; + ShrinkBuffer(n); + /* sig */ + if ((n = getword_str(buf2, sizeof buf2, + &startp, endp)) < 0) + return (-1); + siglen = b64_pton(buf2, buf3, sizeof(buf3)); + if (siglen < 0) + return (-1); + ShrinkBuffer(siglen); + memcpy(cp, buf3, siglen); + cp += siglen; + break; + } + case ns_t_key: + /* flags */ + n = gethexnum_str(&startp, endp); + if (n < 0) + return (-1); + ShrinkBuffer(INT16SZ); + PUTSHORT(n, cp); + /* proto */ + n = getnum_str(&startp, endp); + if (n < 0) + return (-1); + ShrinkBuffer(1); + *cp++ = n; + /* alg */ + n = getnum_str(&startp, endp); + if (n < 0) + return (-1); + ShrinkBuffer(1); + *cp++ = n; + /* key */ + if ((n = getword_str(buf2, sizeof buf2, + &startp, endp)) < 0) + return (-1); + keylen = b64_pton(buf2, buf3, sizeof(buf3)); + if (keylen < 0) + return (-1); + ShrinkBuffer(keylen); + memcpy(cp, buf3, keylen); + cp += keylen; + break; + case ns_t_nxt: + { + int success, nxt_type; + u_char data[32]; + int maxtype; + + /* next name */ + if (!getword_str(buf2, sizeof buf2, &startp, endp)) + return (-1); + n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); + if (n < 0) + return (-1); + cp += n; + ShrinkBuffer(n); + maxtype = 0; + memset(data, 0, sizeof data); + while (1) { + if (!getword_str(buf2, sizeof buf2, &startp, + endp)) + break; + nxt_type = sym_ston(__p_type_syms, buf2, + &success); + if (!success || !ns_t_rr_p(nxt_type)) + return (-1); + NS_NXT_BIT_SET(nxt_type, data); + if (nxt_type > maxtype) + maxtype = nxt_type; + } + n = maxtype/NS_NXT_BITS+1; + ShrinkBuffer(n); + memcpy(cp, data, n); + cp += n; + break; + } + case ns_t_cert: + /* type */ + n = getnum_str(&startp, endp); + if (n < 0) + return (-1); + ShrinkBuffer(INT16SZ); + PUTSHORT(n, cp); + /* key tag */ + n = getnum_str(&startp, endp); + if (n < 0) + return (-1); + ShrinkBuffer(INT16SZ); + PUTSHORT(n, cp); + /* alg */ + n = getnum_str(&startp, endp); + if (n < 0) + return (-1); + ShrinkBuffer(1); + *cp++ = n; + /* cert */ + if ((n = getword_str(buf2, sizeof buf2, + &startp, endp)) < 0) + return (-1); + certlen = b64_pton(buf2, buf3, sizeof(buf3)); + if (certlen < 0) + return (-1); + ShrinkBuffer(certlen); + memcpy(cp, buf3, certlen); + cp += certlen; + break; +#endif + default: + return (-1); + } /*switch*/ + n = (u_int16_t)((cp - sp2) - INT16SZ); + PUTSHORT(n, sp2); + } /*for*/ + + hp->qdcount = htons(counts[0]); + hp->ancount = htons(counts[1]); + hp->nscount = htons(counts[2]); + hp->arcount = htons(counts[3]); + *blp = cp - buf; + return 0; +} + +/* + * Get a whitespace delimited word from a string (not file) + * into buf. modify the start pointer to point after the + * word in the string. + */ +static int +getword_str(char *buf, int size, const u_char **startpp, const u_char *endp) { + char *cp; + int c; + + for (cp = buf; *startpp <= endp; ) { + c = **startpp; + if (isspace(c) || c == '\0') { + if (cp != buf) /* trailing whitespace */ + break; + else { /* leading whitespace */ + (*startpp)++; + continue; + } + } + (*startpp)++; + if (cp >= buf+size-1) + break; + *cp++ = (u_char)c; + } + *cp = '\0'; + return (cp != buf); +} + +/* + * get a white spae delimited string from memory. Process quoted strings + * and \DDD escapes. Return length or -1 on error. Returned string may + * contain nulls. + */ +static char digits[] = "0123456789"; +static int +getstr_str(char *buf, int size, const u_char **startpp, const u_char *endp) { + char *cp; + int c, c1 = 0; + int inquote = 0; + int seen_quote = 0; + int escape = 0; + int dig = 0; + + for (cp = buf; *startpp <= endp; ) { + if ((c = **startpp) == '\0') + break; + /* leading white space */ + if ((cp == buf) && !seen_quote && isspace(c)) { + (*startpp)++; + continue; + } + + switch (c) { + case '\\': + if (!escape) { + escape = 1; + dig = 0; + c1 = 0; + (*startpp)++; + continue; + } + goto do_escape; + case '"': + if (!escape) { + inquote = !inquote; + seen_quote = 1; + (*startpp)++; + continue; + } + /* fall through */ + default: + do_escape: + if (escape) { + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + c1 = c1 * 10 + + (strchr(digits, c) - digits); + + if (++dig == 3) { + c = c1 &0xff; + break; + } + (*startpp)++; + continue; + } + escape = 0; + } else if (!inquote && isspace(c)) + goto done; + if (cp >= buf+size-1) + goto done; + *cp++ = (u_char)c; + (*startpp)++; + } + } + done: + *cp = '\0'; + return ((cp == buf)? (seen_quote? 0: -1): (cp - buf)); +} +/* + * Get a whitespace delimited base 16 number from a string (not file) into buf + * update the start pointer to point after the number in the string. + */ +static int +gethexnum_str(const u_char **startpp, const u_char *endp) { + int c, n; + int seendigit = 0; + int m = 0; + + if (*startpp + 2 >= endp || + strncasecmp((const char *)*startpp, "0x", 2) != 0) + return getnum_str(startpp, endp); + (*startpp)+=2; + for (n = 0; *startpp <= endp; ) { + c = **startpp; + if (isspace(c) || c == '\0') { + if (seendigit) /* trailing whitespace */ + break; + else { /* leading whitespace */ + (*startpp)++; + continue; + } + } + if (c == ';') { + while ((*startpp <= endp) && + ((c = **startpp) != '\n')) + (*startpp)++; + if (seendigit) + break; + continue; + } + if (!isxdigit(c)) { + if (c == ')' && seendigit) { + (*startpp)--; + break; + } + return (-1); + } + (*startpp)++; + if (isdigit(c)) + n = n * 16 + (c - '0'); + else + n = n * 16 + (tolower(c) - 'a' + 10); + seendigit = 1; + } + return (n + m); +} + +/* + * Get a whitespace delimited base 16 number from a string (not file) into buf + * update the start pointer to point after the number in the string. + */ +static int +getnum_str(const u_char **startpp, const u_char *endp) { + int c, n; + int seendigit = 0; + int m = 0; + + for (n = 0; *startpp <= endp; ) { + c = **startpp; + if (isspace(c) || c == '\0') { + if (seendigit) /* trailing whitespace */ + break; + else { /* leading whitespace */ + (*startpp)++; + continue; + } + } + if (c == ';') { + while ((*startpp <= endp) && + ((c = **startpp) != '\n')) + (*startpp)++; + if (seendigit) + break; + continue; + } + if (!isdigit(c)) { + if (c == ')' && seendigit) { + (*startpp)--; + break; + } + return (-1); + } + (*startpp)++; + n = n * 10 + (c - '0'); + seendigit = 1; + } + return (n + m); +} + +/* + * Allocate a resource record buffer & save rr info. + */ +ns_updrec * +res_mkupdrec(int section, const char *dname, + u_int class, u_int type, u_long ttl) { + ns_updrec *rrecp = (ns_updrec *)calloc(1, sizeof(ns_updrec)); + + if (!rrecp || !(rrecp->r_dname = strdup(dname))) { + if (rrecp) + free((char *)rrecp); + return (NULL); + } + rrecp->r_class = class; + rrecp->r_type = type; + rrecp->r_ttl = ttl; + rrecp->r_section = section; + return (rrecp); +} + +/* + * Free a resource record buffer created by res_mkupdrec. + */ +void +res_freeupdrec(ns_updrec *rrecp) { + /* Note: freeing r_dp is the caller's responsibility. */ + if (rrecp->r_dname != NULL) + free(rrecp->r_dname); + free(rrecp); +} + +static struct valuelist *servicelist, *protolist; + +void +res_buildservicelist() { + struct servent *sp; + struct valuelist *slp; + +#ifdef MAYBE_HESIOD + setservent(0); +#else + setservent(1); +#endif + while ((sp = getservent()) != NULL) { + slp = (struct valuelist *)malloc(sizeof(struct valuelist)); + if (!slp) + break; + slp->name = strdup(sp->s_name); + slp->proto = strdup(sp->s_proto); + if ((slp->name == NULL) || (slp->proto == NULL)) { + if (slp->name) free(slp->name); + if (slp->proto) free(slp->proto); + free(slp); + break; + } + slp->port = ntohs((u_int16_t)sp->s_port); /* host byt order */ + slp->next = servicelist; + slp->prev = NULL; + if (servicelist) + servicelist->prev = slp; + servicelist = slp; + } + endservent(); +} + +void +res_destroyservicelist() { + struct valuelist *slp, *slp_next; + + for (slp = servicelist; slp != NULL; slp = slp_next) { + slp_next = slp->next; + free(slp->name); + free(slp->proto); + free(slp); + } + servicelist = (struct valuelist *)0; +} + +void +res_buildprotolist() { + struct protoent *pp; + struct valuelist *slp; + +#ifdef MAYBE_HESIOD + setprotoent(0); +#else + setprotoent(1); +#endif + while ((pp = getprotoent()) != NULL) { + slp = (struct valuelist *)malloc(sizeof(struct valuelist)); + if (!slp) + break; + slp->name = strdup(pp->p_name); + if (slp->name == NULL) { + free(slp); + break; + } + slp->port = pp->p_proto; /* host byte order */ + slp->next = protolist; + slp->prev = NULL; + if (protolist) + protolist->prev = slp; + protolist = slp; + } + endprotoent(); +} + +void +res_destroyprotolist() { + struct valuelist *plp, *plp_next; + + for (plp = protolist; plp != NULL; plp = plp_next) { + plp_next = plp->next; + free(plp->name); + free(plp); + } + protolist = (struct valuelist *)0; +} + +static int +findservice(const char *s, struct valuelist **list) { + struct valuelist *lp = *list; + int n; + + for (; lp != NULL; lp = lp->next) + if (strcasecmp(lp->name, s) == 0) { + if (lp != *list) { + lp->prev->next = lp->next; + if (lp->next) + lp->next->prev = lp->prev; + (*list)->prev = lp; + lp->next = *list; + *list = lp; + } + return (lp->port); /* host byte order */ + } + if (sscanf(s, "%d", &n) != 1 || n <= 0) + n = -1; + return (n); +} + +/* + * Convert service name or (ascii) number to int. + */ +int +res_servicenumber(const char *p) { + if (servicelist == (struct valuelist *)0) + res_buildservicelist(); + return (findservice(p, &servicelist)); +} + +/* + * Convert protocol name or (ascii) number to int. + */ +int +res_protocolnumber(const char *p) { + if (protolist == (struct valuelist *)0) + res_buildprotolist(); + return (findservice(p, &protolist)); +} + +static struct servent * +cgetservbyport(unsigned port, const char *proto) { /* Host byte order. */ + struct valuelist **list = &servicelist; + struct valuelist *lp = *list; + static struct servent serv; + + port = ntohs(port); + for (; lp != NULL; lp = lp->next) { + if (port != (u_int16_t)lp->port) /* Host byte order. */ + continue; + if (strcasecmp(lp->proto, proto) == 0) { + if (lp != *list) { + lp->prev->next = lp->next; + if (lp->next) + lp->next->prev = lp->prev; + (*list)->prev = lp; + lp->next = *list; + *list = lp; + } + serv.s_name = lp->name; + serv.s_port = htons((u_int16_t)lp->port); + serv.s_proto = lp->proto; + return (&serv); + } + } + return (0); +} + +static struct protoent * +cgetprotobynumber(int proto) { /* Host byte order. */ + struct valuelist **list = &protolist; + struct valuelist *lp = *list; + static struct protoent prot; + + for (; lp != NULL; lp = lp->next) + if (lp->port == proto) { /* Host byte order. */ + if (lp != *list) { + lp->prev->next = lp->next; + if (lp->next) + lp->next->prev = lp->prev; + (*list)->prev = lp; + lp->next = *list; + *list = lp; + } + prot.p_name = lp->name; + prot.p_proto = lp->port; /* Host byte order. */ + return (&prot); + } + return (0); +} + +const char * +res_protocolname(int num) { + static char number[8]; + struct protoent *pp; + + if (protolist == (struct valuelist *)0) + res_buildprotolist(); + pp = cgetprotobynumber(num); + if (pp == 0) { + (void) sprintf(number, "%d", num); + return (number); + } + return (pp->p_name); +} + +const char * +res_servicename(u_int16_t port, const char *proto) { /* Host byte order. */ + static char number[8]; + struct servent *ss; + + if (servicelist == (struct valuelist *)0) + res_buildservicelist(); + ss = cgetservbyport(htons(port), proto); + if (ss == 0) { + (void) sprintf(number, "%d", port); + return (number); + } + return (ss->s_name); +} diff --git a/contrib/isc-dhcp/minires/res_query.c b/contrib/isc-dhcp/minires/res_query.c new file mode 100644 index 0000000..412da65 --- /dev/null +++ b/contrib/isc-dhcp/minires/res_query.c @@ -0,0 +1,413 @@ +/* + * Copyright (c) 1988, 1993 + * 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 the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, 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. + */ + +/* + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char sccsid[] = "@(#)res_query.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "$Id: res_query.c,v 1.4 2001/01/16 22:33:15 mellon Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <sys/param.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <ctype.h> +#include <errno.h> +#include <netdb.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> + +#include "minires/minires.h" +#include "arpa/nameser.h" + +/* Options. Leave them on. */ +#define DEBUG + +#if PACKETSZ > 1024 +#define MAXPACKET PACKETSZ +#else +#define MAXPACKET 1024 +#endif + +/* + * Formulate a normal query, send, and await answer. + * Returned answer is placed in supplied buffer "answer". + * Perform preliminary check of answer, returning success only + * if no error is indicated and the answer count is nonzero. + * Return the size of the response on success, -1 on error. + * Error number is left in H_ERRNO. + * + * Caller must parse answer and determine whether it answers the question. + */ +isc_result_t +res_nquery(res_state statp, + const char *name, /* domain name */ + ns_class class, ns_type type, /* class and type of query */ + double *answer, /* buffer to put answer */ + unsigned anslen, + unsigned *ansret) /* size of answer buffer */ +{ + double buf[MAXPACKET / sizeof (double)]; + HEADER *hp = (HEADER *) answer; + unsigned n; + isc_result_t rcode; + + hp->rcode = NOERROR; /* default */ + +#ifdef DEBUG + if (statp->options & RES_DEBUG) + printf(";; res_query(%s, %d, %d)\n", name, class, type); +#endif + + rcode = res_nmkquery(statp, QUERY, name, class, type, NULL, 0, NULL, + buf, sizeof(buf), &n); + if (rcode != ISC_R_SUCCESS) { +#ifdef DEBUG + if (statp->options & RES_DEBUG) + printf(";; res_query: mkquery failed\n"); +#endif + RES_SET_H_ERRNO(statp, NO_RECOVERY); + return rcode; + } + rcode = res_nsend(statp, buf, n, answer, anslen, &n); + if (rcode != ISC_R_SUCCESS) { +#ifdef DEBUG + if (statp->options & RES_DEBUG) + printf(";; res_query: send error\n"); +#endif + RES_SET_H_ERRNO(statp, TRY_AGAIN); + return rcode; + } + + if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { +#ifdef DEBUG + if (statp->options & RES_DEBUG) + printf(";; rcode = %d, ancount=%d\n", hp->rcode, + ntohs(hp->ancount)); +#endif + switch (hp->rcode) { + case NXDOMAIN: + RES_SET_H_ERRNO(statp, HOST_NOT_FOUND); + break; + case SERVFAIL: + RES_SET_H_ERRNO(statp, TRY_AGAIN); + break; + case NOERROR: + RES_SET_H_ERRNO(statp, NO_DATA); + break; + case FORMERR: + case NOTIMP: + case REFUSED: + default: + RES_SET_H_ERRNO(statp, NO_RECOVERY); + break; + } + return ns_rcode_to_isc (hp -> rcode); + } + *ansret = n; + return ISC_R_SUCCESS; +} + +#if 0 +/* + * Formulate a normal query, send, and retrieve answer in supplied buffer. + * Return the size of the response on success, -1 on error. + * If enabled, implement search rules until answer or unrecoverable failure + * is detected. Error code, if any, is left in H_ERRNO. + */ +isc_result_t +res_nsearch(res_state statp, + const char *name, /* domain name */ + ns_class class, ns_type type, /* class and type of query */ + double *answer, /* buffer to put answer */ + unsigned anslen, + unsigned *ansret) /* size of answer */ +{ + const char *cp, * const *domain; + HEADER *hp = (HEADER *) answer; + char tmp[NS_MAXDNAME]; + u_int dots; + int trailing_dot, ret; + int got_nodata = 0, got_servfail = 0, root_on_list = 0; + isc_result_t rcode; + + errno = 0; + RES_SET_H_ERRNO(statp, HOST_NOT_FOUND); /* True if we never query. */ + + dots = 0; + for (cp = name; *cp != '\0'; cp++) + dots += (*cp == '.'); + trailing_dot = 0; + if (cp > name && *--cp == '.') + trailing_dot++; + + /* If there aren't any dots, it could be a user-level alias. */ + if (!dots && (cp = res_hostalias(statp, name, tmp, sizeof tmp))!= NULL) + return res_nquery(statp, cp, class, type, + answer, anslen, ansret); + + /* + * If there are enough dots in the name, do no searching. + * (The threshold can be set with the "ndots" option.) + */ + if (dots >= statp->ndots || trailing_dot) + return res_nquerydomain(statp, name, NULL, class, type, + answer, anslen, ansret); + + /* + * We do at least one level of search if + * - there is no dot and RES_DEFNAME is set, or + * - there is at least one dot, there is no trailing dot, + * and RES_DNSRCH is set. + */ + if ((!dots && (statp->options & RES_DEFNAMES) != 0) || + (dots && !trailing_dot && (statp->options & RES_DNSRCH) != 0)) { + int done = 0; + + for (domain = (const char * const *)statp->dnsrch; + *domain && !done; + domain++) { + + if (domain[0][0] == '\0' || + (domain[0][0] == '.' && domain[0][1] == '\0')) + root_on_list++; + + rcode = res_nquerydomain(statp, name, *domain, + class, type, + answer, anslen, &ret); + if (rcode == ISC_R_SUCCESS && ret > 0) { + *ansret = ret; + return rcode; + } + + /* + * If no server present, give up. + * If name isn't found in this domain, + * keep trying higher domains in the search list + * (if that's enabled). + * On a NO_DATA error, keep trying, otherwise + * a wildcard entry of another type could keep us + * from finding this entry higher in the domain. + * If we get some other error (negative answer or + * server failure), then stop searching up, + * but try the input name below in case it's + * fully-qualified. + */ + if (errno == ECONNREFUSED) { + RES_SET_H_ERRNO(statp, TRY_AGAIN); + return ISC_R_CONNREFUSED; + } + + switch (statp->res_h_errno) { + case NO_DATA: + got_nodata++; + /* FALLTHROUGH */ + case HOST_NOT_FOUND: + /* keep trying */ + break; + case TRY_AGAIN: + if (hp->rcode == SERVFAIL) { + /* try next search element, if any */ + got_servfail++; + break; + } + /* FALLTHROUGH */ + default: + /* anything else implies that we're done */ + done++; + } + + /* if we got here for some reason other than DNSRCH, + * we only wanted one iteration of the loop, so stop. + */ + if ((statp->options & RES_DNSRCH) == 0) + done++; + } + } + + /* + * If the name has any dots at all, and "." is not on the search + * list, then try an as-is query now. + */ + if (statp->ndots) { + rcode = res_nquerydomain(statp, name, NULL, class, type, + answer, anslen, &ret); + if (rcode == ISC_R_SUCCESS && ret > 0) { + *ansret = ret; + return rcode; + } + } + + /* if we got here, we didn't satisfy the search. + * if we did an initial full query, return that query's H_ERRNO + * (note that we wouldn't be here if that query had succeeded). + * else if we ever got a nodata, send that back as the reason. + * else send back meaningless H_ERRNO, that being the one from + * the last DNSRCH we did. + */ + if (got_nodata) { + RES_SET_H_ERRNO(statp, NO_DATA); + return ISC_R_NOTFOUND; + } else if (got_servfail) { + RES_SET_H_ERRNO(statp, TRY_AGAIN); + return ISC_R_TIMEDOUT; + } + return ISC_R_UNEXPECTED; +} +#endif + +/* + * Perform a call on res_query on the concatenation of name and domain, + * removing a trailing dot from name if domain is NULL. + */ +isc_result_t +res_nquerydomain(res_state statp, + const char *name, + const char *domain, + ns_class class, ns_type type, + double *answer, + unsigned anslen, + unsigned *ansret) +{ + char nbuf[MAXDNAME]; + const char *longname = nbuf; + int n, d; + +#ifdef DEBUG + if (statp->options & RES_DEBUG) + printf(";; res_nquerydomain(%s, %s, %d, %d)\n", + name, domain?domain:"<Nil>", class, type); +#endif + if (domain == NULL) { + /* + * Check for trailing '.'; + * copy without '.' if present. + */ + n = strlen(name); + if (n >= MAXDNAME) { + RES_SET_H_ERRNO(statp, NO_RECOVERY); + return ISC_R_NOSPACE; + } + n--; + if (n >= 0 && name[n] == '.') { + strncpy(nbuf, name, (unsigned)n); + nbuf[n] = '\0'; + } else + longname = name; + } else { + n = strlen(name); + d = strlen(domain); + if (n + d + 1 >= MAXDNAME) { + RES_SET_H_ERRNO(statp, NO_RECOVERY); + return ISC_R_NOSPACE; + } + sprintf(nbuf, "%s.%s", name, domain); + } + return res_nquery(statp, + longname, class, type, answer, anslen, ansret); +} + +const char * +res_hostalias(const res_state statp, const char *name, char *dst, size_t siz) { + char *file, *cp1, *cp2; + char buf[BUFSIZ]; + FILE *fp; + + if (statp->options & RES_NOALIASES) + return (NULL); + file = getenv("HOSTALIASES"); + if (file == NULL || (fp = fopen(file, "r")) == NULL) + return (NULL); + setbuf(fp, NULL); + buf[sizeof(buf) - 1] = '\0'; + while (fgets(buf, sizeof(buf), fp)) { + for (cp1 = buf; *cp1 && !isspace(*cp1); ++cp1) + ; + if (!*cp1) + break; + *cp1 = '\0'; + if (ns_samename(buf, name) == 1) { + while (isspace(*++cp1)) + ; + if (!*cp1) + break; + for (cp2 = cp1 + 1; *cp2 && !isspace(*cp2); ++cp2) + ; + *cp2 = '\0'; + strncpy(dst, cp1, siz - 1); + dst[siz - 1] = '\0'; + fclose(fp); + return (dst); + } + } + fclose(fp); + return (NULL); +} diff --git a/contrib/isc-dhcp/minires/res_send.c b/contrib/isc-dhcp/minires/res_send.c new file mode 100644 index 0000000..79946a4 --- /dev/null +++ b/contrib/isc-dhcp/minires/res_send.c @@ -0,0 +1,871 @@ +/* + * Copyright (c) 1985, 1989, 1993 + * 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 the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, 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. + */ + +/* + * Portions Copyright (c) 1996-2001 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "$Id: res_send.c,v 1.7 2001/02/22 07:28:25 mellon Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* Rename the I/O functions in case we're tracing. */ +#define send trace_mr_send +#define recvfrom trace_mr_recvfrom +#define read trace_mr_read +#define connect trace_mr_connect +#define socket trace_mr_socket +#define bind trace_mr_bind +#define close trace_mr_close +#define select trace_mr_select +#define time trace_mr_time + +/* + * Send query to name server and wait for reply. + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <sys/uio.h> + +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <errno.h> +#include <netdb.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "minires/minires.h" +#include "arpa/nameser.h" + +#define CHECK_SRVR_ADDR + +static int cmpsock(struct sockaddr_in *a1, struct sockaddr_in *a2); +void res_pquery(const res_state, const u_char *, int, FILE *); + +/* int + * res_isourserver(ina) + * looks up "ina" in _res.ns_addr_list[] + * returns: + * 0 : not found + * >0 : found + * author: + * paul vixie, 29may94 + */ +int +res_ourserver_p(const res_state statp, const struct sockaddr_in *inp) { + struct sockaddr_in ina; + int ns; + + ina = *inp; + for (ns = 0; ns < statp->nscount; ns++) { + const struct sockaddr_in *srv = &statp->nsaddr_list[ns]; + + if (srv->sin_family == ina.sin_family && + srv->sin_port == ina.sin_port && + (srv->sin_addr.s_addr == INADDR_ANY || + srv->sin_addr.s_addr == ina.sin_addr.s_addr)) + return (1); + } + return (0); +} + +/* int + * res_nameinquery(name, type, class, buf, eom) + * look for (name,type,class) in the query section of packet (buf,eom) + * requires: + * buf + HFIXEDSZ <= eom + * returns: + * -1 : format error + * 0 : not found + * >0 : found + * author: + * paul vixie, 29may94 + */ +int +res_nameinquery(const char *name, int type, int class, + const u_char *buf, const u_char *eom) +{ + const u_char *cp = buf + HFIXEDSZ; + int qdcount = ntohs(((const HEADER *)buf)->qdcount); + + while (qdcount-- > 0) { + char tname[MAXDNAME+1]; + int n, ttype, tclass; + + n = dn_expand(buf, eom, cp, tname, sizeof tname); + if (n < 0) + return (-1); + cp += n; + if (cp + 2 * INT16SZ > eom) + return (-1); + ttype = getUShort(cp); cp += INT16SZ; + tclass = getUShort(cp); cp += INT16SZ; + if (ttype == type && tclass == class && + ns_samename(tname, name) == 1) + return (1); + } + return (0); +} + +/* int + * res_queriesmatch(buf1, eom1, buf2, eom2) + * is there a 1:1 mapping of (name,type,class) + * in (buf1,eom1) and (buf2,eom2)? + * returns: + * -1 : format error + * 0 : not a 1:1 mapping + * >0 : is a 1:1 mapping + * author: + * paul vixie, 29may94 + */ +int +res_queriesmatch(const u_char *buf1, const u_char *eom1, + const u_char *buf2, const u_char *eom2) +{ + const u_char *cp = buf1 + HFIXEDSZ; + int qdcount = ntohs(((const HEADER *)buf1)->qdcount); + + if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2) + return (-1); + + /* + * Only header section present in replies to + * dynamic update packets. + */ + if ( (((const HEADER *)buf1)->opcode == ns_o_update) && + (((const HEADER *)buf2)->opcode == ns_o_update) ) + return (1); + + if (qdcount != ntohs(((const HEADER*)buf2)->qdcount)) + return (0); + while (qdcount-- > 0) { + char tname[MAXDNAME+1]; + int n, ttype, tclass; + + n = dn_expand(buf1, eom1, cp, tname, sizeof tname); + if (n < 0) + return (-1); + cp += n; + if (cp + 2 * INT16SZ > eom1) + return (-1); + ttype = getUShort(cp); cp += INT16SZ; + tclass = getUShort(cp); cp += INT16SZ; + if (!res_nameinquery(tname, ttype, tclass, buf2, eom2)) + return (0); + } + return (1); +} + +isc_result_t +res_nsend(res_state statp, + double *buf, unsigned buflen, + double *ans, unsigned anssiz, unsigned *ansret) +{ + HEADER *hp = (HEADER *) buf; + HEADER *anhp = (HEADER *) ans; + int gotsomewhere, connreset, terrno, try, v_circuit, resplen, ns, n; + u_int badns; /* XXX NSMAX can't exceed #/bits in this variable */ + static int highestFD = FD_SETSIZE - 1; + + if (anssiz < HFIXEDSZ) { + return ISC_R_INVALIDARG; + } + DprintQ((statp->options & RES_DEBUG) || + (statp->pfcode & RES_PRF_QUERY), + (stdout, ";; res_send()\n"), buf, buflen); + v_circuit = (statp->options & RES_USEVC) || buflen > PACKETSZ; + gotsomewhere = 0; + connreset = 0; + terrno = ISC_R_TIMEDOUT; + badns = 0; + + /* + * Some callers want to even out the load on their resolver list. + */ + if (statp->nscount > 0 && (statp->options & RES_ROTATE) != 0) { + struct sockaddr_in ina; + int lastns = statp->nscount - 1; + + ina = statp->nsaddr_list[0]; + for (ns = 0; ns < lastns; ns++) + statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1]; + statp->nsaddr_list[lastns] = ina; + } + +#if defined (TRACING) + trace_mr_statp_setup (statp); +#endif + + /* + * Send request, RETRY times, or until successful + */ + for (try = 0; try < statp->retry; try++) { + for (ns = 0; ns < statp->nscount; ns++) { + struct sockaddr_in *nsap = &statp->nsaddr_list[ns]; + same_ns: + if (badns & (1 << ns)) { + res_nclose(statp); + goto next_ns; + } + + if (statp->qhook) { + int done = 0, loops = 0; + + do { + res_sendhookact act; + + act = (*statp->qhook)(&nsap, &buf, &buflen, + ans, anssiz, &resplen); + switch (act) { + case res_goahead: + done = 1; + break; + case res_nextns: + res_nclose(statp); + goto next_ns; + case res_done: + return (resplen); + case res_modified: + /* give the hook another try */ + if (++loops < 42) /*doug adams*/ + break; + /*FALLTHROUGH*/ + case res_error: + /*FALLTHROUGH*/ + default: + return ISC_R_UNEXPECTED; + } + } while (!done); + } + + Dprint(statp->options & RES_DEBUG, + (stdout, ";; Querying server (# %d) address = %s\n", + ns + 1, inet_ntoa(nsap->sin_addr))); + + if (v_circuit) { + int truncated; + struct iovec iov[2]; + u_short len; + u_char *cp; + + /* Use VC; at most one attempt per server. */ + try = statp->retry; + truncated = 0; + + /* Are we still talking to whom we want to talk to? */ + if (statp->_sock >= 0 && + (statp->_flags & RES_F_VC) != 0) { + struct sockaddr_in peer; + SOCKLEN_T size = sizeof(peer); + + if (getpeername(statp->_sock, + (struct sockaddr *)&peer, + &size) < 0) { + res_nclose(statp); + statp->_flags &= ~RES_F_VC; + } else if (!cmpsock(&peer, nsap)) { + res_nclose(statp); + statp->_flags &= ~RES_F_VC; + } + } + + if (statp->_sock < 0 || + (statp->_flags & RES_F_VC) == 0) { + if (statp->_sock >= 0) + res_nclose(statp); + + statp->_sock = socket(PF_INET, + SOCK_STREAM, 0); + if (statp->_sock < 0 || + statp->_sock > highestFD) { + terrno = uerr2isc (errno); + Perror(statp, stderr, + "socket(vc)", errno); + return (-1); + } + errno = 0; + if (connect(statp->_sock, + (struct sockaddr *)nsap, + sizeof *nsap) < 0) { + terrno = uerr2isc (errno); + Aerror(statp, stderr, "connect/vc", + errno, *nsap); + badns |= (1 << ns); + res_nclose(statp); + goto next_ns; + } + statp->_flags |= RES_F_VC; + } + /* + * Send length & message + */ + putUShort((u_char*)&len, buflen); + iov[0].iov_base = (caddr_t)&len; + iov[0].iov_len = INT16SZ; + iov[1].iov_base = (const caddr_t)buf; + iov[1].iov_len = buflen; + if (writev(statp->_sock, iov, 2) != + (INT16SZ + buflen)) { + terrno = uerr2isc (errno); + Perror(statp, stderr, "write failed", errno); + badns |= (1 << ns); + res_nclose(statp); + goto next_ns; + } + /* + * Receive length & response + */ + read_len: + cp = (u_char *)ans; + len = INT16SZ; + while ((n = read(statp->_sock, + (char *)cp, (unsigned)len)) > 0) { + cp += n; + if ((len -= n) <= 0) + break; + } + if (n <= 0) { + terrno = uerr2isc (errno); + Perror(statp, stderr, "read failed", errno); + res_nclose(statp); + /* + * A long running process might get its TCP + * connection reset if the remote server was + * restarted. Requery the server instead of + * trying a new one. When there is only one + * server, this means that a query might work + * instead of failing. We only allow one reset + * per query to prevent looping. + */ + if (terrno == ISC_R_CONNREFUSED && + !connreset) { + connreset = 1; + res_nclose(statp); + goto same_ns; + } + res_nclose(statp); + goto next_ns; + } + resplen = getUShort ((unsigned char *)ans); + if (resplen > anssiz) { + Dprint(statp->options & RES_DEBUG, + (stdout, ";; response truncated\n") + ); + truncated = 1; + len = anssiz; + } else + len = resplen; + if (len < HFIXEDSZ) { + /* + * Undersized message. + */ + Dprint(statp->options & RES_DEBUG, + (stdout, ";; undersized: %d\n", len)); + terrno = ISC_R_NOSPACE; + badns |= (1 << ns); + res_nclose(statp); + goto next_ns; + } + cp = (u_char *)ans; + while (len != 0 && + (n = read(statp->_sock, + (char *)cp, (unsigned)len)) + > 0) { + cp += n; + len -= n; + } + if (n <= 0) { + terrno = uerr2isc (errno); + Perror(statp, stderr, "read(vc)", errno); + res_nclose(statp); + goto next_ns; + } + if (truncated) { + /* + * Flush rest of answer + * so connection stays in synch. + */ + anhp->tc = 1; + len = resplen - anssiz; + while (len != 0) { + char junk[PACKETSZ]; + + n = (len > sizeof(junk) + ? sizeof(junk) + : len); + n = read(statp->_sock, + junk, (unsigned)n); + if (n > 0) + len -= n; + else + break; + } + } + /* + * The calling applicating has bailed out of + * a previous call and failed to arrange to have + * the circuit closed or the server has got + * itself confused. Anyway drop the packet and + * wait for the correct one. + */ + if (hp->id != anhp->id) { + DprintQ((statp->options & RES_DEBUG) || + (statp->pfcode & RES_PRF_REPLY), + (stdout, + ";; old answer (unexpected):\n"), + ans, (resplen>anssiz)?anssiz:resplen); + goto read_len; + } + } else { + /* + * Use datagrams. + */ + int start, timeout, finish; + fd_set dsmask; + struct sockaddr_in from; + SOCKLEN_T fromlen; + int seconds; + + if (statp->_sock < 0 || + (statp->_flags & RES_F_VC) != 0) { + if ((statp->_flags & RES_F_VC) != 0) + res_nclose(statp); + statp->_sock = socket(PF_INET, SOCK_DGRAM, 0); + if (statp->_sock < 0 || + statp->_sock > highestFD) { +#ifndef CAN_RECONNECT + bad_dg_sock: +#endif + terrno = uerr2isc (errno); + Perror(statp, stderr, + "socket(dg)", errno); + return terrno; + } + statp->_flags &= ~RES_F_CONN; + } +#ifndef CANNOT_CONNECT_DGRAM + /* + * On a 4.3BSD+ machine (client and server, + * actually), sending to a nameserver datagram + * port with no nameserver will cause an + * ICMP port unreachable message to be returned. + * If our datagram socket is "connected" to the + * server, we get an ECONNREFUSED error on the next + * socket operation, and select returns if the + * error message is received. We can thus detect + * the absence of a nameserver without timing out. + * If we have sent queries to at least two servers, + * however, we don't want to remain connected, + * as we wish to receive answers from the first + * server to respond. + */ + if (statp->nscount == 1 || (try == 0 && ns == 0)) { + /* + * Connect only if we are sure we won't + * receive a response from another server. + */ + if ((statp->_flags & RES_F_CONN) == 0) { + if (connect(statp->_sock, + (struct sockaddr *)nsap, + sizeof *nsap) < 0) { + Aerror(statp, stderr, + "connect(dg)", + errno, *nsap); + badns |= (1 << ns); + res_nclose(statp); + goto next_ns; + } + statp->_flags |= RES_F_CONN; + } + if (send(statp->_sock, + (const char*)buf, (unsigned)buflen, 0) + != buflen) { + Perror(statp, stderr, "send", errno); + badns |= (1 << ns); + res_nclose(statp); + goto next_ns; + } + } else { + /* + * Disconnect if we want to listen + * for responses from more than one server. + */ + if ((statp->_flags & RES_F_CONN) != 0) { +#ifdef CAN_RECONNECT + struct sockaddr_in no_addr; + + no_addr.sin_family = AF_INET; + no_addr.sin_addr.s_addr = INADDR_ANY; + no_addr.sin_port = 0; + (void) connect(statp->_sock, + (struct sockaddr *) + &no_addr, + sizeof no_addr); +#else + struct sockaddr_in local_addr; + SOCKLEN_T len; + int result, s1; + + len = sizeof(local_addr); + s1 = socket(PF_INET, SOCK_DGRAM, 0); + result = getsockname(statp->_sock, + (struct sockaddr *)&local_addr, + &len); + if (s1 < 0) + goto bad_dg_sock; + (void) dup2(s1, statp->_sock); + (void) close(s1); + if (result == 0) { + /* + * Attempt to rebind to old + * port. Note connected socket + * has an sin_addr set. + */ + local_addr.sin_addr.s_addr = + htonl(0); + (void)bind(statp->_sock, + (struct sockaddr *) + &local_addr, + (unsigned)len); + } + Dprint(statp->options & RES_DEBUG, + (stdout, ";; new DG socket\n")) +#endif /* CAN_RECONNECT */ + statp->_flags &= ~RES_F_CONN; + errno = 0; + } +#endif /* !CANNOT_CONNECT_DGRAM */ + if (sendto(statp->_sock, + (const char *)buf, buflen, 0, + (struct sockaddr *)nsap, + sizeof *nsap) + != buflen) { + Aerror(statp, stderr, "sendto", errno, *nsap); + badns |= (1 << ns); + res_nclose(statp); + goto next_ns; + } +#ifndef CANNOT_CONNECT_DGRAM + } +#endif /* !CANNOT_CONNECT_DGRAM */ + + if (statp->_sock < 0 || statp->_sock > highestFD) { + Perror(statp, stderr, + "fd out-of-bounds", EMFILE); + res_nclose(statp); + goto next_ns; + } + + /* + * Wait for reply + */ + seconds = (statp->retrans << try); + if (try > 0) + seconds /= statp->nscount; + if (seconds <= 0) + seconds = 1; + start = cur_time; + timeout = seconds; + finish = start + timeout; + wait: + FD_ZERO(&dsmask); + FD_SET(statp->_sock, &dsmask); + { + struct timeval t; + t.tv_sec = timeout; + t.tv_usec = 0; + n = select(statp->_sock + 1, + &dsmask, NULL, NULL, &t); + } + if (n == 0) { + Dprint(statp->options & RES_DEBUG, + (stdout, ";; timeout\n")); + gotsomewhere = 1; + goto next_ns; + } + if (n < 0) { + if (errno == EINTR) { + if (finish >= cur_time) { + timeout = finish - cur_time; + goto wait; + } + } + Perror(statp, stderr, "select", errno); + res_nclose(statp); + goto next_ns; + } + errno = 0; + fromlen = sizeof(struct sockaddr_in); + resplen = recvfrom(statp->_sock, + (char *)ans, anssiz, 0, + (struct sockaddr *)&from, &fromlen); + if (resplen <= 0) { + Perror(statp, stderr, "recvfrom", errno); + res_nclose(statp); + goto next_ns; + } + gotsomewhere = 1; + if (resplen < HFIXEDSZ) { + /* + * Undersized message. + */ + Dprint(statp->options & RES_DEBUG, + (stdout, ";; undersized: %d\n", + resplen)); + terrno = ISC_R_NOSPACE; + badns |= (1 << ns); + res_nclose(statp); + goto next_ns; + } + if (hp->id != anhp->id) { + /* + * response from old query, ignore it. + * XXX - potential security hazard could + * be detected here. + */ + DprintQ((statp->options & RES_DEBUG) || + (statp->pfcode & RES_PRF_REPLY), + (stdout, ";; old answer:\n"), + ans, (resplen>anssiz)?anssiz:resplen); + goto wait; + } +#ifdef CHECK_SRVR_ADDR + if (!(statp->options & RES_INSECURE1) && + !res_ourserver_p(statp, &from)) { + /* + * response from wrong server? ignore it. + * XXX - potential security hazard could + * be detected here. + */ + DprintQ((statp->options & RES_DEBUG) || + (statp->pfcode & RES_PRF_REPLY), + (stdout, ";; not our server:\n"), + ans, (resplen>anssiz)?anssiz:resplen); + goto wait; + } +#endif + if (!(statp->options & RES_INSECURE2) && + !res_queriesmatch((u_char *)buf, + ((u_char *)buf) + buflen, + (u_char *)ans, + ((u_char *)ans) + anssiz)) { + /* + * response contains wrong query? ignore it. + * XXX - potential security hazard could + * be detected here. + */ + DprintQ((statp->options & RES_DEBUG) || + (statp->pfcode & RES_PRF_REPLY), + (stdout, ";; wrong query name:\n"), + ans, (resplen>anssiz)?anssiz:resplen); + goto wait; + } + if (anhp->rcode == SERVFAIL || + anhp->rcode == NOTIMP || + anhp->rcode == REFUSED) { + DprintQ(statp->options & RES_DEBUG, + (stdout, "server rejected query:\n"), + ans, (resplen>anssiz)?anssiz:resplen); + badns |= (1 << ns); + res_nclose(statp); + /* don't retry if called from dig */ + if (!statp->pfcode) + goto next_ns; + } + if (!(statp->options & RES_IGNTC) && anhp->tc) { + /* + * get rest of answer; + * use TCP with same server. + */ + Dprint(statp->options & RES_DEBUG, + (stdout, ";; truncated answer\n")); + v_circuit = 1; + res_nclose(statp); + goto same_ns; + } + } /*if vc/dg*/ + Dprint((statp->options & RES_DEBUG) || + ((statp->pfcode & RES_PRF_REPLY) && + (statp->pfcode & RES_PRF_HEAD1)), + (stdout, ";; got answer:\n")); + DprintQ((statp->options & RES_DEBUG) || + (statp->pfcode & RES_PRF_REPLY), + (stdout, ""), + ans, (resplen>anssiz)?anssiz:resplen); + /* + * If using virtual circuits, we assume that the first server + * is preferred over the rest (i.e. it is on the local + * machine) and only keep that one open. + * If we have temporarily opened a virtual circuit, + * or if we haven't been asked to keep a socket open, + * close the socket. + */ + if ((v_circuit && (!(statp->options & RES_USEVC) || ns != 0)) || + !(statp->options & RES_STAYOPEN)) { + res_nclose(statp); + } + if (statp->rhook) { + int done = 0, loops = 0; + + do { + res_sendhookact act; + + act = (*statp->rhook)(nsap, buf, buflen, + ans, anssiz, &resplen); + switch (act) { + case res_goahead: + case res_done: + done = 1; + break; + case res_nextns: + res_nclose(statp); + goto next_ns; + case res_modified: + /* give the hook another try */ + if (++loops < 42) /*doug adams*/ + break; + /*FALLTHROUGH*/ + case res_error: + /*FALLTHROUGH*/ + default: + return ISC_R_UNEXPECTED; + } + } while (!done); + + } + *ansret = resplen; + return ISC_R_SUCCESS; + next_ns: ; + } /*foreach ns*/ + } /*foreach retry*/ + res_nclose(statp); + if (!v_circuit) { + if (!gotsomewhere) + terrno = ISC_R_CONNREFUSED; /* no nameservers found */ + else + errno = ISC_R_TIMEDOUT; /* no answer obtained */ + } + return terrno; +} + +/* + * This routine is for closing the socket if a virtual circuit is used and + * the program wants to close it. This provides support for endhostent() + * which expects to close the socket. + * + * This routine is not expected to be user visible. + */ +void +res_nclose(res_state statp) { + if (statp->_sock >= 0) { + (void) close(statp->_sock); + statp->_sock = -1; + statp->_flags &= ~(RES_F_VC | RES_F_CONN); + } +} + +/* Private */ +static int +cmpsock(struct sockaddr_in *a1, struct sockaddr_in *a2) { + return ((a1->sin_family == a2->sin_family) && + (a1->sin_port == a2->sin_port) && + (a1->sin_addr.s_addr == a2->sin_addr.s_addr)); +} + +#ifdef NEED_PSELECT +/* XXX needs to move to the porting library. */ +static int +pselect(int nfds, void *rfds, void *wfds, void *efds, + struct timespec *tsp, + const sigset_t *sigmask) +{ + struct timeval tv, *tvp; + sigset_t sigs; + int n; + + if (tsp) { + tvp = &tv; + tv = evTimeVal(*tsp); + } else + tvp = NULL; + if (sigmask) + sigprocmask(SIG_SETMASK, sigmask, &sigs); + n = select(nfds, rfds, wfds, efds, tvp); + if (sigmask) + sigprocmask(SIG_SETMASK, &sigs, NULL); + if (tsp) + *tsp = evTimeSpec(tv); + return (n); +} +#endif diff --git a/contrib/isc-dhcp/minires/res_sendsigned.c b/contrib/isc-dhcp/minires/res_sendsigned.c new file mode 100644 index 0000000..be213af --- /dev/null +++ b/contrib/isc-dhcp/minires/res_sendsigned.c @@ -0,0 +1,116 @@ +#include <sys/types.h> +#include <sys/param.h> + +#include <netinet/in.h> +#include <arpa/inet.h> +#include <sys/socket.h> + +#include <errno.h> +#include <netdb.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "minires/minires.h" +#include "arpa/nameser.h" + +#include <isc-dhcp/dst.h> + +/* res_nsendsigned */ +isc_result_t +res_nsendsigned(res_state statp, + double *msg, unsigned msglen, ns_tsig_key *key, + double *answer, unsigned anslen, unsigned *anssize) +{ + res_state nstatp; + DST_KEY *dstkey; + int usingTCP = 0; + double *newmsg; + unsigned newmsglen; + unsigned bufsize, siglen; + u_char sig[64]; + HEADER *hp; + time_t tsig_time; + unsigned ret; + isc_result_t rcode; + + dst_init(); + + nstatp = (res_state) malloc(sizeof(*statp)); + if (nstatp == NULL) + return ISC_R_NOMEMORY; + memcpy(nstatp, statp, sizeof(*statp)); + + bufsize = msglen + 1024; + newmsg = (double *) malloc(bufsize); + if (newmsg == NULL) + return ISC_R_NOMEMORY; + memcpy(newmsg, msg, msglen); + newmsglen = msglen; + + if (ns_samename(key->alg, NS_TSIG_ALG_HMAC_MD5) != 1) + dstkey = NULL; + else + dstkey = dst_buffer_to_key(key->name, KEY_HMAC_MD5, + NS_KEY_TYPE_AUTH_ONLY, + NS_KEY_PROT_ANY, + key->data, key->len); + if (dstkey == NULL) { + free(nstatp); + free(newmsg); + return ISC_R_BADKEY; + } + + nstatp->nscount = 1; + siglen = sizeof(sig); + rcode = ns_sign((u_char *)newmsg, &newmsglen, bufsize, + NOERROR, dstkey, NULL, 0, + sig, &siglen, 0); + if (rcode != ISC_R_SUCCESS) { + free (nstatp); + free (newmsg); + return rcode; + } + + if (newmsglen > PACKETSZ || (nstatp->options & RES_IGNTC)) + usingTCP = 1; + if (usingTCP == 0) + nstatp->options |= RES_IGNTC; + else + nstatp->options |= RES_USEVC; + +retry: + + rcode = res_nsend(nstatp, newmsg, newmsglen, answer, anslen, &ret); + if (rcode != ISC_R_SUCCESS) { + free (nstatp); + free (newmsg); + return rcode; + } + + anslen = ret; + rcode = ns_verify((u_char *)answer, &anslen, dstkey, sig, siglen, + NULL, NULL, &tsig_time, + (nstatp->options & RES_KEEPTSIG) ? 1 : 0); + if (rcode != ISC_R_SUCCESS) { + Dprint(nstatp->pfcode & RES_PRF_REPLY, + (stdout, ";; TSIG invalid (%s)\n", p_rcode(ret))); + free (nstatp); + free (newmsg); + return rcode; + } + Dprint(nstatp->pfcode & RES_PRF_REPLY, (stdout, ";; TSIG ok\n")); + + hp = (HEADER *) answer; + if (hp->tc && usingTCP == 0) { + nstatp->options &= ~RES_IGNTC; + usingTCP = 1; + goto retry; + } + + free (nstatp); + free (newmsg); + *anssize = anslen; + return ISC_R_SUCCESS; +} diff --git a/contrib/isc-dhcp/minires/res_update.c b/contrib/isc-dhcp/minires/res_update.c new file mode 100644 index 0000000..5fda1a6 --- /dev/null +++ b/contrib/isc-dhcp/minires/res_update.c @@ -0,0 +1,219 @@ +#if !defined(lint) && !defined(SABER) +static const char rcsid[] = "$Id: res_update.c,v 1.11.2.2 2001/06/08 23:12:45 mellon Exp $"; +#endif /* not lint */ + +/* + * Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, 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. + */ + +/* + * Based on the Dynamic DNS reference implementation by Viraj Bais + * <viraj_bais@ccm.fm.intel.com> + */ + +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/time.h> + +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <errno.h> +#include <limits.h> +#include <netdb.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <isc-dhcp/list.h> +#include "minires/minires.h" +#include "arpa/nameser.h" + +/* + * Separate a linked list of records into groups so that all records + * in a group will belong to a single zone on the nameserver. + * Create a dynamic update packet for each zone and send it to the + * nameservers for that zone, and await answer. + * Abort if error occurs in updating any zone. + * Return the number of zones updated on success, < 0 on error. + * + * On error, caller must deal with the unsynchronized zones + * eg. an A record might have been successfully added to the forward + * zone but the corresponding PTR record would be missing if error + * was encountered while updating the reverse zone. + */ + +struct zonegrp { + char z_origin[MAXDNAME]; + ns_class z_class; + struct in_addr z_nsaddrs[MAXNS]; + int z_nscount; + int z_flags; + ISC_LIST(ns_updrec) z_rrlist; + ISC_LINK(struct zonegrp) z_link; +}; + +#define ZG_F_ZONESECTADDED 0x0001 + +/* Forward. */ + +static int nscopy(struct sockaddr_in *, const struct sockaddr_in *, int); +static int nsprom(struct sockaddr_in *, const struct in_addr *, int); + +void tkey_free (ns_tsig_key **); + +isc_result_t +res_nupdate(res_state statp, ns_updrec *rrecp_in) { + ns_updrec *rrecp; + double answer[PACKETSZ / sizeof (double)]; + double packet[2*PACKETSZ / sizeof (double)]; + struct zonegrp *zptr, tgrp; + int nzones = 0, nscount = 0; + unsigned n; + unsigned rval; + struct sockaddr_in nsaddrs[MAXNS]; + ns_tsig_key *key; + void *zcookie = 0; + void *zcookp = &zcookie; + isc_result_t rcode; + + again: + /* Make sure all the updates are in the same zone, and find out + what zone they are in. */ + zptr = NULL; + for (rrecp = rrecp_in; rrecp; rrecp = ISC_LIST_NEXT(rrecp, r_link)) { + /* Find the origin for it if there is one. */ + tgrp.z_class = rrecp->r_class; + rcode = res_findzonecut(statp, rrecp->r_dname, tgrp.z_class, + RES_EXHAUSTIVE, + tgrp.z_origin, + sizeof tgrp.z_origin, + tgrp.z_nsaddrs, MAXNS, &tgrp.z_nscount, + zcookp); + if (rcode != ISC_R_SUCCESS) + goto done; + if (tgrp.z_nscount <= 0) { + rcode = ISC_R_NOTZONE; + goto done; + } + /* Make a group for it if there isn't one. */ + if (zptr == NULL) { + zptr = malloc(sizeof *zptr); + if (zptr == NULL) { + rcode = ISC_R_NOMEMORY; + goto done; + } + *zptr = tgrp; + zptr->z_flags = 0; + ISC_LIST_INIT(zptr->z_rrlist); + } else if (ns_samename(tgrp.z_origin, zptr->z_origin) == 0 || + tgrp.z_class != zptr->z_class) { + /* Some of the records are in different zones. */ + rcode = ISC_R_CROSSZONE; + goto done; + } + /* Thread this rrecp onto the zone group. */ + ISC_LIST_APPEND(zptr->z_rrlist, rrecp, r_glink); + } + + /* Construct zone section and prepend it. */ + rrecp = res_mkupdrec(ns_s_zn, zptr->z_origin, + zptr->z_class, ns_t_soa, 0); + if (rrecp == NULL) { + rcode = ISC_R_UNEXPECTED; + goto done; + } + ISC_LIST_PREPEND(zptr->z_rrlist, rrecp, r_glink); + zptr->z_flags |= ZG_F_ZONESECTADDED; + + /* Marshall the update message. */ + n = sizeof packet; + rcode = res_nmkupdate(statp, + ISC_LIST_HEAD(zptr->z_rrlist), packet, &n); + if (rcode != ISC_R_SUCCESS) + goto done; + + /* Temporarily replace the resolver's nameserver set. */ + nscount = nscopy(nsaddrs, statp->nsaddr_list, statp->nscount); + statp->nscount = nsprom(statp->nsaddr_list, + zptr->z_nsaddrs, zptr->z_nscount); + + /* Send the update and remember the result. */ + key = (ns_tsig_key *)0; + rcode = find_tsig_key (&key, zptr->z_origin, zcookie); + if (rcode == ISC_R_SUCCESS) { + rcode = res_nsendsigned(statp, packet, n, key, + answer, sizeof answer, &rval); + tkey_free (&key); + } else if (rcode == ISC_R_NOTFOUND || rcode == ISC_R_KEY_UNKNOWN) { + rcode = res_nsend(statp, packet, n, + answer, sizeof answer, &rval); + } + if (rcode != ISC_R_SUCCESS) + goto undone; + + rcode = ns_rcode_to_isc (((HEADER *)answer)->rcode); + if (zcookie && rcode == ISC_R_BADSIG) { + repudiate_zone (&zcookie); + } + + undone: + /* Restore resolver's nameserver set. */ + statp->nscount = nscopy(statp->nsaddr_list, nsaddrs, nscount); + nscount = 0; + done: + if (zptr) { + if ((zptr->z_flags & ZG_F_ZONESECTADDED) != 0) + res_freeupdrec(ISC_LIST_HEAD(zptr->z_rrlist)); + free(zptr); + } + + /* If the update failed because we used a cached zone and it + didn't work, try it again without the cached zone. */ + if (zcookp && (rcode == ISC_R_NOTZONE || rcode == ISC_R_BADSIG)) { + zcookp = 0; + goto again; + } + + if (zcookie) + forget_zone (&zcookie); + return rcode; +} + +/* Private. */ + +static int +nscopy(struct sockaddr_in *dst, const struct sockaddr_in *src, int n) { + int i; + + for (i = 0; i < n; i++) + dst[i] = src[i]; + return (n); +} + +static int +nsprom(struct sockaddr_in *dst, const struct in_addr *src, int n) { + int i; + + for (i = 0; i < n; i++) { + memset(&dst[i], 0, sizeof dst[i]); + dst[i].sin_family = AF_INET; + dst[i].sin_port = htons(NS_DEFAULTPORT); + dst[i].sin_addr = src[i]; + } + return (n); +} diff --git a/contrib/isc-dhcp/omapip/Makefile.dist b/contrib/isc-dhcp/omapip/Makefile.dist new file mode 100644 index 0000000..099f83e --- /dev/null +++ b/contrib/isc-dhcp/omapip/Makefile.dist @@ -0,0 +1,106 @@ +# Makefile.dist +# +# Copyright (c) 1996-2001 Internet Software Consortium. +# Use is subject to license terms which appear in the file named +# ISC-LICENSE that should have accompanied this file when you +# received it. If a file named ISC-LICENSE did not accompany this +# file, or you are not sure the one you have is correct, you may +# obtain an applicable copy of the license at: +# +# http://www.isc.org/isc-license-1.0.html. +# +# This file is part of the ISC DHCP distribution. The documentation +# associated with this file is listed in the file DOCUMENTATION, +# included in the top-level directory of this release. +# +# Support and other services are available for ISC products - see +# http://www.isc.org for more information. +# + +CATMANPAGES = omapi.cat3 +SEDMANPAGES = omapi.man3 +SRC = protocol.c buffer.c alloc.c result.c connection.c errwarn.c \ + listener.c dispatch.c generic.c support.c handle.c message.c \ + convert.c hash.c auth.c inet_addr.c array.c trace.c mrtrace.c \ + toisc.c + +OBJ = protocol.o buffer.o alloc.o result.o connection.o errwarn.o \ + listener.o dispatch.o generic.o support.o handle.o message.o \ + convert.o hash.o auth.o inet_addr.o array.o trace.o mrtrace.o \ + toisc.o + +MAN = omapi.3 + +INCLUDES = $(BINDINC) -I$(TOP)/includes +CFLAGS = $(DEBUG) $(PREDEFINES) $(INCLUDES) $(COPTS) + +all: libomapi.a svtest $(CATMANPAGES) + +svtest: test.o libomapi.a $(BINDLIB) ../dst/libdst.a + $(CC) $(DEBUG) $(LFLAGS) -o svtest test.o $(BINDLIB) \ + libomapi.a ../dst/libdst.a $(LIBS) + +libomapi.a: $(OBJ) + rm -f libomapi.a + ar cruv libomapi.a $(OBJ) + $(RANLIB) libomapi.a + +install: all + for dir in $(LIBDIR) $(LIBMANDIR) $(INCDIR)/omapip $(INCDIR)/isc-dhcp;\ + do \ + foo=""; \ + for bar in `echo $(DESTDIR)$${dir} |tr / ' '`; do \ + foo=$${foo}/$$bar; \ + if [ ! -d $$foo ]; then \ + mkdir $$foo; \ + chmod 755 $$foo; \ + fi; \ + done; \ + done + $(INSTALL) libomapi.a $(DESTDIR)$(LIBDIR) + $(CHMOD) 644 $(DESTDIR)$(LIBDIR)/libomapi.a + for file in alloc.h buffer.h omapip.h; do \ + $(INSTALL) $(TOP)/includes/omapip/$$file \ + $(DESTDIR)$(INCDIR)/omapip; \ + $(CHMOD) 644 $(DESTDIR)$(INCDIR)/omapip/$$file; \ + done + for file in boolean.h dst.h int.h lang.h list.h result.h types.h; do \ + $(INSTALL) $(TOP)/includes/isc-dhcp/$$file \ + $(DESTDIR)$(INCDIR)/isc-dhcp; \ + $(CHMOD) 644 $(DESTDIR)$(INCDIR)/isc-dhcp/$$file; \ + done + for man in $(MAN); do \ + prefix=`echo $$man |sed -e 's/\.[0-9]$$//'`; \ + suffix=`echo $$man |sed -e 's/.*\.\([0-9]\)$$/\1/'`; \ + $(MANINSTALL) $(MANFROM) $${prefix}.$(MANCAT)$${suffix} $(MANTO) \ + $(DESTDIR)$(LIBMANDIR)/$${prefix}$(LIBMANEXT); \ + done + +depend: + $(MKDEP) $(INCLUDES) $(PREDEFINES) $(SRC) + +clean: + -rm -f $(OBJ) test.o svtest + +realclean: clean + -rm -f libomapi.a *~ $(CATMANPAGES) $(SEDMANPAGES) + +distclean: realclean + -rm -f Makefile + +links: + @for foo in $(SRC) $(MAN) test.c; do \ + if [ ! -b $$foo ]; then \ + rm -f $$foo; \ + fi; \ + ln -s $(TOP)/omapip/$$foo $$foo; \ + done + +omapi.cat3: omapi.man3 + nroff -man omapi.man3 >omapi.cat3 + +omapi.man3: omapi.3 + sed -e "s#ETCDIR#$(ETC)#g" -e "s#DBDIR#$(VARDB)#g" \ + -e "s#RUNDIR#$(VARRUN)#g" < omapi.3 >omapi.man3 + +# Dependencies (semi-automatically-generated) diff --git a/contrib/isc-dhcp/omapip/alloc.c b/contrib/isc-dhcp/omapip/alloc.c new file mode 100644 index 0000000..245bdaf --- /dev/null +++ b/contrib/isc-dhcp/omapip/alloc.c @@ -0,0 +1,1151 @@ +/* alloc.c + + Functions supporting memory allocation for the object management + protocol... */ + +/* + * Copyright (c) 1999-2001 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. + */ + +#include <omapip/omapip_p.h> + +#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \ + defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) +struct dmalloc_preamble *dmalloc_list; +unsigned long dmalloc_outstanding; +unsigned long dmalloc_longterm; +unsigned long dmalloc_generation; +unsigned long dmalloc_cutoff_generation; +#endif + +#if defined (DEBUG_RC_HISTORY) +struct rc_history_entry rc_history [RC_HISTORY_MAX]; +int rc_history_index; +int rc_history_count; +#endif + +#if defined (DEBUG_RC_HISTORY) +static void print_rc_hist_entry (int); +#endif + +VOIDPTR dmalloc (size, file, line) + unsigned size; + const char *file; + int line; +{ + unsigned char *foo = malloc (size + DMDSIZE); + int i; + VOIDPTR *bar; +#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \ + defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) + struct dmalloc_preamble *dp; +#endif + if (!foo) + return (VOIDPTR)0; + bar = (VOIDPTR)(foo + DMDOFFSET); + memset (bar, 0, size); + +#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \ + defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) + dp = (struct dmalloc_preamble *)foo; + dp -> prev = dmalloc_list; + if (dmalloc_list) + dmalloc_list -> next = dp; + dmalloc_list = dp; + dp -> next = (struct dmalloc_preamble *)0; + dp -> size = size; + dp -> file = file; + dp -> line = line; + dp -> generation = dmalloc_generation++; + dmalloc_outstanding += size; + for (i = 0; i < DMLFSIZE; i++) + dp -> low_fence [i] = + (((unsigned long) + (&dp -> low_fence [i])) % 143) + 113; + for (i = DMDOFFSET; i < DMDSIZE; i++) + foo [i + size] = + (((unsigned long) + (&foo [i + size])) % 143) + 113; +#if defined (DEBUG_MALLOC_POOL_EXHAUSTIVELY) + /* Check _every_ entry in the pool! Very expensive. */ + for (dp = dmalloc_list; dp; dp = dp -> prev) { + for (i = 0; i < DMLFSIZE; i++) { + if (dp -> low_fence [i] != + (((unsigned long) + (&dp -> low_fence [i])) % 143) + 113) + { + log_error ("malloc fence modified: %s(%d)", + dp -> file, dp -> line); + abort (); + } + } + foo = (unsigned char *)dp; + for (i = DMDOFFSET; i < DMDSIZE; i++) { + if (foo [i + dp -> size] != + (((unsigned long) + (&foo [i + dp -> size])) % 143) + 113) { + log_error ("malloc fence modified: %s(%d)", + dp -> file, dp -> line); + abort (); + } + } + } +#endif +#endif +#ifdef DEBUG_REFCNT_DMALLOC_FREE + rc_register (file, line, 0, foo + DMDOFFSET, 1, 0, RC_MALLOC); +#endif + return bar; +} + +void dfree (ptr, file, line) + VOIDPTR ptr; + const char *file; + int line; +{ + if (!ptr) { + log_error ("dfree %s(%d): free on null pointer.", file, line); + return; + } +#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \ + defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) + { + unsigned char *bar = ptr; + struct dmalloc_preamble *dp, *cur; + int i; + bar -= DMDOFFSET; + cur = (struct dmalloc_preamble *)bar; + for (dp = dmalloc_list; dp; dp = dp -> prev) + if (dp == cur) + break; + if (!dp) { + log_error ("%s(%d): freeing unknown memory: %lx", + file, line, (unsigned long)cur); + abort (); + } + if (dp -> prev) + dp -> prev -> next = dp -> next; + if (dp -> next) + dp -> next -> prev = dp -> prev; + if (dp == dmalloc_list) + dmalloc_list = dp -> prev; + if (dp -> generation >= dmalloc_cutoff_generation) + dmalloc_outstanding -= dp -> size; + else + dmalloc_longterm -= dp -> size; + + for (i = 0; i < DMLFSIZE; i++) { + if (dp -> low_fence [i] != + (((unsigned long) + (&dp -> low_fence [i])) % 143) + 113) + { + log_error ("malloc fence modified: %s(%d)", + dp -> file, dp -> line); + abort (); + } + } + for (i = DMDOFFSET; i < DMDSIZE; i++) { + if (bar [i + dp -> size] != + (((unsigned long) + (&bar [i + dp -> size])) % 143) + 113) { + log_error ("malloc fence modified: %s(%d)", + dp -> file, dp -> line); + abort (); + } + } + ptr = bar; + } +#endif +#ifdef DEBUG_REFCNT_DMALLOC_FREE + rc_register (file, line, + 0, (unsigned char *)ptr + DMDOFFSET, 0, 1, RC_MALLOC); +#endif + free (ptr); +} + +#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \ + defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) +/* For allocation functions that keep their own free lists, we want to + account for the reuse of the memory. */ + +void dmalloc_reuse (foo, file, line, justref) + VOIDPTR foo; + const char *file; + int line; + int justref; +{ + struct dmalloc_preamble *dp; + + /* Get the pointer to the dmalloc header. */ + dp = foo; + dp--; + + /* If we just allocated this and are now referencing it, this + function would almost be a no-op, except that it would + increment the generation count needlessly. So just return + in this case. */ + if (dp -> generation == dmalloc_generation) + return; + + /* If this is longterm data, and we just made reference to it, + don't put it on the short-term list or change its name - + we don't need to know about this. */ + if (dp -> generation < dmalloc_cutoff_generation && justref) + return; + + /* Take it out of the place in the allocated list where it was. */ + if (dp -> prev) + dp -> prev -> next = dp -> next; + if (dp -> next) + dp -> next -> prev = dp -> prev; + if (dp == dmalloc_list) + dmalloc_list = dp -> prev; + + /* Account for its removal. */ + if (dp -> generation >= dmalloc_cutoff_generation) + dmalloc_outstanding -= dp -> size; + else + dmalloc_longterm -= dp -> size; + + /* Now put it at the head of the list. */ + dp -> prev = dmalloc_list; + if (dmalloc_list) + dmalloc_list -> next = dp; + dmalloc_list = dp; + dp -> next = (struct dmalloc_preamble *)0; + + /* Change the reference location information. */ + dp -> file = file; + dp -> line = line; + + /* Increment the generation. */ + dp -> generation = dmalloc_generation++; + + /* Account for it. */ + dmalloc_outstanding += dp -> size; +} + +void dmalloc_dump_outstanding () +{ + static unsigned long dmalloc_cutoff_point; + struct dmalloc_preamble *dp; + unsigned char *foo; + int i; + + if (!dmalloc_cutoff_point) + dmalloc_cutoff_point = dmalloc_cutoff_generation; + for (dp = dmalloc_list; dp; dp = dp -> prev) { + if (dp -> generation <= dmalloc_cutoff_point) + break; +#if defined (DEBUG_MALLOC_POOL) + for (i = 0; i < DMLFSIZE; i++) { + if (dp -> low_fence [i] != + (((unsigned long) + (&dp -> low_fence [i])) % 143) + 113) + { + log_error ("malloc fence modified: %s(%d)", + dp -> file, dp -> line); + abort (); + } + } + foo = (unsigned char *)dp; + for (i = DMDOFFSET; i < DMDSIZE; i++) { + if (foo [i + dp -> size] != + (((unsigned long) + (&foo [i + dp -> size])) % 143) + 113) { + log_error ("malloc fence modified: %s(%d)", + dp -> file, dp -> line); + abort (); + } + } +#endif +#if defined (DEBUG_MEMORY_LEAKAGE) || \ + defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) + /* Don't count data that's actually on a free list + somewhere. */ + if (dp -> file) { +#if defined (DEBUG_RC_HISTORY) + int i, count, inhistory = 0, noted = 0; + + /* If we have the info, see if this is actually + new garbage. */ + if (rc_history_count < RC_HISTORY_MAX) { + count = rc_history_count; + } else + count = RC_HISTORY_MAX; + i = rc_history_index - 1; + if (i < 0) + i += RC_HISTORY_MAX; + + do { + if (rc_history [i].addr == dp + 1) { + inhistory = 1; + if (!noted) { + log_info (" %s(%d): %d", dp -> file, + dp -> line, dp -> size); + noted = 1; + } + print_rc_hist_entry (i); + if (!rc_history [i].refcnt) + break; + } + if (--i < 0) + i = RC_HISTORY_MAX - 1; + } while (count--); + if (!inhistory) +#endif + log_info (" %s(%d): %d", + dp -> file, dp -> line, dp -> size); + } +#endif + } + if (dmalloc_list) + dmalloc_cutoff_point = dmalloc_list -> generation; +} +#endif /* DEBUG_MEMORY_LEAKAGE || DEBUG_MALLOC_POOL */ + +#if defined (DEBUG_RC_HISTORY) +static void print_rc_hist_entry (int i) +{ + log_info (" referenced by %s(%d)[%lx]: addr = %lx refcnt = %x", + rc_history [i].file, rc_history [i].line, + (unsigned long)rc_history [i].reference, + (unsigned long)rc_history [i].addr, + rc_history [i].refcnt); +} + +void dump_rc_history (void *addr) +{ + int i; + + i = rc_history_index; + if (!rc_history [i].file) + i = 0; + else if (rc_history_count < RC_HISTORY_MAX) { + i -= rc_history_count; + if (i < 0) + i += RC_HISTORY_MAX; + } + rc_history_count = 0; + + while (rc_history [i].file) { + if (!addr || addr == rc_history [i].addr) + print_rc_hist_entry (i); + ++i; + if (i == RC_HISTORY_MAX) + i = 0; + if (i == rc_history_index) + break; + } +} +void rc_history_next (int d) +{ +#if defined (RC_HISTORY_COMPRESSION) + int i, j = 0, m, n = 0; + void *ap, *rp; + + /* If we are decreasing the reference count, try to find the + entry where the reference was made and eliminate it; then + we can also eliminate this reference. */ + if (d) { + m = rc_history_index - 1000; + if (m < -1) + m = -1; + ap = rc_history [rc_history_index].addr; + rp = rc_history [rc_history_index].reference; + for (i = rc_history_index - 1; i > m; i--) { + if (rc_history [i].addr == ap) { + if (rc_history [i].reference == rp) { + if (n > 10) { + for (n = i; n <= rc_history_index; n++) + print_rc_hist_entry (n); + n = 11; + } + memmove (&rc_history [i], + &rc_history [i + 1], + (unsigned)((rc_history_index - i) * + sizeof (struct rc_history_entry))); + --rc_history_count; + --rc_history_index; + for (j = i; j < rc_history_count; j++) { + if (rc_history [j].addr == ap) + --rc_history [j].refcnt; + } + if (n > 10) { + for (n = i; n <= rc_history_index; n++) + print_rc_hist_entry (n); + n = 11; + exit (0); + } + return; + } + } + } + } +#endif + if (++rc_history_index == RC_HISTORY_MAX) + rc_history_index = 0; + ++rc_history_count; +} +#endif + +#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \ + defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) +struct caller { + struct dmalloc_preamble *dp; + int count; +}; + +static int dmalloc_find_entry (struct dmalloc_preamble *dp, + struct caller *array, + int min, int max) +{ + int middle; + int cmp; + + middle = (min + max) / 2; + if (middle == min) + return middle; + if (array [middle].dp -> file == dp -> file) { + if (array [middle].dp -> line == dp -> line) + return middle; + else if (array [middle].dp -> line < dp -> line) + return dmalloc_find_entry (dp, array, middle, max); + else + return dmalloc_find_entry (dp, array, 0, middle); + } else if (array [middle].dp -> file < dp -> file) + return dmalloc_find_entry (dp, array, middle, max); + else + return dmalloc_find_entry (dp, array, 0, middle); +} + +void omapi_print_dmalloc_usage_by_caller () +{ + struct dmalloc_preamble *dp; + unsigned char *foo; + int ccur, cmax, i, j; + struct caller cp [1024]; + + cmax = 1024; + ccur = 0; + + memset (cp, 0, sizeof cp); + for (dp = dmalloc_list; dp; dp = dp -> prev) { + i = dmalloc_find_entry (dp, cp, 0, ccur); + if ((i == ccur || + cp [i].dp -> file != dp -> file || + cp [i].dp -> line != dp -> line) && + ccur == cmax) { + log_error ("no space for memory usage summary."); + return; + } + if (i == ccur) { + cp [ccur++].dp = dp; + cp [i].count = 1; + } else if (cp [i].dp -> file < dp -> file || + (cp [i].dp -> file == dp -> file && + cp [i].dp -> line < dp -> line)) { + if (i + 1 != ccur) + memmove (cp + i + 2, cp + i + 1, + (ccur - i) * sizeof *cp); + cp [i + 1].dp = dp; + cp [i + 1].count = 1; + ccur++; + } else if (cp [i].dp -> file != dp -> file || + cp [i].dp -> line != dp -> line) { + memmove (cp + i + 1, + cp + i, (ccur - i) * sizeof *cp); + cp [i].dp = dp; + cp [i].count = 1; + ccur++; + } else + cp [i].count++; +#if 0 + printf ("%d\t%s:%d\n", i, dp -> file, dp -> line); + dump_rc_history (dp + 1); +#endif + } + for (i = 0; i < ccur; i++) { + printf ("%d\t%s:%d\t%d\n", i, + cp [i].dp -> file, cp [i].dp -> line, cp [i].count); + dump_rc_history (cp [i].dp + 1); + } +} +#endif /* DEBUG_MEMORY_LEAKAGE || DEBUG_MALLOC_POOL */ + +isc_result_t omapi_object_allocate (omapi_object_t **o, + omapi_object_type_t *type, + size_t size, + const char *file, int line) +{ + size_t tsize; + omapi_object_t *foo; + isc_result_t status; + + if (type -> allocator) { + foo = (omapi_object_t *)0; + status = (*type -> allocator) (&foo, file, line); + tsize = type -> size; + } else + status = ISC_R_NOMEMORY; + if (status == ISC_R_NOMEMORY) { + if (type -> sizer) + tsize = (*type -> sizer) (size); + else + tsize = type -> size; + + /* Sanity check. */ + if (tsize < sizeof (omapi_object_t)) + return ISC_R_INVALIDARG; + + foo = dmalloc (tsize, file, line); + if (!foo) + return ISC_R_NOMEMORY; + } + + status = omapi_object_initialize (foo, type, size, tsize, file, line); + if (status != ISC_R_SUCCESS) { + if (type -> freer) + (*type -> freer) (foo, file, line); + else + dfree (foo, file, line); + return status; + } + return omapi_object_reference (o, foo, file, line); +} + +isc_result_t omapi_object_initialize (omapi_object_t *o, + omapi_object_type_t *type, + size_t usize, size_t psize, + const char *file, int line) +{ + memset (o, 0, psize); + o -> type = type; + if (type -> initialize) + (*type -> initialize) (o, file, line); + return ISC_R_SUCCESS; +} + +isc_result_t omapi_object_reference (omapi_object_t **r, + omapi_object_t *h, + const char *file, int line) +{ + if (!h || !r) + return ISC_R_INVALIDARG; + + if (*r) { +#if defined (POINTER_DEBUG) + log_error ("%s(%d): reference store into non-null pointer!", + file, line); + abort (); +#else + return ISC_R_INVALIDARG; +#endif + } + *r = h; + h -> refcnt++; + rc_register (file, line, r, h, h -> refcnt, 0, h -> type -> rc_flag); + return ISC_R_SUCCESS; +} + +isc_result_t omapi_object_dereference (omapi_object_t **h, + const char *file, int line) +{ + int outer_reference = 0; + int inner_reference = 0; + int handle_reference = 0; + int extra_references; + omapi_object_t *p, *hp; + + if (!h) + return ISC_R_INVALIDARG; + + if (!*h) { +#if defined (POINTER_DEBUG) + log_error ("%s(%d): dereference of null pointer!", file, line); + abort (); +#else + return ISC_R_INVALIDARG; +#endif + } + + if ((*h) -> refcnt <= 0) { +#if defined (POINTER_DEBUG) + log_error ("%s(%d): dereference of pointer with refcnt of zero!", + file, line); +#if defined (DEBUG_RC_HISTORY) + dump_rc_history (*h); +#endif + abort (); +#else + *h = 0; + return ISC_R_INVALIDARG; +#endif + } + + /* See if this object's inner object refers to it, but don't + count this as a reference if we're being asked to free the + reference from the inner object. */ + if ((*h) -> inner && (*h) -> inner -> outer && + h != &((*h) -> inner -> outer)) + inner_reference = 1; + + /* Ditto for the outer object. */ + if ((*h) -> outer && (*h) -> outer -> inner && + h != &((*h) -> outer -> inner)) + outer_reference = 1; + + /* Ditto for the outer object. The code below assumes that + the only reason we'd get a dereference from the handle + table is if this function does it - otherwise we'd have to + traverse the handle table to find the address where the + reference is stored and compare against that, and we don't + want to do that if we can avoid it. */ + if ((*h) -> handle) + handle_reference = 1; + + /* If we are getting rid of the last reference other than + references to inner and outer objects, or from the handle + table, then we must examine all the objects in either + direction to see if they hold any non-inner, non-outer, + non-handle-table references. If not, we need to free the + entire chain of objects. */ + if ((*h) -> refcnt == + inner_reference + outer_reference + handle_reference + 1) { + if (inner_reference || outer_reference || handle_reference) { + /* XXX we could check for a reference from the + handle table here. */ + extra_references = 0; + for (p = (*h) -> inner; + p && !extra_references; p = p -> inner) { + extra_references += p -> refcnt; + if (p -> inner && p -> inner -> outer == p) + --extra_references; + if (p -> outer) + --extra_references; + if (p -> handle) + --extra_references; + } + for (p = (*h) -> outer; + p && !extra_references; p = p -> outer) { + extra_references += p -> refcnt; + if (p -> outer && p -> outer -> inner == p) + --extra_references; + if (p -> inner) + --extra_references; + if (p -> handle) + --extra_references; + } + } else + extra_references = 0; + + if (!extra_references) { + hp = *h; + *h = 0; + hp -> refcnt--; + if (inner_reference) + omapi_object_dereference + (&hp -> inner, file, line); + if (outer_reference) + omapi_object_dereference + (&hp -> outer, file, line); +/* if (!hp -> type -> freer) */ + rc_register (file, line, h, hp, + 0, 1, hp -> type -> rc_flag); + if (hp -> type -> destroy) + (*(hp -> type -> destroy)) (hp, file, line); + if (hp -> type -> freer) + (hp -> type -> freer (hp, file, line)); + else + dfree (hp, file, line); + } else { + (*h) -> refcnt--; +/* if (!(*h) -> type -> freer) */ + rc_register (file, line, + h, *h, (*h) -> refcnt, 1, + (*h) -> type -> rc_flag); + } + } else { + (*h) -> refcnt--; +/* if (!(*h) -> type -> freer) */ + rc_register (file, line, h, *h, (*h) -> refcnt, 1, + (*h) -> type -> rc_flag); + } + *h = 0; + return ISC_R_SUCCESS; +} + +isc_result_t omapi_buffer_new (omapi_buffer_t **h, + const char *file, int line) +{ + omapi_buffer_t *t; + isc_result_t status; + + t = (omapi_buffer_t *)dmalloc (sizeof *t, file, line); + if (!t) + return ISC_R_NOMEMORY; + memset (t, 0, sizeof *t); + status = omapi_buffer_reference (h, t, file, line); + if (status != ISC_R_SUCCESS) + dfree (t, file, line); + (*h) -> head = sizeof ((*h) -> buf) - 1; + return status; +} + +isc_result_t omapi_buffer_reference (omapi_buffer_t **r, + omapi_buffer_t *h, + const char *file, int line) +{ + if (!h || !r) + return ISC_R_INVALIDARG; + + if (*r) { +#if defined (POINTER_DEBUG) + log_error ("%s(%d): reference store into non-null pointer!", + file, line); + abort (); +#else + return ISC_R_INVALIDARG; +#endif + } + *r = h; + h -> refcnt++; + rc_register (file, line, r, h, h -> refcnt, 0, RC_MISC); + return ISC_R_SUCCESS; +} + +isc_result_t omapi_buffer_dereference (omapi_buffer_t **h, + const char *file, int line) +{ + if (!h) + return ISC_R_INVALIDARG; + + if (!*h) { +#if defined (POINTER_DEBUG) + log_error ("%s(%d): dereference of null pointer!", file, line); + abort (); +#else + return ISC_R_INVALIDARG; +#endif + } + + if ((*h) -> refcnt <= 0) { +#if defined (POINTER_DEBUG) + log_error ("%s(%d): dereference of pointer with refcnt of zero!", + file, line); +#if defined (DEBUG_RC_HISTORY) + dump_rc_history (*h); +#endif + abort (); +#else + *h = 0; + return ISC_R_INVALIDARG; +#endif + } + + --(*h) -> refcnt; + rc_register (file, line, h, *h, (*h) -> refcnt, 1, RC_MISC); + if ((*h) -> refcnt == 0) + dfree (*h, file, line); + *h = 0; + return ISC_R_SUCCESS; +} + +isc_result_t omapi_typed_data_new (const char *file, int line, + omapi_typed_data_t **t, + omapi_datatype_t type, ...) +{ + va_list l; + omapi_typed_data_t *new; + unsigned len; + unsigned val; + int intval; + char *s; + isc_result_t status; + omapi_object_t *obj; + + va_start (l, type); + + switch (type) { + case omapi_datatype_int: + len = OMAPI_TYPED_DATA_INT_LEN; + intval = va_arg (l, int); + break; + case omapi_datatype_string: + s = va_arg (l, char *); + val = strlen (s); + len = OMAPI_TYPED_DATA_NOBUFFER_LEN + val; + break; + case omapi_datatype_data: + val = va_arg (l, unsigned); + len = OMAPI_TYPED_DATA_NOBUFFER_LEN + val; + break; + case omapi_datatype_object: + len = OMAPI_TYPED_DATA_OBJECT_LEN; + obj = va_arg (l, omapi_object_t *); + break; + default: + return ISC_R_INVALIDARG; + } + + new = dmalloc (len, file, line); + if (!new) + return ISC_R_NOMEMORY; + memset (new, 0, len); + + switch (type) { + case omapi_datatype_int: + new -> u.integer = intval; + break; + case omapi_datatype_string: + memcpy (new -> u.buffer.value, s, val); + new -> u.buffer.len = val; + break; + case omapi_datatype_data: + new -> u.buffer.len = val; + break; + case omapi_datatype_object: + status = omapi_object_reference (&new -> u.object, obj, + file, line); + if (status != ISC_R_SUCCESS) { + dfree (new, file, line); + return status; + } + break; + } + new -> type = type; + + return omapi_typed_data_reference (t, new, file, line); +} + +isc_result_t omapi_typed_data_reference (omapi_typed_data_t **r, + omapi_typed_data_t *h, + const char *file, int line) +{ + if (!h || !r) + return ISC_R_INVALIDARG; + + if (*r) { +#if defined (POINTER_DEBUG) + log_error ("%s(%d): reference store into non-null pointer!", file, line); + abort (); +#else + return ISC_R_INVALIDARG; +#endif + } + *r = h; + h -> refcnt++; + rc_register (file, line, r, h, h -> refcnt, 0, RC_MISC); + return ISC_R_SUCCESS; +} + +isc_result_t omapi_typed_data_dereference (omapi_typed_data_t **h, + const char *file, int line) +{ + if (!h) + return ISC_R_INVALIDARG; + + if (!*h) { +#if defined (POINTER_DEBUG) + log_error ("%s(%d): dereference of null pointer!", file, line); + abort (); +#else + return ISC_R_INVALIDARG; +#endif + } + + if ((*h) -> refcnt <= 0) { +#if defined (POINTER_DEBUG) + log_error ("%s(%d): dereference of pointer with refcnt of zero!", + file, line); +#if defined (DEBUG_RC_HISTORY) + dump_rc_history (*h); +#endif + abort (); +#else + *h = 0; + return ISC_R_INVALIDARG; +#endif + } + + --((*h) -> refcnt); + rc_register (file, line, h, *h, (*h) -> refcnt, 1, RC_MISC); + if ((*h) -> refcnt <= 0 ) { + switch ((*h) -> type) { + case omapi_datatype_int: + case omapi_datatype_string: + case omapi_datatype_data: + default: + break; + case omapi_datatype_object: + omapi_object_dereference (&(*h) -> u.object, + file, line); + break; + } + dfree (*h, file, line); + } + *h = 0; + return ISC_R_SUCCESS; +} + +isc_result_t omapi_data_string_new (omapi_data_string_t **d, unsigned len, + const char *file, int line) +{ + omapi_data_string_t *new; + + new = dmalloc (OMAPI_DATA_STRING_EMPTY_SIZE + len, file, line); + if (!new) + return ISC_R_NOMEMORY; + memset (new, 0, OMAPI_DATA_STRING_EMPTY_SIZE); + new -> len = len; + return omapi_data_string_reference (d, new, file, line); +} + +isc_result_t omapi_data_string_reference (omapi_data_string_t **r, + omapi_data_string_t *h, + const char *file, int line) +{ + if (!h || !r) + return ISC_R_INVALIDARG; + + if (*r) { +#if defined (POINTER_DEBUG) + log_error ("%s(%d): reference store into non-null pointer!", file, line); + abort (); +#else + return ISC_R_INVALIDARG; +#endif + } + *r = h; + h -> refcnt++; + rc_register (file, line, r, h, h -> refcnt, 0, RC_MISC); + return ISC_R_SUCCESS; +} + +isc_result_t omapi_data_string_dereference (omapi_data_string_t **h, + const char *file, int line) +{ + if (!h) + return ISC_R_INVALIDARG; + + if (!*h) { +#if defined (POINTER_DEBUG) + log_error ("%s(%d): dereference of null pointer!", file, line); + abort (); +#else + return ISC_R_INVALIDARG; +#endif + } + + if ((*h) -> refcnt <= 0) { +#if defined (POINTER_DEBUG) + log_error ("%s(%d): dereference of pointer with refcnt of zero!", + file, line); +#if defined (DEBUG_RC_HISTORY) + dump_rc_history (*h); +#endif + abort (); +#else + *h = 0; + return ISC_R_INVALIDARG; +#endif + } + + --((*h) -> refcnt); + rc_register (file, line, h, *h, (*h) -> refcnt, 1, RC_MISC); + if ((*h) -> refcnt <= 0 ) { + dfree (*h, file, line); + } + *h = 0; + return ISC_R_SUCCESS; +} + +isc_result_t omapi_value_new (omapi_value_t **d, + const char *file, int line) +{ + omapi_value_t *new; + + new = dmalloc (sizeof *new, file, line); + if (!new) + return ISC_R_NOMEMORY; + memset (new, 0, sizeof *new); + return omapi_value_reference (d, new, file, line); +} + +isc_result_t omapi_value_reference (omapi_value_t **r, + omapi_value_t *h, + const char *file, int line) +{ + if (!h || !r) + return ISC_R_INVALIDARG; + + if (*r) { +#if defined (POINTER_DEBUG) + log_error ("%s(%d): reference store into non-null pointer!", + file, line); + abort (); +#else + return ISC_R_INVALIDARG; +#endif + } + *r = h; + h -> refcnt++; + rc_register (file, line, r, h, h -> refcnt, 0, RC_MISC); + return ISC_R_SUCCESS; +} + +isc_result_t omapi_value_dereference (omapi_value_t **h, + const char *file, int line) +{ + if (!h) + return ISC_R_INVALIDARG; + + if (!*h) { +#if defined (POINTER_DEBUG) + log_error ("%s(%d): dereference of null pointer!", file, line); + abort (); +#else + return ISC_R_INVALIDARG; +#endif + } + + if ((*h) -> refcnt <= 0) { +#if defined (POINTER_DEBUG) + log_error ("%s(%d): dereference of pointer with refcnt of zero!", + file, line); +#if defined (DEBUG_RC_HISTORY) + dump_rc_history (*h); +#endif + abort (); +#else + *h = 0; + return ISC_R_INVALIDARG; +#endif + } + + --((*h) -> refcnt); + rc_register (file, line, h, *h, (*h) -> refcnt, 1, RC_MISC); + if ((*h) -> refcnt == 0) { + if ((*h) -> name) + omapi_data_string_dereference (&(*h) -> name, + file, line); + if ((*h) -> value) + omapi_typed_data_dereference (&(*h) -> value, + file, line); + dfree (*h, file, line); + } + *h = 0; + return ISC_R_SUCCESS; +} + +isc_result_t omapi_addr_list_new (omapi_addr_list_t **d, unsigned count, + const char *file, int line) +{ + omapi_addr_list_t *new; + + new = dmalloc ((count * sizeof (omapi_addr_t)) + + sizeof (omapi_addr_list_t), file, line); + if (!new) + return ISC_R_NOMEMORY; + memset (new, 0, ((count * sizeof (omapi_addr_t)) + + sizeof (omapi_addr_list_t))); + new -> count = count; + new -> addresses = (omapi_addr_t *)(new + 1); + return omapi_addr_list_reference (d, new, file, line); +} + +isc_result_t omapi_addr_list_reference (omapi_addr_list_t **r, + omapi_addr_list_t *h, + const char *file, int line) +{ + if (!h || !r) + return ISC_R_INVALIDARG; + + if (*r) { +#if defined (POINTER_DEBUG) + log_error ("%s(%d): reference store into non-null pointer!", + file, line); + abort (); +#else + return ISC_R_INVALIDARG; +#endif + } + *r = h; + h -> refcnt++; + rc_register (file, line, r, h, h -> refcnt, 0, RC_MISC); + return ISC_R_SUCCESS; +} + +isc_result_t omapi_addr_list_dereference (omapi_addr_list_t **h, + const char *file, int line) +{ + if (!h) + return ISC_R_INVALIDARG; + + if (!*h) { +#if defined (POINTER_DEBUG) + log_error ("%s(%d): dereference of null pointer!", file, line); + abort (); +#else + return ISC_R_INVALIDARG; +#endif + } + + if ((*h) -> refcnt <= 0) { +#if defined (POINTER_DEBUG) + log_error ("%s(%d): dereference of pointer with zero refcnt!", + file, line); +#if defined (DEBUG_RC_HISTORY) + dump_rc_history (*h); +#endif + abort (); +#else + *h = 0; + return ISC_R_INVALIDARG; +#endif + } + + --((*h) -> refcnt); + rc_register (file, line, h, *h, (*h) -> refcnt, 1, RC_MISC); + if ((*h) -> refcnt <= 0 ) { + dfree (*h, file, line); + } + *h = 0; + return ISC_R_SUCCESS; +} + diff --git a/contrib/isc-dhcp/omapip/array.c b/contrib/isc-dhcp/omapip/array.c new file mode 100644 index 0000000..56d8d9f --- /dev/null +++ b/contrib/isc-dhcp/omapip/array.c @@ -0,0 +1,172 @@ +/* listener.c + + Subroutines that support the omapi extensible array type. */ + +/* + * Copyright (c) 2001 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. + */ + +#include <omapip/omapip_p.h> + +/* Allocate a new extensible array. */ + +isc_result_t omapi_array_allocate (omapi_array_t **array, + omapi_array_ref_t ref, + omapi_array_deref_t deref, + const char *file, int line) +{ + isc_result_t status; + omapi_array_t *aptr; + + if (!array || *array) + return ISC_R_INVALIDARG; + aptr = dmalloc (sizeof (omapi_array_t),file, line); + if (!aptr) + return ISC_R_NOMEMORY; + *array = aptr; + aptr -> ref = ref; + aptr -> deref = deref; + return ISC_R_SUCCESS; +} + +isc_result_t omapi_array_free (omapi_array_t **array, + const char *file, int line) +{ + isc_result_t status; + omapi_array_t *aptr; + int i; + + if (!array || !*array) + return ISC_R_INVALIDARG; + aptr = *array; + for (i = 0; i < aptr -> count; i++) + if (aptr -> data [i] && aptr -> deref) + (*aptr -> deref) (&aptr -> data [i], file, line); + dfree (aptr -> data, MDL); + dfree (aptr, MDL); + *array = (omapi_array_t *)0; + return ISC_R_SUCCESS; +} + +/* Extend the size of the array by one entry (we may allocate more than that) + and store the specified value in the new array element. */ + +isc_result_t omapi_array_extend (omapi_array_t *array, char *ptr, + int *index, const char *file, int line) +{ + isc_result_t status; + int new = array -> count; + status = omapi_array_set (array, ptr, new, file, line); + if (index && status == ISC_R_SUCCESS) + *index = new; + return status; +} + +/* Set a value in the specified array, extending it if necessary. */ + +isc_result_t omapi_array_set (omapi_array_t *array, void *ptr, int index, + const char *file, int line) +{ + char **newbuf; + int delta; + isc_result_t status; + + if (!array) + return ISC_R_INVALIDARG; + if (!ptr) + return ISC_R_INVALIDARG; + if (index < 0) + return ISC_R_INVALIDARG; + + /* If the proposed index is larger than the current available + space in the array, make more space in the array. */ + if (array -> max <= index) { + delta = index - array -> max + 10; + newbuf = dmalloc ((array -> max + delta) * sizeof (char *), + file, line); + if (!newbuf) + return ISC_R_NOMEMORY; + /* Zero the new elements. */ + memset (&newbuf [array -> max], 0, (sizeof (char *)) * delta); + array -> max += delta; + /* Copy the old array data into the new buffer. */ + if (array -> data) { + memcpy (newbuf, + array -> data, array -> count * sizeof (char *)); + dfree (array -> data, file, line); + } + array -> data = newbuf; + } else { + /* If there's already data there, and this is an array + of references, dereference what's there. */ + if (array -> data [index]) { + status = ((*array -> deref) (&array -> data [index], + file, line)); + + if (status != ISC_R_SUCCESS) + return status; + } + } + + /* Store the pointer using the referencer function. We have + either just memset this to zero or dereferenced what was + there previously, so there is no need to do anything if the + pointer we have been asked to store is null. */ + if (ptr) { + status = (*array -> ref) (&array -> data [index], ptr, + file, line); + if (status != ISC_R_SUCCESS) + return status; + } + if (index >= array -> count) + array -> count = index + 1; + return ISC_R_SUCCESS; +} + +isc_result_t omapi_array_lookup (char **ptr, omapi_array_t *array, int index, + const char *file, int line) +{ + if (!array || !ptr || *ptr || index < 0 || index >= array -> count) + return ISC_R_INVALIDARG; + if (array -> data [index]) + return (*array -> ref) (ptr, + array -> data [index], file, line); + return ISC_R_NOTFOUND; +} + +OMAPI_ARRAY_TYPE_DECL(omapi_object, omapi_object_t); diff --git a/contrib/isc-dhcp/omapip/auth.c b/contrib/isc-dhcp/omapip/auth.c new file mode 100644 index 0000000..ea0c2f6 --- /dev/null +++ b/contrib/isc-dhcp/omapip/auth.c @@ -0,0 +1,273 @@ +/* auth.c + + Subroutines having to do with authentication. */ + +/* + * Copyright (c) 1998-2001 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. + */ + +#ifndef lint +static char ocopyright[] = +"$Id: auth.c,v 1.3.2.3 2001/10/17 03:27:56 mellon Exp $ Copyright 1998-2000 The Internet Software Consortium."; +#endif + +#include <omapip/omapip_p.h> + +OMAPI_OBJECT_ALLOC (omapi_auth_key, omapi_auth_key_t, omapi_type_auth_key) +typedef struct hash omapi_auth_hash_t; +HASH_FUNCTIONS_DECL (omapi_auth_key, const char *, + omapi_auth_key_t, omapi_auth_hash_t) +omapi_auth_hash_t *auth_key_hash; +HASH_FUNCTIONS (omapi_auth_key, const char *, omapi_auth_key_t, + omapi_auth_hash_t, + omapi_auth_key_reference, omapi_auth_key_dereference) + +isc_result_t omapi_auth_key_new (omapi_auth_key_t **o, const char *file, + int line) +{ + return omapi_auth_key_allocate (o, file, line); +} + +isc_result_t omapi_auth_key_destroy (omapi_object_t *h, + const char *file, int line) +{ + omapi_auth_key_t *a; + + if (h -> type != omapi_type_auth_key) + return ISC_R_INVALIDARG; + a = (omapi_auth_key_t *)h; + + if (auth_key_hash) + omapi_auth_key_hash_delete (auth_key_hash, a -> name, 0, MDL); + + if (a -> name) + dfree (a -> name, MDL); + if (a -> algorithm) + dfree (a -> algorithm, MDL); + if (a -> key) + omapi_data_string_dereference (&a -> key, MDL); + + return ISC_R_SUCCESS; +} + +isc_result_t omapi_auth_key_enter (omapi_auth_key_t *a) +{ + omapi_auth_key_t *tk; + + if (a -> type != omapi_type_auth_key) + return ISC_R_INVALIDARG; + + tk = (omapi_auth_key_t *)0; + if (auth_key_hash) { + omapi_auth_key_hash_lookup (&tk, auth_key_hash, + a -> name, 0, MDL); + if (tk == a) { + omapi_auth_key_dereference (&tk, MDL); + return ISC_R_SUCCESS; + } + if (tk) { + omapi_auth_key_hash_delete (auth_key_hash, + tk -> name, 0, MDL); + omapi_auth_key_dereference (&tk, MDL); + } + } else { + if (!omapi_auth_key_new_hash (&auth_key_hash, 1, MDL)) + return ISC_R_NOMEMORY; + } + omapi_auth_key_hash_add (auth_key_hash, a -> name, 0, a, MDL); + return ISC_R_SUCCESS; + +} + +isc_result_t omapi_auth_key_lookup_name (omapi_auth_key_t **a, + const char *name) +{ + if (!auth_key_hash) + return ISC_R_NOTFOUND; + if (!omapi_auth_key_hash_lookup (a, auth_key_hash, name, 0, MDL)) + return ISC_R_NOTFOUND; + return ISC_R_SUCCESS; +} + +isc_result_t omapi_auth_key_lookup (omapi_object_t **h, + omapi_object_t *id, + omapi_object_t *ref) +{ + isc_result_t status; + omapi_value_t *name = (omapi_value_t *)0; + omapi_value_t *algorithm = (omapi_value_t *)0; + + if (!auth_key_hash) + return ISC_R_NOTFOUND; + + if (!ref) + return ISC_R_NOKEYS; + + status = omapi_get_value_str (ref, id, "name", &name); + if (status != ISC_R_SUCCESS) + return status; + + if ((name -> value -> type != omapi_datatype_string) && + (name -> value -> type != omapi_datatype_data)) { + omapi_value_dereference (&name, MDL); + return ISC_R_NOTFOUND; + } + + status = omapi_get_value_str (ref, id, "algorithm", &algorithm); + if (status != ISC_R_SUCCESS) { + omapi_value_dereference (&name, MDL); + return status; + } + + if ((algorithm -> value -> type != omapi_datatype_string) && + (algorithm -> value -> type != omapi_datatype_data)) { + omapi_value_dereference (&name, MDL); + omapi_value_dereference (&algorithm, MDL); + return ISC_R_NOTFOUND; + } + + + if (!omapi_auth_key_hash_lookup ((omapi_auth_key_t **)h, auth_key_hash, + (const char *) + name -> value -> u.buffer.value, + name -> value -> u.buffer.len, MDL)) { + omapi_value_dereference (&name, MDL); + omapi_value_dereference (&algorithm, MDL); + return ISC_R_NOTFOUND; + } + + if (omapi_td_strcasecmp (algorithm -> value, + ((omapi_auth_key_t *)*h) -> algorithm) != 0) { + omapi_value_dereference (&name, MDL); + omapi_value_dereference (&algorithm, MDL); + omapi_object_dereference (h, MDL); + return ISC_R_NOTFOUND; + } + + omapi_value_dereference (&name, MDL); + omapi_value_dereference (&algorithm, MDL); + + return ISC_R_SUCCESS; +} + +isc_result_t omapi_auth_key_stuff_values (omapi_object_t *c, + omapi_object_t *id, + omapi_object_t *h) +{ + omapi_auth_key_t *a; + isc_result_t status; + + if (h -> type != omapi_type_auth_key) + return ISC_R_INVALIDARG; + a = (omapi_auth_key_t *)h; + + /* Write only the name and algorithm -- not the secret! */ + if (a -> name) { + status = omapi_connection_put_name (c, "name"); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_put_string (c, a -> name); + if (status != ISC_R_SUCCESS) + return status; + } + if (a -> algorithm) { + status = omapi_connection_put_name (c, "algorithm"); + if (status != ISC_R_SUCCESS) + return status; + status = omapi_connection_put_string (c, a -> algorithm); + if (status != ISC_R_SUCCESS) + return status; + } + + return ISC_R_SUCCESS; +} + +isc_result_t omapi_auth_key_get_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_value_t **value) +{ + omapi_auth_key_t *a; + isc_result_t status; + + if (h -> type != omapi_type_auth_key) + return ISC_R_UNEXPECTED; + a = (omapi_auth_key_t *)h; + + if (omapi_ds_strcmp (name, "name") == 0) { + if (a -> name) + return omapi_make_string_value + (value, name, a -> name, MDL); + else + return ISC_R_NOTFOUND; + } else if (omapi_ds_strcmp (name, "key") == 0) { + if (a -> key) { + status = omapi_value_new (value, MDL); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_data_string_reference + (&(*value) -> name, name, MDL); + if (status != ISC_R_SUCCESS) { + omapi_value_dereference (value, MDL); + return status; + } + + status = omapi_typed_data_new (MDL, &(*value) -> value, + omapi_datatype_data, + a -> key -> len); + if (status != ISC_R_SUCCESS) { + omapi_value_dereference (value, MDL); + return status; + } + + memcpy ((*value) -> value -> u.buffer.value, + a -> key -> value, a -> key -> len); + return ISC_R_SUCCESS; + } else + return ISC_R_NOTFOUND; + } else if (omapi_ds_strcmp (name, "algorithm") == 0) { + if (a -> algorithm) + return omapi_make_string_value + (value, name, a -> algorithm, MDL); + else + return ISC_R_NOTFOUND; + } + + return ISC_R_SUCCESS; +} diff --git a/contrib/isc-dhcp/omapip/buffer.c b/contrib/isc-dhcp/omapip/buffer.c new file mode 100644 index 0000000..3d01357 --- /dev/null +++ b/contrib/isc-dhcp/omapip/buffer.c @@ -0,0 +1,718 @@ +/* buffer.c + + Buffer access functions for the object management protocol... */ + +/* + * Copyright (c) 1999-2001 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. + */ + +#include <omapip/omapip_p.h> + +#if defined (TRACING) +static void trace_connection_input_input (trace_type_t *, unsigned, char *); +static void trace_connection_input_stop (trace_type_t *); +static void trace_connection_output_input (trace_type_t *, unsigned, char *); +static void trace_connection_output_stop (trace_type_t *); +static trace_type_t *trace_connection_input; +static trace_type_t *trace_connection_output; +static isc_result_t omapi_connection_reader_trace (omapi_object_t *, + unsigned, char *, + unsigned *); +extern omapi_array_t *omapi_connections; + +void omapi_buffer_trace_setup () +{ + trace_connection_input = + trace_type_register ("connection-input", + (void *)0, + trace_connection_input_input, + trace_connection_input_stop, MDL); + trace_connection_output = + trace_type_register ("connection-output", + (void *)0, + trace_connection_output_input, + trace_connection_output_stop, MDL); +} + +static void trace_connection_input_input (trace_type_t *ttype, + unsigned length, char *buf) +{ + unsigned left, taken, cc = 0; + char *s; + int32_t connect_index; + isc_result_t status; + omapi_connection_object_t *c = (omapi_connection_object_t *)0; + + memcpy (&connect_index, buf, sizeof connect_index); + connect_index = ntohl (connect_index); + + omapi_array_foreach_begin (omapi_connections, + omapi_connection_object_t, lp) { + if (lp -> index == ntohl (connect_index)) { + omapi_connection_reference (&c, lp, MDL); + omapi_connection_dereference (&lp, MDL); + break; + } + } omapi_array_foreach_end (omapi_connections, + omapi_connection_object_t, lp); + + if (!c) { + log_error ("trace connection input: no connection index %ld", + (long int)connect_index); + return; + } + + s = buf + sizeof connect_index; + left = length - sizeof connect_index; + + while (left) { + taken = 0; + status = omapi_connection_reader_trace ((omapi_object_t *)c, + left, s, &taken); + if (status != ISC_R_SUCCESS) { + log_error ("trace connection input: %s", + isc_result_totext (status)); + break; + } + if (!taken) { + if (cc > 0) { + log_error ("trace connection_input: %s", + "input is not being consumed."); + break; + } + cc++; + } else { + cc = 0; + left -= taken; + } + } + omapi_connection_dereference (&c, MDL); +} + +static void trace_connection_input_stop (trace_type_t *ttype) { } + +static void trace_connection_output_input (trace_type_t *ttype, + unsigned length, char *buf) +{ + /* We *could* check to see if the output is correct, but for now + we aren't going to do that. */ +} + +static void trace_connection_output_stop (trace_type_t *ttype) { } + +#endif + +/* Make sure that at least len bytes are in the input buffer, and if not, + read enough bytes to make up the difference. */ + +isc_result_t omapi_connection_reader (omapi_object_t *h) +{ +#if defined (TRACING) + return omapi_connection_reader_trace (h, 0, (char *)0, (unsigned *)0); +} + +static isc_result_t omapi_connection_reader_trace (omapi_object_t *h, + unsigned stuff_len, + char *stuff_buf, + unsigned *stuff_taken) +{ +#endif + omapi_buffer_t *buffer; + isc_result_t status; + unsigned read_len; + int read_status; + omapi_connection_object_t *c; + unsigned bytes_to_read; + + if (!h || h -> type != omapi_type_connection) + return ISC_R_INVALIDARG; + c = (omapi_connection_object_t *)h; + + /* Make sure c -> bytes_needed is valid. */ + if (c -> bytes_needed < 0) + return ISC_R_INVALIDARG; + + /* See if there are enough bytes. */ + if (c -> in_bytes >= OMAPI_BUF_SIZE - 1 && + c -> in_bytes > c -> bytes_needed) + return ISC_R_SUCCESS; + + + if (c -> inbufs) { + for (buffer = c -> inbufs; buffer -> next; + buffer = buffer -> next) + ; + if (!BUFFER_BYTES_FREE (buffer)) { + status = omapi_buffer_new (&buffer -> next, MDL); + if (status != ISC_R_SUCCESS) + return status; + buffer = buffer -> next; + } + } else { + status = omapi_buffer_new (&c -> inbufs, MDL); + if (status != ISC_R_SUCCESS) + return status; + buffer = c -> inbufs; + } + + bytes_to_read = BUFFER_BYTES_FREE (buffer); + + while (bytes_to_read) { + if (buffer -> tail > buffer -> head) + read_len = sizeof (buffer -> buf) - buffer -> tail; + else + read_len = buffer -> head - buffer -> tail; + +#if defined (TRACING) + if (trace_playback()) { + if (stuff_len) { + if (read_len > stuff_len) + read_len = stuff_len; + if (stuff_taken) + *stuff_taken += read_len; + memcpy (&buffer -> buf [buffer -> tail], + stuff_buf, read_len); + stuff_len -= read_len; + stuff_buf += read_len; + read_status = read_len; + } else { + break; + } + } else +#endif + { + read_status = read (c -> socket, + &buffer -> buf [buffer -> tail], + read_len); + } + if (read_status < 0) { + if (errno == EWOULDBLOCK) + break; + else if (errno == EIO) + return ISC_R_IOERROR; + else if (errno == EINVAL) + return ISC_R_INVALIDARG; + else if (errno == ECONNRESET) { + omapi_disconnect (h, 1); + return ISC_R_SHUTTINGDOWN; + } else + return ISC_R_UNEXPECTED; + } + + /* If we got a zero-length read, as opposed to EWOULDBLOCK, + the remote end closed the connection. */ + if (read_status == 0) { + omapi_disconnect (h, 0); + return ISC_R_SHUTTINGDOWN; + } +#if defined (TRACING) + if (trace_record ()) { + trace_iov_t iov [2]; + int32_t connect_index; + + connect_index = htonl (c -> index); + + iov [0].buf = (char *)&connect_index; + iov [0].len = sizeof connect_index; + iov [1].buf = &buffer -> buf [buffer -> tail]; + iov [1].len = read_status; + + status = (trace_write_packet_iov + (trace_connection_input, 2, iov, MDL)); + if (status != ISC_R_SUCCESS) { + trace_stop (); + log_error ("trace connection input: %s", + isc_result_totext (status)); + } + } +#endif + buffer -> tail += read_status; + c -> in_bytes += read_status; + if (buffer -> tail == sizeof buffer -> buf) + buffer -> tail = 0; + if (read_status < read_len) + break; + bytes_to_read -= read_status; + } + + if (c -> bytes_needed <= c -> in_bytes) { + omapi_signal (h, "ready", c); + } + return ISC_R_SUCCESS; +} + +/* Put some bytes into the output buffer for a connection. */ + +isc_result_t omapi_connection_copyin (omapi_object_t *h, + const unsigned char *bufp, + unsigned len) +{ + omapi_buffer_t *buffer; + isc_result_t status; + int bytes_copied = 0; + unsigned copy_len; + int sig_flags = SIG_MODE_UPDATE; + omapi_connection_object_t *c; + + /* Make sure len is valid. */ + if (len < 0) + return ISC_R_INVALIDARG; + if (!h || h -> type != omapi_type_connection) + return ISC_R_INVALIDARG; + c = (omapi_connection_object_t *)h; + + /* If the connection is closed, return an error if the caller + tries to copy in. */ + if (c -> state == omapi_connection_disconnecting || + c -> state == omapi_connection_closed) + return ISC_R_NOTCONNECTED; + + if (c -> outbufs) { + for (buffer = c -> outbufs; + buffer -> next; buffer = buffer -> next) + ; + } else { + status = omapi_buffer_new (&c -> outbufs, MDL); + if (status != ISC_R_SUCCESS) + return status; + buffer = c -> outbufs; + } + + while (bytes_copied < len) { + /* If there is no space available in this buffer, + allocate a new one. */ + if (!BUFFER_BYTES_FREE (buffer)) { + status = (omapi_buffer_new (&buffer -> next, MDL)); + if (status != ISC_R_SUCCESS) + return status; + buffer = buffer -> next; + } + + if (buffer -> tail > buffer -> head) + copy_len = sizeof (buffer -> buf) - buffer -> tail; + else + copy_len = buffer -> head - buffer -> tail; + + if (copy_len > (len - bytes_copied)) + copy_len = len - bytes_copied; + + if (c -> out_key) { + if (!c -> out_context) + sig_flags |= SIG_MODE_INIT; + status = omapi_connection_sign_data + (sig_flags, c -> out_key, &c -> out_context, + &bufp [bytes_copied], copy_len, + (omapi_typed_data_t **)0); + if (status != ISC_R_SUCCESS) + return status; + } + + memcpy (&buffer -> buf [buffer -> tail], + &bufp [bytes_copied], copy_len); + buffer -> tail += copy_len; + c -> out_bytes += copy_len; + bytes_copied += copy_len; + if (buffer -> tail == sizeof buffer -> buf) + buffer -> tail = 0; + } + return ISC_R_SUCCESS; +} + +/* Copy some bytes from the input buffer, and advance the input buffer + pointer beyond the bytes copied out. */ + +isc_result_t omapi_connection_copyout (unsigned char *buf, + omapi_object_t *h, + unsigned size) +{ + unsigned bytes_remaining; + unsigned bytes_this_copy; + unsigned first_byte; + omapi_buffer_t *buffer; + unsigned char *bufp; + int sig_flags = SIG_MODE_UPDATE; + omapi_connection_object_t *c; + isc_result_t status; + + if (!h || h -> type != omapi_type_connection) + return ISC_R_INVALIDARG; + c = (omapi_connection_object_t *)h; + + if (size > c -> in_bytes) + return ISC_R_NOMORE; + bufp = buf; + bytes_remaining = size; + buffer = c -> inbufs; + + while (bytes_remaining) { + if (!buffer) + return ISC_R_UNEXPECTED; + if (BYTES_IN_BUFFER (buffer)) { + if (buffer -> head == (sizeof buffer -> buf) - 1) + first_byte = 0; + else + first_byte = buffer -> head + 1; + + if (first_byte > buffer -> tail) { + bytes_this_copy = (sizeof buffer -> buf - + first_byte); + } else { + bytes_this_copy = + buffer -> tail - first_byte; + } + if (bytes_this_copy > bytes_remaining) + bytes_this_copy = bytes_remaining; + if (bufp) { + if (c -> in_key) { + if (!c -> in_context) + sig_flags |= SIG_MODE_INIT; + status = omapi_connection_sign_data + (sig_flags, + c -> in_key, + &c -> in_context, + (unsigned char *) + &buffer -> buf [first_byte], + bytes_this_copy, + (omapi_typed_data_t **)0); + if (status != ISC_R_SUCCESS) + return status; + } + + memcpy (bufp, &buffer -> buf [first_byte], + bytes_this_copy); + bufp += bytes_this_copy; + } + bytes_remaining -= bytes_this_copy; + buffer -> head = first_byte + bytes_this_copy - 1; + c -> in_bytes -= bytes_this_copy; + } + + if (!BYTES_IN_BUFFER (buffer)) + buffer = buffer -> next; + } + + /* Get rid of any input buffers that we emptied. */ + buffer = (omapi_buffer_t *)0; + while (c -> inbufs && + !BYTES_IN_BUFFER (c -> inbufs)) { + if (c -> inbufs -> next) { + omapi_buffer_reference (&buffer, + c -> inbufs -> next, MDL); + omapi_buffer_dereference (&c -> inbufs -> next, MDL); + } + omapi_buffer_dereference (&c -> inbufs, MDL); + if (buffer) { + omapi_buffer_reference + (&c -> inbufs, buffer, MDL); + omapi_buffer_dereference (&buffer, MDL); + } + } + return ISC_R_SUCCESS; +} + +isc_result_t omapi_connection_writer (omapi_object_t *h) +{ + unsigned bytes_this_write; + int bytes_written; + unsigned first_byte; + omapi_buffer_t *buffer; + unsigned char *bufp; + omapi_connection_object_t *c; + isc_result_t status; + + if (!h || h -> type != omapi_type_connection) + return ISC_R_INVALIDARG; + c = (omapi_connection_object_t *)h; + + /* Already flushed... */ + if (!c -> out_bytes) + return ISC_R_SUCCESS; + + buffer = c -> outbufs; + + while (c -> out_bytes) { + if (!buffer) + return ISC_R_UNEXPECTED; + if (BYTES_IN_BUFFER (buffer)) { + if (buffer -> head == (sizeof buffer -> buf) - 1) + first_byte = 0; + else + first_byte = buffer -> head + 1; + + if (first_byte > buffer -> tail) { + bytes_this_write = (sizeof buffer -> buf - + first_byte); + } else { + bytes_this_write = + buffer -> tail - first_byte; + } + bytes_written = write (c -> socket, + &buffer -> buf [first_byte], + bytes_this_write); + /* If the write failed with EWOULDBLOCK or we wrote + zero bytes, a further write would block, so we have + flushed as much as we can for now. Other errors + are really errors. */ + if (bytes_written < 0) { + if (errno == EWOULDBLOCK || errno == EAGAIN) + return ISC_R_SUCCESS; + else if (errno == EPIPE) + return ISC_R_NOCONN; +#ifdef EDQUOT + else if (errno == EFBIG || errno == EDQUOT) +#else + else if (errno == EFBIG) +#endif + return ISC_R_NORESOURCES; + else if (errno == ENOSPC) + return ISC_R_NOSPACE; + else if (errno == EIO) + return ISC_R_IOERROR; + else if (errno == EINVAL) + return ISC_R_INVALIDARG; + else if (errno == ECONNRESET) + return ISC_R_SHUTTINGDOWN; + else + return ISC_R_UNEXPECTED; + } + if (bytes_written == 0) + return ISC_R_SUCCESS; + +#if defined (TRACING) + if (trace_record ()) { + trace_iov_t iov [2]; + int32_t connect_index; + + connect_index = htonl (c -> index); + + iov [0].buf = (char *)&connect_index; + iov [0].len = sizeof connect_index; + iov [1].buf = &buffer -> buf [buffer -> tail]; + iov [1].len = bytes_written; + + status = (trace_write_packet_iov + (trace_connection_input, 2, iov, + MDL)); + if (status != ISC_R_SUCCESS) { + trace_stop (); + log_error ("trace %s output: %s", + "connection", + isc_result_totext (status)); + } + } +#endif + + buffer -> head = first_byte + bytes_written - 1; + c -> out_bytes -= bytes_written; + + /* If we didn't finish out the write, we filled the + O.S. output buffer and a further write would block, + so stop trying to flush now. */ + if (bytes_written != bytes_this_write) + return ISC_R_SUCCESS; + } + + if (!BYTES_IN_BUFFER (buffer)) + buffer = buffer -> next; + } + + /* Get rid of any output buffers we emptied. */ + buffer = (omapi_buffer_t *)0; + while (c -> outbufs && + !BYTES_IN_BUFFER (c -> outbufs)) { + if (c -> outbufs -> next) { + omapi_buffer_reference (&buffer, + c -> outbufs -> next, MDL); + omapi_buffer_dereference (&c -> outbufs -> next, MDL); + } + omapi_buffer_dereference (&c -> outbufs, MDL); + if (buffer) { + omapi_buffer_reference (&c -> outbufs, buffer, MDL); + omapi_buffer_dereference (&buffer, MDL); + } + } + return ISC_R_SUCCESS; +} + +isc_result_t omapi_connection_get_uint32 (omapi_object_t *c, + u_int32_t *result) +{ + u_int32_t inbuf; + isc_result_t status; + + status = omapi_connection_copyout ((unsigned char *)&inbuf, + c, sizeof inbuf); + if (status != ISC_R_SUCCESS) + return status; + + *result = ntohl (inbuf); + return ISC_R_SUCCESS; +} + +isc_result_t omapi_connection_put_uint32 (omapi_object_t *c, + u_int32_t value) +{ + u_int32_t inbuf; + isc_result_t status; + + inbuf = htonl (value); + + return omapi_connection_copyin (c, (unsigned char *)&inbuf, + sizeof inbuf); +} + +isc_result_t omapi_connection_get_uint16 (omapi_object_t *c, + u_int16_t *result) +{ + u_int16_t inbuf; + isc_result_t status; + + status = omapi_connection_copyout ((unsigned char *)&inbuf, + c, sizeof inbuf); + if (status != ISC_R_SUCCESS) + return status; + + *result = ntohs (inbuf); + return ISC_R_SUCCESS; +} + +isc_result_t omapi_connection_put_uint16 (omapi_object_t *c, + u_int32_t value) +{ + u_int16_t inbuf; + isc_result_t status; + + inbuf = htons (value); + + return omapi_connection_copyin (c, (unsigned char *)&inbuf, + sizeof inbuf); +} + +isc_result_t omapi_connection_write_typed_data (omapi_object_t *c, + omapi_typed_data_t *data) +{ + isc_result_t status; + omapi_handle_t handle; + + /* Null data is valid. */ + if (!data) + return omapi_connection_put_uint32 (c, 0); + + switch (data -> type) { + case omapi_datatype_int: + status = omapi_connection_put_uint32 (c, sizeof (u_int32_t)); + if (status != ISC_R_SUCCESS) + return status; + return omapi_connection_put_uint32 (c, ((u_int32_t) + (data -> u.integer))); + + case omapi_datatype_string: + case omapi_datatype_data: + status = omapi_connection_put_uint32 (c, data -> u.buffer.len); + if (status != ISC_R_SUCCESS) + return status; + if (data -> u.buffer.len) + return omapi_connection_copyin + (c, data -> u.buffer.value, + data -> u.buffer.len); + return ISC_R_SUCCESS; + + case omapi_datatype_object: + if (data -> u.object) { + status = omapi_object_handle (&handle, + data -> u.object); + if (status != ISC_R_SUCCESS) + return status; + } else + handle = 0; + status = omapi_connection_put_uint32 (c, sizeof handle); + if (status != ISC_R_SUCCESS) + return status; + return omapi_connection_put_uint32 (c, handle); + + } + return ISC_R_INVALIDARG; +} + +isc_result_t omapi_connection_put_name (omapi_object_t *c, const char *name) +{ + isc_result_t status; + unsigned len = strlen (name); + + status = omapi_connection_put_uint16 (c, len); + if (status != ISC_R_SUCCESS) + return status; + return omapi_connection_copyin (c, (const unsigned char *)name, len); +} + +isc_result_t omapi_connection_put_string (omapi_object_t *c, + const char *string) +{ + isc_result_t status; + unsigned len; + + if (string) + len = strlen (string); + else + len = 0; + + status = omapi_connection_put_uint32 (c, len); + if (status != ISC_R_SUCCESS) + return status; + if (len) + return omapi_connection_copyin + (c, (const unsigned char *)string, len); + return ISC_R_SUCCESS; +} + +isc_result_t omapi_connection_put_handle (omapi_object_t *c, omapi_object_t *h) +{ + isc_result_t status; + omapi_handle_t handle; + + if (h) { + status = omapi_object_handle (&handle, h); + if (status != ISC_R_SUCCESS) + return status; + } else + handle = 0; /* The null handle. */ + status = omapi_connection_put_uint32 (c, sizeof handle); + if (status != ISC_R_SUCCESS) + return status; + return omapi_connection_put_uint32 (c, handle); +} diff --git a/contrib/isc-dhcp/omapip/connection.c b/contrib/isc-dhcp/omapip/connection.c new file mode 100644 index 0000000..77ce113 --- /dev/null +++ b/contrib/isc-dhcp/omapip/connection.c @@ -0,0 +1,1026 @@ +/* connection.c + + Subroutines for dealing with connections. */ + +/* + * Copyright (c) 1999-2001 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. + */ + +#include <omapip/omapip_p.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> + + +#if defined (TRACING) +static void trace_connect_input (trace_type_t *, unsigned, char *); +static void trace_connect_stop (trace_type_t *); +static void trace_disconnect_input (trace_type_t *, unsigned, char *); +static void trace_disconnect_stop (trace_type_t *); +trace_type_t *trace_connect; +trace_type_t *trace_disconnect; +extern omapi_array_t *trace_listeners; +#endif +static isc_result_t omapi_connection_connect_internal (omapi_object_t *); + +OMAPI_OBJECT_ALLOC (omapi_connection, + omapi_connection_object_t, omapi_type_connection) + +isc_result_t omapi_connect (omapi_object_t *c, + const char *server_name, + unsigned port) +{ + struct hostent *he; + unsigned i, hix; + omapi_addr_list_t *addrs = (omapi_addr_list_t *)0; + struct in_addr foo; + isc_result_t status; + +#ifdef DEBUG_PROTOCOL + log_debug ("omapi_connect(%s, port=%d)", server_name, port); +#endif + + if (!inet_aton (server_name, &foo)) { + /* If we didn't get a numeric address, try for a domain + name. It's okay for this call to block. */ + he = gethostbyname (server_name); + if (!he) + return ISC_R_HOSTUNKNOWN; + for (i = 0; he -> h_addr_list [i]; i++) + ; + if (i == 0) + return ISC_R_HOSTUNKNOWN; + hix = i; + + status = omapi_addr_list_new (&addrs, hix, MDL); + if (status != ISC_R_SUCCESS) + return status; + for (i = 0; i < hix; i++) { + addrs -> addresses [i].addrtype = he -> h_addrtype; + addrs -> addresses [i].addrlen = he -> h_length; + memcpy (addrs -> addresses [i].address, + he -> h_addr_list [i], + (unsigned)he -> h_length); + addrs -> addresses [i].port = port; + } + } else { + status = omapi_addr_list_new (&addrs, 1, MDL); + if (status != ISC_R_SUCCESS) + return status; + addrs -> addresses [0].addrtype = AF_INET; + addrs -> addresses [0].addrlen = sizeof foo; + memcpy (addrs -> addresses [0].address, &foo, sizeof foo); + addrs -> addresses [0].port = port; + hix = 1; + } + status = omapi_connect_list (c, addrs, (omapi_addr_t *)0); + omapi_addr_list_dereference (&addrs, MDL); + return status; +} + +isc_result_t omapi_connect_list (omapi_object_t *c, + omapi_addr_list_t *remote_addrs, + omapi_addr_t *local_addr) +{ + isc_result_t status; + omapi_connection_object_t *obj; + int flag; + struct sockaddr_in local_sin; +#if defined (TRACING) + trace_addr_t *addrs; + u_int16_t naddrs; +#endif + + obj = (omapi_connection_object_t *)0; + status = omapi_connection_allocate (&obj, MDL); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_object_reference (&c -> outer, (omapi_object_t *)obj, + MDL); + if (status != ISC_R_SUCCESS) { + omapi_connection_dereference (&obj, MDL); + return status; + } + status = omapi_object_reference (&obj -> inner, c, MDL); + if (status != ISC_R_SUCCESS) { + omapi_connection_dereference (&obj, MDL); + return status; + } + + /* Store the address list on the object. */ + omapi_addr_list_reference (&obj -> connect_list, remote_addrs, MDL); + obj -> cptr = 0; + obj -> state = omapi_connection_unconnected; + +#if defined (TRACING) + /* If we're playing back, don't actually try to connect - just leave + the object available for a subsequent connect or disconnect. */ + if (!trace_playback ()) { +#endif + /* Create a socket on which to communicate. */ + obj -> socket = + socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (obj -> socket < 0) { + omapi_connection_dereference (&obj, MDL); + if (errno == EMFILE || errno == ENFILE + || errno == ENOBUFS) + return ISC_R_NORESOURCES; + return ISC_R_UNEXPECTED; + } + + /* Set up the local address, if any. */ + if (local_addr) { + /* Only do TCPv4 so far. */ + if (local_addr -> addrtype != AF_INET) { + omapi_connection_dereference (&obj, MDL); + return ISC_R_INVALIDARG; + } + local_sin.sin_port = htons (local_addr -> port); + memcpy (&local_sin.sin_addr, + local_addr -> address, + local_addr -> addrlen); +#if defined (HAVE_SA_LEN) + local_sin.sin_len = sizeof local_addr; +#endif + local_sin.sin_family = AF_INET; + memset (&local_sin.sin_zero, 0, + sizeof local_sin.sin_zero); + + if (bind (obj -> socket, (struct sockaddr *)&local_sin, + sizeof local_sin) < 0) { + omapi_object_dereference ((omapi_object_t **) + &obj, MDL); + if (errno == EADDRINUSE) + return ISC_R_ADDRINUSE; + if (errno == EADDRNOTAVAIL) + return ISC_R_ADDRNOTAVAIL; + if (errno == EACCES) + return ISC_R_NOPERM; + return ISC_R_UNEXPECTED; + } + obj -> local_addr = local_sin; + } + +#if defined (HAVE_SETFD) + if (fcntl (obj -> socket, F_SETFD, 1) < 0) { + close (obj -> socket); + omapi_connection_dereference (&obj, MDL); + return ISC_R_UNEXPECTED; + } +#endif + + /* Set the SO_REUSEADDR flag (this should not fail). */ + flag = 1; + if (setsockopt (obj -> socket, SOL_SOCKET, SO_REUSEADDR, + (char *)&flag, sizeof flag) < 0) { + omapi_connection_dereference (&obj, MDL); + return ISC_R_UNEXPECTED; + } + + /* Set the file to nonblocking mode. */ + if (fcntl (obj -> socket, F_SETFL, O_NONBLOCK) < 0) { + omapi_connection_dereference (&obj, MDL); + return ISC_R_UNEXPECTED; + } + + status = (omapi_register_io_object + ((omapi_object_t *)obj, + 0, omapi_connection_writefd, + 0, omapi_connection_connect, + omapi_connection_reaper)); + if (status != ISC_R_SUCCESS) + goto out; + status = omapi_connection_connect_internal ((omapi_object_t *) + obj); +#if defined (TRACING) + } + omapi_connection_register (obj, MDL); +#endif + + out: + omapi_connection_dereference (&obj, MDL); + return status; +} + +#if defined (TRACING) +omapi_array_t *omapi_connections; + +OMAPI_ARRAY_TYPE(omapi_connection, omapi_connection_object_t) + +void omapi_connection_trace_setup (void) { + trace_connect = trace_type_register ("connect", (void *)0, + trace_connect_input, + trace_connect_stop, MDL); + trace_disconnect = trace_type_register ("disconnect", (void *)0, + trace_disconnect_input, + trace_disconnect_stop, MDL); +} + +void omapi_connection_register (omapi_connection_object_t *obj, + const char *file, int line) +{ + isc_result_t status; + trace_iov_t iov [6]; + int iov_count = 0; + int32_t connect_index, listener_index; + static int32_t index; + + if (!omapi_connections) { + status = omapi_connection_array_allocate (&omapi_connections, + file, line); + if (status != ISC_R_SUCCESS) + return; + } + + status = omapi_connection_array_extend (omapi_connections, obj, + (int *)0, file, line); + if (status != ISC_R_SUCCESS) { + obj -> index = -1; + return; + } + +#if defined (TRACING) + if (trace_record ()) { + /* Connection registration packet: + + int32_t index + int32_t listener_index [-1 means no listener] + u_int16_t remote_port + u_int16_t local_port + u_int32_t remote_addr + u_int32_t local_addr */ + + connect_index = htonl (index); + index++; + if (obj -> listener) + listener_index = htonl (obj -> listener -> index); + else + listener_index = htonl (-1); + iov [iov_count].buf = (char *)&connect_index; + iov [iov_count++].len = sizeof connect_index; + iov [iov_count].buf = (char *)&listener_index; + iov [iov_count++].len = sizeof listener_index; + iov [iov_count].buf = (char *)&obj -> remote_addr.sin_port; + iov [iov_count++].len = sizeof obj -> remote_addr.sin_port; + iov [iov_count].buf = (char *)&obj -> local_addr.sin_port; + iov [iov_count++].len = sizeof obj -> local_addr.sin_port; + iov [iov_count].buf = (char *)&obj -> remote_addr.sin_addr; + iov [iov_count++].len = sizeof obj -> remote_addr.sin_addr; + iov [iov_count].buf = (char *)&obj -> local_addr.sin_addr; + iov [iov_count++].len = sizeof obj -> local_addr.sin_addr; + + status = trace_write_packet_iov (trace_connect, + iov_count, iov, file, line); + } +#endif +} + +static void trace_connect_input (trace_type_t *ttype, + unsigned length, char *buf) +{ + struct sockaddr_in remote, local; + int32_t connect_index, listener_index; + char *s = buf; + omapi_connection_object_t *obj; + isc_result_t status; + int i; + + if (length != ((sizeof connect_index) + + (sizeof remote.sin_port) + + (sizeof remote.sin_addr)) * 2) { + log_error ("Trace connect: invalid length %d", length); + return; + } + + memset (&remote, 0, sizeof remote); + memset (&local, 0, sizeof local); + memcpy (&connect_index, s, sizeof connect_index); + s += sizeof connect_index; + memcpy (&listener_index, s, sizeof listener_index); + s += sizeof listener_index; + memcpy (&remote.sin_port, s, sizeof remote.sin_port); + s += sizeof remote.sin_port; + memcpy (&local.sin_port, s, sizeof local.sin_port); + s += sizeof local.sin_port; + memcpy (&remote.sin_addr, s, sizeof remote.sin_addr); + s += sizeof remote.sin_addr; + memcpy (&local.sin_addr, s, sizeof local.sin_addr); + s += sizeof local.sin_addr; + + connect_index = ntohl (connect_index); + listener_index = ntohl (listener_index); + + /* If this was a connect to a listener, then we just slap together + a new connection. */ + if (listener_index != -1) { + omapi_listener_object_t *listener; + listener = (omapi_listener_object_t *)0; + omapi_array_foreach_begin (trace_listeners, + omapi_listener_object_t, lp) { + if (lp -> address.sin_port == local.sin_port) { + omapi_listener_reference (&listener, lp, MDL); + omapi_listener_dereference (&lp, MDL); + break; + } + } omapi_array_foreach_end (trace_listeners, + omapi_listener_object_t, lp); + if (!listener) { + log_error ("%s%ld, addr %s, port %d", + "Spurious traced listener connect - index ", + (long int)listener_index, + inet_ntoa (local.sin_addr), + ntohs (local.sin_port)); + return; + } + obj = (omapi_connection_object_t *)0; + status = omapi_listener_connect (&obj, listener, -1, &remote); + if (status != ISC_R_SUCCESS) { + log_error ("traced listener connect: %s", + isc_result_totext (status)); + } + if (obj) + omapi_connection_dereference (&obj, MDL); + omapi_listener_dereference (&listener, MDL); + return; + } + + /* Find the matching connect object, if there is one. */ + omapi_array_foreach_begin (omapi_connections, + omapi_connection_object_t, lp) { + for (i = 0; (lp -> connect_list && + i < lp -> connect_list -> count); i++) { + if (!memcmp (&remote.sin_addr, + &lp -> connect_list -> addresses [i].address, + sizeof remote.sin_addr) && + (ntohs (remote.sin_port) == + lp -> connect_list -> addresses [i].port)) + lp -> state = omapi_connection_connected; + lp -> remote_addr = remote; + lp -> remote_addr.sin_family = AF_INET; +#if defined (HAVE_SIN_LEN) + lp -> remote_addr.sin_len = sizeof remote; +#endif + omapi_addr_list_dereference (&lp -> connect_list, MDL); + lp -> index = connect_index; + status = omapi_signal_in ((omapi_object_t *)lp, + "connect"); + omapi_connection_dereference (&lp, MDL); + return; + } + } omapi_array_foreach_end (omapi_connections, + omapi_connection_object_t, lp); + + log_error ("Spurious traced connect - index %ld, addr %s, port %d", + (long int)connect_index, inet_ntoa (remote.sin_addr), + ntohs (remote.sin_port)); + return; +} + +static void trace_connect_stop (trace_type_t *ttype) { } + +static void trace_disconnect_input (trace_type_t *ttype, + unsigned length, char *buf) +{ + int32_t *index; + if (length != sizeof *index) { + log_error ("trace disconnect: wrong length %d", length); + return; + } + + index = (int32_t *)buf; + + omapi_array_foreach_begin (omapi_connections, + omapi_connection_object_t, lp) { + if (lp -> index == ntohl (*index)) { + omapi_disconnect ((omapi_object_t *)lp, 1); + omapi_connection_dereference (&lp, MDL); + return; + } + } omapi_array_foreach_end (omapi_connections, + omapi_connection_object_t, lp); + + log_error ("trace disconnect: no connection matching index %ld", + (long int)ntohl (*index)); +} + +static void trace_disconnect_stop (trace_type_t *ttype) { } +#endif + +/* Disconnect a connection object from the remote end. If force is nonzero, + close the connection immediately. Otherwise, shut down the receiving end + but allow any unsent data to be sent before actually closing the socket. */ + +isc_result_t omapi_disconnect (omapi_object_t *h, + int force) +{ + omapi_connection_object_t *c; + isc_result_t status; + +#ifdef DEBUG_PROTOCOL + log_debug ("omapi_disconnect(%s)", force ? "force" : ""); +#endif + + c = (omapi_connection_object_t *)h; + if (c -> type != omapi_type_connection) + return ISC_R_INVALIDARG; + +#if defined (TRACING) + if (trace_record ()) { + int32_t index; + + index = htonl (c -> index); + status = trace_write_packet (trace_disconnect, + sizeof index, (char *)&index, + MDL); + if (status != ISC_R_SUCCESS) { + trace_stop (); + log_error ("trace_write_packet: %s", + isc_result_totext (status)); + } + } + if (!trace_playback ()) { +#endif + if (!force) { + /* If we're already disconnecting, we don't have to do + anything. */ + if (c -> state == omapi_connection_disconnecting) + return ISC_R_SUCCESS; + + /* Try to shut down the socket - this sends a FIN to + the remote end, so that it won't send us any more + data. If the shutdown succeeds, and we still + have bytes left to write, defer closing the socket + until that's done. */ + if (!shutdown (c -> socket, SHUT_RD)) { + if (c -> out_bytes > 0) { + c -> state = + omapi_connection_disconnecting; + return ISC_R_SUCCESS; + } + } + } + close (c -> socket); +#if defined (TRACING) + } +#endif + c -> state = omapi_connection_closed; + + /* Disconnect from I/O object, if any. */ + if (h -> outer) { + if (h -> outer -> inner) + omapi_object_dereference (&h -> outer -> inner, MDL); + omapi_object_dereference (&h -> outer, MDL); + } + + /* If whatever created us registered a signal handler, send it + a disconnect signal. */ + omapi_signal (h, "disconnect", h); + return ISC_R_SUCCESS; +} + +isc_result_t omapi_connection_require (omapi_object_t *h, unsigned bytes) +{ + omapi_connection_object_t *c; + + if (h -> type != omapi_type_connection) + return ISC_R_INVALIDARG; + c = (omapi_connection_object_t *)h; + + c -> bytes_needed = bytes; + if (c -> bytes_needed <= c -> in_bytes) { + return ISC_R_SUCCESS; + } + return ISC_R_NOTYET; +} + +/* Return the socket on which the dispatcher should wait for readiness + to read, for a connection object. If we already have more bytes than + we need to do the next thing, and we have at least a single full input + buffer, then don't indicate that we're ready to read. */ +int omapi_connection_readfd (omapi_object_t *h) +{ + omapi_connection_object_t *c; + if (h -> type != omapi_type_connection) + return -1; + c = (omapi_connection_object_t *)h; + if (c -> state != omapi_connection_connected) + return -1; + if (c -> in_bytes >= OMAPI_BUF_SIZE - 1 && + c -> in_bytes > c -> bytes_needed) + return -1; + return c -> socket; +} + +/* Return the socket on which the dispatcher should wait for readiness + to write, for a connection object. If there are no bytes buffered + for writing, then don't indicate that we're ready to write. */ +int omapi_connection_writefd (omapi_object_t *h) +{ + omapi_connection_object_t *c; + if (h -> type != omapi_type_connection) + return -1; + c = (omapi_connection_object_t *)h; + if (c -> state == omapi_connection_connecting) + return c -> socket; + if (c -> out_bytes) + return c -> socket; + else + return -1; +} + +isc_result_t omapi_connection_connect (omapi_object_t *h) +{ + isc_result_t status; + + status = omapi_connection_connect_internal (h); + if (status != ISC_R_SUCCESS) + omapi_signal (h, "status", status); + return ISC_R_SUCCESS; +} + +static isc_result_t omapi_connection_connect_internal (omapi_object_t *h) +{ + int error; + omapi_connection_object_t *c; + SOCKLEN_T sl; + isc_result_t status; + + if (h -> type != omapi_type_connection) + return ISC_R_INVALIDARG; + c = (omapi_connection_object_t *)h; + + if (c -> state == omapi_connection_connecting) { + sl = sizeof error; + if (getsockopt (c -> socket, SOL_SOCKET, SO_ERROR, + (char *)&error, &sl) < 0) { + omapi_disconnect (h, 1); + return ISC_R_SUCCESS; + } + if (!error) + c -> state = omapi_connection_connected; + } + if (c -> state == omapi_connection_connecting || + c -> state == omapi_connection_unconnected) { + if (c -> cptr >= c -> connect_list -> count) { + switch (error) { + case ECONNREFUSED: + status = ISC_R_CONNREFUSED; + break; + case ENETUNREACH: + status = ISC_R_NETUNREACH; + break; + default: + status = uerr2isc (error); + break; + } + omapi_disconnect (h, 1); + return status; + } + + if (c -> connect_list -> addresses [c -> cptr].addrtype != + AF_INET) { + omapi_disconnect (h, 1); + return ISC_R_INVALIDARG; + } + + memcpy (&c -> remote_addr.sin_addr, + &c -> connect_list -> addresses [c -> cptr].address, + sizeof c -> remote_addr.sin_addr); + c -> remote_addr.sin_family = AF_INET; + c -> remote_addr.sin_port = + htons (c -> connect_list -> addresses [c -> cptr].port); +#if defined (HAVE_SA_LEN) + c -> remote_addr.sin_len = sizeof c -> remote_addr; +#endif + memset (&c -> remote_addr.sin_zero, 0, + sizeof c -> remote_addr.sin_zero); + ++c -> cptr; + + error = connect (c -> socket, + (struct sockaddr *)&c -> remote_addr, + sizeof c -> remote_addr); + if (error < 0) { + error = errno; + if (error != EINPROGRESS) { + omapi_disconnect (h, 1); + switch (error) { + case ECONNREFUSED: + status = ISC_R_CONNREFUSED; + break; + case ENETUNREACH: + status = ISC_R_NETUNREACH; + break; + default: + status = uerr2isc (error); + break; + } + return status; + } + c -> state = omapi_connection_connecting; + return ISC_R_INCOMPLETE; + } + c -> state = omapi_connection_connected; + } + + /* I don't know why this would fail, so I'm tempted not to test + the return value. */ + sl = sizeof (c -> local_addr); + if (getsockname (c -> socket, + (struct sockaddr *)&c -> local_addr, &sl) < 0) { + } + + /* Disconnect from I/O object, if any. */ + if (h -> outer) + omapi_unregister_io_object (h); + + status = omapi_register_io_object (h, + omapi_connection_readfd, + omapi_connection_writefd, + omapi_connection_reader, + omapi_connection_writer, + omapi_connection_reaper); + + if (status != ISC_R_SUCCESS) { + omapi_disconnect (h, 1); + return status; + } + + omapi_signal_in (h, "connect"); + omapi_addr_list_dereference (&c -> connect_list, MDL); + return ISC_R_SUCCESS; +} + +/* Reaper function for connection - if the connection is completely closed, + reap it. If it's in the disconnecting state, there were bytes left + to write when the user closed it, so if there are now no bytes left to + write, we can close it. */ +isc_result_t omapi_connection_reaper (omapi_object_t *h) +{ + omapi_connection_object_t *c; + + if (h -> type != omapi_type_connection) + return ISC_R_INVALIDARG; + + c = (omapi_connection_object_t *)h; + if (c -> state == omapi_connection_disconnecting && + c -> out_bytes == 0) { +#ifdef DEBUG_PROTOCOL + log_debug ("omapi_connection_reaper(): disconnect"); +#endif + omapi_disconnect (h, 1); + } + if (c -> state == omapi_connection_closed) { +#ifdef DEBUG_PROTOCOL + log_debug ("omapi_connection_reaper(): closed"); +#endif + return ISC_R_NOTCONNECTED; + } + return ISC_R_SUCCESS; +} + +static isc_result_t make_dst_key (DST_KEY **dst_key, omapi_object_t *a) { + omapi_value_t *name = (omapi_value_t *)0; + omapi_value_t *algorithm = (omapi_value_t *)0; + omapi_value_t *key = (omapi_value_t *)0; + int algorithm_id; + char *name_str; + isc_result_t status = ISC_R_SUCCESS; + + if (status == ISC_R_SUCCESS) + status = omapi_get_value_str + (a, (omapi_object_t *)0, "name", &name); + + if (status == ISC_R_SUCCESS) + status = omapi_get_value_str + (a, (omapi_object_t *)0, "algorithm", &algorithm); + + if (status == ISC_R_SUCCESS) + status = omapi_get_value_str + (a, (omapi_object_t *)0, "key", &key); + + if (status == ISC_R_SUCCESS) { + if ((algorithm -> value -> type == omapi_datatype_data || + algorithm -> value -> type == omapi_datatype_string) && + strncasecmp ((char *)algorithm -> value -> u.buffer.value, + NS_TSIG_ALG_HMAC_MD5 ".", + algorithm -> value -> u.buffer.len) == 0) { + algorithm_id = KEY_HMAC_MD5; + } else { + status = ISC_R_INVALIDARG; + } + } + + if (status == ISC_R_SUCCESS) { + name_str = dmalloc (name -> value -> u.buffer.len + 1, MDL); + if (!name_str) + status = ISC_R_NOMEMORY; + } + + if (status == ISC_R_SUCCESS) { + memcpy (name_str, + name -> value -> u.buffer.value, + name -> value -> u.buffer.len); + name_str [name -> value -> u.buffer.len] = 0; + + *dst_key = dst_buffer_to_key (name_str, algorithm_id, 0, 0, + key -> value -> u.buffer.value, + key -> value -> u.buffer.len); + if (!*dst_key) + status = ISC_R_NOMEMORY; + } + + if (name_str) + dfree (name_str, MDL); + if (key) + omapi_value_dereference (&key, MDL); + if (algorithm) + omapi_value_dereference (&algorithm, MDL); + if (name) + omapi_value_dereference (&name, MDL); + + return status; +} + +isc_result_t omapi_connection_sign_data (int mode, + DST_KEY *key, + void **context, + const unsigned char *data, + const unsigned len, + omapi_typed_data_t **result) +{ + omapi_typed_data_t *td = (omapi_typed_data_t *)0; + isc_result_t status; + int r; + + if (mode & SIG_MODE_FINAL) { + status = omapi_typed_data_new (MDL, &td, + omapi_datatype_data, + dst_sig_size (key)); + if (status != ISC_R_SUCCESS) + return status; + } + + r = dst_sign_data (mode, key, context, data, len, + td ? td -> u.buffer.value : (u_char *)0, + td ? td -> u.buffer.len : 0); + + /* dst_sign_data() really should do this for us, shouldn't it? */ + if (mode & SIG_MODE_FINAL) + *context = (void *)0; + + if (r < 0) { + if (td) + omapi_typed_data_dereference (&td, MDL); + return ISC_R_INVALIDKEY; + } + + if (result && td) { + omapi_typed_data_reference (result, td, MDL); + } + + if (td) + omapi_typed_data_dereference (&td, MDL); + + return ISC_R_SUCCESS; +} + +isc_result_t omapi_connection_output_auth_length (omapi_object_t *h, + unsigned *l) +{ + omapi_connection_object_t *c; + + if (h -> type != omapi_type_connection) + return ISC_R_INVALIDARG; + c = (omapi_connection_object_t *)h; + + if (!c -> out_key) + return ISC_R_NOTFOUND; + + *l = dst_sig_size (c -> out_key); + return ISC_R_SUCCESS; +} + +isc_result_t omapi_connection_set_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_typed_data_t *value) +{ + omapi_connection_object_t *c; + isc_result_t status; + + if (h -> type != omapi_type_connection) + return ISC_R_INVALIDARG; + c = (omapi_connection_object_t *)h; + + if (omapi_ds_strcmp (name, "input-authenticator") == 0) { + if (value && value -> type != omapi_datatype_object) + return ISC_R_INVALIDARG; + + if (c -> in_context) { + omapi_connection_sign_data (SIG_MODE_FINAL, + c -> in_key, + &c -> in_context, + 0, 0, + (omapi_typed_data_t **) 0); + } + + if (c -> in_key) { + dst_free_key (c -> in_key); + c -> in_key = (DST_KEY *)0; + } + + if (value) { + status = make_dst_key (&c -> in_key, + value -> u.object); + if (status != ISC_R_SUCCESS) + return status; + } + + return ISC_R_SUCCESS; + } + else if (omapi_ds_strcmp (name, "output-authenticator") == 0) { + if (value && value -> type != omapi_datatype_object) + return ISC_R_INVALIDARG; + + if (c -> out_context) { + omapi_connection_sign_data (SIG_MODE_FINAL, + c -> out_key, + &c -> out_context, + 0, 0, + (omapi_typed_data_t **) 0); + } + + if (c -> out_key) { + dst_free_key (c -> out_key); + c -> out_key = (DST_KEY *)0; + } + + if (value) { + status = make_dst_key (&c -> out_key, + value -> u.object); + if (status != ISC_R_SUCCESS) + return status; + } + + return ISC_R_SUCCESS; + } + + if (h -> inner && h -> inner -> type -> set_value) + return (*(h -> inner -> type -> set_value)) + (h -> inner, id, name, value); + return ISC_R_NOTFOUND; +} + +isc_result_t omapi_connection_get_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_value_t **value) +{ + omapi_connection_object_t *c; + omapi_typed_data_t *td = (omapi_typed_data_t *)0; + isc_result_t status; + + if (h -> type != omapi_type_connection) + return ISC_R_INVALIDARG; + c = (omapi_connection_object_t *)h; + + if (omapi_ds_strcmp (name, "input-signature") == 0) { + if (!c -> in_key || !c -> in_context) + return ISC_R_NOTFOUND; + + status = omapi_connection_sign_data (SIG_MODE_FINAL, + c -> in_key, + &c -> in_context, + 0, 0, &td); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_make_value (value, name, td, MDL); + omapi_typed_data_dereference (&td, MDL); + return status; + + } else if (omapi_ds_strcmp (name, "input-signature-size") == 0) { + if (!c -> in_key) + return ISC_R_NOTFOUND; + + return omapi_make_int_value (value, name, + dst_sig_size (c -> in_key), MDL); + + } else if (omapi_ds_strcmp (name, "output-signature") == 0) { + if (!c -> out_key || !c -> out_context) + return ISC_R_NOTFOUND; + + status = omapi_connection_sign_data (SIG_MODE_FINAL, + c -> out_key, + &c -> out_context, + 0, 0, &td); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_make_value (value, name, td, MDL); + omapi_typed_data_dereference (&td, MDL); + return status; + + } else if (omapi_ds_strcmp (name, "output-signature-size") == 0) { + if (!c -> out_key) + return ISC_R_NOTFOUND; + + return omapi_make_int_value (value, name, + dst_sig_size (c -> out_key), MDL); + } + + if (h -> inner && h -> inner -> type -> get_value) + return (*(h -> inner -> type -> get_value)) + (h -> inner, id, name, value); + return ISC_R_NOTFOUND; +} + +isc_result_t omapi_connection_destroy (omapi_object_t *h, + const char *file, int line) +{ + omapi_connection_object_t *c; + +#ifdef DEBUG_PROTOCOL + log_debug ("omapi_connection_destroy()"); +#endif + + if (h -> type != omapi_type_connection) + return ISC_R_UNEXPECTED; + c = (omapi_connection_object_t *)(h); + if (c -> state == omapi_connection_connected) + omapi_disconnect (h, 1); + if (c -> listener) + omapi_listener_dereference (&c -> listener, file, line); + if (c -> connect_list) + omapi_addr_list_dereference (&c -> connect_list, file, line); + return ISC_R_SUCCESS; +} + +isc_result_t omapi_connection_signal_handler (omapi_object_t *h, + const char *name, va_list ap) +{ + if (h -> type != omapi_type_connection) + return ISC_R_INVALIDARG; + +#ifdef DEBUG_PROTOCOL + log_debug ("omapi_connection_signal_handler(%s)", name); +#endif + + if (h -> inner && h -> inner -> type -> signal_handler) + return (*(h -> inner -> type -> signal_handler)) (h -> inner, + name, ap); + return ISC_R_NOTFOUND; +} + +/* Write all the published values associated with the object through the + specified connection. */ + +isc_result_t omapi_connection_stuff_values (omapi_object_t *c, + omapi_object_t *id, + omapi_object_t *m) +{ + int i; + + if (m -> type != omapi_type_connection) + return ISC_R_INVALIDARG; + + if (m -> inner && m -> inner -> type -> stuff_values) + return (*(m -> inner -> type -> stuff_values)) (c, id, + m -> inner); + return ISC_R_SUCCESS; +} diff --git a/contrib/isc-dhcp/omapip/convert.c b/contrib/isc-dhcp/omapip/convert.c new file mode 100644 index 0000000..83d5fc3 --- /dev/null +++ b/contrib/isc-dhcp/omapip/convert.c @@ -0,0 +1,193 @@ +/* convert.c + + Safe copying of option values into and out of the option buffer, which + can't be assumed to be aligned. */ + +/* + * Copyright (c) 1996-1999 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. + */ + +#ifndef lint +static char copyright[] = +"$Id: convert.c,v 1.1 2000/08/01 22:34:36 neild Exp $ Copyright (c) 1996-1999 The Internet Software Consortium. All rights reserved.\n"; +#endif /* not lint */ + +#include <omapip/omapip_p.h> + +u_int32_t getULong (buf) + const unsigned char *buf; +{ + unsigned long ibuf; + + memcpy (&ibuf, buf, sizeof (u_int32_t)); + return ntohl (ibuf); +} + +int32_t getLong (buf) + const unsigned char *buf; +{ + long ibuf; + + memcpy (&ibuf, buf, sizeof (int32_t)); + return ntohl (ibuf); +} + +u_int32_t getUShort (buf) + const unsigned char *buf; +{ + unsigned short ibuf; + + memcpy (&ibuf, buf, sizeof (u_int16_t)); + return ntohs (ibuf); +} + +int32_t getShort (buf) + const unsigned char *buf; +{ + short ibuf; + + memcpy (&ibuf, buf, sizeof (int16_t)); + return ntohs (ibuf); +} + +void putULong (obuf, val) + unsigned char *obuf; + u_int32_t val; +{ + u_int32_t tmp = htonl (val); + memcpy (obuf, &tmp, sizeof tmp); +} + +void putLong (obuf, val) + unsigned char *obuf; + int32_t val; +{ + int32_t tmp = htonl (val); + memcpy (obuf, &tmp, sizeof tmp); +} + +void putUShort (obuf, val) + unsigned char *obuf; + u_int32_t val; +{ + u_int16_t tmp = htons (val); + memcpy (obuf, &tmp, sizeof tmp); +} + +void putShort (obuf, val) + unsigned char *obuf; + int32_t val; +{ + int16_t tmp = htons (val); + memcpy (obuf, &tmp, sizeof tmp); +} + +void putUChar (obuf, val) + unsigned char *obuf; + u_int32_t val; +{ + *obuf = val; +} + +u_int32_t getUChar (obuf) + const unsigned char *obuf; +{ + return obuf [0]; +} + +int converted_length (buf, base, width) + const unsigned char *buf; + unsigned int base; + unsigned int width; +{ + u_int32_t number; + u_int32_t column; + int power = 1; + u_int32_t newcolumn = base; + + if (base > 16) + return 0; + + if (width == 1) + number = getUChar (buf); + else if (width == 2) + number = getUShort (buf); + else if (width == 4) + number = getULong (buf); + + do { + column = newcolumn; + + if (number < column) + return power; + power++; + newcolumn = column * base; + /* If we wrap around, it must be the next power of two up. */ + } while (newcolumn > column); + + return power; +} + +int binary_to_ascii (outbuf, inbuf, base, width) + unsigned char *outbuf; + const unsigned char *inbuf; + unsigned int base; + unsigned int width; +{ + u_int32_t number; + static char h2a [] = "0123456789abcdef"; + int power = converted_length (inbuf, base, width); + int i, j; + + if (base > 16) + return 0; + + if (width == 1) + number = getUChar (inbuf); + else if (width == 2) + number = getUShort (inbuf); + else if (width == 4) + number = getULong (inbuf); + + for (i = power - 1 ; i >= 0; i--) { + outbuf [i] = h2a [number % base]; + number /= base; + } + + return power; +} diff --git a/contrib/isc-dhcp/omapip/dispatch.c b/contrib/isc-dhcp/omapip/dispatch.c new file mode 100644 index 0000000..02bab7c --- /dev/null +++ b/contrib/isc-dhcp/omapip/dispatch.c @@ -0,0 +1,604 @@ +/* dispatch.c + + I/O dispatcher. */ + +/* + * Copyright (c) 1999-2000 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. + */ + +#include <omapip/omapip_p.h> + +static omapi_io_object_t omapi_io_states; +u_int32_t cur_time; + +OMAPI_OBJECT_ALLOC (omapi_io, + omapi_io_object_t, omapi_type_io_object) +OMAPI_OBJECT_ALLOC (omapi_waiter, + omapi_waiter_object_t, omapi_type_waiter) + +/* Register an I/O handle so that we can do asynchronous I/O on it. */ + +isc_result_t omapi_register_io_object (omapi_object_t *h, + int (*readfd) (omapi_object_t *), + int (*writefd) (omapi_object_t *), + isc_result_t (*reader) + (omapi_object_t *), + isc_result_t (*writer) + (omapi_object_t *), + isc_result_t (*reaper) + (omapi_object_t *)) +{ + isc_result_t status; + omapi_io_object_t *obj, *p; + + /* omapi_io_states is a static object. If its reference count + is zero, this is the first I/O handle to be registered, so + we need to initialize it. Because there is no inner or outer + pointer on this object, and we're setting its refcnt to 1, it + will never be freed. */ + if (!omapi_io_states.refcnt) { + omapi_io_states.refcnt = 1; + omapi_io_states.type = omapi_type_io_object; + } + + obj = (omapi_io_object_t *)0; + status = omapi_io_allocate (&obj, MDL); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_object_reference (&obj -> inner, h, MDL); + if (status != ISC_R_SUCCESS) { + omapi_io_dereference (&obj, MDL); + return status; + } + + status = omapi_object_reference (&h -> outer, + (omapi_object_t *)obj, MDL); + if (status != ISC_R_SUCCESS) { + omapi_io_dereference (&obj, MDL); + return status; + } + + /* Find the last I/O state, if there are any. */ + for (p = omapi_io_states.next; + p && p -> next; p = p -> next) + ; + if (p) + omapi_io_reference (&p -> next, obj, MDL); + else + omapi_io_reference (&omapi_io_states.next, obj, MDL); + + obj -> readfd = readfd; + obj -> writefd = writefd; + obj -> reader = reader; + obj -> writer = writer; + obj -> reaper = reaper; + return ISC_R_SUCCESS; +} + +isc_result_t omapi_unregister_io_object (omapi_object_t *h) +{ + omapi_io_object_t *p, *obj, *last, *ph; + + if (!h -> outer || h -> outer -> type != omapi_type_io_object) + return ISC_R_INVALIDARG; + obj = (omapi_io_object_t *)h -> outer; + ph = (omapi_io_object_t *)0; + omapi_io_reference (&ph, obj, MDL); + + /* remove from the list of I/O states */ + last = &omapi_io_states; + for (p = omapi_io_states.next; p; p = p -> next) { + if (p == obj) { + omapi_io_dereference (&last -> next, MDL); + omapi_io_reference (&last -> next, p -> next, MDL); + break; + } + last = p; + } + if (obj -> next) + omapi_io_dereference (&obj -> next, MDL); + + if (obj -> outer) { + if (obj -> outer -> inner == (omapi_object_t *)obj) + omapi_object_dereference (&obj -> outer -> inner, + MDL); + omapi_object_dereference (&obj -> outer, MDL); + } + omapi_object_dereference (&obj -> inner, MDL); + omapi_object_dereference (&h -> outer, MDL); + omapi_io_dereference (&ph, MDL); + return ISC_R_SUCCESS; +} + +isc_result_t omapi_dispatch (struct timeval *t) +{ + return omapi_wait_for_completion ((omapi_object_t *)&omapi_io_states, + t); +} + +isc_result_t omapi_wait_for_completion (omapi_object_t *object, + struct timeval *t) +{ + isc_result_t status; + omapi_waiter_object_t *waiter; + omapi_object_t *inner; + + if (object) { + waiter = (omapi_waiter_object_t *)0; + status = omapi_waiter_allocate (&waiter, MDL); + if (status != ISC_R_SUCCESS) + return status; + + /* Paste the waiter object onto the inner object we're + waiting on. */ + for (inner = object; inner -> inner; inner = inner -> inner) + ; + + status = omapi_object_reference (&waiter -> outer, inner, MDL); + if (status != ISC_R_SUCCESS) { + omapi_waiter_dereference (&waiter, MDL); + return status; + } + + status = omapi_object_reference (&inner -> inner, + (omapi_object_t *)waiter, + MDL); + if (status != ISC_R_SUCCESS) { + omapi_waiter_dereference (&waiter, MDL); + return status; + } + } else + waiter = (omapi_waiter_object_t *)0; + + do { + status = omapi_one_dispatch ((omapi_object_t *)waiter, t); + if (status != ISC_R_SUCCESS) + return status; + } while (!waiter || !waiter -> ready); + + if (waiter -> outer) { + if (waiter -> outer -> inner) { + omapi_object_dereference (&waiter -> outer -> inner, + MDL); + if (waiter -> inner) + omapi_object_reference + (&waiter -> outer -> inner, + waiter -> inner, MDL); + } + omapi_object_dereference (&waiter -> outer, MDL); + } + if (waiter -> inner) + omapi_object_dereference (&waiter -> inner, MDL); + + status = waiter -> waitstatus; + omapi_waiter_dereference (&waiter, MDL); + return status; +} + +isc_result_t omapi_one_dispatch (omapi_object_t *wo, + struct timeval *t) +{ + fd_set r, w, x; + int max = 0; + int count; + int desc; + struct timeval now, to; + omapi_io_object_t *io, *prev; + isc_result_t status; + omapi_waiter_object_t *waiter; + omapi_object_t *tmp = (omapi_object_t *)0; + + if (!wo || wo -> type != omapi_type_waiter) + waiter = (omapi_waiter_object_t *)0; + else + waiter = (omapi_waiter_object_t *)wo; + + FD_ZERO (&x); + + /* First, see if the timeout has expired, and if so return. */ + if (t) { + gettimeofday (&now, (struct timezone *)0); + cur_time = now.tv_sec; + if (now.tv_sec > t -> tv_sec || + (now.tv_sec == t -> tv_sec && now.tv_usec >= t -> tv_usec)) + return ISC_R_TIMEDOUT; + + /* We didn't time out, so figure out how long until + we do. */ + to.tv_sec = t -> tv_sec - now.tv_sec; + to.tv_usec = t -> tv_usec - now.tv_usec; + if (to.tv_usec < 0) { + to.tv_usec += 1000000; + to.tv_sec--; + } + + /* It is possible for the timeout to get set larger than + the largest time select() is willing to accept. + Restricting the timeout to a maximum of one day should + work around this. -DPN. (Ref: Bug #416) */ + if (to.tv_sec > (60 * 60 * 24)) + to.tv_sec = 60 * 60 * 24; + } + + /* If the object we're waiting on has reached completion, + return now. */ + if (waiter && waiter -> ready) + return ISC_R_SUCCESS; + + again: + /* If we have no I/O state, we can't proceed. */ + if (!(io = omapi_io_states.next)) + return ISC_R_NOMORE; + + /* Set up the read and write masks. */ + FD_ZERO (&r); + FD_ZERO (&w); + + for (; io; io = io -> next) { + /* Check for a read socket. If we shouldn't be + trying to read for this I/O object, either there + won't be a readfd function, or it'll return -1. */ + if (io -> readfd && io -> inner && + (desc = (*(io -> readfd)) (io -> inner)) >= 0) { + FD_SET (desc, &r); + if (desc > max) + max = desc; + } + + /* Same deal for write fdets. */ + if (io -> writefd && io -> inner && + (desc = (*(io -> writefd)) (io -> inner)) >= 0) { + FD_SET (desc, &w); + if (desc > max) + max = desc; + } + } + + /* Wait for a packet or a timeout... XXX */ +#if 0 +#if defined (__linux__) +#define fds_bits __fds_bits +#endif + log_error ("dispatch: %d %lx %lx", max, + (unsigned long)r.fds_bits [0], + (unsigned long)w.fds_bits [0]); +#endif + count = select (max + 1, &r, &w, &x, t ? &to : (struct timeval *)0); + + /* Get the current time... */ + gettimeofday (&now, (struct timezone *)0); + cur_time = now.tv_sec; + + /* We probably have a bad file descriptor. Figure out which one. + When we find it, call the reaper function on it, which will + maybe make it go away, and then try again. */ + if (count < 0) { + struct timeval t0; + omapi_io_object_t *prev = (omapi_io_object_t *)0; + io = (omapi_io_object_t *)0; + if (omapi_io_states.next) + omapi_io_reference (&io, omapi_io_states.next, MDL); + + while (io) { + omapi_object_t *obj; + FD_ZERO (&r); + FD_ZERO (&w); + t0.tv_sec = t0.tv_usec = 0; + + if (io -> readfd && io -> inner && + (desc = (*(io -> readfd)) (io -> inner)) >= 0) { + FD_SET (desc, &r); +#if 0 + log_error ("read check: %d %lx %lx", max, + (unsigned long)r.fds_bits [0], + (unsigned long)w.fds_bits [0]); +#endif + count = select (desc + 1, &r, &w, &x, &t0); + bogon: + if (count < 0) { + log_error ("Bad descriptor %d.", desc); + for (obj = (omapi_object_t *)io; + obj -> outer; + obj = obj -> outer) + ; + for (; obj; obj = obj -> inner) { + omapi_value_t *ov; + int len; + const char *s; + ov = (omapi_value_t *)0; + omapi_get_value_str (obj, + (omapi_object_t *)0, + "name", &ov); + if (ov && ov -> value && + (ov -> value -> type == + omapi_datatype_string)) { + s = (char *) + ov -> value -> u.buffer.value; + len = ov -> value -> u.buffer.len; + } else { + s = ""; + len = 0; + } + log_error ("Object %lx %s%s%.*s", + (unsigned long)obj, + obj -> type -> name, + len ? " " : "", + len, s); + if (len) + omapi_value_dereference (&ov, MDL); + } + status = (*(io -> reaper)) (io -> inner); + if (prev) { + omapi_io_dereference (&prev -> next, MDL); + if (io -> next) + omapi_io_reference (&prev -> next, + io -> next, MDL); + } else { + omapi_io_dereference + (&omapi_io_states.next, MDL); + if (io -> next) + omapi_io_reference + (&omapi_io_states.next, + io -> next, MDL); + } + omapi_io_dereference (&io, MDL); + goto again; + } + } + + FD_ZERO (&r); + FD_ZERO (&w); + t0.tv_sec = t0.tv_usec = 0; + + /* Same deal for write fdets. */ + if (io -> writefd && io -> inner && + (desc = (*(io -> writefd)) (io -> inner)) >= 0) { + FD_SET (desc, &w); + count = select (desc + 1, &r, &w, &x, &t0); + if (count < 0) + goto bogon; + } + if (prev) + omapi_io_dereference (&prev, MDL); + omapi_io_reference (&prev, io, MDL); + omapi_io_dereference (&io, MDL); + if (prev -> next) + omapi_io_reference (&io, prev -> next, MDL); + } + if (prev) + omapi_io_dereference (&prev, MDL); + + } + + for (io = omapi_io_states.next; io; io = io -> next) { + if (!io -> inner) + continue; + omapi_object_reference (&tmp, io -> inner, MDL); + /* Check for a read descriptor, and if there is one, + see if we got input on that socket. */ + if (io -> readfd && + (desc = (*(io -> readfd)) (tmp)) >= 0) { + if (FD_ISSET (desc, &r)) + status = ((*(io -> reader)) (tmp)); + /* XXX what to do with status? */ + } + + /* Same deal for write descriptors. */ + if (io -> writefd && + (desc = (*(io -> writefd)) (tmp)) >= 0) + { + if (FD_ISSET (desc, &w)) + status = ((*(io -> writer)) (tmp)); + /* XXX what to do with status? */ + } + omapi_object_dereference (&tmp, MDL); + } + + /* Now check for I/O handles that are no longer valid, + and remove them from the list. */ + prev = (omapi_io_object_t *)0; + for (io = omapi_io_states.next; io; io = io -> next) { + if (io -> reaper) { + if (io -> inner) + status = (*(io -> reaper)) (io -> inner); + if (!io -> inner || status != ISC_R_SUCCESS) { + omapi_io_object_t *tmp = + (omapi_io_object_t *)0; + /* Save a reference to the next + pointer, if there is one. */ + if (io -> next) + omapi_io_reference (&tmp, + io -> next, MDL); + if (prev) { + omapi_io_dereference (&prev -> next, + MDL); + if (tmp) + omapi_io_reference + (&prev -> next, + tmp, MDL); + } else { + omapi_io_dereference + (&omapi_io_states.next, MDL); + if (tmp) + omapi_io_reference + (&omapi_io_states.next, + tmp, MDL); + else + omapi_signal_in + ((omapi_object_t *) + &omapi_io_states, + "ready"); + } + if (tmp) + omapi_io_dereference (&tmp, MDL); + } + } + prev = io; + } + + return ISC_R_SUCCESS; +} + +isc_result_t omapi_io_set_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_typed_data_t *value) +{ + if (h -> type != omapi_type_io_object) + return ISC_R_INVALIDARG; + + if (h -> inner && h -> inner -> type -> set_value) + return (*(h -> inner -> type -> set_value)) + (h -> inner, id, name, value); + return ISC_R_NOTFOUND; +} + +isc_result_t omapi_io_get_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_value_t **value) +{ + if (h -> type != omapi_type_io_object) + return ISC_R_INVALIDARG; + + if (h -> inner && h -> inner -> type -> get_value) + return (*(h -> inner -> type -> get_value)) + (h -> inner, id, name, value); + return ISC_R_NOTFOUND; +} + +isc_result_t omapi_io_destroy (omapi_object_t *h, const char *file, int line) +{ + omapi_io_object_t *obj, *p, *last; + + if (h -> type != omapi_type_io_object) + return ISC_R_INVALIDARG; + + obj = (omapi_io_object_t *)h; + + /* remove from the list of I/O states */ + for (p = omapi_io_states.next; p; p = p -> next) { + if (p == obj) { + omapi_io_dereference (&last -> next, MDL); + omapi_io_reference (&last -> next, p -> next, MDL); + omapi_io_dereference (&p, MDL); + break; + } + last = p; + } + + return ISC_R_SUCCESS; +} + +isc_result_t omapi_io_signal_handler (omapi_object_t *h, + const char *name, va_list ap) +{ + if (h -> type != omapi_type_io_object) + return ISC_R_INVALIDARG; + + if (h -> inner && h -> inner -> type -> signal_handler) + return (*(h -> inner -> type -> signal_handler)) (h -> inner, + name, ap); + return ISC_R_NOTFOUND; +} + +isc_result_t omapi_io_stuff_values (omapi_object_t *c, + omapi_object_t *id, + omapi_object_t *i) +{ + if (i -> type != omapi_type_io_object) + return ISC_R_INVALIDARG; + + if (i -> inner && i -> inner -> type -> stuff_values) + return (*(i -> inner -> type -> stuff_values)) (c, id, + i -> inner); + return ISC_R_SUCCESS; +} + +isc_result_t omapi_waiter_signal_handler (omapi_object_t *h, + const char *name, va_list ap) +{ + omapi_waiter_object_t *waiter; + + if (h -> type != omapi_type_waiter) + return ISC_R_INVALIDARG; + + if (!strcmp (name, "ready")) { + waiter = (omapi_waiter_object_t *)h; + waiter -> ready = 1; + waiter -> waitstatus = ISC_R_SUCCESS; + return ISC_R_SUCCESS; + } + + if (!strcmp (name, "status")) { + waiter = (omapi_waiter_object_t *)h; + waiter -> ready = 1; + waiter -> waitstatus = va_arg (ap, isc_result_t); + return ISC_R_SUCCESS; + } + + if (!strcmp (name, "disconnect")) { + waiter = (omapi_waiter_object_t *)h; + waiter -> ready = 1; + waiter -> waitstatus = ISC_R_CONNRESET; + return ISC_R_SUCCESS; + } + + if (h -> inner && h -> inner -> type -> signal_handler) + return (*(h -> inner -> type -> signal_handler)) (h -> inner, + name, ap); + return ISC_R_NOTFOUND; +} + +isc_result_t omapi_io_state_foreach (isc_result_t (*func) (omapi_object_t *, + void *), + void *p) +{ + omapi_io_object_t *io; + isc_result_t status; + + for (io = omapi_io_states.next; io; io = io -> next) { + if (io -> inner) { + status = (*func) (io -> inner, p); + if (status != ISC_R_SUCCESS) + return status; + } + } + return ISC_R_SUCCESS; +} diff --git a/contrib/isc-dhcp/omapip/errwarn.c b/contrib/isc-dhcp/omapip/errwarn.c new file mode 100644 index 0000000..6dc6dd9 --- /dev/null +++ b/contrib/isc-dhcp/omapip/errwarn.c @@ -0,0 +1,363 @@ +/* errwarn.c + + Errors and warnings... */ + +/* + * Copyright (c) 1995 RadioMail Corporation. + * Copyright (c) 1996-2000 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software was written for RadioMail Corporation by Ted Lemon + * under a contract with Vixie Enterprises. Further modifications have + * been made for the Internet Software Consortium under a contract + * with Vixie Laboratories. + */ + +#ifndef lint +static char copyright[] = +"$Id: errwarn.c,v 1.9 2000/09/29 20:01:49 mellon Exp $ Copyright (c) 1996 The Internet Software Consortium. All rights reserved.\n"; +#endif /* not lint */ + +#include <omapip/omapip_p.h> +#include <errno.h> + +#ifdef DEBUG +int log_perror = -1; +#else +int log_perror = 1; +#endif +int log_priority; +void (*log_cleanup) (void); + +#define CVT_BUF_MAX 1023 +static char mbuf [CVT_BUF_MAX + 1]; +static char fbuf [CVT_BUF_MAX + 1]; + +/* Log an error message, then exit... */ + +void log_fatal (const char * fmt, ... ) +{ + va_list list; + + do_percentm (fbuf, fmt); + + va_start (list, fmt); + vsnprintf (mbuf, sizeof mbuf, fbuf, list); + va_end (list); + +#ifndef DEBUG + syslog (log_priority | LOG_ERR, "%s", mbuf); +#endif + + /* Also log it to stderr? */ + if (log_perror) { + write (2, mbuf, strlen (mbuf)); + write (2, "\n", 1); + } + +#if !defined (NOMINUM) + log_error ("%s", ""); + log_error ("If you did not get this software from ftp.isc.org, please"); + log_error ("get the latest from ftp.isc.org and install that before"); + log_error ("requesting help."); + log_error ("%s", ""); + log_error ("If you did get this software from ftp.isc.org and have not"); + log_error ("yet read the README, please read it before requesting help."); + log_error ("If you intend to request help from the dhcp-server@isc.org"); + log_error ("mailing list, please read the section on the README about"); + log_error ("submitting bug reports and requests for help."); + log_error ("%s", ""); + log_error ("Please do not under any circumstances send requests for"); + log_error ("help directly to the authors of this software - please"); + log_error ("send them to the appropriate mailing list as described in"); + log_error ("the README file."); + log_error ("%s", ""); + log_error ("exiting."); +#endif + if (log_cleanup) + (*log_cleanup) (); + exit (1); +} + +/* Log an error message... */ + +int log_error (const char * fmt, ...) +{ + va_list list; + + do_percentm (fbuf, fmt); + + va_start (list, fmt); + vsnprintf (mbuf, sizeof mbuf, fbuf, list); + va_end (list); + +#ifndef DEBUG + syslog (log_priority | LOG_ERR, "%s", mbuf); +#endif + + if (log_perror) { + write (2, mbuf, strlen (mbuf)); + write (2, "\n", 1); + } + + return 0; +} + +/* Log a note... */ + +int log_info (const char *fmt, ...) +{ + va_list list; + + do_percentm (fbuf, fmt); + + va_start (list, fmt); + vsnprintf (mbuf, sizeof mbuf, fbuf, list); + va_end (list); + +#ifndef DEBUG + syslog (log_priority | LOG_INFO, "%s", mbuf); +#endif + + if (log_perror) { + write (2, mbuf, strlen (mbuf)); + write (2, "\n", 1); + } + + return 0; +} + +/* Log a debug message... */ + +int log_debug (const char *fmt, ...) +{ + va_list list; + + do_percentm (fbuf, fmt); + + va_start (list, fmt); + vsnprintf (mbuf, sizeof mbuf, fbuf, list); + va_end (list); + +#ifndef DEBUG + syslog (log_priority | LOG_DEBUG, "%s", mbuf); +#endif + + if (log_perror) { + write (2, mbuf, strlen (mbuf)); + write (2, "\n", 1); + } + + return 0; +} + +/* Find %m in the input string and substitute an error message string. */ + +void do_percentm (obuf, ibuf) + char *obuf; + const char *ibuf; +{ + const char *s = ibuf; + char *p = obuf; + int infmt = 0; + const char *m; + int len = 0; + + while (*s) { + if (infmt) { + if (*s == 'm') { +#ifndef __CYGWIN32__ + m = strerror (errno); +#else + m = pWSAError (); +#endif + if (!m) + m = "<unknown error>"; + len += strlen (m); + if (len > CVT_BUF_MAX) + goto out; + strcpy (p - 1, m); + p += strlen (p); + ++s; + } else { + if (++len > CVT_BUF_MAX) + goto out; + *p++ = *s++; + } + infmt = 0; + } else { + if (*s == '%') + infmt = 1; + if (++len > CVT_BUF_MAX) + goto out; + *p++ = *s++; + } + } + out: + *p = 0; +} + +#ifdef NO_STRERROR +char *strerror (err) + int err; +{ + extern char *sys_errlist []; + extern int sys_nerr; + static char errbuf [128]; + + if (err < 0 || err >= sys_nerr) { + sprintf (errbuf, "Error %d", err); + return errbuf; + } + return sys_errlist [err]; +} +#endif /* NO_STRERROR */ + +#ifdef _WIN32 +char *pWSAError () +{ + int err = WSAGetLastError (); + + switch (err) + { + case WSAEACCES: + return "Permission denied"; + case WSAEADDRINUSE: + return "Address already in use"; + case WSAEADDRNOTAVAIL: + return "Cannot assign requested address"; + case WSAEAFNOSUPPORT: + return "Address family not supported by protocol family"; + case WSAEALREADY: + return "Operation already in progress"; + case WSAECONNABORTED: + return "Software caused connection abort"; + case WSAECONNREFUSED: + return "Connection refused"; + case WSAECONNRESET: + return "Connection reset by peer"; + case WSAEDESTADDRREQ: + return "Destination address required"; + case WSAEFAULT: + return "Bad address"; + case WSAEHOSTDOWN: + return "Host is down"; + case WSAEHOSTUNREACH: + return "No route to host"; + case WSAEINPROGRESS: + return "Operation now in progress"; + case WSAEINTR: + return "Interrupted function call"; + case WSAEINVAL: + return "Invalid argument"; + case WSAEISCONN: + return "Socket is already connected"; + case WSAEMFILE: + return "Too many open files"; + case WSAEMSGSIZE: + return "Message too long"; + case WSAENETDOWN: + return "Network is down"; + case WSAENETRESET: + return "Network dropped connection on reset"; + case WSAENETUNREACH: + return "Network is unreachable"; + case WSAENOBUFS: + return "No buffer space available"; + case WSAENOPROTOOPT: + return "Bad protocol option"; + case WSAENOTCONN: + return "Socket is not connected"; + case WSAENOTSOCK: + return "Socket operation on non-socket"; + case WSAEOPNOTSUPP: + return "Operation not supported"; + case WSAEPFNOSUPPORT: + return "Protocol family not supported"; + case WSAEPROCLIM: + return "Too many processes"; + case WSAEPROTONOSUPPORT: + return "Protocol not supported"; + case WSAEPROTOTYPE: + return "Protocol wrong type for socket"; + case WSAESHUTDOWN: + return "Cannot send after socket shutdown"; + case WSAESOCKTNOSUPPORT: + return "Socket type not supported"; + case WSAETIMEDOUT: + return "Connection timed out"; + case WSAEWOULDBLOCK: + return "Resource temporarily unavailable"; + case WSAHOST_NOT_FOUND: + return "Host not found"; +#if 0 + case WSA_INVALID_HANDLE: + return "Specified event object handle is invalid"; + case WSA_INVALID_PARAMETER: + return "One or more parameters are invalid"; + case WSAINVALIDPROCTABLE: + return "Invalid procedure table from service provider"; + case WSAINVALIDPROVIDER: + return "Invalid service provider version number"; + case WSA_IO_PENDING: + return "Overlapped operations will complete later"; + case WSA_IO_INCOMPLETE: + return "Overlapped I/O event object not in signaled state"; + case WSA_NOT_ENOUGH_MEMORY: + return "Insufficient memory available"; +#endif + case WSANOTINITIALISED: + return "Successful WSAStartup not yet performer"; + case WSANO_DATA: + return "Valid name, no data record of requested type"; + case WSANO_RECOVERY: + return "This is a non-recoverable error"; +#if 0 + case WSAPROVIDERFAILEDINIT: + return "Unable to initialize a service provider"; + case WSASYSCALLFAILURE: + return "System call failure"; +#endif + case WSASYSNOTREADY: + return "Network subsystem is unavailable"; + case WSATRY_AGAIN: + return "Non-authoritative host not found"; + case WSAVERNOTSUPPORTED: + return "WINSOCK.DLL version out of range"; + case WSAEDISCON: + return "Graceful shutdown in progress"; +#if 0 + case WSA_OPERATION_ABORTED: + return "Overlapped operation aborted"; +#endif + } + return "Unknown WinSock error"; +} +#endif /* _WIN32 */ diff --git a/contrib/isc-dhcp/omapip/generic.c b/contrib/isc-dhcp/omapip/generic.c new file mode 100644 index 0000000..6154bcf --- /dev/null +++ b/contrib/isc-dhcp/omapip/generic.c @@ -0,0 +1,311 @@ +/* generic.c + + Subroutines that support the generic object. */ + +/* + * Copyright (c) 1999-2001 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. + */ + +#include <omapip/omapip_p.h> + +OMAPI_OBJECT_ALLOC (omapi_generic, + omapi_generic_object_t, omapi_type_generic) + +isc_result_t omapi_generic_new (omapi_object_t **gen, + const char *file, int line) +{ + /* Backwards compatibility. */ + return omapi_generic_allocate ((omapi_generic_object_t **)gen, + file, line); +} + +isc_result_t omapi_generic_set_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_typed_data_t *value) +{ + omapi_generic_object_t *g; + omapi_value_t *new; + omapi_value_t **va; + u_int8_t *ca; + int vm_new; + int i, vfree = -1; + isc_result_t status; + + if (h -> type != omapi_type_generic) + return ISC_R_INVALIDARG; + g = (omapi_generic_object_t *)h; + + /* See if there's already a value with this name attached to + the generic object, and if so, replace the current value + with the new one. */ + for (i = 0; i < g -> nvalues; i++) { + if (!omapi_data_string_cmp (name, g -> values [i] -> name)) { + /* There's an inconsistency here: the standard + behaviour of a set_values method when + passed a matching name and a null value is + to delete the value associated with that + name (where possible). In the generic + object, we remember the name/null pair, + because generic objects are generally used + to pass messages around, and this is the + way that remote entities delete values from + local objects. If the get_value method of + a generic object is called for a name that + maps to a name/null pair, ISC_R_NOTFOUND is + returned. */ + new = (omapi_value_t *)0; + status = (omapi_value_new (&new, MDL)); + if (status != ISC_R_SUCCESS) + return status; + omapi_data_string_reference (&new -> name, name, MDL); + if (value) + omapi_typed_data_reference (&new -> value, + value, MDL); + + omapi_value_dereference (&(g -> values [i]), MDL); + status = (omapi_value_reference + (&(g -> values [i]), new, MDL)); + omapi_value_dereference (&new, MDL); + g -> changed [i] = 1; + return status; + } + /* Notice a free slot if we pass one. */ + else if (vfree == -1 && !g -> values [i]) + vfree = i; + } + + /* If the name isn't already attached to this object, see if an + inner object has it. */ + if (h -> inner && h -> inner -> type -> set_value) { + status = ((*(h -> inner -> type -> set_value)) + (h -> inner, id, name, value)); + if (status != ISC_R_NOTFOUND) + return status; + } + + /* Okay, so it's a value that no inner object knows about, and + (implicitly, since the outer object set_value method would + have called this object's set_value method) it's an object that + no outer object knows about, it's this object's responsibility + to remember it - that's what generic objects do. */ + + /* Arrange for there to be space for the pointer to the new + name/value pair if necessary: */ + if (vfree == -1) { + vfree = g -> nvalues; + if (vfree == g -> va_max) { + if (g -> va_max) + vm_new = 2 * g -> va_max; + else + vm_new = 10; + va = dmalloc (vm_new * sizeof *va, MDL); + if (!va) + return ISC_R_NOMEMORY; + ca = dmalloc (vm_new * sizeof *ca, MDL); + if (!ca) { + dfree (va, MDL); + return ISC_R_NOMEMORY; + } + if (g -> va_max) { + memcpy (va, g -> values, + g -> va_max * sizeof *va); + memcpy (ca, g -> changed, + g -> va_max * sizeof *ca); + } + memset (va + g -> va_max, 0, + (vm_new - g -> va_max) * sizeof *va); + memset (ca + g -> va_max, 0, + (vm_new - g -> va_max) * sizeof *ca); + if (g -> values) + dfree (g -> values, MDL); + if (g -> changed) + dfree (g -> changed, MDL); + g -> values = va; + g -> changed = ca; + g -> va_max = vm_new; + } + } + status = omapi_value_new (&g -> values [vfree], MDL); + if (status != ISC_R_SUCCESS) + return status; + omapi_data_string_reference (&g -> values [vfree] -> name, + name, MDL); + if (value) + omapi_typed_data_reference + (&g -> values [vfree] -> value, value, MDL); + g -> changed [vfree] = 1; + if (vfree == g -> nvalues) + g -> nvalues++; + return ISC_R_SUCCESS; +} + +isc_result_t omapi_generic_get_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_value_t **value) +{ + int i; + omapi_generic_object_t *g; + + if (h -> type != omapi_type_generic) + return ISC_R_INVALIDARG; + g = (omapi_generic_object_t *)h; + + /* Look up the specified name in our list of objects. */ + for (i = 0; i < g -> nvalues; i++) { + if (!omapi_data_string_cmp (name, g -> values [i] -> name)) { + /* If this is a name/null value pair, this is the + same as if there were no value that matched + the specified name, so return ISC_R_NOTFOUND. */ + if (!g -> values [i] -> value) + return ISC_R_NOTFOUND; + /* Otherwise, return the name/value pair. */ + return omapi_value_reference (value, + g -> values [i], MDL); + } + } + + if (h -> inner && h -> inner -> type -> get_value) + return (*(h -> inner -> type -> get_value)) + (h -> inner, id, name, value); + return ISC_R_NOTFOUND; +} + +isc_result_t omapi_generic_destroy (omapi_object_t *h, + const char *file, int line) +{ + omapi_generic_object_t *g; + int i; + + if (h -> type != omapi_type_generic) + return ISC_R_UNEXPECTED; + g = (omapi_generic_object_t *)h; + + if (g -> values) { + for (i = 0; i < g -> nvalues; i++) { + if (g -> values [i]) + omapi_value_dereference (&g -> values [i], + file, line); + } + dfree (g -> values, file, line); + dfree (g -> changed, file, line); + g -> values = (omapi_value_t **)0; + g -> changed = (u_int8_t *)0; + g -> va_max = 0; + } + + return ISC_R_SUCCESS; +} + +isc_result_t omapi_generic_signal_handler (omapi_object_t *h, + const char *name, va_list ap) +{ + if (h -> type != omapi_type_generic) + return ISC_R_INVALIDARG; + + if (h -> inner && h -> inner -> type -> signal_handler) + return (*(h -> inner -> type -> signal_handler)) (h -> inner, + name, ap); + return ISC_R_NOTFOUND; +} + +/* Write all the published values associated with the object through the + specified connection. */ + +isc_result_t omapi_generic_stuff_values (omapi_object_t *c, + omapi_object_t *id, + omapi_object_t *g) +{ + omapi_generic_object_t *src; + int i; + isc_result_t status; + + if (g -> type != omapi_type_generic) + return ISC_R_INVALIDARG; + src = (omapi_generic_object_t *)g; + + for (i = 0; i < src -> nvalues; i++) { + if (src -> values [i] && src -> values [i] -> name -> len && + src -> changed [i]) { + status = (omapi_connection_put_uint16 + (c, src -> values [i] -> name -> len)); + if (status != ISC_R_SUCCESS) + return status; + status = (omapi_connection_copyin + (c, src -> values [i] -> name -> value, + src -> values [i] -> name -> len)); + if (status != ISC_R_SUCCESS) + return status; + + status = (omapi_connection_write_typed_data + (c, src -> values [i] -> value)); + if (status != ISC_R_SUCCESS) + return status; + } + } + + if (g -> inner && g -> inner -> type -> stuff_values) + return (*(g -> inner -> type -> stuff_values)) (c, id, + g -> inner); + return ISC_R_SUCCESS; +} + +/* Clear the changed flags on the object. This has the effect that if + generic_stuff is called, any attributes that still have a cleared changed + flag aren't sent to the peer. This also deletes any values that are + null, presuming that these have now been properly handled. */ + +isc_result_t omapi_generic_clear_flags (omapi_object_t *o) +{ + int i; + isc_result_t status; + omapi_generic_object_t *g; + + if (o -> type != omapi_type_generic) + return ISC_R_INVALIDARG; + g = (omapi_generic_object_t *)o; + + for (i = 0; i < g -> nvalues; i++) { + g -> changed [i] = 0; + if (g -> values [i] && + !g -> values [i] -> value) + omapi_value_dereference (&g -> values [i], MDL); + } + return ISC_R_SUCCESS; +} diff --git a/contrib/isc-dhcp/omapip/handle.c b/contrib/isc-dhcp/omapip/handle.c new file mode 100644 index 0000000..3b99ec7 --- /dev/null +++ b/contrib/isc-dhcp/omapip/handle.c @@ -0,0 +1,304 @@ +/* handle.c + + Functions for maintaining handles on objects. */ + +/* + * Copyright (c) 1999-2000 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. + */ + +#include <omapip/omapip_p.h> + +/* The handle table is a hierarchical tree designed for quick mapping + of handle identifiers to objects. Objects contain their own handle + identifiers if they have them, so the reverse mapping is also + quick. The hierarchy is made up of table objects, each of which + has 120 entries, a flag indicating whether the table is a leaf + table or an indirect table, the handle of the first object covered + by the table and the first object after that that's *not* covered + by the table, a count of how many objects of either type are + currently stored in the table, and an array of 120 entries pointing + either to objects or tables. + + When we go to add an object to the table, we look to see if the + next object handle to be assigned is covered by the outermost + table. If it is, we find the place within that table where the + next handle should go, and if necessary create additional nodes in + the tree to contain the new handle. The pointer to the object is + then stored in the correct position. + + Theoretically, we could have some code here to free up handle + tables as they go out of use, but by and large handle tables won't + go out of use, so this is being skipped for now. It shouldn't be + too hard to implement in the future if there's a different + application. */ + +omapi_handle_table_t *omapi_handle_table; +omapi_handle_t omapi_next_handle = 1; /* Next handle to be assigned. */ + +static isc_result_t omapi_handle_lookup_in (omapi_object_t **, + omapi_handle_t, + omapi_handle_table_t *); +static isc_result_t omapi_object_handle_in_table (omapi_handle_t, + omapi_handle_table_t *, + omapi_object_t *); +static isc_result_t omapi_handle_table_enclose (omapi_handle_table_t **); + +isc_result_t omapi_object_handle (omapi_handle_t *h, omapi_object_t *o) +{ + int tabix; + isc_result_t status; + + if (o -> handle) { + *h = o -> handle; + return ISC_R_SUCCESS; + } + + if (!omapi_handle_table) { + omapi_handle_table = dmalloc (sizeof *omapi_handle_table, MDL); + if (!omapi_handle_table) + return ISC_R_NOMEMORY; + memset (omapi_handle_table, 0, sizeof *omapi_handle_table); + omapi_handle_table -> first = 0; + omapi_handle_table -> limit = OMAPI_HANDLE_TABLE_SIZE; + omapi_handle_table -> leafp = 1; + } + + /* If this handle doesn't fit in the outer table, we need to + make a new outer table. This is a while loop in case for + some reason we decide to do disjoint handle allocation, + where the next level of indirection still isn't big enough + to enclose the next handle ID. */ + + while (omapi_next_handle >= omapi_handle_table -> limit) { + omapi_handle_table_t *new; + + new = dmalloc (sizeof *new, MDL); + if (!new) + return ISC_R_NOMEMORY; + memset (new, 0, sizeof *new); + new -> first = 0; + new -> limit = (omapi_handle_table -> limit * + OMAPI_HANDLE_TABLE_SIZE); + new -> leafp = 0; + new -> children [0].table = omapi_handle_table; + omapi_handle_table = new; + } + + /* Try to cram this handle into the existing table. */ + status = omapi_object_handle_in_table (omapi_next_handle, + omapi_handle_table, o); + /* If it worked, return the next handle and increment it. */ + if (status == ISC_R_SUCCESS) { + *h = omapi_next_handle; + omapi_next_handle++; + return ISC_R_SUCCESS; + } + if (status != ISC_R_NOSPACE) + return status; + + status = omapi_handle_table_enclose (&omapi_handle_table); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_object_handle_in_table (omapi_next_handle, + omapi_handle_table, o); + if (status != ISC_R_SUCCESS) + return status; + *h = omapi_next_handle; + omapi_next_handle++; + + return ISC_R_SUCCESS; +} + +static isc_result_t omapi_object_handle_in_table (omapi_handle_t h, + omapi_handle_table_t *table, + omapi_object_t *o) +{ + omapi_handle_table_t *inner; + omapi_handle_t scale, index; + isc_result_t status; + + if (table -> first > h || table -> limit <= h) + return ISC_R_NOSPACE; + + /* If this is a leaf table, just stash the object in the + appropriate place. */ + if (table -> leafp) { + status = (omapi_object_reference + (&table -> children [h - table -> first].object, + o, MDL)); + if (status != ISC_R_SUCCESS) + return status; + o -> handle = h; + return ISC_R_SUCCESS; + } + + /* Scale is the number of handles represented by each child of this + table. For a leaf table, scale would be 1. For a first level + of indirection, 120. For a second, 120 * 120. Et cetera. */ + scale = (table -> limit - table -> first) / OMAPI_HANDLE_TABLE_SIZE; + + /* So the next most direct table from this one that contains the + handle must be the subtable of this table whose index into this + table's array of children is the handle divided by the scale. */ + index = (h - table -> first) / scale; + inner = table -> children [index].table; + + /* If there is no more direct table than this one in the slot + we came up with, make one. */ + if (!inner) { + inner = dmalloc (sizeof *inner, MDL); + if (!inner) + return ISC_R_NOMEMORY; + memset (inner, 0, sizeof *inner); + inner -> first = index * scale + table -> first; + inner -> limit = inner -> first + scale; + if (scale == OMAPI_HANDLE_TABLE_SIZE) + inner -> leafp = 1; + table -> children [index].table = inner; + } + + status = omapi_object_handle_in_table (h, inner, o); + if (status == ISC_R_NOSPACE) { + status = (omapi_handle_table_enclose + (&table -> children [index].table)); + if (status != ISC_R_SUCCESS) + return status; + + return omapi_object_handle_in_table + (h, table -> children [index].table, o); + } + return status; +} + +static isc_result_t omapi_handle_table_enclose (omapi_handle_table_t **table) +{ + omapi_handle_table_t *inner = *table; + omapi_handle_table_t *new; + int index, base, scale; + + /* The scale of the table we're enclosing is going to be the + difference between its "first" and "limit" members. So the + scale of the table enclosing it is going to be that multiplied + by the table size. */ + scale = (inner -> first - inner -> limit) * OMAPI_HANDLE_TABLE_SIZE; + + /* The range that the enclosing table covers is going to be + the result of subtracting the remainder of dividing the + enclosed table's first entry number by the enclosing + table's scale. If handle IDs are being allocated + sequentially, the enclosing table's "first" value will be + the same as the enclosed table's "first" value. */ + base = inner -> first - inner -> first % scale; + + /* The index into the enclosing table at which the enclosed table + will be stored is going to be the difference between the "first" + value of the enclosing table and the enclosed table - zero, if + we are allocating sequentially. */ + index = (base - inner -> first) / OMAPI_HANDLE_TABLE_SIZE; + + new = dmalloc (sizeof *new, MDL); + if (!new) + return ISC_R_NOMEMORY; + memset (new, 0, sizeof *new); + new -> first = base; + new -> limit = base + scale; + if (scale == OMAPI_HANDLE_TABLE_SIZE) + new -> leafp = 0; + new -> children [index].table = inner; + *table = new; + return ISC_R_SUCCESS; +} + +isc_result_t omapi_handle_lookup (omapi_object_t **o, omapi_handle_t h) +{ + return omapi_handle_lookup_in (o, h, omapi_handle_table); +} + +static isc_result_t omapi_handle_lookup_in (omapi_object_t **o, + omapi_handle_t h, + omapi_handle_table_t *table) + +{ + omapi_handle_table_t *inner; + omapi_handle_t scale, index; + + if (!table || table -> first > h || table -> limit <= h) + return ISC_R_NOTFOUND; + + /* If this is a leaf table, just grab the object. */ + if (table -> leafp) { + /* Not there? */ + if (!table -> children [h - table -> first].object) + return ISC_R_NOTFOUND; + return omapi_object_reference + (o, table -> children [h - table -> first].object, + MDL); + } + + /* Scale is the number of handles represented by each child of this + table. For a leaf table, scale would be 1. For a first level + of indirection, 120. For a second, 120 * 120. Et cetera. */ + scale = (table -> limit - table -> first) / OMAPI_HANDLE_TABLE_SIZE; + + /* So the next most direct table from this one that contains the + handle must be the subtable of this table whose index into this + table's array of children is the handle divided by the scale. */ + index = (h - table -> first) / scale; + inner = table -> children [index].table; + + return omapi_handle_lookup_in (o, h, table -> children [index].table); +} + +/* For looking up objects based on handles that have been sent on the wire. */ +isc_result_t omapi_handle_td_lookup (omapi_object_t **obj, + omapi_typed_data_t *handle) +{ + isc_result_t status; + omapi_handle_t h; + + if (handle -> type == omapi_datatype_int) + h = handle -> u.integer; + else if (handle -> type == omapi_datatype_data && + handle -> u.buffer.len == sizeof h) { + memcpy (&h, handle -> u.buffer.value, sizeof h); + h = ntohl (h); + } else + return ISC_R_INVALIDARG; + return omapi_handle_lookup (obj, h); +} diff --git a/contrib/isc-dhcp/omapip/hash.c b/contrib/isc-dhcp/omapip/hash.c new file mode 100644 index 0000000..67c46bf --- /dev/null +++ b/contrib/isc-dhcp/omapip/hash.c @@ -0,0 +1,425 @@ +/* hash.c + + Routines for manipulating hash tables... */ + +/* + * Copyright (c) 1995-2001 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. + */ + +#ifndef lint +static char copyright[] = +"$Id: hash.c,v 1.1.2.5 2001/10/17 04:00:35 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n"; +#endif /* not lint */ + +#include <omapip/omapip_p.h> +#include <ctype.h> + +static int do_hash (const unsigned char *, unsigned, unsigned); +static int do_case_hash (const unsigned char *, unsigned, unsigned); + +int new_hash_table (tp, count, file, line) + struct hash_table **tp; + int count; + const char *file; + int line; +{ + struct hash_table *rval; + + if (!tp) { + log_error ("%s(%d): new_hash_table called with null pointer.", + file, line); +#if defined (POINTER_DEBUG) + abort (); +#endif + return 0; + } + if (*tp) { + log_error ("%s(%d): non-null target for new_hash_table.", + file, line); +#if defined (POINTER_DEBUG) + abort (); +#endif + } + rval = dmalloc (sizeof (struct hash_table) - + (DEFAULT_HASH_SIZE * sizeof (struct hash_bucket *)) + + (count * sizeof (struct hash_bucket *)), file, line); + if (!rval) + return 0; + rval -> hash_count = count; + *tp = rval; + return 1; +} + +void free_hash_table (tp, file, line) + struct hash_table **tp; + const char *file; + int line; +{ + int i; + struct hash_bucket *hbc, *hbn = (struct hash_bucket *)0; + struct hash_table *ptr = *tp; + +#if defined (DEBUG_MEMORY_LEAKAGE) || \ + defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) + for (i = 0; i < ptr -> hash_count; i++) { + for (hbc = ptr -> buckets [i]; hbc; hbc = hbn) { + hbn = hbc -> next; + if (ptr -> dereferencer && hbc -> value) + (*ptr -> dereferencer) (&hbc -> value, MDL); + } + for (hbc = ptr -> buckets [i]; hbc; hbc = hbn) { + hbn = hbc -> next; + free_hash_bucket (hbc, MDL); + } + ptr -> buckets [i] = (struct hash_bucket *)0; + } +#endif + + dfree ((VOIDPTR)ptr, MDL); + *tp = (struct hash_table *)0; +} + +struct hash_bucket *free_hash_buckets; + +#if defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) +struct hash_bucket *hash_bucket_hunks; + +void relinquish_hash_bucket_hunks () +{ + struct hash_bucket *c, *n, **p; + + /* Account for all the hash buckets on the free list. */ + p = &free_hash_buckets; + for (c = free_hash_buckets; c; c = c -> next) { + for (n = hash_bucket_hunks; n; n = n -> next) { + if (c > n && c < n + 127) { + *p = c -> next; + n -> len++; + break; + } + } + /* If we didn't delete the hash bucket from the free list, + advance the pointer. */ + if (!n) + p = &c -> next; + } + + for (c = hash_bucket_hunks; c; c = n) { + n = c -> next; + if (c -> len != 126) { + log_info ("hashbucket %lx hash_buckets %d free %u", + (unsigned long)c, 127, c -> len); + } + dfree (c, MDL); + } +} +#endif + +struct hash_bucket *new_hash_bucket (file, line) + const char *file; + int line; +{ + struct hash_bucket *rval; + int i = 0; + if (!free_hash_buckets) { + rval = dmalloc (127 * sizeof (struct hash_bucket), + file, line); + if (!rval) + return rval; +# if defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) + rval -> next = hash_bucket_hunks; + hash_bucket_hunks = rval; + hash_bucket_hunks -> len = 0; + i++; + rval++; +#endif + for (; i < 127; i++) { + rval -> next = free_hash_buckets; + free_hash_buckets = rval; + rval++; + } + } + rval = free_hash_buckets; + free_hash_buckets = rval -> next; + return rval; +} + +void free_hash_bucket (ptr, file, line) + struct hash_bucket *ptr; + const char *file; + int line; +{ + struct hash_bucket *hp; +#if defined (DEBUG_MALLOC_POOL) + for (hp = free_hash_buckets; hp; hp = hp -> next) { + if (hp == ptr) { + log_error ("hash bucket freed twice!"); + abort (); + } + } +#endif + ptr -> next = free_hash_buckets; + free_hash_buckets = ptr; +} + +int new_hash (struct hash_table **rp, + hash_reference referencer, + hash_dereference dereferencer, + int casep, const char *file, int line) +{ + if (!new_hash_table (rp, DEFAULT_HASH_SIZE, file, line)) + return 0; + memset (&(*rp) -> buckets [0], 0, + DEFAULT_HASH_SIZE * sizeof (struct hash_bucket *)); + (*rp) -> referencer = referencer; + (*rp) -> dereferencer = dereferencer; + if (casep) { + (*rp) -> cmp = casecmp; + (*rp) -> do_hash = do_case_hash; + } else { + (*rp) -> cmp = (hash_comparator_t)memcmp; + (*rp) -> do_hash = do_hash; + } + return 1; +} + +static int do_case_hash (name, len, size) + const unsigned char *name; + unsigned len; + unsigned size; +{ + register int accum = 0; + register const unsigned char *s = (const unsigned char *)name; + int i = len; + register unsigned c; + + while (i--) { + /* Make the hash case-insensitive. */ + c = *s++; + if (isascii (c) && isupper (c)) + c = tolower (c); + + /* Add the character in... */ + accum = (accum << 1) + c; + + /* Add carry back in... */ + while (accum > 65535) { + accum = (accum & 65535) + (accum >> 16); + } + } + return accum % size; +} + +static int do_hash (name, len, size) + const unsigned char *name; + unsigned len; + unsigned size; +{ + register int accum = 0; + register const unsigned char *s = (const unsigned char *)name; + int i = len; + + while (i--) { + /* Add the character in... */ + accum = (accum << 1) + *s++; + + /* Add carry back in... */ + while (accum > 65535) { + accum = (accum & 65535) + (accum >> 16); + } + } + return accum % size; +} + +void add_hash (table, name, len, pointer, file, line) + struct hash_table *table; + unsigned len; + const unsigned char *name; + hashed_object_t *pointer; + const char *file; + int line; +{ + int hashno; + struct hash_bucket *bp; + void *foo; + + if (!table) + return; + + if (!len) + len = strlen ((const char *)name); + + hashno = (*table -> do_hash) (name, len, table -> hash_count); + bp = new_hash_bucket (file, line); + + if (!bp) { + log_error ("Can't add %s to hash table.", name); + return; + } + bp -> name = name; + if (table -> referencer) { + foo = &bp -> value; + (*(table -> referencer)) (foo, pointer, file, line); + } else + bp -> value = pointer; + bp -> next = table -> buckets [hashno]; + bp -> len = len; + table -> buckets [hashno] = bp; +} + +void delete_hash_entry (table, name, len, file, line) + struct hash_table *table; + unsigned len; + const unsigned char *name; + const char *file; + int line; +{ + int hashno; + struct hash_bucket *bp, *pbp = (struct hash_bucket *)0; + void *foo; + + if (!table) + return; + + if (!len) + len = strlen ((const char *)name); + + hashno = (*table -> do_hash) (name, len, table -> hash_count); + + /* Go through the list looking for an entry that matches; + if we find it, delete it. */ + for (bp = table -> buckets [hashno]; bp; bp = bp -> next) { + if ((!bp -> len && + !strcmp ((const char *)bp -> name, (const char *)name)) || + (bp -> len == len && + !(*table -> cmp) (bp -> name, name, len))) { + if (pbp) { + pbp -> next = bp -> next; + } else { + table -> buckets [hashno] = bp -> next; + } + if (bp -> value && table -> dereferencer) { + foo = &bp -> value; + (*(table -> dereferencer)) (foo, file, line); + } + free_hash_bucket (bp, file, line); + break; + } + pbp = bp; /* jwg, 9/6/96 - nice catch! */ + } +} + +int hash_lookup (vp, table, name, len, file, line) + hashed_object_t **vp; + struct hash_table *table; + const unsigned char *name; + unsigned len; + const char *file; + int line; +{ + int hashno; + struct hash_bucket *bp; + + if (!table) + return 0; + if (!len) + len = strlen ((const char *)name); + + hashno = (*table -> do_hash) (name, len, table -> hash_count); + + for (bp = table -> buckets [hashno]; bp; bp = bp -> next) { + if (len == bp -> len + && !(*table -> cmp) (bp -> name, name, len)) { + if (table -> referencer) + (*table -> referencer) (vp, bp -> value, + file, line); + else + *vp = bp -> value; + return 1; + } + } + return 0; +} + +int hash_foreach (struct hash_table *table, hash_foreach_func func) +{ + int i; + struct hash_bucket *bp, *next; + int count = 0; + + if (!table) + return 0; + + for (i = 0; i < table -> hash_count; i++) { + bp = table -> buckets [i]; + while (bp) { + next = bp -> next; + (*func) (bp -> name, bp -> len, bp -> value); + bp = next; + count++; + } + } + return count; +} + +int casecmp (const void *v1, const void *v2, unsigned long len) +{ + unsigned i; + const char *s = v1; + const char *t = v2; + + for (i = 0; i < len; i++) + { + int c1, c2; + if (isascii (s [i]) && isupper (s [i])) + c1 = tolower (s [i]); + else + c1 = s [i]; + + if (isascii (t [i]) && isupper (t [i])) + c2 = tolower (t [i]); + else + c2 = t [i]; + + if (c1 < c2) + return -1; + if (c1 > c2) + return 1; + } + return 0; +} diff --git a/contrib/isc-dhcp/omapip/inet_addr.c b/contrib/isc-dhcp/omapip/inet_addr.c new file mode 100644 index 0000000..0e7967c --- /dev/null +++ b/contrib/isc-dhcp/omapip/inet_addr.c @@ -0,0 +1,150 @@ +/* $NetBSD: inet_addr.c,v 1.6 1996/02/02 15:22:23 mrg Exp $ */ + +/* + * Copyright (c) 1983, 1990, 1993 + * 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 the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)inet_addr.c 8.1 (Berkeley) 6/17/93"; +#else +static char rcsid[] = "$NetBSD: inet_addr.c,v 1.6 1996/02/02 15:22:23 mrg Exp $"; +#endif +#endif /* LIBC_SCCS and not lint */ + +#ifndef lint +static char copyright[] = +"$Id: inet_addr.c,v 1.1 2000/09/20 00:01:50 mellon Exp $ Copyright (c) 1983, 1990, 1993 The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#include "omapip/omapip_p.h" + +#ifdef NEED_INET_ATON +/* + * Check whether "cp" is a valid ascii representation + * of an Internet address and convert to a binary address. + * Returns 1 if the address is valid, 0 if not. + * This replaces inet_addr, the return value from which + * cannot distinguish between failure and a local broadcast address. + */ +int +inet_aton(cp, addr) + const char *cp; + struct in_addr *addr; +{ + register u_long val; + register int base, n; + register char c; + u_int parts[4]; + register u_int *pp = parts; + + for (;;) { + /* + * Collect number up to ``.''. + * Values are specified as for C: + * 0x=hex, 0=octal, other=decimal. + */ + val = 0; base = 10; + if (*cp == '0') { + if (*++cp == 'x' || *cp == 'X') + base = 16, cp++; + else + base = 8; + } + while ((c = *cp) != '\0') { + if (isascii(c) && isdigit(c)) { + val = (val * base) + (c - '0'); + cp++; + continue; + } + if (base == 16 && isascii(c) && isxdigit(c)) { + val = (val << 4) + + (c + 10 - (islower(c) ? 'a' : 'A')); + cp++; + continue; + } + break; + } + if (*cp == '.') { + /* + * Internet format: + * a.b.c.d + * a.b.c (with c treated as 16-bits) + * a.b (with b treated as 24 bits) + */ + if (pp >= parts + 3 || val > 0xff) + return (0); + *pp++ = val, cp++; + } else + break; + } + /* + * Check for trailing characters. + */ + if (*cp && (!isascii(*cp) || !isspace(*cp))) + return (0); + /* + * Concoct the address according to + * the number of parts specified. + */ + n = pp - parts + 1; + switch (n) { + + case 0: + return (0); /* initial nondigit */ + + case 1: /* a -- 32 bits */ + break; + + case 2: /* a.b -- 8.24 bits */ + if (val > 0xffffff) + return (0); + val |= parts[0] << 24; + break; + + case 3: /* a.b.c -- 8.8.16 bits */ + if (val > 0xffff) + return (0); + val |= (parts[0] << 24) | (parts[1] << 16); + break; + + case 4: /* a.b.c.d -- 8.8.8.8 bits */ + if (val > 0xff) + return (0); + val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); + break; + } + if (addr) + addr->s_addr = htonl(val); + return (1); +} +#endif diff --git a/contrib/isc-dhcp/omapip/listener.c b/contrib/isc-dhcp/omapip/listener.c new file mode 100644 index 0000000..9953a91 --- /dev/null +++ b/contrib/isc-dhcp/omapip/listener.c @@ -0,0 +1,477 @@ +/* listener.c + + Subroutines that support the generic listener object. */ + +/* + * Copyright (c) 1999-2001 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. + */ + +#include <omapip/omapip_p.h> + +#if defined (TRACING) +omapi_array_t *trace_listeners; +static void trace_listener_accept_input (trace_type_t *, unsigned, char *); +static void trace_listener_remember (omapi_listener_object_t *, + const char *, int); +static void trace_listener_accept_stop (trace_type_t *); +trace_type_t *trace_listener_accept; +#endif + +OMAPI_OBJECT_ALLOC (omapi_listener, + omapi_listener_object_t, omapi_type_listener) + +isc_result_t omapi_listen (omapi_object_t *h, + unsigned port, + int max) +{ + omapi_addr_t addr; + +#ifdef DEBUG_PROTOCOL + log_debug ("omapi_listen(port=%d, max=%d)", port, max); +#endif + + addr.addrtype = AF_INET; + addr.addrlen = sizeof (struct in_addr); + memset (addr.address, 0, sizeof addr.address); /* INADDR_ANY */ + addr.port = port; + + return omapi_listen_addr (h, &addr, max); +} + +isc_result_t omapi_listen_addr (omapi_object_t *h, + omapi_addr_t *addr, + int max) +{ + struct hostent *he; + int hix; + isc_result_t status; + omapi_listener_object_t *obj; + int i; + struct in_addr ia; + + /* Get the handle. */ + obj = (omapi_listener_object_t *)0; + status = omapi_listener_allocate (&obj, MDL); + if (status != ISC_R_SUCCESS) + return status; + + /* Connect this object to the inner object. */ + status = omapi_object_reference (&h -> outer, + (omapi_object_t *)obj, MDL); + if (status != ISC_R_SUCCESS) { + omapi_listener_dereference (&obj, MDL); + return status; + } + status = omapi_object_reference (&obj -> inner, h, MDL); + if (status != ISC_R_SUCCESS) { + omapi_listener_dereference (&obj, MDL); + return status; + } + + /* Currently only support TCPv4 addresses. */ + if (addr -> addrtype != AF_INET) + return ISC_R_INVALIDARG; + + /* Set up the address on which we will listen... */ + obj -> address.sin_port = htons (addr -> port); + memcpy (&obj -> address.sin_addr, + addr -> address, sizeof obj -> address.sin_addr); +#if defined (HAVE_SA_LEN) + obj -> address.sin_len = + sizeof (struct sockaddr_in); +#endif + obj -> address.sin_family = AF_INET; + memset (&(obj -> address.sin_zero), 0, + sizeof obj -> address.sin_zero); + +#if defined (TRACING) + /* If we're playing back a trace file, we remember the object + on the trace listener queue. */ + if (trace_playback ()) { + trace_listener_remember (obj, MDL); + } else { +#endif + /* Create a socket on which to listen. */ + obj -> socket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (!obj -> socket) { + omapi_listener_dereference (&obj, MDL); + if (errno == EMFILE + || errno == ENFILE || errno == ENOBUFS) + return ISC_R_NORESOURCES; + return ISC_R_UNEXPECTED; + } + +#if defined (HAVE_SETFD) + if (fcntl (obj -> socket, F_SETFD, 1) < 0) { + close (obj -> socket); + omapi_listener_dereference (&obj, MDL); + return ISC_R_UNEXPECTED; + } +#endif + + /* Set the REUSEADDR option so that we don't fail to start if + we're being restarted. */ + i = 1; + if (setsockopt (obj -> socket, SOL_SOCKET, SO_REUSEADDR, + (char *)&i, sizeof i) < 0) { + close (obj -> socket); + omapi_listener_dereference (&obj, MDL); + return ISC_R_UNEXPECTED; + } + + /* Try to bind to the wildcard address using the port number + we were given. */ + i = bind (obj -> socket, + (struct sockaddr *)&obj -> address, + sizeof obj -> address); + if (i < 0) { + omapi_listener_dereference (&obj, MDL); + if (errno == EADDRINUSE) + return ISC_R_ADDRNOTAVAIL; + if (errno == EPERM) + return ISC_R_NOPERM; + return ISC_R_UNEXPECTED; + } + + /* Now tell the kernel to listen for connections. */ + if (listen (obj -> socket, max)) { + omapi_listener_dereference (&obj, MDL); + return ISC_R_UNEXPECTED; + } + + if (fcntl (obj -> socket, F_SETFL, O_NONBLOCK) < 0) { + omapi_listener_dereference (&obj, MDL); + return ISC_R_UNEXPECTED; + } + + status = omapi_register_io_object ((omapi_object_t *)obj, + omapi_listener_readfd, 0, + omapi_accept, 0, 0); +#if defined (TRACING) + } +#endif + omapi_listener_dereference (&obj, MDL); + return status; +} + +/* Return the socket on which the dispatcher should wait for readiness + to read, for a listener object. */ +int omapi_listener_readfd (omapi_object_t *h) +{ + omapi_listener_object_t *l; + + if (h -> type != omapi_type_listener) + return -1; + l = (omapi_listener_object_t *)h; + + return l -> socket; +} + +/* Reader callback for a listener object. Accept an incoming connection. */ +isc_result_t omapi_accept (omapi_object_t *h) +{ + isc_result_t status; + SOCKLEN_T len; + omapi_connection_object_t *obj; + omapi_listener_object_t *listener; + omapi_addr_t remote_addr; + int i; + struct sockaddr_in addr; + int socket; + + if (h -> type != omapi_type_listener) + return ISC_R_INVALIDARG; + listener = (omapi_listener_object_t *)h; + + /* Accept the connection. */ + len = sizeof addr; + socket = accept (listener -> socket, + ((struct sockaddr *)&(addr)), &len); + if (socket < 0) { + if (errno == EMFILE || errno == ENFILE || errno == ENOBUFS) + return ISC_R_NORESOURCES; + return ISC_R_UNEXPECTED; + } + +#if defined (TRACING) + /* If we're recording a trace, remember the connection. */ + if (trace_record ()) { + trace_iov_t iov [3]; + u_int32_t lsock; + iov [0].buf = (char *)&addr.sin_port; + iov [0].len = sizeof addr.sin_port; + iov [1].buf = (char *)&addr.sin_addr; + iov [1].len = sizeof addr.sin_addr; + iov [2].buf = (char *)&listener -> address.sin_port; + iov [2].len = sizeof listener -> address.sin_port; + trace_write_packet_iov (trace_listener_accept, + 3, iov, MDL); + } +#endif + + obj = (omapi_connection_object_t *)0; + status = omapi_listener_connect (&obj, listener, socket, &addr); + if (status != ISC_R_SUCCESS) { + close (socket); + return status; + } + + status = omapi_register_io_object ((omapi_object_t *)obj, + omapi_connection_readfd, + omapi_connection_writefd, + omapi_connection_reader, + omapi_connection_writer, + omapi_connection_reaper); + + /* Lose our reference to the connection, so it'll be gc'd when it's + reaped. */ + omapi_connection_dereference (&obj, MDL); + if (status != ISC_R_SUCCESS) + omapi_disconnect ((omapi_object_t *)(obj), 1); + return status; +} + +isc_result_t omapi_listener_connect (omapi_connection_object_t **obj, + omapi_listener_object_t *listener, + int socket, + struct sockaddr_in *remote_addr) +{ + isc_result_t status; + omapi_object_t *h = (omapi_object_t *)listener; + omapi_addr_t addr; + +#ifdef DEBUG_PROTOCOL + log_debug ("omapi_accept()"); +#endif + + /* Get the handle. */ + status = omapi_connection_allocate (obj, MDL); + if (status != ISC_R_SUCCESS) + return status; + + (*obj) -> state = omapi_connection_connected; + (*obj) -> remote_addr = *remote_addr; + (*obj) -> socket = socket; + + /* Verify that this host is allowed to connect. */ + if (listener -> verify_addr) { + addr.addrtype = AF_INET; + addr.addrlen = sizeof (remote_addr -> sin_addr); + memcpy (addr.address, &remote_addr -> sin_addr, + sizeof (remote_addr -> sin_addr)); + addr.port = ntohs(remote_addr -> sin_port); + + status = (listener -> verify_addr) (h, &addr); + if (status != ISC_R_SUCCESS) { + omapi_disconnect ((omapi_object_t *)(*obj), 1); + omapi_connection_dereference (obj, MDL); + return status; + } + } + + omapi_listener_reference (&(*obj) -> listener, listener, MDL); +#if defined (TRACING) + omapi_connection_register (*obj, MDL); +#endif + status = omapi_signal (h, "connect", (*obj)); + return status; +} + +#if defined (TRACING) +OMAPI_ARRAY_TYPE(omapi_listener, omapi_listener_object_t) + +void omapi_listener_trace_setup (void) { + trace_listener_accept = + trace_type_register ("listener-accept", (void *)0, + trace_listener_accept_input, + trace_listener_accept_stop, MDL); +} + +static void trace_listener_remember (omapi_listener_object_t *obj, + const char *file, int line) +{ + isc_result_t status; + if (!trace_listeners) { + status = omapi_listener_array_allocate (&trace_listeners, + file, line); + if (status != ISC_R_SUCCESS) { + foo: + log_error ("trace_listener_remember: %s", + isc_result_totext (status)); + return; + } + } + status = omapi_listener_array_extend (trace_listeners, obj, + &obj -> index, MDL); + if (status != ISC_R_SUCCESS) + goto foo; +} + +static void trace_listener_accept_input (trace_type_t *ttype, + unsigned length, char *buf) +{ + struct in_addr *addr; + u_int16_t *remote_port; + u_int16_t *local_port; + omapi_connection_object_t *obj; + isc_result_t status; + struct sockaddr_in remote_addr; + + addr = (struct in_addr *)buf; + remote_port = (u_int16_t *)(addr + 1); + local_port = remote_port + 1; + + memset (&remote_addr, 0, sizeof remote_addr); + remote_addr.sin_addr = *addr; + remote_addr.sin_port = *remote_port; + + omapi_array_foreach_begin (trace_listeners, + omapi_listener_object_t, lp) { + if (lp -> address.sin_port == *local_port) { + obj = (omapi_connection_object_t *)0; + status = omapi_listener_connect (&obj, + lp, 0, &remote_addr); + omapi_listener_dereference (&lp, MDL); + return; + } + } omapi_array_foreach_end (trace_listeners, + omapi_listener_object_t, lp); + log_error ("trace_listener_accept: %s from %s/%d to port %d", + "unexpected connect", + inet_ntoa (*addr), *remote_port, *local_port); +} + +static void trace_listener_accept_stop (trace_type_t *ttype) { } + + +#endif + +isc_result_t omapi_listener_configure_security (omapi_object_t *h, + isc_result_t (*verify_addr) + (omapi_object_t *, + omapi_addr_t *)) +{ + omapi_listener_object_t *l; + + if (h -> type != omapi_type_listener) + return ISC_R_INVALIDARG; + l = (omapi_listener_object_t *)h; + + l -> verify_addr = verify_addr; + + return ISC_R_SUCCESS; +} + +isc_result_t omapi_listener_set_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_typed_data_t *value) +{ + if (h -> type != omapi_type_listener) + return ISC_R_INVALIDARG; + + if (h -> inner && h -> inner -> type -> set_value) + return (*(h -> inner -> type -> set_value)) + (h -> inner, id, name, value); + return ISC_R_NOTFOUND; +} + +isc_result_t omapi_listener_get_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_value_t **value) +{ + if (h -> type != omapi_type_listener) + return ISC_R_INVALIDARG; + + if (h -> inner && h -> inner -> type -> get_value) + return (*(h -> inner -> type -> get_value)) + (h -> inner, id, name, value); + return ISC_R_NOTFOUND; +} + +isc_result_t omapi_listener_destroy (omapi_object_t *h, + const char *file, int line) +{ + omapi_listener_object_t *l; + + if (h -> type != omapi_type_listener) + return ISC_R_INVALIDARG; + l = (omapi_listener_object_t *)h; + +#ifdef DEBUG_PROTOCOL + log_debug ("omapi_listener_destroy()"); +#endif + + if (l -> socket != -1) { + close (l -> socket); + l -> socket = -1; + } + return ISC_R_SUCCESS; +} + +isc_result_t omapi_listener_signal_handler (omapi_object_t *h, + const char *name, va_list ap) +{ + if (h -> type != omapi_type_listener) + return ISC_R_INVALIDARG; + + if (h -> inner && h -> inner -> type -> signal_handler) + return (*(h -> inner -> type -> signal_handler)) (h -> inner, + name, ap); + return ISC_R_NOTFOUND; +} + +/* Write all the published values associated with the object through the + specified connection. */ + +isc_result_t omapi_listener_stuff_values (omapi_object_t *c, + omapi_object_t *id, + omapi_object_t *l) +{ + int i; + + if (l -> type != omapi_type_listener) + return ISC_R_INVALIDARG; + + if (l -> inner && l -> inner -> type -> stuff_values) + return (*(l -> inner -> type -> stuff_values)) (c, id, + l -> inner); + return ISC_R_SUCCESS; +} + diff --git a/contrib/isc-dhcp/omapip/message.c b/contrib/isc-dhcp/omapip/message.c new file mode 100644 index 0000000..ffdae85 --- /dev/null +++ b/contrib/isc-dhcp/omapip/message.c @@ -0,0 +1,769 @@ +/* message.c + + Subroutines for dealing with message objects. */ + +/* + * Copyright (c) 1999-2000 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. + */ + +#include <omapip/omapip_p.h> + +OMAPI_OBJECT_ALLOC (omapi_message, + omapi_message_object_t, omapi_type_message) + +omapi_message_object_t *omapi_registered_messages; + +isc_result_t omapi_message_new (omapi_object_t **o, const char *file, int line) +{ + omapi_message_object_t *m; + omapi_object_t *g; + isc_result_t status; + + m = (omapi_message_object_t *)0; + status = omapi_message_allocate (&m, file, line); + if (status != ISC_R_SUCCESS) + return status; + + g = (omapi_object_t *)0; + status = omapi_generic_new (&g, file, line); + if (status != ISC_R_SUCCESS) { + dfree (m, file, line); + return status; + } + status = omapi_object_reference (&m -> inner, g, file, line); + if (status != ISC_R_SUCCESS) { + omapi_object_dereference ((omapi_object_t **)&m, file, line); + omapi_object_dereference (&g, file, line); + return status; + } + status = omapi_object_reference (&g -> outer, + (omapi_object_t *)m, file, line); + + if (status != ISC_R_SUCCESS) { + omapi_object_dereference ((omapi_object_t **)&m, file, line); + omapi_object_dereference (&g, file, line); + return status; + } + + status = omapi_object_reference (o, (omapi_object_t *)m, file, line); + omapi_message_dereference (&m, file, line); + omapi_object_dereference (&g, file, line); + if (status != ISC_R_SUCCESS) + return status; + + return status; +} + +isc_result_t omapi_message_set_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_typed_data_t *value) +{ + omapi_message_object_t *m; + isc_result_t status; + + if (h -> type != omapi_type_message) + return ISC_R_INVALIDARG; + m = (omapi_message_object_t *)h; + + /* Can't set authlen. */ + + /* Can set authenticator, but the value must be typed data. */ + if (!omapi_ds_strcmp (name, "authenticator")) { + if (m -> authenticator) + omapi_typed_data_dereference (&m -> authenticator, + MDL); + omapi_typed_data_reference (&m -> authenticator, value, MDL); + return ISC_R_SUCCESS; + + } else if (!omapi_ds_strcmp (name, "object")) { + if (value -> type != omapi_datatype_object) + return ISC_R_INVALIDARG; + if (m -> object) + omapi_object_dereference (&m -> object, MDL); + omapi_object_reference (&m -> object, value -> u.object, MDL); + return ISC_R_SUCCESS; + + } else if (!omapi_ds_strcmp (name, "notify-object")) { + if (value -> type != omapi_datatype_object) + return ISC_R_INVALIDARG; + if (m -> notify_object) + omapi_object_dereference (&m -> notify_object, MDL); + omapi_object_reference (&m -> notify_object, + value -> u.object, MDL); + return ISC_R_SUCCESS; + + /* Can set authid, but it has to be an integer. */ + } else if (!omapi_ds_strcmp (name, "authid")) { + if (value -> type != omapi_datatype_int) + return ISC_R_INVALIDARG; + m -> authid = value -> u.integer; + return ISC_R_SUCCESS; + + /* Can set op, but it has to be an integer. */ + } else if (!omapi_ds_strcmp (name, "op")) { + if (value -> type != omapi_datatype_int) + return ISC_R_INVALIDARG; + m -> op = value -> u.integer; + return ISC_R_SUCCESS; + + /* Handle also has to be an integer. */ + } else if (!omapi_ds_strcmp (name, "handle")) { + if (value -> type != omapi_datatype_int) + return ISC_R_INVALIDARG; + m -> h = value -> u.integer; + return ISC_R_SUCCESS; + + /* Transaction ID has to be an integer. */ + } else if (!omapi_ds_strcmp (name, "id")) { + if (value -> type != omapi_datatype_int) + return ISC_R_INVALIDARG; + m -> id = value -> u.integer; + return ISC_R_SUCCESS; + + /* Remote transaction ID has to be an integer. */ + } else if (!omapi_ds_strcmp (name, "rid")) { + if (value -> type != omapi_datatype_int) + return ISC_R_INVALIDARG; + m -> rid = value -> u.integer; + return ISC_R_SUCCESS; + } + + /* Try to find some inner object that can take the value. */ + if (h -> inner && h -> inner -> type -> set_value) { + status = ((*(h -> inner -> type -> set_value)) + (h -> inner, id, name, value)); + if (status == ISC_R_SUCCESS) + return status; + } + + return ISC_R_NOTFOUND; +} + +isc_result_t omapi_message_get_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_value_t **value) +{ + omapi_message_object_t *m; + if (h -> type != omapi_type_message) + return ISC_R_INVALIDARG; + m = (omapi_message_object_t *)h; + + /* Look for values that are in the message data structure. */ + if (!omapi_ds_strcmp (name, "authlen")) + return omapi_make_int_value (value, name, (int)m -> authlen, + MDL); + else if (!omapi_ds_strcmp (name, "authenticator")) { + if (m -> authenticator) + return omapi_make_value (value, name, + m -> authenticator, MDL); + else + return ISC_R_NOTFOUND; + } else if (!omapi_ds_strcmp (name, "authid")) { + return omapi_make_int_value (value, + name, (int)m -> authid, MDL); + } else if (!omapi_ds_strcmp (name, "op")) { + return omapi_make_int_value (value, name, (int)m -> op, MDL); + } else if (!omapi_ds_strcmp (name, "handle")) { + return omapi_make_int_value (value, name, (int)m -> h, MDL); + } else if (!omapi_ds_strcmp (name, "id")) { + return omapi_make_int_value (value, name, (int)m -> id, MDL); + } else if (!omapi_ds_strcmp (name, "rid")) { + return omapi_make_int_value (value, name, (int)m -> rid, MDL); + } + + /* See if there's an inner object that has the value. */ + if (h -> inner && h -> inner -> type -> get_value) + return (*(h -> inner -> type -> get_value)) + (h -> inner, id, name, value); + return ISC_R_NOTFOUND; +} + +isc_result_t omapi_message_destroy (omapi_object_t *h, + const char *file, int line) +{ + int i; + + omapi_message_object_t *m; + if (h -> type != omapi_type_message) + return ISC_R_INVALIDARG; + m = (omapi_message_object_t *)h; + if (m -> authenticator) { + omapi_typed_data_dereference (&m -> authenticator, file, line); + } + if (!m -> prev && omapi_registered_messages != m) + omapi_message_unregister (h); + if (m -> id_object) + omapi_object_dereference (&m -> id_object, file, line); + if (m -> object) + omapi_object_dereference (&m -> object, file, line); + if (m -> notify_object) + omapi_object_dereference (&m -> notify_object, file, line); + if (m -> protocol_object) + omapi_protocol_dereference (&m -> protocol_object, file, line); + return ISC_R_SUCCESS; +} + +isc_result_t omapi_message_signal_handler (omapi_object_t *h, + const char *name, va_list ap) +{ + omapi_message_object_t *m; + if (h -> type != omapi_type_message) + return ISC_R_INVALIDARG; + m = (omapi_message_object_t *)h; + + if (!strcmp (name, "status")) { + if (m -> notify_object && + m -> notify_object -> type -> signal_handler) + return ((m -> notify_object -> type -> signal_handler)) + (m -> notify_object, name, ap); + else if (m -> object && m -> object -> type -> signal_handler) + return ((m -> object -> type -> signal_handler)) + (m -> object, name, ap); + } + if (h -> inner && h -> inner -> type -> signal_handler) + return (*(h -> inner -> type -> signal_handler)) (h -> inner, + name, ap); + return ISC_R_NOTFOUND; +} + +/* Write all the published values associated with the object through the + specified connection. */ + +isc_result_t omapi_message_stuff_values (omapi_object_t *c, + omapi_object_t *id, + omapi_object_t *m) +{ + int i; + + if (m -> type != omapi_type_message) + return ISC_R_INVALIDARG; + + if (m -> inner && m -> inner -> type -> stuff_values) + return (*(m -> inner -> type -> stuff_values)) (c, id, + m -> inner); + return ISC_R_SUCCESS; +} + +isc_result_t omapi_message_register (omapi_object_t *mo) +{ + omapi_message_object_t *m; + + if (mo -> type != omapi_type_message) + return ISC_R_INVALIDARG; + m = (omapi_message_object_t *)mo; + + /* Already registered? */ + if (m -> prev || m -> next || omapi_registered_messages == m) + return ISC_R_INVALIDARG; + + if (omapi_registered_messages) { + omapi_object_reference + ((omapi_object_t **)&m -> next, + (omapi_object_t *)omapi_registered_messages, MDL); + omapi_object_reference + ((omapi_object_t **)&omapi_registered_messages -> prev, + (omapi_object_t *)m, MDL); + omapi_object_dereference + ((omapi_object_t **)&omapi_registered_messages, MDL); + } + omapi_object_reference + ((omapi_object_t **)&omapi_registered_messages, + (omapi_object_t *)m, MDL); + return ISC_R_SUCCESS;; +} + +isc_result_t omapi_message_unregister (omapi_object_t *mo) +{ + omapi_message_object_t *m; + omapi_message_object_t *n; + + if (mo -> type != omapi_type_message) + return ISC_R_INVALIDARG; + m = (omapi_message_object_t *)mo; + + /* Not registered? */ + if (!m -> prev && omapi_registered_messages != m) + return ISC_R_INVALIDARG; + + n = (omapi_message_object_t *)0; + if (m -> next) { + omapi_object_reference ((omapi_object_t **)&n, + (omapi_object_t *)m -> next, MDL); + omapi_object_dereference ((omapi_object_t **)&m -> next, MDL); + } + if (m -> prev) { + omapi_message_object_t *tmp = (omapi_message_object_t *)0; + omapi_object_reference ((omapi_object_t **)&tmp, + (omapi_object_t *)m -> prev, MDL); + omapi_object_dereference ((omapi_object_t **)&m -> prev, MDL); + if (tmp -> next) + omapi_object_dereference + ((omapi_object_t **)&tmp -> next, MDL); + if (n) + omapi_object_reference + ((omapi_object_t **)&tmp -> next, + (omapi_object_t *)n, MDL); + omapi_object_dereference ((omapi_object_t **)&tmp, MDL); + } else { + omapi_object_dereference + ((omapi_object_t **)&omapi_registered_messages, MDL); + if (n) + omapi_object_reference + ((omapi_object_t **)&omapi_registered_messages, + (omapi_object_t *)n, MDL); + } + if (n) + omapi_object_dereference ((omapi_object_t **)&n, MDL); + return ISC_R_SUCCESS; +} + +#ifdef DEBUG_PROTOCOL +static const char *omapi_message_op_name(int op) { + switch (op) { + case OMAPI_OP_OPEN: return "OMAPI_OP_OPEN"; + case OMAPI_OP_REFRESH: return "OMAPI_OP_REFRESH"; + case OMAPI_OP_UPDATE: return "OMAPI_OP_UPDATE"; + case OMAPI_OP_STATUS: return "OMAPI_OP_STATUS"; + case OMAPI_OP_DELETE: return "OMAPI_OP_DELETE"; + case OMAPI_OP_NOTIFY: return "OMAPI_OP_NOTIFY"; + default: return "(unknown op)"; + } +} +#endif + +static isc_result_t +omapi_message_process_internal (omapi_object_t *, omapi_object_t *); + +isc_result_t omapi_message_process (omapi_object_t *mo, omapi_object_t *po) +{ + isc_result_t status; +#if defined (DEBUG_MEMORY_LEAKAGE) + unsigned long previous_outstanding = dmalloc_outstanding; +#endif + + status = omapi_message_process_internal (mo, po); + +#if defined (DEBUG_MEMORY_LEAKAGE) && 0 + log_info ("generation %ld: %ld new, %ld outstanding, %ld long-term", + dmalloc_generation, + dmalloc_outstanding - previous_outstanding, + dmalloc_outstanding, dmalloc_longterm); +#endif +#if defined (DEBUG_MEMORY_LEAKAGE) && 0 + dmalloc_dump_outstanding (); +#endif +#if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY) && 0 + dump_rc_history (); +#endif + + return status; +} + +static isc_result_t +omapi_message_process_internal (omapi_object_t *mo, omapi_object_t *po) +{ + omapi_message_object_t *message, *m; + omapi_object_t *object = (omapi_object_t *)0; + omapi_value_t *tv = (omapi_value_t *)0; + unsigned long create, update, exclusive; + unsigned long wsi; + isc_result_t status, waitstatus; + omapi_object_type_t *type; + + if (mo -> type != omapi_type_message) + return ISC_R_INVALIDARG; + message = (omapi_message_object_t *)mo; + +#ifdef DEBUG_PROTOCOL + log_debug ("omapi_message_process(): " + "op=%s handle=%#x id=%#x rid=%#x", + omapi_message_op_name (message -> op), + message -> h, message -> id, message -> rid); +#endif + + if (message -> rid) { + for (m = omapi_registered_messages; m; m = m -> next) + if (m -> id == message -> rid) + break; + /* If we don't have a real message corresponding to + the message ID to which this message claims it is a + response, something's fishy. */ + if (!m) + return ISC_R_NOTFOUND; + /* The authenticator on responses must match the initial + message. */ + if (message -> authid != m -> authid) + return ISC_R_NOTFOUND; + } else { + m = (omapi_message_object_t *)0; + + /* All messages must have an authenticator, with the exception + of messages that are opening a new authenticator. */ + if (omapi_protocol_authenticated (po) && + !message -> id_object && + message -> op != OMAPI_OP_OPEN) { + return omapi_protocol_send_status + (po, message -> id_object, ISC_R_NOKEYS, + message -> id, "No authenticator on message"); + } + } + + switch (message -> op) { + case OMAPI_OP_OPEN: + if (m) { + return omapi_protocol_send_status + (po, message -> id_object, ISC_R_INVALIDARG, + message -> id, "OPEN can't be a response"); + } + + /* Get the type of the requested object, if one was + specified. */ + status = omapi_get_value_str (mo, message -> id_object, + "type", &tv); + if (status == ISC_R_SUCCESS && + (tv -> value -> type == omapi_datatype_data || + tv -> value -> type == omapi_datatype_string)) { + for (type = omapi_object_types; + type; type = type -> next) + if (!omapi_td_strcmp (tv -> value, + type -> name)) + break; + } else + type = (omapi_object_type_t *)0; + if (tv) + omapi_value_dereference (&tv, MDL); + + /* If this object had no authenticator, the requested object + must be an authenticator object. */ + if (omapi_protocol_authenticated (po) && + !message -> id_object && + type != omapi_type_auth_key) { + return omapi_protocol_send_status + (po, message -> id_object, ISC_R_NOKEYS, + message -> id, "No authenticator on message"); + } + + /* Get the create flag. */ + status = omapi_get_value_str (mo, message -> id_object, + "create", &tv); + if (status == ISC_R_SUCCESS) { + status = omapi_get_int_value (&create, tv -> value); + omapi_value_dereference (&tv, MDL); + if (status != ISC_R_SUCCESS) { + return omapi_protocol_send_status + (po, message -> id_object, + status, message -> id, + "invalid create flag value"); + } + } else + create = 0; + + /* Get the update flag. */ + status = omapi_get_value_str (mo, message -> id_object, + "update", &tv); + if (status == ISC_R_SUCCESS) { + status = omapi_get_int_value (&update, tv -> value); + omapi_value_dereference (&tv, MDL); + if (status != ISC_R_SUCCESS) { + return omapi_protocol_send_status + (po, message -> id_object, + status, message -> id, + "invalid update flag value"); + } + } else + update = 0; + + /* Get the exclusive flag. */ + status = omapi_get_value_str (mo, message -> id_object, + "exclusive", &tv); + if (status == ISC_R_SUCCESS) { + status = omapi_get_int_value (&exclusive, tv -> value); + omapi_value_dereference (&tv, MDL); + if (status != ISC_R_SUCCESS) { + return omapi_protocol_send_status + (po, message -> id_object, + status, message -> id, + "invalid exclusive flag value"); + } + } else + exclusive = 0; + + /* If we weren't given a type, look the object up with + the handle. */ + if (!type) { + if (create) { + return omapi_protocol_send_status + (po, message -> id_object, + ISC_R_INVALIDARG, + message -> id, + "type required on create"); + } + goto refresh; + } + + /* If the type doesn't provide a lookup method, we can't + look up the object. */ + if (!type -> lookup) { + return omapi_protocol_send_status + (po, message -> id_object, + ISC_R_NOTIMPLEMENTED, message -> id, + "unsearchable object type"); + } + + status = (*(type -> lookup)) (&object, message -> id_object, + message -> object); + + if (status != ISC_R_SUCCESS && + status != ISC_R_NOTFOUND && + status != ISC_R_NOKEYS) { + return omapi_protocol_send_status + (po, message -> id_object, + status, message -> id, + "object lookup failed"); + } + + /* If we didn't find the object and we aren't supposed to + create it, return an error. */ + if (status == ISC_R_NOTFOUND && !create) { + return omapi_protocol_send_status + (po, message -> id_object, + ISC_R_NOTFOUND, message -> id, + "no object matches specification"); + } + + /* If we found an object, we're supposed to be creating an + object, and we're not supposed to have found an object, + return an error. */ + if (status == ISC_R_SUCCESS && create && exclusive) { + omapi_object_dereference (&object, MDL); + return omapi_protocol_send_status + (po, message -> id_object, + ISC_R_EXISTS, message -> id, + "specified object already exists"); + } + + /* If we're creating the object, do it now. */ + if (!object) { + status = omapi_object_create (&object, + message -> id_object, + type); + if (status != ISC_R_SUCCESS) { + return omapi_protocol_send_status + (po, message -> id_object, + status, message -> id, + "can't create new object"); + } + } + + /* If we're updating it, do so now. */ + if (create || update) { + /* This check does not belong here. */ + if (object -> type == omapi_type_auth_key) { + omapi_object_dereference (&object, MDL); + return omapi_protocol_send_status + (po, message -> id_object, + status, message -> id, + "can't update object"); + } + + status = omapi_object_update (object, + message -> id_object, + message -> object, + message -> h); + if (status != ISC_R_SUCCESS) { + omapi_object_dereference (&object, MDL); + return omapi_protocol_send_status + (po, message -> id_object, + status, message -> id, + "can't update object"); + } + } + + /* If this is an authenticator object, add it to the active + set for the connection. */ + if (object -> type == omapi_type_auth_key) { + omapi_handle_t handle; + status = omapi_object_handle (&handle, object); + if (status != ISC_R_SUCCESS) { + omapi_object_dereference (&object, MDL); + return omapi_protocol_send_status + (po, message -> id_object, + status, message -> id, + "can't select authenticator"); + } + + status = omapi_protocol_add_auth (po, object, handle); + if (status != ISC_R_SUCCESS) { + omapi_object_dereference (&object, MDL); + return omapi_protocol_send_status + (po, message -> id_object, + status, message -> id, + "can't select authenticator"); + } + } + + /* Now send the new contents of the object back in + response. */ + goto send; + + case OMAPI_OP_REFRESH: + refresh: + status = omapi_handle_lookup (&object, message -> h); + if (status != ISC_R_SUCCESS) { + return omapi_protocol_send_status + (po, message -> id_object, + status, message -> id, + "no matching handle"); + } + send: + status = omapi_protocol_send_update (po, message -> id_object, + message -> id, object); + omapi_object_dereference (&object, MDL); + return status; + + case OMAPI_OP_UPDATE: + if (m && m -> object) { + omapi_object_reference (&object, m -> object, MDL); + } else { + status = omapi_handle_lookup (&object, message -> h); + if (status != ISC_R_SUCCESS) { + return omapi_protocol_send_status + (po, message -> id_object, + status, message -> id, + "no matching handle"); + } + } + + if (object -> type == omapi_type_auth_key || + (object -> inner && + object -> inner -> type == omapi_type_auth_key)) { + if (!m) { + omapi_object_dereference (&object, MDL); + return omapi_protocol_send_status + (po, message -> id_object, + status, message -> id, + "cannot update authenticator"); + } + + status = omapi_protocol_add_auth (po, object, + message -> h); + } else { + status = omapi_object_update (object, + message -> id_object, + message -> object, + message -> h); + } + if (status != ISC_R_SUCCESS) { + omapi_object_dereference (&object, MDL); + if (!message -> rid) + return omapi_protocol_send_status + (po, message -> id_object, + status, message -> id, + "can't update object"); + if (m) + omapi_signal ((omapi_object_t *)m, + "status", status, + (omapi_typed_data_t *)0); + return ISC_R_SUCCESS; + } + if (!message -> rid) + status = omapi_protocol_send_status + (po, message -> id_object, ISC_R_SUCCESS, + message -> id, (char *)0); + if (m) + omapi_signal ((omapi_object_t *)m, + "status", ISC_R_SUCCESS, + (omapi_typed_data_t *)0); + return status; + + case OMAPI_OP_NOTIFY: + return omapi_protocol_send_status + (po, message -> id_object, ISC_R_NOTIMPLEMENTED, + message -> id, "notify not implemented yet"); + + case OMAPI_OP_STATUS: + /* The return status of a request. */ + if (!m) + return ISC_R_UNEXPECTED; + + /* Get the wait status. */ + status = omapi_get_value_str (mo, message -> id_object, + "result", &tv); + if (status == ISC_R_SUCCESS) { + status = omapi_get_int_value (&wsi, tv -> value); + waitstatus = wsi; + omapi_value_dereference (&tv, MDL); + if (status != ISC_R_SUCCESS) + waitstatus = ISC_R_UNEXPECTED; + } else + waitstatus = ISC_R_UNEXPECTED; + + status = omapi_get_value_str (mo, message -> id_object, + "message", &tv); + omapi_signal ((omapi_object_t *)m, "status", waitstatus, tv); + if (status == ISC_R_SUCCESS) + omapi_value_dereference (&tv, MDL); + return ISC_R_SUCCESS; + + case OMAPI_OP_DELETE: + status = omapi_handle_lookup (&object, message -> h); + if (status != ISC_R_SUCCESS) { + return omapi_protocol_send_status + (po, message -> id_object, + status, message -> id, + "no matching handle"); + } + + if (!object -> type -> remove) + return omapi_protocol_send_status + (po, message -> id_object, + ISC_R_NOTIMPLEMENTED, message -> id, + "no remove method for object"); + + status = (*(object -> type -> remove)) (object, + message -> id_object); + omapi_object_dereference (&object, MDL); + + return omapi_protocol_send_status (po, message -> id_object, + status, message -> id, + (char *)0); + } + return ISC_R_NOTIMPLEMENTED; +} diff --git a/contrib/isc-dhcp/omapip/mrtrace.c b/contrib/isc-dhcp/omapip/mrtrace.c new file mode 100644 index 0000000..c353990 --- /dev/null +++ b/contrib/isc-dhcp/omapip/mrtrace.c @@ -0,0 +1,488 @@ +/* mrtrace.c + + Subroutines that support minires tracing... */ + +/* + * Copyright (c) 2001 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon, as part of a project for Nominum, Inc. To learn more + * about the Internet Software Consortium, see http://www.isc.org/. To + * learn more about Nominum, Inc., see ``http://www.nominum.com''. + */ + +#include <omapip/omapip_p.h> + +#include "minires/minires.h" +#include "arpa/nameser.h" + +static void trace_mr_output_input (trace_type_t *, unsigned, char *); +static void trace_mr_output_stop (trace_type_t *); +static void trace_mr_input_input (trace_type_t *, unsigned, char *); +static void trace_mr_input_stop (trace_type_t *); +static void trace_mr_statp_input (trace_type_t *, unsigned, char *); +static void trace_mr_statp_stop (trace_type_t *); +static void trace_mr_randomid_input (trace_type_t *, unsigned, char *); +static void trace_mr_randomid_stop (trace_type_t *); +trace_type_t *trace_mr_output; +trace_type_t *trace_mr_input; +trace_type_t *trace_mr_statp; +trace_type_t *trace_mr_randomid; +ssize_t trace_mr_send (int, void *, size_t, int); +ssize_t trace_mr_read_playback (struct sockaddr_in *, void *, size_t); +void trace_mr_read_record (struct sockaddr_in *, void *, ssize_t); +ssize_t trace_mr_recvfrom (int s, void *, size_t, int, + struct sockaddr *, SOCKLEN_T *); +ssize_t trace_mr_read (int, void *, size_t); +int trace_mr_connect (int s, struct sockaddr *, SOCKLEN_T); +int trace_mr_socket (int, int, int); +int trace_mr_bind (int, struct sockaddr *, SOCKLEN_T); +int trace_mr_close (int); +time_t trace_mr_time (time_t *); +int trace_mr_select (int, fd_set *, fd_set *, fd_set *, struct timeval *); +unsigned int trace_mr_res_randomid (unsigned int); + +extern time_t cur_time; + +#if defined (TRACING) +void trace_mr_init () +{ + trace_mr_output = trace_type_register ("mr-output", (void *)0, + trace_mr_output_input, + trace_mr_output_stop, MDL); + trace_mr_input = trace_type_register ("mr-input", (void *)0, + trace_mr_input_input, + trace_mr_input_stop, MDL); + trace_mr_statp = trace_type_register ("mr-statp", (void *)0, + trace_mr_statp_input, + trace_mr_statp_stop, MDL); + trace_mr_randomid = trace_type_register ("mr-randomid", (void *)0, + trace_mr_randomid_input, + trace_mr_randomid_stop, MDL); +} + +void trace_mr_statp_setup (res_state statp) +{ + unsigned buflen = 0; + char *buf = (char *)0; + isc_result_t status; + u_int32_t id; + int i; + + if (trace_playback ()) { + int nscount; + status = trace_get_packet (&trace_mr_statp, &buflen, &buf); + if (status != ISC_R_SUCCESS) { + log_error ("trace_mr_statp: no statp packet found."); + return; + } + nscount = buflen / sizeof (struct in_addr); + if (nscount * (sizeof (struct in_addr)) != buflen || + nscount < 1) { + log_error ("trace_mr_statp: bogus length: %d", + buflen); + return; + } + if (nscount > MAXNS) + nscount = MAXNS; + for (i = 0; i < nscount; i++) { +#if defined (HAVE_SA_LEN) + statp -> nsaddr_list [i].sin_len = + sizeof (struct sockaddr_in); +#endif + memset (&statp -> nsaddr_list [i].sin_zero, 0, + sizeof statp -> nsaddr_list [i].sin_zero); + statp -> nsaddr_list [i].sin_port = htons (53); /*XXX*/ + statp -> nsaddr_list [i].sin_family = AF_INET; + memcpy (&statp -> nsaddr_list [i].sin_addr, + (buf + i * (sizeof (struct in_addr))), + sizeof (struct in_addr)); + } + statp -> nscount = nscount; + dfree (buf, MDL); + buf = (char *)0; + } + if (trace_record ()) { + trace_iov_t *iov; + iov = dmalloc ((statp -> nscount * + sizeof (trace_iov_t)), MDL); + if (!iov) { + trace_stop (); + log_error ("No memory for statp iov."); + return; + } + for (i = 0; i < statp -> nscount; i++) { + iov [i].buf = + (char *)&statp -> nsaddr_list [i].sin_addr; + iov [i].len = sizeof (struct in_addr); + } + trace_write_packet_iov (trace_mr_statp, i, iov, MDL); + dfree (iov, MDL); + } +} +#endif + +ssize_t trace_mr_send (int fd, void *msg, size_t len, int flags) +{ + ssize_t rv; +#if defined (TRACING) + isc_result_t status; + unsigned buflen = 0; + char *inbuf = (char *)0; + u_int32_t result; + u_int32_t sflags; + + if (trace_playback()) { + status = trace_get_packet (&trace_mr_output, &buflen, &inbuf); + if (status != ISC_R_SUCCESS) { + log_error ("trace_mr_recvfrom: no input found."); + errno = ECONNREFUSED; + return -1; + } + if (buflen < sizeof result) { + log_error ("trace_mr_recvfrom: data too short."); + errno = ECONNREFUSED; + dfree (inbuf, MDL); + return -1; + } + memcpy (&result, inbuf, sizeof result); + rv = ntohl (result); + dfree (inbuf, MDL); + } else +#endif + rv = send (fd, msg, len, flags); +#if defined (TRACING) + if (trace_record ()) { + trace_iov_t iov [3]; + result = htonl (rv); + sflags = htonl (flags); + iov [0].len = sizeof result; + iov [0].buf = (char *)&result; + iov [1].len = sizeof sflags; + iov [1].buf = (char *)&flags; + iov [2].len = len; + iov [2].buf = msg; + trace_write_packet_iov (trace_mr_output, 2, iov, MDL); + } +#endif + return rv; +} + +#if defined (TRACING) +ssize_t trace_mr_read_playback (struct sockaddr_in *from, + void *buf, size_t nbytes) +{ + isc_result_t status; + unsigned buflen = 0, left; + char *inbuf = (char *)0; + char *bufp; + u_int32_t result; + + status = trace_get_packet (&trace_mr_input, &buflen, &inbuf); + if (status != ISC_R_SUCCESS) { + log_error ("trace_mr_recvfrom: no input found."); + errno = ECONNREFUSED; + return -1; + } + if (buflen < sizeof result) { + log_error ("trace_mr_recvfrom: data too short."); + errno = ECONNREFUSED; + dfree (inbuf, MDL); + return -1; + } + bufp = inbuf; + left = buflen; + memcpy (&result, bufp, sizeof result); + result = ntohl (result); + bufp += sizeof result; + left -= sizeof result; + if (result == 0) { + if (left < ((sizeof from -> sin_port) + + sizeof (from -> sin_addr))) { + log_error ("trace_mr_recvfrom: data too short."); + errno = ECONNREFUSED; + dfree (inbuf, MDL); + return -1; + } + if (from) + memcpy (&from -> sin_addr, bufp, + sizeof from -> sin_addr); + bufp += sizeof from -> sin_addr; + left -= sizeof from -> sin_addr; + if (from) + memcpy (&from -> sin_port, bufp, + sizeof from -> sin_port); + bufp += sizeof from -> sin_port; + left -= sizeof from -> sin_port; + if (from) { + from -> sin_family = AF_INET; +#if defined(HAVE_SA_LEN) + from -> sin_len = sizeof (struct sockaddr_in); +#endif + memset (from -> sin_zero, 0, sizeof from -> sin_zero); + } + if (left > nbytes) { + log_error ("trace_mr_recvfrom: too much%s", + " data."); + errno = ECONNREFUSED; + dfree (inbuf, MDL); + return -1; + } + memcpy (buf, bufp, left); + dfree (inbuf, MDL); + return left; + } + errno = ECONNREFUSED; + return -1; +} + +void trace_mr_read_record (struct sockaddr_in *from, void *buf, ssize_t rv) +{ + trace_iov_t iov [4]; + u_int32_t result; + int iolen = 0; + static char zero [4] = { 0, 0, 0, 0 }; + + if (rv < 0) + result = htonl (errno); /* XXX */ + else + result = 0; + iov [iolen].buf = (char *)&result; + iov [iolen++].len = sizeof result; + if (rv > 0) { + if (from) { + iov [iolen].buf = (char *)&from -> sin_addr; + iov [iolen++].len = sizeof from -> sin_addr; + iov [iolen].buf = (char *)&from -> sin_port; + iov [iolen++].len = sizeof from -> sin_port; + } else { + iov [iolen].buf = zero; + iov [iolen++].len = sizeof from -> sin_addr; + iov [iolen].buf = zero; + iov [iolen++].len = sizeof from -> sin_port; + } + + iov [iolen].buf = buf; + iov [iolen++].len = rv; + } + trace_write_packet_iov (trace_mr_input, iolen, iov, MDL); +} +#endif + +ssize_t trace_mr_recvfrom (int s, void *buf, size_t len, int flags, + struct sockaddr *from, SOCKLEN_T *fromlen) +{ + ssize_t rv; + +#if defined (TRACING) + if (trace_playback ()) + rv = trace_mr_read_playback ((struct sockaddr_in *)from, + buf, len); + else +#endif + rv = recvfrom (s, buf, len, flags, from, fromlen); +#if defined (TRACING) + if (trace_record ()) { + trace_mr_read_record ((struct sockaddr_in *)from, buf, rv); + } +#endif + return rv; +} + +ssize_t trace_mr_read (int d, void *buf, size_t nbytes) +{ + ssize_t rv; + +#if defined (TRACING) + if (trace_playback ()) + rv = trace_mr_read_playback ((struct sockaddr_in *)0, + buf, nbytes); + else +#endif + rv = read (d, buf, nbytes); +#if defined (TRACING) + if (trace_record ()) { + trace_mr_read_record ((struct sockaddr_in *)0, buf, rv); + } +#endif + return rv; +} + +int trace_mr_connect (int s, struct sockaddr *name, SOCKLEN_T namelen) +{ +#if defined (TRACING) + if (!trace_playback ()) +#endif + return connect (s, name, namelen); +#if defined (TRACING) + return 0; +#endif +} + +int trace_mr_socket (int domain, int type, int protocol) +{ +#if defined (TRACING) + if (!trace_playback ()) +#endif + return socket (domain, type, protocol); +#if defined (TRACING) + return 100; +#endif +} + +int trace_mr_bind (int s, struct sockaddr *name, SOCKLEN_T namelen) +{ +#if defined (TRACING) + if (!trace_playback ()) +#endif + return bind (s, name, namelen); +#if defined (TRACING) + return 0; +#endif +} + +int trace_mr_close (int s) +{ +#if defined (TRACING) + if (!trace_playback ()) +#endif + return close (s); +#if defined (TRACING) + return 0; +#endif +} + +time_t trace_mr_time (time_t *tp) +{ +#if defined (TRACING) + if (trace_playback ()) { + if (tp) + *tp = cur_time; + return cur_time; + } +#endif + return time (tp); +} + +int trace_mr_select (int s, fd_set *r, fd_set *w, fd_set *x, struct timeval *t) +{ +#if defined (TRACING) + trace_type_t *ttp = (trace_type_t *)0; + + if (trace_playback ()) { + time_t nct = trace_snoop_time (&ttp); + time_t secr = t -> tv_sec; + t -> tv_sec = nct - cur_time; + if (t -> tv_sec > secr) + return 0; + if (ttp == trace_mr_input) + return 1; + return 0; + } +#endif + return select (s, r, w, x, t); +} + +unsigned int trace_mr_res_randomid (unsigned int oldid) +{ + u_int32_t id; + int rid = oldid; +#if defined (TRACING) + unsigned buflen = 0; + char *buf = (char *)0; + isc_result_t status; + + if (trace_playback ()) { + int nscount; + status = trace_get_packet (&trace_mr_randomid, &buflen, &buf); + if (status != ISC_R_SUCCESS) { + log_error ("trace_mr_statp: no statp packet found."); + return oldid; + } + if (buflen != sizeof id) { + log_error ("trace_mr_randomid: bogus length: %d", + buflen); + return oldid; + } + memcpy (&id, buf, sizeof id); + dfree (buf, MDL); + buf = (char *)0; + rid = ntohl (id); + } + if (trace_record ()) { + id = htonl (rid); + trace_write_packet (trace_mr_randomid, + sizeof id, (char *)&id, MDL); + } +#endif + return rid; +} + +#if defined (TRACING) +static void trace_mr_output_input (trace_type_t *ttype, + unsigned length, char *buf) +{ +} + +static void trace_mr_output_stop (trace_type_t *ttype) +{ +} + +static void trace_mr_input_input (trace_type_t *ttype, + unsigned length, char *buf) +{ + log_error ("unaccounted-for minires input."); +} + +static void trace_mr_input_stop (trace_type_t *ttype) +{ +} + +static void trace_mr_statp_input (trace_type_t *ttype, + unsigned length, char *buf) +{ + log_error ("unaccounted-for minires statp input."); +} + +static void trace_mr_statp_stop (trace_type_t *ttype) +{ +} + +static void trace_mr_randomid_input (trace_type_t *ttype, + unsigned length, char *buf) +{ + log_error ("unaccounted-for minires randomid input."); +} + +static void trace_mr_randomid_stop (trace_type_t *ttype) +{ +} +#endif diff --git a/contrib/isc-dhcp/omapip/omapi.3 b/contrib/isc-dhcp/omapip/omapi.3 new file mode 100644 index 0000000..112621d --- /dev/null +++ b/contrib/isc-dhcp/omapip/omapi.3 @@ -0,0 +1,254 @@ +.\" omapi.3 +.\" +.\" Copyright (c) 2000-2001 Internet Software Consortium. +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of The Internet Software Consortium nor the names +.\" of its contributors may be used to endorse or promote products derived +.\" from this software without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND +.\" CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, +.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +.\" DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR +.\" CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +.\" USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +.\" ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" This software has been written for the Internet Software Consortium +.\" by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. +.\" To learn more about the Internet Software Consortium, see +.\" ``http://www.isc.org/''. To learn more about Vixie Enterprises, +.\" see ``http://www.vix.com''. To learn more about Nominum, Inc., see +.\" ``http://www.nominum.com''. +.TH omapi 3 +.SH NAME +OMAPI - Object Management Application Programming Interface +.SH DESCRIPTION +.PP +OMAPI is an programming layer designed for controlling remote +applications, and for querying them for their state. It is currently +used by the ISC DHCP server and this outline addresses the parts of +OMAPI appropriate to the clients of DHCP server. It does this by also +describing the use of a thin API layered on top of OMAPI called +'dhcpctl' +.PP +OMAPI uses TCP/IP as the transport for server communication, and +security can be imposed by having the client and server +cryptographically sign messages using a shared secret. +.PP +dhcpctl works by presenting the client with handles to objects that +act as surrogates for the real objects in the server. For example a +client will create a handle for a lease object, and will request the +server to fill the lease handle's state. The client application can +then pull details such as the lease expiration time from the lease +handle. +.PP +Modifications can be made to the server state by creating handles to +new objects, or by modifying attributes of handles to existing +objects, and then instructing the server to update itself according to +the changes made. +.SH USAGE +.PP +The client application must always call dhcpctl_initialize() before +making calls to any other dhcpctl functions. This initializes +various internal data structures. +.PP +To create the connection to the server the client must use +dhcpctl_connect() function. As well as making the physical connection +it will also set up the connection data structures to do +authentication on each message, if that is required. +.PP +All the dhcpctl functions return an integer value of type +isc_result_t. A successful call will yield a result of +ISC_R_SUCCESS. If the call fails for a reason local to the client +(e.g. insufficient local memory, or invalid arguments to the call) +then the return value of the dhcpctl function will show that. If the +call succeeds but the server couldn't process the request the error +value from the server is returned through another way, shown below. +.PP +The easiest way to understand dhcpctl is to see it in action. The +following program is fully functional, but almost all error checking +has been removed to make is shorter and easier to understand. This +program will query the server running on the localhost for the details +of the lease for IP address 10.0.0.101. It will then print out the time +the lease ends. +.PP +.nf + #include <stdarg.h> + #include <sys/time.h> + #include <sys/socket.h> + #include <stdio.h> + #include <netinet/in.h> + + #include <isc/result.h> + #include <dhcpctl/dhcpctl.h> + + int main (int argc, char **argv) { + dhcpctl_data_string ipaddrstring = NULL; + dhcpctl_data_string value = NULL; +.fi +.PP +All modifications of handles and all accesses of handle data happen +via dhcpctl_data_string objects. +.PP +.nf + dhcpctl_handle connection = NULL; + dhcpctl_handle lease = NULL; + isc_result_t waitstatus; + struct in_addr convaddr; + time_t thetime; + + dhcpctl_initialize (); +.fi +.PP +Required first step. +.PP +.nf + dhcpctl_connect (&connection, "127.0.0.1", + 7911, 0); +.fi +.PP +Sets up the connection to the server. The server normally listens on +port 7911 unless configured to do otherwise. +.PP +.nf + dhcpctl_new_object (&lease, connection, + "lease"); +.fi +.PP +Here we create a handle to a lease. This call just sets up local data +structure. The server hasn't yet made any association between the +client's data structure and any lease it has. +.PP +.nf + memset (&ipaddrstring, 0, sizeof + ipaddrstring); + + inet_pton(AF_INET, "10.0.0.101", + &convaddr); + + omapi_data_string_new (&ipaddrstring, + 4, MDL); +.fi +.PP +Create a new data string to storing in the handle. +.PP +.nf + memcpy(ipaddrstring->value, &convaddr.s_addr, 4); + + dhcpctl_set_value (lease, ipaddrstring, + "ip-address"); +.fi +.PP +We're setting the ip-address attribute of the lease handle to the +given address. We've not set any other attributes so when the server +makes the association the ip address will be all it uses to look up +the lease in its tables. +.PP +.nf + dhcpctl_open_object (lease, connection, 0); +.fi +.PP +Here we prime the connection with the request to look up the lease in +the server and fill up the local handle with the attributes the server +will send over in its answer. +.PP +.nf + dhcpctl_wait_for_completion (lease, + &waitstatus); +.fi +.PP +This call causes the message to get sent to the server (the message to +look up the lease and send back the attribute values in the +answer). The value in the variable waitstatus when the function +returns will be the result from the server. If the message could +not be processed properly by the server then the error will be +reflected here. +.PP +.nf + if (waitstatus != ISC_R_SUCCESS) { + /* server not authoritative */ + exit (0); + } + + dhcpctl_data_string_dereference(&ipaddrstring, + MDL); +.fi +.PP +Clean-up memory we no longer need. +.PP +.nf + dhcpctl_get_value (&value, lease, "ends"); +.fi +.PP +Get the attribute named ``ends'' from the lease handle. This is a +4-byte integer of the time (in unix epoch seconds) that the lease +will expire. +.PP +.nf + + memcpy(&thetime, value->value, value->len); + dhcpctl_data_string_dereference(&value, MDL); + + fprintf (stdout, "ending time is %s", + ctime(&thetime)); + } + +.fi +.SH AUTHENTICATION +If the server demands authenticated connections then before opening +the connection the user must call dhcpctl_new_authenticator. +.PP +.nf + dhcpctl_handle authenticator = NULL; + const char *keyname = "a-key-name"; + const char *algorithm = "hmac-md5"; + const char *secret = "a-shared-secret"; + + dhcpctl_new_authenticator (&authenticator, + keyname, + algorithm, + secret, + strlen(secret) + 1); +.fi +.PP +The keyname, algorithm and secret must all match what is specified in +the server's dhcpd.conf file: +.PP +.nf + key "a-key-name" { + algorithm hmac-md5; + secret "a-shared-secret"; + }; + + # Set the omapi-key value to use + # authenticated connections + omapi-key "a-key-name"; +.fi +.PP +The authenticator handle that is created by the call to +dhcpctl_new_authenticator must be given as the last (the 4th) argument +to the call to dhcpctl_connect(). All messages will then be signed +with the given secret string using the specified algorithm. +.SH SEE ALSO +dhcpctl(3), omapi(3), dhcpd(8), dhclient(8), dhcpd.conf(5), dhclient.conf(5). +.SH AUTHOR +.B omapi +was created by Ted Lemon of Nominum, Inc. Information about Nominum +and support contracts for DHCP and BIND can be found at +.B http://www.nominum.com. This documentation was written by James +Brister of Nominum, Inc. diff --git a/contrib/isc-dhcp/omapip/protocol.c b/contrib/isc-dhcp/omapip/protocol.c new file mode 100644 index 0000000..c61fa19 --- /dev/null +++ b/contrib/isc-dhcp/omapip/protocol.c @@ -0,0 +1,1319 @@ +/* protocol.c + + Functions supporting the object management protocol... */ + +/* + * Copyright (c) 1999-2000 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. + */ + +#include <omapip/omapip_p.h> + +OMAPI_OBJECT_ALLOC (omapi_protocol, omapi_protocol_object_t, + omapi_type_protocol) +OMAPI_OBJECT_ALLOC (omapi_protocol_listener, omapi_protocol_listener_object_t, + omapi_type_protocol_listener) + +isc_result_t omapi_protocol_connect (omapi_object_t *h, + const char *server_name, + unsigned port, + omapi_object_t *a) +{ + isc_result_t rstatus, status; + omapi_protocol_object_t *obj; + +#ifdef DEBUG_PROTOCOL + log_debug ("omapi_protocol_connect(%s port=%d)", server_name, port); +#endif + + obj = (omapi_protocol_object_t *)0; + status = omapi_protocol_allocate (&obj, MDL); + if (status != ISC_R_SUCCESS) + return status; + + rstatus = omapi_connect ((omapi_object_t *)obj, server_name, port); + if (rstatus != ISC_R_SUCCESS && rstatus != ISC_R_INCOMPLETE) { + omapi_protocol_dereference (&obj, MDL); + return rstatus; + } + status = omapi_object_reference (&h -> outer, + (omapi_object_t *)obj, MDL); + if (status != ISC_R_SUCCESS) { + omapi_protocol_dereference (&obj, MDL); + return status; + } + status = omapi_object_reference (&obj -> inner, h, MDL); + if (status != ISC_R_SUCCESS) { + omapi_protocol_dereference (&obj, MDL); + return status; + } + + /* If we were passed a default authenticator, store it now. We'll + open it once we're connected. */ + if (a) { + obj -> default_auth = + dmalloc (sizeof(omapi_remote_auth_t), MDL); + if (!obj -> default_auth) { + omapi_protocol_dereference (&obj, MDL); + return ISC_R_NOMEMORY; + } + + obj -> default_auth -> next = (omapi_remote_auth_t *)0; + status = omapi_object_reference (&obj -> default_auth -> a, + a, MDL); + if (status != ISC_R_SUCCESS) { + dfree (obj -> default_auth, MDL); + omapi_protocol_dereference (&obj, MDL); + return status; + } + + obj -> insecure = 0; + rstatus = ISC_R_INCOMPLETE; + } else { + obj -> insecure = 1; +#if 0 + status = ISC_R_SUCCESS; +#endif + } + + omapi_protocol_dereference (&obj, MDL); + return rstatus; +} + +/* Send the protocol introduction message. */ +isc_result_t omapi_protocol_send_intro (omapi_object_t *h, + unsigned ver, + unsigned hsize) +{ + isc_result_t status; + omapi_protocol_object_t *p; + +#ifdef DEBUG_PROTOCOL + log_debug ("omapi_protocol_send_intro()"); +#endif + + if (h -> type != omapi_type_protocol) + return ISC_R_INVALIDARG; + p = (omapi_protocol_object_t *)h; + + if (!h -> outer || h -> outer -> type != omapi_type_connection) + return ISC_R_NOTCONNECTED; + + status = omapi_connection_put_uint32 (h -> outer, ver); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_connection_put_uint32 (h -> outer, hsize); + + if (status != ISC_R_SUCCESS) + return status; + + /* Require the other end to send an intro - this kicks off the + protocol input state machine. */ + p -> state = omapi_protocol_intro_wait; + status = omapi_connection_require (h -> outer, 8); + if (status != ISC_R_SUCCESS && status != ISC_R_NOTYET) + return status; + + /* Make up an initial transaction ID for this connection. */ + p -> next_xid = random (); + return ISC_R_SUCCESS; +} + +isc_result_t omapi_protocol_send_message (omapi_object_t *po, + omapi_object_t *id, + omapi_object_t *mo, + omapi_object_t *omo) +{ + omapi_protocol_object_t *p; + omapi_object_t *c; + omapi_message_object_t *m, *om; + omapi_remote_auth_t *ra; + omapi_value_t *signature; + isc_result_t status; + u_int32_t foo; + unsigned auth_len; + + if (po -> type != omapi_type_protocol || + !po -> outer || po -> outer -> type != omapi_type_connection || + mo -> type != omapi_type_message) + return ISC_R_INVALIDARG; + if (omo && omo -> type != omapi_type_message) + return ISC_R_INVALIDARG; + p = (omapi_protocol_object_t *)po; + c = (omapi_object_t *)(po -> outer); + m = (omapi_message_object_t *)mo; + om = (omapi_message_object_t *)omo; + +#ifdef DEBUG_PROTOCOL + log_debug ("omapi_protocol_send_message()" + "op=%ld handle=%#lx id=%#lx rid=%#lx", + (long)m -> op, + (long)(m -> object ? m -> object -> handle : m -> handle), + (long)p -> next_xid, (long)m -> rid); +#endif + + /* Find the authid to use for this message. */ + if (id) { + for (ra = p -> remote_auth_list; ra; ra = ra -> next) { + if (ra -> a == id) { + break; + } + } + + if (!ra) + return ISC_R_KEY_UNKNOWN; + } else if (p -> remote_auth_list) { + ra = p -> default_auth; + } else { + ra = (omapi_remote_auth_t *)0; + } + + if (ra) { + m -> authid = ra -> remote_handle; + status = omapi_object_reference (&m -> id_object, + ra -> a, MDL); + if (status != ISC_R_SUCCESS) + return status; + } + + /* Write the ID of the authentication key we're using. */ + status = omapi_connection_put_uint32 (c, ra ? ra -> remote_handle : 0); + if (status != ISC_R_SUCCESS) { + omapi_disconnect (c, 1); + return status; + } + + /* Activate the authentication key on the connection. */ + auth_len = 0; + if (ra) { + status = omapi_set_object_value (c, (omapi_object_t *)0, + "output-authenticator", + ra -> a); + if (status != ISC_R_SUCCESS) { + omapi_disconnect (c, 1); + return status; + } + + status = omapi_connection_output_auth_length (c, &auth_len); + if (status != ISC_R_SUCCESS) { + omapi_disconnect (c, 1); + return status; + } + } + + /* Write the authenticator length */ + status = omapi_connection_put_uint32 (c, auth_len); + if (status != ISC_R_SUCCESS) { + omapi_disconnect (c, 1); + return status; + } + + /* Write the opcode. */ + status = omapi_connection_put_uint32 (c, m -> op); + if (status != ISC_R_SUCCESS) { + omapi_disconnect (c, 1); + return status; + } + + /* Write the handle. If we've been given an explicit handle, use + that. Otherwise, use the handle of the object we're sending. + The caller is responsible for arranging for one of these handles + to be set (or not). */ + status = omapi_connection_put_uint32 (c, (m -> h + ? m -> h + : (m -> object + ? m -> object -> handle + : 0))); + if (status != ISC_R_SUCCESS) { + omapi_disconnect (c, 1); + return status; + } + + /* Set and write the transaction ID. */ + m -> id = p -> next_xid++; + status = omapi_connection_put_uint32 (c, m -> id); + if (status != ISC_R_SUCCESS) { + omapi_disconnect (c, 1); + return status; + } + + /* Write the transaction ID of the message to which this is a + response, if there is such a message. */ + status = omapi_connection_put_uint32 (c, om ? om -> id : m -> rid); + if (status != ISC_R_SUCCESS) { + omapi_disconnect (c, 1); + return status; + } + + /* Stuff out the name/value pairs specific to this message. */ + status = omapi_stuff_values (c, id, (omapi_object_t *)m); + if (status != ISC_R_SUCCESS) { + omapi_disconnect (c, 1); + return status; + } + + /* Write the zero-length name that terminates the list of name/value + pairs specific to the message. */ + status = omapi_connection_put_uint16 (c, 0); + if (status != ISC_R_SUCCESS) { + omapi_disconnect (c, 1); + return status; + } + + /* Stuff out all the published name/value pairs in the object that's + being sent in the message, if there is one. */ + if (m -> object) { + status = omapi_stuff_values (c, id, m -> object); + if (status != ISC_R_SUCCESS) { + omapi_disconnect (c, 1); + return status; + } + } + + /* Write the zero-length name that terminates the list of name/value + pairs for the associated object. */ + status = omapi_connection_put_uint16 (c, 0); + if (status != ISC_R_SUCCESS) { + omapi_disconnect (c, 1); + return status; + } + + if (ra) { + /* Calculate the message signature. */ + signature = (omapi_value_t *)0; + status = omapi_get_value_str (c, (omapi_object_t *)0, + "output-signature", &signature); + if (status != ISC_R_SUCCESS) { + omapi_disconnect (c, 1); + return status; + } + + /* Write the authenticator... */ + status = (omapi_connection_copyin + (c, signature -> value -> u.buffer.value, + signature -> value -> u.buffer.len)); + omapi_value_dereference (&signature, MDL); + if (status != ISC_R_SUCCESS) { + omapi_disconnect (c, 1); + return status; + } + + /* Dectivate the authentication key on the connection. */ + status = omapi_set_value_str (c, (omapi_object_t *)0, + "output-authenticator", + (omapi_typed_data_t *)0); + if (status != ISC_R_SUCCESS) { + omapi_disconnect (c, 1); + return status; + } + } + + if (!omo) { + omapi_protocol_reference (&m -> protocol_object, p, MDL); + } + return ISC_R_SUCCESS; +} + + +isc_result_t omapi_protocol_signal_handler (omapi_object_t *h, + const char *name, va_list ap) +{ + isc_result_t status; + omapi_protocol_object_t *p; + omapi_object_t *c; + omapi_message_object_t *m; + omapi_value_t *signature; + u_int16_t nlen; + u_int32_t vlen; + u_int32_t th; +#if defined (DEBUG_MEMORY_LEAKAGE) + unsigned long previous_outstanding = 0xDEADBEEF; + unsigned long connect_outstanding = 0xDEADBEEF; +#endif + + if (h -> type != omapi_type_protocol) { + /* XXX shouldn't happen. Put an assert here? */ + return ISC_R_UNEXPECTED; + } + p = (omapi_protocol_object_t *)h; + + if (!strcmp (name, "connect")) { +#if defined (DEBUG_MEMORY_LEAKAGE) + connect_outstanding = dmalloc_outstanding; +#endif + /* Send the introductory message. */ + status = omapi_protocol_send_intro + (h, OMAPI_PROTOCOL_VERSION, + sizeof (omapi_protocol_header_t)); + if (status != ISC_R_SUCCESS) { + omapi_disconnect (p -> outer, 1); + return status; + } + return ISC_R_SUCCESS; + } + + /* Should only receive these when opening the initial authenticator. */ + if (!strcmp (name, "status")) { + status = va_arg (ap, isc_result_t); + if (status != ISC_R_SUCCESS) { + omapi_signal_in (h -> inner, "status", status, + (omapi_object_t *)0); + omapi_disconnect (p -> outer, 1); + return status; + } else { + return omapi_signal_in (h -> inner, "ready"); + } + } + + /* If we get a disconnect, dump memory usage. */ + if (!strcmp (name, "disconnect")) { +#if defined (DEBUG_MEMORY_LEAKAGE) + if (connect_outstanding != 0xDEADBEEF) { + log_info ("generation %ld: %ld new, %ld outstanding, %ld%s", + dmalloc_generation, + dmalloc_outstanding - previous_outstanding, + dmalloc_outstanding, dmalloc_longterm, " long-term"); + } +#endif +#if defined (DEBUG_MEMORY_LEAKAGE) + dmalloc_dump_outstanding (); +#endif +#if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY) + dump_rc_history (); +#endif + for (m = omapi_registered_messages; m; m = m -> next) { + if (m -> protocol_object == p) { + if (m -> object) + omapi_signal (m -> object, "disconnect"); + } + } + } + + /* Not a signal we recognize? */ + if (strcmp (name, "ready")) { + if (p -> inner && p -> inner -> type -> signal_handler) + return (*(p -> inner -> type -> signal_handler)) (h, + name, + ap); + return ISC_R_NOTFOUND; + } + + if (!p -> outer || p -> outer -> type != omapi_type_connection) + return ISC_R_INVALIDARG; + c = p -> outer; + + /* We get here because we requested that we be woken up after + some number of bytes were read, and that number of bytes + has in fact been read. */ + switch (p -> state) { + case omapi_protocol_intro_wait: + /* Get protocol version and header size in network + byte order. */ + omapi_connection_get_uint32 (c, &p -> protocol_version); + omapi_connection_get_uint32 (c, &p -> header_size); + + /* We currently only support the current protocol version. */ + if (p -> protocol_version != OMAPI_PROTOCOL_VERSION) { + omapi_disconnect (c, 1); + return ISC_R_VERSIONMISMATCH; + } + + if (p -> header_size < sizeof (omapi_protocol_header_t)) { + omapi_disconnect (c, 1); + return ISC_R_PROTOCOLERROR; + } + + if (p -> default_auth) { + status = omapi_protocol_send_open + (h, (omapi_object_t *)0, "authenticator", + p -> default_auth -> a, + OMAPI_NOTIFY_PROTOCOL); + if (status != ISC_R_SUCCESS) { + omapi_disconnect (c, 1); + return status; + } + } else { + status = omapi_signal_in (h -> inner, "ready"); + } + + to_header_wait: + /* The next thing we're expecting is a message header. */ + p -> state = omapi_protocol_header_wait; + + /* Register a need for the number of bytes in a + header, and if we already have that many, process + them immediately. */ + if ((omapi_connection_require (c, p -> header_size)) != + ISC_R_SUCCESS) + break; + /* If we already have the data, fall through. */ + + case omapi_protocol_header_wait: +#if defined (DEBUG_MEMORY_LEAKAGE) + if (previous_outstanding != 0xDEADBEEF) { + log_info ("%s %ld: %ld new, %ld outstanding, %ld%s", + "generation", dmalloc_generation, + dmalloc_outstanding - previous_outstanding, + dmalloc_outstanding, dmalloc_longterm, + " long-term"); +#endif +#if (defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL)) + dmalloc_dump_outstanding (); +#endif +#if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY) + dump_rc_history (); +#endif +#if defined (DEBUG_MEMORY_LEAKAGE) + } + previous_outstanding = dmalloc_outstanding; +#endif + status = omapi_message_new ((omapi_object_t **)&p -> message, + MDL); + if (status != ISC_R_SUCCESS) { + omapi_disconnect (c, 1); + return status; + } + + p -> verify_result = ISC_R_SUCCESS; + + /* Swap in the header... */ + omapi_connection_get_uint32 (c, &p -> message -> authid); + + /* Bind the authenticator to the message object. */ + if (p -> message -> authid) { + status = (omapi_protocol_lookup_auth + (&p -> message -> id_object, h, + p -> message -> authid)); + if (status != ISC_R_SUCCESS) + p -> verify_result = status; + + /* Activate the authentication key. */ + status = omapi_set_object_value + (c, (omapi_object_t *)0, "input-authenticator", + p -> message -> id_object); + if (status != ISC_R_SUCCESS) { + omapi_disconnect (c, 1); + return status; + } + } + + omapi_connection_get_uint32 (c, &p -> message -> authlen); + omapi_connection_get_uint32 (c, &p -> message -> op); + omapi_connection_get_uint32 (c, &th); + p -> message -> h = th; + omapi_connection_get_uint32 (c, &p -> message -> id); + omapi_connection_get_uint32 (c, &p -> message -> rid); + + /* If there was any extra header data, skip over it. */ + if (p -> header_size > sizeof (omapi_protocol_header_t)) { + omapi_connection_copyout + (0, c, (p -> header_size - + sizeof (omapi_protocol_header_t))); + } + + /* XXX must compute partial signature across the + XXX preceding bytes. Also, if authenticator + specifies encryption as well as signing, we may + have to decrypt the data on the way in. */ + + /* First we read in message-specific values, then object + values. */ + p -> reading_message_values = 1; + + need_name_length: + /* The next thing we're expecting is length of the + first name. */ + p -> state = omapi_protocol_name_length_wait; + + /* Wait for a 16-bit length. */ + if ((omapi_connection_require (c, 2)) != ISC_R_SUCCESS) + break; + /* If it's already here, fall through. */ + + case omapi_protocol_name_length_wait: + omapi_connection_get_uint16 (c, &nlen); + /* A zero-length name means that we're done reading name+value + pairs. */ + if (nlen == 0) { + /* If we've already read in the object, we are + done reading the message, but if we've just + finished reading in the values associated + with the message, we need to read the + object. */ + if (p -> reading_message_values) { + p -> reading_message_values = 0; + goto need_name_length; + } + + /* If the authenticator length is zero, there's no + signature to read in, so go straight to processing + the message. */ + if (p -> message -> authlen == 0) + goto message_done; + + /* The next thing we're expecting is the + message signature. */ + p -> state = omapi_protocol_signature_wait; + + /* Wait for the number of bytes specified for + the authenticator. If we already have it, + go read it in. */ + if (omapi_connection_require + (c, p -> message -> authlen) == ISC_R_SUCCESS) + goto signature_wait; + break; + } + + /* Allocate a buffer for the name. */ + status = (omapi_data_string_new (&p -> name, nlen, MDL)); + if (status != ISC_R_SUCCESS) { + omapi_disconnect (c, 1); + return ISC_R_NOMEMORY; + } + p -> state = omapi_protocol_name_wait; + if (omapi_connection_require (c, nlen) != ISC_R_SUCCESS) + break; + /* If it's already here, fall through. */ + + case omapi_protocol_name_wait: + omapi_connection_copyout (p -> name -> value, c, + p -> name -> len); + /* Wait for a 32-bit length. */ + p -> state = omapi_protocol_value_length_wait; + if ((omapi_connection_require (c, 4)) != ISC_R_SUCCESS) + break; + /* If it's already here, fall through. */ + + case omapi_protocol_value_length_wait: + omapi_connection_get_uint32 (c, &vlen); + + /* Zero-length values are allowed - if we get one, we + don't have to read any data for the value - just + get the next one, if there is a next one. */ + if (!vlen) + goto insert_new_value; + + status = omapi_typed_data_new (MDL, &p -> value, + omapi_datatype_data, + vlen); + if (status != ISC_R_SUCCESS) { + omapi_disconnect (c, 1); + return ISC_R_NOMEMORY; + } + + p -> state = omapi_protocol_value_wait; + if (omapi_connection_require (c, vlen) != ISC_R_SUCCESS) + break; + /* If it's already here, fall through. */ + + case omapi_protocol_value_wait: + omapi_connection_copyout (p -> value -> u.buffer.value, c, + p -> value -> u.buffer.len); + + insert_new_value: + if (p -> reading_message_values) { + status = (omapi_set_value + ((omapi_object_t *)p -> message, + p -> message -> id_object, + p -> name, p -> value)); + } else { + if (!p -> message -> object) { + /* We need a generic object to hang off of the + incoming message. */ + status = (omapi_generic_new + (&p -> message -> object, MDL)); + if (status != ISC_R_SUCCESS) { + omapi_disconnect (c, 1); + return status; + } + } + status = (omapi_set_value + ((omapi_object_t *)p -> message -> object, + p -> message -> id_object, + p -> name, p -> value)); + } + if (status != ISC_R_SUCCESS) { + omapi_disconnect (c, 1); + return status; + } + omapi_data_string_dereference (&p -> name, MDL); + if (p -> value) + omapi_typed_data_dereference (&p -> value, MDL); + goto need_name_length; + + signature_wait: + case omapi_protocol_signature_wait: + if (p -> message -> id_object) { + /* Compute the signature of the message. */ + signature = (omapi_value_t *)0; + status = omapi_get_value_str (c, (omapi_object_t *)0, + "input-signature", + &signature); + if (status != ISC_R_SUCCESS) { + omapi_disconnect (c, 1); + return status; + } + + /* Disable the authentication key on the connection. */ + status = omapi_set_value_str (c, (omapi_object_t *)0, + "input-authenticator", + (omapi_typed_data_t *)0); + if (status != ISC_R_SUCCESS) { + omapi_value_dereference (&signature, MDL); + omapi_disconnect (c, 1); + return status; + } + } + + /* Read the authenticator. */ + status = omapi_typed_data_new (MDL, + &p -> message -> authenticator, + omapi_datatype_data, + p -> message -> authlen); + + if (status != ISC_R_SUCCESS) { + omapi_value_dereference (&signature, MDL); + omapi_disconnect (c, 1); + return ISC_R_NOMEMORY; + } + omapi_connection_copyout + (p -> message -> authenticator -> u.buffer.value, c, + p -> message -> authlen); + + /* Verify the signature. */ + if (p -> message -> id_object && + ((signature -> value -> u.buffer.len != + p -> message -> authlen) || + (memcmp (signature -> value -> u.buffer.value, + p -> message -> authenticator -> u.buffer.value, + p -> message -> authlen) != 0))) { + /* Invalid signature. */ + p -> verify_result = ISC_R_INVALIDKEY; + } + + omapi_value_dereference (&signature, MDL); + + /* Process the message. */ + message_done: + if (p -> verify_result != ISC_R_SUCCESS) { + status = omapi_protocol_send_status + (h, (omapi_object_t *)0, p -> verify_result, + p -> message -> id, (char *)0); + } else { + status = omapi_message_process + ((omapi_object_t *)p -> message, h); + } + if (status != ISC_R_SUCCESS) { + omapi_disconnect (c, 1); + return ISC_R_NOMEMORY; + } + + omapi_message_dereference (&p -> message, MDL); +#if defined (DEBUG_MEMORY_LEAKAGE) + log_info ("generation %ld: %ld new, %ld outstanding, %ld%s", + dmalloc_generation, + dmalloc_outstanding - previous_outstanding, + dmalloc_outstanding, dmalloc_longterm, " long-term"); +#endif +#if (defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL)) + dmalloc_dump_outstanding (); +#endif +#if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY) + dump_rc_history (); +#endif +#if defined (DEBUG_MEMORY_LEAKAGE) + previous_outstanding = 0xDEADBEEF; +#endif + /* Now wait for the next message. */ + goto to_header_wait; + + default: + /* XXX should never get here. Assertion? */ + break; + } + return ISC_R_SUCCESS; +} + +isc_result_t omapi_protocol_add_auth (omapi_object_t *po, + omapi_object_t *ao, + omapi_handle_t handle) +{ + omapi_protocol_object_t *p; + omapi_remote_auth_t *r; + isc_result_t status; + + if (ao -> type != omapi_type_auth_key && + (!ao -> inner || ao -> inner -> type != omapi_type_auth_key)) + return ISC_R_INVALIDARG; + + if (po -> type != omapi_type_protocol) + return ISC_R_INVALIDARG; + p = (omapi_protocol_object_t *)po; + +#ifdef DEBUG_PROTOCOL + log_debug ("omapi_protocol_add_auth(name=%s)", + ((omapi_auth_key_t *)ao) -> name); +#endif + + if (p -> verify_auth) { + status = (p -> verify_auth) (po, (omapi_auth_key_t *)ao); + if (status != ISC_R_SUCCESS) + return status; + } + + /* If omapi_protocol_connect() was called with a default + authenticator, p -> default_auth will already be set, + but p -> remote_auth_list will not yet be initialized. */ + if (p -> default_auth && !p -> remote_auth_list) { + if (p -> default_auth -> a != ao) { + /* Something just went horribly wrong. */ + omapi_disconnect (p -> outer, 1); + return ISC_R_UNEXPECTED; + } + + p -> remote_auth_list = p -> default_auth; + p -> default_auth -> remote_handle = handle; + + return omapi_signal_in (p -> inner, "ready"); + } + + r = dmalloc (sizeof(*r), MDL); + if (!r) + return ISC_R_NOMEMORY; + + status = omapi_object_reference (&r -> a, ao, MDL); + if (status != ISC_R_SUCCESS) { + dfree (r, MDL); + return status; + } + + r -> remote_handle = handle; + r -> next = p -> remote_auth_list; + p -> remote_auth_list = r; + + return ISC_R_SUCCESS; +} + +isc_result_t omapi_protocol_lookup_auth (omapi_object_t **a, + omapi_object_t *po, + omapi_handle_t handle) +{ + omapi_protocol_object_t *p; + omapi_remote_auth_t *r; + + if (po -> type != omapi_type_protocol) + return ISC_R_INVALIDARG; + p = (omapi_protocol_object_t *)po; + + for (r = p -> remote_auth_list; r; r = r -> next) + if (r -> remote_handle == handle) + return omapi_object_reference (a, r -> a, MDL); + + return ISC_R_KEY_UNKNOWN; +} + +isc_result_t omapi_protocol_set_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_typed_data_t *value) +{ + omapi_protocol_object_t *p; + omapi_remote_auth_t *r; + + if (h -> type != omapi_type_protocol) + return ISC_R_INVALIDARG; + p = (omapi_protocol_object_t *)h; + + if (omapi_ds_strcmp (name, "default-authenticator") == 0) { + if (value -> type != omapi_datatype_object) + return ISC_R_INVALIDARG; + + if (!value || !value -> u.object) { + p -> default_auth = (omapi_remote_auth_t *)0; + } else { + for (r = p -> remote_auth_list; r; r = r -> next) + if (r -> a == value -> u.object) + break; + + if (!r) + return ISC_R_KEY_UNKNOWN; + + p -> default_auth = r; + } + + return ISC_R_SUCCESS; + } + + if (h -> inner && h -> inner -> type -> set_value) + return (*(h -> inner -> type -> set_value)) + (h -> inner, id, name, value); + return ISC_R_NOTFOUND; +} + +isc_result_t omapi_protocol_get_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_value_t **value) +{ + omapi_protocol_object_t *p; + + if (h -> type != omapi_type_protocol) + return ISC_R_INVALIDARG; + p = (omapi_protocol_object_t *)h; + + if (omapi_ds_strcmp (name, "default-authenticator") == 0) { + if (!p -> default_auth) + return ISC_R_NOTFOUND; + + return omapi_make_object_value (value, name, + p -> default_auth -> a, MDL); + } + + if (h -> inner && h -> inner -> type -> get_value) + return (*(h -> inner -> type -> get_value)) + (h -> inner, id, name, value); + return ISC_R_NOTFOUND; +} + +isc_result_t omapi_protocol_destroy (omapi_object_t *h, + const char *file, int line) +{ + omapi_protocol_object_t *p; + if (h -> type != omapi_type_protocol) + return ISC_R_INVALIDARG; + p = (omapi_protocol_object_t *)h; + if (p -> message) + omapi_message_dereference (&p -> message, file, line); + + /* This will happen if: 1) A default authenticator is supplied to + omapi_protocol_connect(), and 2) something goes wrong before + the authenticator can be opened. */ + if (p -> default_auth && !p -> remote_auth_list) + dfree (p -> default_auth, file, line); + + while (p -> remote_auth_list) { + omapi_remote_auth_t *r = p -> remote_auth_list -> next; + p -> remote_auth_list = r; + if (r) { + omapi_object_dereference (&r -> a, file, line); + dfree (r, file, line); + } + } + return ISC_R_SUCCESS; +} + +/* Write all the published values associated with the object through the + specified connection. */ + +isc_result_t omapi_protocol_stuff_values (omapi_object_t *c, + omapi_object_t *id, + omapi_object_t *p) +{ + int i; + + if (p -> type != omapi_type_protocol) + return ISC_R_INVALIDARG; + + if (p -> inner && p -> inner -> type -> stuff_values) + return (*(p -> inner -> type -> stuff_values)) (c, id, + p -> inner); + return ISC_R_SUCCESS; +} + +/* Returns a boolean indicating whether this protocol requires that + messages be authenticated or not. */ + +isc_boolean_t omapi_protocol_authenticated (omapi_object_t *h) +{ + if (h -> type != omapi_type_protocol) + return isc_boolean_false; + if (((omapi_protocol_object_t *)h) -> insecure) + return isc_boolean_false; + else + return isc_boolean_true; +} + +/* Sets the address and authenticator verification callbacks. The handle + is to a listener object, not a protocol object. */ + +isc_result_t omapi_protocol_configure_security (omapi_object_t *h, + isc_result_t (*verify_addr) + (omapi_object_t *, + omapi_addr_t *), + isc_result_t (*verify_auth) + (omapi_object_t *, + omapi_auth_key_t *)) +{ + omapi_protocol_listener_object_t *l; + + if (h -> outer && h -> outer -> type == omapi_type_protocol_listener) + h = h -> outer; + + if (h -> type != omapi_type_protocol_listener) + return ISC_R_INVALIDARG; + l = (omapi_protocol_listener_object_t *)h; + + l -> verify_auth = verify_auth; + l -> insecure = 0; + + return omapi_listener_configure_security (h -> outer, verify_addr); +} + + +/* Set up a listener for the omapi protocol. The handle stored points to + a listener object, not a protocol object. */ + +isc_result_t omapi_protocol_listen (omapi_object_t *h, + unsigned port, + int max) +{ + isc_result_t status; + omapi_protocol_listener_object_t *obj; + + obj = (omapi_protocol_listener_object_t *)0; + status = omapi_protocol_listener_allocate (&obj, MDL); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_object_reference (&h -> outer, + (omapi_object_t *)obj, MDL); + if (status != ISC_R_SUCCESS) { + omapi_protocol_listener_dereference (&obj, MDL); + return status; + } + status = omapi_object_reference (&obj -> inner, h, MDL); + if (status != ISC_R_SUCCESS) { + omapi_protocol_listener_dereference (&obj, MDL); + return status; + } + + /* What a terrible default. */ + obj -> insecure = 1; + + status = omapi_listen ((omapi_object_t *)obj, port, max); + omapi_protocol_listener_dereference (&obj, MDL); + return status; +} + +/* Signal handler for protocol listener - if we get a connect signal, + create a new protocol connection, otherwise pass the signal down. */ + +isc_result_t omapi_protocol_listener_signal (omapi_object_t *o, + const char *name, va_list ap) +{ + isc_result_t status; + omapi_object_t *c; + omapi_protocol_object_t *obj; + omapi_protocol_listener_object_t *p; + + if (!o || o -> type != omapi_type_protocol_listener) + return ISC_R_INVALIDARG; + p = (omapi_protocol_listener_object_t *)o; + + /* Not a signal we recognize? */ + if (strcmp (name, "connect")) { + if (p -> inner && p -> inner -> type -> signal_handler) + return (*(p -> inner -> type -> signal_handler)) + (p -> inner, name, ap); + return ISC_R_NOTFOUND; + } + + c = va_arg (ap, omapi_object_t *); + if (!c || c -> type != omapi_type_connection) + return ISC_R_INVALIDARG; + + obj = (omapi_protocol_object_t *)0; + status = omapi_protocol_allocate (&obj, MDL); + if (status != ISC_R_SUCCESS) + return status; + + obj -> verify_auth = p -> verify_auth; + obj -> insecure = p -> insecure; + + status = omapi_object_reference (&obj -> outer, c, MDL); + if (status != ISC_R_SUCCESS) { + lose: + omapi_protocol_dereference (&obj, MDL); + omapi_disconnect (c, 1); + return status; + } + + status = omapi_object_reference (&c -> inner, + (omapi_object_t *)obj, MDL); + if (status != ISC_R_SUCCESS) + goto lose; + + /* Send the introductory message. */ + status = omapi_protocol_send_intro ((omapi_object_t *)obj, + OMAPI_PROTOCOL_VERSION, + sizeof (omapi_protocol_header_t)); + if (status != ISC_R_SUCCESS) + goto lose; + + omapi_protocol_dereference (&obj, MDL); + return status; +} + +isc_result_t omapi_protocol_listener_set_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_typed_data_t *value) +{ + if (h -> type != omapi_type_protocol_listener) + return ISC_R_INVALIDARG; + + if (h -> inner && h -> inner -> type -> set_value) + return (*(h -> inner -> type -> set_value)) + (h -> inner, id, name, value); + return ISC_R_NOTFOUND; +} + +isc_result_t omapi_protocol_listener_get_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_value_t **value) +{ + if (h -> type != omapi_type_protocol_listener) + return ISC_R_INVALIDARG; + + if (h -> inner && h -> inner -> type -> get_value) + return (*(h -> inner -> type -> get_value)) + (h -> inner, id, name, value); + return ISC_R_NOTFOUND; +} + +isc_result_t omapi_protocol_listener_destroy (omapi_object_t *h, + const char *file, int line) +{ + if (h -> type != omapi_type_protocol_listener) + return ISC_R_INVALIDARG; + return ISC_R_SUCCESS; +} + +/* Write all the published values associated with the object through the + specified connection. */ + +isc_result_t omapi_protocol_listener_stuff (omapi_object_t *c, + omapi_object_t *id, + omapi_object_t *p) +{ + int i; + + if (p -> type != omapi_type_protocol_listener) + return ISC_R_INVALIDARG; + + if (p -> inner && p -> inner -> type -> stuff_values) + return (*(p -> inner -> type -> stuff_values)) (c, id, + p -> inner); + return ISC_R_SUCCESS; +} + +isc_result_t omapi_protocol_send_status (omapi_object_t *po, + omapi_object_t *id, + isc_result_t waitstatus, + unsigned rid, const char *msg) +{ + isc_result_t status; + omapi_message_object_t *message = (omapi_message_object_t *)0; + omapi_object_t *mo; + + if (po -> type != omapi_type_protocol) + return ISC_R_INVALIDARG; + + status = omapi_message_new ((omapi_object_t **)&message, MDL); + if (status != ISC_R_SUCCESS) + return status; + mo = (omapi_object_t *)message; + + status = omapi_set_int_value (mo, (omapi_object_t *)0, + "op", OMAPI_OP_STATUS); + if (status != ISC_R_SUCCESS) { + omapi_message_dereference (&message, MDL); + return status; + } + + status = omapi_set_int_value (mo, (omapi_object_t *)0, + "rid", (int)rid); + if (status != ISC_R_SUCCESS) { + omapi_message_dereference (&message, MDL); + return status; + } + + status = omapi_set_int_value (mo, (omapi_object_t *)0, + "result", (int)waitstatus); + if (status != ISC_R_SUCCESS) { + omapi_message_dereference (&message, MDL); + return status; + } + + /* If a message has been provided, send it. */ + if (msg) { + status = omapi_set_string_value (mo, (omapi_object_t *)0, + "message", msg); + if (status != ISC_R_SUCCESS) { + omapi_message_dereference (&message, MDL); + return status; + } + } + + status = omapi_protocol_send_message (po, id, mo, (omapi_object_t *)0); + omapi_message_dereference (&message, MDL); + return status; +} + +/* The OMAPI_NOTIFY_PROTOCOL flag will cause the notify-object for the + message to be set to the protocol object. This is used when opening + the default authenticator. */ + +isc_result_t omapi_protocol_send_open (omapi_object_t *po, + omapi_object_t *id, + const char *type, + omapi_object_t *object, + unsigned flags) +{ + isc_result_t status; + omapi_message_object_t *message = (omapi_message_object_t *)0; + omapi_object_t *mo; + + if (po -> type != omapi_type_protocol) + return ISC_R_INVALIDARG; + + status = omapi_message_new ((omapi_object_t **)&message, MDL); + mo = (omapi_object_t *)message; + + if (status == ISC_R_SUCCESS) + status = omapi_set_int_value (mo, (omapi_object_t *)0, + "op", OMAPI_OP_OPEN); + + if (status == ISC_R_SUCCESS) + status = omapi_set_object_value (mo, (omapi_object_t *)0, + "object", object); + + if ((flags & OMAPI_CREATE) && (status == ISC_R_SUCCESS)) + status = omapi_set_boolean_value (mo, (omapi_object_t *)0, + "create", 1); + + if ((flags & OMAPI_UPDATE) && (status == ISC_R_SUCCESS)) + status = omapi_set_boolean_value (mo, (omapi_object_t *)0, + "update", 1); + + if ((flags & OMAPI_EXCL) && (status == ISC_R_SUCCESS)) + status = omapi_set_boolean_value (mo, (omapi_object_t *)0, + "exclusive", 1); + + if ((flags & OMAPI_NOTIFY_PROTOCOL) && (status == ISC_R_SUCCESS)) + status = omapi_set_object_value (mo, (omapi_object_t *)0, + "notify-object", po); + + if (type && (status == ISC_R_SUCCESS)) + status = omapi_set_string_value (mo, (omapi_object_t *)0, + "type", type); + + if (status == ISC_R_SUCCESS) + status = omapi_message_register (mo); + + if (status == ISC_R_SUCCESS) { + status = omapi_protocol_send_message (po, id, mo, + (omapi_object_t *)0); + if (status != ISC_R_SUCCESS) + omapi_message_unregister (mo); + } + + if (message) + omapi_message_dereference (&message, MDL); + + return status; +} + +isc_result_t omapi_protocol_send_update (omapi_object_t *po, + omapi_object_t *id, + unsigned rid, + omapi_object_t *object) +{ + isc_result_t status; + omapi_message_object_t *message = (omapi_message_object_t *)0; + omapi_object_t *mo; + + if (po -> type != omapi_type_protocol) + return ISC_R_INVALIDARG; + + status = omapi_message_new ((omapi_object_t **)&message, MDL); + if (status != ISC_R_SUCCESS) + return status; + mo = (omapi_object_t *)message; + + status = omapi_set_int_value (mo, (omapi_object_t *)0, + "op", OMAPI_OP_UPDATE); + if (status != ISC_R_SUCCESS) { + omapi_message_dereference (&message, MDL); + return status; + } + + if (rid) { + omapi_handle_t handle; + status = omapi_set_int_value (mo, (omapi_object_t *)0, + "rid", (int)rid); + if (status != ISC_R_SUCCESS) { + omapi_message_dereference (&message, MDL); + return status; + } + + status = omapi_object_handle (&handle, object); + if (status != ISC_R_SUCCESS) { + omapi_message_dereference (&message, MDL); + return status; + } + status = omapi_set_int_value (mo, (omapi_object_t *)0, + "handle", (int)handle); + if (status != ISC_R_SUCCESS) { + omapi_message_dereference (&message, MDL); + return status; + } + } + + status = omapi_set_object_value (mo, (omapi_object_t *)0, + "object", object); + if (status != ISC_R_SUCCESS) { + omapi_message_dereference (&message, MDL); + return status; + } + + status = omapi_protocol_send_message (po, id, mo, (omapi_object_t *)0); + omapi_message_dereference (&message, MDL); + return status; +} diff --git a/contrib/isc-dhcp/omapip/result.c b/contrib/isc-dhcp/omapip/result.c new file mode 100644 index 0000000..8e6695e --- /dev/null +++ b/contrib/isc-dhcp/omapip/result.c @@ -0,0 +1,125 @@ +/* result.c + + Cheap knock-off of libisc result table code. This is just a place-holder + until the actual libisc merge. */ + +/* + * Copyright (c) 1999-2001 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. + */ + +#include <omapip/omapip_p.h> + +static const char *text[ISC_R_NRESULTS] = { + "success", /* 0 */ + "out of memory", /* 1 */ + "timed out", /* 2 */ + "no available threads", /* 3 */ + "address not available", /* 4 */ + "address in use", /* 5 */ + "permission denied", /* 6 */ + "no pending connections", /* 7 */ + "network unreachable", /* 8 */ + "host unreachable", /* 9 */ + "network down", /* 10 */ + "host down", /* 11 */ + "connection refused", /* 12 */ + "not enough free resources", /* 13 */ + "end of file", /* 14 */ + "socket already bound", /* 15 */ + "task is done", /* 16 */ + "lock busy", /* 17 */ + "already exists", /* 18 */ + "ran out of space", /* 19 */ + "operation canceled", /* 20 */ + "sending events is not allowed", /* 21 */ + "shutting down", /* 22 */ + "not found", /* 23 */ + "unexpected end of input", /* 24 */ + "failure", /* 25 */ + "I/O error", /* 26 */ + "not implemented", /* 27 */ + "unbalanced parentheses", /* 28 */ + "no more", /* 29 */ + "invalid file", /* 30 */ + "bad base64 encoding", /* 31 */ + "unexpected token", /* 32 */ + "quota reached", /* 33 */ + "unexpected error", /* 34 */ + "already running", /* 35 */ + "host unknown", /* 36 */ + "protocol version mismatch", /* 37 */ + "protocol error", /* 38 */ + "invalid argument", /* 39 */ + "not connected", /* 40 */ + "data not yet available", /* 41 */ + "object unchanged", /* 42 */ + "more than one object matches key", /* 43 */ + "key conflict", /* 44 */ + "parse error(s) occurred", /* 45 */ + "no key specified", /* 46 */ + "zone TSIG key not known", /* 47 */ + "invalid TSIG key", /* 48 */ + "operation in progress", /* 49 */ + "DNS format error", /* 50 */ + "DNS server failed", /* 51 */ + "no such domain", /* 52 */ + "not implemented", /* 53 */ + "refused", /* 54 */ + "domain already exists", /* 55 */ + "RRset already exists", /* 56 */ + "no such RRset", /* 57 */ + "not authorized", /* 58 */ + "not a zone", /* 59 */ + "bad DNS signature", /* 60 */ + "bad DNS key", /* 61 */ + "clock skew too great", /* 62 */ + "no root zone", /* 63 */ + "destination address required", /* 64 */ + "cross-zone update", /* 65 */ + "no TSIG signature", /* 66 */ + "not equal", /* 67 */ + "connection reset by peer", /* 68 */ + "unknown attribute" /* 69 */ +}; + +const char *isc_result_totext (isc_result_t result) +{ + if (result >= ISC_R_SUCCESS && result < ISC_R_NRESULTS) + return text [result]; + return "unknown error."; +} diff --git a/contrib/isc-dhcp/omapip/support.c b/contrib/isc-dhcp/omapip/support.c new file mode 100644 index 0000000..1fb9803 --- /dev/null +++ b/contrib/isc-dhcp/omapip/support.c @@ -0,0 +1,872 @@ +/* support.c + + Subroutines providing general support for objects. */ + +/* + * Copyright (c) 1999-2001 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. + */ + +#include <omapip/omapip_p.h> + +omapi_object_type_t *omapi_type_connection; +omapi_object_type_t *omapi_type_listener; +omapi_object_type_t *omapi_type_io_object; +omapi_object_type_t *omapi_type_datagram; +omapi_object_type_t *omapi_type_generic; +omapi_object_type_t *omapi_type_protocol; +omapi_object_type_t *omapi_type_protocol_listener; +omapi_object_type_t *omapi_type_waiter; +omapi_object_type_t *omapi_type_remote; +omapi_object_type_t *omapi_type_message; +omapi_object_type_t *omapi_type_auth_key; + +omapi_object_type_t *omapi_object_types; +int omapi_object_type_count; +static int ot_max; + +#if defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) +void omapi_type_relinquish () +{ + omapi_object_type_t *t, *n; + + for (t = omapi_object_types; t; t = n) { + n = t -> next; + dfree (t, MDL); + } + omapi_object_types = (omapi_object_type_t *)0; +} +#endif + +isc_result_t omapi_init (void) +{ + isc_result_t status; + + dst_init(); + + /* Register all the standard object types... */ + status = omapi_object_type_register (&omapi_type_connection, + "connection", + omapi_connection_set_value, + omapi_connection_get_value, + omapi_connection_destroy, + omapi_connection_signal_handler, + omapi_connection_stuff_values, + 0, 0, 0, 0, 0, 0, + sizeof + (omapi_connection_object_t), 0, + RC_MISC); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_object_type_register (&omapi_type_listener, + "listener", + omapi_listener_set_value, + omapi_listener_get_value, + omapi_listener_destroy, + omapi_listener_signal_handler, + omapi_listener_stuff_values, + 0, 0, 0, 0, 0, 0, + sizeof (omapi_listener_object_t), + 0, RC_MISC); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_object_type_register (&omapi_type_io_object, + "io", + omapi_io_set_value, + omapi_io_get_value, + omapi_io_destroy, + omapi_io_signal_handler, + omapi_io_stuff_values, + 0, 0, 0, 0, 0, 0, + sizeof (omapi_io_object_t), + 0, RC_MISC); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_object_type_register (&omapi_type_generic, + "generic", + omapi_generic_set_value, + omapi_generic_get_value, + omapi_generic_destroy, + omapi_generic_signal_handler, + omapi_generic_stuff_values, + 0, 0, 0, 0, 0, 0, + sizeof (omapi_generic_object_t), + 0, RC_MISC); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_object_type_register (&omapi_type_protocol, + "protocol", + omapi_protocol_set_value, + omapi_protocol_get_value, + omapi_protocol_destroy, + omapi_protocol_signal_handler, + omapi_protocol_stuff_values, + 0, 0, 0, 0, 0, 0, + sizeof (omapi_protocol_object_t), + 0, RC_MISC); + if (status != ISC_R_SUCCESS) + return status; + + status = (omapi_object_type_register + (&omapi_type_protocol_listener, "protocol-listener", + omapi_protocol_listener_set_value, + omapi_protocol_listener_get_value, + omapi_protocol_listener_destroy, + omapi_protocol_listener_signal, + omapi_protocol_listener_stuff, + 0, 0, 0, 0, 0, 0, + sizeof (omapi_protocol_listener_object_t), 0, RC_MISC)); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_object_type_register (&omapi_type_message, + "message", + omapi_message_set_value, + omapi_message_get_value, + omapi_message_destroy, + omapi_message_signal_handler, + omapi_message_stuff_values, + 0, 0, 0, 0, 0, 0, + sizeof (omapi_message_object_t), + 0, RC_MISC); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_object_type_register (&omapi_type_waiter, + "waiter", + 0, + 0, + 0, + omapi_waiter_signal_handler, 0, + 0, 0, 0, 0, 0, 0, + sizeof (omapi_waiter_object_t), + 0, RC_MISC); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_object_type_register (&omapi_type_auth_key, + "authenticator", + 0, + omapi_auth_key_get_value, + omapi_auth_key_destroy, + 0, + omapi_auth_key_stuff_values, + omapi_auth_key_lookup, + 0, 0, 0, 0, 0, + sizeof (omapi_auth_key_t), 0, + RC_MISC); + if (status != ISC_R_SUCCESS) + return status; + +#if defined (TRACING) + omapi_listener_trace_setup (); + omapi_connection_trace_setup (); + omapi_buffer_trace_setup (); + trace_mr_init (); +#endif + + /* This seems silly, but leave it. */ + return ISC_R_SUCCESS; +} + +isc_result_t omapi_object_type_register (omapi_object_type_t **type, + const char *name, + isc_result_t (*set_value) + (omapi_object_t *, + omapi_object_t *, + omapi_data_string_t *, + omapi_typed_data_t *), + isc_result_t (*get_value) + (omapi_object_t *, + omapi_object_t *, + omapi_data_string_t *, + omapi_value_t **), + isc_result_t (*destroy) + (omapi_object_t *, + const char *, int), + isc_result_t (*signal_handler) + (omapi_object_t *, + const char *, va_list), + isc_result_t (*stuff_values) + (omapi_object_t *, + omapi_object_t *, + omapi_object_t *), + isc_result_t (*lookup) + (omapi_object_t **, + omapi_object_t *, + omapi_object_t *), + isc_result_t (*create) + (omapi_object_t **, + omapi_object_t *), + isc_result_t (*remove) + (omapi_object_t *, + omapi_object_t *), + isc_result_t (*freer) + (omapi_object_t *, + const char *, int), + isc_result_t (*allocator) + (omapi_object_t **, + const char *, int), + isc_result_t (*sizer) (size_t), + size_t size, + isc_result_t (*initialize) + (omapi_object_t *, + const char *, int), + int rc_flag) +{ + omapi_object_type_t *t; + + t = dmalloc (sizeof *t, MDL); + if (!t) + return ISC_R_NOMEMORY; + memset (t, 0, sizeof *t); + + t -> name = name; + t -> set_value = set_value; + t -> get_value = get_value; + t -> destroy = destroy; + t -> signal_handler = signal_handler; + t -> stuff_values = stuff_values; + t -> lookup = lookup; + t -> create = create; + t -> remove = remove; + t -> next = omapi_object_types; + t -> sizer = sizer; + t -> size = size; + t -> freer = freer; + t -> allocator = allocator; + t -> initialize = initialize; + t -> rc_flag = rc_flag; + omapi_object_types = t; + if (type) + *type = t; + return ISC_R_SUCCESS; +} + +isc_result_t omapi_signal (omapi_object_t *handle, const char *name, ...) +{ + va_list ap; + omapi_object_t *outer; + isc_result_t status; + + va_start (ap, name); + for (outer = handle; outer -> outer; outer = outer -> outer) + ; + if (outer -> type -> signal_handler) + status = (*(outer -> type -> signal_handler)) (outer, + name, ap); + else + status = ISC_R_NOTFOUND; + va_end (ap); + return status; +} + +isc_result_t omapi_signal_in (omapi_object_t *handle, const char *name, ...) +{ + va_list ap; + omapi_object_t *outer; + isc_result_t status; + + if (!handle) + return ISC_R_NOTFOUND; + va_start (ap, name); + + if (handle -> type -> signal_handler) + status = (*(handle -> type -> signal_handler)) (handle, + name, ap); + else + status = ISC_R_NOTFOUND; + va_end (ap); + return status; +} + +isc_result_t omapi_set_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_typed_data_t *value) +{ + omapi_object_t *outer; + isc_result_t status; + +#if defined (DEBUG) + if (!value) { + log_info ("omapi_set_value (%.*s, NULL)", + (int)name -> len, name -> value); + } else if (value -> type == omapi_datatype_int) { + log_info ("omapi_set_value (%.*s, %ld)", + (int)name -> len, name -> value, + (long)value -> u.integer); + } else if (value -> type == omapi_datatype_string) { + log_info ("omapi_set_value (%.*s, %.*s)", + (int)name -> len, name -> value, + (int)value -> u.buffer.len, value -> u.buffer.value); + } else if (value -> type == omapi_datatype_data) { + log_info ("omapi_set_value (%.*s, %ld %lx)", + (int)name -> len, name -> value, + (long)value -> u.buffer.len, + (unsigned long)value -> u.buffer.value); + } else if (value -> type == omapi_datatype_object) { + log_info ("omapi_set_value (%.*s, %s)", + (int)name -> len, name -> value, + value -> u.object + ? (value -> u.object -> type + ? value -> u.object -> type -> name + : "(unknown object)") + : "(unknown object)"); + } +#endif + + for (outer = h; outer -> outer; outer = outer -> outer) + ; + if (outer -> type -> set_value) + status = (*(outer -> type -> set_value)) (outer, + id, name, value); + else + status = ISC_R_NOTFOUND; +#if defined (DEBUG) + log_info (" ==> %s", isc_result_totext (status)); +#endif + return status; +} + +isc_result_t omapi_set_value_str (omapi_object_t *h, + omapi_object_t *id, + const char *name, + omapi_typed_data_t *value) +{ + omapi_object_t *outer; + omapi_data_string_t *nds; + isc_result_t status; + + nds = (omapi_data_string_t *)0; + status = omapi_data_string_new (&nds, strlen (name), MDL); + if (status != ISC_R_SUCCESS) + return status; + memcpy (nds -> value, name, strlen (name)); + + status = omapi_set_value (h, id, nds, value); + omapi_data_string_dereference (&nds, MDL); + return status; +} + +isc_result_t omapi_set_boolean_value (omapi_object_t *h, omapi_object_t *id, + const char *name, int value) +{ + isc_result_t status; + omapi_typed_data_t *tv = (omapi_typed_data_t *)0; + omapi_data_string_t *n = (omapi_data_string_t *)0; + int len; + int ip; + + status = omapi_data_string_new (&n, strlen (name), MDL); + if (status != ISC_R_SUCCESS) + return status; + memcpy (n -> value, name, strlen (name)); + + status = omapi_typed_data_new (MDL, &tv, omapi_datatype_int, value); + if (status != ISC_R_SUCCESS) { + omapi_data_string_dereference (&n, MDL); + return status; + } + + status = omapi_set_value (h, id, n, tv); + omapi_data_string_dereference (&n, MDL); + omapi_typed_data_dereference (&tv, MDL); + return status; +} + +isc_result_t omapi_set_int_value (omapi_object_t *h, omapi_object_t *id, + const char *name, int value) +{ + isc_result_t status; + omapi_typed_data_t *tv = (omapi_typed_data_t *)0; + omapi_data_string_t *n = (omapi_data_string_t *)0; + int len; + int ip; + + status = omapi_data_string_new (&n, strlen (name), MDL); + if (status != ISC_R_SUCCESS) + return status; + memcpy (n -> value, name, strlen (name)); + + status = omapi_typed_data_new (MDL, &tv, omapi_datatype_int, value); + if (status != ISC_R_SUCCESS) { + omapi_data_string_dereference (&n, MDL); + return status; + } + + status = omapi_set_value (h, id, n, tv); + omapi_data_string_dereference (&n, MDL); + omapi_typed_data_dereference (&tv, MDL); + return status; +} + +isc_result_t omapi_set_object_value (omapi_object_t *h, omapi_object_t *id, + const char *name, omapi_object_t *value) +{ + isc_result_t status; + omapi_typed_data_t *tv = (omapi_typed_data_t *)0; + omapi_data_string_t *n = (omapi_data_string_t *)0; + int len; + int ip; + + status = omapi_data_string_new (&n, strlen (name), MDL); + if (status != ISC_R_SUCCESS) + return status; + memcpy (n -> value, name, strlen (name)); + + status = omapi_typed_data_new (MDL, &tv, omapi_datatype_object, value); + if (status != ISC_R_SUCCESS) { + omapi_data_string_dereference (&n, MDL); + return status; + } + + status = omapi_set_value (h, id, n, tv); + omapi_data_string_dereference (&n, MDL); + omapi_typed_data_dereference (&tv, MDL); + return status; +} + +isc_result_t omapi_set_string_value (omapi_object_t *h, omapi_object_t *id, + const char *name, const char *value) +{ + isc_result_t status; + omapi_typed_data_t *tv = (omapi_typed_data_t *)0; + omapi_data_string_t *n = (omapi_data_string_t *)0; + int len; + int ip; + + status = omapi_data_string_new (&n, strlen (name), MDL); + if (status != ISC_R_SUCCESS) + return status; + memcpy (n -> value, name, strlen (name)); + + status = omapi_typed_data_new (MDL, &tv, omapi_datatype_string, value); + if (status != ISC_R_SUCCESS) { + omapi_data_string_dereference (&n, MDL); + return status; + } + + status = omapi_set_value (h, id, n, tv); + omapi_data_string_dereference (&n, MDL); + omapi_typed_data_dereference (&tv, MDL); + return status; +} + +isc_result_t omapi_get_value (omapi_object_t *h, + omapi_object_t *id, + omapi_data_string_t *name, + omapi_value_t **value) +{ + omapi_object_t *outer; + + for (outer = h; outer -> outer; outer = outer -> outer) + ; + if (outer -> type -> get_value) + return (*(outer -> type -> get_value)) (outer, + id, name, value); + return ISC_R_NOTFOUND; +} + +isc_result_t omapi_get_value_str (omapi_object_t *h, + omapi_object_t *id, + const char *name, + omapi_value_t **value) +{ + omapi_object_t *outer; + omapi_data_string_t *nds; + isc_result_t status; + + nds = (omapi_data_string_t *)0; + status = omapi_data_string_new (&nds, strlen (name), MDL); + if (status != ISC_R_SUCCESS) + return status; + memcpy (nds -> value, name, strlen (name)); + + for (outer = h; outer -> outer; outer = outer -> outer) + ; + if (outer -> type -> get_value) + status = (*(outer -> type -> get_value)) (outer, + id, nds, value); + else + status = ISC_R_NOTFOUND; + omapi_data_string_dereference (&nds, MDL); + return status; +} + +isc_result_t omapi_stuff_values (omapi_object_t *c, + omapi_object_t *id, + omapi_object_t *o) +{ + omapi_object_t *outer; + + for (outer = o; outer -> outer; outer = outer -> outer) + ; + if (outer -> type -> stuff_values) + return (*(outer -> type -> stuff_values)) (c, id, outer); + return ISC_R_NOTFOUND; +} + +isc_result_t omapi_object_create (omapi_object_t **obj, omapi_object_t *id, + omapi_object_type_t *type) +{ + if (!type -> create) + return ISC_R_NOTIMPLEMENTED; + return (*(type -> create)) (obj, id); +} + +isc_result_t omapi_object_update (omapi_object_t *obj, omapi_object_t *id, + omapi_object_t *src, omapi_handle_t handle) +{ + omapi_generic_object_t *gsrc; + isc_result_t status; + int i; + + if (!src) + return ISC_R_INVALIDARG; + if (src -> type != omapi_type_generic) + return ISC_R_NOTIMPLEMENTED; + gsrc = (omapi_generic_object_t *)src; + for (i = 0; i < gsrc -> nvalues; i++) { + status = omapi_set_value (obj, id, + gsrc -> values [i] -> name, + gsrc -> values [i] -> value); + if (status != ISC_R_SUCCESS && status != ISC_R_UNCHANGED) + return status; + } + if (handle) + omapi_set_int_value (obj, id, "remote-handle", (int)handle); + status = omapi_signal (obj, "updated"); + if (status != ISC_R_NOTFOUND) + return status; + return ISC_R_SUCCESS; +} + +int omapi_data_string_cmp (omapi_data_string_t *s1, omapi_data_string_t *s2) +{ + unsigned len; + int rv; + + if (s1 -> len > s2 -> len) + len = s2 -> len; + else + len = s1 -> len; + rv = memcmp (s1 -> value, s2 -> value, len); + if (rv) + return rv; + if (s1 -> len > s2 -> len) + return 1; + else if (s1 -> len < s2 -> len) + return -1; + return 0; +} + +int omapi_ds_strcmp (omapi_data_string_t *s1, const char *s2) +{ + unsigned len, slen; + int rv; + + slen = strlen (s2); + if (slen > s1 -> len) + len = s1 -> len; + else + len = slen; + rv = memcmp (s1 -> value, s2, len); + if (rv) + return rv; + if (s1 -> len > slen) + return 1; + else if (s1 -> len < slen) + return -1; + return 0; +} + +int omapi_td_strcmp (omapi_typed_data_t *s1, const char *s2) +{ + unsigned len, slen; + int rv; + + /* If the data type is not compatible, never equal. */ + if (s1 -> type != omapi_datatype_data && + s1 -> type != omapi_datatype_string) + return -1; + + slen = strlen (s2); + if (slen > s1 -> u.buffer.len) + len = s1 -> u.buffer.len; + else + len = slen; + rv = memcmp (s1 -> u.buffer.value, s2, len); + if (rv) + return rv; + if (s1 -> u.buffer.len > slen) + return 1; + else if (s1 -> u.buffer.len < slen) + return -1; + return 0; +} + +int omapi_td_strcasecmp (omapi_typed_data_t *s1, const char *s2) +{ + unsigned len, slen; + int rv; + + /* If the data type is not compatible, never equal. */ + if (s1 -> type != omapi_datatype_data && + s1 -> type != omapi_datatype_string) + return -1; + + slen = strlen (s2); + if (slen > s1 -> u.buffer.len) + len = s1 -> u.buffer.len; + else + len = slen; + rv = casecmp (s1 -> u.buffer.value, s2, len); + if (rv) + return rv; + if (s1 -> u.buffer.len > slen) + return 1; + else if (s1 -> u.buffer.len < slen) + return -1; + return 0; +} + +isc_result_t omapi_make_value (omapi_value_t **vp, + omapi_data_string_t *name, + omapi_typed_data_t *value, + const char *file, int line) +{ + isc_result_t status; + + status = omapi_value_new (vp, file, line); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_data_string_reference (&(*vp) -> name, + name, file, line); + if (status != ISC_R_SUCCESS) { + omapi_value_dereference (vp, file, line); + return status; + } + if (value) { + status = omapi_typed_data_reference (&(*vp) -> value, + value, file, line); + if (status != ISC_R_SUCCESS) { + omapi_value_dereference (vp, file, line); + return status; + } + } + return ISC_R_SUCCESS; +} + +isc_result_t omapi_make_const_value (omapi_value_t **vp, + omapi_data_string_t *name, + const unsigned char *value, + unsigned len, + const char *file, int line) +{ + isc_result_t status; + + status = omapi_value_new (vp, file, line); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_data_string_reference (&(*vp) -> name, + name, file, line); + if (status != ISC_R_SUCCESS) { + omapi_value_dereference (vp, file, line); + return status; + } + if (value) { + status = omapi_typed_data_new (file, line, &(*vp) -> value, + omapi_datatype_data, len); + if (status != ISC_R_SUCCESS) { + omapi_value_dereference (vp, file, line); + return status; + } + memcpy ((*vp) -> value -> u.buffer.value, value, len); + } + return ISC_R_SUCCESS; +} + +isc_result_t omapi_make_int_value (omapi_value_t **vp, + omapi_data_string_t *name, + int value, const char *file, int line) +{ + isc_result_t status; + + status = omapi_value_new (vp, file, line); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_data_string_reference (&(*vp) -> name, + name, file, line); + if (status != ISC_R_SUCCESS) { + omapi_value_dereference (vp, file, line); + return status; + } + status = omapi_typed_data_new (file, line, &(*vp) -> value, + omapi_datatype_int, value); + if (status != ISC_R_SUCCESS) { + omapi_value_dereference (vp, file, line); + return status; + } + return ISC_R_SUCCESS; +} + +isc_result_t omapi_make_uint_value (omapi_value_t **vp, + omapi_data_string_t *name, + unsigned int value, + const char *file, int line) +{ + return omapi_make_int_value (vp, name, (int)value, file, line); +} + +isc_result_t omapi_make_object_value (omapi_value_t **vp, + omapi_data_string_t *name, + omapi_object_t *value, + const char *file, int line) +{ + isc_result_t status; + + status = omapi_value_new (vp, file, line); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_data_string_reference (&(*vp) -> name, + name, file, line); + if (status != ISC_R_SUCCESS) { + omapi_value_dereference (vp, file, line); + return status; + } + + if (value) { + status = omapi_typed_data_new (file, line, &(*vp) -> value, + omapi_datatype_object, value); + if (status != ISC_R_SUCCESS) { + omapi_value_dereference (vp, file, line); + return status; + } + } + + return ISC_R_SUCCESS; +} + +isc_result_t omapi_make_handle_value (omapi_value_t **vp, + omapi_data_string_t *name, + omapi_object_t *value, + const char *file, int line) +{ + isc_result_t status; + + status = omapi_value_new (vp, file, line); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_data_string_reference (&(*vp) -> name, + name, file, line); + if (status != ISC_R_SUCCESS) { + omapi_value_dereference (vp, file, line); + return status; + } + if (value) { + status = omapi_typed_data_new (file, line, &(*vp) -> value, + omapi_datatype_int); + if (status != ISC_R_SUCCESS) { + omapi_value_dereference (vp, file, line); + return status; + } + status = (omapi_object_handle + ((omapi_handle_t *)&(*vp) -> value -> u.integer, + value)); + if (status != ISC_R_SUCCESS) { + omapi_value_dereference (vp, file, line); + return status; + } + } + return ISC_R_SUCCESS; +} + +isc_result_t omapi_make_string_value (omapi_value_t **vp, + omapi_data_string_t *name, + const char *value, + const char *file, int line) +{ + isc_result_t status; + + status = omapi_value_new (vp, file, line); + if (status != ISC_R_SUCCESS) + return status; + + status = omapi_data_string_reference (&(*vp) -> name, + name, file, line); + if (status != ISC_R_SUCCESS) { + omapi_value_dereference (vp, file, line); + return status; + } + if (value) { + status = omapi_typed_data_new (file, line, &(*vp) -> value, + omapi_datatype_string, value); + if (status != ISC_R_SUCCESS) { + omapi_value_dereference (vp, file, line); + return status; + } + } + return ISC_R_SUCCESS; +} + +isc_result_t omapi_get_int_value (unsigned long *v, omapi_typed_data_t *t) +{ + u_int32_t rv; + + if (t -> type == omapi_datatype_int) { + *v = t -> u.integer; + return ISC_R_SUCCESS; + } else if (t -> type == omapi_datatype_string || + t -> type == omapi_datatype_data) { + if (t -> u.buffer.len != sizeof (rv)) + return ISC_R_INVALIDARG; + memcpy (&rv, t -> u.buffer.value, sizeof rv); + *v = ntohl (rv); + return ISC_R_SUCCESS; + } + return ISC_R_INVALIDARG; +} diff --git a/contrib/isc-dhcp/omapip/test.c b/contrib/isc-dhcp/omapip/test.c new file mode 100644 index 0000000..249099e --- /dev/null +++ b/contrib/isc-dhcp/omapip/test.c @@ -0,0 +1,108 @@ +/* test.c + + Test code for omapip... */ + +/* + * Copyright (c) 1999-2000 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. + */ + +#include <time.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <isc-dhcp/result.h> +#include <sys/time.h> +#include <omapip/omapip.h> + +int main (int argc, char **argv) +{ + omapi_object_t *listener = (omapi_object_t*)0; + omapi_object_t *connection = (omapi_object_t*)0; + isc_result_t status; + + omapi_init (); + + if (argc > 1 && !strcmp (argv [1], "listen")) { + if (argc < 3) { + fprintf (stderr, "Usage: test listen port\n"); + exit (1); + } + status = omapi_generic_new (&listener, MDL); + if (status != ISC_R_SUCCESS) { + fprintf (stderr, "omapi_generic_new: %s\n", + isc_result_totext (status)); + exit (1); + } + status = omapi_protocol_listen (listener, + (unsigned)atoi (argv [2]), 1); + if (status != ISC_R_SUCCESS) { + fprintf (stderr, "omapi_listen: %s\n", + isc_result_totext (status)); + exit (1); + } + omapi_dispatch (0); + } else if (argc > 1 && !strcmp (argv [1], "connect")) { + if (argc < 4) { + fprintf (stderr, "Usage: test listen address port\n"); + exit (1); + } + status = omapi_generic_new (&connection, MDL); + if (status != ISC_R_SUCCESS) { + fprintf (stderr, "omapi_generic_new: %s\n", + isc_result_totext (status)); + exit (1); + } + status = omapi_protocol_connect (connection, + argv [2], + (unsigned)atoi (argv [3]), 0); + fprintf (stderr, "connect: %s\n", isc_result_totext (status)); + if (status != ISC_R_SUCCESS) + exit (1); + status = omapi_wait_for_completion (connection, 0); + fprintf (stderr, "completion: %s\n", + isc_result_totext (status)); + if (status != ISC_R_SUCCESS) + exit (1); + /* ... */ + } else { + fprintf (stderr, "Usage: test [listen | connect] ...\n"); + exit (1); + } + + return 0; +} diff --git a/contrib/isc-dhcp/omapip/toisc.c b/contrib/isc-dhcp/omapip/toisc.c new file mode 100644 index 0000000..a30dcff --- /dev/null +++ b/contrib/isc-dhcp/omapip/toisc.c @@ -0,0 +1,324 @@ +/* toisc.c + + Convert non-ISC result codes to ISC result codes. */ + +/* + * Copyright (c) 2001 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. + * To learn more about the Internet Software Consortium, see + * ``http://www.isc.org/''. To learn more about Vixie Enterprises, + * see ``http://www.vix.com''. To learn more about Nominum, Inc., see + * ``http://www.nominum.com''. + */ + +#include <omapip/omapip_p.h> +#include "arpa/nameser.h" +#include "minires/minires.h" + +isc_result_t ns_rcode_to_isc (int nsr) +{ + switch (nsr) { + case ns_r_noerror: + return ISC_R_SUCCESS; + + case ns_r_formerr: + return ISC_R_FORMERR; + + case ns_r_servfail: + return ISC_R_SERVFAIL; + + case ns_r_nxdomain: + return ISC_R_NXDOMAIN; + + case ns_r_notimpl: + return ISC_R_NOTIMPL; + + case ns_r_refused: + return ISC_R_REFUSED; + + case ns_r_yxdomain: + return ISC_R_YXDOMAIN; + + case ns_r_yxrrset: + return ISC_R_YXRRSET; + + case ns_r_nxrrset: + return ISC_R_NXRRSET; + + case ns_r_notauth: + return ISC_R_NOTAUTH; + + case ns_r_notzone: + return ISC_R_NOTZONE; + + case ns_r_badsig: + return ISC_R_BADSIG; + + case ns_r_badkey: + return ISC_R_BADKEY; + + case ns_r_badtime: + return ISC_R_BADTIME; + + default: + ; + } + return ISC_R_UNEXPECTED; +} + +isc_result_t uerr2isc (int err) +{ + switch (err) { + case EPERM: + return ISC_R_NOPERM; + + case ENOENT: + return ISC_R_NOTFOUND; + + case ESRCH: + return ISC_R_NOTFOUND; + + case EIO: + return ISC_R_IOERROR; + + case ENXIO: + return ISC_R_NOTFOUND; + + case E2BIG: + return ISC_R_NOSPACE; + + case ENOEXEC: + return ISC_R_FORMERR; + + case ECHILD: + return ISC_R_NOTFOUND; + + case ENOMEM: + return ISC_R_NOMEMORY; + + case EACCES: + return ISC_R_NOPERM; + + case EFAULT: + return ISC_R_INVALIDARG; + + case EEXIST: + return ISC_R_EXISTS; + + case EINVAL: + return ISC_R_INVALIDARG; + + case ENOTTY: + return ISC_R_INVALIDARG; + + case EFBIG: + return ISC_R_NOSPACE; + + case ENOSPC: + return ISC_R_NOSPACE; + + case EROFS: + return ISC_R_NOPERM; + + case EMLINK: + return ISC_R_NOSPACE; + + case EPIPE: + return ISC_R_NOTCONNECTED; + + case EINPROGRESS: + return ISC_R_ALREADYRUNNING; + + case EALREADY: + return ISC_R_ALREADYRUNNING; + + case ENOTSOCK: + return ISC_R_INVALIDFILE; + + case EDESTADDRREQ: + return ISC_R_DESTADDRREQ; + + case EMSGSIZE: + return ISC_R_NOSPACE; + + case EPROTOTYPE: + return ISC_R_INVALIDARG; + + case ENOPROTOOPT: + return ISC_R_NOTIMPLEMENTED; + + case EPROTONOSUPPORT: + return ISC_R_NOTIMPLEMENTED; + + case ESOCKTNOSUPPORT: + return ISC_R_NOTIMPLEMENTED; + + case EOPNOTSUPP: + return ISC_R_NOTIMPLEMENTED; + + case EPFNOSUPPORT: + return ISC_R_NOTIMPLEMENTED; + + case EAFNOSUPPORT: + return ISC_R_NOTIMPLEMENTED; + + case EADDRINUSE: + return ISC_R_ADDRINUSE; + + case EADDRNOTAVAIL: + return ISC_R_ADDRNOTAVAIL; + + case ENETDOWN: + return ISC_R_NETDOWN; + + case ENETUNREACH: + return ISC_R_NETUNREACH; + + case ECONNABORTED: + return ISC_R_TIMEDOUT; + + case ECONNRESET: + return ISC_R_CONNRESET; + + case ENOBUFS: + return ISC_R_NOSPACE; + + case EISCONN: + return ISC_R_ALREADYRUNNING; + + case ENOTCONN: + return ISC_R_NOTCONNECTED; + + case ESHUTDOWN: + return ISC_R_SHUTTINGDOWN; + + case ETIMEDOUT: + return ISC_R_TIMEDOUT; + + case ECONNREFUSED: + return ISC_R_CONNREFUSED; + + case EHOSTDOWN: + return ISC_R_HOSTDOWN; + + case EHOSTUNREACH: + return ISC_R_HOSTUNREACH; + +#ifdef EDQUOT + case EDQUOT: + return ISC_R_QUOTA; +#endif + +#ifdef EBADRPC + case EBADRPC: + return ISC_R_NOTIMPLEMENTED; +#endif + +#ifdef ERPCMISMATCH + case ERPCMISMATCH: + return ISC_R_VERSIONMISMATCH; +#endif + +#ifdef EPROGMISMATCH + case EPROGMISMATCH: + return ISC_R_VERSIONMISMATCH; +#endif + +#ifdef EAUTH + case EAUTH: + return ISC_R_NOTAUTH; +#endif + +#ifdef ENEEDAUTH + case ENEEDAUTH: + return ISC_R_NOTAUTH; +#endif + +#ifdef EOVERFLOW + case EOVERFLOW: + return ISC_R_NOSPACE; +#endif + } + return ISC_R_UNEXPECTED; +} + +ns_rcode isc_rcode_to_ns (isc_result_t isc) +{ + switch (isc) { + case ISC_R_SUCCESS: + return ns_r_noerror; + + case ISC_R_FORMERR: + return ns_r_formerr; + + case ISC_R_SERVFAIL: + return ns_r_servfail; + + case ISC_R_NXDOMAIN: + return ns_r_nxdomain; + + case ISC_R_NOTIMPL: + return ns_r_notimpl; + + case ISC_R_REFUSED: + return ns_r_refused; + + case ISC_R_YXDOMAIN: + return ns_r_yxdomain; + + case ISC_R_YXRRSET: + return ns_r_yxrrset; + + case ISC_R_NXRRSET: + return ns_r_nxrrset; + + case ISC_R_NOTAUTH: + return ns_r_notauth; + + case ISC_R_NOTZONE: + return ns_r_notzone; + + case ISC_R_BADSIG: + return ns_r_badsig; + + case ISC_R_BADKEY: + return ns_r_badkey; + + case ISC_R_BADTIME: + return ns_r_badtime; + + default: + ; + } + return ns_r_servfail; +} diff --git a/contrib/isc-dhcp/omapip/trace.c b/contrib/isc-dhcp/omapip/trace.c new file mode 100644 index 0000000..4ff3051 --- /dev/null +++ b/contrib/isc-dhcp/omapip/trace.c @@ -0,0 +1,718 @@ +/* trace.c + + Subroutines that support tracing of OMAPI wire transactions and + provide a mechanism for programs using OMAPI to trace their own + transactions... */ + +/* + * Copyright (c) 2001 Internet Software Consortium. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The Internet Software Consortium nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This software has been written for the Internet Software Consortium + * by Ted Lemon, as part of a project for Nominum, Inc. To learn more + * about the Internet Software Consortium, see http://www.isc.org/. To + * learn more about Nominum, Inc., see ``http://www.nominum.com''. + */ + +#include <omapip/omapip_p.h> + +#if defined (TRACING) +void (*trace_set_time_hook) (u_int32_t); +static int tracing_stopped; +static int traceoutfile; +static int traceindex; +static trace_type_t **trace_types; +static int trace_type_count; +static int trace_type_max; +static trace_type_t *new_trace_types; +static FILE *traceinfile; +static tracefile_header_t tracefile_header; +static int trace_playback_flag; +trace_type_t trace_time_marker; + +#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) +extern omapi_array_t *trace_listeners; +extern omapi_array_t *omapi_connections; + +void trace_free_all () +{ + trace_type_t *tp; + int i; + tp = new_trace_types; + while (tp) { + new_trace_types = tp -> next; + if (tp -> name) { + dfree (tp -> name, MDL); + tp -> name = (char *)0; + } + dfree (tp, MDL); + tp = new_trace_types; + } + for (i = 0; i < trace_type_count; i++) { + if (trace_types [i]) { + if (trace_types [i] -> name) + dfree (trace_types [i] -> name, MDL); + dfree (trace_types [i], MDL); + } + } + dfree (trace_types, MDL); + trace_types = (trace_type_t **)0; + trace_type_count = trace_type_max = 0; + + omapi_array_free (&trace_listeners, MDL); + omapi_array_free (&omapi_connections, MDL); +} +#endif + +static isc_result_t trace_type_record (trace_type_t *, + unsigned, const char *, int); + +int trace_playback () +{ + return trace_playback_flag; +} + +int trace_record () +{ + if (traceoutfile && !tracing_stopped) + return 1; + return 0; +} + +isc_result_t trace_init (void (*set_time) (u_int32_t), + const char *file, int line) +{ + trace_type_t *root_type; + static int root_setup = 0; + + if (root_setup) + return ISC_R_SUCCESS; + + trace_set_time_hook = set_time; + + root_type = trace_type_register ("trace-index-mapping", + (void *)0, trace_index_map_input, + trace_index_stop_tracing, file, line); + if (!root_type) + return ISC_R_UNEXPECTED; + if (new_trace_types == root_type) + new_trace_types = new_trace_types -> next; + root_type -> index = 0; + trace_type_stash (root_type); + + root_setup = 1; + return ISC_R_SUCCESS; +} + +isc_result_t trace_begin (const char *filename, + const char *file, int line) +{ + tracefile_header_t tfh; + int status; + trace_type_t *tptr, *next; + isc_result_t result; + + if (traceoutfile) { + log_error ("%s(%d): trace_begin called twice", + file, line); + return ISC_R_INVALIDARG; + } + + traceoutfile = open (filename, O_CREAT | O_WRONLY | O_EXCL, 0644); + if (traceoutfile < 0) { + log_error ("%s(%d): trace_begin: %s: %m", + file, line, filename); + return ISC_R_UNEXPECTED; + } +#if defined (HAVE_SETFD) + if (fcntl (traceoutfile, F_SETFD, 1) < 0) + log_error ("Can't set close-on-exec on %s: %m", filename); +#endif + + tfh.magic = htonl (TRACEFILE_MAGIC); + tfh.version = htonl (TRACEFILE_VERSION); + tfh.hlen = htonl (sizeof (tracefile_header_t)); + tfh.phlen = htonl (sizeof (tracepacket_t)); + + status = write (traceoutfile, &tfh, sizeof tfh); + if (status < 0) { + log_error ("%s(%d): trace_begin write failed: %m", file, line); + return ISC_R_UNEXPECTED; + } else if (status != sizeof tfh) { + log_error ("%s(%d): trace_begin: short write (%d:%ld)", + file, line, status, (long)(sizeof tfh)); + trace_stop (); + return ISC_R_UNEXPECTED; + } + + /* Stash all the types that have already been set up. */ + if (new_trace_types) { + next = new_trace_types; + new_trace_types = (trace_type_t *)0; + for (tptr = next; tptr; tptr = next) { + next = tptr -> next; + if (tptr -> index != 0) { + result = (trace_type_record + (tptr, + strlen (tptr -> name), file, line)); + if (result != ISC_R_SUCCESS) + return status; + } + } + } + + return ISC_R_SUCCESS; +} + +isc_result_t trace_write_packet (trace_type_t *ttype, unsigned length, + const char *buf, const char *file, int line) +{ + trace_iov_t iov; + + iov.buf = buf; + iov.len = length; + return trace_write_packet_iov (ttype, 1, &iov, file, line); +} + +isc_result_t trace_write_packet_iov (trace_type_t *ttype, + int count, trace_iov_t *iov, + const char *file, int line) +{ + tracepacket_t tmp; + int status; + int i; + int length; + + /* Really shouldn't get called here, but it may be hard to turn off + tracing midstream if the trace file write fails or something. */ + if (tracing_stopped) + return 0; + + if (!ttype) { + log_error ("%s(%d): trace_write_packet with null trace type", + file ? file : "<unknown file>", line); + return ISC_R_INVALIDARG; + } + if (!traceoutfile) { + log_error ("%s(%d): trace_write_packet with no tracefile.", + file ? file : "<unknown file>", line); + return ISC_R_INVALIDARG; + } + + /* Compute the total length of the iov. */ + length = 0; + for (i = 0; i < count; i++) + length += iov [i].len; + + /* We have to swap out the data, because it may be read back on a + machine of different endianness. */ + tmp.type_index = htonl (ttype -> index); + tmp.when = htonl (time ((time_t *)0)); /* XXX */ + tmp.length = htonl (length); + + status = write (traceoutfile, &tmp, sizeof tmp); + if (status < 0) { + log_error ("%s(%d): trace_write_packet write failed: %m", + file, line); + return ISC_R_UNEXPECTED; + } else if (status != sizeof tmp) { + log_error ("%s(%d): trace_write_packet: short write (%d:%ld)", + file, line, status, (long)(sizeof tmp)); + trace_stop (); + } + + for (i = 0; i < count; i++) { + status = write (traceoutfile, iov [i].buf, iov [i].len); + if (status < 0) { + log_error ("%s(%d): %s write failed: %m", + file, line, "trace_write_packet"); + return ISC_R_UNEXPECTED; + } else if (status != iov [i].len) { + log_error ("%s(%d): %s: short write (%d:%d)", + file, line, + "trace_write_packet", status, length); + trace_stop (); + } + } + + /* Write padding on the end of the packet to align the next + packet to an 8-byte boundary. This is in case we decide to + use mmap in some clever way later on. */ + if (length % 8) { + static char zero [] = { 0, 0, 0, 0, 0, 0, 0 }; + unsigned padl = 8 - (length % 8); + + status = write (traceoutfile, zero, padl); + if (status < 0) { + log_error ("%s(%d): trace_write_packet write failed: %m", + file, line); + return ISC_R_UNEXPECTED; + } else if (status != padl) { + log_error ("%s(%d): trace_write_packet: short write (%d:%d)", + file, line, status, padl); + trace_stop (); + } + } + + return ISC_R_SUCCESS; +} + +void trace_type_stash (trace_type_t *tptr) +{ + trace_type_t **vec; + int delta; + if (trace_type_max <= tptr -> index) { + delta = tptr -> index - trace_type_max + 10; + vec = dmalloc (((trace_type_max + delta) * + sizeof (trace_type_t *)), MDL); + if (!vec) + return; + memset (&vec [trace_type_max], 0, + (sizeof (trace_type_t *)) * delta); + trace_type_max += delta; + if (trace_types) { + memcpy (vec, trace_types, + trace_type_count * sizeof (trace_type_t *)); + dfree (trace_types, MDL); + } + trace_types = vec; + } + trace_types [tptr -> index] = tptr; + if (tptr -> index >= trace_type_count) + trace_type_count = tptr -> index + 1; +} + +trace_type_t *trace_type_register (const char *name, + void *baggage, + void (*have_packet) (trace_type_t *, + unsigned, char *), + void (*stop_tracing) (trace_type_t *), + const char *file, int line) +{ + trace_type_t *ttmp, *tptr; + unsigned slen = strlen (name); + isc_result_t status; + + ttmp = dmalloc (sizeof *ttmp, file, line); + if (!ttmp) + return ttmp; + ttmp -> index = -1; + ttmp -> name = dmalloc (slen + 1, file, line); + if (!ttmp -> name) { + dfree (ttmp, file, line); + return (trace_type_t *)0; + } + strcpy (ttmp -> name, name); + ttmp -> have_packet = have_packet; + ttmp -> stop_tracing = stop_tracing; + + if (traceoutfile) { + status = trace_type_record (ttmp, slen, file, line); + if (status != ISC_R_SUCCESS) { + dfree (ttmp -> name, file, line); + dfree (ttmp, file, line); + return (trace_type_t *)0; + } + } else { + ttmp -> next = new_trace_types; + new_trace_types = ttmp; + } + + return ttmp; +} + +static isc_result_t trace_type_record (trace_type_t *ttmp, unsigned slen, + const char *file, int line) +{ + trace_index_mapping_t *tim; + isc_result_t status; + + tim = dmalloc (slen + TRACE_INDEX_MAPPING_SIZE, file, line); + if (!tim) + return ISC_R_NOMEMORY; + ttmp -> index = ++traceindex; + trace_type_stash (ttmp); + tim -> index = htonl (ttmp -> index); + memcpy (tim -> name, ttmp -> name, slen); + status = trace_write_packet (trace_types [0], + slen + TRACE_INDEX_MAPPING_SIZE, + (char *)tim, file, line); + dfree (tim, file, line); + return status; +} + +/* Stop all registered trace types from trying to trace. */ + +void trace_stop (void) +{ + int i; + + for (i = 0; i < trace_type_count; i++) + if (trace_types [i] -> stop_tracing) + (*(trace_types [i] -> stop_tracing)) + (trace_types [i]); + tracing_stopped = 1; +} + +void trace_index_map_input (trace_type_t *ttype, unsigned length, char *buf) +{ + trace_index_mapping_t *tmap; + unsigned len; + trace_type_t *tptr, **prev; + + if (length < TRACE_INDEX_MAPPING_SIZE) { + log_error ("short trace index mapping"); + return; + } + tmap = (trace_index_mapping_t *)buf; + + prev = &new_trace_types; + for (tptr = new_trace_types; tptr; tptr = tptr -> next) { + len = strlen (tptr -> name); + if (len == length - TRACE_INDEX_MAPPING_SIZE && + !memcmp (tptr -> name, tmap -> name, len)) { + tptr -> index = ntohl (tmap -> index); + trace_type_stash (tptr); + *prev = tptr -> next; + return; + } + prev = &tptr -> next; + } + + log_error ("No registered trace type for type name %.*s", + (int)length - TRACE_INDEX_MAPPING_SIZE, tmap -> name); + return; +} + +void trace_index_stop_tracing (trace_type_t *ttype) { } + +void trace_replay_init (void) +{ + trace_playback_flag = 1; +} + +void trace_file_replay (const char *filename) +{ + tracepacket_t *tpkt = (tracepacket_t *)0; + int status; + char *buf = (char *)0; + unsigned buflen; + unsigned bufmax = 0; + trace_type_t *ttype = (trace_type_t *)0; + isc_result_t result; + int len; + + traceinfile = fopen (filename, "r"); + if (!traceinfile) { + log_error ("Can't open tracefile %s: %m", filename); + return; + } +#if defined (HAVE_SETFD) + if (fcntl (fileno (traceinfile), F_SETFD, 1) < 0) + log_error ("Can't set close-on-exec on %s: %m", filename); +#endif + status = fread (&tracefile_header, 1, + sizeof tracefile_header, traceinfile); + if (status < sizeof tracefile_header) { + if (ferror (traceinfile)) + log_error ("Error reading trace file header: %m"); + else + log_error ("Short read on trace file header: %d %ld.", + status, (long)(sizeof tracefile_header)); + goto out; + } + tracefile_header.magic = ntohl (tracefile_header.magic); + tracefile_header.version = ntohl (tracefile_header.version); + tracefile_header.hlen = ntohl (tracefile_header.hlen); + tracefile_header.phlen = ntohl (tracefile_header.phlen); + + if (tracefile_header.magic != TRACEFILE_MAGIC) { + log_error ("%s: not a dhcp trace file.", filename); + goto out; + } + if (tracefile_header.version > TRACEFILE_VERSION) { + log_error ("tracefile version %ld > current %ld.", + (long int)tracefile_header.version, + (long int)TRACEFILE_VERSION); + goto out; + } + if (tracefile_header.phlen < sizeof *tpkt) { + log_error ("tracefile packet size too small - %ld < %ld", + (long int)tracefile_header.phlen, + (long int)sizeof *tpkt); + goto out; + } + len = (sizeof tracefile_header) - tracefile_header.hlen; + if (len < 0) { + log_error ("tracefile header size too small - %ld < %ld", + (long int)tracefile_header.hlen, + (long int)sizeof tracefile_header); + goto out; + } + if (len > 0) { + status = fseek (traceinfile, (long)len, SEEK_CUR); + if (status < 0) { + log_error ("can't seek past header: %m"); + goto out; + } + } + + tpkt = dmalloc ((unsigned)tracefile_header.phlen, MDL); + if (!tpkt) { + log_error ("can't allocate trace packet header."); + goto out; + } + + while ((result = trace_get_next_packet (&ttype, tpkt, &buf, &buflen, + &bufmax)) == ISC_R_SUCCESS) { + (*ttype -> have_packet) (ttype, tpkt -> length, buf); + ttype = (trace_type_t *)0; + } + out: + fclose (traceinfile); + if (buf) + dfree (buf, MDL); + if (tpkt) + dfree (tpkt, MDL); +} + +/* Get the next packet from the file. If ttp points to a nonzero pointer + to a trace type structure, check the next packet to see if it's of the + expected type, and back off if not. */ + +isc_result_t trace_get_next_packet (trace_type_t **ttp, + tracepacket_t *tpkt, + char **buf, unsigned *buflen, + unsigned *bufmax) +{ + trace_type_t *ttype; + unsigned paylen; + int status; + int len; + fpos_t curpos; + + status = fgetpos (traceinfile, &curpos); + if (status < 0) + log_error ("Can't save tracefile position: %m"); + + status = fread (tpkt, 1, (size_t)tracefile_header.phlen, traceinfile); + if (status < tracefile_header.phlen) { + if (ferror (traceinfile)) + log_error ("Error reading trace packet header: %m"); + else if (status == 0) + return ISC_R_EOF; + else + log_error ("Short read on trace packet header: " + "%ld %ld.", + (long int)status, + (long int)tracefile_header.phlen); + return ISC_R_PROTOCOLERROR; + } + + /* Swap the packet. */ + tpkt -> type_index = ntohl (tpkt -> type_index); + tpkt -> length = ntohl (tpkt -> length); + tpkt -> when = ntohl (tpkt -> when); + + /* See if there's a handler for this packet type. */ + if (tpkt -> type_index < trace_type_count && + trace_types [tpkt -> type_index]) + ttype = trace_types [tpkt -> type_index]; + else { + log_error ("Trace packet with unknown index %ld", + (long int)tpkt -> type_index); + return ISC_R_PROTOCOLERROR; + } + + /* If we were just hunting for the time marker, we've found it, + so back up to the beginning of the packet and return its + type. */ + if (ttp && *ttp == &trace_time_marker) { + *ttp = ttype; + status = fsetpos (traceinfile, &curpos); + if (status < 0) { + log_error ("fsetpos in tracefile failed: %m"); + return ISC_R_PROTOCOLERROR; + } + return ISC_R_EXISTS; + } + + /* If we were supposed to get a particular kind of packet, + check to see that we got the right kind. */ + if (ttp && *ttp && ttype != *ttp) { + log_error ("Read packet type %s when expecting %s", + ttype -> name, (*ttp) -> name); + status = fsetpos (traceinfile, &curpos); + if (status < 0) { + log_error ("fsetpos in tracefile failed: %m"); + return ISC_R_PROTOCOLERROR; + } + return ISC_R_UNEXPECTEDTOKEN; + } + + paylen = tpkt -> length; + if (paylen % 8) + paylen += 8 - (tpkt -> length % 8); + if (paylen > (*bufmax)) { + if ((*buf)) + dfree ((*buf), MDL); + (*bufmax) = ((paylen + 1023) & ~1023U); + (*buf) = dmalloc ((*bufmax), MDL); + if (!(*buf)) { + log_error ("Can't allocate input buffer sized %d", + (*bufmax)); + return ISC_R_NOMEMORY; + } + } + + status = fread ((*buf), 1, paylen, traceinfile); + if (status < paylen) { + if (ferror (traceinfile)) + log_error ("Error reading trace payload: %m"); + else + log_error ("Short read on trace payload: %d %d.", + status, paylen); + return ISC_R_PROTOCOLERROR; + } + + /* Store the actual length of the payload. */ + *buflen = tpkt -> length; + + if (trace_set_time_hook) + (*trace_set_time_hook) (tpkt -> when); + + if (ttp) + *ttp = ttype; + return ISC_R_SUCCESS; +} + +isc_result_t trace_get_packet (trace_type_t **ttp, + unsigned *buflen, char **buf) +{ + tracepacket_t *tpkt; + unsigned bufmax = 0; + isc_result_t status; + + if (!buf || *buf) + return ISC_R_INVALIDARG; + + tpkt = dmalloc ((unsigned)tracefile_header.phlen, MDL); + if (!tpkt) { + log_error ("can't allocate trace packet header."); + return ISC_R_NOMEMORY; + } + + status = trace_get_next_packet (ttp, tpkt, buf, buflen, &bufmax); + + dfree (tpkt, MDL); + return status; +} + +time_t trace_snoop_time (trace_type_t **ptp) +{ + tracepacket_t *tpkt; + unsigned bufmax = 0; + unsigned buflen = 0; + char *buf = (char *)0; + isc_result_t status; + time_t result; + trace_type_t *ttp; + + if (!ptp) + ptp = &ttp; + + tpkt = dmalloc ((unsigned)tracefile_header.phlen, MDL); + if (!tpkt) { + log_error ("can't allocate trace packet header."); + return ISC_R_NOMEMORY; + } + + *ptp = &trace_time_marker; + trace_get_next_packet (ptp, tpkt, &buf, &buflen, &bufmax); + result = tpkt -> when; + + dfree (tpkt, MDL); + return result; +} + +/* Get a packet from the trace input file that contains a file with the + specified name. We don't hunt for the packet - it should be the next + packet in the tracefile. If it's not, or something else bad happens, + return an error code. */ + +isc_result_t trace_get_file (trace_type_t *ttype, + const char *filename, unsigned *len, char **buf) +{ + fpos_t curpos; + unsigned max = 0; + tracepacket_t *tpkt; + int status; + isc_result_t result; + + /* Disallow some obvious bogosities. */ + if (!buf || !len || *buf) + return ISC_R_INVALIDARG; + + /* Save file position in case of filename mismatch. */ + status = fgetpos (traceinfile, &curpos); + if (status < 0) + log_error ("Can't save tracefile position: %m"); + + tpkt = dmalloc ((unsigned)tracefile_header.phlen, MDL); + if (!tpkt) { + log_error ("can't allocate trace packet header."); + return ISC_R_NOMEMORY; + } + + result = trace_get_next_packet (&ttype, tpkt, buf, len, &max); + if (result != ISC_R_SUCCESS) { + dfree (tpkt, MDL); + if (*buf) + dfree (*buf, MDL); + return result; + } + + /* Make sure the filename is right. */ + if (strcmp (filename, *buf)) { + log_error ("Read file %s when expecting %s", *buf, filename); + status = fsetpos (traceinfile, &curpos); + if (status < 0) { + log_error ("fsetpos in tracefile failed: %m"); + dfree (tpkt, MDL); + dfree (*buf, MDL); + return ISC_R_PROTOCOLERROR; + } + return ISC_R_UNEXPECTEDTOKEN; + } + + dfree (tpkt, MDL); + return ISC_R_SUCCESS; +} +#endif /* TRACING */ diff --git a/contrib/isc-dhcp/site.conf b/contrib/isc-dhcp/site.conf new file mode 100644 index 0000000..fced754 --- /dev/null +++ b/contrib/isc-dhcp/site.conf @@ -0,0 +1,2 @@ +# Put local site configuration stuff here to override the default +# settings in Makefile.conf diff --git a/contrib/isc-dhcp/tests/failover/dhcp-1.cf b/contrib/isc-dhcp/tests/failover/dhcp-1.cf new file mode 100644 index 0000000..24c1b53 --- /dev/null +++ b/contrib/isc-dhcp/tests/failover/dhcp-1.cf @@ -0,0 +1,144 @@ +authoritative; + +class "even" { + match if ((extract-int (suffix + (pick-first-value (option dhcp-client-identifier, + hardware), 1), 8) % 2) = 0); +} +class "odd" { + match if ((extract-int (suffix + (pick-first-value (option dhcp-client-identifier, + hardware), 1), 8) % 2) = 1); +} + +lease-file-name "dhcp-1.leases"; +pid-file-name "dhcp-1.pid"; +ddns-update-style none; +local-port 50002; +remote-port 50003; +omapi-port 50004; +omapi-key FOO; + +default-lease-time 600; +max-lease-time 600; + +failover peer "foo" { + primary; + address 10.0.0.1; + port 51000; + peer address 10.0.0.1; + peer port 51001; + max-response-delay 60; + max-unacked-updates 10; + mclt 100; + hba ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff: + 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00; + load balance max seconds 2; +} + +option space SUNW; +option SUNW.root-mount-options code 1 = text; +option SUNW.root-server-ip-address code 2 = ip-address; +option SUNW.root-server-hostname code 3 = text; +option SUNW.root-path-name code 4 = text; +option SUNW.swap-server-ip-address code 5 = ip-address; +option SUNW.swap-file-path code 6 = text; +option SUNW.boot-file-path code 7 = text; +option SUNW.posix-timezone-string code 8 = text; +option SUNW.boot-read-size code 9 = unsigned integer 16; +option SUNW.install-server-ip-address code 10 = ip-address; +option SUNW.install-server-hostname code 11 = text; +option SUNW.install-path code 12 = text; +option SUNW.sysid-config-file-server code 13 = text; +option SUNW.JumpStart-server code 14 = text; +option SUNW.terminal-name code 15 = text; + +class "solaris-i86pc" { + match if option vendor-class-identifier = "SUNW.i86pc"; + vendor-option-space SUNW; + option SUNW.boot-file-path "/platform/i86pc/kernel/unix"; + option SUNW.root-path-name "/export/root/i86pc"; +} + +class "solaris-sun4u" { + match if option vendor-class-identifier = "SUNW.Ultra-5_10"; + vendor-option-space SUNW; + option SUNW.install-path "/export/2/s581_sparc"; + option SUNW.root-path-name "/export/2/s581_sparc/Solaris_8/Tools/Boot"; +} + +option domain-name "connectathon.org."; +option SUNW.root-server-ip-address 172.16.113.1; +option SUNW.root-server-hostname "sundhcp-server17-1"; + +key FOO { + algorithm HMAC-MD5.SIG-ALG.REG.INT; + secret ABCD; +} + +zone BISBEE.FUGUE.COM. { + primary 127.0.0.1; + key FOO; +} + +zone 17.127.10.in-addr.arpa. { + primary 127.0.0.1; + key FOO; +} + +zone 0.0.10.in-addr.arpa. { + primary 127.0.0.1; + key FOO; +} + +subnet 204.152.186.128 netmask 255.255.255.192 { + not authoritative; +} + +shared-network LOCAL { + subnet 127.0.0.0 netmask 255.255.255.0 { + } + subnet 10.0.2.0 netmask 255.255.255.0 { + pool { + deny dynamic bootp clients; + failover peer "foo"; + range 10.0.2.100 10.0.2.200; + } + } +} + +shared-network NET-187 { + subnet 204.152.187.0 netmask 255.255.255.0 { + } + subnet 205.140.116.224 netmask 255.255.255.248 { + } + subnet 10.0.1.0 netmask 255.255.255.0 { + pool { + deny dynamic bootp clients; + failover peer "foo"; + range 10.0.1.10 10.0.1.200; + } + } +} + +subnet 10.0.0.0 netmask 255.255.255.0 { + pool { + deny dynamic bootp clients; + allow members of "even"; + option impress-servers 10.0.0.0; + failover peer "foo"; + range 10.0.0.10 10.0.0.54; + range 10.0.0.100 10.0.0.149; + } + pool { + deny dynamic bootp clients; + allow members of "odd"; + failover peer "foo"; + option impress-servers 10.0.0.1; + range 10.0.0.55 10.0.0.99; + range 10.0.0.150 10.0.0.200; + } + option routers 10.0.0.1; + option domain-name "bisbee.fugue.com"; + option domain-name-servers 10.0.0.1; +} diff --git a/contrib/isc-dhcp/tests/failover/dhcp-2.cf b/contrib/isc-dhcp/tests/failover/dhcp-2.cf new file mode 100644 index 0000000..ee31b7d --- /dev/null +++ b/contrib/isc-dhcp/tests/failover/dhcp-2.cf @@ -0,0 +1,142 @@ +authoritative; + +class "even" { + match if ((extract-int (suffix + (pick-first-value (option dhcp-client-identifier, + hardware), 1), 8) % 2) = 0); +} +class "odd" { + match if ((extract-int (suffix + (pick-first-value (option dhcp-client-identifier, + hardware), 1), 8) % 2) = 1); +} + +lease-file-name "dhcp-2.leases"; +pid-file-name "dhcp-2.pid"; +local-port 50000; +remote-port 50001; +omapi-port 50005; + +ddns-update-style none; + +default-lease-time 600; +max-lease-time 600; + +failover peer "foo" { + secondary; + address 10.0.0.1; + port 51001; + peer address 10.0.0.1; + peer port 51000; + max-response-delay 60; + max-unacked-updates 10; + mclt 100; + load balance max seconds 2; +} + +option space SUNW; +option SUNW.root-mount-options code 1 = text; +option SUNW.root-server-ip-address code 2 = ip-address; +option SUNW.root-server-hostname code 3 = text; +option SUNW.root-path-name code 4 = text; +option SUNW.swap-server-ip-address code 5 = ip-address; +option SUNW.swap-file-path code 6 = text; +option SUNW.boot-file-path code 7 = text; +option SUNW.posix-timezone-string code 8 = text; +option SUNW.boot-read-size code 9 = unsigned integer 16; +option SUNW.install-server-ip-address code 10 = ip-address; +option SUNW.install-server-hostname code 11 = text; +option SUNW.install-path code 12 = text; +option SUNW.sysid-config-file-server code 13 = text; +option SUNW.JumpStart-server code 14 = text; +option SUNW.terminal-name code 15 = text; + +class "solaris-i86pc" { + match if option vendor-class-identifier = "SUNW.i86pc"; + vendor-option-space SUNW; + option SUNW.boot-file-path "/platform/i86pc/kernel/unix"; + option SUNW.root-path-name "/export/root/i86pc"; +} + +class "solaris-sun4u" { + match if option vendor-class-identifier = "SUNW.Ultra-5_10"; + vendor-option-space SUNW; + option SUNW.install-path "/export/2/s581_sparc"; + option SUNW.root-path-name "/export/2/s581_sparc/Solaris_8/Tools/Boot"; +} + +option domain-name "connectathon.org."; +option SUNW.root-server-ip-address 172.16.113.1; +option SUNW.root-server-hostname "sundhcp-server17-1"; + +key FOO { + algorithm HMAC-MD5.SIG-ALG.REG.INT; + secret ABCD; +} + +zone BISBEE.FUGUE.COM. { + primary 127.0.0.1; + key FOO; +} + +zone 17.127.10.in-addr.arpa. { + primary 127.0.0.1; + key FOO; +} + +zone 0.0.10.in-addr.arpa. { + primary 127.0.0.1; + key FOO; +} + +subnet 204.152.186.128 netmask 255.255.255.192 { + not authoritative; +} + +shared-network LOCAL { + subnet 127.0.0.0 netmask 255.255.255.0 { + } + subnet 10.0.2.0 netmask 255.255.255.0 { + pool { + deny dynamic bootp clients; + failover peer "foo"; + range 10.0.2.100 10.0.2.200; + } + } +} + +shared-network 187-NET { + subnet 204.152.187.0 netmask 255.255.255.0 { + } + subnet 205.140.116.224 netmask 255.255.255.248 { + } + subnet 10.0.1.0 netmask 255.255.255.0 { + pool { + deny dynamic bootp clients; + failover peer "foo"; + range 10.0.1.10 10.0.1.200; + } + } +} + +subnet 10.0.0.0 netmask 255.255.255.0 { + pool { + deny dynamic bootp clients; + allow members of "even"; + option impress-servers 10.0.0.0; + failover peer "foo"; + range 10.0.0.10 10.0.0.54; + range 10.0.0.100 10.0.0.149; + } + pool { + deny dynamic bootp clients; + allow members of "odd"; + failover peer "foo"; + option impress-servers 10.0.0.1; + range 10.0.0.55 10.0.0.99; + range 10.0.0.150 10.0.0.200; + } + option routers 10.0.0.1; + option domain-name "bisbee.fugue.com"; + option domain-name-servers 10.0.0.1; +} diff --git a/contrib/isc-dhcp/tests/failover/new-failover b/contrib/isc-dhcp/tests/failover/new-failover new file mode 100755 index 0000000..65d82e0 --- /dev/null +++ b/contrib/isc-dhcp/tests/failover/new-failover @@ -0,0 +1,28 @@ +#!/bin/sh + +foo=10 +while [ $foo -lt 100 ]; do + cat >>dhcp-1.leases <<~ +lease 10.0.0.$foo { + starts 4 2001/05/01 02:19:16; + ends 5 2021/05/03 02:29:16; + binding state active; + next binding state free; + hardware ethernet 08:00:46:06:6c:23; + uid "test-$foo"; +} +~ + foo=`expr $foo + 1` + cat >>dhcp-2.leases <<~ +lease 10.0.0.$foo { + starts 4 2001/04/19 02:19:16; + ends 5 2021/04/21 02:29:16; + binding state active; + next binding state free; + hardware ethernet 08:00:46:06:6c:23; + uid "test-$foo"; +} +~ + foo=`expr $foo + 1` +done + |