]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Initial pull over from BIND 8
authorMark Andrews <marka@isc.org>
Thu, 29 Mar 2001 06:31:59 +0000 (06:31 +0000)
committerMark Andrews <marka@isc.org>
Thu, 29 Mar 2001 06:31:59 +0000 (06:31 +0000)
399 files changed:
lib/bind/Makefile.in [new file with mode: 0644]
lib/bind/README [new file with mode: 0644]
lib/bind/bsd/Makefile.in [new file with mode: 0644]
lib/bind/bsd/daemon.c [new file with mode: 0644]
lib/bind/bsd/ftruncate.c [new file with mode: 0644]
lib/bind/bsd/gettimeofday.c [new file with mode: 0644]
lib/bind/bsd/gettimeofday.h [new file with mode: 0644]
lib/bind/bsd/mktemp.c [new file with mode: 0644]
lib/bind/bsd/putenv.c [new file with mode: 0644]
lib/bind/bsd/readv.c [new file with mode: 0644]
lib/bind/bsd/setenv.c [new file with mode: 0644]
lib/bind/bsd/setitimer.c [new file with mode: 0644]
lib/bind/bsd/strcasecmp.c [new file with mode: 0644]
lib/bind/bsd/strdup.c [new file with mode: 0644]
lib/bind/bsd/strerror.c [new file with mode: 0644]
lib/bind/bsd/strpbrk.c [new file with mode: 0644]
lib/bind/bsd/strsep.c [new file with mode: 0644]
lib/bind/bsd/strtoul.c [new file with mode: 0644]
lib/bind/bsd/utimes.c [new file with mode: 0644]
lib/bind/bsd/writev.c [new file with mode: 0644]
lib/bind/config.h.in [new file with mode: 0644]
lib/bind/configure [new file with mode: 0644]
lib/bind/configure.in [new file with mode: 0644]
lib/bind/cylink/Makefile.in [new file with mode: 0644]
lib/bind/cylink/bits.c [new file with mode: 0644]
lib/bind/cylink/bn.c [new file with mode: 0644]
lib/bind/cylink/bn.h [new file with mode: 0644]
lib/bind/cylink/bn00.c [new file with mode: 0644]
lib/bind/cylink/bn16.c [new file with mode: 0644]
lib/bind/cylink/bn16.h [new file with mode: 0644]
lib/bind/cylink/bn32.c [new file with mode: 0644]
lib/bind/cylink/bn32.h [new file with mode: 0644]
lib/bind/cylink/bn68000.c [new file with mode: 0644]
lib/bind/cylink/bn8086.c [new file with mode: 0644]
lib/bind/cylink/bninit16.c [new file with mode: 0644]
lib/bind/cylink/bninit32.c [new file with mode: 0644]
lib/bind/cylink/bnsize00.h [new file with mode: 0644]
lib/bind/cylink/c_asm.h [new file with mode: 0644]
lib/bind/cylink/cencrint.h [new file with mode: 0644]
lib/bind/cylink/ctk_endian.h [new file with mode: 0644]
lib/bind/cylink/ctk_prime.c [new file with mode: 0644]
lib/bind/cylink/cylink.h [new file with mode: 0644]
lib/bind/cylink/dss.c [new file with mode: 0644]
lib/bind/cylink/dssnum.h [new file with mode: 0644]
lib/bind/cylink/funcs.h [new file with mode: 0644]
lib/bind/cylink/kludge.h [new file with mode: 0644]
lib/bind/cylink/lbn.h [new file with mode: 0644]
lib/bind/cylink/lbn00.c [new file with mode: 0644]
lib/bind/cylink/lbn16.c [new file with mode: 0644]
lib/bind/cylink/lbn16.h [new file with mode: 0644]
lib/bind/cylink/lbn32.c [new file with mode: 0644]
lib/bind/cylink/lbn32.h [new file with mode: 0644]
lib/bind/cylink/lbn68000.c [new file with mode: 0644]
lib/bind/cylink/lbn68000.h [new file with mode: 0644]
lib/bind/cylink/lbn68020.c [new file with mode: 0644]
lib/bind/cylink/lbn68020.h [new file with mode: 0644]
lib/bind/cylink/lbn80386.h [new file with mode: 0644]
lib/bind/cylink/lbn8086.h [new file with mode: 0644]
lib/bind/cylink/lbnmem.c [new file with mode: 0644]
lib/bind/cylink/lbnmem.h [new file with mode: 0644]
lib/bind/cylink/lbnppc.c [new file with mode: 0644]
lib/bind/cylink/lbnppc.h [new file with mode: 0644]
lib/bind/cylink/legal.c [new file with mode: 0644]
lib/bind/cylink/legal.h [new file with mode: 0644]
lib/bind/cylink/math.c [new file with mode: 0644]
lib/bind/cylink/ppcasm.h [new file with mode: 0644]
lib/bind/cylink/rand.c [new file with mode: 0644]
lib/bind/cylink/sha.c [new file with mode: 0644]
lib/bind/cylink/sha.h [new file with mode: 0644]
lib/bind/cylink/sizetest.c [new file with mode: 0644]
lib/bind/cylink/swap.c [new file with mode: 0644]
lib/bind/cylink/toolkit.h [new file with mode: 0644]
lib/bind/dnssafe/Makefile.in [new file with mode: 0644]
lib/bind/dnssafe/ahcbcpad.c [new file with mode: 0644]
lib/bind/dnssafe/ahcbcpad.h [new file with mode: 0644]
lib/bind/dnssafe/ahchdig.c [new file with mode: 0644]
lib/bind/dnssafe/ahchdig.h [new file with mode: 0644]
lib/bind/dnssafe/ahchencr.c [new file with mode: 0644]
lib/bind/dnssafe/ahchencr.h [new file with mode: 0644]
lib/bind/dnssafe/ahchgen.c [new file with mode: 0644]
lib/bind/dnssafe/ahchgen.h [new file with mode: 0644]
lib/bind/dnssafe/ahchrand.c [new file with mode: 0644]
lib/bind/dnssafe/ahchrand.h [new file with mode: 0644]
lib/bind/dnssafe/ahdigest.c [new file with mode: 0644]
lib/bind/dnssafe/ahdigest.h [new file with mode: 0644]
lib/bind/dnssafe/ahencryp.c [new file with mode: 0644]
lib/bind/dnssafe/ahencryp.h [new file with mode: 0644]
lib/bind/dnssafe/ahgen.c [new file with mode: 0644]
lib/bind/dnssafe/ahgen.h [new file with mode: 0644]
lib/bind/dnssafe/ahrandom.c [new file with mode: 0644]
lib/bind/dnssafe/ahrandom.h [new file with mode: 0644]
lib/bind/dnssafe/ahrsaenc.c [new file with mode: 0644]
lib/bind/dnssafe/ahrsaenc.h [new file with mode: 0644]
lib/bind/dnssafe/ahrsaepr.c [new file with mode: 0644]
lib/bind/dnssafe/ahrsaepr.h [new file with mode: 0644]
lib/bind/dnssafe/ahrsaepu.c [new file with mode: 0644]
lib/bind/dnssafe/ahrsaepu.h [new file with mode: 0644]
lib/bind/dnssafe/aichdig.c [new file with mode: 0644]
lib/bind/dnssafe/aichdig.h [new file with mode: 0644]
lib/bind/dnssafe/aichenc8.c [new file with mode: 0644]
lib/bind/dnssafe/aichenc8.h [new file with mode: 0644]
lib/bind/dnssafe/aichencn.c [new file with mode: 0644]
lib/bind/dnssafe/aichencn.h [new file with mode: 0644]
lib/bind/dnssafe/aichencr.c [new file with mode: 0644]
lib/bind/dnssafe/aichencr.h [new file with mode: 0644]
lib/bind/dnssafe/aichgen.c [new file with mode: 0644]
lib/bind/dnssafe/aichgen.h [new file with mode: 0644]
lib/bind/dnssafe/aichrand.c [new file with mode: 0644]
lib/bind/dnssafe/aichrand.h [new file with mode: 0644]
lib/bind/dnssafe/aimd5.c [new file with mode: 0644]
lib/bind/dnssafe/aimd5ran.c [new file with mode: 0644]
lib/bind/dnssafe/ainfotyp.c [new file with mode: 0644]
lib/bind/dnssafe/ainfotyp.h [new file with mode: 0644]
lib/bind/dnssafe/ainull.c [new file with mode: 0644]
lib/bind/dnssafe/ainull.h [new file with mode: 0644]
lib/bind/dnssafe/airsaepr.c [new file with mode: 0644]
lib/bind/dnssafe/airsaepu.c [new file with mode: 0644]
lib/bind/dnssafe/airsakgn.c [new file with mode: 0644]
lib/bind/dnssafe/airsaprv.c [new file with mode: 0644]
lib/bind/dnssafe/airsapub.c [new file with mode: 0644]
lib/bind/dnssafe/algae.h [new file with mode: 0644]
lib/bind/dnssafe/algchoic.c [new file with mode: 0644]
lib/bind/dnssafe/algchoic.h [new file with mode: 0644]
lib/bind/dnssafe/algobj.c [new file with mode: 0644]
lib/bind/dnssafe/algobj.h [new file with mode: 0644]
lib/bind/dnssafe/amcrte.c [new file with mode: 0644]
lib/bind/dnssafe/amdigest.h [new file with mode: 0644]
lib/bind/dnssafe/amencdec.h [new file with mode: 0644]
lib/bind/dnssafe/amgen.h [new file with mode: 0644]
lib/bind/dnssafe/ammd5.c [new file with mode: 0644]
lib/bind/dnssafe/ammd5r.c [new file with mode: 0644]
lib/bind/dnssafe/amrandom.h [new file with mode: 0644]
lib/bind/dnssafe/amrkg.c [new file with mode: 0644]
lib/bind/dnssafe/amrsae.c [new file with mode: 0644]
lib/bind/dnssafe/atypes.h [new file with mode: 0644]
lib/bind/dnssafe/balg.c [new file with mode: 0644]
lib/bind/dnssafe/balg.h [new file with mode: 0644]
lib/bind/dnssafe/balgmeth.h [new file with mode: 0644]
lib/bind/dnssafe/bgclrbit.c [new file with mode: 0644]
lib/bind/dnssafe/bgmdmpyx.c [new file with mode: 0644]
lib/bind/dnssafe/bgmdsqx.c [new file with mode: 0644]
lib/bind/dnssafe/bgmodexp.c [new file with mode: 0644]
lib/bind/dnssafe/bgpegcd.c [new file with mode: 0644]
lib/bind/dnssafe/big2exp.c [new file with mode: 0644]
lib/bind/dnssafe/bigabs.c [new file with mode: 0644]
lib/bind/dnssafe/bigacc.c [new file with mode: 0644]
lib/bind/dnssafe/bigarith.c [new file with mode: 0644]
lib/bind/dnssafe/bigcmp.c [new file with mode: 0644]
lib/bind/dnssafe/bigconst.c [new file with mode: 0644]
lib/bind/dnssafe/biginv.c [new file with mode: 0644]
lib/bind/dnssafe/biglen.c [new file with mode: 0644]
lib/bind/dnssafe/bigmath.h [new file with mode: 0644]
lib/bind/dnssafe/bigmaxes.h [new file with mode: 0644]
lib/bind/dnssafe/bigmodx.c [new file with mode: 0644]
lib/bind/dnssafe/bigmpy.c [new file with mode: 0644]
lib/bind/dnssafe/bigpdiv.c [new file with mode: 0644]
lib/bind/dnssafe/bigpmpy.c [new file with mode: 0644]
lib/bind/dnssafe/bigpmpyh.c [new file with mode: 0644]
lib/bind/dnssafe/bigpmpyl.c [new file with mode: 0644]
lib/bind/dnssafe/bigpsq.c [new file with mode: 0644]
lib/bind/dnssafe/bigqrx.c [new file with mode: 0644]
lib/bind/dnssafe/bigsmod.c [new file with mode: 0644]
lib/bind/dnssafe/bigtocan.c [new file with mode: 0644]
lib/bind/dnssafe/bigu.c [new file with mode: 0644]
lib/bind/dnssafe/bigunexp.c [new file with mode: 0644]
lib/bind/dnssafe/binfocsh.c [new file with mode: 0644]
lib/bind/dnssafe/binfocsh.h [new file with mode: 0644]
lib/bind/dnssafe/bkey.c [new file with mode: 0644]
lib/bind/dnssafe/bkey.h [new file with mode: 0644]
lib/bind/dnssafe/bmempool.c [new file with mode: 0644]
lib/bind/dnssafe/bmempool.h [new file with mode: 0644]
lib/bind/dnssafe/bsafe2.h [new file with mode: 0644]
lib/bind/dnssafe/btypechk.h [new file with mode: 0644]
lib/bind/dnssafe/cantobig.c [new file with mode: 0644]
lib/bind/dnssafe/crt2.c [new file with mode: 0644]
lib/bind/dnssafe/crt2.h [new file with mode: 0644]
lib/bind/dnssafe/digest.c [new file with mode: 0644]
lib/bind/dnssafe/digrand.c [new file with mode: 0644]
lib/bind/dnssafe/digrand.h [new file with mode: 0644]
lib/bind/dnssafe/encrypt.c [new file with mode: 0644]
lib/bind/dnssafe/generate.c [new file with mode: 0644]
lib/bind/dnssafe/global.h [new file with mode: 0644]
lib/bind/dnssafe/intbits.c [new file with mode: 0644]
lib/bind/dnssafe/intitem.c [new file with mode: 0644]
lib/bind/dnssafe/intitem.h [new file with mode: 0644]
lib/bind/dnssafe/keyobj.c [new file with mode: 0644]
lib/bind/dnssafe/keyobj.h [new file with mode: 0644]
lib/bind/dnssafe/ki8byte.c [new file with mode: 0644]
lib/bind/dnssafe/ki8byte.h [new file with mode: 0644]
lib/bind/dnssafe/kifulprv.c [new file with mode: 0644]
lib/bind/dnssafe/kifulprv.h [new file with mode: 0644]
lib/bind/dnssafe/kiitem.c [new file with mode: 0644]
lib/bind/dnssafe/kiitem.h [new file with mode: 0644]
lib/bind/dnssafe/kinfotyp.c [new file with mode: 0644]
lib/bind/dnssafe/kinfotyp.h [new file with mode: 0644]
lib/bind/dnssafe/kipkcrpr.c [new file with mode: 0644]
lib/bind/dnssafe/kipkcrpr.h [new file with mode: 0644]
lib/bind/dnssafe/kirsacrt.c [new file with mode: 0644]
lib/bind/dnssafe/kirsapub.c [new file with mode: 0644]
lib/bind/dnssafe/kirsapub.h [new file with mode: 0644]
lib/bind/dnssafe/md5.c [new file with mode: 0644]
lib/bind/dnssafe/md5.h [new file with mode: 0644]
lib/bind/dnssafe/md5rand.c [new file with mode: 0644]
lib/bind/dnssafe/md5rand.h [new file with mode: 0644]
lib/bind/dnssafe/prime.c [new file with mode: 0644]
lib/bind/dnssafe/prime.h [new file with mode: 0644]
lib/bind/dnssafe/random.c [new file with mode: 0644]
lib/bind/dnssafe/rsa.c [new file with mode: 0644]
lib/bind/dnssafe/rsa.h [new file with mode: 0644]
lib/bind/dnssafe/rsakeygn.c [new file with mode: 0644]
lib/bind/dnssafe/rsakeygn.h [new file with mode: 0644]
lib/bind/dnssafe/seccbcd.c [new file with mode: 0644]
lib/bind/dnssafe/seccbce.c [new file with mode: 0644]
lib/bind/dnssafe/secrcbc.h [new file with mode: 0644]
lib/bind/dnssafe/surrendr.c [new file with mode: 0644]
lib/bind/dnssafe/surrendr.h [new file with mode: 0644]
lib/bind/dst/Makefile.in [new file with mode: 0644]
lib/bind/dst/bsafe_link.c [new file with mode: 0644]
lib/bind/dst/cylink_link.c [new file with mode: 0644]
lib/bind/dst/dst_api.c [new file with mode: 0644]
lib/bind/dst/dst_internal.h [new file with mode: 0644]
lib/bind/dst/eay_dss_link.c [new file with mode: 0644]
lib/bind/dst/hmac_link.c [new file with mode: 0644]
lib/bind/dst/md5.h [new file with mode: 0644]
lib/bind/dst/md5_dgst.c [new file with mode: 0644]
lib/bind/dst/md5_locl.h [new file with mode: 0644]
lib/bind/dst/prandom.c [new file with mode: 0644]
lib/bind/dst/rsaref_link.c [new file with mode: 0644]
lib/bind/dst/support.c [new file with mode: 0644]
lib/bind/include/Makefile.in [new file with mode: 0644]
lib/bind/include/arpa/inet.h [new file with mode: 0644]
lib/bind/include/arpa/nameser.h [new file with mode: 0644]
lib/bind/include/arpa/nameser_compat.h [new file with mode: 0644]
lib/bind/include/fd_setsize.h [new file with mode: 0644]
lib/bind/include/hesiod.h [new file with mode: 0644]
lib/bind/include/irp.h [new file with mode: 0644]
lib/bind/include/irs.h [new file with mode: 0644]
lib/bind/include/isc/assertions.h [new file with mode: 0644]
lib/bind/include/isc/ctl.h [new file with mode: 0644]
lib/bind/include/isc/dst.h [new file with mode: 0644]
lib/bind/include/isc/eventlib.h [new file with mode: 0644]
lib/bind/include/isc/heap.h [new file with mode: 0644]
lib/bind/include/isc/irpmarshall.h [new file with mode: 0644]
lib/bind/include/isc/list.h [new file with mode: 0644]
lib/bind/include/isc/logging.h [new file with mode: 0644]
lib/bind/include/isc/memcluster.h [new file with mode: 0644]
lib/bind/include/isc/misc.h [new file with mode: 0644]
lib/bind/include/isc/tree.h [new file with mode: 0644]
lib/bind/include/netdb.h [new file with mode: 0644]
lib/bind/include/netgroup.h [new file with mode: 0644]
lib/bind/include/res_update.h [new file with mode: 0644]
lib/bind/include/resolv.h [new file with mode: 0644]
lib/bind/inet/Makefile.in [new file with mode: 0644]
lib/bind/inet/inet_addr.c [new file with mode: 0644]
lib/bind/inet/inet_cidr_ntop.c [new file with mode: 0644]
lib/bind/inet/inet_cidr_pton.c [new file with mode: 0644]
lib/bind/inet/inet_data.c [new file with mode: 0644]
lib/bind/inet/inet_lnaof.c [new file with mode: 0644]
lib/bind/inet/inet_makeaddr.c [new file with mode: 0644]
lib/bind/inet/inet_net_ntop.c [new file with mode: 0644]
lib/bind/inet/inet_net_pton.c [new file with mode: 0644]
lib/bind/inet/inet_neta.c [new file with mode: 0644]
lib/bind/inet/inet_netof.c [new file with mode: 0644]
lib/bind/inet/inet_network.c [new file with mode: 0644]
lib/bind/inet/inet_ntoa.c [new file with mode: 0644]
lib/bind/inet/inet_ntop.c [new file with mode: 0644]
lib/bind/inet/inet_pton.c [new file with mode: 0644]
lib/bind/inet/nsap_addr.c [new file with mode: 0644]
lib/bind/irs/Makefile.in [new file with mode: 0644]
lib/bind/irs/dns.c [new file with mode: 0644]
lib/bind/irs/dns_gr.c [new file with mode: 0644]
lib/bind/irs/dns_ho.c [new file with mode: 0644]
lib/bind/irs/dns_nw.c [new file with mode: 0644]
lib/bind/irs/dns_p.h [new file with mode: 0644]
lib/bind/irs/dns_pr.c [new file with mode: 0644]
lib/bind/irs/dns_pw.c [new file with mode: 0644]
lib/bind/irs/dns_sv.c [new file with mode: 0644]
lib/bind/irs/gai_strerror.c [new file with mode: 0644]
lib/bind/irs/gen.c [new file with mode: 0644]
lib/bind/irs/gen_gr.c [new file with mode: 0644]
lib/bind/irs/gen_ho.c [new file with mode: 0644]
lib/bind/irs/gen_ng.c [new file with mode: 0644]
lib/bind/irs/gen_nw.c [new file with mode: 0644]
lib/bind/irs/gen_p.h [new file with mode: 0644]
lib/bind/irs/gen_pr.c [new file with mode: 0644]
lib/bind/irs/gen_pw.c [new file with mode: 0644]
lib/bind/irs/gen_sv.c [new file with mode: 0644]
lib/bind/irs/getaddrinfo.c [new file with mode: 0644]
lib/bind/irs/getgrent.c [new file with mode: 0644]
lib/bind/irs/getgrent_r.c [new file with mode: 0644]
lib/bind/irs/gethostent.c [new file with mode: 0644]
lib/bind/irs/gethostent_r.c [new file with mode: 0644]
lib/bind/irs/getnameinfo.c [new file with mode: 0644]
lib/bind/irs/getnetent.c [new file with mode: 0644]
lib/bind/irs/getnetent_r.c [new file with mode: 0644]
lib/bind/irs/getnetgrent.c [new file with mode: 0644]
lib/bind/irs/getnetgrent_r.c [new file with mode: 0644]
lib/bind/irs/getprotoent.c [new file with mode: 0644]
lib/bind/irs/getprotoent_r.c [new file with mode: 0644]
lib/bind/irs/getpwent.c [new file with mode: 0644]
lib/bind/irs/getpwent_r.c [new file with mode: 0644]
lib/bind/irs/getservent.c [new file with mode: 0644]
lib/bind/irs/getservent_r.c [new file with mode: 0644]
lib/bind/irs/hesiod.c [new file with mode: 0644]
lib/bind/irs/hesiod_p.h [new file with mode: 0644]
lib/bind/irs/irp.c [new file with mode: 0644]
lib/bind/irs/irp_gr.c [new file with mode: 0644]
lib/bind/irs/irp_ho.c [new file with mode: 0644]
lib/bind/irs/irp_ng.c [new file with mode: 0644]
lib/bind/irs/irp_nw.c [new file with mode: 0644]
lib/bind/irs/irp_p.h [new file with mode: 0644]
lib/bind/irs/irp_pr.c [new file with mode: 0644]
lib/bind/irs/irp_pw.c [new file with mode: 0644]
lib/bind/irs/irp_sv.c [new file with mode: 0644]
lib/bind/irs/irpmarshall.c [new file with mode: 0644]
lib/bind/irs/irs_data.c [new file with mode: 0644]
lib/bind/irs/irs_data.h [new file with mode: 0644]
lib/bind/irs/irs_p.h [new file with mode: 0644]
lib/bind/irs/lcl.c [new file with mode: 0644]
lib/bind/irs/lcl_gr.c [new file with mode: 0644]
lib/bind/irs/lcl_ho.c [new file with mode: 0644]
lib/bind/irs/lcl_ng.c [new file with mode: 0644]
lib/bind/irs/lcl_nw.c [new file with mode: 0644]
lib/bind/irs/lcl_p.h [new file with mode: 0644]
lib/bind/irs/lcl_pr.c [new file with mode: 0644]
lib/bind/irs/lcl_pw.c [new file with mode: 0644]
lib/bind/irs/lcl_sv.c [new file with mode: 0644]
lib/bind/irs/nis.c [new file with mode: 0644]
lib/bind/irs/nis_gr.c [new file with mode: 0644]
lib/bind/irs/nis_ho.c [new file with mode: 0644]
lib/bind/irs/nis_ng.c [new file with mode: 0644]
lib/bind/irs/nis_nw.c [new file with mode: 0644]
lib/bind/irs/nis_p.h [new file with mode: 0644]
lib/bind/irs/nis_pr.c [new file with mode: 0644]
lib/bind/irs/nis_pw.c [new file with mode: 0644]
lib/bind/irs/nis_sv.c [new file with mode: 0644]
lib/bind/irs/nul_ng.c [new file with mode: 0644]
lib/bind/irs/pathnames.h [new file with mode: 0644]
lib/bind/irs/util.c [new file with mode: 0644]
lib/bind/isc/Makefile.in [new file with mode: 0644]
lib/bind/isc/assertions.c [new file with mode: 0644]
lib/bind/isc/assertions.mdoc [new file with mode: 0644]
lib/bind/isc/base64.c [new file with mode: 0644]
lib/bind/isc/bitncmp.c [new file with mode: 0644]
lib/bind/isc/bitncmp.mdoc [new file with mode: 0644]
lib/bind/isc/ctl_clnt.c [new file with mode: 0644]
lib/bind/isc/ctl_p.c [new file with mode: 0644]
lib/bind/isc/ctl_p.h [new file with mode: 0644]
lib/bind/isc/ctl_srvr.c [new file with mode: 0644]
lib/bind/isc/ev_connects.c [new file with mode: 0644]
lib/bind/isc/ev_files.c [new file with mode: 0644]
lib/bind/isc/ev_streams.c [new file with mode: 0644]
lib/bind/isc/ev_timers.c [new file with mode: 0644]
lib/bind/isc/ev_waits.c [new file with mode: 0644]
lib/bind/isc/eventlib.c [new file with mode: 0644]
lib/bind/isc/eventlib.mdoc [new file with mode: 0644]
lib/bind/isc/eventlib_p.h [new file with mode: 0644]
lib/bind/isc/heap.c [new file with mode: 0644]
lib/bind/isc/heap.mdoc [new file with mode: 0644]
lib/bind/isc/logging.c [new file with mode: 0644]
lib/bind/isc/logging.mdoc [new file with mode: 0644]
lib/bind/isc/logging_p.h [new file with mode: 0644]
lib/bind/isc/memcluster.c [new file with mode: 0644]
lib/bind/isc/memcluster.mdoc [new file with mode: 0644]
lib/bind/isc/movefile.c [new file with mode: 0644]
lib/bind/isc/tree.c [new file with mode: 0644]
lib/bind/isc/tree.mdoc [new file with mode: 0644]
lib/bind/make/includes.in [new file with mode: 0644]
lib/bind/make/mkdep.in [new file with mode: 0644]
lib/bind/make/rules.in [new file with mode: 0644]
lib/bind/nameser/Makefile.in [new file with mode: 0644]
lib/bind/nameser/ns_date.c [new file with mode: 0644]
lib/bind/nameser/ns_name.c [new file with mode: 0644]
lib/bind/nameser/ns_netint.c [new file with mode: 0644]
lib/bind/nameser/ns_parse.c [new file with mode: 0644]
lib/bind/nameser/ns_print.c [new file with mode: 0644]
lib/bind/nameser/ns_samedomain.c [new file with mode: 0644]
lib/bind/nameser/ns_sign.c [new file with mode: 0644]
lib/bind/nameser/ns_ttl.c [new file with mode: 0644]
lib/bind/nameser/ns_verify.c [new file with mode: 0644]
lib/bind/port_after.h.in [new file with mode: 0644]
lib/bind/port_before.h.in [new file with mode: 0644]
lib/bind/prand_conf.c [new file with mode: 0644]
lib/bind/resolv/Makefile.in [new file with mode: 0644]
lib/bind/resolv/herror.c [new file with mode: 0644]
lib/bind/resolv/res_comp.c [new file with mode: 0644]
lib/bind/resolv/res_data.c [new file with mode: 0644]
lib/bind/resolv/res_debug.c [new file with mode: 0644]
lib/bind/resolv/res_debug.h [new file with mode: 0644]
lib/bind/resolv/res_findzonecut.c [new file with mode: 0644]
lib/bind/resolv/res_init.c [new file with mode: 0644]
lib/bind/resolv/res_mkquery.c [new file with mode: 0644]
lib/bind/resolv/res_mkupdate.c [new file with mode: 0644]
lib/bind/resolv/res_mkupdate.h [new file with mode: 0644]
lib/bind/resolv/res_private.h [new file with mode: 0644]
lib/bind/resolv/res_query.c [new file with mode: 0644]
lib/bind/resolv/res_send.c [new file with mode: 0644]
lib/bind/resolv/res_sendsigned.c [new file with mode: 0644]
lib/bind/resolv/res_update.c [new file with mode: 0644]

diff --git a/lib/bind/Makefile.in b/lib/bind/Makefile.in
new file mode 100644 (file)
index 0000000..d9ee853
--- /dev/null
@@ -0,0 +1,20 @@
+BSDOBJS=       daemon.o putenv.o strcasecmp.o strsep.o ftruncate.o \
+               readv.o strdup.o strtoul.o gettimeofday.o setenv.o \
+               strerror.o utimes.o mktemp.o setitimer.o strpbrk.o \
+               writev.o
+
+SUBDIRS = bsd cylink dnssafe dst include inet irs isc nameser resolv
+
+OBJS=  prand_conf.@O@
+
+SRCS=  prand_conf.c
+
+@BIND9_MAKE_RULES@
+
+all depend:  prand_conf.h
+
+prand_conf.h:  prand_conf
+       ./prand_conf > $@
+
+prand_conf: ${OBJS}
+       ${CC} -o $@ ${OBJS}
diff --git a/lib/bind/README b/lib/bind/README
new file mode 100644 (file)
index 0000000..b89cff7
--- /dev/null
@@ -0,0 +1,4 @@
+--with-irs-gr=yes #define WANT_IRS_GR
+--with-irs-nis=yes #define WANT_IRS_NIS
+--with-irs-pw=yes #define WANT_IRS_PW
+
diff --git a/lib/bind/bsd/Makefile.in b/lib/bind/bsd/Makefile.in
new file mode 100644 (file)
index 0000000..4d1c74e
--- /dev/null
@@ -0,0 +1,16 @@
+OBJS=  daemon.@O@ ftruncate.@O@ gettimeofday.@O@ mktemp.@O@ putenv.@O@ \
+       readv.@O@ setenv.@O@ setitimer.@O@ strcasecmp.@O@ strdup.@O@ \
+       strerror.@O@ strpbrk.@O@ strsep.@O@ strtoul.@O@ utimes.@O@ \
+       writev.@O@
+
+SRCS=  daemon.c ftruncate.c gettimeofday.c mktemp.c putenv.c \
+       readv.c setenv.c setitimer.c strcasecmp.c strdup.c \
+       strerror.c strpbrk.c strsep.c strtoul.c utimes.c \
+       writev.c
+
+TARGETS= ${OBJS}
+
+CINCLUDES= -I.. -I../include
+CWARNINGS= -Werror
+
+@BIND9_MAKE_RULES@
diff --git a/lib/bind/bsd/daemon.c b/lib/bind/bsd/daemon.c
new file mode 100644 (file)
index 0000000..a1472f9
--- /dev/null
@@ -0,0 +1,79 @@
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)daemon.c     8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: daemon.c,v 1.1 2001/03/29 06:30:31 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Copyright (c) 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.
+ */
+
+#include "port_before.h"
+
+#include <fcntl.h>
+#include <paths.h>
+#include <unistd.h>
+
+#include "port_after.h"
+
+#ifndef NEED_DAEMON
+int __bind_daemon__;
+#else
+
+int
+daemon(int nochdir, int noclose) {
+       int fd;
+
+       switch (fork()) {
+       case -1:
+               return (-1);
+       case 0:
+               break;
+       default:
+               _exit(0);
+       }
+
+       if (setsid() == -1)
+               return (-1);
+
+       if (!nochdir)
+               (void)chdir("/");
+
+       if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
+               (void)dup2(fd, STDIN_FILENO);
+               (void)dup2(fd, STDOUT_FILENO);
+               (void)dup2(fd, STDERR_FILENO);
+               if (fd > 2)
+                       (void)close (fd);
+       }
+       return (0);
+}
+#endif
diff --git a/lib/bind/bsd/ftruncate.c b/lib/bind/bsd/ftruncate.c
new file mode 100644 (file)
index 0000000..56ce8d3
--- /dev/null
@@ -0,0 +1,63 @@
+#ifndef LINT
+static const char rcsid[] = "$Id: ftruncate.c,v 1.1 2001/03/29 06:30:32 marka Exp $";
+#endif
+
+/*
+ * ftruncate - set file size, BSD Style
+ *
+ * shortens or enlarges the file as neeeded
+ * uses some undocumented locking call. It is known to work on SCO unix,
+ * other vendors should try.
+ * The #error directive prevents unsupported OSes
+ */
+
+#include "port_before.h"
+
+#if defined(M_UNIX)
+#define OWN_FTRUNCATE
+#include <stdio.h>
+#ifdef _XOPEN_SOURCE
+#undef _XOPEN_SOURCE
+#endif
+#ifdef _POSIX_SOURCE
+#undef _POSIX_SOURCE
+#endif
+
+#include <fcntl.h>
+
+#include "port_after.h"
+
+int
+__ftruncate(int fd, long wantsize) {
+       long cursize;
+
+       /* determine current file size */
+       if ((cursize = lseek(fd, 0L, 2)) == -1)
+               return (-1);
+
+       /* maybe lengthen... */
+       if (cursize < wantsize) {
+               if (lseek(fd, wantsize - 1, 0) == -1 ||
+                   write(fd, "", 1) == -1) {
+                       return (-1);
+               }
+               return (0);
+       }
+
+       /* maybe shorten... */
+       if (wantsize < cursize) {
+               struct flock fl;
+
+               fl.l_whence = 0;
+               fl.l_len = 0;
+               fl.l_start = wantsize;
+               fl.l_type = F_WRLCK;
+               return (fcntl(fd, F_FREESP, &fl));
+       }
+       return (0);
+}
+#endif
+
+#ifndef OWN_FTRUNCATE
+int __bindcompat_ftruncate;
+#endif
diff --git a/lib/bind/bsd/gettimeofday.c b/lib/bind/bsd/gettimeofday.c
new file mode 100644 (file)
index 0000000..c6415aa
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef LINT
+static const char rcsid[] = "$Id: gettimeofday.c,v 1.1 2001/03/29 06:30:32 marka Exp $";
+#endif
+
+#include "port_before.h"
+#undef gettimeofday
+#include <stdio.h>
+#include <syslog.h>
+#include <sys/time.h>
+#include "port_after.h"
+
+#if !defined(NEED_GETTIMEOFDAY)
+/*
+ * gettimeofday() occasionally returns invalid tv_usec on some platforms.
+ */
+#define MILLION 1000000
+
+#include "gettimeofday.h"
+
+int
+isc__gettimeofday(struct timeval *tp, struct timezone *tzp) {
+       int res;
+
+       res = gettimeofday(tp, tzp);
+       if (res < 0)
+               return (res);
+       if (tp == NULL)
+               return (res);
+       if (tp->tv_usec < 0) {
+               do {
+                       tp->tv_usec += MILLION;
+                       tp->tv_sec--;
+               } while (tp->tv_usec < 0);
+               goto log;
+       } else if (tp->tv_usec > MILLION) {
+               do {
+                       tp->tv_usec -= MILLION;
+                       tp->tv_sec++;
+               } while (tp->tv_usec > MILLION);
+               goto log;
+       }
+       return (res);
+ log:
+       syslog(LOG_ERR, "gettimeofday: tv_usec out of range\n");
+       return (res);
+}
+#else
+int
+gettimeofday(struct timeval *tvp, struct _TIMEZONE *tzp) {
+       time_t clock, time(time_t *);
+
+       if (time(&clock) == (time_t) -1)
+               return (-1);
+       if (tvp) {
+               tvp->tv_sec = clock;
+               tvp->tv_usec = 0;
+       }
+       if (tzp) {
+               tzp->tz_minuteswest = 0;
+               tzp->tz_dsttime = 0;
+       }
+       return (0);
+}
+#endif /*NEED_GETTIMEOFDAY*/
diff --git a/lib/bind/bsd/gettimeofday.h b/lib/bind/bsd/gettimeofday.h
new file mode 100644 (file)
index 0000000..e9975a2
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef gettimeofday_h
+#define gettimeofday_h
+#include <sys/time.h>
+
+int isc__gettimeofday(struct timeval *tp, struct timezone *tzp);
+
+#endif
diff --git a/lib/bind/bsd/mktemp.c b/lib/bind/bsd/mktemp.c
new file mode 100644 (file)
index 0000000..9852a35
--- /dev/null
@@ -0,0 +1,154 @@
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)mktemp.c     8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: mktemp.c,v 1.1 2001/03/29 06:30:33 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Copyright (c) 1987, 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.
+ */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#include "port_after.h"
+
+#if (!defined(NEED_MKTEMP)) && (!defined(NEED_MKSTEMP))
+int __mktemp_unneeded__;
+#else
+
+static int gettemp(char *path, int *doopen);
+
+#ifdef NEED_MKSTEMP
+mkstemp(char *path) {
+       int fd;
+
+       return (gettemp(path, &fd) ? fd : -1);
+}
+#endif
+
+#ifdef NEED_MKTEMP
+char *
+mktemp(char *path) {
+       return(gettemp(path, (int *)NULL) ? path : (char *)NULL);
+}
+#endif
+
+static int
+gettemp(char *path, int *doopen) {
+       char *start, *trv;
+       struct stat sbuf;
+       u_int pid;
+
+       pid = getpid();
+       for (trv = path; *trv; ++trv);          /* extra X's get set to 0's */
+       while (*--trv == 'X') {
+               *trv = (pid % 10) + '0';
+               pid /= 10;
+       }
+
+       /*
+        * check the target directory; if you have six X's and it
+        * doesn't exist this runs for a *very* long time.
+        */
+       for (start = trv + 1;; --trv) {
+               if (trv <= path)
+                       break;
+               if (*trv == '/') {
+                       *trv = '\0';
+                       if (stat(path, &sbuf))
+                               return(0);
+                       if (!S_ISDIR(sbuf.st_mode)) {
+                               errno = ENOTDIR;
+                               return(0);
+                       }
+                       *trv = '/';
+                       break;
+               }
+       }
+
+       for (;;) {
+               if (doopen) {
+                       if ((*doopen =
+                           open(path, O_CREAT|O_EXCL|O_RDWR, 0600)) >= 0)
+                               return(1);
+                       if (errno != EEXIST)
+                               return(0);
+               }
+               else if (stat(path, &sbuf))
+                       return(errno == ENOENT ? 1 : 0);
+
+               /* tricky little algorithm for backward compatibility */
+               for (trv = start;;) {
+                       if (!*trv)
+                               return(0);
+                       if (*trv == 'z')
+                               *trv++ = 'a';
+                       else {
+                               if (isdigit(*trv))
+                                       *trv = 'a';
+                               else
+                                       ++*trv;
+                               break;
+                       }
+               }
+       }
+       /*NOTREACHED*/
+}
+
+#endif /*NEED_MKTEMP*/
diff --git a/lib/bind/bsd/putenv.c b/lib/bind/bsd/putenv.c
new file mode 100644 (file)
index 0000000..abaa525
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef LINT
+static const char rcsid[] = "$Id: putenv.c,v 1.1 2001/03/29 06:30:33 marka Exp $";
+#endif
+
+#include "port_before.h"
+#include "port_after.h"
+
+/*
+ * To give a little credit to Sun, SGI,
+ * and many vendors in the SysV world.
+ */
+
+#if !defined(NEED_PUTENV)
+int __bindcompat_putenv;
+#else
+int
+putenv(char *str) {
+       char *tmp;
+
+       for (tmp = str; *tmp && (*tmp != '='); tmp++)
+               ;
+
+       return (setenv(str, tmp, 1));
+}
+#endif
diff --git a/lib/bind/bsd/readv.c b/lib/bind/bsd/readv.c
new file mode 100644 (file)
index 0000000..ccfcb5a
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef LINT
+static const char rcsid[] = "$Id: readv.c,v 1.1 2001/03/29 06:30:35 marka Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+
+#include "port_after.h"
+
+#ifndef NEED_READV
+int __bindcompat_readv;
+#else
+
+int
+__readv(fd, vp, vpcount)
+       int fd;
+       const struct iovec *vp;
+       int vpcount;
+{
+       int count = 0;
+
+       while (vpcount-- > 0) {
+               int bytes = read(fd, vp->iov_base, vp->iov_len);
+
+               if (bytes < 0)
+                       return (-1);
+               count += bytes;
+               if (bytes != vp->iov_len)
+                       break;
+               vp++;
+       }
+       return (count);
+}
+#endif /* NEED_READV */
diff --git a/lib/bind/bsd/setenv.c b/lib/bind/bsd/setenv.c
new file mode 100644 (file)
index 0000000..6a11c9d
--- /dev/null
@@ -0,0 +1,149 @@
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)setenv.c     8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: setenv.c,v 1.1 2001/03/29 06:30:35 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Copyright (c) 1987, 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.
+ */
+
+#include "port_before.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "port_after.h"
+
+#if !defined(NEED_SETENV)
+int __bindcompat_setenv;
+#else
+
+extern char **environ;
+
+static char *findenv(const char *name, int *offset);
+
+/*
+ * setenv --
+ *     Set the value of the environmental variable "name" to be
+ *     "value".  If rewrite is set, replace any current value.
+ */
+setenv(const char *name, const char *value, int rewrite) {
+       extern char **environ;
+       static int alloced;                     /* if allocated space before */
+       char *c;
+       int l_value, offset;
+
+       if (*value == '=')                      /* no `=' in value */
+               ++value;
+       l_value = strlen(value);
+       if ((c = findenv(name, &offset))) {     /* find if already exists */
+               if (!rewrite)
+                       return (0);
+               if (strlen(c) >= l_value) {     /* old larger; copy over */
+                       while (*c++ = *value++);
+                       return (0);
+               }
+       } else {                                        /* create new slot */
+               int cnt;
+               char **p;
+
+               for (p = environ, cnt = 0; *p; ++p, ++cnt);
+               if (alloced) {                  /* just increase size */
+                       environ = (char **)realloc((char *)environ,
+                           (size_t)(sizeof(char *) * (cnt + 2)));
+                       if (!environ)
+                               return (-1);
+               }
+               else {                          /* get new space */
+                       alloced = 1;            /* copy old entries into it */
+                       p = malloc((size_t)(sizeof(char *) * (cnt + 2)));
+                       if (!p)
+                               return (-1);
+                       memcpy(p, environ, cnt * sizeof(char *));
+                       environ = p;
+               }
+               environ[cnt + 1] = NULL;
+               offset = cnt;
+       }
+       for (c = (char *)name; *c && *c != '='; ++c);   /* no `=' in name */
+       if (!(environ[offset] =                 /* name + `=' + value */
+           malloc((size_t)((int)(c - name) + l_value + 2))))
+               return (-1);
+       for (c = environ[offset]; (*c = *name++) && *c != '='; ++c);
+       for (*c++ = '='; *c++ = *value++;);
+       return (0);
+}
+
+/*
+ * unsetenv(name) --
+ *     Delete environmental variable "name".
+ */
+void
+unsetenv(const char *name) {
+       char **p;
+       int offset;
+
+       while (findenv(name, &offset))  /* if set multiple times */
+               for (p = &environ[offset];; ++p)
+                       if (!(*p = *(p + 1)))
+                               break;
+}
+
+/*
+ * findenv --
+ *     Returns pointer to value associated with name, if any, else NULL.
+ *     Sets offset to be the offset of the name/value combination in the
+ *     environmental array, for use by setenv(3) and unsetenv(3).
+ *     Explicitly removes '=' in argument name.
+ *
+ *     This routine *should* be a static; don't use it.
+ */
+static char *
+findenv(const char *name, int *offset) {
+       const char *np;
+       char **p, *c;
+       int len;
+
+       if (name == NULL || environ == NULL)
+               return (NULL);
+       for (np = name; *np && *np != '='; ++np)
+               continue;
+       len = np - name;
+       for (p = environ; (c = *p) != NULL; ++p)
+               if (strncmp(c, name, len) == 0 && c[len] == '=') {
+                       *offset = p - environ;
+                       return (c + len + 1);
+               }
+       return (NULL);
+}
+#endif
diff --git a/lib/bind/bsd/setitimer.c b/lib/bind/bsd/setitimer.c
new file mode 100644 (file)
index 0000000..791846a
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef LINT
+static const char rcsid[] = "$Id: setitimer.c,v 1.1 2001/03/29 06:30:35 marka Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <sys/time.h>
+
+#include "port_after.h"
+
+/*
+ * Setitimer emulation routine.
+ */
+#ifndef NEED_SETITIMER
+int __bindcompat_setitimer;
+#else
+
+int
+__setitimer(int which, const struct itimerval *value,
+           struct itimerval *ovalue)
+{
+       if (alarm(value->it_value.tv_sec) >= 0)
+               return (0);
+       else
+               return (-1);
+}
+#endif
diff --git a/lib/bind/bsd/strcasecmp.c b/lib/bind/bsd/strcasecmp.c
new file mode 100644 (file)
index 0000000..c8c9d05
--- /dev/null
@@ -0,0 +1,122 @@
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)strcasecmp.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: strcasecmp.c,v 1.1 2001/03/29 06:30:35 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Copyright (c) 1987, 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.
+ */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/cdefs.h>
+
+#include <string.h>
+
+#include "port_after.h"
+
+#ifndef NEED_STRCASECMP
+int __strcasecmp_unneeded__;
+#else
+
+/*
+ * This array is designed for mapping upper and lower case letter
+ * together for a case independent comparison.  The mappings are
+ * based upon ascii character sequences.
+ */
+static const u_char charmap[] = {
+       0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007,
+       0010, 0011, 0012, 0013, 0014, 0015, 0016, 0017,
+       0020, 0021, 0022, 0023, 0024, 0025, 0026, 0027,
+       0030, 0031, 0032, 0033, 0034, 0035, 0036, 0037,
+       0040, 0041, 0042, 0043, 0044, 0045, 0046, 0047,
+       0050, 0051, 0052, 0053, 0054, 0055, 0056, 0057,
+       0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,
+       0070, 0071, 0072, 0073, 0074, 0075, 0076, 0077,
+       0100, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
+       0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157,
+       0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167,
+       0170, 0171, 0172, 0133, 0134, 0135, 0136, 0137,
+       0140, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
+       0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157,
+       0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167,
+       0170, 0171, 0172, 0173, 0174, 0175, 0176, 0177,
+       0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
+       0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217,
+       0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227,
+       0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237,
+       0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247,
+       0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
+       0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
+       0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
+       0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
+       0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317,
+       0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327,
+       0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
+       0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
+       0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
+       0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
+       0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377
+};
+
+int
+strcasecmp(const char *s1, const char *s2) {
+       const u_char *cm = charmap,
+                    *us1 = (const u_char *)s1,
+                    *us2 = (const u_char *)s2;
+
+       while (cm[*us1] == cm[*us2++])
+               if (*us1++ == '\0')
+                       return (0);
+       return (cm[*us1] - cm[*--us2]);
+}
+
+int
+strncasecmp(const char *s1, const char *s2, size_t n) {
+       if (n != 0) {
+               const u_char *cm = charmap,
+                            *us1 = (const u_char *)s1,
+                            *us2 = (const u_char *)s2;
+
+               do {
+                       if (cm[*us1] != cm[*us2++])
+                               return (cm[*us1] - cm[*--us2]);
+                       if (*us1++ == '\0')
+                               break;
+               } while (--n != 0);
+       }
+       return (0);
+}
+
+#endif /*NEED_STRCASECMP*/
diff --git a/lib/bind/bsd/strdup.c b/lib/bind/bsd/strdup.c
new file mode 100644 (file)
index 0000000..246bc1f
--- /dev/null
@@ -0,0 +1,18 @@
+#include "port_before.h"
+
+#include <stdlib.h>
+
+#include "port_after.h"
+
+#ifndef NEED_STRDUP
+int __bind_strdup_unneeded;
+#else
+char *
+strdup(const char *src) {
+       char *dst = malloc(strlen(src) + 1);
+
+       if (dst)
+               strcpy(dst, src);
+       return (dst);
+}
+#endif
diff --git a/lib/bind/bsd/strerror.c b/lib/bind/bsd/strerror.c
new file mode 100644 (file)
index 0000000..5c48029
--- /dev/null
@@ -0,0 +1,80 @@
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)strerror.c   8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: strerror.c,v 1.1 2001/03/29 06:30:36 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * 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.
+ */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <sys/types.h>
+
+#include <string.h>
+
+#include "port_after.h"
+
+extern int sys_nerr;
+extern char *sys_errlist[];
+
+#ifndef NEED_STRERROR
+int __strerror_unneeded__;
+#else
+
+const char *
+strerror(int num) {
+#define        UPREFIX "Unknown error: "
+       static char ebuf[40] = UPREFIX;         /* 64-bit number + slop */
+       u_int errnum;
+       char *p, *t;
+       char tmp[40];
+
+       errnum = num;                           /* convert to unsigned */
+       if (errnum < sys_nerr)
+               return (sys_errlist[errnum]);
+
+       /* Do this by hand, so we don't include stdio(3). */
+       t = tmp;
+       do {
+               *t++ = "0123456789"[errnum % 10];
+       } while (errnum /= 10);
+       for (p = ebuf + sizeof(UPREFIX) - 1;;) {
+               *p++ = *--t;
+               if (t <= tmp)
+                       break;
+       }
+       return (ebuf);
+}
+
+#endif /*NEED_STRERROR*/
diff --git a/lib/bind/bsd/strpbrk.c b/lib/bind/bsd/strpbrk.c
new file mode 100644 (file)
index 0000000..ff039e1
--- /dev/null
@@ -0,0 +1,68 @@
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)strpbrk.c    8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: strpbrk.c,v 1.1 2001/03/29 06:30:36 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * 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.
+ */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <sys/cdefs.h>
+
+#include <string.h>
+
+#include "port_after.h"
+
+#ifndef NEED_STRPBRK
+int __strpbrk_unneeded__;
+#else
+
+/*
+ * Find the first occurrence in s1 of a character in s2 (excluding NUL).
+ */
+char *
+strpbrk(const char *s1, const char *s2) {
+       const char *scanp;
+       int c, sc;
+
+       while ((c = *s1++) != 0) {
+               for (scanp = s2; (sc = *scanp++) != 0;)
+                       if (sc == c)
+                               return ((char *)(s1 - 1));
+       }
+       return (NULL);
+}
+
+#endif /*NEED_STRPBRK*/
diff --git a/lib/bind/bsd/strsep.c b/lib/bind/bsd/strsep.c
new file mode 100644 (file)
index 0000000..3dcee4a
--- /dev/null
@@ -0,0 +1,86 @@
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "strsep.c 8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: strsep.c,v 1.1 2001/03/29 06:30:36 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Copyright (c) 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.
+ */
+
+#include "port_before.h"
+#include <sys/cdefs.h>
+#include <string.h>
+#include <stdio.h>
+#include "port_after.h"
+
+#ifndef NEED_STRSEP
+int __strsep_unneeded__;
+#else
+
+/*
+ * Get next token from string *stringp, where tokens are possibly-empty
+ * strings separated by characters from delim.  
+ *
+ * Writes NULs into the string at *stringp to end tokens.
+ * delim need not remain constant from call to call.
+ * On return, *stringp points past the last NUL written (if there might
+ * be further tokens), or is NULL (if there are definitely no more tokens).
+ *
+ * If *stringp is NULL, strsep returns NULL.
+ */
+char *
+strsep(char **stringp, const char *delim) {
+       char *s;
+       const char *spanp;
+       int c, sc;
+       char *tok;
+
+       if ((s = *stringp) == NULL)
+               return (NULL);
+       for (tok = s;;) {
+               c = *s++;
+               spanp = delim;
+               do {
+                       if ((sc = *spanp++) == c) {
+                               if (c == 0)
+                                       s = NULL;
+                               else
+                                       s[-1] = 0;
+                               *stringp = s;
+                               return (tok);
+                       }
+               } while (sc != 0);
+       }
+       /* NOTREACHED */
+}
+
+#endif /*NEED_STRSEP*/
diff --git a/lib/bind/bsd/strtoul.c b/lib/bind/bsd/strtoul.c
new file mode 100644 (file)
index 0000000..ab3d5a4
--- /dev/null
@@ -0,0 +1,117 @@
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)strtoul.c    8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: strtoul.c,v 1.1 2001/03/29 06:30:36 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Copyright (c) 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.
+ */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#include "port_after.h"
+
+#ifndef NEED_STRTOUL
+int __strtoul_unneeded__;
+#else
+
+/*
+ * Convert a string to an unsigned long integer.
+ *
+ * Ignores `locale' stuff.  Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+u_long
+strtoul(const char *nptr, char **endptr, int base) {
+       const char *s = nptr;
+       u_long acc, cutoff;
+       int neg, c, any, cutlim;
+
+       neg = 0;
+
+       /*
+        * See strtol for comments as to the logic used.
+        */
+       do {
+               c = *s++;
+       } while (isspace(c));
+       if (c == '-') {
+               neg = 1;
+               c = *s++;
+       } else if (c == '+')
+               c = *s++;
+       if ((base == 0 || base == 16) &&
+           c == '0' && (*s == 'x' || *s == 'X')) {
+               c = s[1];
+               s += 2;
+               base = 16;
+       }
+       if (base == 0)
+               base = c == '0' ? 8 : 10;
+       cutoff = (u_long)ULONG_MAX / (u_long)base;
+       cutlim = (u_long)ULONG_MAX % (u_long)base;
+       for (acc = 0, any = 0;; c = *s++) {
+               if (isdigit(c))
+                       c -= '0';
+               else if (isalpha(c))
+                       c -= isupper(c) ? 'A' - 10 : 'a' - 10;
+               else
+                       break;
+               if (c >= base)
+                       break;
+               if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim)
+                       any = -1;
+               else {
+                       any = 1;
+                       acc *= base;
+                       acc += c;
+               }
+       }
+       if (any < 0) {
+               acc = ULONG_MAX;
+               errno = ERANGE;
+       } else if (neg)
+               acc = -acc;
+       if (endptr != 0)
+               *endptr = (char *)(any ? s - 1 : nptr);
+       return (acc);
+}
+
+#endif /*NEED_STRTOUL*/
diff --git a/lib/bind/bsd/utimes.c b/lib/bind/bsd/utimes.c
new file mode 100644 (file)
index 0000000..73e4b02
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 1997,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.
+ */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <utime.h>
+
+#include "port_after.h"
+
+#ifndef NEED_UTIMES
+int __bind_utimes_unneeded;
+#else
+
+int
+__utimes(char *filename, struct timeval *tvp) {
+       struct utimbuf utb;
+
+       utb.actime = (time_t)tvp[0].tv_sec;
+       utb.modtime = (time_t)tvp[1].tv_sec;
+       return (utime(filename, &utb));
+}
+
+#endif /* NEED_UTIMES */
diff --git a/lib/bind/bsd/writev.c b/lib/bind/bsd/writev.c
new file mode 100644 (file)
index 0000000..3739288
--- /dev/null
@@ -0,0 +1,86 @@
+#ifndef LINT
+static const char rcsid[] = "$Id: writev.c,v 1.1 2001/03/29 06:30:37 marka Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+
+#include "port_after.h"
+
+#ifndef NEED_WRITEV
+int __bindcompat_writev;
+#else
+
+#ifdef _CRAY
+#define OWN_WRITEV
+int
+__writev(int fd, struct iovec *iov, int iovlen)
+{
+       struct stat statbuf;
+
+       if (fstat(fd, &statbuf) < 0)
+               return (-1);
+
+       /*
+        * Allow for atomic writes to network.
+        */
+       if (statbuf.st_mode & S_IFSOCK) {
+               struct msghdr   mesg;           
+
+               mesg.msg_name = 0;
+               mesg.msg_namelen = 0;
+               mesg.msg_iov = iov;
+               mesg.msg_iovlen = iovlen;
+               mesg.msg_accrights = 0;
+               mesg.msg_accrightslen = 0;
+               return (sendmsg(fd, &mesg, 0));
+       } else {
+               struct iovec *tv;
+               int i, rcode = 0, count = 0;
+
+               for (i = 0, tv = iov; i <= iovlen; tv++) {
+                       rcode = write(fd, tv->iov_base, tv->iov_len);
+
+                       if (rcode < 0)
+                               break;
+
+                       count += rcode;
+               }
+
+               if (count == 0)
+                       return (rcode);
+               else
+                       return (count);
+       }
+}
+
+#else /*_CRAY*/
+
+int
+__writev(fd, vp, vpcount)
+       int fd;
+       const struct iovec *vp;
+       int vpcount;
+{
+       int count = 0;
+
+       while (vpcount-- > 0) {
+               int written = write(fd, vp->iov_base, vp->iov_len);
+
+               if (written < 0)
+                       return (-1);
+               count += written;
+               if (written != vp->iov_len)
+                       break;
+               vp++;
+       }
+       return (count);
+}
+
+#endif /*_CRAY*/
+
+#endif /*NEED_WRITEV*/
diff --git a/lib/bind/config.h.in b/lib/bind/config.h.in
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/lib/bind/configure b/lib/bind/configure
new file mode 100644 (file)
index 0000000..5116af4
--- /dev/null
@@ -0,0 +1,6825 @@
+#! /bin/sh
+
+
+# From configure.in Revision: 1.238 
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.13 
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_help="$ac_help
+ --with-irs-gr         Build ...."
+ac_help="$ac_help
+ --with-irs-pw         Build ...."
+ac_help="$ac_help
+ --with-irs-nis                Build ...."
+ac_help="$ac_help
+  --with-openssl=PATH  Specify path for system-supplied openssl
+                        (rather than using bind-9 internal openssl)"
+ac_help="$ac_help
+  --with-randomdev=PATH Specify path for random device"
+ac_help="$ac_help
+  --disable-threads    disable multithreading"
+ac_help="$ac_help
+  --with-ptl2          on NetBSD, use the ptl2 thread library (experimental)"
+ac_help="$ac_help
+  --with-purify[=PATH] use Rational purify"
+ac_help="$ac_help
+  --with-libtool       use GNU libtool (following indented options supported)"
+ac_help="$ac_help
+  --enable-ipv6                use IPv6 [default=autodetect]"
+ac_help="$ac_help
+  --with-kame[=PATH]   use Kame IPv6 [default path /usr/local/v6]"
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval "$ac_prev=\$ac_option"
+    ac_prev=
+    continue
+  fi
+
+  case "$ac_option" in
+  -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+  *) ac_optarg= ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case "$ac_option" in
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir="$ac_optarg" ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build="$ac_optarg" ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file="$ac_optarg" ;;
+
+  -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+  | --da=*)
+    datadir="$ac_optarg" ;;
+
+  -disable-* | --disable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    eval "enable_${ac_feature}=no" ;;
+
+  -enable-* | --enable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix="$ac_optarg" ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he)
+    # Omit some internal or obsolete options to make the list less imposing.
+    # This message is too long to be a string in the A/UX 3.1 sh.
+    cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+  --cache-file=FILE       cache test results in FILE
+  --help                  print this message
+  --no-create             do not create output files
+  --quiet, --silent       do not print \`checking...' messages
+  --version               print the version of autoconf that created configure
+Directory and file names:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [same as prefix]
+  --bindir=DIR            user executables in DIR [EPREFIX/bin]
+  --sbindir=DIR           system admin executables in DIR [EPREFIX/sbin]
+  --libexecdir=DIR        program executables in DIR [EPREFIX/libexec]
+  --datadir=DIR           read-only architecture-independent data in DIR
+                          [PREFIX/share]
+  --sysconfdir=DIR        read-only single-machine data in DIR [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data in DIR
+                          [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data in DIR [PREFIX/var]
+  --libdir=DIR            object code libraries in DIR [EPREFIX/lib]
+  --includedir=DIR        C header files in DIR [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc in DIR [/usr/include]
+  --infodir=DIR           info documentation in DIR [PREFIX/info]
+  --mandir=DIR            man documentation in DIR [PREFIX/man]
+  --srcdir=DIR            find the sources in DIR [configure dir or ..]
+  --program-prefix=PREFIX prepend PREFIX to installed program names
+  --program-suffix=SUFFIX append SUFFIX to installed program names
+  --program-transform-name=PROGRAM
+                          run sed PROGRAM on installed program names
+EOF
+    cat << EOF
+Host type:
+  --build=BUILD           configure for building on BUILD [BUILD=HOST]
+  --host=HOST             configure for HOST [guessed]
+  --target=TARGET         configure for TARGET [TARGET=HOST]
+Features and packages:
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --x-includes=DIR        X include files are in DIR
+  --x-libraries=DIR       X library files are in DIR
+EOF
+    if test -n "$ac_help"; then
+      echo "--enable and --with options recognized:$ac_help"
+    fi
+    exit 0 ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host="$ac_optarg" ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir="$ac_optarg" ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir="$ac_optarg" ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir="$ac_optarg" ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir="$ac_optarg" ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst \
+  | --locals | --local | --loca | --loc | --lo)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+  | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+    localstatedir="$ac_optarg" ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir="$ac_optarg" ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir="$ac_optarg" ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix="$ac_optarg" ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix="$ac_optarg" ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix="$ac_optarg" ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name="$ac_optarg" ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir="$ac_optarg" ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir="$ac_optarg" ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site="$ac_optarg" ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir="$ac_optarg" ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir="$ac_optarg" ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target="$ac_optarg" ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers)
+    echo "configure generated by autoconf version 2.13"
+    exit 0 ;;
+
+  -with-* | --with-*)
+    ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "with_${ac_package}='$ac_optarg'" ;;
+
+  -without-* | --without-*)
+    ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    eval "with_${ac_package}=no" ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes="$ac_optarg" ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries="$ac_optarg" ;;
+
+  -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+    ;;
+
+  *)
+    if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+      echo "configure: warning: $ac_option: invalid host type" 1>&2
+    fi
+    if test "x$nonopt" != xNONE; then
+      { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+    fi
+    nonopt="$ac_option"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+  exec 6>/dev/null
+else
+  exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+  case "$ac_arg" in
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c) ;;
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+  *" "*|*"     "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+  ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+  *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+  esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set.  These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}"   = set; then LANG=C;   export LANG;   fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}"    = set; then LC_CTYPE=C;    export LC_CTYPE;    fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=resolv/herror.c
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then its parent.
+  ac_prog=$0
+  ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+  test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+  srcdir=$ac_confdir
+  if test ! -r $srcdir/$ac_unique_file; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+  if test "$ac_srcdir_defaulted" = yes; then
+    { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+  else
+    { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+  fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+  if test "x$prefix" != xNONE; then
+    CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+  else
+    CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+  fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+  if test -r "$ac_site_file"; then
+    echo "loading site script $ac_site_file"
+    . "$ac_site_file"
+  fi
+done
+
+if test -r "$cache_file"; then
+  echo "loading cache $cache_file"
+  . $cache_file
+else
+  echo "creating cache $cache_file"
+  > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+ac_exeext=
+ac_objext=o
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+  # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+  if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+    ac_n= ac_c='
+' ac_t='       '
+  else
+    ac_n=-n ac_c= ac_t=
+  fi
+else
+  ac_n= ac_c='\c' ac_t=
+fi
+
+
+
+
+
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+  if test -f $ac_dir/install-sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f $ac_dir/install.sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+
+# Make sure we can run config.sub.
+if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then :
+else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking host system type""... $ac_c" 1>&6
+echo "configure:581: checking host system type" >&5
+
+host_alias=$host
+case "$host_alias" in
+NONE)
+  case $nonopt in
+  NONE)
+    if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then :
+    else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; }
+    fi ;;
+  *) host_alias=$nonopt ;;
+  esac ;;
+esac
+
+host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias`
+host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+echo "$ac_t""$host" 1>&6
+
+
+echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
+echo "configure:603: checking whether ${MAKE-make} sets \${MAKE}" >&5
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftestmake <<\EOF
+all:
+       @echo 'ac_maketemp="${MAKE}"'
+EOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+  eval ac_cv_prog_make_${ac_make}_set=yes
+else
+  eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftestmake
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  SET_MAKE=
+else
+  echo "$ac_t""no" 1>&6
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+# Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:632: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_RANLIB="ranlib"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":"
+fi
+fi
+RANLIB="$ac_cv_prog_RANLIB"
+if test -n "$RANLIB"; then
+  echo "$ac_t""$RANLIB" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:671: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    IFS="${IFS=        }"; ac_save_IFS="$IFS"; IFS=":"
+  for ac_dir in $PATH; do
+    # Account for people who put trailing slashes in PATH elements.
+    case "$ac_dir/" in
+    /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+    *)
+      # OSF1 and SCO ODT 3.0 have their own names for install.
+      # Don't use installbsd from OSF since it installs stuff as root
+      # by default.
+      for ac_prog in ginstall scoinst install; do
+        if test -f $ac_dir/$ac_prog; then
+         if test $ac_prog = install &&
+            grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+           # AIX install.  It has an incompatible calling convention.
+           :
+         else
+           ac_cv_path_install="$ac_dir/$ac_prog -c"
+           break 2
+         fi
+       fi
+      done
+      ;;
+    esac
+  done
+  IFS="$ac_save_IFS"
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL="$ac_cv_path_install"
+  else
+    # As a last resort, use the slow shell script.  We don't cache a
+    # path for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the path is relative.
+    INSTALL="$ac_install_sh"
+  fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+
+
+
+
+
+
+# Extract the first word of "ar", so it can be a program name with args.
+set dummy ar; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:732: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_AR'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$AR" in
+  /*)
+  ac_cv_path_AR="$AR" # Let the user override the test with a path.
+  ;;
+  ?:/*)                         
+  ac_cv_path_AR="$AR" # Let the user override the test with a dos path.
+  ;;
+  *)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do 
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_AR="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  ;;
+esac
+fi
+AR="$ac_cv_path_AR"
+if test -n "$AR"; then
+  echo "$ac_t""$AR" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+ARFLAGS="cruv"
+
+
+
+# The POSIX ln(1) program.  Non-POSIX systems may substitute
+# "copy" or something.
+LN=ln
+
+
+case "$AR" in
+       "")
+               { echo "configure: error: 
+ar program not found.  Please fix your PATH to include the directory in
+which ar resides, or set AR in the environment with the full path to ar.
+" 1>&2; exit 1; }
+
+               ;;
+esac
+
+#
+# Etags.
+#
+for ac_prog in etags emacs-etags
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:791: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_ETAGS'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$ETAGS" in
+  /*)
+  ac_cv_path_ETAGS="$ETAGS" # Let the user override the test with a path.
+  ;;
+  ?:/*)                         
+  ac_cv_path_ETAGS="$ETAGS" # Let the user override the test with a dos path.
+  ;;
+  *)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do 
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_ETAGS="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  ;;
+esac
+fi
+ETAGS="$ac_cv_path_ETAGS"
+if test -n "$ETAGS"; then
+  echo "$ac_t""$ETAGS" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+test -n "$ETAGS" && break
+done
+
+
+#
+# Some systems, e.g. RH7, have the Exuberant Ctags etags instead of
+# GNU emacs etags, and it requires the -L flag.
+#
+if test "X$ETAGS" != "X"; then
+       echo $ac_n "checking for Exuberant Ctags etags""... $ac_c" 1>&6
+echo "configure:833: checking for Exuberant Ctags etags" >&5
+       if $ETAGS --version 2>&1 | grep 'Exuberant Ctags' >/dev/null 2>&1; then
+               echo "$ac_t""yes" 1>&6
+               ETAGS="$ETAGS -L"
+       else
+               echo "$ac_t""no" 1>&6
+       fi
+fi
+
+
+#
+# Perl is optional; it is used only by some of the system test scripts.
+#
+for ac_prog in perl5 perl
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:851: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_PERL'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$PERL" in
+  /*)
+  ac_cv_path_PERL="$PERL" # Let the user override the test with a path.
+  ;;
+  ?:/*)                         
+  ac_cv_path_PERL="$PERL" # Let the user override the test with a dos path.
+  ;;
+  *)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do 
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_PERL="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  ;;
+esac
+fi
+PERL="$ac_cv_path_PERL"
+if test -n "$PERL"; then
+  echo "$ac_t""$PERL" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+test -n "$PERL" && break
+done
+
+
+
+#
+# Special processing of paths depending on whether --prefix,
+# --sysconfdir or --localstatedir arguments were given.  What's
+# desired is some compatability with the way previous versions
+# of BIND built; they defaulted to /usr/local for most parts of
+# the installation, but named.boot/named.conf was in /etc
+# and named.pid was in /var/run.
+#
+# So ... if none of --prefix, --sysconfdir or --localstatedir are
+# specified, set things up that way.  If --prefix is given, use
+# it for sysconfdir and localstatedir the way configure normally
+# would.  To change the prefix for everything but leave named.conf
+# in /etc or named.pid in /var/run, then do this the usual configure way:
+# ./configure --prefix=/somewhere --sysconfdir=/etc
+# ./configure --prefix=/somewhere --localstatedir=/var
+#
+# To put named.conf and named.pid in /usr/local with everything else,
+# set the prefix explicitly to /usr/local even though that's the default:
+# ./configure --prefix=/usr/local
+#
+case "$prefix" in
+        NONE)
+                case "$sysconfdir" in
+                        '${prefix}/etc')
+                                sysconfdir=/etc
+                                ;;
+                esac
+                case "$localstatedir" in
+                        '${prefix}/var')
+                                localstatedir=/var
+                                ;;
+                esac
+                ;;
+esac
+
+#
+# Make sure INSTALL uses an absolute path, else it will be wrong in all
+# Makefiles, since they use make/rules.in and INSTALL will be adjusted by
+# configure based on the location of the file where it is substituted.
+# Since in BIND9 INSTALL is only substituted into make/rules.in, an immediate
+# subdirectory of install-sh, This relative path will be wrong for all
+# directories more than one level down from install-sh.
+#
+case "$INSTALL" in
+       /*)
+                ;;
+        *)
+                #
+                # Not all systems have dirname.
+                #
+                
+                ac_dir="`echo $INSTALL | sed 's%/[^/]*$%%'`"
+                
+
+                ac_prog="`echo $INSTALL | sed 's%.*/%%'`"
+                test "$ac_dir" = "$ac_prog" && ac_dir=.
+                test -d "$ac_dir" && ac_dir="`(cd \"$ac_dir\" && pwd)`"
+                INSTALL="$ac_dir/$ac_prog"
+                ;;
+esac
+
+#
+# On these hosts, we really want to use cc, not gcc, even if it is
+# found.  The gcc that these systems have will not correctly handle
+# pthreads.
+#
+# However, if the user sets $CC to be something, let that override
+# our change.
+#
+if test "X$CC" = "X" ; then
+       case "$host" in
+               *-dec-osf*)
+                       CC="cc"
+                       ;;
+               *-solaris*)
+                        # Use Sun's cc if it is available, but watch
+                        # out for /usr/ucb/cc; it will never be the right
+                        # compiler to use.
+                        #
+                        # If setting CC here fails, the AC_PROG_CC done
+                        # below might still find gcc.
+                       IFS="${IFS=     }"; ac_save_ifs="$IFS"; IFS=":"
+                       for ac_dir in $PATH; do
+                               test -z "$ac_dir" && ac_dir=.
+                               case "$ac_dir" in
+                               /usr/ucb)
+                                       # exclude
+                                       ;;
+                               *)
+                                       if test -f "$ac_dir/cc"; then
+                                               CC="$ac_dir/cc"
+                                               break
+                                       fi
+                                       ;;
+                               esac
+                       done
+                       IFS="$ac_save_ifs"
+                       ;;
+               *-hp-hpux*)
+                       CC="cc"
+                       ;;
+               mips-sgi-irix*)
+                       CC="cc"
+                       ;;
+       esac
+fi
+
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:999: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="gcc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1029: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_prog_rejected=no
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+        ac_prog_rejected=yes
+       continue
+      fi
+      ac_cv_prog_CC="cc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# -gt 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    set dummy "$ac_dir/$ac_word" "$@"
+    shift
+    ac_cv_prog_CC="$@"
+  fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+  if test -z "$CC"; then
+    case "`uname -s`" in
+    *win32* | *WIN32*)
+      # Extract the first word of "cl", so it can be a program name with args.
+set dummy cl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1080: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="cl"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+ ;;
+    esac
+  fi
+  test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:1112: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 1123 "configure"
+#include "confdefs.h"
+
+main(){return(0);}
+EOF
+if { (eval echo configure:1128: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  ac_cv_prog_cc_works=yes
+  # If we can't run a trivial program, we are probably using a cross compiler.
+  if (./conftest; exit) 2>/dev/null; then
+    ac_cv_prog_cc_cross=no
+  else
+    ac_cv_prog_cc_cross=yes
+  fi
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+  { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:1154: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:1159: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.c <<EOF
+#ifdef __GNUC__
+  yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:1168: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+  ac_cv_prog_gcc=yes
+else
+  ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+
+ac_test_CFLAGS="${CFLAGS+set}"
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS=
+echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:1187: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+  ac_cv_prog_cc_g=yes
+else
+  ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS="$ac_save_CFLAGS"
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:1220: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    # This must be in double quotes, not single quotes, because CPP may get
+  # substituted into the Makefile and "${CC-cc}" will confuse make.
+  CPP="${CC-cc} -E"
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp.
+  cat > conftest.$ac_ext <<EOF
+#line 1235 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1241: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -E -traditional-cpp"
+  cat > conftest.$ac_ext <<EOF
+#line 1252 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1258: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -nologo -E"
+  cat > conftest.$ac_ext <<EOF
+#line 1269 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1275: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+  ac_cv_prog_CPP="$CPP"
+fi
+  CPP="$ac_cv_prog_CPP"
+else
+  ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:1300: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1305 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1313: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  ac_cv_header_stdc=yes
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1330 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "memchr" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1348 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "free" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+  :
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1369 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:1380: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  :
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+  cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+
+
+for ac_hdr in fcntl.h sys/time.h unistd.h sys/sockio.h sys/select.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1409: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1414 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1419: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+
+echo $ac_n "checking for working const""... $ac_c" 1>&6
+echo "configure:1447: checking for working const" >&5
+if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1452 "configure"
+#include "confdefs.h"
+
+int main() {
+
+/* Ultrix mips cc rejects this.  */
+typedef int charset[2]; const charset x;
+/* SunOS 4.1.1 cc rejects this.  */
+char const *const *ccp;
+char **p;
+/* NEC SVR4.0.2 mips cc rejects this.  */
+struct point {int x, y;};
+static struct point const zero = {0,0};
+/* AIX XL C 1.02.0.0 rejects this.
+   It does not let you subtract one const X* pointer from another in an arm
+   of an if-expression whose if-part is not a constant expression */
+const char *g = "string";
+ccp = &g + (g ? g-g : 0);
+/* HPUX 7.0 cc rejects these. */
+++ccp;
+p = (char**) ccp;
+ccp = (char const *const *) p;
+{ /* SCO 3.2v4 cc rejects this.  */
+  char *t;
+  char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+  *t++ = 0;
+}
+{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this.  */
+  int x[] = {25, 17};
+  const int *foo = &x[0];
+  ++foo;
+}
+{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+  typedef const int *iptr;
+  iptr p = 0;
+  ++p;
+}
+{ /* AIX XL C 1.02.0.0 rejects this saying
+     "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+  struct s { int j; const int *ap[3]; };
+  struct s *b; b->j = 5;
+}
+{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+  const int foo = 10;
+}
+
+; return 0; }
+EOF
+if { (eval echo configure:1501: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_c_const=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_c_const=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_c_const" 1>&6
+if test $ac_cv_c_const = no; then
+  cat >> confdefs.h <<\EOF
+#define const 
+EOF
+
+fi
+
+echo $ac_n "checking for inline""... $ac_c" 1>&6
+echo "configure:1522: checking for inline" >&5
+if eval "test \"`echo '$''{'ac_cv_c_inline'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_cv_c_inline=no
+for ac_kw in inline __inline__ __inline; do
+  cat > conftest.$ac_ext <<EOF
+#line 1529 "configure"
+#include "confdefs.h"
+
+int main() {
+} $ac_kw foo() {
+; return 0; }
+EOF
+if { (eval echo configure:1536: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_c_inline=$ac_kw; break
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+done
+
+fi
+
+echo "$ac_t""$ac_cv_c_inline" 1>&6
+case "$ac_cv_c_inline" in
+  inline | yes) ;;
+  no) cat >> confdefs.h <<\EOF
+#define inline 
+EOF
+ ;;
+  *)  cat >> confdefs.h <<EOF
+#define inline $ac_cv_c_inline
+EOF
+ ;;
+esac
+
+echo $ac_n "checking for size_t""... $ac_c" 1>&6
+echo "configure:1562: checking for size_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1567 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "(^|[^a-zA-Z_0-9])size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_type_size_t=yes
+else
+  rm -rf conftest*
+  ac_cv_type_size_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_size_t" 1>&6
+if test $ac_cv_type_size_t = no; then
+  cat >> confdefs.h <<\EOF
+#define size_t unsigned
+EOF
+
+fi
+
+echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
+echo "configure:1595: checking whether time.h and sys/time.h may both be included" >&5
+if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1600 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+int main() {
+struct tm *tp;
+; return 0; }
+EOF
+if { (eval echo configure:1609: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_header_time=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_time=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_time" 1>&6
+if test $ac_cv_header_time = yes; then
+  cat >> confdefs.h <<\EOF
+#define TIME_WITH_SYS_TIME 1
+EOF
+
+fi
+
+echo $ac_n "checking for long long""... $ac_c" 1>&6
+echo "configure:1630: checking for long long" >&5
+cat > conftest.$ac_ext <<EOF
+#line 1632 "configure"
+#include "confdefs.h"
+
+int main() {
+long long i = 0; return (0);
+; return 0; }
+EOF
+if { (eval echo configure:1639: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  echo "$ac_t""yes" 1>&6
+               ISC_PLATFORM_HAVELONGLONG="#define ISC_PLATFORM_HAVELONGLONG 1"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  echo "$ac_t""no" 1>&6
+               ISC_PLATFORM_HAVELONGLONG="#undef ISC_PLATFORM_HAVELONGLONG"
+fi
+rm -f conftest*
+
+
+#
+# check if we need to #include sys/select.h explicitly
+#
+case $ac_cv_header_unistd_h in
+yes)
+echo $ac_n "checking if unistd.h defines fd_set""... $ac_c" 1>&6
+echo "configure:1659: checking if unistd.h defines fd_set" >&5
+cat > conftest.$ac_ext <<EOF
+#line 1661 "configure"
+#include "confdefs.h"
+
+#include <unistd.h>
+int main() {
+fd_set read_set; return (0);
+; return 0; }
+EOF
+if { (eval echo configure:1669: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  echo "$ac_t""yes" 1>&6
+        ISC_PLATFORM_NEEDSYSSELECTH="#undef ISC_PLATFORM_NEEDSYSSELECTH"
+        LWRES_PLATFORM_NEEDSYSSELECTH="#undef LWRES_PLATFORM_NEEDSYSSELECTH"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  echo "$ac_t""no" 1>&6
+       case ac_cv_header_sys_select_h in
+       yes)
+         ISC_PLATFORM_NEEDSYSSELECTH="#define ISC_PLATFORM_NEEDSYSSELECTH 1"
+        LWRES_PLATFORM_NEEDSYSSELECTH="#define LWRES_PLATFORM_NEEDSYSSELECTH 1"
+               ;;
+       no)
+               { echo "configure: error: need either working unistd.h or sys/select.h" 1>&2; exit 1; }
+               ;;
+       esac
+       
+fi
+rm -f conftest*
+       ;;
+no)
+       case ac_cv_header_sys_select_h in
+       yes)
+             ISC_PLATFORM_NEEDSYSSELECTH="#define ISC_PLATFORM_NEEDSYSSELECTH 1"
+            LWRES_PLATFORM_NEEDSYSSELECTH="#define LWRES_PLATFORM_NEEDSYSSELECTH 1"
+               ;;
+       no)
+               { echo "configure: error: need either unistd.h or sys/select.h" 1>&2; exit 1; }
+               ;;
+       esac
+       ;;
+esac
+
+
+
+#
+# Find the machine's endian flavor.
+#
+echo $ac_n "checking whether byte ordering is bigendian""... $ac_c" 1>&6
+echo "configure:1711: checking whether byte ordering is bigendian" >&5
+if eval "test \"`echo '$''{'ac_cv_c_bigendian'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_cv_c_bigendian=unknown
+# See if sys/param.h defines the BYTE_ORDER macro.
+cat > conftest.$ac_ext <<EOF
+#line 1718 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/param.h>
+int main() {
+
+#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN
+ bogus endian macros
+#endif
+; return 0; }
+EOF
+if { (eval echo configure:1729: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  # It does; now see whether it defined to BIG_ENDIAN or not.
+cat > conftest.$ac_ext <<EOF
+#line 1733 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/param.h>
+int main() {
+
+#if BYTE_ORDER != BIG_ENDIAN
+ not big endian
+#endif
+; return 0; }
+EOF
+if { (eval echo configure:1744: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_c_bigendian=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_c_bigendian=no
+fi
+rm -f conftest*
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+if test $ac_cv_c_bigendian = unknown; then
+if test "$cross_compiling" = yes; then
+    { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1764 "configure"
+#include "confdefs.h"
+main () {
+  /* Are we little or big endian?  From Harbison&Steele.  */
+  union
+  {
+    long l;
+    char c[sizeof (long)];
+  } u;
+  u.l = 1;
+  exit (u.c[sizeof (long) - 1] == 1);
+}
+EOF
+if { (eval echo configure:1777: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_c_bigendian=no
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_c_bigendian=yes
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_c_bigendian" 1>&6
+if test $ac_cv_c_bigendian = yes; then
+  cat >> confdefs.h <<\EOF
+#define WORDS_BIGENDIAN 1
+EOF
+
+fi
+
+
+# Check whether --with-irs-gr or --without-irs-gr was given.
+if test "${with_irs_gr+set}" = set; then
+  withval="$with_irs_gr"
+  want_irs_gr="$withval"
+else
+  want_irs_gr="no"
+fi
+
+case "$want_irs_gr" in
+yes) WANT_IRS_GR="#define WANT_IRS_GR 1"
+     WANT_IRS_GR_OBJS="\${WANT_IRS_GR_OBJS}"
+       ;;
+*) WANT_IRS_GR="#undef WANT_IRS_GR" WANT_IRS_GR_OBJS="";;
+esac
+
+
+
+# Check whether --with-irs-pw or --without-irs-pw was given.
+if test "${with_irs_pw+set}" = set; then
+  withval="$with_irs_pw"
+  want_irs_pw="$withval"
+else
+  want_irs_pw="no"
+fi
+
+case "$want_irs_pw" in
+yes) WANT_IRS_PW="#define WANT_IRS_PW 1"
+     WANT_IRS_PW_OBJS="\${WANT_IRS_PW_OBJS}";;
+*) WANT_IRS_PW="#undef WANT_IRS_PW" WANT_IRS_PW_OBJS="";;
+esac
+
+
+
+# Check whether --with-irs-nis or --without-irs-nis was given.
+if test "${with_irs_nis+set}" = set; then
+  withval="$with_irs_nis"
+  want_irs_nis="$withval"
+else
+  want_irs_nis="no"
+fi
+
+case "$want_irs_nis" in
+yes)
+       WANT_IRS_NIS="#define WANT_IRS_NIS 1"
+       WANT_IRS_NIS_OBJS="WANT_IRS_NIS_OBJS"
+       case "$want_irs_gr" in
+       yes)
+               WANT_IRS_NISGR_OBJS="\${WANT_IRS_NISGR_OBJS}";;
+       *)
+               WANT_IRS_NISGR_OBJS="";;
+       esac
+       case "$want_irs_pw" in
+       yes)
+               WANT_IRS_NISPW_OBJS="\${WANT_IRS_NISPW_OBJS}";;
+       *)
+               WANT_IRS_NISPW_OBJS="";;
+       esac
+       ;;
+*)
+       WANT_IRS_NIS="#undef WANT_IRS_NIS"
+       WANT_IRS_NIS_OBJS=""
+       WANT_IRS_NISGR_OBJS=""
+       WANT_IRS_NISPW_OBJS="";;
+esac
+
+
+
+
+
+#
+# was --with-openssl specified?
+#
+echo $ac_n "checking for compatible OpenSSL library""... $ac_c" 1>&6
+echo "configure:1874: checking for compatible OpenSSL library" >&5
+# Check whether --with-openssl or --without-openssl was given.
+if test "${with_openssl+set}" = set; then
+  withval="$with_openssl"
+  use_openssl="$withval"
+else
+  use_openssl="no"
+fi
+
+
+#
+# If the user didn't specify where openssl is, and we didn't find or it
+# is incompatible with our code, use our internal one.
+#
+# XXX This appears to assume that the user specified path is correct,
+# and does no checking.
+#
+
+case "$use_openssl" in
+       no)
+               DST_PRIVATEOPENSSL='-DDST_USE_PRIVATE_OPENSSL'
+               dst_privateopenssl='openssl'
+               DST_OPENSSL_INC='-I${srcdir}/../openssl/include'
+               DST_OPENSSL_LIB=''
+               DST_OPENSSL_OBJS='${OPENSSLOBJS}'
+               echo "$ac_t""using private library" 1>&6
+               openssl_makefiles="lib/dns/sec/openssl/Makefile \
+                                  lib/dns/sec/openssl/include/Makefile \
+                                  lib/dns/sec/openssl/include/openssl/Makefile"
+
+               ;;
+       yes)
+               { echo "configure: error: --with-openssl must specify a path" 1>&2; exit 1; }
+               ;;
+       *)
+               DST_PRIVATEOPENSSL=''
+               dst_privateopenssl=''
+               DST_OPENSSL_INC="-I$use_openssl/include"
+               DNS_OPENSSL_LIBS="-L$use_openssl/lib -lcrypto"
+               DST_OPENSSL_LIB=''
+               echo "$ac_t""using openssl from $use_openssl/lib and $use_openssl/include" 1>&6
+               openssl_makefiles=""
+               ;;
+esac
+
+
+
+
+
+
+
+#
+# This would include the system openssl path (and linker options to use
+# it as needed) if it is found.
+#
+
+
+
+#
+# was --with-gssapi specified?
+#
+#AC_MSG_CHECKING(for GSSAPI library)
+#AC_ARG_WITH(gssapi,
+#[  --with-gssapi=PATH   Specify path for system-supplied GSSAPI],
+#    use_gssapi="$withval", use_gssapi="no")
+#
+#case "$use_gssapi" in
+#      no)
+#              USE_GSSAPI=''
+#              DST_GSSAPI_INC=''
+#              DNS_GSSAPI_LIBS=''
+#              AC_MSG_RESULT(not specified)
+#              ;;
+#      yes)
+#              AC_MSG_ERROR([--with-gssapi must specify a path])
+#              ;;
+#      *)
+#              USE_GSSAPI='-DGSSAPI'
+#              DST_GSSAPI_INC="-I$use_gssapi/include"
+#              DNS_GSSAPI_LIBS="-L$use_gssapi/lib -lgssapi_krb5"
+#              AC_MSG_RESULT(using gssapi from $use_gssapi/lib and $use_gssapi/include)
+#              ;;
+#esac
+
+USE_GSSAPI=''
+DST_GSSAPI_INC=''
+DNS_GSSAPI_LIBS=''
+
+
+
+
+
+#
+# was --with-randomdev specified?
+#
+echo $ac_n "checking for random device""... $ac_c" 1>&6
+echo "configure:1970: checking for random device" >&5
+# Check whether --with-randomdev or --without-randomdev was given.
+if test "${with_randomdev+set}" = set; then
+  withval="$with_randomdev"
+  use_randomdev="$withval"
+else
+  use_randomdev="unspec"
+fi
+
+
+case "$use_randomdev" in
+       unspec)
+               case "$host" in
+                       *-openbsd*)
+                               devrandom=/dev/srandom
+                               ;;
+                       *)
+                               devrandom=/dev/random
+                               ;;
+               esac
+               
+ac_safe=`echo "$devrandom" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $devrandom""... $ac_c" 1>&6
+echo "configure:1993: checking for $devrandom" >&5
+if eval "test \"`echo '$''{'ac_cv_file_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+    { echo "configure: error: Cannot check for file existence when cross compiling" 1>&2; exit 1; }
+else
+  if test -r $devrandom; then
+    eval "ac_cv_file_$ac_safe=yes"
+  else
+    eval "ac_cv_file_$ac_safe=no"
+  fi
+fi
+fi
+if eval "test \"`echo '$ac_cv_file_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<EOF
+#define PATH_RANDOMDEV "$devrandom"
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+
+fi
+
+               ;;
+       yes)
+               { echo "configure: error: --with-randomdev must specify a path" 1>&2; exit 1; }
+               ;;
+       *)
+               cat >> confdefs.h <<EOF
+#define PATH_RANDOMDEV "$use_randomdev"
+EOF
+
+               echo "$ac_t""using "$use_randomdev"" 1>&6
+               ;;
+esac
+
+#
+# Begin pthreads checking.
+#
+# First, decide whether to use multithreading or not.
+#
+echo $ac_n "checking whether to look for thread support""... $ac_c" 1>&6
+echo "configure:2037: checking whether to look for thread support" >&5
+# Check whether --enable-threads or --disable-threads was given.
+if test "${enable_threads+set}" = set; then
+  enableval="$enable_threads"
+  :
+fi
+
+case "$enable_threads" in
+       yes|'')
+               echo "$ac_t""yes" 1>&6
+               use_threads=true
+               ;;
+       no)
+               echo "$ac_t""no" 1>&6   
+               use_threads=false
+               ;;
+       *)
+               { echo "configure: error: --enable-threads takes yes or no" 1>&2; exit 1; }
+               ;;
+esac
+
+if $use_threads
+then
+       #
+       # Search for / configure pthreads in a system-dependent fashion.
+       #
+       case "$host" in
+         *-netbsd*)
+               # NetBSD has multiple pthreads implementations.  The
+               # recommended one to use is "unproven-pthreads".  The
+               # older "mit-pthreads" may also work on some NetBSD
+               # versions.  The PTL2 thread library does not
+               # currently work with bind9, but can be chosen with
+               # the --with-ptl2 option for those who wish to
+               # experiment with it.
+               CC="gcc"
+               echo $ac_n "checking which NetBSD thread library to use""... $ac_c" 1>&6
+echo "configure:2074: checking which NetBSD thread library to use" >&5
+
+               # Check whether --with-ptl2 or --without-ptl2 was given.
+if test "${with_ptl2+set}" = set; then
+  withval="$with_ptl2"
+  use_ptl2="$withval"
+else
+  use_ptl2="no"
+fi
+
+
+               : ${LOCALBASE:=/usr/pkg}
+
+               if test "X$use_ptl2" = "Xyes"
+               then
+                       echo "$ac_t""PTL2" 1>&6
+                       echo "configure: warning: linking with PTL2 is highly experimental and not expected to work" 1>&2
+                       CC=ptlgcc
+               else
+                       if test ! -d $LOCALBASE/pthreads
+                       then
+                               echo "$ac_t""none" 1>&6
+                               use_threads=false
+                       fi
+
+                       if $use_threads
+                       then
+                               echo "$ac_t""mit-pthreads/unproven-pthreads" 1>&6
+                               pkg="$LOCALBASE/pthreads"
+                               lib1="-L$pkg/lib -Wl,-R$pkg/lib"
+                               lib2="-lpthread -lm -lgcc -lpthread"
+                               LIBS="$lib1 $lib2 $LIBS"
+                               CPPFLAGS="$CPPFLAGS -I$pkg/include"
+                               STD_CINCLUDES="$STD_CINCLUDES -I$pkg/include"
+                       fi
+               fi
+               ;;
+               *)
+                       echo $ac_n "checking for pthread_create in -lpthread""... $ac_c" 1>&6
+echo "configure:2113: checking for pthread_create in -lpthread" >&5
+ac_lib_var=`echo pthread'_'pthread_create | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lpthread  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2121 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char pthread_create();
+
+int main() {
+pthread_create()
+; return 0; }
+EOF
+if { (eval echo configure:2132: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo pthread | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lpthread $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+echo $ac_n "checking for __pthread_create in -lpthread""... $ac_c" 1>&6
+echo "configure:2158: checking for __pthread_create in -lpthread" >&5
+ac_lib_var=`echo pthread'_'__pthread_create | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lpthread  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2166 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char __pthread_create();
+
+int main() {
+__pthread_create()
+; return 0; }
+EOF
+if { (eval echo configure:2177: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo pthread | sed -e 's/^a-zA-Z0-9_/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lpthread $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+echo $ac_n "checking for __pthread_create_system in -lpthread""... $ac_c" 1>&6
+echo "configure:2203: checking for __pthread_create_system in -lpthread" >&5
+ac_lib_var=`echo pthread'_'__pthread_create_system | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lpthread  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2211 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char __pthread_create_system();
+
+int main() {
+__pthread_create_system()
+; return 0; }
+EOF
+if { (eval echo configure:2222: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo pthread | sed -e 's/^a-zA-Z0-9_/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lpthread $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+echo $ac_n "checking for pthread_create in -lc_r""... $ac_c" 1>&6
+echo "configure:2248: checking for pthread_create in -lc_r" >&5
+ac_lib_var=`echo c_r'_'pthread_create | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lc_r  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2256 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char pthread_create();
+
+int main() {
+pthread_create()
+; return 0; }
+EOF
+if { (eval echo configure:2267: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo c_r | sed -e 's/^a-zA-Z0-9_/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lc_r $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+echo $ac_n "checking for pthread_create in -lc""... $ac_c" 1>&6
+echo "configure:2293: checking for pthread_create in -lc" >&5
+ac_lib_var=`echo c'_'pthread_create | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lc  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2301 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char pthread_create();
+
+int main() {
+pthread_create()
+; return 0; }
+EOF
+if { (eval echo configure:2312: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo c | sed -e 's/^a-zA-Z0-9_/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lc $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+use_threads=false
+fi
+
+fi
+
+fi
+
+fi
+
+fi
+
+               ;;
+       esac
+fi
+
+if $use_threads
+then
+       #
+       # We'd like to use sigwait() too
+       #
+       echo $ac_n "checking for sigwait in -lc""... $ac_c" 1>&6
+echo "configure:2358: checking for sigwait in -lc" >&5
+ac_lib_var=`echo c'_'sigwait | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lc  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2366 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char sigwait();
+
+int main() {
+sigwait()
+; return 0; }
+EOF
+if { (eval echo configure:2377: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_SIGWAIT 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+echo $ac_n "checking for sigwait in -lpthread""... $ac_c" 1>&6
+echo "configure:2399: checking for sigwait in -lpthread" >&5
+ac_lib_var=`echo pthread'_'sigwait | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lpthread  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2407 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char sigwait();
+
+int main() {
+sigwait()
+; return 0; }
+EOF
+if { (eval echo configure:2418: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_SIGWAIT 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+echo $ac_n "checking for _Psigwait in -lpthread""... $ac_c" 1>&6
+echo "configure:2440: checking for _Psigwait in -lpthread" >&5
+ac_lib_var=`echo pthread'_'_Psigwait | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lpthread  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2448 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char _Psigwait();
+
+int main() {
+_Psigwait()
+; return 0; }
+EOF
+if { (eval echo configure:2459: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_SIGWAIT 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+       
+fi
+
+
+       echo $ac_n "checking for pthread_attr_getstacksize""... $ac_c" 1>&6
+echo "configure:2489: checking for pthread_attr_getstacksize" >&5
+if eval "test \"`echo '$''{'ac_cv_func_pthread_attr_getstacksize'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2494 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char pthread_attr_getstacksize(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char pthread_attr_getstacksize();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_pthread_attr_getstacksize) || defined (__stub___pthread_attr_getstacksize)
+choke me
+#else
+pthread_attr_getstacksize();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2517: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_pthread_attr_getstacksize=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_pthread_attr_getstacksize=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'pthread_attr_getstacksize`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_PTHREAD_ATTR_GETSTACKSIZE 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+       #
+       # Additional OS-specific issues related to pthreads and sigwait.
+       #
+       case "$host" in
+               #
+               # One more place to look for sigwait.
+               #
+               *-freebsd*)
+                       echo $ac_n "checking for sigwait in -lc_r""... $ac_c" 1>&6
+echo "configure:2549: checking for sigwait in -lc_r" >&5
+ac_lib_var=`echo c_r'_'sigwait | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lc_r  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2557 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char sigwait();
+
+int main() {
+sigwait()
+; return 0; }
+EOF
+if { (eval echo configure:2568: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_SIGWAIT 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+                       ;;
+               #
+               # BSDI 3.0 through 4.0.1 needs pthread_init() to be
+               # called before certain pthreads calls.  This is deprecated
+               # in BSD/OS 4.1.
+               #
+               *-bsdi3.*|*-bsdi4.0*)
+                       cat >> confdefs.h <<\EOF
+#define NEED_PTHREAD_INIT 1
+EOF
+
+                       ;;
+               #
+               # LinuxThreads requires some changes to the way we
+               # deal with signals.
+               #
+               *-linux*)
+                       cat >> confdefs.h <<\EOF
+#define HAVE_LINUXTHREADS 1
+EOF
+
+                       ;;
+               #
+               # Ensure the right sigwait() semantics on Solaris and make
+               # sure we call pthread_setconcurrency.
+               #
+               *-solaris*)
+                       cat >> confdefs.h <<\EOF
+#define _POSIX_PTHREAD_SEMANTICS 1
+EOF
+
+                       echo $ac_n "checking for pthread_setconcurrency""... $ac_c" 1>&6
+echo "configure:2623: checking for pthread_setconcurrency" >&5
+if eval "test \"`echo '$''{'ac_cv_func_pthread_setconcurrency'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2628 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char pthread_setconcurrency(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char pthread_setconcurrency();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_pthread_setconcurrency) || defined (__stub___pthread_setconcurrency)
+choke me
+#else
+pthread_setconcurrency();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2651: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_pthread_setconcurrency=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_pthread_setconcurrency=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'pthread_setconcurrency`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define CALL_PTHREAD_SETCONCURRENCY 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+                       ;;
+               #
+               # UnixWare does things its own way.
+               #
+               *-UnixWare*)
+                       cat >> confdefs.h <<\EOF
+#define HAVE_UNIXWARE_SIGWAIT 1
+EOF
+
+                       ;;
+       esac
+
+       #
+       # Look for sysconf to allow detection of the number of processors.
+       #
+       echo $ac_n "checking for sysconf""... $ac_c" 1>&6
+echo "configure:2689: checking for sysconf" >&5
+if eval "test \"`echo '$''{'ac_cv_func_sysconf'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2694 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char sysconf(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char sysconf();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_sysconf) || defined (__stub___sysconf)
+choke me
+#else
+sysconf();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2717: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_sysconf=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_sysconf=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'sysconf`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_SYSCONF 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+       if test "X$GCC" = "Xyes"; then
+               case "$host" in
+               *-freebsd*)
+                       CC="$CC -pthread"
+                       CCOPT="$CCOPT -pthread"
+                       STD_CDEFINES="$STD_CDEFINES -D_THREAD_SAFE"
+                       ;;
+               *-openbsd*)
+                       CC="$CC -pthread"
+                       CCOPT="$CCOPT -pthread"
+                       ;;
+               *-solaris*)
+                       LIBS="$LIBS -lthread"
+                       ;;
+               *-ibm-aix*)
+                       STD_CDEFINES="$STD_CDEFINES -D_THREAD_SAFE"
+                       ;;
+               esac
+       else
+               case $host in
+               *-dec-osf*)
+                       CC="$CC -pthread"
+                       CCOPT="$CCOPT -pthread"
+                       ;;
+               *-solaris*)
+                       CC="$CC -mt"
+                       CCOPT="$CCOPT -mt"
+                       ;;
+               *-ibm-aix*)
+                       STD_CDEFINES="$STD_CDEFINES -D_THREAD_SAFE"
+                       ;;
+               *-UnixWare*)
+                       CC="$CC -Kthread"
+                       CCOPT="$CCOPT -Kthread"
+                       ;;
+               esac
+       fi
+       ALWAYS_DEFINES="-D_REENTRANT"
+       DO_PTHREADS="#define DO_PTHREADS 1"
+       WANT_IRS_THREADSGR_OBJS="\${WANT_IRS_THREADSGR_OBJS}"
+       WANT_IRS_THREADSPW_OBJS="\${WANT_IRS_THREADSPW_OBJS}"
+       WANT_IRS_THREADS_OBJS="\${WANT_IRS_THREADS_OBJS}"
+       thread_dir=pthreads
+else
+       ALWAYS_DEFINES=""
+       DO_PTHREADS="#undef DO_PTHREADS"
+       WANT_IRS_THREADSGR_OBJS=""
+       WANT_IRS_THREADSPW_OBJS=""
+       WANT_IRS_THREADS_OBJS=""
+       thread_dir=nothreads
+fi
+
+
+
+
+
+
+
+ISC_THREAD_DIR=$thread_dir
+
+
+#
+# flockfile is usually provided by pthreads, but we may want to use it
+# even if compiled with --disable-threads.
+#
+echo $ac_n "checking for flockfile""... $ac_c" 1>&6
+echo "configure:2806: checking for flockfile" >&5
+if eval "test \"`echo '$''{'ac_cv_func_flockfile'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2811 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char flockfile(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char flockfile();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_flockfile) || defined (__stub___flockfile)
+choke me
+#else
+flockfile();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2834: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_flockfile=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_flockfile=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'flockfile`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_FLOCKFILE 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+# 
+# Indicate what the final decision was regarding threads.
+#
+echo $ac_n "checking whether to build with threads""... $ac_c" 1>&6
+echo "configure:2861: checking whether to build with threads" >&5
+if $use_threads; then
+       echo "$ac_t""yes" 1>&6
+else
+       echo "$ac_t""no" 1>&6
+fi
+
+# 
+# End of pthreads stuff.
+#
+
+#
+# Additional compiler settings.
+#
+MKDEPCC="$CC"
+MKDEPCFLAGS="-M"
+IRIX_DNSSEC_WARNINGS_HACK=""
+
+if test "X$GCC" = "Xyes"; then
+       STD_CWARNINGS="$STD_CWARNINGS -W -Wall -Wmissing-prototypes -Wcast-qual -Wwrite-strings"
+else
+       case $host in
+       *-dec-osf*)
+               CC="$CC -std"
+               CCOPT="$CCOPT -std"
+               MKDEPCC="$CC"
+               ;;
+       *-hp-hpux*)
+               CC="$CC -Ae -z"
+               # The version of the C compiler that constantly warns about
+                # 'const' as well as alignment issues is unfortunately not
+                # able to be discerned via the version of the operating
+                # system, nor does cc have a version flag.
+               case "`$CC +W 123 2>&1`" in
+               *Unknown?option*)
+                       STD_CWARNINGS="+w1"
+                       ;;
+               *)
+                       # Turn off the pointlessly noisy warnings.
+                       STD_CWARNINGS="+w1 +W 474,530"
+                       ;;
+               esac
+               CCOPT="$CCOPT -Ae -z"
+               LIBS="-Wl,+vnocompatwarnings $LIBS"
+               MKDEPPROG='cc -Ae -E -Wp,-M >/dev/null 2>>$TMP'
+               ;;
+       *-sgi-irix*)
+               STD_CWARNINGS="-fullwarn -woff 1209"
+               #
+               # Silence more than 250 instances of
+               #   "prototyped function redeclared without prototype"
+               # and 11 instances of
+               #   "variable ... was set but never used"
+               # from lib/dns/sec/openssl.
+               #
+               IRIX_DNSSEC_WARNINGS_HACK="-woff 1692,1552"
+               ;;
+       *-solaris*)
+               MKDEPCFLAGS="-xM"
+               ;;
+       *-UnixWare*)
+               CC="$CC -w"
+               ;;
+       esac
+fi
+
+
+
+
+
+
+#
+# NLS
+#
+echo $ac_n "checking for catgets""... $ac_c" 1>&6
+echo "configure:2936: checking for catgets" >&5
+if eval "test \"`echo '$''{'ac_cv_func_catgets'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2941 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char catgets(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char catgets();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_catgets) || defined (__stub___catgets)
+choke me
+#else
+catgets();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2964: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_catgets=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_catgets=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'catgets`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_CATGETS 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+#
+# -lxnet buys us one big porting headache...  standards, gotta love 'em.
+#
+# AC_CHECK_LIB(xnet, socket, ,
+#    AC_CHECK_LIB(socket, socket)
+#    AC_CHECK_LIB(nsl, inet_ntoa)
+# )
+#
+# Use this for now, instead:
+#
+case "$host" in
+       mips-sgi-irix*)
+               ;;
+       *)
+               echo $ac_n "checking for socket in -lsocket""... $ac_c" 1>&6
+echo "configure:3002: checking for socket in -lsocket" >&5
+ac_lib_var=`echo socket'_'socket | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lsocket  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 3010 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char socket();
+
+int main() {
+socket()
+; return 0; }
+EOF
+if { (eval echo configure:3021: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo socket | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lsocket $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+               echo $ac_n "checking for inet_ntoa in -lnsl""... $ac_c" 1>&6
+echo "configure:3049: checking for inet_ntoa in -lnsl" >&5
+ac_lib_var=`echo nsl'_'inet_ntoa | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lnsl  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 3057 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char inet_ntoa();
+
+int main() {
+inet_ntoa()
+; return 0; }
+EOF
+if { (eval echo configure:3068: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo nsl | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lnsl $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+               ;;
+esac
+
+#
+# Purify support
+#
+echo $ac_n "checking whether to use purify""... $ac_c" 1>&6
+echo "configure:3102: checking whether to use purify" >&5
+# Check whether --with-purify or --without-purify was given.
+if test "${with_purify+set}" = set; then
+  withval="$with_purify"
+  use_purify="$withval"
+else
+  use_purify="no"
+fi
+
+
+case "$use_purify" in
+       no)
+               ;;
+       yes)
+               # Extract the first word of "purify", so it can be a program name with args.
+set dummy purify; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:3119: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_purify_path'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$purify_path" in
+  /*)
+  ac_cv_path_purify_path="$purify_path" # Let the user override the test with a path.
+  ;;
+  ?:/*)                         
+  ac_cv_path_purify_path="$purify_path" # Let the user override the test with a dos path.
+  ;;
+  *)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do 
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_purify_path="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_path_purify_path" && ac_cv_path_purify_path="purify"
+  ;;
+esac
+fi
+purify_path="$ac_cv_path_purify_path"
+if test -n "$purify_path"; then
+  echo "$ac_t""$purify_path" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+               ;;
+       *)
+               purify_path="$use_purify"
+               ;;
+esac
+
+case "$use_purify" in
+       no)
+               echo "$ac_t""no" 1>&6
+               PURIFY=""
+               ;;
+       *)
+               if test -f $purify_path || test $purify_path = purify; then
+                       echo "$ac_t""$purify_path" 1>&6
+                       PURIFYFLAGS="`echo $PURIFYOPTIONS`"
+                       PURIFY="$purify_path $PURIFYFLAGS"
+               else
+                       { echo "configure: error: $purify_path not found.
+
+Please choose the proper path with the following command:
+
+    configure --with-purify=PATH
+" 1>&2; exit 1; }
+               fi
+               ;;
+esac
+
+
+
+#
+# GNU libtool support
+#
+# Check whether --with-libtool or --without-libtool was given.
+if test "${with_libtool+set}" = set; then
+  withval="$with_libtool"
+  use_libtool="$withval"
+else
+  use_libtool="no"
+fi
+
+
+case $use_libtool in
+       yes)
+               AM_PROG_LIBTOOL
+               O=lo
+               A=la
+               ;;
+       *)
+               O=o
+               A=a
+               LIBTOOL=
+               
+               ;;
+esac
+
+#
+# File name extension for static archive files, for those few places
+# where they are treated differently from dynamic ones.
+#
+SA=a
+
+
+
+
+
+#
+# Here begins a very long section to determine the system's networking
+# capabilities.  The order of the tests is signficant.
+#
+
+#
+# IPv6
+#
+# Check whether --enable-ipv6 or --disable-ipv6 was given.
+if test "${enable_ipv6+set}" = set; then
+  enableval="$enable_ipv6"
+  :
+fi
+
+
+case "$enable_ipv6" in
+       yes|''|autodetect)
+               cat >> confdefs.h <<\EOF
+#define WANT_IPV6 1
+EOF
+
+               ;;
+       no)
+               ;;
+esac
+
+#
+# We do the IPv6 compilation checking after libtool so that we can put
+# the right suffix on the files.
+#
+echo $ac_n "checking for IPv6 structures""... $ac_c" 1>&6
+echo "configure:3248: checking for IPv6 structures" >&5
+cat > conftest.$ac_ext <<EOF
+#line 3250 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+int main() {
+struct sockaddr_in6 sin6; return (0);
+; return 0; }
+EOF
+if { (eval echo configure:3260: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  echo "$ac_t""yes" 1>&6
+        found_ipv6=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  echo "$ac_t""no" 1>&6
+        found_ipv6=no
+fi
+rm -f conftest*
+
+#
+# See whether IPv6 support is provided via a Kame add-on.
+# This is done before other IPv6 linking tests to LIBS is properly set.
+#
+echo $ac_n "checking for Kame IPv6 support""... $ac_c" 1>&6
+echo "configure:3278: checking for Kame IPv6 support" >&5
+# Check whether --with-kame or --without-kame was given.
+if test "${with_kame+set}" = set; then
+  withval="$with_kame"
+  use_kame="$withval"
+else
+  use_kame="no"
+fi
+
+
+case "$use_kame" in
+       no)
+               ;;
+       yes)
+               kame_path=/usr/local/v6
+               ;;
+       *)
+               kame_path="$use_kame"
+               ;;
+esac
+
+case "$use_kame" in
+       no)
+               echo "$ac_t""no" 1>&6
+               ;;
+       *)
+               if test -f $kame_path/lib/libinet6.a; then
+                       echo "$ac_t""$kame_path/lib/libinet6.a" 1>&6
+                       LIBS="-L$kame_path/lib -linet6 $LIBS"
+               else
+                       { echo "configure: error: $kame_path/lib/libinet6.a not found.
+
+Please choose the proper path with the following command:
+
+    configure --with-kame=PATH
+" 1>&2; exit 1; }
+               fi
+               ;;
+esac
+
+#
+# Whether netinet6/in6.h is needed has to be defined in isc/platform.h.
+# Including it on Kame-using platforms is very bad, though, because
+# Kame uses #error against direct inclusion.   So include it on only
+# the platform that is otherwise broken without it -- BSD/OS 4.0 through 4.1.
+# This is done before the in6_pktinfo check because that's what
+# netinet6/in6.h is needed for.
+#
+
+case "$host" in
+*-bsdi4.[01]*)
+       ISC_PLATFORM_NEEDNETINET6IN6H="#define ISC_PLATFORM_NEEDNETINET6IN6H 1"
+       LWRES_PLATFORM_NEEDNETINET6IN6H="#define LWRES_PLATFORM_NEEDNETINET6IN6H 1"
+       isc_netinet6in6_hack="#include <netinet6/in6.h>"
+       ;;
+*)
+       ISC_PLATFORM_NEEDNETINET6IN6H="#undef ISC_PLATFORM_NEEDNETINET6IN6H"
+       LWRES_PLATFORM_NEEDNETINET6IN6H="#undef LWRES_PLATFORM_NEEDNETINET6IN6H"
+       isc_netinet6in6_hack=""
+       ;;
+esac
+
+
+#
+# This is similar to the netinet6/in6.h issue.
+#
+case "$host" in
+*-UnixWare*)
+       ISC_PLATFORM_NEEDNETINETIN6H="#define ISC_PLATFORM_NEEDNETINETIN6H 1"
+       LWRES_PLATFORM_NEEDNETINETIN6H="#define LWRES_PLATFORM_NEEDNETINETIN6H 1"
+        ISC_PLATFORM_FIXIN6ISADDR="#define ISC_PLATFORM_FIXIN6ISADDR 1"
+       isc_netinetin6_hack="#include <netinet/in6.h>"
+       ;;
+*)
+       ISC_PLATFORM_NEEDNETINETIN6H="#undef ISC_PLATFORM_NEEDNETINETIN6H"
+       LWRES_PLATFORM_NEEDNETINETIN6H="#undef LWRES_PLATFORM_NEEDNETINETIN6H"
+        ISC_PLATFORM_FIXIN6ISADDR="#undef ISC_PLATFORM_FIXIN6ISADDR"
+       isc_netinetin6_hack=""
+       ;;
+esac
+
+#
+# Now delve deeper into the suitability of the IPv6 support.
+#
+case "$found_ipv6" in
+       yes)
+               ISC_PLATFORM_HAVEIPV6="#define ISC_PLATFORM_HAVEIPV6 1"
+               LWRES_PLATFORM_HAVEIPV6="#define LWRES_PLATFORM_HAVEIPV6 1"
+
+               echo $ac_n "checking for in6_addr""... $ac_c" 1>&6
+echo "configure:3368: checking for in6_addr" >&5
+               cat > conftest.$ac_ext <<EOF
+#line 3370 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+$isc_netinetin6_hack
+$isc_netinet6in6_hack
+
+int main() {
+struct in6_addr in6; return (0);
+; return 0; }
+EOF
+if { (eval echo configure:3383: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  echo "$ac_t""yes" 1>&6
+                ISC_PLATFORM_HAVEINADDR6="#undef ISC_PLATFORM_HAVEINADDR6"
+                LWRES_PLATFORM_HAVEINADDR6="#undef LWRES_PLATFORM_HAVEINADDR6"
+                isc_in_addr6_hack=""
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  echo "$ac_t""no" 1>&6
+                ISC_PLATFORM_HAVEINADDR6="#define ISC_PLATFORM_HAVEINADDR6 1"
+                LWRES_PLATFORM_HAVEINADDR6="#define LWRES_PLATFORM_HAVEINADDR6 1"
+                isc_in_addr6_hack="#define in6_addr in_addr6"
+fi
+rm -f conftest*
+
+               echo $ac_n "checking for in6addr_any""... $ac_c" 1>&6
+echo "configure:3401: checking for in6addr_any" >&5
+               cat > conftest.$ac_ext <<EOF
+#line 3403 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+$isc_netinetin6_hack
+$isc_netinet6in6_hack
+$isc_in_addr6_hack
+
+int main() {
+struct in6_addr in6; in6 = in6addr_any; return (0);
+; return 0; }
+EOF
+if { (eval echo configure:3417: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  echo "$ac_t""yes" 1>&6
+                        ISC_PLATFORM_NEEDIN6ADDRANY="#undef ISC_PLATFORM_NEEDIN6ADDRANY"
+                        LWRES_PLATFORM_NEEDIN6ADDRANY="#undef LWRES_PLATFORM_NEEDIN6ADDRANY"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  echo "$ac_t""no" 1>&6
+                        ISC_PLATFORM_NEEDIN6ADDRANY="#define ISC_PLATFORM_NEEDIN6ADDRANY 1"
+                        LWRES_PLATFORM_NEEDIN6ADDRANY="#define LWRES_PLATFORM_NEEDIN6ADDRANY 1"
+fi
+rm -f conftest*
+
+               echo $ac_n "checking for sin6_scope_id in struct sockaddr_in6""... $ac_c" 1>&6
+echo "configure:3433: checking for sin6_scope_id in struct sockaddr_in6" >&5
+               cat > conftest.$ac_ext <<EOF
+#line 3435 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+$isc_netinetin6_hack
+$isc_netinet6in6_hack
+
+int main() {
+struct sockaddr_in6 xyzzy; xyzzy.sin6_scope_id = 0; return (0);
+; return 0; }
+EOF
+if { (eval echo configure:3448: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  echo "$ac_t""yes" 1>&6
+                        result="#define LWRES_HAVE_SIN6_SCOPE_ID 1"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  echo "$ac_t""no" 1>&6
+                        result="#undef LWRES_HAVE_SIN6_SCOPE_ID"
+fi
+rm -f conftest*
+               LWRES_HAVE_SIN6_SCOPE_ID="$result"
+
+               echo $ac_n "checking for in6_pktinfo""... $ac_c" 1>&6
+echo "configure:3463: checking for in6_pktinfo" >&5
+               cat > conftest.$ac_ext <<EOF
+#line 3465 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+$isc_netinetin6_hack
+$isc_netinet6in6_hack
+
+int main() {
+struct in6_pktinfo xyzzy; return (0);
+; return 0; }
+EOF
+if { (eval echo configure:3478: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  echo "$ac_t""yes" 1>&6
+                        ISC_PLATFORM_HAVEIN6PKTINFO="#define ISC_PLATFORM_HAVEIN6PKTINFO 1"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  echo "$ac_t""no -- disabling runtime ipv6 support" 1>&6
+                        ISC_PLATFORM_HAVEIN6PKTINFO="#undef ISC_PLATFORM_HAVEIN6PKTINFO"
+fi
+rm -f conftest*
+               ;;
+       no)
+               ISC_PLATFORM_HAVEIPV6="#undef ISC_PLATFORM_HAVEIPV6"
+               LWRES_PLATFORM_HAVEIPV6="#undef LWRES_PLATFORM_HAVEIPV6"
+               ISC_PLATFORM_NEEDIN6ADDRANY="#undef ISC_PLATFORM_NEEDIN6ADDRANY"
+               LWRES_PLATFORM_NEEDIN6ADDRANY="#undef LWRES_PLATFORM_NEEDIN6ADDRANY"
+               ISC_PLATFORM_HAVEIN6PKTINFO="#undef ISC_PLATFORM_HAVEIN6PKTINFO"
+               LWRES_HAVE_SIN6_SCOPE_ID="#define LWRES_HAVE_SIN6_SCOPE_ID 1"
+               ISC_IPV6_H="ipv6.h"
+               ISC_IPV6_O="ipv6.$O"
+               ISC_ISCIPV6_O="unix/ipv6.$O"
+               ISC_IPV6_C="ipv6.c"
+               ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#
+# Check for network functions that are often missing.  We do this
+# after the libtool checking, so we can put the right suffix on
+# the files.  It also needs to come after checking for a Kame add-on,
+# which provides some (all?) of the desired functions.
+#
+echo $ac_n "checking for inet_ntop""... $ac_c" 1>&6
+echo "configure:3530: checking for inet_ntop" >&5
+cat > conftest.$ac_ext <<EOF
+#line 3532 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+int main() {
+inet_ntop(0, 0, 0, 0); return (0);
+; return 0; }
+EOF
+if { (eval echo configure:3542: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  echo "$ac_t""yes" 1>&6
+        ISC_PLATFORM_NEEDNTOP="#undef ISC_PLATFORM_NEEDNTOP"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  echo "$ac_t""no" 1>&6
+        ISC_EXTRA_OBJS="$ISC_EXTRA_OBJS inet_ntop.$O"
+        ISC_EXTRA_SRCS="$ISC_EXTRA_SRCS inet_ntop.c"
+        ISC_PLATFORM_NEEDNTOP="#define ISC_PLATFORM_NEEDNTOP 1"
+fi
+rm -f conftest*
+echo $ac_n "checking for inet_pton""... $ac_c" 1>&6
+echo "configure:3557: checking for inet_pton" >&5
+cat > conftest.$ac_ext <<EOF
+#line 3559 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+int main() {
+inet_pton(0, 0, 0); return (0);
+; return 0; }
+EOF
+if { (eval echo configure:3569: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  echo "$ac_t""yes" 1>&6
+        ISC_PLATFORM_NEEDPTON="#undef ISC_PLATFORM_NEEDPTON"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  echo "$ac_t""no" 1>&6
+        ISC_EXTRA_OBJS="$ISC_EXTRA_OBJS inet_pton.$O"
+        ISC_EXTRA_SRCS="$ISC_EXTRA_SRCS inet_pton.c"
+        ISC_PLATFORM_NEEDPTON="#define ISC_PLATFORM_NEEDPTON 1"
+fi
+rm -f conftest*
+echo $ac_n "checking for inet_aton""... $ac_c" 1>&6
+echo "configure:3584: checking for inet_aton" >&5
+cat > conftest.$ac_ext <<EOF
+#line 3586 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+int main() {
+struct in_addr in; inet_aton(0, &in); return (0);
+; return 0; }
+EOF
+if { (eval echo configure:3596: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  echo "$ac_t""yes" 1>&6
+        ISC_PLATFORM_NEEDATON="#undef ISC_PLATFORM_NEEDATON"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  echo "$ac_t""no" 1>&6
+        ISC_EXTRA_OBJS="$ISC_EXTRA_OBJS inet_aton.$O"
+        ISC_EXTRA_SRCS="$ISC_EXTRA_SRCS inet_aton.c"
+        ISC_PLATFORM_NEEDATON="#define ISC_PLATFORM_NEEDATON 1"
+fi
+rm -f conftest*
+
+
+
+
+
+#
+# Look for a 4.4BSD-style sa_len member in struct sockaddr.
+#
+case "$host" in
+       *-dec-osf*)
+               # Turn on 4.4BSD style sa_len support.
+               cat >> confdefs.h <<\EOF
+#define _SOCKADDR_LEN 1
+EOF
+
+               ;;
+esac
+
+echo $ac_n "checking for sa_len in struct sockaddr""... $ac_c" 1>&6
+echo "configure:3629: checking for sa_len in struct sockaddr" >&5
+cat > conftest.$ac_ext <<EOF
+#line 3631 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+int main() {
+struct sockaddr sa; sa.sa_len = 0; return (0);
+; return 0; }
+EOF
+if { (eval echo configure:3640: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  echo "$ac_t""yes" 1>&6
+       HAVE_SA_LEN="#define HAVE_SA_LEN 1"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  echo "$ac_t""no" 1>&6
+       HAVE_SA_LEN="#undef HAVE_SA_LEN"
+fi
+rm -f conftest*
+
+
+# HAVE_MINIMUM_IFREQ
+
+case "$host" in
+       *-bsdi4*)       have_minimum_ifreq=yes;;
+       *-bsdi3*)       have_minimum_ifreq=yes;;
+       *-bsdi2*)       have_minimum_ifreq=yes;;
+       *-darwin*)      have_minimum_ifreq=yes;;
+       *-freebsd*)     have_minimum_ifreq=yes;;
+       *-lynxos*)      have_minimum_ifreq=yes;;
+       *-netbsd*)      have_minimum_ifreq=yes;;
+       *-next*)        have_minimum_ifreq=yes;;
+       *-openbsd*)     have_minimum_ifreq=yes;;
+       *-rhapsody*)    have_minimum_ifreq=yes;;
+esac
+case "$have_minimum_ifreq" in
+       yes)
+               HAVE_MINIMUM_IFREQ="#define HAVE_MINIMUM_IFREQ 1";;
+       no)
+               HAVE_MINIMUM_IFREQ="#undef HAVE_MINIMUM_IFREQ";;
+       *)
+               HAVE_MINIMUM_IFREQ="#undef HAVE_MINIMUM_IFREQ";;
+esac
+
+#
+# Look for a 4.4BSD or 4.3BSD struct msghdr
+#
+echo $ac_n "checking for struct msghdr flavor""... $ac_c" 1>&6
+echo "configure:3681: checking for struct msghdr flavor" >&5
+cat > conftest.$ac_ext <<EOF
+#line 3683 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+int main() {
+struct msghdr msg; msg.msg_flags = 0; return (0);
+; return 0; }
+EOF
+if { (eval echo configure:3692: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  echo "$ac_t""4.4BSD" 1>&6
+       ISC_PLATFORM_MSGHDRFLAVOR="#define ISC_NET_BSD44MSGHDR 1"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  echo "$ac_t""4.3BSD" 1>&6
+       ISC_PLATFORM_MSGHDRFLAVOR="#define ISC_NET_BSD43MSGHDR 1"
+fi
+rm -f conftest*
+
+
+#
+# Look for in_port_t.
+#
+echo $ac_n "checking for type in_port_t""... $ac_c" 1>&6
+echo "configure:3710: checking for type in_port_t" >&5
+cat > conftest.$ac_ext <<EOF
+#line 3712 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+int main() {
+in_port_t port = 25; return (0);
+; return 0; }
+EOF
+if { (eval echo configure:3721: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  echo "$ac_t""yes" 1>&6
+       ISC_PLATFORM_NEEDPORTT="#undef ISC_PLATFORM_NEEDPORTT"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  echo "$ac_t""no" 1>&6
+       ISC_PLATFORM_NEEDPORTT="#define ISC_PLATFORM_NEEDPORTT 1"
+fi
+rm -f conftest*
+
+
+#
+# Check for addrinfo
+#
+echo $ac_n "checking for struct addrinfo""... $ac_c" 1>&6
+echo "configure:3739: checking for struct addrinfo" >&5
+cat > conftest.$ac_ext <<EOF
+#line 3741 "configure"
+#include "confdefs.h"
+
+#include <netdb.h>
+int main() {
+struct addrinfo a; return (0);
+; return 0; }
+EOF
+if { (eval echo configure:3749: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  echo "$ac_t""yes" 1>&6
+       ISC_LWRES_NEEDADDRINFO="#undef ISC_LWRES_NEEDADDRINFO"
+       cat >> confdefs.h <<\EOF
+#define HAVE_ADDRINFO 1
+EOF
+
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  echo "$ac_t""no" 1>&6
+       ISC_LWRES_NEEDADDRINFO="#define ISC_LWRES_NEEDADDRINFO 1"
+fi
+rm -f conftest*
+
+
+echo $ac_n "checking for int sethostent""... $ac_c" 1>&6
+echo "configure:3768: checking for int sethostent" >&5
+cat > conftest.$ac_ext <<EOF
+#line 3770 "configure"
+#include "confdefs.h"
+
+#include <netdb.h>
+int main() {
+int i = sethostent(0); return(0);
+; return 0; }
+EOF
+if { (eval echo configure:3778: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  echo "$ac_t""yes" 1>&6
+       ISC_LWRES_SETHOSTENTINT="#define ISC_LWRES_SETHOSTENTINT 1"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  echo "$ac_t""no" 1>&6
+       ISC_LWRES_SETHOSTENTINT="#undef ISC_LWRES_SETHOSTENTINT"
+fi
+rm -f conftest*
+
+
+echo $ac_n "checking for int endhostent""... $ac_c" 1>&6
+echo "configure:3793: checking for int endhostent" >&5
+cat > conftest.$ac_ext <<EOF
+#line 3795 "configure"
+#include "confdefs.h"
+
+#include <netdb.h>
+int main() {
+int i = endhostent(); return(0);
+; return 0; }
+EOF
+if { (eval echo configure:3803: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  echo "$ac_t""yes" 1>&6
+       ISC_LWRES_ENDHOSTENTINT="#define ISC_LWRES_ENDHOSTENTINT 1"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  echo "$ac_t""no" 1>&6
+       ISC_LWRES_ENDHOSTENTINT="#undef ISC_LWRES_ENDHOSTENTINT"
+fi
+rm -f conftest*
+
+
+echo $ac_n "checking for getnetbyaddr(in_addr_t, ...)""... $ac_c" 1>&6
+echo "configure:3818: checking for getnetbyaddr(in_addr_t, ...)" >&5
+cat > conftest.$ac_ext <<EOF
+#line 3820 "configure"
+#include "confdefs.h"
+
+#include <netdb.h>
+struct netent *getnetbyaddr(in_addr_t, int);
+int main() {
+
+; return 0; }
+EOF
+if { (eval echo configure:3829: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  echo "$ac_t""yes" 1>&6
+       GETNETBYADDR_ADDR_T="#define GETNETBYADDR_ADDR_T in_addr_t"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  echo "$ac_t""no" 1>&6
+       GETNETBYADDR_ADDR_T="#define GETNETBYADDR_ADDR_T long"
+fi
+rm -f conftest*
+
+
+echo $ac_n "checking for int setnetent""... $ac_c" 1>&6
+echo "configure:3844: checking for int setnetent" >&5
+cat > conftest.$ac_ext <<EOF
+#line 3846 "configure"
+#include "confdefs.h"
+
+#include <netdb.h>
+int main() {
+int i = setnetent(0); return(0);
+; return 0; }
+EOF
+if { (eval echo configure:3854: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  echo "$ac_t""yes" 1>&6
+       ISC_LWRES_SETNETENTINT="#define ISC_LWRES_SETNETENTINT 1"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  echo "$ac_t""no" 1>&6
+       ISC_LWRES_SETNETENTINT="#undef ISC_LWRES_SETNETENTINT"
+fi
+rm -f conftest*
+
+
+echo $ac_n "checking for int endnetent""... $ac_c" 1>&6
+echo "configure:3869: checking for int endnetent" >&5
+cat > conftest.$ac_ext <<EOF
+#line 3871 "configure"
+#include "confdefs.h"
+
+#include <netdb.h>
+int main() {
+int i = endnetent(); return(0);
+; return 0; }
+EOF
+if { (eval echo configure:3879: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  echo "$ac_t""yes" 1>&6
+       ISC_LWRES_ENDNETENTINT="#define ISC_LWRES_ENDNETENTINT 1"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  echo "$ac_t""no" 1>&6
+       ISC_LWRES_ENDNETENTINT="#undef ISC_LWRES_ENDNETENTINT"
+fi
+rm -f conftest*
+
+
+echo $ac_n "checking for gethostbyaddr(const void *, size_t, ...)""... $ac_c" 1>&6
+echo "configure:3894: checking for gethostbyaddr(const void *, size_t, ...)" >&5
+cat > conftest.$ac_ext <<EOF
+#line 3896 "configure"
+#include "confdefs.h"
+
+#include <netdb.h>
+struct hostent *gethostbyaddr(const void *, size_t, int);
+int main() {
+return(0);
+; return 0; }
+EOF
+if { (eval echo configure:3905: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  echo "$ac_t""yes" 1>&6
+       ISC_LWRES_GETHOSTBYADDRVOID="#define ISC_LWRES_GETHOSTBYADDRVOID 1"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  echo "$ac_t""no" 1>&6
+       ISC_LWRES_GETHOSTBYADDRVOID="#undef ISC_LWRES_GETHOSTBYADDRVOID"
+fi
+rm -f conftest*
+
+
+echo $ac_n "checking for h_errno in netdb.h""... $ac_c" 1>&6
+echo "configure:3920: checking for h_errno in netdb.h" >&5
+cat > conftest.$ac_ext <<EOF
+#line 3922 "configure"
+#include "confdefs.h"
+
+#include <netdb.h>
+int main() {
+h_errno = 1; return(0);
+; return 0; }
+EOF
+if { (eval echo configure:3930: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  echo "$ac_t""yes" 1>&6
+       ISC_LWRES_NEEDHERRNO="#undef ISC_LWRES_NEEDHERRNO"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  echo "$ac_t""no" 1>&6
+       ISC_LWRES_NEEDHERRNO="#define ISC_LWRES_NEEDHERRNO 1"
+fi
+rm -f conftest*
+
+
+echo $ac_n "checking for getipnodebyname""... $ac_c" 1>&6
+echo "configure:3945: checking for getipnodebyname" >&5
+if eval "test \"`echo '$''{'ac_cv_func_getipnodebyname'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 3950 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char getipnodebyname(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char getipnodebyname();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_getipnodebyname) || defined (__stub___getipnodebyname)
+choke me
+#else
+getipnodebyname();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:3973: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_getipnodebyname=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_getipnodebyname=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'getipnodebyname`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  ISC_LWRES_GETIPNODEPROTO="#undef ISC_LWRES_GETIPNODEPROTO"
+else
+  echo "$ac_t""no" 1>&6
+ISC_LWRES_GETIPNODEPROTO="#define ISC_LWRES_GETIPNODEPROTO 1"
+fi
+
+echo $ac_n "checking for getnameinfo""... $ac_c" 1>&6
+echo "configure:3994: checking for getnameinfo" >&5
+if eval "test \"`echo '$''{'ac_cv_func_getnameinfo'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 3999 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char getnameinfo(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char getnameinfo();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_getnameinfo) || defined (__stub___getnameinfo)
+choke me
+#else
+getnameinfo();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:4022: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_getnameinfo=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_getnameinfo=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'getnameinfo`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  ISC_LWRES_GETNAMEINFOPROTO="#undef ISC_LWRES_GETNAMEINFOPROTO"
+else
+  echo "$ac_t""no" 1>&6
+ISC_LWRES_GETNAMEINFOPROTO="#define ISC_LWRES_GETNAMEINFOPROTO 1"
+fi
+
+echo $ac_n "checking for getaddrinfo""... $ac_c" 1>&6
+echo "configure:4043: checking for getaddrinfo" >&5
+if eval "test \"`echo '$''{'ac_cv_func_getaddrinfo'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4048 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char getaddrinfo(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char getaddrinfo();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_getaddrinfo) || defined (__stub___getaddrinfo)
+choke me
+#else
+getaddrinfo();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:4071: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_getaddrinfo=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_getaddrinfo=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'getaddrinfo`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  ISC_LWRES_GETADDRINFOPROTO="#undef ISC_LWRES_GETADDRINFOPROTO"
+       cat >> confdefs.h <<\EOF
+#define HAVE_GETADDRINFO 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+ISC_LWRES_GETADDRINFOPROTO="#define ISC_LWRES_GETADDRINFOPROTO 1"
+fi
+
+echo $ac_n "checking for gai_strerror""... $ac_c" 1>&6
+echo "configure:4096: checking for gai_strerror" >&5
+if eval "test \"`echo '$''{'ac_cv_func_gai_strerror'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4101 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char gai_strerror(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char gai_strerror();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_gai_strerror) || defined (__stub___gai_strerror)
+choke me
+#else
+gai_strerror();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:4124: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_gai_strerror=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_gai_strerror=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'gai_strerror`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_GAISTRERROR 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+
+
+echo $ac_n "checking for pselect""... $ac_c" 1>&6
+echo "configure:4150: checking for pselect" >&5
+if eval "test \"`echo '$''{'ac_cv_func_pselect'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4155 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char pselect(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char pselect();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_pselect) || defined (__stub___pselect)
+choke me
+#else
+pselect();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:4178: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_pselect=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_pselect=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'pselect`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  NEED_PSELECT="#undef NEED_PSELECT"
+else
+  echo "$ac_t""no" 1>&6
+NEED_PSELECT="#define NEED_PSELECT"
+fi
+
+
+
+#
+# Look for a sysctl call to get the list of network interfaces.
+#
+echo $ac_n "checking for interface list sysctl""... $ac_c" 1>&6
+echo "configure:4204: checking for interface list sysctl" >&5
+cat > conftest.$ac_ext <<EOF
+#line 4206 "configure"
+#include "confdefs.h"
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/socket.h>
+#ifdef NET_RT_IFLIST
+found_rt_iflist
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "found_rt_iflist" >/dev/null 2>&1; then
+  rm -rf conftest*
+  echo "$ac_t""yes" 1>&6
+        cat >> confdefs.h <<\EOF
+#define HAVE_IFLIST_SYSCTL 1
+EOF
+
+else
+  rm -rf conftest*
+  echo "$ac_t""no" 1>&6
+fi
+rm -f conftest*
+
+
+#
+# Check for some other useful functions that are not ever-present.
+#
+echo $ac_n "checking for strsep""... $ac_c" 1>&6
+echo "configure:4236: checking for strsep" >&5
+if eval "test \"`echo '$''{'ac_cv_func_strsep'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4241 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char strsep(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char strsep();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_strsep) || defined (__stub___strsep)
+choke me
+#else
+strsep();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:4264: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_strsep=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_strsep=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'strsep`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  ISC_PLATFORM_NEEDSTRSEP="#undef ISC_PLATFORM_NEEDSTRSEP"
+else
+  echo "$ac_t""no" 1>&6
+ISC_PLATFORM_NEEDSTRSEP="#define ISC_PLATFORM_NEEDSTRSEP 1"
+fi
+
+echo $ac_n "checking for vsnprintf""... $ac_c" 1>&6
+echo "configure:4285: checking for vsnprintf" >&5
+if eval "test \"`echo '$''{'ac_cv_func_vsnprintf'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4290 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char vsnprintf(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char vsnprintf();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_vsnprintf) || defined (__stub___vsnprintf)
+choke me
+#else
+vsnprintf();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:4313: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_vsnprintf=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_vsnprintf=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'vsnprintf`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  ISC_PLATFORM_NEEDVSNPRINTF="#undef ISC_PLATFORM_NEEDVSNPRINTF"
+else
+  echo "$ac_t""no" 1>&6
+ISC_EXTRA_OBJS="$ISC_EXTRA_OBJS print.$O"
+        ISC_EXTRA_SRCS="$ISC_EXTRA_SRCS print.c"
+        ISC_PLATFORM_NEEDVSNPRINTF="#define ISC_PLATFORM_NEEDVSNPRINTF 1"
+fi
+
+
+
+
+
+
+
+#
+# Determine the printf format characters to use when printing
+# values of type isc_int64_t.  We make the assumption that platforms
+# where a "long long" is the same size as a "long" (e.g., Alpha/OSF1)
+# want "%ld" and everyone else can use "%lld".  Win32 uses "%I64d",
+# but that's defined elsewhere since we don't use configure on Win32.
+#
+echo $ac_n "checking printf format modifier for 64-bit integers""... $ac_c" 1>&6
+echo "configure:4349: checking printf format modifier for 64-bit integers" >&5
+if test "$cross_compiling" = yes; then
+  echo "$ac_t""default ll" 1>&6
+       ISC_PLATFORM_QUADFORMAT='#define ISC_PLATFORM_QUADFORMAT "ll"'
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4355 "configure"
+#include "confdefs.h"
+main() { exit(!(sizeof(long long int) == sizeof(long int))); }
+EOF
+if { (eval echo configure:4359: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  echo "$ac_t""l" 1>&6
+       ISC_PLATFORM_QUADFORMAT='#define ISC_PLATFORM_QUADFORMAT "l"'
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  echo "$ac_t""ll" 1>&6
+       ISC_PLATFORM_QUADFORMAT='#define ISC_PLATFORM_QUADFORMAT "ll"'
+fi
+rm -fr conftest*
+fi
+
+
+
+#
+# Security Stuff
+#
+echo $ac_n "checking for chroot""... $ac_c" 1>&6
+echo "configure:4379: checking for chroot" >&5
+if eval "test \"`echo '$''{'ac_cv_func_chroot'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4384 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char chroot(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char chroot();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_chroot) || defined (__stub___chroot)
+choke me
+#else
+chroot();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:4407: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_chroot=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_chroot=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'chroot`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_CHROOT 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+for ac_hdr in linux/capability.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:4433: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4438 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:4443: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_hdr in sys/prctl.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:4473: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4478 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:4483: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+
+#
+# BSD/OS, and perhaps some others, don't define rlim_t.
+#
+echo $ac_n "checking for type rlim_t""... $ac_c" 1>&6
+echo "configure:4514: checking for type rlim_t" >&5
+cat > conftest.$ac_ext <<EOF
+#line 4516 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+int main() {
+rlim_t rl = 19671212; return (0);
+; return 0; }
+EOF
+if { (eval echo configure:4526: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  echo "$ac_t""yes" 1>&6
+         cat >> confdefs.h <<\EOF
+#define HAVE_RLIM_T 1
+EOF
+
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  echo "$ac_t""no" 1>&6
+fi
+rm -f conftest*
+echo $ac_n "checking sizeof rlim_cur""... $ac_c" 1>&6
+echo "configure:4541: checking sizeof rlim_cur" >&5
+if test "$cross_compiling" = yes; then
+    { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4546 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+main() { struct rlimit r; exit(!(sizeof(r.rlim_cur) == sizeof(int)));}
+EOF
+if { (eval echo configure:4554: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  echo "$ac_t""int" 1>&6
+ISC_PLATFORM_RLIMITTYPE="#define ISC_PLATFORM_RLIMITTYPE int"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  
+if test "$cross_compiling" = yes; then
+    { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4567 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+main() { struct rlimit r; exit(!(sizeof(r.rlim_cur) == sizeof(long int)));}
+EOF
+if { (eval echo configure:4575: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  echo "$ac_t""long int" 1>&6
+ISC_PLATFORM_RLIMITTYPE="#define ISC_PLATFORM_RLIMITTYPE long int"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  
+if test "$cross_compiling" = yes; then
+    { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4588 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+main() { struct rlimit r; exit((!sizeof(r.rlim_cur) == sizeof(long long int)));}
+EOF
+if { (eval echo configure:4596: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  echo "$ac_t""long long int" 1>&6
+ISC_PLATFORM_RLIMITTYPE="#define ISC_PLATFORM_RLIMITTYPE long long int"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  { echo "configure: error: unable to determine sizeof rlim_cur" 1>&2; exit 1; }
+
+fi
+rm -fr conftest*
+fi
+
+
+fi
+rm -fr conftest*
+fi
+
+
+fi
+rm -fr conftest*
+fi
+
+
+
+echo $ac_n "checking for getgrouplist""... $ac_c" 1>&6
+echo "configure:4623: checking for getgrouplist" >&5
+if eval "test \"`echo '$''{'ac_cv_func_getgrouplist'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4628 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char getgrouplist(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char getgrouplist();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_getgrouplist) || defined (__stub___getgrouplist)
+choke me
+#else
+getgrouplist();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:4651: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_getgrouplist=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_getgrouplist=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'getgrouplist`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat > conftest.$ac_ext <<EOF
+#line 4666 "configure"
+#include "confdefs.h"
+#include <unistd.h>
+int
+getgrouplist(const char *name, int basegid, int *groups, int *ngroups) {
+}
+
+int main() {
+return (0);
+; return 0; }
+EOF
+if { (eval echo configure:4677: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  GETGROUPLIST_ARGS="#define GETGROUPLIST_ARGS const char *name, int basegid, int *groups, int *ngroups"
+
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  GETGROUPLIST_ARGS="#define GETGROUPLIST_ARGS const char *name, gid_t basegid, gid_t *groups, int *ngroups"
+
+fi
+rm -f conftest*
+else
+  echo "$ac_t""no" 1>&6
+GETGROUPLIST_ARGS="#define GETGROUPLIST_ARGS const char *name, gid_t basegid, gid_t *groups, int *ngroups"
+
+fi
+
+
+
+echo $ac_n "checking for getnetbyaddr_r""... $ac_c" 1>&6
+echo "configure:4698: checking for getnetbyaddr_r" >&5
+if eval "test \"`echo '$''{'ac_cv_func_getnetbyaddr_r'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4703 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char getnetbyaddr_r(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char getnetbyaddr_r();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_getnetbyaddr_r) || defined (__stub___getnetbyaddr_r)
+choke me
+#else
+getnetbyaddr_r();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:4726: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_getnetbyaddr_r=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_getnetbyaddr_r=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'getnetbyaddr_r`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+NET_R_ARGS="#define NET_R_ARGS char *buf, int buflen"
+NET_R_BAD="#define NET_R_BAD NULL"
+NET_R_COPY="#define NET_R_COPY buf, buflen"
+NET_R_COPY_ARGS="#define NET_R_COPY_ARGS NET_R_ARGS"
+NET_R_OK="#define NET_R_OK nptr"
+NET_R_RETURN="#define NET_R_RETURN struct netent *"
+
+fi
+
+
+
+
+
+
+
+
+echo $ac_n "checking for setnetent_r""... $ac_c" 1>&6
+echo "configure:4760: checking for setnetent_r" >&5
+if eval "test \"`echo '$''{'ac_cv_func_setnetent_r'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4765 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char setnetent_r(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char setnetent_r();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_setnetent_r) || defined (__stub___setnetent_r)
+choke me
+#else
+setnetent_r();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:4788: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_setnetent_r=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_setnetent_r=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'setnetent_r`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+NET_R_ENT_ARGS="#undef NET_R_ENT_ARGS /*empty*/"
+NET_R_SET_RESULT="#undef NET_R_SET_RESULT /*empty*/"
+NET_R_SET_RETURN="#define NET_R_SET_RETURN void"
+
+fi
+
+
+
+
+
+echo $ac_n "checking for endnetent_r""... $ac_c" 1>&6
+echo "configure:4816: checking for endnetent_r" >&5
+if eval "test \"`echo '$''{'ac_cv_func_endnetent_r'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4821 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char endnetent_r(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char endnetent_r();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_endnetent_r) || defined (__stub___endnetent_r)
+choke me
+#else
+endnetent_r();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:4844: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_endnetent_r=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_endnetent_r=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'endnetent_r`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+NET_R_END_RESULT="#define NET_R_END_RESULT(x) /*empty*/"
+NET_R_END_RETURN="#define NET_R_END_RETURN void"
+
+fi
+
+
+
+
+echo $ac_n "checking for getgrent_r""... $ac_c" 1>&6
+echo "configure:4870: checking for getgrent_r" >&5
+if eval "test \"`echo '$''{'ac_cv_func_getgrent_r'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4875 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char getgrent_r(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char getgrent_r();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_getgrent_r) || defined (__stub___getgrent_r)
+choke me
+#else
+getgrent_r();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:4898: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_getgrent_r=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_getgrent_r=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'getgrent_r`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+GROUP_R_ARGS="#define GROUP_R_ARGS char *buf, int buflen"
+GROUP_R_BAD="#define GROUP_R_BAD NULL"
+GROUP_R_OK="#define GROUP_R_OK gptr"
+GROUP_R_RETURN="#define GROUP_R_RETURN struct group *"
+
+fi
+
+
+
+
+
+
+echo $ac_n "checking for endgrent_r""... $ac_c" 1>&6
+echo "configure:4928: checking for endgrent_r" >&5
+if eval "test \"`echo '$''{'ac_cv_func_endgrent_r'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4933 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char endgrent_r(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char endgrent_r();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_endgrent_r) || defined (__stub___endgrent_r)
+choke me
+#else
+endgrent_r();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:4956: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_endgrent_r=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_endgrent_r=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'endgrent_r`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+GROUP_R_END_RESULT="#define GROUP_R_END_RESULT(x) /*empty*/"
+GROUP_R_END_RETURN="#define GROUP_R_END_RETURN void"
+GROUP_R_ENT_ARGS="#define GROUP_R_ENT_ARGS void"
+
+fi
+
+
+
+
+
+echo $ac_n "checking for setgrent_r""... $ac_c" 1>&6
+echo "configure:4984: checking for setgrent_r" >&5
+if eval "test \"`echo '$''{'ac_cv_func_setgrent_r'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4989 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char setgrent_r(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char setgrent_r();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_setgrent_r) || defined (__stub___setgrent_r)
+choke me
+#else
+setgrent_r();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5012: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_setgrent_r=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_setgrent_r=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'setgrent_r`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+GROUP_R_SET_RESULT="#undef GROUP_R_SET_RESULT /*empty*/"
+GROUP_R_SET_RETURN="#define GROUP_R_SET_RETURN void"
+
+fi
+
+
+
+
+echo $ac_n "checking for gethostbyname_r""... $ac_c" 1>&6
+echo "configure:5038: checking for gethostbyname_r" >&5
+if eval "test \"`echo '$''{'ac_cv_func_gethostbyname_r'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5043 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char gethostbyname_r(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char gethostbyname_r();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_gethostbyname_r) || defined (__stub___gethostbyname_r)
+choke me
+#else
+gethostbyname_r();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5066: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_gethostbyname_r=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_gethostbyname_r=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'gethostbyname_r`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+HOST_R_ARGS="#define HOST_R_ARGS char *buf, int buflen, int *h_errnop"
+HOST_R_BAD="#define HOST_R_BAD NULL"
+HOST_R_COPY="#define HOST_R_COPY buf, buflen"
+HOST_R_COPY_ARGS="#define HOST_R_COPY_ARGS char *buf, int buflen"
+HOST_R_ERRNO="#define HOST_R_ERRNO *h_errnop = h_errno"
+HOST_R_OK="#define HOST_R_OK hptr"
+HOST_R_RETURN="#define HOST_R_RETURN struct hostent *"
+
+fi
+
+
+
+
+
+
+
+
+
+echo $ac_n "checking for endhostent_r""... $ac_c" 1>&6
+echo "configure:5102: checking for endhostent_r" >&5
+if eval "test \"`echo '$''{'ac_cv_func_endhostent_r'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5107 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char endhostent_r(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char endhostent_r();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_endhostent_r) || defined (__stub___endhostent_r)
+choke me
+#else
+endhostent_r();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5130: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_endhostent_r=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_endhostent_r=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'endhostent_r`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+HOST_R_END_RESULT="#define HOST_R_END_RESULT(x) /*empty*/"
+HOST_R_END_RETURN="#define HOST_R_END_RETURN void"
+HOST_R_ENT_ARGS="#undef HOST_R_ENT_ARGS /*empty*/"
+
+fi
+
+
+
+
+
+echo $ac_n "checking for sethostent_r""... $ac_c" 1>&6
+echo "configure:5158: checking for sethostent_r" >&5
+if eval "test \"`echo '$''{'ac_cv_func_sethostent_r'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5163 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char sethostent_r(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char sethostent_r();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_sethostent_r) || defined (__stub___sethostent_r)
+choke me
+#else
+sethostent_r();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5186: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_sethostent_r=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_sethostent_r=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'sethostent_r`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+HOST_R_SET_RESULT="#undef HOST_R_SET_RESULT /*empty*/"
+HOST_R_SET_RETURN="#define HOST_R_SET_RETURN void"
+
+fi
+
+
+
+
+
+cat > conftest.$ac_ext <<EOF
+#line 5213 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <pwd.h>
+void
+setpwent(void) {}
+
+int main() {
+return (0);
+; return 0; }
+EOF
+if { (eval echo configure:5225: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  SETPWENT_VOID="#define SETPWENT_VOID 1"
+
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  SETPWENT_VOID="#undef SETPWENT_VOID"
+
+fi
+rm -f conftest*
+
+
+echo $ac_n "checking for getnetgrent_r""... $ac_c" 1>&6
+echo "configure:5240: checking for getnetgrent_r" >&5
+if eval "test \"`echo '$''{'ac_cv_func_getnetgrent_r'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5245 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char getnetgrent_r(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char getnetgrent_r();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_getnetgrent_r) || defined (__stub___getnetgrent_r)
+choke me
+#else
+getnetgrent_r();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5268: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_getnetgrent_r=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_getnetgrent_r=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'getnetgrent_r`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+NGR_R_ARGS="#define NGR_R_ARGS char *buf, int buflen"
+NGR_R_BAD="#define NGR_R_BAD (0)"
+NGR_R_COPY="#define NGR_R_COPY buf, buflen"
+NGR_R_COPY_ARGS="#define NGR_R_COPY_ARGS NGR_R_ARGS"
+NGR_R_OK="#define NGR_R_OK 1"
+NGR_R_RETURN="#define NGR_R_RETURN int"
+
+fi
+
+
+
+
+
+
+
+
+echo $ac_n "checking for endnetgrent_r""... $ac_c" 1>&6
+echo "configure:5302: checking for endnetgrent_r" >&5
+if eval "test \"`echo '$''{'ac_cv_func_endnetgrent_r'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5307 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char endnetgrent_r(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char endnetgrent_r();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_endnetgrent_r) || defined (__stub___endnetgrent_r)
+choke me
+#else
+endnetgrent_r();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5330: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_endnetgrent_r=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_endnetgrent_r=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'endnetgrent_r`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+NGR_R_END_RESULT="#define NGR_R_END_RESULT(x)  /*empty*/"
+NGR_R_END_RETURN="#define NGR_R_END_RETURN void"
+NGR_R_ENT_ARGS="#undef NGR_R_ENT_ARGS /*empty*/"
+
+fi
+
+
+
+
+
+echo $ac_n "checking for setnetgrent_r""... $ac_c" 1>&6
+echo "configure:5358: checking for setnetgrent_r" >&5
+if eval "test \"`echo '$''{'ac_cv_func_setnetgrent_r'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5363 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char setnetgrent_r(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char setnetgrent_r();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_setnetgrent_r) || defined (__stub___setnetgrent_r)
+choke me
+#else
+setnetgrent_r();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5386: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_setnetgrent_r=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_setnetgrent_r=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'setnetgrent_r`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+NGR_R_SET_RESULT="#undef NGR_R_SET_RESULT /*empty*/"
+NGR_R_SET_RETURN="#define NGR_R_SET_RETURN void"
+
+fi
+
+
+
+
+
+echo $ac_n "checking for getprotoent_r""... $ac_c" 1>&6
+echo "configure:5413: checking for getprotoent_r" >&5
+if eval "test \"`echo '$''{'ac_cv_func_getprotoent_r'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5418 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char getprotoent_r(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char getprotoent_r();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_getprotoent_r) || defined (__stub___getprotoent_r)
+choke me
+#else
+getprotoent_r();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5441: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_getprotoent_r=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_getprotoent_r=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'getprotoent_r`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+PROTO_R_ARGS="#define PROTO_R_ARGS char *buf, int buflen"
+PROTO_R_BAD="#define PROTO_R_BAD NULL"
+PROTO_R_COPY="#define PROTO_R_COPY buf, buflen"
+PROTO_R_COPY_ARGS="#define PROTO_R_COPY_ARGS PROTO_R_ARGS"
+PROTO_R_OK="#define PROTO_R_OK pptr"
+PROTO_R_RETURN="#define PROTO_R_RETURN struct protoent *"
+
+fi
+
+
+
+
+
+
+
+
+echo $ac_n "checking for endprotoent_r""... $ac_c" 1>&6
+echo "configure:5475: checking for endprotoent_r" >&5
+if eval "test \"`echo '$''{'ac_cv_func_endprotoent_r'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5480 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char endprotoent_r(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char endprotoent_r();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_endprotoent_r) || defined (__stub___endprotoent_r)
+choke me
+#else
+endprotoent_r();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5503: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_endprotoent_r=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_endprotoent_r=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'endprotoent_r`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+PROTO_R_END_RESULT="#define PROTO_R_END_RESULT(x) /*empty*/"
+PROTO_R_END_RETURN="#define PROTO_R_END_RETURN void"
+PROTO_R_ENT_ARGS="#undef PROTO_R_ENT_ARGS /*empty*/"
+
+fi
+
+
+
+
+
+echo $ac_n "checking for setprotoent_r""... $ac_c" 1>&6
+echo "configure:5531: checking for setprotoent_r" >&5
+if eval "test \"`echo '$''{'ac_cv_func_setprotoent_r'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5536 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char setprotoent_r(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char setprotoent_r();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_setprotoent_r) || defined (__stub___setprotoent_r)
+choke me
+#else
+setprotoent_r();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5559: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_setprotoent_r=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_setprotoent_r=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'setprotoent_r`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+PROTO_R_SET_RESULT="#undef PROTO_R_SET_RESULT /*empty*/"
+PROTO_R_SET_RETURN="#define PROTO_R_SET_RETURN void"
+
+fi
+
+
+
+
+echo $ac_n "checking for getpwent_r""... $ac_c" 1>&6
+echo "configure:5585: checking for getpwent_r" >&5
+if eval "test \"`echo '$''{'ac_cv_func_getpwent_r'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5590 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char getpwent_r(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char getpwent_r();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_getpwent_r) || defined (__stub___getpwent_r)
+choke me
+#else
+getpwent_r();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5613: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_getpwent_r=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_getpwent_r=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'getpwent_r`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+PASS_R_ARGS="#define PASS_R_ARGS char *buf, int buflen"
+PASS_R_BAD="#define PASS_R_BAD NULL"
+PASS_R_COPY="#define PASS_R_COPY buf, buflen"
+PASS_R_COPY_ARGS="#define PASS_R_COPY_ARGS PASS_R_ARGS"
+PASS_R_OK="#define PASS_R_OK pwptr"
+PASS_R_RETURN="#define PASS_R_RETURN struct passwd *"
+
+fi
+
+
+
+
+
+
+
+
+echo $ac_n "checking for endpwent_r""... $ac_c" 1>&6
+echo "configure:5647: checking for endpwent_r" >&5
+if eval "test \"`echo '$''{'ac_cv_func_endpwent_r'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5652 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char endpwent_r(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char endpwent_r();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_endpwent_r) || defined (__stub___endpwent_r)
+choke me
+#else
+endpwent_r();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5675: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_endpwent_r=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_endpwent_r=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'endpwent_r`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+PASS_R_END_RESULT="#define PASS_R_END_RESULT(x) /*empty*/"
+PASS_R_END_RETURN="#define PASS_R_END_RETURN void"
+PASS_R_ENT_ARGS="#undef PASS_R_ENT_ARGS /*empty*/"
+
+fi
+
+
+
+
+
+echo $ac_n "checking for setpwent_r""... $ac_c" 1>&6
+echo "configure:5703: checking for setpwent_r" >&5
+if eval "test \"`echo '$''{'ac_cv_func_setpwent_r'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5708 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char setpwent_r(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char setpwent_r();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_setpwent_r) || defined (__stub___setpwent_r)
+choke me
+#else
+setpwent_r();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5731: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_setpwent_r=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_setpwent_r=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'setpwent_r`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+PASS_R_SET_RESULT="#undef PASS_R_SET_RESULT /*empty*/"
+PASS_R_SET_RETURN="#define PASS_R_SET_RETURN void"
+
+fi
+
+
+
+
+echo $ac_n "checking for getservent_r""... $ac_c" 1>&6
+echo "configure:5757: checking for getservent_r" >&5
+if eval "test \"`echo '$''{'ac_cv_func_getservent_r'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5762 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char getservent_r(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char getservent_r();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_getservent_r) || defined (__stub___getservent_r)
+choke me
+#else
+getservent_r();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5785: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_getservent_r=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_getservent_r=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'getservent_r`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+SERV_R_ARGS="#define SERV_R_ARGS char *buf, int buflen"
+SERV_R_BAD="#define SERV_R_BAD NULL"
+SERV_R_COPY="#define SERV_R_COPY buf, buflen"
+SERV_R_COPY_ARGS="#define SERV_R_COPY_ARGS SERV_R_ARGS"
+SERV_R_OK="#define SERV_R_OK sptr"
+SERV_R_RETURN="#define SERV_R_RETURN struct servent *"
+
+fi
+
+
+
+
+
+
+
+
+echo $ac_n "checking for endservent_r""... $ac_c" 1>&6
+echo "configure:5819: checking for endservent_r" >&5
+if eval "test \"`echo '$''{'ac_cv_func_endservent_r'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5824 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char endservent_r(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char endservent_r();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_endservent_r) || defined (__stub___endservent_r)
+choke me
+#else
+endservent_r();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5847: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_endservent_r=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_endservent_r=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'endservent_r`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+SERV_R_END_RESULT="#define SERV_R_END_RESULT(x) /*empty*/"
+SERV_R_END_RETURN="#define SERV_R_END_RETURN void "
+SERV_R_ENT_ARGS="#undef SERV_R_ENT_ARGS /*empty*/"
+
+fi
+
+
+
+
+
+echo $ac_n "checking for setservent_r""... $ac_c" 1>&6
+echo "configure:5875: checking for setservent_r" >&5
+if eval "test \"`echo '$''{'ac_cv_func_setservent_r'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5880 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char setservent_r(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char setservent_r();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_setservent_r) || defined (__stub___setservent_r)
+choke me
+#else
+setservent_r();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5903: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_setservent_r=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_setservent_r=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'setservent_r`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+SERV_R_SET_RESULT="#undef SERV_R_SET_RESULT /*empty*/"
+SERV_R_SET_RETURN="#define SERV_R_SET_RETURN void"
+
+fi
+
+
+
+
+#
+# Random remaining OS-specific issues involving compiler warnings.
+# XXXDCL print messages to indicate some compensation is being done?
+#
+
+ISC_PLATFORM_BRACEPTHREADONCEINIT="#undef ISC_PLATFORM_BRACEPTHREADONCEINIT"
+
+case "$host" in
+       *-bsdi3.1*)
+               hack_shutup_sputaux=yes
+               ;;
+       *-bsdi4.0*)
+               hack_shutup_sigwait=yes
+               hack_shutup_sputaux=yes
+               ;;
+       *-bsdi4.1*)
+               hack_shutup_stdargcast=yes
+               ;;
+       *-solaris2.8)
+               hack_shutup_pthreadonceinit=yes
+               ;;
+esac
+
+case "$hack_shutup_pthreadonceinit" in
+       yes)
+               #
+               # Shut up PTHREAD_ONCE_INIT unbraced initializer warnings.
+               #
+               ISC_PLATFORM_BRACEPTHREADONCEINIT="#define ISC_PLATFORM_BRACEPTHREADONCEINIT 1"
+               ;;
+esac
+
+case "$hack_shutup_sigwait" in
+       yes)
+               #
+               # Shut up a -Wmissing-prototypes warning for sigwait().
+               #
+               cat >> confdefs.h <<\EOF
+#define SHUTUP_SIGWAIT 1
+EOF
+
+               ;;
+esac
+
+case "$hack_shutup_sputaux" in
+       yes)
+               #
+               # Shut up a -Wmissing-prototypes warning from <stdio.h>.
+               #
+               cat >> confdefs.h <<\EOF
+#define SHUTUP_SPUTAUX 1
+EOF
+
+               ;;
+esac
+
+case "$hack_shutup_stdargcast" in
+       yes)
+               #
+               # Shut up a -Wcast-qual warning from va_start().
+               #
+               cat >> confdefs.h <<\EOF
+#define SHUTUP_STDARG_CAST 1
+EOF
+
+               ;;
+esac
+
+
+#
+# Look for jade, preferring openjade if installed.
+#
+
+for ac_prog in openjade jade
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:6006: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_JADE'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$JADE" in
+  /*)
+  ac_cv_path_JADE="$JADE" # Let the user override the test with a path.
+  ;;
+  ?:/*)                         
+  ac_cv_path_JADE="$JADE" # Let the user override the test with a dos path.
+  ;;
+  *)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do 
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_JADE="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  ;;
+esac
+fi
+JADE="$ac_cv_path_JADE"
+if test -n "$JADE"; then
+  echo "$ac_t""$JADE" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+test -n "$JADE" && break
+done
+test -n "$JADE" || JADE="jade"
+
+
+
+#
+# Look for tex & pdftex.
+#
+
+for ac_prog in tex
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:6053: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_TEX'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$TEX" in
+  /*)
+  ac_cv_path_TEX="$TEX" # Let the user override the test with a path.
+  ;;
+  ?:/*)                         
+  ac_cv_path_TEX="$TEX" # Let the user override the test with a dos path.
+  ;;
+  *)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do 
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_TEX="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  ;;
+esac
+fi
+TEX="$ac_cv_path_TEX"
+if test -n "$TEX"; then
+  echo "$ac_t""$TEX" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+test -n "$TEX" && break
+done
+
+
+
+for ac_prog in pdftex
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:6095: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_PDFTEX'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$PDFTEX" in
+  /*)
+  ac_cv_path_PDFTEX="$PDFTEX" # Let the user override the test with a path.
+  ;;
+  ?:/*)                         
+  ac_cv_path_PDFTEX="$PDFTEX" # Let the user override the test with a dos path.
+  ;;
+  *)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do 
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_PDFTEX="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  ;;
+esac
+fi
+PDFTEX="$ac_cv_path_PDFTEX"
+if test -n "$PDFTEX"; then
+  echo "$ac_t""$PDFTEX" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+test -n "$PDFTEX" && break
+done
+
+
+
+#
+# Look for SGML files.  NetBSD has them under /usr/pkg/share 
+# (if installed), FreeBSD has them under /usr/local/share.
+#
+
+SGMLDIR=""
+
+echo $ac_n "checking for SGML files""... $ac_c" 1>&6
+echo "configure:6140: checking for SGML files" >&5
+for d in /usr/pkg/share/sgml /usr/local/share/sgml 
+do
+       if test -f $d/docbook/dsssl/modular/html/docbook.dsl
+       then
+               SGMLDIR=$d
+               echo "$ac_t""in $SGMLDIR" 1>&6
+               break
+       fi
+done
+
+if test "X$SGMLDIR" = "X"
+then
+       echo "$ac_t"""not found"" 1>&6;
+       SGMLDIR=/usr/local/share/sgml
+fi
+
+
+
+#
+# Look for XML files.
+#
+XGMLDIR=""
+
+echo $ac_n "checking for XML files""... $ac_c" 1>&6
+echo "configure:6165: checking for XML files" >&5
+for d in /usr/pkg/share/xml /usr/local/share/xml
+do
+       if test -f $d/dtd/docbook/docbookx.dtd
+       then
+               XMLDIR=$d
+               echo "$ac_t""in $XMLDIR" 1>&6
+               break
+       fi
+done
+
+if test "X$XMLDIR" = "X"
+then
+       echo "$ac_t"""not found"" 1>&6;
+       XMLDIR=/usr/local/share/xml
+fi
+
+
+
+#
+# Substitutions
+#
+
+BIND9_TOP_BUILDDIR=`pwd`
+
+
+
+
+
+
+if test "X$srcdir" != "X"; then
+       BIND9_ISC_BUILDINCLUDE="-I${BIND9_TOP_BUILDDIR}/lib/isc/include"
+       BIND9_ISCCFG_BUILDINCLUDE="-I${BIND9_TOP_BUILDDIR}/lib/isccfg/include"
+       BIND9_DNS_BUILDINCLUDE="-I${BIND9_TOP_BUILDDIR}/lib/dns/include"
+       BIND9_OMAPI_BUILDINCLUDE="-I${BIND9_TOP_BUILDDIR}/lib/omapi/include"
+       BIND9_LWRES_BUILDINCLUDE="-I${BIND9_TOP_BUILDDIR}/lib/lwres/include"
+else
+       BIND9_ISC_BUILDINCLUDE=""
+       BIND9_ISCCFG_BUILDINCLUDE=""
+       BIND9_DNS_BUILDINCLUDE=""
+       BIND9_OMAPI_BUILDINCLUDE=""
+       BIND9_LWRES_BUILDINCLUDE=""
+fi
+
+
+BIND9_INCLUDES=$BIND9_TOP_BUILDDIR/make/includes
+
+
+BIND9_MAKE_RULES=$BIND9_TOP_BUILDDIR/make/rules
+
+. $srcdir/../../version
+BIND9_VERSION="VERSION=${MAJORVER}.${MINORVER}.${PATCHVER}${RELEASETYPE}${RELEASEVER}"
+
+
+
+LIBISC_API=$srcdir/lib/isc/api
+
+
+LIBISCCFG_API=$srcdir/lib/isccfg/api
+
+
+LIBDNS_API=$srcdir/lib/dns/api
+
+
+LIBLWRES_API=$srcdir/lib/lwres/api
+
+
+LIBOMAPI_API=$srcdir/lib/omapi/api
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs.  It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already.  You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+  case `(ac_space=' '; set | grep ac_space) 2>&1` in
+  *ac_space=\ *)
+    # `set' does not quote correctly, so add quotes (double-quote substitution
+    # turns \\\\ into \\, and sed turns \\ into \).
+    sed -n \
+      -e "s/'/'\\\\''/g" \
+      -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+    ;;
+  *)
+    # `set' quotes correctly as required by POSIX, so do not add quotes.
+    sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+    ;;
+  esac >> confcache
+if cmp -s $cache_file confcache; then
+  :
+else
+  if test -w $cache_file; then
+    echo "updating cache $cache_file"
+    cat confcache > $cache_file
+  else
+    echo "not updating unwritable cache $cache_file"
+  fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[        ]*VPATH[        ]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+DEFS=-DHAVE_CONFIG_H
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+  case "\$ac_option" in
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+    exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+  -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+    echo "$CONFIG_STATUS generated by autoconf version 2.13"
+    exit 0 ;;
+  -help | --help | --hel | --he | --h)
+    echo "\$ac_cs_usage"; exit 0 ;;
+  *) echo "\$ac_cs_usage"; exit 1 ;;
+  esac
+done
+
+ac_given_srcdir=$srcdir
+ac_given_INSTALL="$INSTALL"
+
+trap 'rm -fr `echo "Makefile
+       bsd/Makefile
+       cylink/Makefile
+       dnssafe/Makefile
+       dst/Makefile
+       include/Makefile
+       inet/Makefile
+       irs/Makefile
+       isc/Makefile
+       nameser/Makefile
+       port_after.h
+       port_before.h
+       resolv/Makefile
+       make/rules
+       make/mkdep
+       make/includes
+ config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@SHELL@%$SHELL%g
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@FFLAGS@%$FFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@host@%$host%g
+s%@host_alias@%$host_alias%g
+s%@host_cpu@%$host_cpu%g
+s%@host_vendor@%$host_vendor%g
+s%@host_os@%$host_os%g
+s%@SET_MAKE@%$SET_MAKE%g
+s%@RANLIB@%$RANLIB%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@STD_CINCLUDES@%$STD_CINCLUDES%g
+s%@STD_CDEFINES@%$STD_CDEFINES%g
+s%@STD_CWARNINGS@%$STD_CWARNINGS%g
+s%@CCOPT@%$CCOPT%g
+s%@AR@%$AR%g
+s%@ARFLAGS@%$ARFLAGS%g
+s%@LN@%$LN%g
+s%@ETAGS@%$ETAGS%g
+s%@PERL@%$PERL%g
+s%@CC@%$CC%g
+s%@CPP@%$CPP%g
+s%@ISC_PLATFORM_HAVELONGLONG@%$ISC_PLATFORM_HAVELONGLONG%g
+s%@ISC_PLATFORM_NEEDSYSSELECTH@%$ISC_PLATFORM_NEEDSYSSELECTH%g
+s%@LWRES_PLATFORM_NEEDSYSSELECTH@%$LWRES_PLATFORM_NEEDSYSSELECTH%g
+s%@WANT_IRS_GR@%$WANT_IRS_GR%g
+s%@WANT_IRS_GR_OBJS@%$WANT_IRS_GR_OBJS%g
+s%@WANT_IRS_PW@%$WANT_IRS_PW%g
+s%@WANT_IRS_PW_OBJS@%$WANT_IRS_PW_OBJS%g
+s%@WANT_IRS_NIS@%$WANT_IRS_NIS%g
+s%@WANT_IRS_NIS_OBJS@%$WANT_IRS_NIS_OBJS%g
+s%@WANT_IRS_NISGR_OBJS@%$WANT_IRS_NISGR_OBJS%g
+s%@WANT_IRS_NISPW_OBJS@%$WANT_IRS_NISPW_OBJS%g
+s%@DST_PRIVATEOPENSSL@%$DST_PRIVATEOPENSSL%g
+s%@dst_privateopenssl@%$dst_privateopenssl%g
+s%@DST_OPENSSL_INC@%$DST_OPENSSL_INC%g
+s%@DST_OPENSSL_LIB@%$DST_OPENSSL_LIB%g
+s%@DST_OPENSSL_OBJS@%$DST_OPENSSL_OBJS%g
+s%@DNS_OPENSSL_LIBS@%$DNS_OPENSSL_LIBS%g
+s%@USE_GSSAPI@%$USE_GSSAPI%g
+s%@DST_GSSAPI_INC@%$DST_GSSAPI_INC%g
+s%@DNS_GSSAPI_LIBS@%$DNS_GSSAPI_LIBS%g
+s%@ALWAYS_DEFINES@%$ALWAYS_DEFINES%g
+s%@DO_PTHREADS@%$DO_PTHREADS%g
+s%@WANT_IRS_THREADSGR_OBJS@%$WANT_IRS_THREADSGR_OBJS%g
+s%@WANT_IRS_THREADSPW_OBJS@%$WANT_IRS_THREADSPW_OBJS%g
+s%@WANT_IRS_THREADS_OBJS@%$WANT_IRS_THREADS_OBJS%g
+s%@ISC_THREAD_DIR@%$ISC_THREAD_DIR%g
+s%@MKDEPCC@%$MKDEPCC%g
+s%@MKDEPCFLAGS@%$MKDEPCFLAGS%g
+s%@MKDEPPROG@%$MKDEPPROG%g
+s%@IRIX_DNSSEC_WARNINGS_HACK@%$IRIX_DNSSEC_WARNINGS_HACK%g
+s%@purify_path@%$purify_path%g
+s%@PURIFY@%$PURIFY%g
+s%@LIBTOOL@%$LIBTOOL%g
+s%@O@%$O%g
+s%@A@%$A%g
+s%@SA@%$SA%g
+s%@ISC_PLATFORM_HAVEIPV6@%$ISC_PLATFORM_HAVEIPV6%g
+s%@LWRES_PLATFORM_HAVEIPV6@%$LWRES_PLATFORM_HAVEIPV6%g
+s%@ISC_PLATFORM_NEEDNETINETIN6H@%$ISC_PLATFORM_NEEDNETINETIN6H%g
+s%@LWRES_PLATFORM_NEEDNETINETIN6H@%$LWRES_PLATFORM_NEEDNETINETIN6H%g
+s%@ISC_PLATFORM_NEEDNETINET6IN6H@%$ISC_PLATFORM_NEEDNETINET6IN6H%g
+s%@LWRES_PLATFORM_NEEDNETINET6IN6H@%$LWRES_PLATFORM_NEEDNETINET6IN6H%g
+s%@ISC_PLATFORM_HAVEINADDR6@%$ISC_PLATFORM_HAVEINADDR6%g
+s%@LWRES_PLATFORM_HAVEINADDR6@%$LWRES_PLATFORM_HAVEINADDR6%g
+s%@ISC_PLATFORM_NEEDIN6ADDRANY@%$ISC_PLATFORM_NEEDIN6ADDRANY%g
+s%@LWRES_PLATFORM_NEEDIN6ADDRANY@%$LWRES_PLATFORM_NEEDIN6ADDRANY%g
+s%@ISC_PLATFORM_HAVEIN6PKTINFO@%$ISC_PLATFORM_HAVEIN6PKTINFO%g
+s%@ISC_PLATFORM_FIXIN6ISADDR@%$ISC_PLATFORM_FIXIN6ISADDR%g
+s%@ISC_IPV6_H@%$ISC_IPV6_H%g
+s%@ISC_IPV6_O@%$ISC_IPV6_O%g
+s%@ISC_ISCIPV6_O@%$ISC_ISCIPV6_O%g
+s%@ISC_IPV6_C@%$ISC_IPV6_C%g
+s%@LWRES_HAVE_SIN6_SCOPE_ID@%$LWRES_HAVE_SIN6_SCOPE_ID%g
+s%@ISC_PLATFORM_NEEDNTOP@%$ISC_PLATFORM_NEEDNTOP%g
+s%@ISC_PLATFORM_NEEDPTON@%$ISC_PLATFORM_NEEDPTON%g
+s%@ISC_PLATFORM_NEEDATON@%$ISC_PLATFORM_NEEDATON%g
+s%@HAVE_SA_LEN@%$HAVE_SA_LEN%g
+s%@HAVE_MINIMUM_IFREQ@%$HAVE_MINIMUM_IFREQ%g
+s%@ISC_PLATFORM_MSGHDRFLAVOR@%$ISC_PLATFORM_MSGHDRFLAVOR%g
+s%@ISC_PLATFORM_NEEDPORTT@%$ISC_PLATFORM_NEEDPORTT%g
+s%@ISC_LWRES_NEEDADDRINFO@%$ISC_LWRES_NEEDADDRINFO%g
+s%@ISC_LWRES_SETHOSTENTINT@%$ISC_LWRES_SETHOSTENTINT%g
+s%@ISC_LWRES_ENDHOSTENTINT@%$ISC_LWRES_ENDHOSTENTINT%g
+s%@GETNETBYADDR_ADDR_T@%$GETNETBYADDR_ADDR_T%g
+s%@ISC_LWRES_SETNETENTINT@%$ISC_LWRES_SETNETENTINT%g
+s%@ISC_LWRES_ENDNETENTINT@%$ISC_LWRES_ENDNETENTINT%g
+s%@ISC_LWRES_GETHOSTBYADDRVOID@%$ISC_LWRES_GETHOSTBYADDRVOID%g
+s%@ISC_LWRES_NEEDHERRNO@%$ISC_LWRES_NEEDHERRNO%g
+s%@ISC_LWRES_GETIPNODEPROTO@%$ISC_LWRES_GETIPNODEPROTO%g
+s%@ISC_LWRES_GETADDRINFOPROTO@%$ISC_LWRES_GETADDRINFOPROTO%g
+s%@ISC_LWRES_GETNAMEINFOPROTO@%$ISC_LWRES_GETNAMEINFOPROTO%g
+s%@NEED_PSELECT@%$NEED_PSELECT%g
+s%@ISC_PLATFORM_NEEDSTRSEP@%$ISC_PLATFORM_NEEDSTRSEP%g
+s%@ISC_PLATFORM_NEEDVSNPRINTF@%$ISC_PLATFORM_NEEDVSNPRINTF%g
+s%@ISC_EXTRA_OBJS@%$ISC_EXTRA_OBJS%g
+s%@ISC_EXTRA_SRCS@%$ISC_EXTRA_SRCS%g
+s%@ISC_PLATFORM_QUADFORMAT@%$ISC_PLATFORM_QUADFORMAT%g
+s%@ISC_PLATFORM_RLIMITTYPE@%$ISC_PLATFORM_RLIMITTYPE%g
+s%@GETGROUPLIST_ARGS@%$GETGROUPLIST_ARGS%g
+s%@NET_R_ARGS@%$NET_R_ARGS%g
+s%@NET_R_BAD@%$NET_R_BAD%g
+s%@NET_R_COPY@%$NET_R_COPY%g
+s%@NET_R_COPY_ARGS@%$NET_R_COPY_ARGS%g
+s%@NET_R_OK@%$NET_R_OK%g
+s%@NET_R_RETURN@%$NET_R_RETURN%g
+s%@NET_R_ENT_ARGS@%$NET_R_ENT_ARGS%g
+s%@NET_R_SET_RESULT@%$NET_R_SET_RESULT%g
+s%@NET_R_SET_RETURN@%$NET_R_SET_RETURN%g
+s%@NET_R_END_RESULT@%$NET_R_END_RESULT%g
+s%@NET_R_END_RETURN@%$NET_R_END_RETURN%g
+s%@GROUP_R_ARGS@%$GROUP_R_ARGS%g
+s%@GROUP_R_BAD@%$GROUP_R_BAD%g
+s%@GROUP_R_OK@%$GROUP_R_OK%g
+s%@GROUP_R_RETURN@%$GROUP_R_RETURN%g
+s%@GROUP_R_END_RESULT@%$GROUP_R_END_RESULT%g
+s%@GROUP_R_END_RETURN@%$GROUP_R_END_RETURN%g
+s%@GROUP_R_ENT_ARGS@%$GROUP_R_ENT_ARGS%g
+s%@GROUP_R_SET_RESULT@%$GROUP_R_SET_RESULT%g
+s%@GROUP_R_SET_RETURN@%$GROUP_R_SET_RETURN%g
+s%@HOST_R_ARGS@%$HOST_R_ARGS%g
+s%@HOST_R_BAD@%$HOST_R_BAD%g
+s%@HOST_R_COPY@%$HOST_R_COPY%g
+s%@HOST_R_COPY_ARGS@%$HOST_R_COPY_ARGS%g
+s%@HOST_R_ERRNO@%$HOST_R_ERRNO%g
+s%@HOST_R_OK@%$HOST_R_OK%g
+s%@HOST_R_RETURN@%$HOST_R_RETURN%g
+s%@HOST_R_END_RESULT@%$HOST_R_END_RESULT%g
+s%@HOST_R_END_RETURN@%$HOST_R_END_RETURN%g
+s%@HOST_R_ENT_ARGS@%$HOST_R_ENT_ARGS%g
+s%@HOST_R_SET_RESULT@%$HOST_R_SET_RESULT%g
+s%@HOST_R_SET_RETURN@%$HOST_R_SET_RETURN%g
+s%@SETPWENT_VOID@%$SETPWENT_VOID%g
+s%@NGR_R_ARGS@%$NGR_R_ARGS%g
+s%@NGR_R_BAD@%$NGR_R_BAD%g
+s%@NGR_R_COPY@%$NGR_R_COPY%g
+s%@NGR_R_COPY_ARGS@%$NGR_R_COPY_ARGS%g
+s%@NGR_R_OK@%$NGR_R_OK%g
+s%@NGR_R_RETURN@%$NGR_R_RETURN%g
+s%@NGR_R_END_RESULT@%$NGR_R_END_RESULT%g
+s%@NGR_R_END_RETURN@%$NGR_R_END_RETURN%g
+s%@NGR_R_ENT_ARGS@%$NGR_R_ENT_ARGS%g
+s%@NGR_R_SET_RESULT@%$NGR_R_SET_RESULT%g
+s%@NGR_R_SET_RETURN@%$NGR_R_SET_RETURN%g
+s%@PROTO_R_ARGS@%$PROTO_R_ARGS%g
+s%@PROTO_R_BAD@%$PROTO_R_BAD%g
+s%@PROTO_R_COPY@%$PROTO_R_COPY%g
+s%@PROTO_R_COPY_ARGS@%$PROTO_R_COPY_ARGS%g
+s%@PROTO_R_OK@%$PROTO_R_OK%g
+s%@PROTO_R_RETURN@%$PROTO_R_RETURN%g
+s%@PROTO_R_END_RESULT@%$PROTO_R_END_RESULT%g
+s%@PROTO_R_END_RETURN@%$PROTO_R_END_RETURN%g
+s%@PROTO_R_ENT_ARGS@%$PROTO_R_ENT_ARGS%g
+s%@PROTO_R_SET_RESULT@%$PROTO_R_SET_RESULT%g
+s%@PROTO_R_SET_RETURN@%$PROTO_R_SET_RETURN%g
+s%@PASS_R_ARGS@%$PASS_R_ARGS%g
+s%@PASS_R_BAD@%$PASS_R_BAD%g
+s%@PASS_R_COPY@%$PASS_R_COPY%g
+s%@PASS_R_COPY_ARGS@%$PASS_R_COPY_ARGS%g
+s%@PASS_R_OK@%$PASS_R_OK%g
+s%@PASS_R_RETURN@%$PASS_R_RETURN%g
+s%@PASS_R_END_RESULT@%$PASS_R_END_RESULT%g
+s%@PASS_R_END_RETURN@%$PASS_R_END_RETURN%g
+s%@PASS_R_ENT_ARGS@%$PASS_R_ENT_ARGS%g
+s%@PASS_R_SET_RESULT@%$PASS_R_SET_RESULT%g
+s%@PASS_R_SET_RETURN@%$PASS_R_SET_RETURN%g
+s%@SERV_R_ARGS@%$SERV_R_ARGS%g
+s%@SERV_R_BAD@%$SERV_R_BAD%g
+s%@SERV_R_COPY@%$SERV_R_COPY%g
+s%@SERV_R_COPY_ARGS@%$SERV_R_COPY_ARGS%g
+s%@SERV_R_OK@%$SERV_R_OK%g
+s%@SERV_R_RETURN@%$SERV_R_RETURN%g
+s%@SERV_R_END_RESULT@%$SERV_R_END_RESULT%g
+s%@SERV_R_END_RETURN@%$SERV_R_END_RETURN%g
+s%@SERV_R_ENT_ARGS@%$SERV_R_ENT_ARGS%g
+s%@SERV_R_SET_RESULT@%$SERV_R_SET_RESULT%g
+s%@SERV_R_SET_RETURN@%$SERV_R_SET_RETURN%g
+s%@ISC_PLATFORM_BRACEPTHREADONCEINIT@%$ISC_PLATFORM_BRACEPTHREADONCEINIT%g
+s%@JADE@%$JADE%g
+s%@TEX@%$TEX%g
+s%@PDFTEX@%$PDFTEX%g
+s%@SGMLDIR@%$SGMLDIR%g
+s%@XMLDIR@%$XMLDIR%g
+s%@BIND9_TOP_BUILDDIR@%$BIND9_TOP_BUILDDIR%g
+s%@BIND9_ISC_BUILDINCLUDE@%$BIND9_ISC_BUILDINCLUDE%g
+s%@BIND9_ISCCFG_BUILDINCLUDE@%$BIND9_ISCCFG_BUILDINCLUDE%g
+s%@BIND9_DNS_BUILDINCLUDE@%$BIND9_DNS_BUILDINCLUDE%g
+s%@BIND9_OMAPI_BUILDINCLUDE@%$BIND9_OMAPI_BUILDINCLUDE%g
+s%@BIND9_LWRES_BUILDINCLUDE@%$BIND9_LWRES_BUILDINCLUDE%g
+/@BIND9_INCLUDES@/r $BIND9_INCLUDES
+s%@BIND9_INCLUDES@%%g
+/@BIND9_MAKE_RULES@/r $BIND9_MAKE_RULES
+s%@BIND9_MAKE_RULES@%%g
+s%@BIND9_VERSION@%$BIND9_VERSION%g
+/@LIBISC_API@/r $LIBISC_API
+s%@LIBISC_API@%%g
+/@LIBISCCFG_API@/r $LIBISCCFG_API
+s%@LIBISCCFG_API@%%g
+/@LIBDNS_API@/r $LIBDNS_API
+s%@LIBDNS_API@%%g
+/@LIBLWRES_API@/r $LIBLWRES_API
+s%@LIBLWRES_API@%%g
+/@LIBOMAPI_API@/r $LIBOMAPI_API
+s%@LIBOMAPI_API@%%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+  if test $ac_beg -gt 1; then
+    sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+  else
+    sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+  fi
+  if test ! -s conftest.s$ac_file; then
+    ac_more_lines=false
+    rm -f conftest.s$ac_file
+  else
+    if test -z "$ac_sed_cmds"; then
+      ac_sed_cmds="sed -f conftest.s$ac_file"
+    else
+      ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+    fi
+    ac_file=`expr $ac_file + 1`
+    ac_beg=$ac_end
+    ac_end=`expr $ac_end + $ac_max_sed_cmds`
+  fi
+done
+if test -z "$ac_sed_cmds"; then
+  ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"Makefile
+       bsd/Makefile
+       cylink/Makefile
+       dnssafe/Makefile
+       dst/Makefile
+       include/Makefile
+       inet/Makefile
+       irs/Makefile
+       isc/Makefile
+       nameser/Makefile
+       port_after.h
+       port_before.h
+       resolv/Makefile
+       make/rules
+       make/mkdep
+       make/includes
+"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+  # Remove last slash and all that follows it.  Not all systems have dirname.
+  ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+  if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+    # The file is in a subdirectory.
+    test ! -d "$ac_dir" && mkdir "$ac_dir"
+    ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+    # A "../" for each directory in $ac_dir_suffix.
+    ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+  else
+    ac_dir_suffix= ac_dots=
+  fi
+
+  case "$ac_given_srcdir" in
+  .)  srcdir=.
+      if test -z "$ac_dots"; then top_srcdir=.
+      else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+  /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+  *) # Relative path.
+    srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+    top_srcdir="$ac_dots$ac_given_srcdir" ;;
+  esac
+
+  case "$ac_given_INSTALL" in
+  [/$]*) INSTALL="$ac_given_INSTALL" ;;
+  *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+  esac
+
+  echo creating "$ac_file"
+  rm -f "$ac_file"
+  configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+  case "$ac_file" in
+  *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+  *) ac_comsub= ;;
+  esac
+
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([  ]*\)#\([        ]*define[       ][      ]*\)'
+ac_dB='\([     ][      ]*\)[^  ]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([  ]*\)#\([        ]*\)undef\([    ][      ]*\)'
+ac_uB='\([     ]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([  ]*\)#\([        ]*\)undef\([    ][      ]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+if test "${CONFIG_HEADERS+set}" != set; then
+EOF
+cat >> $CONFIG_STATUS <<EOF
+  CONFIG_HEADERS="config.h"
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+fi
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  echo creating $ac_file
+
+  rm -f conftest.frag conftest.in conftest.out
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  cat $ac_file_inputs > conftest.in
+
+EOF
+
+# Transform confdefs.h into a sed script conftest.vals that substitutes
+# the proper values into config.h.in to produce config.h.  And first:
+# Protect against being on the right side of a sed subst in config.status.
+# Protect against being in an unquoted here document in config.status.
+rm -f conftest.vals
+cat > conftest.hdr <<\EOF
+s/[\\&%]/\\&/g
+s%[\\$`]%\\&%g
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
+s%ac_d%ac_u%gp
+s%ac_u%ac_e%gp
+EOF
+sed -n -f conftest.hdr confdefs.h > conftest.vals
+rm -f conftest.hdr
+
+# This sed command replaces #undef with comments.  This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >> conftest.vals <<\EOF
+s%^[   ]*#[    ]*undef[        ][      ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+EOF
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+
+rm -f conftest.tail
+while :
+do
+  ac_lines=`grep -c . conftest.vals`
+  # grep -c gives empty output for an empty file on some AIX systems.
+  if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+  # Write a limited-size here document to conftest.frag.
+  echo '  cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
+  sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
+  echo 'CEOF
+  sed -f conftest.frag conftest.in > conftest.out
+  rm -f conftest.in
+  mv conftest.out conftest.in
+' >> $CONFIG_STATUS
+  sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+  rm -f conftest.vals
+  mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+cat >> $CONFIG_STATUS <<\EOF
+  rm -f conftest.frag conftest.h
+  echo "/* $ac_file.  Generated automatically by configure.  */" > conftest.h
+  cat conftest.in >> conftest.h
+  rm -f conftest.in
+  if cmp -s $ac_file conftest.h 2>/dev/null; then
+    echo "$ac_file is unchanged"
+    rm -f conftest.h
+  else
+    # Remove last slash and all that follows it.  Not all systems have dirname.
+      ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+      if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+      # The file is in a subdirectory.
+      test ! -d "$ac_dir" && mkdir "$ac_dir"
+    fi
+    rm -f $ac_file
+    mv conftest.h $ac_file
+  fi
+fi; done
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
+
+# Tell Emacs to edit this file in shell mode.
+# Local Variables:
+# mode: sh
+# End:
diff --git a/lib/bind/configure.in b/lib/bind/configure.in
new file mode 100644 (file)
index 0000000..450d8a4
--- /dev/null
@@ -0,0 +1,1821 @@
+# Copyright (C) 1998-2001  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.
+
+dnl
+AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)dnl
+esyscmd([sed "s/^/# /" COPYRIGHT])dnl
+AC_DIVERT_POP()dnl
+
+AC_REVISION($Revision: 1.1 $)
+
+AC_INIT(resolv/herror.c)
+AC_PREREQ(2.13)
+
+AC_CONFIG_HEADER(config.h)
+
+AC_CANONICAL_HOST
+
+AC_PROG_MAKE_SET
+AC_PROG_RANLIB
+AC_PROG_INSTALL
+
+AC_SUBST(STD_CINCLUDES)
+AC_SUBST(STD_CDEFINES)
+AC_SUBST(STD_CWARNINGS)
+AC_SUBST(CCOPT)
+
+AC_PATH_PROG(AR, ar)
+ARFLAGS="cruv"
+AC_SUBST(AR)
+AC_SUBST(ARFLAGS)
+
+# The POSIX ln(1) program.  Non-POSIX systems may substitute
+# "copy" or something.
+LN=ln
+AC_SUBST(LN)
+
+case "$AR" in
+       "")
+               AC_MSG_ERROR([
+ar program not found.  Please fix your PATH to include the directory in
+which ar resides, or set AR in the environment with the full path to ar.
+])
+
+               ;;
+esac
+
+#
+# Etags.
+#
+AC_PATH_PROGS(ETAGS, etags emacs-etags)
+
+#
+# Some systems, e.g. RH7, have the Exuberant Ctags etags instead of
+# GNU emacs etags, and it requires the -L flag.
+#
+if test "X$ETAGS" != "X"; then
+       AC_MSG_CHECKING(for Exuberant Ctags etags)
+       if $ETAGS --version 2>&1 | grep 'Exuberant Ctags' >/dev/null 2>&1; then
+               AC_MSG_RESULT(yes)
+               ETAGS="$ETAGS -L"
+       else
+               AC_MSG_RESULT(no)
+       fi
+fi
+AC_SUBST(ETAGS)
+
+#
+# Perl is optional; it is used only by some of the system test scripts.
+#
+AC_PATH_PROGS(PERL, perl5 perl)
+AC_SUBST(PERL)
+
+#
+# Special processing of paths depending on whether --prefix,
+# --sysconfdir or --localstatedir arguments were given.  What's
+# desired is some compatability with the way previous versions
+# of BIND built; they defaulted to /usr/local for most parts of
+# the installation, but named.boot/named.conf was in /etc
+# and named.pid was in /var/run.
+#
+# So ... if none of --prefix, --sysconfdir or --localstatedir are
+# specified, set things up that way.  If --prefix is given, use
+# it for sysconfdir and localstatedir the way configure normally
+# would.  To change the prefix for everything but leave named.conf
+# in /etc or named.pid in /var/run, then do this the usual configure way:
+# ./configure --prefix=/somewhere --sysconfdir=/etc
+# ./configure --prefix=/somewhere --localstatedir=/var
+#
+# To put named.conf and named.pid in /usr/local with everything else,
+# set the prefix explicitly to /usr/local even though that's the default:
+# ./configure --prefix=/usr/local
+#
+case "$prefix" in
+        NONE)
+                case "$sysconfdir" in
+                        '${prefix}/etc')
+                                sysconfdir=/etc
+                                ;;
+                esac
+                case "$localstatedir" in
+                        '${prefix}/var')
+                                localstatedir=/var
+                                ;;
+                esac
+                ;;
+esac
+
+#
+# Make sure INSTALL uses an absolute path, else it will be wrong in all
+# Makefiles, since they use make/rules.in and INSTALL will be adjusted by
+# configure based on the location of the file where it is substituted.
+# Since in BIND9 INSTALL is only substituted into make/rules.in, an immediate
+# subdirectory of install-sh, This relative path will be wrong for all
+# directories more than one level down from install-sh.
+#
+case "$INSTALL" in
+       /*)
+                ;;
+        *)
+                #
+                # Not all systems have dirname.
+                #
+                changequote({, })
+                ac_dir="`echo $INSTALL | sed 's%/[^/]*$%%'`"
+                changequote([, ])
+
+                ac_prog="`echo $INSTALL | sed 's%.*/%%'`"
+                test "$ac_dir" = "$ac_prog" && ac_dir=.
+                test -d "$ac_dir" && ac_dir="`(cd \"$ac_dir\" && pwd)`"
+                INSTALL="$ac_dir/$ac_prog"
+                ;;
+esac
+
+#
+# On these hosts, we really want to use cc, not gcc, even if it is
+# found.  The gcc that these systems have will not correctly handle
+# pthreads.
+#
+# However, if the user sets $CC to be something, let that override
+# our change.
+#
+if test "X$CC" = "X" ; then
+       case "$host" in
+               *-dec-osf*)
+                       CC="cc"
+                       ;;
+               *-solaris*)
+                        # Use Sun's cc if it is available, but watch
+                        # out for /usr/ucb/cc; it will never be the right
+                        # compiler to use.
+                        #
+                        # If setting CC here fails, the AC_PROG_CC done
+                        # below might still find gcc.
+                       IFS="${IFS=     }"; ac_save_ifs="$IFS"; IFS=":"
+                       for ac_dir in $PATH; do
+                               test -z "$ac_dir" && ac_dir=.
+                               case "$ac_dir" in
+                               /usr/ucb)
+                                       # exclude
+                                       ;;
+                               *)
+                                       if test -f "$ac_dir/cc"; then
+                                               CC="$ac_dir/cc"
+                                               break
+                                       fi
+                                       ;;
+                               esac
+                       done
+                       IFS="$ac_save_ifs"
+                       ;;
+               *-hp-hpux*)
+                       CC="cc"
+                       ;;
+               mips-sgi-irix*)
+                       CC="cc"
+                       ;;
+       esac
+fi
+
+
+AC_PROG_CC
+
+AC_HEADER_STDC
+
+
+AC_CHECK_HEADERS(fcntl.h sys/time.h unistd.h sys/sockio.h sys/select.h)
+
+AC_C_CONST
+AC_C_INLINE
+AC_TYPE_SIZE_T
+AC_HEADER_TIME
+AC_MSG_CHECKING(for long long)
+AC_TRY_COMPILE([],[long long i = 0; return (0);],
+       [AC_MSG_RESULT(yes)
+               ISC_PLATFORM_HAVELONGLONG="#define ISC_PLATFORM_HAVELONGLONG 1"],
+       [AC_MSG_RESULT(no)
+               ISC_PLATFORM_HAVELONGLONG="#undef ISC_PLATFORM_HAVELONGLONG"])
+AC_SUBST(ISC_PLATFORM_HAVELONGLONG)
+
+#
+# check if we need to #include sys/select.h explicitly
+#
+case $ac_cv_header_unistd_h in
+yes)
+AC_MSG_CHECKING(if unistd.h defines fd_set)
+AC_TRY_COMPILE([
+#include <unistd.h>],
+[fd_set read_set; return (0);],
+       [AC_MSG_RESULT(yes)
+        ISC_PLATFORM_NEEDSYSSELECTH="#undef ISC_PLATFORM_NEEDSYSSELECTH"
+        LWRES_PLATFORM_NEEDSYSSELECTH="#undef LWRES_PLATFORM_NEEDSYSSELECTH"],
+       [AC_MSG_RESULT(no)
+       case ac_cv_header_sys_select_h in
+       yes)
+         ISC_PLATFORM_NEEDSYSSELECTH="#define ISC_PLATFORM_NEEDSYSSELECTH 1"
+        LWRES_PLATFORM_NEEDSYSSELECTH="#define LWRES_PLATFORM_NEEDSYSSELECTH 1"
+               ;;
+       no)
+               AC_MSG_ERROR([need either working unistd.h or sys/select.h])
+               ;;
+       esac
+       ])
+       ;;
+no)
+       case ac_cv_header_sys_select_h in
+       yes)
+             ISC_PLATFORM_NEEDSYSSELECTH="#define ISC_PLATFORM_NEEDSYSSELECTH 1"
+            LWRES_PLATFORM_NEEDSYSSELECTH="#define LWRES_PLATFORM_NEEDSYSSELECTH 1"
+               ;;
+       no)
+               AC_MSG_ERROR([need either unistd.h or sys/select.h])
+               ;;
+       esac
+       ;;
+esac
+AC_SUBST(ISC_PLATFORM_NEEDSYSSELECTH)
+AC_SUBST(LWRES_PLATFORM_NEEDSYSSELECTH)
+
+#
+# Find the machine's endian flavor.
+#
+AC_C_BIGENDIAN
+
+AC_ARG_WITH(irs-gr,[ --with-irs-gr             Build ....],
+want_irs_gr="$withval", want_irs_gr="no")
+case "$want_irs_gr" in
+yes) WANT_IRS_GR="#define WANT_IRS_GR 1"
+     WANT_IRS_GR_OBJS="\${WANT_IRS_GR_OBJS}"
+       ;;
+*) WANT_IRS_GR="#undef WANT_IRS_GR" WANT_IRS_GR_OBJS="";;
+esac
+AC_SUBST(WANT_IRS_GR)
+AC_SUBST(WANT_IRS_GR_OBJS)
+
+AC_ARG_WITH(irs-pw,[ --with-irs-pw             Build ....],
+want_irs_pw="$withval", want_irs_pw="no")
+case "$want_irs_pw" in
+yes) WANT_IRS_PW="#define WANT_IRS_PW 1"
+     WANT_IRS_PW_OBJS="\${WANT_IRS_PW_OBJS}";;
+*) WANT_IRS_PW="#undef WANT_IRS_PW" WANT_IRS_PW_OBJS="";;
+esac
+AC_SUBST(WANT_IRS_PW)
+AC_SUBST(WANT_IRS_PW_OBJS)
+
+AC_ARG_WITH(irs-nis,[ --with-irs-nis           Build ....],
+want_irs_nis="$withval", want_irs_nis="no")
+case "$want_irs_nis" in
+yes)
+       WANT_IRS_NIS="#define WANT_IRS_NIS 1"
+       WANT_IRS_NIS_OBJS="WANT_IRS_NIS_OBJS"
+       case "$want_irs_gr" in
+       yes)
+               WANT_IRS_NISGR_OBJS="\${WANT_IRS_NISGR_OBJS}";;
+       *)
+               WANT_IRS_NISGR_OBJS="";;
+       esac
+       case "$want_irs_pw" in
+       yes)
+               WANT_IRS_NISPW_OBJS="\${WANT_IRS_NISPW_OBJS}";;
+       *)
+               WANT_IRS_NISPW_OBJS="";;
+       esac
+       ;;
+*)
+       WANT_IRS_NIS="#undef WANT_IRS_NIS"
+       WANT_IRS_NIS_OBJS=""
+       WANT_IRS_NISGR_OBJS=""
+       WANT_IRS_NISPW_OBJS="";;
+esac
+AC_SUBST(WANT_IRS_NIS)
+AC_SUBST(WANT_IRS_NIS_OBJS)
+AC_SUBST(WANT_IRS_NISGR_OBJS)
+AC_SUBST(WANT_IRS_NISPW_OBJS)
+
+#
+# was --with-openssl specified?
+#
+AC_MSG_CHECKING(for compatible OpenSSL library)
+AC_ARG_WITH(openssl,
+[  --with-openssl=PATH  Specify path for system-supplied openssl
+                        (rather than using bind-9 internal openssl)],
+    use_openssl="$withval", use_openssl="no")
+
+#
+# If the user didn't specify where openssl is, and we didn't find or it
+# is incompatible with our code, use our internal one.
+#
+# XXX This appears to assume that the user specified path is correct,
+# and does no checking.
+#
+
+case "$use_openssl" in
+       no)
+               DST_PRIVATEOPENSSL='-DDST_USE_PRIVATE_OPENSSL'
+               dst_privateopenssl='openssl'
+               DST_OPENSSL_INC='-I${srcdir}/../openssl/include'
+               DST_OPENSSL_LIB=''
+               DST_OPENSSL_OBJS='${OPENSSLOBJS}'
+               AC_MSG_RESULT(using private library)
+               openssl_makefiles="lib/dns/sec/openssl/Makefile \
+                                  lib/dns/sec/openssl/include/Makefile \
+                                  lib/dns/sec/openssl/include/openssl/Makefile"
+
+               ;;
+       yes)
+               AC_MSG_ERROR([--with-openssl must specify a path])
+               ;;
+       *)
+               DST_PRIVATEOPENSSL=''
+               dst_privateopenssl=''
+               DST_OPENSSL_INC="-I$use_openssl/include"
+               DNS_OPENSSL_LIBS="-L$use_openssl/lib -lcrypto"
+               DST_OPENSSL_LIB=''
+               AC_MSG_RESULT(using openssl from $use_openssl/lib and $use_openssl/include)
+               openssl_makefiles=""
+               ;;
+esac
+
+AC_SUBST(DST_PRIVATEOPENSSL)
+AC_SUBST(dst_privateopenssl)
+AC_SUBST(DST_OPENSSL_INC)
+AC_SUBST(DST_OPENSSL_LIB)
+AC_SUBST(DST_OPENSSL_OBJS)
+
+#
+# This would include the system openssl path (and linker options to use
+# it as needed) if it is found.
+#
+
+AC_SUBST(DNS_OPENSSL_LIBS)
+
+#
+# was --with-gssapi specified?
+#
+#AC_MSG_CHECKING(for GSSAPI library)
+#AC_ARG_WITH(gssapi,
+#[  --with-gssapi=PATH   Specify path for system-supplied GSSAPI],
+#    use_gssapi="$withval", use_gssapi="no")
+#
+#case "$use_gssapi" in
+#      no)
+#              USE_GSSAPI=''
+#              DST_GSSAPI_INC=''
+#              DNS_GSSAPI_LIBS=''
+#              AC_MSG_RESULT(not specified)
+#              ;;
+#      yes)
+#              AC_MSG_ERROR([--with-gssapi must specify a path])
+#              ;;
+#      *)
+#              USE_GSSAPI='-DGSSAPI'
+#              DST_GSSAPI_INC="-I$use_gssapi/include"
+#              DNS_GSSAPI_LIBS="-L$use_gssapi/lib -lgssapi_krb5"
+#              AC_MSG_RESULT(using gssapi from $use_gssapi/lib and $use_gssapi/include)
+#              ;;
+#esac
+
+USE_GSSAPI=''
+DST_GSSAPI_INC=''
+DNS_GSSAPI_LIBS=''
+
+AC_SUBST(USE_GSSAPI)
+AC_SUBST(DST_GSSAPI_INC)
+AC_SUBST(DNS_GSSAPI_LIBS)
+
+#
+# was --with-randomdev specified?
+#
+AC_MSG_CHECKING(for random device)
+AC_ARG_WITH(randomdev,
+[  --with-randomdev=PATH Specify path for random device],
+    use_randomdev="$withval", use_randomdev="unspec")
+
+case "$use_randomdev" in
+       unspec)
+               case "$host" in
+                       *-openbsd*)
+                               devrandom=/dev/srandom
+                               ;;
+                       *)
+                               devrandom=/dev/random
+                               ;;
+               esac
+               AC_CHECK_FILE($devrandom,
+                             AC_DEFINE_UNQUOTED(PATH_RANDOMDEV,
+                                                "$devrandom"),)
+               ;;
+       yes)
+               AC_MSG_ERROR([--with-randomdev must specify a path])
+               ;;
+       *)
+               AC_DEFINE_UNQUOTED(PATH_RANDOMDEV, "$use_randomdev")
+               AC_MSG_RESULT(using "$use_randomdev")
+               ;;
+esac
+
+#
+# Begin pthreads checking.
+#
+# First, decide whether to use multithreading or not.
+#
+AC_MSG_CHECKING(whether to look for thread support)
+AC_ARG_ENABLE(threads,
+       [  --disable-threads    disable multithreading])
+case "$enable_threads" in
+       yes|'')
+               AC_MSG_RESULT(yes)
+               use_threads=true
+               ;;
+       no)
+               AC_MSG_RESULT(no)       
+               use_threads=false
+               ;;
+       *)
+               AC_MSG_ERROR([--enable-threads takes yes or no])
+               ;;
+esac
+
+if $use_threads
+then
+       #
+       # Search for / configure pthreads in a system-dependent fashion.
+       #
+       case "$host" in
+         *-netbsd*)
+               # NetBSD has multiple pthreads implementations.  The
+               # recommended one to use is "unproven-pthreads".  The
+               # older "mit-pthreads" may also work on some NetBSD
+               # versions.  The PTL2 thread library does not
+               # currently work with bind9, but can be chosen with
+               # the --with-ptl2 option for those who wish to
+               # experiment with it.
+               CC="gcc"
+               AC_MSG_CHECKING(which NetBSD thread library to use)
+
+               AC_ARG_WITH(ptl2,
+[  --with-ptl2         on NetBSD, use the ptl2 thread library (experimental)],
+                   use_ptl2="$withval", use_ptl2="no")
+
+               : ${LOCALBASE:=/usr/pkg}
+
+               if test "X$use_ptl2" = "Xyes"
+               then
+                       AC_MSG_RESULT(PTL2)
+                       AC_MSG_WARN(
+[linking with PTL2 is highly experimental and not expected to work])
+                       CC=ptlgcc
+               else
+                       if test ! -d $LOCALBASE/pthreads
+                       then
+                               AC_MSG_RESULT(none)
+                               use_threads=false
+                       fi
+
+                       if $use_threads
+                       then
+                               AC_MSG_RESULT(mit-pthreads/unproven-pthreads)
+                               pkg="$LOCALBASE/pthreads"
+                               lib1="-L$pkg/lib -Wl,-R$pkg/lib"
+                               lib2="-lpthread -lm -lgcc -lpthread"
+                               LIBS="$lib1 $lib2 $LIBS"
+                               CPPFLAGS="$CPPFLAGS -I$pkg/include"
+                               STD_CINCLUDES="$STD_CINCLUDES -I$pkg/include"
+                       fi
+               fi
+               ;;
+               *)
+                       AC_CHECK_LIB(pthread, pthread_create,,
+                               AC_CHECK_LIB(pthread, __pthread_create,,
+                               AC_CHECK_LIB(pthread, __pthread_create_system,,
+                               AC_CHECK_LIB(c_r, pthread_create,,
+                               AC_CHECK_LIB(c, pthread_create,,
+                               use_threads=false)))))
+               ;;
+       esac
+fi
+
+if $use_threads
+then
+       #
+       # We'd like to use sigwait() too
+       #
+       AC_CHECK_LIB(c, sigwait,
+                    AC_DEFINE(HAVE_SIGWAIT),
+                    AC_CHECK_LIB(pthread, sigwait,
+                                 AC_DEFINE(HAVE_SIGWAIT),
+                                 AC_CHECK_LIB(pthread, _Psigwait,
+                                              AC_DEFINE(HAVE_SIGWAIT),))
+       )
+
+       AC_CHECK_FUNC(pthread_attr_getstacksize,
+                     AC_DEFINE(HAVE_PTHREAD_ATTR_GETSTACKSIZE),)
+
+       #
+       # Additional OS-specific issues related to pthreads and sigwait.
+       #
+       case "$host" in
+               #
+               # One more place to look for sigwait.
+               #
+               *-freebsd*)
+                       AC_CHECK_LIB(c_r, sigwait, AC_DEFINE(HAVE_SIGWAIT),)
+                       ;;
+               #
+               # BSDI 3.0 through 4.0.1 needs pthread_init() to be
+               # called before certain pthreads calls.  This is deprecated
+               # in BSD/OS 4.1.
+               #
+               *-bsdi3.*|*-bsdi4.0*)
+                       AC_DEFINE(NEED_PTHREAD_INIT)
+                       ;;
+               #
+               # LinuxThreads requires some changes to the way we
+               # deal with signals.
+               #
+               *-linux*)
+                       AC_DEFINE(HAVE_LINUXTHREADS)
+                       ;;
+               #
+               # Ensure the right sigwait() semantics on Solaris and make
+               # sure we call pthread_setconcurrency.
+               #
+               *-solaris*)
+                       AC_DEFINE(_POSIX_PTHREAD_SEMANTICS)
+                       AC_CHECK_FUNC(pthread_setconcurrency,
+                                     AC_DEFINE(CALL_PTHREAD_SETCONCURRENCY))
+                       ;;
+               #
+               # UnixWare does things its own way.
+               #
+               *-UnixWare*)
+                       AC_DEFINE(HAVE_UNIXWARE_SIGWAIT)
+                       ;;
+       esac
+
+       #
+       # Look for sysconf to allow detection of the number of processors.
+       #
+       AC_CHECK_FUNC(sysconf, AC_DEFINE(HAVE_SYSCONF),)
+
+       if test "X$GCC" = "Xyes"; then
+               case "$host" in
+               *-freebsd*)
+                       CC="$CC -pthread"
+                       CCOPT="$CCOPT -pthread"
+                       STD_CDEFINES="$STD_CDEFINES -D_THREAD_SAFE"
+                       ;;
+               *-openbsd*)
+                       CC="$CC -pthread"
+                       CCOPT="$CCOPT -pthread"
+                       ;;
+               *-solaris*)
+                       LIBS="$LIBS -lthread"
+                       ;;
+               *-ibm-aix*)
+                       STD_CDEFINES="$STD_CDEFINES -D_THREAD_SAFE"
+                       ;;
+               esac
+       else
+               case $host in
+               *-dec-osf*)
+                       CC="$CC -pthread"
+                       CCOPT="$CCOPT -pthread"
+                       ;;
+               *-solaris*)
+                       CC="$CC -mt"
+                       CCOPT="$CCOPT -mt"
+                       ;;
+               *-ibm-aix*)
+                       STD_CDEFINES="$STD_CDEFINES -D_THREAD_SAFE"
+                       ;;
+               *-UnixWare*)
+                       CC="$CC -Kthread"
+                       CCOPT="$CCOPT -Kthread"
+                       ;;
+               esac
+       fi
+       ALWAYS_DEFINES="-D_REENTRANT"
+       DO_PTHREADS="#define DO_PTHREADS 1"
+       WANT_IRS_THREADSGR_OBJS="\${WANT_IRS_THREADSGR_OBJS}"
+       WANT_IRS_THREADSPW_OBJS="\${WANT_IRS_THREADSPW_OBJS}"
+       WANT_IRS_THREADS_OBJS="\${WANT_IRS_THREADS_OBJS}"
+       thread_dir=pthreads
+else
+       ALWAYS_DEFINES=""
+       DO_PTHREADS="#undef DO_PTHREADS"
+       WANT_IRS_THREADSGR_OBJS=""
+       WANT_IRS_THREADSPW_OBJS=""
+       WANT_IRS_THREADS_OBJS=""
+       thread_dir=nothreads
+fi
+
+AC_SUBST(ALWAYS_DEFINES)
+AC_SUBST(DO_PTHREADS)
+AC_SUBST(WANT_IRS_THREADSGR_OBJS)
+AC_SUBST(WANT_IRS_THREADSPW_OBJS)
+AC_SUBST(WANT_IRS_THREADS_OBJS)
+
+ISC_THREAD_DIR=$thread_dir
+AC_SUBST(ISC_THREAD_DIR)
+
+#
+# flockfile is usually provided by pthreads, but we may want to use it
+# even if compiled with --disable-threads.
+#
+AC_CHECK_FUNC(flockfile, AC_DEFINE(HAVE_FLOCKFILE),)
+
+# 
+# Indicate what the final decision was regarding threads.
+#
+AC_MSG_CHECKING(whether to build with threads)
+if $use_threads; then
+       AC_MSG_RESULT(yes)
+else
+       AC_MSG_RESULT(no)
+fi
+
+# 
+# End of pthreads stuff.
+#
+
+#
+# Additional compiler settings.
+#
+MKDEPCC="$CC"
+MKDEPCFLAGS="-M"
+IRIX_DNSSEC_WARNINGS_HACK=""
+
+if test "X$GCC" = "Xyes"; then
+       STD_CWARNINGS="$STD_CWARNINGS -W -Wall -Wmissing-prototypes -Wcast-qual -Wwrite-strings"
+else
+       case $host in
+       *-dec-osf*)
+               CC="$CC -std"
+               CCOPT="$CCOPT -std"
+               MKDEPCC="$CC"
+               ;;
+       *-hp-hpux*)
+               CC="$CC -Ae -z"
+               # The version of the C compiler that constantly warns about
+                # 'const' as well as alignment issues is unfortunately not
+                # able to be discerned via the version of the operating
+                # system, nor does cc have a version flag.
+               case "`$CC +W 123 2>&1`" in
+               *Unknown?option*)
+                       STD_CWARNINGS="+w1"
+                       ;;
+               *)
+                       # Turn off the pointlessly noisy warnings.
+                       STD_CWARNINGS="+w1 +W 474,530"
+                       ;;
+               esac
+               CCOPT="$CCOPT -Ae -z"
+               LIBS="-Wl,+vnocompatwarnings $LIBS"
+               MKDEPPROG='cc -Ae -E -Wp,-M >/dev/null 2>>$TMP'
+               ;;
+       *-sgi-irix*)
+               STD_CWARNINGS="-fullwarn -woff 1209"
+               #
+               # Silence more than 250 instances of
+               #   "prototyped function redeclared without prototype"
+               # and 11 instances of
+               #   "variable ... was set but never used"
+               # from lib/dns/sec/openssl.
+               #
+               IRIX_DNSSEC_WARNINGS_HACK="-woff 1692,1552"
+               ;;
+       *-solaris*)
+               MKDEPCFLAGS="-xM"
+               ;;
+       *-UnixWare*)
+               CC="$CC -w"
+               ;;
+       esac
+fi
+
+AC_SUBST(MKDEPCC)
+AC_SUBST(MKDEPCFLAGS)
+AC_SUBST(MKDEPPROG)
+AC_SUBST(IRIX_DNSSEC_WARNINGS_HACK)
+
+#
+# NLS
+#
+AC_CHECK_FUNC(catgets, AC_DEFINE(HAVE_CATGETS),)
+
+#
+# -lxnet buys us one big porting headache...  standards, gotta love 'em.
+#
+# AC_CHECK_LIB(xnet, socket, ,
+#    AC_CHECK_LIB(socket, socket)
+#    AC_CHECK_LIB(nsl, inet_ntoa)
+# )
+#
+# Use this for now, instead:
+#
+case "$host" in
+       mips-sgi-irix*)
+               ;;
+       *)
+               AC_CHECK_LIB(socket, socket)
+               AC_CHECK_LIB(nsl, inet_ntoa)
+               ;;
+esac
+
+#
+# Purify support
+#
+AC_MSG_CHECKING(whether to use purify)
+AC_ARG_WITH(purify,
+       [  --with-purify[=PATH] use Rational purify],
+       use_purify="$withval", use_purify="no")
+
+case "$use_purify" in
+       no)
+               ;;
+       yes)
+               AC_PATH_PROG(purify_path, purify, purify)
+               ;;
+       *)
+               purify_path="$use_purify"
+               ;;
+esac
+
+case "$use_purify" in
+       no)
+               AC_MSG_RESULT(no)
+               PURIFY=""
+               ;;
+       *)
+               if test -f $purify_path || test $purify_path = purify; then
+                       AC_MSG_RESULT($purify_path)
+                       PURIFYFLAGS="`echo $PURIFYOPTIONS`"
+                       PURIFY="$purify_path $PURIFYFLAGS"
+               else
+                       AC_MSG_ERROR([$purify_path not found.
+
+Please choose the proper path with the following command:
+
+    configure --with-purify=PATH
+])
+               fi
+               ;;
+esac
+
+AC_SUBST(PURIFY)
+
+#
+# GNU libtool support
+#
+AC_ARG_WITH(libtool,
+           [  --with-libtool   use GNU libtool (following indented options supported)],
+           use_libtool="$withval", use_libtool="no")
+
+case $use_libtool in
+       yes)
+               AM_PROG_LIBTOOL
+               O=lo
+               A=la
+               ;;
+       *)
+               O=o
+               A=a
+               LIBTOOL=
+               AC_SUBST(LIBTOOL)
+               ;;
+esac
+
+#
+# File name extension for static archive files, for those few places
+# where they are treated differently from dynamic ones.
+#
+SA=a
+
+AC_SUBST(O)
+AC_SUBST(A)
+AC_SUBST(SA)
+
+#
+# Here begins a very long section to determine the system's networking
+# capabilities.  The order of the tests is signficant.
+#
+
+#
+# IPv6
+#
+AC_ARG_ENABLE(ipv6,
+       [  --enable-ipv6                use IPv6 [default=autodetect]])
+
+case "$enable_ipv6" in
+       yes|''|autodetect)
+               AC_DEFINE(WANT_IPV6)
+               ;;
+       no)
+               ;;
+esac
+
+#
+# We do the IPv6 compilation checking after libtool so that we can put
+# the right suffix on the files.
+#
+AC_MSG_CHECKING(for IPv6 structures)
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>],
+[struct sockaddr_in6 sin6; return (0);],
+       [AC_MSG_RESULT(yes)
+        found_ipv6=yes],
+       [AC_MSG_RESULT(no)
+        found_ipv6=no])
+
+#
+# See whether IPv6 support is provided via a Kame add-on.
+# This is done before other IPv6 linking tests to LIBS is properly set.
+#
+AC_MSG_CHECKING(for Kame IPv6 support)
+AC_ARG_WITH(kame,
+       [  --with-kame[=PATH]   use Kame IPv6 [default path /usr/local/v6]],
+       use_kame="$withval", use_kame="no")
+
+case "$use_kame" in
+       no)
+               ;;
+       yes)
+               kame_path=/usr/local/v6
+               ;;
+       *)
+               kame_path="$use_kame"
+               ;;
+esac
+
+case "$use_kame" in
+       no)
+               AC_MSG_RESULT(no)
+               ;;
+       *)
+               if test -f $kame_path/lib/libinet6.a; then
+                       AC_MSG_RESULT($kame_path/lib/libinet6.a)
+                       LIBS="-L$kame_path/lib -linet6 $LIBS"
+               else
+                       AC_MSG_ERROR([$kame_path/lib/libinet6.a not found.
+
+Please choose the proper path with the following command:
+
+    configure --with-kame=PATH
+])
+               fi
+               ;;
+esac
+
+#
+# Whether netinet6/in6.h is needed has to be defined in isc/platform.h.
+# Including it on Kame-using platforms is very bad, though, because
+# Kame uses #error against direct inclusion.   So include it on only
+# the platform that is otherwise broken without it -- BSD/OS 4.0 through 4.1.
+# This is done before the in6_pktinfo check because that's what
+# netinet6/in6.h is needed for.
+#
+changequote({, })
+case "$host" in
+*-bsdi4.[01]*)
+       ISC_PLATFORM_NEEDNETINET6IN6H="#define ISC_PLATFORM_NEEDNETINET6IN6H 1"
+       LWRES_PLATFORM_NEEDNETINET6IN6H="#define LWRES_PLATFORM_NEEDNETINET6IN6H 1"
+       isc_netinet6in6_hack="#include <netinet6/in6.h>"
+       ;;
+*)
+       ISC_PLATFORM_NEEDNETINET6IN6H="#undef ISC_PLATFORM_NEEDNETINET6IN6H"
+       LWRES_PLATFORM_NEEDNETINET6IN6H="#undef LWRES_PLATFORM_NEEDNETINET6IN6H"
+       isc_netinet6in6_hack=""
+       ;;
+esac
+changequote([, ])
+
+#
+# This is similar to the netinet6/in6.h issue.
+#
+case "$host" in
+*-UnixWare*)
+       ISC_PLATFORM_NEEDNETINETIN6H="#define ISC_PLATFORM_NEEDNETINETIN6H 1"
+       LWRES_PLATFORM_NEEDNETINETIN6H="#define LWRES_PLATFORM_NEEDNETINETIN6H 1"
+        ISC_PLATFORM_FIXIN6ISADDR="#define ISC_PLATFORM_FIXIN6ISADDR 1"
+       isc_netinetin6_hack="#include <netinet/in6.h>"
+       ;;
+*)
+       ISC_PLATFORM_NEEDNETINETIN6H="#undef ISC_PLATFORM_NEEDNETINETIN6H"
+       LWRES_PLATFORM_NEEDNETINETIN6H="#undef LWRES_PLATFORM_NEEDNETINETIN6H"
+        ISC_PLATFORM_FIXIN6ISADDR="#undef ISC_PLATFORM_FIXIN6ISADDR"
+       isc_netinetin6_hack=""
+       ;;
+esac
+
+#
+# Now delve deeper into the suitability of the IPv6 support.
+#
+case "$found_ipv6" in
+       yes)
+               ISC_PLATFORM_HAVEIPV6="#define ISC_PLATFORM_HAVEIPV6 1"
+               LWRES_PLATFORM_HAVEIPV6="#define LWRES_PLATFORM_HAVEIPV6 1"
+
+               AC_MSG_CHECKING(for in6_addr)
+               AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+$isc_netinetin6_hack
+$isc_netinet6in6_hack
+],
+[struct in6_addr in6; return (0);],
+               [AC_MSG_RESULT(yes)
+                ISC_PLATFORM_HAVEINADDR6="#undef ISC_PLATFORM_HAVEINADDR6"
+                LWRES_PLATFORM_HAVEINADDR6="#undef LWRES_PLATFORM_HAVEINADDR6"
+                isc_in_addr6_hack=""],
+               [AC_MSG_RESULT(no)
+                ISC_PLATFORM_HAVEINADDR6="#define ISC_PLATFORM_HAVEINADDR6 1"
+                LWRES_PLATFORM_HAVEINADDR6="#define LWRES_PLATFORM_HAVEINADDR6 1"
+                isc_in_addr6_hack="#define in6_addr in_addr6"])
+
+               AC_MSG_CHECKING(for in6addr_any)
+               AC_TRY_LINK([
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+$isc_netinetin6_hack
+$isc_netinet6in6_hack
+$isc_in_addr6_hack
+],
+               [struct in6_addr in6; in6 = in6addr_any; return (0);],
+                       [AC_MSG_RESULT(yes)
+                        ISC_PLATFORM_NEEDIN6ADDRANY="#undef ISC_PLATFORM_NEEDIN6ADDRANY"
+                        LWRES_PLATFORM_NEEDIN6ADDRANY="#undef LWRES_PLATFORM_NEEDIN6ADDRANY"],
+                       [AC_MSG_RESULT(no)
+                        ISC_PLATFORM_NEEDIN6ADDRANY="#define ISC_PLATFORM_NEEDIN6ADDRANY 1"
+                        LWRES_PLATFORM_NEEDIN6ADDRANY="#define LWRES_PLATFORM_NEEDIN6ADDRANY 1"])
+
+               AC_MSG_CHECKING(for sin6_scope_id in struct sockaddr_in6)
+               AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+$isc_netinetin6_hack
+$isc_netinet6in6_hack
+],
+               [struct sockaddr_in6 xyzzy; xyzzy.sin6_scope_id = 0; return (0);],
+                       [AC_MSG_RESULT(yes)
+                        result="#define LWRES_HAVE_SIN6_SCOPE_ID 1"],
+                       [AC_MSG_RESULT(no)
+                        result="#undef LWRES_HAVE_SIN6_SCOPE_ID"])
+               LWRES_HAVE_SIN6_SCOPE_ID="$result"
+
+               AC_MSG_CHECKING(for in6_pktinfo)
+               AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+$isc_netinetin6_hack
+$isc_netinet6in6_hack
+],
+               [struct in6_pktinfo xyzzy; return (0);],
+                       [AC_MSG_RESULT(yes)
+                        ISC_PLATFORM_HAVEIN6PKTINFO="#define ISC_PLATFORM_HAVEIN6PKTINFO 1"],
+                       [AC_MSG_RESULT(no -- disabling runtime ipv6 support)
+                        ISC_PLATFORM_HAVEIN6PKTINFO="#undef ISC_PLATFORM_HAVEIN6PKTINFO"])
+               ;;
+       no)
+               ISC_PLATFORM_HAVEIPV6="#undef ISC_PLATFORM_HAVEIPV6"
+               LWRES_PLATFORM_HAVEIPV6="#undef LWRES_PLATFORM_HAVEIPV6"
+               ISC_PLATFORM_NEEDIN6ADDRANY="#undef ISC_PLATFORM_NEEDIN6ADDRANY"
+               LWRES_PLATFORM_NEEDIN6ADDRANY="#undef LWRES_PLATFORM_NEEDIN6ADDRANY"
+               ISC_PLATFORM_HAVEIN6PKTINFO="#undef ISC_PLATFORM_HAVEIN6PKTINFO"
+               LWRES_HAVE_SIN6_SCOPE_ID="#define LWRES_HAVE_SIN6_SCOPE_ID 1"
+               ISC_IPV6_H="ipv6.h"
+               ISC_IPV6_O="ipv6.$O"
+               ISC_ISCIPV6_O="unix/ipv6.$O"
+               ISC_IPV6_C="ipv6.c"
+               ;;
+esac
+
+AC_SUBST(ISC_PLATFORM_HAVEIPV6)
+AC_SUBST(LWRES_PLATFORM_HAVEIPV6)
+AC_SUBST(ISC_PLATFORM_NEEDNETINETIN6H)
+AC_SUBST(LWRES_PLATFORM_NEEDNETINETIN6H)
+AC_SUBST(ISC_PLATFORM_NEEDNETINET6IN6H)
+AC_SUBST(LWRES_PLATFORM_NEEDNETINET6IN6H)
+AC_SUBST(ISC_PLATFORM_HAVEINADDR6)
+AC_SUBST(LWRES_PLATFORM_HAVEINADDR6)
+AC_SUBST(ISC_PLATFORM_NEEDIN6ADDRANY)
+AC_SUBST(LWRES_PLATFORM_NEEDIN6ADDRANY)
+AC_SUBST(ISC_PLATFORM_HAVEIN6PKTINFO)
+AC_SUBST(ISC_PLATFORM_FIXIN6ISADDR)
+AC_SUBST(ISC_IPV6_H)
+AC_SUBST(ISC_IPV6_O)
+AC_SUBST(ISC_ISCIPV6_O)
+AC_SUBST(ISC_IPV6_C)
+AC_SUBST(LWRES_HAVE_SIN6_SCOPE_ID)
+
+#
+# Check for network functions that are often missing.  We do this
+# after the libtool checking, so we can put the right suffix on
+# the files.  It also needs to come after checking for a Kame add-on,
+# which provides some (all?) of the desired functions.
+#
+AC_MSG_CHECKING([for inet_ntop])
+AC_TRY_LINK([
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>],
+        [inet_ntop(0, 0, 0, 0); return (0);],
+        [AC_MSG_RESULT(yes)
+        ISC_PLATFORM_NEEDNTOP="#undef ISC_PLATFORM_NEEDNTOP"],
+
+        [AC_MSG_RESULT(no)
+        ISC_EXTRA_OBJS="$ISC_EXTRA_OBJS inet_ntop.$O"
+        ISC_EXTRA_SRCS="$ISC_EXTRA_SRCS inet_ntop.c"
+        ISC_PLATFORM_NEEDNTOP="#define ISC_PLATFORM_NEEDNTOP 1"])
+AC_MSG_CHECKING([for inet_pton])
+AC_TRY_LINK([
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>],
+        [inet_pton(0, 0, 0); return (0);],
+        [AC_MSG_RESULT(yes)
+        ISC_PLATFORM_NEEDPTON="#undef ISC_PLATFORM_NEEDPTON"],
+
+        [AC_MSG_RESULT(no)
+        ISC_EXTRA_OBJS="$ISC_EXTRA_OBJS inet_pton.$O"
+        ISC_EXTRA_SRCS="$ISC_EXTRA_SRCS inet_pton.c"
+        ISC_PLATFORM_NEEDPTON="#define ISC_PLATFORM_NEEDPTON 1"])
+AC_MSG_CHECKING([for inet_aton])
+AC_TRY_LINK([
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>],
+        [struct in_addr in; inet_aton(0, &in); return (0);],
+        [AC_MSG_RESULT(yes)
+        ISC_PLATFORM_NEEDATON="#undef ISC_PLATFORM_NEEDATON"],
+
+        [AC_MSG_RESULT(no)
+        ISC_EXTRA_OBJS="$ISC_EXTRA_OBJS inet_aton.$O"
+        ISC_EXTRA_SRCS="$ISC_EXTRA_SRCS inet_aton.c"
+        ISC_PLATFORM_NEEDATON="#define ISC_PLATFORM_NEEDATON 1"])
+
+AC_SUBST(ISC_PLATFORM_NEEDNTOP)
+AC_SUBST(ISC_PLATFORM_NEEDPTON)
+AC_SUBST(ISC_PLATFORM_NEEDATON)
+
+#
+# Look for a 4.4BSD-style sa_len member in struct sockaddr.
+#
+case "$host" in
+       *-dec-osf*)
+               # Turn on 4.4BSD style sa_len support.
+               AC_DEFINE(_SOCKADDR_LEN)
+               ;;
+esac
+
+AC_MSG_CHECKING(for sa_len in struct sockaddr)
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <sys/socket.h>],
+[struct sockaddr sa; sa.sa_len = 0; return (0);],
+       [AC_MSG_RESULT(yes)
+       HAVE_SA_LEN="#define HAVE_SA_LEN 1"],
+       [AC_MSG_RESULT(no)
+       HAVE_SA_LEN="#undef HAVE_SA_LEN"])
+AC_SUBST(HAVE_SA_LEN)
+
+# HAVE_MINIMUM_IFREQ
+
+case "$host" in
+       *-bsdi4*)       have_minimum_ifreq=yes;;
+       *-bsdi3*)       have_minimum_ifreq=yes;;
+       *-bsdi2*)       have_minimum_ifreq=yes;;
+       *-darwin*)      have_minimum_ifreq=yes;;
+       *-freebsd*)     have_minimum_ifreq=yes;;
+       *-lynxos*)      have_minimum_ifreq=yes;;
+       *-netbsd*)      have_minimum_ifreq=yes;;
+       *-next*)        have_minimum_ifreq=yes;;
+       *-openbsd*)     have_minimum_ifreq=yes;;
+       *-rhapsody*)    have_minimum_ifreq=yes;;
+esac
+case "$have_minimum_ifreq" in
+       yes)
+               HAVE_MINIMUM_IFREQ="#define HAVE_MINIMUM_IFREQ 1";;
+       no)
+               HAVE_MINIMUM_IFREQ="#undef HAVE_MINIMUM_IFREQ";;
+       *)
+               HAVE_MINIMUM_IFREQ="#undef HAVE_MINIMUM_IFREQ";;
+esac
+AC_SUBST(HAVE_MINIMUM_IFREQ)
+#
+# Look for a 4.4BSD or 4.3BSD struct msghdr
+#
+AC_MSG_CHECKING(for struct msghdr flavor)
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <sys/socket.h>],
+[struct msghdr msg; msg.msg_flags = 0; return (0);],
+       [AC_MSG_RESULT(4.4BSD)
+       ISC_PLATFORM_MSGHDRFLAVOR="#define ISC_NET_BSD44MSGHDR 1"],
+       [AC_MSG_RESULT(4.3BSD)
+       ISC_PLATFORM_MSGHDRFLAVOR="#define ISC_NET_BSD43MSGHDR 1"])
+AC_SUBST(ISC_PLATFORM_MSGHDRFLAVOR)
+
+#
+# Look for in_port_t.
+#
+AC_MSG_CHECKING(for type in_port_t)
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <netinet/in.h>],
+[in_port_t port = 25; return (0);],
+       [AC_MSG_RESULT(yes)
+       ISC_PLATFORM_NEEDPORTT="#undef ISC_PLATFORM_NEEDPORTT"],
+        [AC_MSG_RESULT(no)
+       ISC_PLATFORM_NEEDPORTT="#define ISC_PLATFORM_NEEDPORTT 1"])
+AC_SUBST(ISC_PLATFORM_NEEDPORTT)
+
+#
+# Check for addrinfo
+#
+AC_MSG_CHECKING(for struct addrinfo)
+AC_TRY_COMPILE([
+#include <netdb.h>],
+[struct addrinfo a; return (0);],
+       [AC_MSG_RESULT(yes)
+       ISC_LWRES_NEEDADDRINFO="#undef ISC_LWRES_NEEDADDRINFO"
+       AC_DEFINE(HAVE_ADDRINFO)],
+       [AC_MSG_RESULT(no)
+       ISC_LWRES_NEEDADDRINFO="#define ISC_LWRES_NEEDADDRINFO 1"])
+AC_SUBST(ISC_LWRES_NEEDADDRINFO)
+
+AC_MSG_CHECKING(for int sethostent)
+AC_TRY_COMPILE([
+#include <netdb.h>],
+[int i = sethostent(0); return(0);],
+       [AC_MSG_RESULT(yes)
+       ISC_LWRES_SETHOSTENTINT="#define ISC_LWRES_SETHOSTENTINT 1"],
+       [AC_MSG_RESULT(no)
+       ISC_LWRES_SETHOSTENTINT="#undef ISC_LWRES_SETHOSTENTINT"])
+AC_SUBST(ISC_LWRES_SETHOSTENTINT)
+
+AC_MSG_CHECKING(for int endhostent)
+AC_TRY_COMPILE([
+#include <netdb.h>],
+[int i = endhostent(); return(0);],
+       [AC_MSG_RESULT(yes)
+       ISC_LWRES_ENDHOSTENTINT="#define ISC_LWRES_ENDHOSTENTINT 1"],
+       [AC_MSG_RESULT(no)
+       ISC_LWRES_ENDHOSTENTINT="#undef ISC_LWRES_ENDHOSTENTINT"])
+AC_SUBST(ISC_LWRES_ENDHOSTENTINT)
+
+AC_MSG_CHECKING(for getnetbyaddr(in_addr_t, ...))
+AC_TRY_COMPILE([
+#include <netdb.h>
+struct netent *getnetbyaddr(in_addr_t, int);],
+[],
+       [AC_MSG_RESULT(yes)
+       GETNETBYADDR_ADDR_T="#define GETNETBYADDR_ADDR_T in_addr_t"],
+       [AC_MSG_RESULT(no)
+       GETNETBYADDR_ADDR_T="#define GETNETBYADDR_ADDR_T long"])
+AC_SUBST(GETNETBYADDR_ADDR_T)
+
+AC_MSG_CHECKING(for int setnetent)
+AC_TRY_COMPILE([
+#include <netdb.h>],
+[int i = setnetent(0); return(0);],
+       [AC_MSG_RESULT(yes)
+       ISC_LWRES_SETNETENTINT="#define ISC_LWRES_SETNETENTINT 1"],
+       [AC_MSG_RESULT(no)
+       ISC_LWRES_SETNETENTINT="#undef ISC_LWRES_SETNETENTINT"])
+AC_SUBST(ISC_LWRES_SETNETENTINT)
+
+AC_MSG_CHECKING(for int endnetent)
+AC_TRY_COMPILE([
+#include <netdb.h>],
+[int i = endnetent(); return(0);],
+       [AC_MSG_RESULT(yes)
+       ISC_LWRES_ENDNETENTINT="#define ISC_LWRES_ENDNETENTINT 1"],
+       [AC_MSG_RESULT(no)
+       ISC_LWRES_ENDNETENTINT="#undef ISC_LWRES_ENDNETENTINT"])
+AC_SUBST(ISC_LWRES_ENDNETENTINT)
+
+AC_MSG_CHECKING(for gethostbyaddr(const void *, size_t, ...))
+AC_TRY_COMPILE([
+#include <netdb.h>
+struct hostent *gethostbyaddr(const void *, size_t, int);],
+[return(0);],
+       [AC_MSG_RESULT(yes)
+       ISC_LWRES_GETHOSTBYADDRVOID="#define ISC_LWRES_GETHOSTBYADDRVOID 1"],
+       [AC_MSG_RESULT(no)
+       ISC_LWRES_GETHOSTBYADDRVOID="#undef ISC_LWRES_GETHOSTBYADDRVOID"])
+AC_SUBST(ISC_LWRES_GETHOSTBYADDRVOID)
+
+AC_MSG_CHECKING(for h_errno in netdb.h)
+AC_TRY_COMPILE([
+#include <netdb.h>],
+[h_errno = 1; return(0);],
+       [AC_MSG_RESULT(yes)
+       ISC_LWRES_NEEDHERRNO="#undef ISC_LWRES_NEEDHERRNO"],
+       [AC_MSG_RESULT(no)
+       ISC_LWRES_NEEDHERRNO="#define ISC_LWRES_NEEDHERRNO 1"])
+AC_SUBST(ISC_LWRES_NEEDHERRNO)
+
+AC_CHECK_FUNC(getipnodebyname,
+        [ISC_LWRES_GETIPNODEPROTO="#undef ISC_LWRES_GETIPNODEPROTO"],
+        [ISC_LWRES_GETIPNODEPROTO="#define ISC_LWRES_GETIPNODEPROTO 1"])
+AC_CHECK_FUNC(getnameinfo,
+        [ISC_LWRES_GETNAMEINFOPROTO="#undef ISC_LWRES_GETNAMEINFOPROTO"],
+        [ISC_LWRES_GETNAMEINFOPROTO="#define ISC_LWRES_GETNAMEINFOPROTO 1"])
+AC_CHECK_FUNC(getaddrinfo,
+        [ISC_LWRES_GETADDRINFOPROTO="#undef ISC_LWRES_GETADDRINFOPROTO"
+       AC_DEFINE(HAVE_GETADDRINFO)],
+        [ISC_LWRES_GETADDRINFOPROTO="#define ISC_LWRES_GETADDRINFOPROTO 1"])
+AC_CHECK_FUNC(gai_strerror, AC_DEFINE(HAVE_GAISTRERROR))
+AC_SUBST(ISC_LWRES_GETIPNODEPROTO)
+AC_SUBST(ISC_LWRES_GETADDRINFOPROTO)
+AC_SUBST(ISC_LWRES_GETNAMEINFOPROTO)
+AC_CHECK_FUNC(pselect,
+             [NEED_PSELECT="#undef NEED_PSELECT"],
+             [NEED_PSELECT="#define NEED_PSELECT"])
+AC_SUBST(NEED_PSELECT)
+
+#
+# Look for a sysctl call to get the list of network interfaces.
+#
+AC_MSG_CHECKING(for interface list sysctl)
+AC_EGREP_CPP(found_rt_iflist, [
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/socket.h>
+#ifdef NET_RT_IFLIST
+found_rt_iflist
+#endif
+],
+       [AC_MSG_RESULT(yes)
+        AC_DEFINE(HAVE_IFLIST_SYSCTL)],
+       [AC_MSG_RESULT(no)])
+
+#
+# Check for some other useful functions that are not ever-present.
+#
+AC_CHECK_FUNC(strsep,
+       [ISC_PLATFORM_NEEDSTRSEP="#undef ISC_PLATFORM_NEEDSTRSEP"],
+       [ISC_PLATFORM_NEEDSTRSEP="#define ISC_PLATFORM_NEEDSTRSEP 1"])
+AC_CHECK_FUNC(vsnprintf,
+       [ISC_PLATFORM_NEEDVSNPRINTF="#undef ISC_PLATFORM_NEEDVSNPRINTF"],
+       [ISC_EXTRA_OBJS="$ISC_EXTRA_OBJS print.$O"
+        ISC_EXTRA_SRCS="$ISC_EXTRA_SRCS print.c"
+        ISC_PLATFORM_NEEDVSNPRINTF="#define ISC_PLATFORM_NEEDVSNPRINTF 1"])
+AC_SUBST(ISC_PLATFORM_NEEDSTRSEP)
+AC_SUBST(ISC_PLATFORM_NEEDVSNPRINTF)
+
+AC_SUBST(ISC_EXTRA_OBJS)
+AC_SUBST(ISC_EXTRA_SRCS)
+
+#
+# Determine the printf format characters to use when printing
+# values of type isc_int64_t.  We make the assumption that platforms
+# where a "long long" is the same size as a "long" (e.g., Alpha/OSF1)
+# want "%ld" and everyone else can use "%lld".  Win32 uses "%I64d",
+# but that's defined elsewhere since we don't use configure on Win32.
+#
+AC_MSG_CHECKING(printf format modifier for 64-bit integers)
+AC_TRY_RUN([main() { exit(!(sizeof(long long int) == sizeof(long int))); }],
+       [AC_MSG_RESULT(l)
+       ISC_PLATFORM_QUADFORMAT='#define ISC_PLATFORM_QUADFORMAT "l"'],
+       [AC_MSG_RESULT(ll)
+       ISC_PLATFORM_QUADFORMAT='#define ISC_PLATFORM_QUADFORMAT "ll"'],
+       [AC_MSG_RESULT(default ll)
+       ISC_PLATFORM_QUADFORMAT='#define ISC_PLATFORM_QUADFORMAT "ll"'])
+AC_SUBST(ISC_PLATFORM_QUADFORMAT)
+
+#
+# Security Stuff
+#
+AC_CHECK_FUNC(chroot, AC_DEFINE(HAVE_CHROOT))
+AC_CHECK_HEADERS(linux/capability.h)
+AC_CHECK_HEADERS(sys/prctl.h)
+
+#
+# BSD/OS, and perhaps some others, don't define rlim_t.
+#
+AC_MSG_CHECKING(for type rlim_t)
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>],
+[rlim_t rl = 19671212; return (0);],
+       [AC_MSG_RESULT(yes)
+         AC_DEFINE(HAVE_RLIM_T)],
+        [AC_MSG_RESULT(no)])
+AC_MSG_CHECKING(sizeof rlim_cur)
+AC_TRY_RUN([
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+main() { struct rlimit r; exit(!(sizeof(r.rlim_cur) == sizeof(int)));}],
+[AC_MSG_RESULT(int)
+ISC_PLATFORM_RLIMITTYPE="#define ISC_PLATFORM_RLIMITTYPE int"],
+[
+AC_TRY_RUN([
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+main() { struct rlimit r; exit(!(sizeof(r.rlim_cur) == sizeof(long int)));}],
+[AC_MSG_RESULT(long int)
+ISC_PLATFORM_RLIMITTYPE="#define ISC_PLATFORM_RLIMITTYPE long int"],
+[
+AC_TRY_RUN([
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+main() { struct rlimit r; exit((!sizeof(r.rlim_cur) == sizeof(long long int)));}],
+[AC_MSG_RESULT(long long int)
+ISC_PLATFORM_RLIMITTYPE="#define ISC_PLATFORM_RLIMITTYPE long long int"],
+[AC_MSG_ERROR([unable to determine sizeof rlim_cur])
+],[])
+],[])
+],[])
+AC_SUBST(ISC_PLATFORM_RLIMITTYPE)
+
+AC_CHECK_FUNC(getgrouplist,
+AC_TRY_COMPILE(
+[#include <unistd.h>
+int
+getgrouplist(const char *name, int basegid, int *groups, int *ngroups) {
+}
+],
+[return (0);],
+GETGROUPLIST_ARGS="#define GETGROUPLIST_ARGS const char *name, int basegid, int *groups, int *ngroups"
+,
+GETGROUPLIST_ARGS="#define GETGROUPLIST_ARGS const char *name, gid_t basegid, gid_t *groups, int *ngroups"
+),
+GETGROUPLIST_ARGS="#define GETGROUPLIST_ARGS const char *name, gid_t basegid, gid_t *groups, int *ngroups"
+)
+AC_SUBST(GETGROUPLIST_ARGS)
+
+AC_CHECK_FUNC(getnetbyaddr_r,
+,
+NET_R_ARGS="#define NET_R_ARGS char *buf, int buflen"
+NET_R_BAD="#define NET_R_BAD NULL"
+NET_R_COPY="#define NET_R_COPY buf, buflen"
+NET_R_COPY_ARGS="#define NET_R_COPY_ARGS NET_R_ARGS"
+NET_R_OK="#define NET_R_OK nptr"
+NET_R_RETURN="#define NET_R_RETURN struct netent *"
+)
+AC_SUBST(NET_R_ARGS)
+AC_SUBST(NET_R_BAD)
+AC_SUBST(NET_R_COPY)
+AC_SUBST(NET_R_COPY_ARGS)
+AC_SUBST(NET_R_OK)
+AC_SUBST(NET_R_RETURN)
+
+AC_CHECK_FUNC(setnetent_r,
+,
+NET_R_ENT_ARGS="#undef NET_R_ENT_ARGS /*empty*/"
+NET_R_SET_RESULT="#undef NET_R_SET_RESULT /*empty*/"
+NET_R_SET_RETURN="#define NET_R_SET_RETURN void"
+)
+AC_SUBST(NET_R_ENT_ARGS)
+AC_SUBST(NET_R_SET_RESULT)
+AC_SUBST(NET_R_SET_RETURN)
+
+AC_CHECK_FUNC(endnetent_r,
+,
+NET_R_END_RESULT="#define NET_R_END_RESULT(x) /*empty*/"
+NET_R_END_RETURN="#define NET_R_END_RETURN void"
+)
+AC_SUBST(NET_R_END_RESULT)
+AC_SUBST(NET_R_END_RETURN)
+
+AC_CHECK_FUNC(getgrent_r,
+,
+GROUP_R_ARGS="#define GROUP_R_ARGS char *buf, int buflen"
+GROUP_R_BAD="#define GROUP_R_BAD NULL"
+GROUP_R_OK="#define GROUP_R_OK gptr"
+GROUP_R_RETURN="#define GROUP_R_RETURN struct group *"
+)
+AC_SUBST(GROUP_R_ARGS)
+AC_SUBST(GROUP_R_BAD)
+AC_SUBST(GROUP_R_OK)
+AC_SUBST(GROUP_R_RETURN)
+
+AC_CHECK_FUNC(endgrent_r,
+,
+GROUP_R_END_RESULT="#define GROUP_R_END_RESULT(x) /*empty*/"
+GROUP_R_END_RETURN="#define GROUP_R_END_RETURN void"
+GROUP_R_ENT_ARGS="#define GROUP_R_ENT_ARGS void"
+)
+AC_SUBST(GROUP_R_END_RESULT)
+AC_SUBST(GROUP_R_END_RETURN)
+AC_SUBST(GROUP_R_ENT_ARGS)
+
+AC_CHECK_FUNC(setgrent_r,
+,
+GROUP_R_SET_RESULT="#undef GROUP_R_SET_RESULT /*empty*/"
+GROUP_R_SET_RETURN="#define GROUP_R_SET_RETURN void"
+)
+AC_SUBST(GROUP_R_SET_RESULT)
+AC_SUBST(GROUP_R_SET_RETURN)
+
+AC_CHECK_FUNC(gethostbyname_r,
+,
+HOST_R_ARGS="#define HOST_R_ARGS char *buf, int buflen, int *h_errnop"
+HOST_R_BAD="#define HOST_R_BAD NULL"
+HOST_R_COPY="#define HOST_R_COPY buf, buflen"
+HOST_R_COPY_ARGS="#define HOST_R_COPY_ARGS char *buf, int buflen"
+HOST_R_ERRNO="#define HOST_R_ERRNO *h_errnop = h_errno"
+HOST_R_OK="#define HOST_R_OK hptr"
+HOST_R_RETURN="#define HOST_R_RETURN struct hostent *"
+)
+AC_SUBST(HOST_R_ARGS)
+AC_SUBST(HOST_R_BAD)
+AC_SUBST(HOST_R_COPY)
+AC_SUBST(HOST_R_COPY_ARGS)
+AC_SUBST(HOST_R_ERRNO)
+AC_SUBST(HOST_R_OK)
+AC_SUBST(HOST_R_RETURN)
+
+AC_CHECK_FUNC(endhostent_r,
+,
+HOST_R_END_RESULT="#define HOST_R_END_RESULT(x) /*empty*/"
+HOST_R_END_RETURN="#define HOST_R_END_RETURN void"
+HOST_R_ENT_ARGS="#undef HOST_R_ENT_ARGS /*empty*/"
+)
+AC_SUBST(HOST_R_END_RESULT)
+AC_SUBST(HOST_R_END_RETURN)
+AC_SUBST(HOST_R_ENT_ARGS)
+
+AC_CHECK_FUNC(sethostent_r,
+,
+HOST_R_SET_RESULT="#undef HOST_R_SET_RESULT /*empty*/"
+HOST_R_SET_RETURN="#define HOST_R_SET_RETURN void"
+)
+AC_SUBST(HOST_R_SET_RESULT)
+AC_SUBST(HOST_R_SET_RETURN)
+
+
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <pwd.h>
+void
+setpwent(void) {}
+],
+[return (0);],
+SETPWENT_VOID="#define SETPWENT_VOID 1"
+,
+SETPWENT_VOID="#undef SETPWENT_VOID"
+)
+AC_SUBST(SETPWENT_VOID)
+
+AC_CHECK_FUNC(getnetgrent_r,
+,
+NGR_R_ARGS="#define NGR_R_ARGS char *buf, int buflen"
+NGR_R_BAD="#define NGR_R_BAD (0)"
+NGR_R_COPY="#define NGR_R_COPY buf, buflen"
+NGR_R_COPY_ARGS="#define NGR_R_COPY_ARGS NGR_R_ARGS"
+NGR_R_OK="#define NGR_R_OK 1"
+NGR_R_RETURN="#define NGR_R_RETURN int"
+)
+AC_SUBST(NGR_R_ARGS)
+AC_SUBST(NGR_R_BAD)
+AC_SUBST(NGR_R_COPY)
+AC_SUBST(NGR_R_COPY_ARGS)
+AC_SUBST(NGR_R_OK)
+AC_SUBST(NGR_R_RETURN)
+
+AC_CHECK_FUNC(endnetgrent_r,
+,
+NGR_R_END_RESULT="#define NGR_R_END_RESULT(x)  /*empty*/"
+NGR_R_END_RETURN="#define NGR_R_END_RETURN void"
+NGR_R_ENT_ARGS="#undef NGR_R_ENT_ARGS /*empty*/"
+)
+AC_SUBST(NGR_R_END_RESULT)
+AC_SUBST(NGR_R_END_RETURN)
+AC_SUBST(NGR_R_ENT_ARGS)
+
+AC_CHECK_FUNC(setnetgrent_r,
+,
+NGR_R_SET_RESULT="#undef NGR_R_SET_RESULT /*empty*/"
+NGR_R_SET_RETURN="#define NGR_R_SET_RETURN void"
+)
+AC_SUBST(NGR_R_SET_RESULT)
+AC_SUBST(NGR_R_SET_RETURN)
+
+
+AC_CHECK_FUNC(getprotoent_r,
+,
+PROTO_R_ARGS="#define PROTO_R_ARGS char *buf, int buflen"
+PROTO_R_BAD="#define PROTO_R_BAD NULL"
+PROTO_R_COPY="#define PROTO_R_COPY buf, buflen"
+PROTO_R_COPY_ARGS="#define PROTO_R_COPY_ARGS PROTO_R_ARGS"
+PROTO_R_OK="#define PROTO_R_OK pptr"
+PROTO_R_RETURN="#define PROTO_R_RETURN struct protoent *"
+)
+AC_SUBST(PROTO_R_ARGS)
+AC_SUBST(PROTO_R_BAD)
+AC_SUBST(PROTO_R_COPY)
+AC_SUBST(PROTO_R_COPY_ARGS)
+AC_SUBST(PROTO_R_OK)
+AC_SUBST(PROTO_R_RETURN)
+
+AC_CHECK_FUNC(endprotoent_r,
+,
+PROTO_R_END_RESULT="#define PROTO_R_END_RESULT(x) /*empty*/"
+PROTO_R_END_RETURN="#define PROTO_R_END_RETURN void"
+PROTO_R_ENT_ARGS="#undef PROTO_R_ENT_ARGS /*empty*/"
+)
+AC_SUBST(PROTO_R_END_RESULT)
+AC_SUBST(PROTO_R_END_RETURN)
+AC_SUBST(PROTO_R_ENT_ARGS)
+
+AC_CHECK_FUNC(setprotoent_r,
+,
+PROTO_R_SET_RESULT="#undef PROTO_R_SET_RESULT /*empty*/"
+PROTO_R_SET_RETURN="#define PROTO_R_SET_RETURN void"
+)
+AC_SUBST(PROTO_R_SET_RESULT)
+AC_SUBST(PROTO_R_SET_RETURN)
+
+AC_CHECK_FUNC(getpwent_r,
+,
+PASS_R_ARGS="#define PASS_R_ARGS char *buf, int buflen"
+PASS_R_BAD="#define PASS_R_BAD NULL"
+PASS_R_COPY="#define PASS_R_COPY buf, buflen"
+PASS_R_COPY_ARGS="#define PASS_R_COPY_ARGS PASS_R_ARGS"
+PASS_R_OK="#define PASS_R_OK pwptr"
+PASS_R_RETURN="#define PASS_R_RETURN struct passwd *"
+)
+AC_SUBST(PASS_R_ARGS)
+AC_SUBST(PASS_R_BAD)
+AC_SUBST(PASS_R_COPY)
+AC_SUBST(PASS_R_COPY_ARGS)
+AC_SUBST(PASS_R_OK)
+AC_SUBST(PASS_R_RETURN)
+
+AC_CHECK_FUNC(endpwent_r,
+,
+PASS_R_END_RESULT="#define PASS_R_END_RESULT(x) /*empty*/"
+PASS_R_END_RETURN="#define PASS_R_END_RETURN void"
+PASS_R_ENT_ARGS="#undef PASS_R_ENT_ARGS /*empty*/"
+)
+AC_SUBST(PASS_R_END_RESULT)
+AC_SUBST(PASS_R_END_RETURN)
+AC_SUBST(PASS_R_ENT_ARGS)
+
+AC_CHECK_FUNC(setpwent_r,
+,
+PASS_R_SET_RESULT="#undef PASS_R_SET_RESULT /*empty*/"
+PASS_R_SET_RETURN="#define PASS_R_SET_RETURN void"
+)
+AC_SUBST(PASS_R_SET_RESULT)
+AC_SUBST(PASS_R_SET_RETURN)
+
+AC_CHECK_FUNC(getservent_r,
+,
+SERV_R_ARGS="#define SERV_R_ARGS char *buf, int buflen"
+SERV_R_BAD="#define SERV_R_BAD NULL"
+SERV_R_COPY="#define SERV_R_COPY buf, buflen"
+SERV_R_COPY_ARGS="#define SERV_R_COPY_ARGS SERV_R_ARGS"
+SERV_R_OK="#define SERV_R_OK sptr"
+SERV_R_RETURN="#define SERV_R_RETURN struct servent *"
+)
+AC_SUBST(SERV_R_ARGS)
+AC_SUBST(SERV_R_BAD)
+AC_SUBST(SERV_R_COPY)
+AC_SUBST(SERV_R_COPY_ARGS)
+AC_SUBST(SERV_R_OK)
+AC_SUBST(SERV_R_RETURN)
+
+AC_CHECK_FUNC(endservent_r,
+,
+SERV_R_END_RESULT="#define SERV_R_END_RESULT(x) /*empty*/"
+SERV_R_END_RETURN="#define SERV_R_END_RETURN void "
+SERV_R_ENT_ARGS="#undef SERV_R_ENT_ARGS /*empty*/"
+)
+AC_SUBST(SERV_R_END_RESULT)
+AC_SUBST(SERV_R_END_RETURN)
+AC_SUBST(SERV_R_ENT_ARGS)
+
+AC_CHECK_FUNC(setservent_r,
+,
+SERV_R_SET_RESULT="#undef SERV_R_SET_RESULT /*empty*/"
+SERV_R_SET_RETURN="#define SERV_R_SET_RETURN void"
+)
+AC_SUBST(SERV_R_SET_RESULT)
+AC_SUBST(SERV_R_SET_RETURN)
+
+#
+# Random remaining OS-specific issues involving compiler warnings.
+# XXXDCL print messages to indicate some compensation is being done?
+#
+AC_SUBST(ISC_PLATFORM_BRACEPTHREADONCEINIT)
+ISC_PLATFORM_BRACEPTHREADONCEINIT="#undef ISC_PLATFORM_BRACEPTHREADONCEINIT"
+
+case "$host" in
+       *-bsdi3.1*)
+               hack_shutup_sputaux=yes
+               ;;
+       *-bsdi4.0*)
+               hack_shutup_sigwait=yes
+               hack_shutup_sputaux=yes
+               ;;
+       *-bsdi4.1*)
+               hack_shutup_stdargcast=yes
+               ;;
+       *-solaris2.8)
+               hack_shutup_pthreadonceinit=yes
+               ;;
+esac
+
+case "$hack_shutup_pthreadonceinit" in
+       yes)
+               #
+               # Shut up PTHREAD_ONCE_INIT unbraced initializer warnings.
+               #
+               ISC_PLATFORM_BRACEPTHREADONCEINIT="#define ISC_PLATFORM_BRACEPTHREADONCEINIT 1"
+               ;;
+esac
+
+case "$hack_shutup_sigwait" in
+       yes)
+               #
+               # Shut up a -Wmissing-prototypes warning for sigwait().
+               #
+               AC_DEFINE(SHUTUP_SIGWAIT)
+               ;;
+esac
+
+case "$hack_shutup_sputaux" in
+       yes)
+               #
+               # Shut up a -Wmissing-prototypes warning from <stdio.h>.
+               #
+               AC_DEFINE(SHUTUP_SPUTAUX)
+               ;;
+esac
+
+case "$hack_shutup_stdargcast" in
+       yes)
+               #
+               # Shut up a -Wcast-qual warning from va_start().
+               #
+               AC_DEFINE(SHUTUP_STDARG_CAST)
+               ;;
+esac
+
+
+#
+# Look for jade, preferring openjade if installed.
+#
+
+AC_PATH_PROGS(JADE, openjade jade, jade)
+AC_SUBST(JADE)
+
+#
+# Look for tex & pdftex.
+#
+
+AC_PATH_PROGS(TEX, tex)
+AC_SUBST(TEX)
+
+AC_PATH_PROGS(PDFTEX, pdftex)
+AC_SUBST(PDFTEX)
+
+#
+# Look for SGML files.  NetBSD has them under /usr/pkg/share 
+# (if installed), FreeBSD has them under /usr/local/share.
+#
+
+SGMLDIR=""
+
+AC_MSG_CHECKING(for SGML files)
+for d in /usr/pkg/share/sgml /usr/local/share/sgml 
+do
+       if test -f $d/docbook/dsssl/modular/html/docbook.dsl
+       then
+               SGMLDIR=$d
+               AC_MSG_RESULT(in $SGMLDIR)
+               break
+       fi
+done
+
+if test "X$SGMLDIR" = "X"
+then
+       AC_MSG_RESULT("not found");
+       SGMLDIR=/usr/local/share/sgml
+fi
+
+AC_SUBST(SGMLDIR)
+
+#
+# Look for XML files.
+#
+XGMLDIR=""
+
+AC_MSG_CHECKING(for XML files)
+for d in /usr/pkg/share/xml /usr/local/share/xml
+do
+       if test -f $d/dtd/docbook/docbookx.dtd
+       then
+               XMLDIR=$d
+               AC_MSG_RESULT(in $XMLDIR)
+               break
+       fi
+done
+
+if test "X$XMLDIR" = "X"
+then
+       AC_MSG_RESULT("not found");
+       XMLDIR=/usr/local/share/xml
+fi
+
+AC_SUBST(XMLDIR)
+
+#
+# Substitutions
+#
+AC_SUBST(BIND9_TOP_BUILDDIR)
+BIND9_TOP_BUILDDIR=`pwd`
+
+AC_SUBST(BIND9_ISC_BUILDINCLUDE)
+AC_SUBST(BIND9_ISCCFG_BUILDINCLUDE)
+AC_SUBST(BIND9_DNS_BUILDINCLUDE)
+AC_SUBST(BIND9_OMAPI_BUILDINCLUDE)
+AC_SUBST(BIND9_LWRES_BUILDINCLUDE)
+if test "X$srcdir" != "X"; then
+       BIND9_ISC_BUILDINCLUDE="-I${BIND9_TOP_BUILDDIR}/lib/isc/include"
+       BIND9_ISCCFG_BUILDINCLUDE="-I${BIND9_TOP_BUILDDIR}/lib/isccfg/include"
+       BIND9_DNS_BUILDINCLUDE="-I${BIND9_TOP_BUILDDIR}/lib/dns/include"
+       BIND9_OMAPI_BUILDINCLUDE="-I${BIND9_TOP_BUILDDIR}/lib/omapi/include"
+       BIND9_LWRES_BUILDINCLUDE="-I${BIND9_TOP_BUILDDIR}/lib/lwres/include"
+else
+       BIND9_ISC_BUILDINCLUDE=""
+       BIND9_ISCCFG_BUILDINCLUDE=""
+       BIND9_DNS_BUILDINCLUDE=""
+       BIND9_OMAPI_BUILDINCLUDE=""
+       BIND9_LWRES_BUILDINCLUDE=""
+fi
+
+AC_SUBST_FILE(BIND9_INCLUDES)
+BIND9_INCLUDES=$BIND9_TOP_BUILDDIR/make/includes
+
+AC_SUBST_FILE(BIND9_MAKE_RULES)
+BIND9_MAKE_RULES=$BIND9_TOP_BUILDDIR/make/rules
+
+. $srcdir/../../version
+BIND9_VERSION="VERSION=${MAJORVER}.${MINORVER}.${PATCHVER}${RELEASETYPE}${RELEASEVER}"
+AC_SUBST(BIND9_VERSION)
+
+AC_SUBST_FILE(LIBISC_API)
+LIBISC_API=$srcdir/lib/isc/api
+
+AC_SUBST_FILE(LIBISCCFG_API)
+LIBISCCFG_API=$srcdir/lib/isccfg/api
+
+AC_SUBST_FILE(LIBDNS_API)
+LIBDNS_API=$srcdir/lib/dns/api
+
+AC_SUBST_FILE(LIBLWRES_API)
+LIBLWRES_API=$srcdir/lib/lwres/api
+
+AC_SUBST_FILE(LIBOMAPI_API)
+LIBOMAPI_API=$srcdir/lib/omapi/api
+
+AC_OUTPUT(
+       Makefile
+       bsd/Makefile
+       cylink/Makefile
+       dnssafe/Makefile
+       dst/Makefile
+       include/Makefile
+       inet/Makefile
+       irs/Makefile
+       isc/Makefile
+       nameser/Makefile
+       port_after.h
+       port_before.h
+       resolv/Makefile
+       make/rules
+       make/mkdep
+       make/includes
+)
+
+# Tell Emacs to edit this file in shell mode.
+# Local Variables:
+# mode: sh
+# End:
diff --git a/lib/bind/cylink/Makefile.in b/lib/bind/cylink/Makefile.in
new file mode 100644 (file)
index 0000000..c4fd9ac
--- /dev/null
@@ -0,0 +1,12 @@
+OBJS=  bn.@O@ bn00.@O@ lbn00.@O@ lbnmem.@O@ legal.@O@ \
+        bits.@O@ dss.@O@ math.@O@ ctk_prime.@O@ rand.@O@ sha.@O@ swap.@O@
+
+SRCS=  bn.c bn00.c lbn00.c lbnmem.c legal.c \
+        bits.c dss.c math.c ctk_prime.c rand.c sha.c swap.c
+
+TARGETS= ${OBJS}
+
+CINCLUDES= -I.. -I../include
+CWARNINGS= -Werror
+
+@BIND9_MAKE_RULES@
diff --git a/lib/bind/cylink/bits.c b/lib/bind/cylink/bits.c
new file mode 100644 (file)
index 0000000..7cfae8c
--- /dev/null
@@ -0,0 +1,359 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/****************************************************************************
+*  FILENAME: bit.c   PRODUCT NAME: CRYPTOGRAPHIC TOOLKIT
+*
+*  FILE STATUS:
+*
+*  DESCRIPTION:  Bit Utility Functions
+*
+*  PUBLIC FUNCTIONS:
+*
+*
+*  PRIVATE FUNCTIONS:
+*
+*  REVISION  HISTORY:
+*
+*
+****************************************************************************/
+
+/****************************************************************************
+*  INCLUDE FILES
+****************************************************************************/
+/* bn files */
+#include "port_before.h"
+#include <sys/types.h>
+#include "bn.h"
+/* system files */
+#ifdef VXD
+#include <vtoolsc.h>
+#else
+#include <stdlib.h>
+#include <string.h>
+#endif
+/* program files */
+#include "cylink.h"
+#include "ctk_endian.h"
+#include "c_asm.h"
+#include "port_after.h"
+
+
+/****************************************************************************
+*  NAME: void  RShiftL( ord   *X,
+*                       u_int32_t  len_X,
+*                       u_int32_t  n_bit )
+*
+*  DESCRIPTION:  Shift array to the right by n_bit.
+*
+*  INPUTS:
+*          PARAMETERS:
+*            ord  *X            Pointer to array
+*            u_int32_t len_X         Length of array
+*                        u_int32_t n_bit             Number of bits
+*  OUTPUT:
+*          PARAMETERS:
+*            ord  *X            Pointer to array
+*
+*          RETURN:
+*
+*  REVISION HISTORY:
+*
+*  24 Sep 94    KPZ             Initial release
+*  14 Oct 94    GKL     Second version (big endian support)
+*
+****************************************************************************/
+
+void  RShiftL_big( ord   *X,
+                  u_int32_t  len_X,
+                  u_int32_t  n_bit )
+{
+
+struct BigNum dest;
+bnInit();
+bnBegin(&dest);
+
+dest.ptr = X;
+dest.size = len_X;
+dest.allocated = len_X;
+
+bnRShift(&dest,n_bit);
+
+}
+
+/****************************************************************************
+*  NAME: void  LShiftL( ord   *X,
+*                       u_int32_t  len_X,
+*                       u_int32_t  n_bit )
+*
+*  DESCRIPTION:  Shifts array to the left by n_bit.
+*
+*  INPUTS:
+*          PARAMETERS:
+*            ord  *X            Pointer to array
+*            u_int32_t len_X         Length of array
+*                        u_int32_t n_bit             Number of bits
+*  OUTPUT:
+*          PARAMETERS:
+*            ord  *X            Pointer to array
+*
+*          RETURN:
+*
+*  REVISION HISTORY:
+*
+*  24 Sep 94    KPZ             Initial release
+*  14 Oct 94    GKL     Second version (big endian support)
+*
+****************************************************************************/
+
+void  LShiftL_big( ord *X,
+                          u_int32_t len_X,
+                  u_int32_t n_bit )
+{
+struct BigNum dest;
+bnInit();
+bnBegin(&dest);
+
+dest.ptr = X;
+dest.size = len_X;
+dest.allocated = len_X;
+
+bnLShift(&dest,n_bit);
+}
+
+/************9****************************************************************
+*  NAME:     int RShiftMostBit( ord *a,
+*                                                       u_int32_t len )
+*
+*  DESCRIPTION:  Find a least significant non zero bit
+*                                and sfift array to the right
+*
+*  INPUTS:
+*          PARAMETERS:
+*           ord *a           Pointer to array
+*           u_int32_t len         Number of elements in number
+*  OUTPUT:
+*
+*  RETURN:
+*            Number of shifted bits
+*
+*  REVISION HISTORY:
+*
+*
+*  24 Sep 94    KPZ             Initial release
+*  14 Oct 94    GKL     Second version (big endian support)
+*
+****************************************************************************/
+
+int RShiftMostBit( ord *a,
+                        u_int32_t len )
+{
+
+struct BigNum n;
+bnInit();
+bnBegin(&n);
+
+n.size = len;
+n.ptr = a;
+n.allocated = len;
+
+return (bnMakeOdd(&n));
+
+}
+
+
+/****************************************************************************
+*  NAME:   void  ByteLong (uchar *X, u_int32_t X_bytes,
+*                                    u_int32_t  *Y )
+*
+*
+*  DESCRIPTION:  Transfer bytes to u_int32_t.
+*
+*  INPUTS:
+*          PARAMETERS:
+*            uchar  *X            Pointer to byte array
+*            u_int32_t X_bytes   Number of bytes in array
+*  OUTPUT:
+*          PARAMETERS:
+*            u_int32_t *Y         Pointer to long arrray
+*
+*          RETURN:
+*
+*
+*  REVISION HISTORY:
+*
+*  24 Sep 94   KPZ     Initial release
+*  14 Oct 94   GKL     Second version (big endian support)
+*
+****************************************************************************/
+
+void  ByteLong( uchar *X,
+                u_int32_t X_bytes,
+                u_int32_t *Y )
+{
+    u_int32_t i, j;                    /* counters */
+    for ( i = 0, j = 0; j < X_bytes; i++, j += 4)
+    {
+                               Y[i] = ( (u_int32_t)X[j] ) | ( ((u_int32_t)X[j+1]) << 8 ) |
+                     ( ((u_int32_t)X[j+2]) << 16 ) | ( ((u_int32_t)X[j+3]) << 24 );
+       }
+}
+
+/****************************************************************************
+*  NAME:   void  ByteOrd (uchar *X, u_int32_t X_bytes,
+*                                   ord   *Y )
+*
+*
+*  DESCRIPTION:  Transfer bytes to ord.
+*
+*  INPUTS:
+*          PARAMETERS:
+*            uchar  *X            Pointer to byte array
+*            u_int32_t X_bytes   Number of bytes in array
+*  OUTPUT:
+*          PARAMETERS:
+*            ord *Y         Pointer to long array
+*
+*          RETURN:
+*
+*
+*  REVISION HISTORY:
+*
+*  24 Sep 94   KPZ     Initial release
+*  14 Oct 94   GKL     Second version (big endian support)
+*
+****************************************************************************/
+
+void  ByteOrd( uchar *X,
+               u_int32_t X_bytes,
+               ord *Y )
+{
+    u_int32_t i, j;                    /* counters */
+       for ( i = 0, j = 0; j < X_bytes; i++, j += sizeof(ord))
+    {
+              Y[i] = ( (ord)X[j] ) | ( ((ord)X[j+1]) << 8 )
+#ifdef ORD_32
+          | ( ((ord)X[j+2]) << 16 ) | ( ((ord)X[j+3]) << 24 )
+#endif
+            ;
+    }
+}
+
+/****************************************************************************
+*  NAME:   void  OrdByte (ord *X, u_int32_t X_bytes,
+*                                 uchar  *Y )
+*
+*
+*  DESCRIPTION:  Transfer ord to bytes.
+*
+*  INPUTS:
+*          PARAMETERS:
+*            ord  *X            Pointer to ord array
+*            u_int32_t X_bytes     Number of bytes in array
+*  OUTPUT:
+*          PARAMETERS:
+*            uchar *Y         Pointer to byte array
+*
+*          RETURN:
+*
+*
+*  REVISION HISTORY:
+*
+*  24 Sep 94   KPZ     Initial release
+*  14 Oct 94   GKL     Second version (big endian support)
+*
+****************************************************************************/
+
+void  OrdByte( ord *X,
+               u_int32_t X_bytes,
+               uchar *Y )
+{
+    u_int32_t i, j;              /* counters */
+    for ( i=0, j=0; j < X_bytes; i++, j += sizeof(ord))
+    {
+                         Y[j] = (uchar ) ( X[i] & 0xff );
+                               Y[j+1] = (uchar)( (X[i] >> 8) & 0xff );
+#ifdef ORD_32
+        Y[j+2] = (uchar)( (X[i] >> 16) & 0xff );
+        Y[j+3] = (uchar)( (X[i] >> 24) & 0xff );
+#endif
+    }
+}
+
+/****************************************************************************
+*  NAME: void  LongByte( u_int32_t  *X,
+*                        u_int32_t X_bytes,
+*                        uchar  *Y )
+*
+*  DESCRIPTION:  Transfer u_int32_t to bytes.
+*
+*  INPUTS:
+*          PARAMETERS:
+*            u_int32_t  *X            Pointer to long array
+*            u_int32_t X_bytes   Number of longs in array
+*  OUTPUT:
+*          PARAMETERS:
+*            uchar *Y         Pointer to bytes array
+*
+*          RETURN:
+*
+*
+*  REVISION HISTORY:
+*
+*  24 Sep 94    KPZ             Initial release
+*  14 Oct 94    GKL     Second version (big endian support)
+*
+****************************************************************************/
+
+void  LongByte( u_int32_t *X,
+                               u_int32_t X_bytes,
+                uchar  *Y )
+{
+    u_int32_t i, j;              /* counters */
+    for ( i=0, j=0; j < X_bytes; i++, j += 4)
+    {
+            Y[j] = (uchar ) ( X[i] & 0xff );
+        Y[j+1] = (uchar)( (X[i] >> 8) & 0xff );
+        Y[j+2] = (uchar)( (X[i] >> 16) & 0xff );
+               Y[j+3] = (uchar)( (X[i] >> 24) & 0xff );
+    }
+}
+
+
diff --git a/lib/bind/cylink/bn.c b/lib/bind/cylink/bn.c
new file mode 100644 (file)
index 0000000..6685dca
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/*
+ * bn.c - the high-level bignum interface
+ *
+ * Copyright (c) 1995  Colin Plumb.  All rights reserved.
+ * For licensing and other legal details, see the file legal.c.
+ */
+
+#include "port_before.h"
+#include "bn.h"
+#include "port_after.h"
+
+/* Functions */
+void
+bnBegin(struct BigNum *bn)
+{
+       static int bninit = 0;
+
+       if (!bninit) {
+               bnInit();
+               bninit = 1;
+       }
+
+       bn->ptr = 0;
+       bn->size = 0;
+       bn->allocated = 0;
+}
+
+void
+bnSwap(struct BigNum *a, struct BigNum *b)
+{
+       void *p;
+       unsigned t;
+
+       p = a->ptr;
+       a->ptr = b->ptr;
+       b->ptr = p;
+
+       t = a->size;
+       a->size = b->size;
+       b->size = t;
+
+       t = a->allocated;
+       a->allocated = b->allocated;
+       b->allocated = t;
+}
+
+void (*bnEnd)(struct BigNum *bn);
+int (*bnPrealloc)(struct BigNum *bn, unsigned bits);
+int (*bnCopy)(struct BigNum *dest, struct BigNum const *src);
+void (*bnNorm)(struct BigNum *bn);
+void (*bnExtractBigBytes)(struct BigNum const *bn, unsigned char *dest,
+       unsigned lsbyte, unsigned len);
+int (*bnInsertBigBytes)(struct BigNum *bn, unsigned char const *src,
+       unsigned lsbyte, unsigned len);
+void (*bnExtractLittleBytes)(struct BigNum const *bn, unsigned char *dest,
+       unsigned lsbyte, unsigned len);
+int (*bnInsertLittleBytes)(struct BigNum *bn, unsigned char const *src,
+       unsigned lsbyte, unsigned len);
+unsigned (*bnLSWord)(struct BigNum const *src);
+unsigned (*bnBits)(struct BigNum const *src);
+int (*bnAdd)(struct BigNum *dest, struct BigNum const *src);
+int (*bnSub)(struct BigNum *dest, struct BigNum const *src);
+int (*bnCmpQ)(struct BigNum const *a, unsigned b);
+int (*bnSetQ)(struct BigNum *dest, unsigned src);
+int (*bnAddQ)(struct BigNum *dest, unsigned src);
+int (*bnSubQ)(struct BigNum *dest, unsigned src);
+int (*bnCmp)(struct BigNum const *a, struct BigNum const *b);
+int (*bnSquare)(struct BigNum *dest, struct BigNum const *src);
+int (*bnMul)(struct BigNum *dest, struct BigNum const *a,
+       struct BigNum const *b);
+int (*bnMulQ)(struct BigNum *dest, struct BigNum const *a, unsigned b);
+int (*bnDivMod)(struct BigNum *q, struct BigNum *r, struct BigNum const *n,
+       struct BigNum const *d);
+int (*bnMod)(struct BigNum *dest, struct BigNum const *src,
+       struct BigNum const *d);
+unsigned (*bnModQ)(struct BigNum const *src, unsigned d);
+int (*bnExpMod)(struct BigNum *result, struct BigNum const *n,
+       struct BigNum const *exp, struct BigNum const *mod);
+int (*bnDoubleExpMod)(struct BigNum *dest,
+       struct BigNum const *n1, struct BigNum const *e1,
+       struct BigNum const *n2, struct BigNum const *e2,
+       struct BigNum const *mod);
+int (*bnTwoExpMod)(struct BigNum *n, struct BigNum const *exp,
+       struct BigNum const *mod);
+int (*bnGcd)(struct BigNum *dest, struct BigNum const *a,
+       struct BigNum const *b);
+int (*bnInv)(struct BigNum *dest, struct BigNum const *src,
+       struct BigNum const *mod);
+int (*bnLShift)(struct BigNum *dest, unsigned amt);
+void (*bnRShift)(struct BigNum *dest, unsigned amt);
+unsigned (*bnMakeOdd)(struct BigNum *n);
diff --git a/lib/bind/cylink/bn.h b/lib/bind/cylink/bn.h
new file mode 100644 (file)
index 0000000..a0029cd
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/*
+ * bn.h - the interface to the bignum routines.
+ * All functions which return ints can potentially allocate memory
+ * and return -1 if they are unable to. All "const" arguments
+ * are unmodified.
+ *
+ * This is not particularly asymmetric, as some operations are of the
+ * form a = b @ c, while others do a @= b.  In general, outputs may not
+ * point to the same struct BigNums as inputs, except as specified
+ * below.  This relationship is referred to as "being the same as".
+ * This is not numerical equivalence.
+ *
+ * The "Q" operations take "unsigned" inputs.  Higher values of the
+ * extra input may work on some implementations, but 65535 is the
+ * highest portable value.  Just because UNSIGNED_MAX is larger than
+ * that, or you know that the word size of the library is larger than that,
+ * that, does *not* mean it's allowed.
+ */
+#ifndef BN_H
+#define BN_H
+
+struct BigNum {
+       void *ptr;
+       unsigned size;  /* Note: in (variable-sized) words */
+       unsigned allocated;
+};
+
+/* Functions */
+
+/*
+ * You usually never have to call this function explicitly, as
+ * bnBegin() takes care of it.  If the program jumps to address 0,
+ * this function has bot been called.
+ */
+void bnInit(void);
+
+/*
+ * This initializes an empty struct BigNum to a zero value.
+ * Do not use this on a BigNum which has had a value stored in it!
+ */
+void bnBegin(struct BigNum *bn);
+
+/* Swap two BigNums.  Cheap. */
+void bnSwap(struct BigNum *a, struct BigNum *b);
+
+/* Reset an initialized bigNum to empty, pending deallocation. */
+extern void (*bnEnd)(struct BigNum *bn);
+
+/*
+ * If you know you'll need space in the number soon, you can use this function
+ * to ensure that there is room for at least "bits" bits.  Optional.
+ * Returns <0 on out of memory, but the value is unaffected.
+ */
+extern int (*bnPrealloc)(struct BigNum *bn, unsigned bits);
+
+/* Hopefully obvious.  dest = src.   dest may be the same as src. */
+extern int (*bnCopy)(struct BigNum *dest, struct BigNum const *src);
+
+/*
+ * Mostly done automatically, but this removes leading zero words from
+ * the internal representation of the BigNum.  Use is unclear.
+ */
+extern void (*bnNorm)(struct BigNum *bn);
+
+/*
+ * Move bytes between the given buffer and the given BigNum encoded in
+ * base 256.  I.e. after either of these, the buffer will be equal to
+ * (bn / 256^lsbyte) % 256^len.  The difference is which is altered to
+ * match the other!
+ */
+extern void (*bnExtractBigBytes)(struct BigNum const *bn,
+       unsigned char *dest, unsigned lsbyte, unsigned len);
+extern int (*bnInsertBigBytes)(struct BigNum *bn, unsigned char const *src,
+       unsigned lsbyte, unsigned len);
+
+/* The same, but the buffer is little-endian. */
+extern void (*bnExtractLittleBytes)(struct BigNum const *bn,
+       unsigned char *dest, unsigned lsbyte, unsigned len);
+extern int (*bnInsertLittleBytes)(struct BigNum *bn, unsigned char const *src,
+       unsigned lsbyte, unsigned len);
+
+/* Return the least-significant bits (at least 16) of the BigNum */
+extern unsigned (*bnLSWord)(struct BigNum const *src);
+
+/*
+ * Return the number of significant bits in the BigNum.
+ * 0 or 1+floor(log2(src))
+ */
+extern unsigned (*bnBits)(struct BigNum const *src);
+
+/*
+ * dest += src.  dest and src may be the same.  Guaranteed not to
+ * allocate memory unnecessarily, so if you're sure bnBits(dest)
+ * won't change, you don't need to check the return value.
+ */
+extern int (*bnAdd)(struct BigNum *dest, struct BigNum const *src);
+
+/*
+ * dest -= src.  dest and src may be the same, but bnSetQ(dest, 0) is faster.
+ * if dest < src, returns +1 and sets dest = src-dest.
+ */
+extern int (*bnSub)(struct BigNum *dest, struct BigNum const *src);
+
+/* Return sign (-1, 0, +1) of a-b.  a <=> b --> bnCmpQ(a, b) <=> 0 */
+extern int (*bnCmpQ)(struct BigNum const *a, unsigned b);
+
+/* dest = src, where 0 <= src < 2^16. */
+extern int (*bnSetQ)(struct BigNum *dest, unsigned src);
+
+/* dest += src, where 0 <= src < 2^16 */
+extern int (*bnAddQ)(struct BigNum *dest, unsigned src);
+
+/* dest -= src, where 0 <= src < 2^16 */
+extern int (*bnSubQ)(struct BigNum *dest, unsigned src);
+
+/* Return sign (-1, 0, +1) of a-b.  a <=> b --> bnCmp(a, b) <=> 0 */
+extern int (*bnCmp)(struct BigNum const *a, struct BigNum const *b);
+
+/* dest = src^2.  dest may be the same as src, but it costs time. */
+extern int (*bnSquare)(struct BigNum *dest, struct BigNum const *src);
+
+/* dest = a * b.  dest may be the same as a or b, but it costs time. */
+extern int (*bnMul)(struct BigNum *dest, struct BigNum const *a,
+       struct BigNum const *b);
+
+/* dest = a * b, where 0 <= b < 2^16.  dest and a may be the same. */
+extern int (*bnMulQ)(struct BigNum *dest, struct BigNum const *a, unsigned b);
+
+/*
+ * q = n/d, r = n%d.  r may be the same as n, but not d,
+ * and q may not be the same as n or d.
+ * re-entrancy issue: this temporarily modifies d, but restores
+ * it for return.
+ */
+extern int (*bnDivMod)(struct BigNum *q, struct BigNum *r,
+       struct BigNum const *n, struct BigNum const *d);
+/*
+ * dest = src % d.  dest and src may be the same, but not dest and d.
+ * re-entrancy issue: this temporarily modifies d, but restores
+ * it for return.
+ */
+extern int (*bnMod)(struct BigNum *dest, struct BigNum const *src,
+       struct BigNum const *d);
+
+/* return src % d, where 0 <= d < 2^16.  */
+extern unsigned int (*bnModQ)(struct BigNum const *src, unsigned d);
+
+/* n = n^exp, modulo "mod"   "mod" *must* be odd */
+extern int (*bnExpMod)(struct BigNum *result, struct BigNum const *n,
+       struct BigNum const *exp, struct BigNum const *mod);
+
+/*
+ * dest = n1^e1 * n2^e2, modulo "mod".  "mod" *must* be odd.
+ * dest may be the same as n1 or n2.
+ */
+extern int (*bnDoubleExpMod)(struct BigNum *dest,
+       struct BigNum const *n1, struct BigNum const *e1,
+       struct BigNum const *n2, struct BigNum const *e2,
+       struct BigNum const *mod);
+
+/* n = 2^exp, modulo "mod"   "mod" *must* be odd */
+extern int (*bnTwoExpMod)(struct BigNum *n, struct BigNum const *exp,
+       struct BigNum const *mod);
+
+/* dest = gcd(a, b).  The inputs may overlap arbitrarily. */
+extern int (*bnGcd)(struct BigNum *dest, struct BigNum const *a,
+       struct BigNum const *b);
+
+/* dest = src^-1, modulo "mod".  dest may be the same as src. */
+extern int (*bnInv)(struct BigNum *dest, struct BigNum const *src,
+       struct BigNum const *mod);
+
+/* Shift dest left "amt" places */
+extern int (*bnLShift)(struct BigNum *dest, unsigned amt);
+/* Shift dest right "amt" places, discarding low-order bits */
+extern void (*bnRShift)(struct BigNum *dest, unsigned amt);
+
+/* For the largest 2^k that divides n, divide n by it and return k. */
+extern unsigned (*bnMakeOdd)(struct BigNum *n);
+
+#endif/* !BN_H */
diff --git a/lib/bind/cylink/bn00.c b/lib/bind/cylink/bn00.c
new file mode 100644 (file)
index 0000000..bf02d2c
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/*
+ * bn00.c - auto-size-detecting bn??.c file.
+ *
+ * Written in 1995 by Colin Plumb.
+ */
+
+#include "port_before.h"
+#include "bnsize00.h"
+
+#if BNSIZE64
+
+/* Include all of the C source file by reference */
+#include "bn64.c"
+#include "bninit64.c"
+
+#elif BNSIZE32
+
+/* Include all of the C source file by reference */
+#include "bn32.c"
+#include "bninit32.c"
+
+#else /* BNSIZE16 */
+
+/* Include all of the C source file by reference */
+#include "bn16.c"
+#include "bninit16.c"
+
+#endif
diff --git a/lib/bind/cylink/bn16.c b/lib/bind/cylink/bn16.c
new file mode 100644 (file)
index 0000000..6d9c3a6
--- /dev/null
@@ -0,0 +1,949 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/*
+ * bn16.c - the high-level bignum interface
+ *
+ * Like lbn16.c, this reserves the string "16" for textual replacement.
+ * The string must not appear anywhere unless it is intended to be replaced
+ * to generate other bignum interface functions.
+ *
+ * Copyright (c) 1995  Colin Plumb.  All rights reserved.
+ * For licensing and other legal details, see the file legal.c.
+ */
+
+#ifndef HAVE_CONFIG_H
+#define HAVE_CONFIG_H 0
+#endif
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/*
+ * Some compilers complain about #if FOO if FOO isn't defined,
+ * so do the ANSI-mandated thing explicitly...
+ */
+#ifndef NO_ASSERT_H
+#define NO_ASSERT_H 0
+#endif
+#ifndef NO_STRING_H
+#define NO_STRING_H 0
+#endif
+#ifndef HAVE_STRINGS_H
+#define HAVE_STRINGS_H 0
+#endif
+#ifndef NEED_MEMORY_H
+#define NEED_MEMORY_H 0
+#endif
+
+#if !NO_ASSERT_H
+#include <assert.h>
+#else
+#define assert(x) (void)0
+#endif
+
+#if !NO_STRING_H
+#include <string.h>    /* for memmove() in bnMakeOdd */
+#elif HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#if NEED_MEMORY_H
+#include <memory.h>
+#endif
+
+/*
+ * This was useful during debugging, so it's left in here.
+ * You can ignore it.  DBMALLOC is generally undefined.
+ */
+#ifndef DBMALLOC
+#define DBAMLLOC 0
+#endif
+#if DBMALLOC
+#include "../dbmalloc/malloc.h"
+#define MALLOCDB malloc_chain_check(1)
+#else
+#define MALLOCDB (void)0
+#endif
+
+#include "lbn.h"
+#include "lbn16.h"
+#include "lbnmem.h"
+#include "bn16.h"
+#include "bn.h"
+
+/* Work-arounds for some particularly broken systems */
+#include "kludge.h"    /* For memmove() */
+#include <port_after.h>
+
+/* Functions */
+void
+bnInit_16(void)
+{
+       bnEnd = bnEnd_16;
+       bnPrealloc = bnPrealloc_16;
+       bnCopy = bnCopy_16;
+       bnNorm = bnNorm_16;
+       bnExtractBigBytes = bnExtractBigBytes_16;
+       bnInsertBigBytes = bnInsertBigBytes_16;
+       bnExtractLittleBytes = bnExtractLittleBytes_16;
+       bnInsertLittleBytes = bnInsertLittleBytes_16;
+       bnLSWord = bnLSWord_16;
+       bnBits = bnBits_16;
+       bnAdd = bnAdd_16;
+       bnSub = bnSub_16;
+       bnCmpQ = bnCmpQ_16;
+       bnSetQ = bnSetQ_16;
+       bnAddQ = bnAddQ_16;
+       bnSubQ = bnSubQ_16;
+       bnCmp = bnCmp_16;
+       bnSquare = bnSquare_16;
+       bnMul = bnMul_16;
+       bnMulQ = bnMulQ_16;
+       bnDivMod = bnDivMod_16;
+       bnMod = bnMod_16;
+       bnModQ = bnModQ_16;
+       bnExpMod = bnExpMod_16;
+       bnDoubleExpMod = bnDoubleExpMod_16;
+       bnTwoExpMod = bnTwoExpMod_16;
+       bnGcd = bnGcd_16;
+       bnInv = bnInv_16;
+       bnLShift = bnLShift_16;
+       bnRShift = bnRShift_16;
+       bnMakeOdd = bnMakeOdd_16;
+}
+
+void
+bnEnd_16(struct BigNum *bn)
+{
+       if (bn->ptr) {
+               LBNFREE((BNWORD16 *)bn->ptr, bn->allocated);
+               bn->ptr = 0;
+       }
+       bn->size = 0;
+       bn->allocated = 0;
+
+       MALLOCDB;
+}
+
+/* Internal function.  It operates in words. */
+static int
+bnResize_16(struct BigNum *bn, unsigned len)
+{
+       void *p;
+
+       /* Round size up: most mallocs impose 8-byte granularity anyway */
+       len = (len + (8/sizeof(BNWORD16) - 1)) & ~(8/sizeof(BNWORD16) - 1);
+       p = LBNREALLOC((BNWORD16 *)bn->ptr, bn->allocated, len);
+       if (!p)
+               return -1;
+       bn->ptr = p;
+       bn->allocated = len;
+
+       MALLOCDB;
+
+       return 0;
+}
+
+#define bnSizeCheck(bn, size) \
+       if (bn->allocated < size && bnResize_16(bn, size) < 0) \
+               return -1
+
+int
+bnPrealloc_16(struct BigNum *bn, unsigned bits)
+{
+       bits = (bits + 16-1)/16;
+       bnSizeCheck(bn, bits);
+       MALLOCDB;
+       return 0;
+}
+
+int
+bnCopy_16(struct BigNum *dest, struct BigNum const *src)
+{
+       bnSizeCheck(dest, src->size);
+       dest->size = src->size;
+       lbnCopy_16((BNWORD16 *)dest->ptr, (BNWORD16 *)src->ptr, src->size);
+       MALLOCDB;
+       return 0;
+}
+
+void
+bnNorm_16(struct BigNum *bn)
+{
+       bn->size = lbnNorm_16((BNWORD16 *)bn->ptr, bn->size);
+}
+
+/*
+ * Convert a bignum to big-endian bytes.  Returns, in big-endian form, a
+ * substring of the bignum starting from lsbyte and "len" bytes long.
+ * Unused high-order (leading) bytes are filled with 0.
+ */
+void
+bnExtractBigBytes_16(struct BigNum const *bn, unsigned char *dest,
+                  unsigned lsbyte, unsigned len)
+{
+       unsigned s = bn->size * (16 / 8);
+
+       /* Fill unused leading bytes with 0 */
+       while (s < lsbyte+len) {
+               *dest++ = 0;
+               len--;
+       }
+
+       if (len)
+               lbnExtractBigBytes_16((BNWORD16 *)bn->ptr, dest, lsbyte, len);
+       MALLOCDB;
+}
+
+int
+bnInsertBigBytes_16(struct BigNum *bn, unsigned char const *src,
+                 unsigned lsbyte, unsigned len)
+{
+       unsigned s = bn->size;
+       unsigned words = (len+lsbyte+sizeof(BNWORD16)-1) / sizeof(BNWORD16);
+
+       /* Pad with zeros as required */
+       bnSizeCheck(bn, words);
+
+       if (s < words) {
+               lbnZero_16((BNWORD16 *)bn->ptr BIGLITTLE(-s,+s), words-s);
+               s = words;
+       }
+
+       lbnInsertBigBytes_16((BNWORD16 *)bn->ptr, src, lsbyte, len);
+
+       bn->size = lbnNorm_16((BNWORD16 *)bn->ptr, s);
+
+       MALLOCDB;
+       return 0;
+}
+
+
+/*
+ * Convert a bignum to little-endian bytes.  Returns, in little-endian form, a
+ * substring of the bignum starting from lsbyte and "len" bytes long.
+ * Unused high-order (trailing) bytes are filled with 0.
+ */
+void
+bnExtractLittleBytes_16(struct BigNum const *bn, unsigned char *dest,
+                  unsigned lsbyte, unsigned len)
+{
+       unsigned s = bn->size * (16 / 8);
+
+       /* Fill unused leading bytes with 0 */
+       while (s < lsbyte+len)
+               dest[--len] = 0;
+
+       if (len)
+               lbnExtractLittleBytes_16((BNWORD16 *)bn->ptr, dest,
+                                        lsbyte, len);
+       MALLOCDB;
+}
+
+int
+bnInsertLittleBytes_16(struct BigNum *bn, unsigned char const *src,
+                       unsigned lsbyte, unsigned len)
+{
+       unsigned s = bn->size;
+       unsigned words = (len+lsbyte+sizeof(BNWORD16)-1) / sizeof(BNWORD16);
+
+       /* Pad with zeros as required */
+       bnSizeCheck(bn, words);
+
+       if (s < words) {
+               lbnZero_16((BNWORD16 *)bn->ptr BIGLITTLE(-s,+s), words-s);
+               s = words;
+       }
+
+       lbnInsertLittleBytes_16((BNWORD16 *)bn->ptr, src, lsbyte, len);
+
+       bn->size = lbnNorm_16((BNWORD16 *)bn->ptr, s);
+
+       MALLOCDB;
+       return 0;
+}
+
+/* Return the least-significant word of the input. */
+unsigned
+bnLSWord_16(struct BigNum const *src)
+{
+       return src->size ? (unsigned)((BNWORD16 *)src->ptr)[BIGLITTLE(-1,0)]: 0;
+}
+
+unsigned
+bnBits_16(struct BigNum const *src)
+{
+       return lbnBits_16((BNWORD16 *)src->ptr, src->size);
+}
+
+int
+bnAdd_16(struct BigNum *dest, struct BigNum const *src)
+{
+       unsigned s = src->size, d = dest->size;
+       BNWORD16 t;
+
+       if (!s)
+               return 0;
+
+       bnSizeCheck(dest, s);
+
+       if (d < s) {
+               lbnZero_16((BNWORD16 *)dest->ptr BIGLITTLE(-d,+d), s-d);
+               dest->size = d = s;
+               MALLOCDB;
+       }
+       t = lbnAddN_16((BNWORD16 *)dest->ptr, (BNWORD16 *)src->ptr, s);
+       MALLOCDB;
+       if (t) {
+               if (d > s) {
+                       t = lbnAdd1_16((BNWORD16 *)dest->ptr BIGLITTLE(-s,+s),
+                                      d-s, t);
+                       MALLOCDB;
+               }
+               if (t) {
+                       bnSizeCheck(dest, d+1);
+                       ((BNWORD16 *)dest->ptr)[BIGLITTLE(-1-d,d)] = t;
+                       dest->size = d+1;
+               }
+       }
+       return 0;
+}
+
+/*
+ * dest -= src.
+ * If dest goes negative, this produces the absolute value of
+ * the difference (the negative of the true value) and returns 1.
+ * Otherwise, it returls 0.
+ */
+int
+bnSub_16(struct BigNum *dest, struct BigNum const *src)
+{
+       unsigned s = src->size, d = dest->size;
+       BNWORD16 t;
+
+       if (d < s  &&  d < (s = lbnNorm_16((BNWORD16 *)src->ptr, s))) {
+               bnSizeCheck(dest, s);
+               lbnZero_16((BNWORD16 *)dest->ptr BIGLITTLE(-d,+d), s-d);
+               dest->size = d = s;
+               MALLOCDB;
+       }
+       if (!s)
+               return 0;
+       t = lbnSubN_16((BNWORD16 *)dest->ptr, (BNWORD16 *)src->ptr, s);
+       MALLOCDB;
+       if (t) {
+               if (d > s) {
+                       t = lbnSub1_16((BNWORD16 *)dest->ptr BIGLITTLE(-s,+s),
+                                      d-s, t);
+                       MALLOCDB;
+               }
+               if (t) {
+                       lbnNeg_16((BNWORD16 *)dest->ptr, d);
+                       dest->size = lbnNorm_16((BNWORD16 *)dest->ptr,
+                                               dest->size);
+                       MALLOCDB;
+                       return 1;
+               }
+       }
+       dest->size = lbnNorm_16((BNWORD16 *)dest->ptr, dest->size);
+       return 0;
+}
+
+/*
+ * Compare the BigNum to the given value, which must be < 65536.
+ * Returns -1. 0 or 1 if a<b, a == b or a>b.
+ * a <=> b --> bnCmpQ(a,b) <=> 0
+ */
+int
+bnCmpQ_16(struct BigNum const *a, unsigned b)
+{
+       unsigned t;
+       BNWORD16 v;
+
+       t = lbnNorm_16((BNWORD16 *)a->ptr, a->size);
+       /* If a is more than one word long or zero, it's easy... */
+       if (t != 1)
+               return (t > 1) ? 1 : (b ? -1 : 0);
+       v = (unsigned)((BNWORD16 *)a->ptr)[BIGLITTLE(-1,0)];
+       return (v > b) ? 1 : ((v < b) ? -1 : 0);
+}
+
+int
+bnSetQ_16(struct BigNum *dest, unsigned src)
+{
+       if (src) {
+               bnSizeCheck(dest, 1);
+
+               ((BNWORD16 *)dest->ptr)[BIGLITTLE(-1,0)] = (BNWORD16)src;
+               dest->size = 1;
+       } else {
+               dest->size = 0;
+       }
+       return 0;
+}
+
+int
+bnAddQ_16(struct BigNum *dest, unsigned src)
+{
+       BNWORD16 t;
+
+       if (!dest->size)
+               return bnSetQ(dest, src);
+       
+       t = lbnAdd1_16((BNWORD16 *)dest->ptr, dest->size, (BNWORD16)src);
+       MALLOCDB;
+       if (t) {
+               src = dest->size;
+               bnSizeCheck(dest, src+1);
+               ((BNWORD16 *)dest->ptr)[BIGLITTLE(-1-src,src)] = t;
+               dest->size = src+1;
+       }
+       return 0;
+}
+
+/*
+ * Return value as for bnSub: 1 if subtract underflowed, in which
+ * case the return is the negative of the computed value.
+ */
+int
+bnSubQ_16(struct BigNum *dest, unsigned src)
+{
+       BNWORD16 t;
+
+       if (!dest->size)
+               return bnSetQ(dest, src) < 0 ? -1 : (src != 0);
+
+       t = lbnSub1_16((BNWORD16 *)dest->ptr, dest->size, (BNWORD16)src);
+       MALLOCDB;
+       if (t) {
+               /* Underflow. <= 1 word, so do it simply. */
+               lbnNeg_16((BNWORD16 *)dest->ptr, 1);
+               dest->size = 1;
+               return 1;
+       }
+/* Try to normalize?  Needing this is going to be very rare. */
+/*             dest->size = lbnNorm_16((BNWORD16 *)dest->ptr, dest->size); */
+       return 0;
+}
+
+/*
+ * Compare two BigNums.  Returns -1. 0 or 1 if a<b, a == b or a>b.
+ * a <=> b --> bnCmp(a,b) <=> 0
+ */
+int
+bnCmp_16(struct BigNum const *a, struct BigNum const *b)
+{
+       unsigned s, t;
+
+       s = lbnNorm_16((BNWORD16 *)a->ptr, a->size);
+       t = lbnNorm_16((BNWORD16 *)b->ptr, b->size);
+       
+       if (s != t)
+               return s > t ? 1 : -1;
+       return lbnCmp_16((BNWORD16 *)a->ptr, (BNWORD16 *)b->ptr, s);
+}
+
+int
+bnSquare_16(struct BigNum *dest, struct BigNum const *src)
+{
+       unsigned s;
+       BNWORD16 *srcbuf;
+
+       s = lbnNorm_16((BNWORD16 *)src->ptr, src->size);
+       if (!s) {
+               dest->size = 0;
+               return 0;
+       }
+       bnSizeCheck(dest, 2*s);
+
+       if (src == dest) {
+               LBNALLOC(srcbuf, s);
+               if (!srcbuf)
+                       return -1;
+               lbnCopy_16(srcbuf, (BNWORD16 *)src->ptr, s);
+               lbnSquare_16((BNWORD16 *)dest->ptr, (BNWORD16 *)srcbuf, s);
+               LBNFREE(srcbuf, s);
+       } else {
+               lbnSquare_16((BNWORD16 *)dest->ptr, (BNWORD16 *)src->ptr, s);
+       }
+
+       dest->size = lbnNorm_16((BNWORD16 *)dest->ptr, 2*s);
+       MALLOCDB;
+       return 0;
+}
+
+int
+bnMul_16(struct BigNum *dest, struct BigNum const *a, struct BigNum const *b)
+{
+       unsigned s, t;
+       BNWORD16 *srcbuf;
+
+       s = lbnNorm_16((BNWORD16 *)a->ptr, a->size);
+       t = lbnNorm_16((BNWORD16 *)b->ptr, b->size);
+
+       if (!s || !t) {
+               dest->size = 0;
+               return 0;
+       }
+
+       if (a == b)
+               return bnSquare_16(dest, a);
+
+       bnSizeCheck(dest, s+t);
+
+       if (dest == a) {
+               LBNALLOC(srcbuf, s);
+               if (!srcbuf)
+                       return -1;
+               lbnCopy_16(srcbuf, (BNWORD16 *)a->ptr, s);
+               lbnMul_16((BNWORD16 *)dest->ptr, srcbuf, s,
+                                                (BNWORD16 *)b->ptr, t);
+               LBNFREE(srcbuf, s);
+       } else if (dest == b) {
+               LBNALLOC(srcbuf, t);
+               if (!srcbuf)
+                       return -1;
+               lbnCopy_16(srcbuf, (BNWORD16 *)b->ptr, t);
+               lbnMul_16((BNWORD16 *)dest->ptr, (BNWORD16 *)a->ptr, s,
+                                                srcbuf, t);
+               LBNFREE(srcbuf, t);
+       } else {
+               lbnMul_16((BNWORD16 *)dest->ptr, (BNWORD16 *)a->ptr, s,
+                                                (BNWORD16 *)b->ptr, t);
+       }
+       dest->size = lbnNorm_16((BNWORD16 *)dest->ptr, s+t);
+       MALLOCDB;
+       return 0;
+}
+
+int
+bnMulQ_16(struct BigNum *dest, struct BigNum const *a, unsigned b)
+{
+       unsigned s;
+
+       s = lbnNorm_16((BNWORD16 *)a->ptr, a->size);
+       if (!s || !b) {
+               dest->size = 0;
+               return 0;
+       }
+       if (b == 1)
+               return bnCopy_16(dest, a);
+       bnSizeCheck(dest, s+1);
+       lbnMulN1_16((BNWORD16 *)dest->ptr, (BNWORD16 *)a->ptr, s, (BNWORD16)b);
+       dest->size = lbnNorm_16((BNWORD16 *)dest->ptr, s+1);
+       MALLOCDB;
+       return 0;
+}
+
+int
+bnDivMod_16(struct BigNum *q, struct BigNum *r, struct BigNum const *n,
+            struct BigNum const *d)
+{
+       unsigned dsize, nsize;
+       BNWORD16 qhigh;
+
+       dsize = lbnNorm_16((BNWORD16 *)d->ptr, d->size);
+       nsize = lbnNorm_16((BNWORD16 *)n->ptr, n->size);
+
+       if (nsize < dsize) {
+               q->size = 0;    /* No quotient */
+               r->size = nsize;
+               return 0;       /* Success */
+       }
+
+       bnSizeCheck(q, nsize-dsize);
+
+       if (r != n) {   /* You are allowed to reduce in place */
+               bnSizeCheck(r, nsize);
+               lbnCopy_16((BNWORD16 *)r->ptr, (BNWORD16 *)n->ptr, nsize);
+       }
+               
+       qhigh = lbnDiv_16((BNWORD16 *)q->ptr, (BNWORD16 *)r->ptr, nsize,
+                         (BNWORD16 *)d->ptr, dsize);
+       nsize -= dsize;
+       if (qhigh) {
+               bnSizeCheck(q, nsize+1);
+               *((BNWORD16 *)q->ptr BIGLITTLE(-nsize-1,+nsize)) = qhigh;
+               q->size = nsize+1;
+       } else {
+               q->size = lbnNorm_16((BNWORD16 *)q->ptr, nsize);
+       }
+       r->size = lbnNorm_16((BNWORD16 *)r->ptr, dsize);
+       MALLOCDB;
+       return 0;
+}
+
+int
+bnMod_16(struct BigNum *dest, struct BigNum const *src, struct BigNum const *d)
+{
+       unsigned dsize, nsize;
+
+       nsize = lbnNorm_16((BNWORD16 *)src->ptr, src->size);
+       dsize = lbnNorm_16((BNWORD16 *)d->ptr, d->size);
+
+
+       if (dest != src) {
+               bnSizeCheck(dest, nsize);
+               lbnCopy_16((BNWORD16 *)dest->ptr, (BNWORD16 *)src->ptr, nsize);
+       }
+
+       if (nsize < dsize) {
+               dest->size = nsize;     /* No quotient */
+               return 0;
+       }
+
+       (void)lbnDiv_16((BNWORD16 *)dest->ptr BIGLITTLE(-dsize,+dsize),
+                       (BNWORD16 *)dest->ptr, nsize,
+                       (BNWORD16 *)d->ptr, dsize);
+       dest->size = lbnNorm_16((BNWORD16 *)dest->ptr, dsize);
+       MALLOCDB;
+       return 0;
+}
+
+unsigned
+bnModQ_16(struct BigNum const *src, unsigned d)
+{
+       unsigned s;
+
+       s = lbnNorm_16((BNWORD16 *)src->ptr, src->size);
+       if (!s)
+               return 0;
+       
+       return lbnModQ_16((BNWORD16 *)src->ptr, s, d);
+}
+
+int
+bnExpMod_16(struct BigNum *dest, struct BigNum const *n,
+       struct BigNum const *exp, struct BigNum const *mod)
+{
+       unsigned nsize, esize, msize;
+
+       nsize = lbnNorm_16((BNWORD16 *)n->ptr, n->size);
+       esize = lbnNorm_16((BNWORD16 *)exp->ptr, exp->size);
+       msize = lbnNorm_16((BNWORD16 *)mod->ptr, mod->size);
+
+       if (!msize || (((BNWORD16 *)mod->ptr)[BIGLITTLE(-1,0)] & 1) == 0)
+               return -1;      /* Illegal modulus! */
+
+       bnSizeCheck(dest, msize);
+
+       /* Special-case base of 2 */
+       if (nsize == 1 && ((BNWORD16 *)n->ptr)[BIGLITTLE(-1,0)] == 2) {
+               if (lbnTwoExpMod_16((BNWORD16 *)dest->ptr,
+                                   (BNWORD16 *)exp->ptr, esize,
+                                   (BNWORD16 *)mod->ptr, msize) < 0)
+                       return -1;
+       } else {
+               if (lbnExpMod_16((BNWORD16 *)dest->ptr,
+                                (BNWORD16 *)n->ptr, nsize,
+                                (BNWORD16 *)exp->ptr, esize,
+                                (BNWORD16 *)mod->ptr, msize) < 0)
+               return -1;
+       }
+
+       dest->size = lbnNorm_16((BNWORD16 *)dest->ptr, msize);
+       MALLOCDB;
+       return 0;
+}
+
+int
+bnDoubleExpMod_16(struct BigNum *dest,
+       struct BigNum const *n1, struct BigNum const *e1,
+       struct BigNum const *n2, struct BigNum const *e2,
+       struct BigNum const *mod)
+{
+       unsigned n1size, e1size, n2size, e2size, msize;
+
+       n1size = lbnNorm_16((BNWORD16 *)n1->ptr, n1->size);
+       e1size = lbnNorm_16((BNWORD16 *)e1->ptr, e1->size);
+       n2size = lbnNorm_16((BNWORD16 *)n2->ptr, n2->size);
+       e2size = lbnNorm_16((BNWORD16 *)e2->ptr, e2->size);
+       msize = lbnNorm_16((BNWORD16 *)mod->ptr, mod->size);
+
+       if (!msize || (((BNWORD16 *)mod->ptr)[BIGLITTLE(-1,0)] & 1) == 0)
+               return -1;      /* Illegal modulus! */
+
+       bnSizeCheck(dest, msize);
+
+       if (lbnDoubleExpMod_16((BNWORD16 *)dest->ptr,
+               (BNWORD16 *)n1->ptr, n1size, (BNWORD16 *)e1->ptr, e1size,
+               (BNWORD16 *)n2->ptr, n2size, (BNWORD16 *)e2->ptr, e2size,
+               (BNWORD16 *)mod->ptr, msize) < 0)
+               return -1;
+
+       dest->size = lbnNorm_16((BNWORD16 *)dest->ptr, msize);
+       MALLOCDB;
+       return 0;
+}
+
+int
+bnTwoExpMod_16(struct BigNum *n, struct BigNum const *exp,
+       struct BigNum const *mod)
+{
+       unsigned esize, msize;
+
+       esize = lbnNorm_16((BNWORD16 *)exp->ptr, exp->size);
+       msize = lbnNorm_16((BNWORD16 *)mod->ptr, mod->size);
+
+       if (!msize || (((BNWORD16 *)mod->ptr)[BIGLITTLE(-1,0)] & 1) == 0)
+               return -1;      /* Illegal modulus! */
+
+       bnSizeCheck(n, msize);
+
+       if (lbnTwoExpMod_16((BNWORD16 *)n->ptr, (BNWORD16 *)exp->ptr, esize,
+                           (BNWORD16 *)mod->ptr, msize) < 0)
+               return -1;
+
+       n->size = lbnNorm_16((BNWORD16 *)n->ptr, msize);
+       MALLOCDB;
+       return 0;
+}
+
+int
+bnGcd_16(struct BigNum *dest, struct BigNum const *a, struct BigNum const *b)
+{
+       BNWORD16 *tmp;
+       unsigned asize, bsize;
+       int i;
+
+       /* Kind of silly, but we might as well permit it... */
+       if (a == b)
+               return dest == a ? 0 : bnCopy(dest, a);
+
+       /* Ensure a is not the same as "dest" */
+       if (a == dest) {
+               a = b;
+               b = dest;
+       }
+
+       asize = lbnNorm_16((BNWORD16 *)a->ptr, a->size);
+       bsize = lbnNorm_16((BNWORD16 *)b->ptr, b->size);
+
+       bnSizeCheck(dest, bsize+1);
+
+       /* Copy a to tmp */
+       LBNALLOC(tmp, asize+1);
+       if (!tmp)
+               return -1;
+       lbnCopy_16(tmp, (BNWORD16 *)a->ptr, asize);
+
+       /* Copy b to dest,if necessary */
+       if (dest != b)
+               lbnCopy_16((BNWORD16 *)dest->ptr,
+                          (BNWORD16 *)b->ptr, bsize);
+       if (bsize > asize || (bsize == asize &&
+               lbnCmp_16((BNWORD16 *)b->ptr, (BNWORD16 *)a->ptr, asize) > 0))
+       {
+               i = lbnGcd_16((BNWORD16 *)dest->ptr, bsize, tmp, asize);
+               if (i >= 0) {
+                       dest->size = (unsigned)i;
+               } else {
+                       lbnCopy_16((BNWORD16 *)dest->ptr, tmp,
+                                  (unsigned)-i);
+                       dest->size = (unsigned)-i;
+               }
+       } else {
+               i = lbnGcd_16(tmp, asize, (BNWORD16 *)dest->ptr, bsize);
+               if (i <= 0) {
+                       dest->size = (unsigned)-i;
+               } else {
+                       lbnCopy_16((BNWORD16 *)dest->ptr, tmp,
+                                  (unsigned)i);
+                       dest->size = (unsigned)i;
+               }
+       }
+       LBNFREE(tmp, asize+1);
+       MALLOCDB;
+       return 0;
+}
+
+int
+bnInv_16(struct BigNum *dest, struct BigNum const *src,
+         struct BigNum const *mod)
+{
+       unsigned s, m;
+       int i;
+
+       s = lbnNorm_16((BNWORD16 *)src->ptr, src->size);
+       m = lbnNorm_16((BNWORD16 *)mod->ptr, mod->size);
+
+       /* lbnInv_16 requires that the input be less than the modulus */
+       if (m < s ||
+           (m==s && lbnCmp_16((BNWORD16 *)src->ptr, (BNWORD16 *)mod->ptr, s)))
+       {
+               bnSizeCheck(dest, s + (m==s));
+               if (dest != src)
+                       lbnCopy_16((BNWORD16 *)dest->ptr,
+                                  (BNWORD16 *)src->ptr, s);
+               /* Pre-reduce modulo the modulus */
+               (void)lbnDiv_16((BNWORD16 *)dest->ptr BIGLITTLE(-m,+m),
+                               (BNWORD16 *)dest->ptr, s,
+                               (BNWORD16 *)mod->ptr, m);
+               s = lbnNorm_16((BNWORD16 *)dest->ptr, m);
+               MALLOCDB;
+       } else {
+               bnSizeCheck(dest, m+1);
+               if (dest != src)
+                       lbnCopy_16((BNWORD16 *)dest->ptr,
+                                  (BNWORD16 *)src->ptr, s);
+       }
+
+       i = lbnInv_16((BNWORD16 *)dest->ptr, s, (BNWORD16 *)mod->ptr, m);
+       if (i == 0)
+               dest->size = lbnNorm_16((BNWORD16 *)dest->ptr, m);
+
+       MALLOCDB;
+       return i;
+}
+
+/*
+ * Shift a bignum left the appropriate number of bits,
+ * multiplying by 2^amt.
+ */
+int 
+bnLShift_16(struct BigNum *dest, unsigned amt)
+{
+       unsigned s = dest->size;
+       BNWORD16 carry;
+
+       if (amt % 16) {
+               carry = lbnLshift_16(dest->ptr, s, amt % 16);
+               if (carry) {
+                       s++;
+                       bnSizeCheck(dest, s);
+                       ((BNWORD16 *)dest->ptr)[BIGLITTLE(-s,s-1)] = carry;
+               }
+       }
+
+       amt /= 16;
+       if (amt) {
+               bnSizeCheck(dest, s+amt);
+               memmove((BNWORD16 *)dest->ptr BIGLITTLE(-s-amt, +amt),
+                       (BNWORD16 *)dest->ptr BIG(-s),
+                       s * sizeof(BNWORD16));
+               lbnZero_16((BNWORD16 *)dest->ptr, amt);
+               s += amt;
+       }
+       dest->size = s;
+       MALLOCDB;
+       return 0;
+}
+
+/*
+ * Shift a bignum right the appropriate number of bits,
+ * dividing by 2^amt.
+ */
+void bnRShift_16(struct BigNum *dest, unsigned amt)
+{
+       unsigned s = dest->size;
+
+       if (amt >= 16) {
+               memmove(
+                       (BNWORD16 *)dest->ptr BIG(-s+amt/16),
+                       (BNWORD16 *)dest->ptr BIGLITTLE(-s, +amt/16),
+                       s-amt/16 * sizeof(BNWORD16));
+               s -= amt/16;
+               amt %= 16;
+       }
+
+       if (amt)
+               (void)lbnRshift_16(dest->ptr, s, amt);
+
+       dest->size = lbnNorm_16(dest->ptr, s);
+       MALLOCDB;
+}
+
+/*
+ * Shift a bignum right until it is odd, and return the number of
+ * bits shifted.  n = d * 2^s.  Replaces n with d and returns s.
+ * Returns 0 when given 0.  (Another valid answer is infinity.)
+ */
+unsigned
+bnMakeOdd_16(struct BigNum *n)
+{
+       unsigned size;
+       unsigned s;     /* shift amount */
+       BNWORD16 *p;
+       BNWORD16 t;
+
+       p = (BNWORD16 *)n->ptr;
+       size = lbnNorm_16(p, n->size);
+       if (!size)
+               return 0;
+
+       t = BIGLITTLE(p[-1],p[0]);
+       s = 0;
+
+       /* See how many words we have to shift */
+       if (!t) {
+               /* Shift by words */
+               do {
+                       
+                       s++;
+                       BIGLITTLE(--p,p++);
+               } while ((t = BIGLITTLE(p[-1],p[0])) == 0);
+               size -= s;
+               s *= 16;
+               memmove((BNWORD16 *)n->ptr BIG(-size), p BIG(-size),
+                       size * sizeof(BNWORD16));
+               p = (BNWORD16 *)n->ptr;
+               MALLOCDB;
+       }
+
+       assert(t);
+
+       /* Now count the bits */
+       while ((t & 1) == 0) {
+               t >>= 1;
+               s++;
+       }
+
+       /* Shift the bits */
+       if (s & (16-1)) {
+               lbnRshift_16(p, size, s & (16-1));
+               /* Renormalize */
+               if (BIGLITTLE(*(p-size),*(p+(size-1))) == 0)
+                       --size;
+       }
+       n->size = size;
+
+       MALLOCDB;
+       return s;
+}
diff --git a/lib/bind/cylink/bn16.h b/lib/bind/cylink/bn16.h
new file mode 100644 (file)
index 0000000..fcf65bb
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/*
+ * bn16.h - interface to 16-bit bignum routines.
+ */
+struct BigNum;
+
+void bnInit_16(void);
+void bnEnd_16(struct BigNum *bn);
+int bnPrealloc_16(struct BigNum *bn, unsigned bits);
+int bnCopy_16(struct BigNum *dest, struct BigNum const *src);
+int bnSwap_16(struct BigNum *a, struct BigNum *b);
+void bnNorm_16(struct BigNum *bn);
+void bnExtractBigBytes_16(struct BigNum const *bn, unsigned char *dest,
+       unsigned lsbyte, unsigned dlen);
+int bnInsertBigBytes_16(struct BigNum *bn, unsigned char const *src,
+       unsigned lsbyte, unsigned len);
+void bnExtractLittleBytes_16(struct BigNum const *bn, unsigned char *dest,
+       unsigned lsbyte, unsigned dlen);
+int bnInsertLittleBytes_16(struct BigNum *bn, unsigned char const *src,
+       unsigned lsbyte, unsigned len);
+unsigned bnLSWord_16(struct BigNum const *src);
+unsigned bnBits_16(struct BigNum const *src);
+int bnAdd_16(struct BigNum *dest, struct BigNum const *src);
+int bnSub_16(struct BigNum *dest, struct BigNum const *src);
+int bnCmpQ_16(struct BigNum const *a, unsigned b);
+int bnSetQ_16(struct BigNum *dest, unsigned src);
+int bnAddQ_16(struct BigNum *dest, unsigned src);
+int bnSubQ_16(struct BigNum *dest, unsigned src);
+int bnCmp_16(struct BigNum const *a, struct BigNum const *b);
+int bnSquare_16(struct BigNum *dest, struct BigNum const *src);
+int bnMul_16(struct BigNum *dest, struct BigNum const *a,
+       struct BigNum const *b);
+int bnMulQ_16(struct BigNum *dest, struct BigNum const *a, unsigned b);
+int bnDivMod_16(struct BigNum *q, struct BigNum *r, struct BigNum const *n,
+       struct BigNum const *d);
+int bnMod_16(struct BigNum *dest, struct BigNum const *src,
+       struct BigNum const *d);
+unsigned bnModQ_16(struct BigNum const *src, unsigned d);
+int bnExpMod_16(struct BigNum *dest, struct BigNum const *n,
+       struct BigNum const *exp, struct BigNum const *mod);
+int bnDoubleExpMod_16(struct BigNum *dest,
+       struct BigNum const *n1, struct BigNum const *e1,
+       struct BigNum const *n2, struct BigNum const *e2,
+       struct BigNum const *mod);
+int bnTwoExpMod_16(struct BigNum *n, struct BigNum const *exp,
+       struct BigNum const *mod);
+int bnGcd_16(struct BigNum *dest, struct BigNum const *a,
+       struct BigNum const *b);
+int bnInv_16(struct BigNum *dest, struct BigNum const *src,
+       struct BigNum const *mod);
+int bnLShift_16(struct BigNum *dest, unsigned amt);
+void bnRShift_16(struct BigNum *dest, unsigned amt);
+unsigned bnMakeOdd_16(struct BigNum *n);
diff --git a/lib/bind/cylink/bn32.c b/lib/bind/cylink/bn32.c
new file mode 100644 (file)
index 0000000..a477778
--- /dev/null
@@ -0,0 +1,949 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/*
+ * bn32.c - the high-level bignum interface
+ *
+ * Like lbn32.c, this reserves the string "32" for textual replacement.
+ * The string must not appear anywhere unless it is intended to be replaced
+ * to generate other bignum interface functions.
+ *
+ * Copyright (c) 1995  Colin Plumb.  All rights reserved.
+ * For licensing and other legal details, see the file legal.c.
+ */
+
+#ifndef HAVE_CONFIG_H
+#define HAVE_CONFIG_H 0
+#endif
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/*
+ * Some compilers complain about #if FOO if FOO isn't defined,
+ * so do the ANSI-mandated thing explicitly...
+ */
+#ifndef NO_ASSERT_H
+#define NO_ASSERT_H 0
+#endif
+#ifndef NO_STRING_H
+#define NO_STRING_H 0
+#endif
+#ifndef HAVE_STRINGS_H
+#define HAVE_STRINGS_H 0
+#endif
+#ifndef NEED_MEMORY_H
+#define NEED_MEMORY_H 0
+#endif
+
+#if !NO_ASSERT_H
+#include <assert.h>
+#else
+#define assert(x) (void)0
+#endif
+
+#if !NO_STRING_H
+#include <string.h>    /* for memmove() in bnMakeOdd */
+#elif HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#if NEED_MEMORY_H
+#include <memory.h>
+#endif
+
+/*
+ * This was useful during debugging, so it's left in here.
+ * You can ignore it.  DBMALLOC is generally undefined.
+ */
+#ifndef DBMALLOC
+#define DBAMLLOC 0
+#endif
+#if DBMALLOC
+#include "../dbmalloc/malloc.h"
+#define MALLOCDB malloc_chain_check(1)
+#else
+#define MALLOCDB (void)0
+#endif
+
+#include "lbn.h"
+#include "lbn32.h"
+#include "lbnmem.h"
+#include "bn32.h"
+#include "bn.h"
+
+/* Work-arounds for some particularly broken systems */
+#include "kludge.h"    /* For memmove() */
+#include <port_after.h>
+
+/* Functions */
+void
+bnInit_32(void)
+{
+       bnEnd = bnEnd_32;
+       bnPrealloc = bnPrealloc_32;
+       bnCopy = bnCopy_32;
+       bnNorm = bnNorm_32;
+       bnExtractBigBytes = bnExtractBigBytes_32;
+       bnInsertBigBytes = bnInsertBigBytes_32;
+       bnExtractLittleBytes = bnExtractLittleBytes_32;
+       bnInsertLittleBytes = bnInsertLittleBytes_32;
+       bnLSWord = bnLSWord_32;
+       bnBits = bnBits_32;
+       bnAdd = bnAdd_32;
+       bnSub = bnSub_32;
+       bnCmpQ = bnCmpQ_32;
+       bnSetQ = bnSetQ_32;
+       bnAddQ = bnAddQ_32;
+       bnSubQ = bnSubQ_32;
+       bnCmp = bnCmp_32;
+       bnSquare = bnSquare_32;
+       bnMul = bnMul_32;
+       bnMulQ = bnMulQ_32;
+       bnDivMod = bnDivMod_32;
+       bnMod = bnMod_32;
+       bnModQ = bnModQ_32;
+       bnExpMod = bnExpMod_32;
+       bnDoubleExpMod = bnDoubleExpMod_32;
+       bnTwoExpMod = bnTwoExpMod_32;
+       bnGcd = bnGcd_32;
+       bnInv = bnInv_32;
+       bnLShift = bnLShift_32;
+       bnRShift = bnRShift_32;
+       bnMakeOdd = bnMakeOdd_32;
+}
+
+void
+bnEnd_32(struct BigNum *bn)
+{
+       if (bn->ptr) {
+               LBNFREE((BNWORD32 *)bn->ptr, bn->allocated);
+               bn->ptr = 0;
+       }
+       bn->size = 0;
+       bn->allocated = 0;
+
+       MALLOCDB;
+}
+
+/* Internal function.  It operates in words. */
+static int
+bnResize_32(struct BigNum *bn, unsigned len)
+{
+       void *p;
+
+       /* Round size up: most mallocs impose 8-byte granularity anyway */
+       len = (len + (8/sizeof(BNWORD32) - 1)) & ~(8/sizeof(BNWORD32) - 1);
+       p = LBNREALLOC((BNWORD32 *)bn->ptr, bn->allocated, len);
+       if (!p)
+               return -1;
+       bn->ptr = p;
+       bn->allocated = len;
+
+       MALLOCDB;
+
+       return 0;
+}
+
+#define bnSizeCheck(bn, size) \
+       if (bn->allocated < size && bnResize_32(bn, size) < 0) \
+               return -1
+
+int
+bnPrealloc_32(struct BigNum *bn, unsigned bits)
+{
+       bits = (bits + 32-1)/32;
+       bnSizeCheck(bn, bits);
+       MALLOCDB;
+       return 0;
+}
+
+int
+bnCopy_32(struct BigNum *dest, struct BigNum const *src)
+{
+       bnSizeCheck(dest, src->size);
+       dest->size = src->size;
+       lbnCopy_32((BNWORD32 *)dest->ptr, (BNWORD32 *)src->ptr, src->size);
+       MALLOCDB;
+       return 0;
+}
+
+void
+bnNorm_32(struct BigNum *bn)
+{
+       bn->size = lbnNorm_32((BNWORD32 *)bn->ptr, bn->size);
+}
+
+/*
+ * Convert a bignum to big-endian bytes.  Returns, in big-endian form, a
+ * substring of the bignum starting from lsbyte and "len" bytes long.
+ * Unused high-order (leading) bytes are filled with 0.
+ */
+void
+bnExtractBigBytes_32(struct BigNum const *bn, unsigned char *dest,
+                  unsigned lsbyte, unsigned len)
+{
+       unsigned s = bn->size * (32 / 8);
+
+       /* Fill unused leading bytes with 0 */
+       while (s < lsbyte+len) {
+               *dest++ = 0;
+               len--;
+       }
+
+       if (len)
+               lbnExtractBigBytes_32((BNWORD32 *)bn->ptr, dest, lsbyte, len);
+       MALLOCDB;
+}
+
+int
+bnInsertBigBytes_32(struct BigNum *bn, unsigned char const *src,
+                 unsigned lsbyte, unsigned len)
+{
+       unsigned s = bn->size;
+       unsigned words = (len+lsbyte+sizeof(BNWORD32)-1) / sizeof(BNWORD32);
+
+       /* Pad with zeros as required */
+       bnSizeCheck(bn, words);
+
+       if (s < words) {
+               lbnZero_32((BNWORD32 *)bn->ptr BIGLITTLE(-s,+s), words-s);
+               s = words;
+       }
+
+       lbnInsertBigBytes_32((BNWORD32 *)bn->ptr, src, lsbyte, len);
+
+       bn->size = lbnNorm_32((BNWORD32 *)bn->ptr, s);
+
+       MALLOCDB;
+       return 0;
+}
+
+
+/*
+ * Convert a bignum to little-endian bytes.  Returns, in little-endian form, a
+ * substring of the bignum starting from lsbyte and "len" bytes long.
+ * Unused high-order (trailing) bytes are filled with 0.
+ */
+void
+bnExtractLittleBytes_32(struct BigNum const *bn, unsigned char *dest,
+                  unsigned lsbyte, unsigned len)
+{
+       unsigned s = bn->size * (32 / 8);
+
+       /* Fill unused leading bytes with 0 */
+       while (s < lsbyte+len)
+               dest[--len] = 0;
+
+       if (len)
+               lbnExtractLittleBytes_32((BNWORD32 *)bn->ptr, dest,
+                                        lsbyte, len);
+       MALLOCDB;
+}
+
+int
+bnInsertLittleBytes_32(struct BigNum *bn, unsigned char const *src,
+                       unsigned lsbyte, unsigned len)
+{
+       unsigned s = bn->size;
+       unsigned words = (len+lsbyte+sizeof(BNWORD32)-1) / sizeof(BNWORD32);
+
+       /* Pad with zeros as required */
+       bnSizeCheck(bn, words);
+
+       if (s < words) {
+               lbnZero_32((BNWORD32 *)bn->ptr BIGLITTLE(-s,+s), words-s);
+               s = words;
+       }
+
+       lbnInsertLittleBytes_32((BNWORD32 *)bn->ptr, src, lsbyte, len);
+
+       bn->size = lbnNorm_32((BNWORD32 *)bn->ptr, s);
+
+       MALLOCDB;
+       return 0;
+}
+
+/* Return the least-significant word of the input. */
+unsigned
+bnLSWord_32(struct BigNum const *src)
+{
+       return src->size ? (unsigned)((BNWORD32 *)src->ptr)[BIGLITTLE(-1,0)]: 0;
+}
+
+unsigned
+bnBits_32(struct BigNum const *src)
+{
+       return lbnBits_32((BNWORD32 *)src->ptr, src->size);
+}
+
+int
+bnAdd_32(struct BigNum *dest, struct BigNum const *src)
+{
+       unsigned s = src->size, d = dest->size;
+       BNWORD32 t;
+
+       if (!s)
+               return 0;
+
+       bnSizeCheck(dest, s);
+
+       if (d < s) {
+               lbnZero_32((BNWORD32 *)dest->ptr BIGLITTLE(-d,+d), s-d);
+               dest->size = d = s;
+               MALLOCDB;
+       }
+       t = lbnAddN_32((BNWORD32 *)dest->ptr, (BNWORD32 *)src->ptr, s);
+       MALLOCDB;
+       if (t) {
+               if (d > s) {
+                       t = lbnAdd1_32((BNWORD32 *)dest->ptr BIGLITTLE(-s,+s),
+                                      d-s, t);
+                       MALLOCDB;
+               }
+               if (t) {
+                       bnSizeCheck(dest, d+1);
+                       ((BNWORD32 *)dest->ptr)[BIGLITTLE(-1-d,d)] = t;
+                       dest->size = d+1;
+               }
+       }
+       return 0;
+}
+
+/*
+ * dest -= src.
+ * If dest goes negative, this produces the absolute value of
+ * the difference (the negative of the true value) and returns 1.
+ * Otherwise, it returls 0.
+ */
+int
+bnSub_32(struct BigNum *dest, struct BigNum const *src)
+{
+       unsigned s = src->size, d = dest->size;
+       BNWORD32 t;
+
+       if (d < s  &&  d < (s = lbnNorm_32((BNWORD32 *)src->ptr, s))) {
+               bnSizeCheck(dest, s);
+               lbnZero_32((BNWORD32 *)dest->ptr BIGLITTLE(-d,+d), s-d);
+               dest->size = d = s;
+               MALLOCDB;
+       }
+       if (!s)
+               return 0;
+       t = lbnSubN_32((BNWORD32 *)dest->ptr, (BNWORD32 *)src->ptr, s);
+       MALLOCDB;
+       if (t) {
+               if (d > s) {
+                       t = lbnSub1_32((BNWORD32 *)dest->ptr BIGLITTLE(-s,+s),
+                                      d-s, t);
+                       MALLOCDB;
+               }
+               if (t) {
+                       lbnNeg_32((BNWORD32 *)dest->ptr, d);
+                       dest->size = lbnNorm_32((BNWORD32 *)dest->ptr,
+                                               dest->size);
+                       MALLOCDB;
+                       return 1;
+               }
+       }
+       dest->size = lbnNorm_32((BNWORD32 *)dest->ptr, dest->size);
+       return 0;
+}
+
+/*
+ * Compare the BigNum to the given value, which must be < 65536.
+ * Returns -1. 0 or 1 if a<b, a == b or a>b.
+ * a <=> b --> bnCmpQ(a,b) <=> 0
+ */
+int
+bnCmpQ_32(struct BigNum const *a, unsigned b)
+{
+       unsigned t;
+       BNWORD32 v;
+
+       t = lbnNorm_32((BNWORD32 *)a->ptr, a->size);
+       /* If a is more than one word long or zero, it's easy... */
+       if (t != 1)
+               return (t > 1) ? 1 : (b ? -1 : 0);
+       v = (unsigned)((BNWORD32 *)a->ptr)[BIGLITTLE(-1,0)];
+       return (v > b) ? 1 : ((v < b) ? -1 : 0);
+}
+
+int
+bnSetQ_32(struct BigNum *dest, unsigned src)
+{
+       if (src) {
+               bnSizeCheck(dest, 1);
+
+               ((BNWORD32 *)dest->ptr)[BIGLITTLE(-1,0)] = (BNWORD32)src;
+               dest->size = 1;
+       } else {
+               dest->size = 0;
+       }
+       return 0;
+}
+
+int
+bnAddQ_32(struct BigNum *dest, unsigned src)
+{
+       BNWORD32 t;
+
+       if (!dest->size)
+               return bnSetQ(dest, src);
+       
+       t = lbnAdd1_32((BNWORD32 *)dest->ptr, dest->size, (BNWORD32)src);
+       MALLOCDB;
+       if (t) {
+               src = dest->size;
+               bnSizeCheck(dest, src+1);
+               ((BNWORD32 *)dest->ptr)[BIGLITTLE(-1-src,src)] = t;
+               dest->size = src+1;
+       }
+       return 0;
+}
+
+/*
+ * Return value as for bnSub: 1 if subtract underflowed, in which
+ * case the return is the negative of the computed value.
+ */
+int
+bnSubQ_32(struct BigNum *dest, unsigned src)
+{
+       BNWORD32 t;
+
+       if (!dest->size)
+               return bnSetQ(dest, src) < 0 ? -1 : (src != 0);
+
+       t = lbnSub1_32((BNWORD32 *)dest->ptr, dest->size, src);
+       MALLOCDB;
+       if (t) {
+               /* Underflow. <= 1 word, so do it simply. */
+               lbnNeg_32((BNWORD32 *)dest->ptr, 1);
+               dest->size = 1;
+               return 1;
+       }
+/* Try to normalize?  Needing this is going to be very rare. */
+/*             dest->size = lbnNorm_32((BNWORD32 *)dest->ptr, dest->size); */
+       return 0;
+}
+
+/*
+ * Compare two BigNums.  Returns -1. 0 or 1 if a<b, a == b or a>b.
+ * a <=> b --> bnCmp(a,b) <=> 0
+ */
+int
+bnCmp_32(struct BigNum const *a, struct BigNum const *b)
+{
+       unsigned s, t;
+
+       s = lbnNorm_32((BNWORD32 *)a->ptr, a->size);
+       t = lbnNorm_32((BNWORD32 *)b->ptr, b->size);
+       
+       if (s != t)
+               return s > t ? 1 : -1;
+       return lbnCmp_32((BNWORD32 *)a->ptr, (BNWORD32 *)b->ptr, s);
+}
+
+int
+bnSquare_32(struct BigNum *dest, struct BigNum const *src)
+{
+       unsigned s;
+       BNWORD32 *srcbuf;
+
+       s = lbnNorm_32((BNWORD32 *)src->ptr, src->size);
+       if (!s) {
+               dest->size = 0;
+               return 0;
+       }
+       bnSizeCheck(dest, 2*s);
+
+       if (src == dest) {
+               LBNALLOC(srcbuf, s);
+               if (!srcbuf)
+                       return -1;
+               lbnCopy_32(srcbuf, (BNWORD32 *)src->ptr, s);
+               lbnSquare_32((BNWORD32 *)dest->ptr, (BNWORD32 *)srcbuf, s);
+               LBNFREE(srcbuf, s);
+       } else {
+               lbnSquare_32((BNWORD32 *)dest->ptr, (BNWORD32 *)src->ptr, s);
+       }
+
+       dest->size = lbnNorm_32((BNWORD32 *)dest->ptr, 2*s);
+       MALLOCDB;
+       return 0;
+}
+
+int
+bnMul_32(struct BigNum *dest, struct BigNum const *a, struct BigNum const *b)
+{
+       unsigned s, t;
+       BNWORD32 *srcbuf;
+
+       s = lbnNorm_32((BNWORD32 *)a->ptr, a->size);
+       t = lbnNorm_32((BNWORD32 *)b->ptr, b->size);
+
+       if (!s || !t) {
+               dest->size = 0;
+               return 0;
+       }
+
+       if (a == b)
+               return bnSquare_32(dest, a);
+
+       bnSizeCheck(dest, s+t);
+
+       if (dest == a) {
+               LBNALLOC(srcbuf, s);
+               if (!srcbuf)
+                       return -1;
+               lbnCopy_32(srcbuf, (BNWORD32 *)a->ptr, s);
+               lbnMul_32((BNWORD32 *)dest->ptr, srcbuf, s,
+                                                (BNWORD32 *)b->ptr, t);
+               LBNFREE(srcbuf, s);
+       } else if (dest == b) {
+               LBNALLOC(srcbuf, t);
+               if (!srcbuf)
+                       return -1;
+               lbnCopy_32(srcbuf, (BNWORD32 *)b->ptr, t);
+               lbnMul_32((BNWORD32 *)dest->ptr, (BNWORD32 *)a->ptr, s,
+                                                srcbuf, t);
+               LBNFREE(srcbuf, t);
+       } else {
+               lbnMul_32((BNWORD32 *)dest->ptr, (BNWORD32 *)a->ptr, s,
+                                                (BNWORD32 *)b->ptr, t);
+       }
+       dest->size = lbnNorm_32((BNWORD32 *)dest->ptr, s+t);
+       MALLOCDB;
+       return 0;
+}
+
+int
+bnMulQ_32(struct BigNum *dest, struct BigNum const *a, unsigned b)
+{
+       unsigned s;
+
+       s = lbnNorm_32((BNWORD32 *)a->ptr, a->size);
+       if (!s || !b) {
+               dest->size = 0;
+               return 0;
+       }
+       if (b == 1)
+               return bnCopy_32(dest, a);
+       bnSizeCheck(dest, s+1);
+       lbnMulN1_32((BNWORD32 *)dest->ptr, (BNWORD32 *)a->ptr, s, b);
+       dest->size = lbnNorm_32((BNWORD32 *)dest->ptr, s+1);
+       MALLOCDB;
+       return 0;
+}
+
+int
+bnDivMod_32(struct BigNum *q, struct BigNum *r, struct BigNum const *n,
+            struct BigNum const *d)
+{
+       unsigned dsize, nsize;
+       BNWORD32 qhigh;
+
+       dsize = lbnNorm_32((BNWORD32 *)d->ptr, d->size);
+       nsize = lbnNorm_32((BNWORD32 *)n->ptr, n->size);
+
+       if (nsize < dsize) {
+               q->size = 0;    /* No quotient */
+               r->size = nsize;
+               return 0;       /* Success */
+       }
+
+       bnSizeCheck(q, nsize-dsize);
+
+       if (r != n) {   /* You are allowed to reduce in place */
+               bnSizeCheck(r, nsize);
+               lbnCopy_32((BNWORD32 *)r->ptr, (BNWORD32 *)n->ptr, nsize);
+       }
+               
+       qhigh = lbnDiv_32((BNWORD32 *)q->ptr, (BNWORD32 *)r->ptr, nsize,
+                         (BNWORD32 *)d->ptr, dsize);
+       nsize -= dsize;
+       if (qhigh) {
+               bnSizeCheck(q, nsize+1);
+               *((BNWORD32 *)q->ptr BIGLITTLE(-nsize-1,+nsize)) = qhigh;
+               q->size = nsize+1;
+       } else {
+               q->size = lbnNorm_32((BNWORD32 *)q->ptr, nsize);
+       }
+       r->size = lbnNorm_32((BNWORD32 *)r->ptr, dsize);
+       MALLOCDB;
+       return 0;
+}
+
+int
+bnMod_32(struct BigNum *dest, struct BigNum const *src, struct BigNum const *d)
+{
+       unsigned dsize, nsize;
+
+       nsize = lbnNorm_32((BNWORD32 *)src->ptr, src->size);
+       dsize = lbnNorm_32((BNWORD32 *)d->ptr, d->size);
+
+
+       if (dest != src) {
+               bnSizeCheck(dest, nsize);
+               lbnCopy_32((BNWORD32 *)dest->ptr, (BNWORD32 *)src->ptr, nsize);
+       }
+
+       if (nsize < dsize) {
+               dest->size = nsize;     /* No quotient */
+               return 0;
+       }
+
+       (void)lbnDiv_32((BNWORD32 *)dest->ptr BIGLITTLE(-dsize,+dsize),
+                       (BNWORD32 *)dest->ptr, nsize,
+                       (BNWORD32 *)d->ptr, dsize);
+       dest->size = lbnNorm_32((BNWORD32 *)dest->ptr, dsize);
+       MALLOCDB;
+       return 0;
+}
+
+unsigned
+bnModQ_32(struct BigNum const *src, unsigned d)
+{
+       unsigned s;
+
+       s = lbnNorm_32((BNWORD32 *)src->ptr, src->size);
+       if (!s)
+               return 0;
+       
+       return lbnModQ_32((BNWORD32 *)src->ptr, s, d);
+}
+
+int
+bnExpMod_32(struct BigNum *dest, struct BigNum const *n,
+       struct BigNum const *exp, struct BigNum const *mod)
+{
+       unsigned nsize, esize, msize;
+
+       nsize = lbnNorm_32((BNWORD32 *)n->ptr, n->size);
+       esize = lbnNorm_32((BNWORD32 *)exp->ptr, exp->size);
+       msize = lbnNorm_32((BNWORD32 *)mod->ptr, mod->size);
+
+       if (!msize || (((BNWORD32 *)mod->ptr)[BIGLITTLE(-1,0)] & 1) == 0)
+               return -1;      /* Illegal modulus! */
+
+       bnSizeCheck(dest, msize);
+
+       /* Special-case base of 2 */
+       if (nsize == 1 && ((BNWORD32 *)n->ptr)[BIGLITTLE(-1,0)] == 2) {
+               if (lbnTwoExpMod_32((BNWORD32 *)dest->ptr,
+                                   (BNWORD32 *)exp->ptr, esize,
+                                   (BNWORD32 *)mod->ptr, msize) < 0)
+                       return -1;
+       } else {
+               if (lbnExpMod_32((BNWORD32 *)dest->ptr,
+                                (BNWORD32 *)n->ptr, nsize,
+                                (BNWORD32 *)exp->ptr, esize,
+                                (BNWORD32 *)mod->ptr, msize) < 0)
+               return -1;
+       }
+
+       dest->size = lbnNorm_32((BNWORD32 *)dest->ptr, msize);
+       MALLOCDB;
+       return 0;
+}
+
+int
+bnDoubleExpMod_32(struct BigNum *dest,
+       struct BigNum const *n1, struct BigNum const *e1,
+       struct BigNum const *n2, struct BigNum const *e2,
+       struct BigNum const *mod)
+{
+       unsigned n1size, e1size, n2size, e2size, msize;
+
+       n1size = lbnNorm_32((BNWORD32 *)n1->ptr, n1->size);
+       e1size = lbnNorm_32((BNWORD32 *)e1->ptr, e1->size);
+       n2size = lbnNorm_32((BNWORD32 *)n2->ptr, n2->size);
+       e2size = lbnNorm_32((BNWORD32 *)e2->ptr, e2->size);
+       msize = lbnNorm_32((BNWORD32 *)mod->ptr, mod->size);
+
+       if (!msize || (((BNWORD32 *)mod->ptr)[BIGLITTLE(-1,0)] & 1) == 0)
+               return -1;      /* Illegal modulus! */
+
+       bnSizeCheck(dest, msize);
+
+       if (lbnDoubleExpMod_32((BNWORD32 *)dest->ptr,
+               (BNWORD32 *)n1->ptr, n1size, (BNWORD32 *)e1->ptr, e1size,
+               (BNWORD32 *)n2->ptr, n2size, (BNWORD32 *)e2->ptr, e2size,
+               (BNWORD32 *)mod->ptr, msize) < 0)
+               return -1;
+
+       dest->size = lbnNorm_32((BNWORD32 *)dest->ptr, msize);
+       MALLOCDB;
+       return 0;
+}
+
+int
+bnTwoExpMod_32(struct BigNum *n, struct BigNum const *exp,
+       struct BigNum const *mod)
+{
+       unsigned esize, msize;
+
+       esize = lbnNorm_32((BNWORD32 *)exp->ptr, exp->size);
+       msize = lbnNorm_32((BNWORD32 *)mod->ptr, mod->size);
+
+       if (!msize || (((BNWORD32 *)mod->ptr)[BIGLITTLE(-1,0)] & 1) == 0)
+               return -1;      /* Illegal modulus! */
+
+       bnSizeCheck(n, msize);
+
+       if (lbnTwoExpMod_32((BNWORD32 *)n->ptr, (BNWORD32 *)exp->ptr, esize,
+                           (BNWORD32 *)mod->ptr, msize) < 0)
+               return -1;
+
+       n->size = lbnNorm_32((BNWORD32 *)n->ptr, msize);
+       MALLOCDB;
+       return 0;
+}
+
+int
+bnGcd_32(struct BigNum *dest, struct BigNum const *a, struct BigNum const *b)
+{
+       BNWORD32 *tmp;
+       unsigned asize, bsize;
+       int i;
+
+       /* Kind of silly, but we might as well permit it... */
+       if (a == b)
+               return dest == a ? 0 : bnCopy(dest, a);
+
+       /* Ensure a is not the same as "dest" */
+       if (a == dest) {
+               a = b;
+               b = dest;
+       }
+
+       asize = lbnNorm_32((BNWORD32 *)a->ptr, a->size);
+       bsize = lbnNorm_32((BNWORD32 *)b->ptr, b->size);
+
+       bnSizeCheck(dest, bsize+1);
+
+       /* Copy a to tmp */
+       LBNALLOC(tmp, asize+1);
+       if (!tmp)
+               return -1;
+       lbnCopy_32(tmp, (BNWORD32 *)a->ptr, asize);
+
+       /* Copy b to dest,if necessary */
+       if (dest != b)
+               lbnCopy_32((BNWORD32 *)dest->ptr,
+                          (BNWORD32 *)b->ptr, bsize);
+       if (bsize > asize || (bsize == asize &&
+               lbnCmp_32((BNWORD32 *)b->ptr, (BNWORD32 *)a->ptr, asize) > 0))
+       {
+               i = lbnGcd_32((BNWORD32 *)dest->ptr, bsize, tmp, asize);
+               if (i >= 0) {
+                       dest->size = (unsigned)i;
+               } else {
+                       lbnCopy_32((BNWORD32 *)dest->ptr, tmp,
+                                  (unsigned)-i);
+                       dest->size = (unsigned)-i;
+               }
+       } else {
+               i = lbnGcd_32(tmp, asize, (BNWORD32 *)dest->ptr, bsize);
+               if (i <= 0) {
+                       dest->size = (unsigned)-i;
+               } else {
+                       lbnCopy_32((BNWORD32 *)dest->ptr, tmp,
+                                  (unsigned)i);
+                       dest->size = (unsigned)i;
+               }
+       }
+       LBNFREE(tmp, asize+1);
+       MALLOCDB;
+       return 0;
+}
+
+int
+bnInv_32(struct BigNum *dest, struct BigNum const *src,
+         struct BigNum const *mod)
+{
+       unsigned s, m;
+       int i;
+
+       s = lbnNorm_32((BNWORD32 *)src->ptr, src->size);
+       m = lbnNorm_32((BNWORD32 *)mod->ptr, mod->size);
+
+       /* lbnInv_32 requires that the input be less than the modulus */
+       if (m < s ||
+           (m==s && lbnCmp_32((BNWORD32 *)src->ptr, (BNWORD32 *)mod->ptr, s)))
+       {
+               bnSizeCheck(dest, s + (m==s));
+               if (dest != src)
+                       lbnCopy_32((BNWORD32 *)dest->ptr,
+                                  (BNWORD32 *)src->ptr, s);
+               /* Pre-reduce modulo the modulus */
+               (void)lbnDiv_32((BNWORD32 *)dest->ptr BIGLITTLE(-m,+m),
+                               (BNWORD32 *)dest->ptr, s,
+                               (BNWORD32 *)mod->ptr, m);
+               s = lbnNorm_32((BNWORD32 *)dest->ptr, m);
+               MALLOCDB;
+       } else {
+               bnSizeCheck(dest, m+1);
+               if (dest != src)
+                       lbnCopy_32((BNWORD32 *)dest->ptr,
+                                  (BNWORD32 *)src->ptr, s);
+       }
+
+       i = lbnInv_32((BNWORD32 *)dest->ptr, s, (BNWORD32 *)mod->ptr, m);
+       if (i == 0)
+               dest->size = lbnNorm_32((BNWORD32 *)dest->ptr, m);
+
+       MALLOCDB;
+       return i;
+}
+
+/*
+ * Shift a bignum left the appropriate number of bits,
+ * multiplying by 2^amt.
+ */
+int 
+bnLShift_32(struct BigNum *dest, unsigned amt)
+{
+       unsigned s = dest->size;
+       BNWORD32 carry;
+
+       if (amt % 32) {
+               carry = lbnLshift_32(dest->ptr, s, amt % 32);
+               if (carry) {
+                       s++;
+                       bnSizeCheck(dest, s);
+                       ((BNWORD32 *)dest->ptr)[BIGLITTLE(-s,s-1)] = carry;
+               }
+       }
+
+       amt /= 32;
+       if (amt) {
+               bnSizeCheck(dest, s+amt);
+               memmove((BNWORD32 *)dest->ptr BIGLITTLE(-s-amt, +amt),
+                       (BNWORD32 *)dest->ptr BIG(-s),
+                       s * sizeof(BNWORD32));
+               lbnZero_32((BNWORD32 *)dest->ptr, amt);
+               s += amt;
+       }
+       dest->size = s;
+       MALLOCDB;
+       return 0;
+}
+
+/*
+ * Shift a bignum right the appropriate number of bits,
+ * dividing by 2^amt.
+ */
+void bnRShift_32(struct BigNum *dest, unsigned amt)
+{
+       unsigned s = dest->size;
+
+       if (amt >= 32) {
+               memmove(
+                       (BNWORD32 *)dest->ptr BIG(-s+amt/32),
+                       (BNWORD32 *)dest->ptr BIGLITTLE(-s, +amt/32),
+                       s-amt/32 * sizeof(BNWORD32));
+               s -= amt/32;
+               amt %= 32;
+       }
+
+       if (amt)
+               (void)lbnRshift_32(dest->ptr, s, amt);
+
+       dest->size = lbnNorm_32(dest->ptr, s);
+       MALLOCDB;
+}
+
+/*
+ * Shift a bignum right until it is odd, and return the number of
+ * bits shifted.  n = d * 2^s.  Replaces n with d and returns s.
+ * Returns 0 when given 0.  (Another valid answer is infinity.)
+ */
+unsigned
+bnMakeOdd_32(struct BigNum *n)
+{
+       unsigned size;
+       unsigned s;     /* shift amount */
+       BNWORD32 *p;
+       BNWORD32 t;
+
+       p = (BNWORD32 *)n->ptr;
+       size = lbnNorm_32(p, n->size);
+       if (!size)
+               return 0;
+
+       t = BIGLITTLE(p[-1],p[0]);
+       s = 0;
+
+       /* See how many words we have to shift */
+       if (!t) {
+               /* Shift by words */
+               do {
+                       
+                       s++;
+                       BIGLITTLE(--p,p++);
+               } while ((t = BIGLITTLE(p[-1],p[0])) == 0);
+               size -= s;
+               s *= 32;
+               memmove((BNWORD32 *)n->ptr BIG(-size), p BIG(-size),
+                       size * sizeof(BNWORD32));
+               p = (BNWORD32 *)n->ptr;
+               MALLOCDB;
+       }
+
+       assert(t);
+
+       /* Now count the bits */
+       while ((t & 1) == 0) {
+               t >>= 1;
+               s++;
+       }
+
+       /* Shift the bits */
+       if (s & (32-1)) {
+               lbnRshift_32(p, size, s & (32-1));
+               /* Renormalize */
+               if (BIGLITTLE(*(p-size),*(p+(size-1))) == 0)
+                       --size;
+       }
+       n->size = size;
+
+       MALLOCDB;
+       return s;
+}
diff --git a/lib/bind/cylink/bn32.h b/lib/bind/cylink/bn32.h
new file mode 100644 (file)
index 0000000..3c042ee
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/*
+ * bn32.h - interface to 32-bit bignum routines.
+ */
+struct BigNum;
+
+void bnInit_32(void);
+void bnEnd_32(struct BigNum *bn);
+int bnPrealloc_32(struct BigNum *bn, unsigned bits);
+int bnCopy_32(struct BigNum *dest, struct BigNum const *src);
+int bnSwap_32(struct BigNum *a, struct BigNum *b);
+void bnNorm_32(struct BigNum *bn);
+void bnExtractBigBytes_32(struct BigNum const *bn, unsigned char *dest,
+       unsigned lsbyte, unsigned dlen);
+int bnInsertBigBytes_32(struct BigNum *bn, unsigned char const *src,
+       unsigned lsbyte, unsigned len);
+void bnExtractLittleBytes_32(struct BigNum const *bn, unsigned char *dest,
+       unsigned lsbyte, unsigned dlen);
+int bnInsertLittleBytes_32(struct BigNum *bn, unsigned char const *src,
+       unsigned lsbyte, unsigned len);
+unsigned bnLSWord_32(struct BigNum const *src);
+unsigned bnBits_32(struct BigNum const *src);
+int bnAdd_32(struct BigNum *dest, struct BigNum const *src);
+int bnSub_32(struct BigNum *dest, struct BigNum const *src);
+int bnCmpQ_32(struct BigNum const *a, unsigned b);
+int bnSetQ_32(struct BigNum *dest, unsigned src);
+int bnAddQ_32(struct BigNum *dest, unsigned src);
+int bnSubQ_32(struct BigNum *dest, unsigned src);
+int bnCmp_32(struct BigNum const *a, struct BigNum const *b);
+int bnSquare_32(struct BigNum *dest, struct BigNum const *src);
+int bnMul_32(struct BigNum *dest, struct BigNum const *a,
+       struct BigNum const *b);
+int bnMulQ_32(struct BigNum *dest, struct BigNum const *a, unsigned b);
+int bnDivMod_32(struct BigNum *q, struct BigNum *r, struct BigNum const *n,
+       struct BigNum const *d);
+int bnMod_32(struct BigNum *dest, struct BigNum const *src,
+       struct BigNum const *d);
+unsigned bnModQ_32(struct BigNum const *src, unsigned d);
+int bnExpMod_32(struct BigNum *dest, struct BigNum const *n,
+       struct BigNum const *exp, struct BigNum const *mod);
+int bnDoubleExpMod_32(struct BigNum *dest,
+       struct BigNum const *n1, struct BigNum const *e1,
+       struct BigNum const *n2, struct BigNum const *e2,
+       struct BigNum const *mod);
+int bnTwoExpMod_32(struct BigNum *n, struct BigNum const *exp,
+       struct BigNum const *mod);
+int bnGcd_32(struct BigNum *dest, struct BigNum const *a,
+       struct BigNum const *b);
+int bnInv_32(struct BigNum *dest, struct BigNum const *src,
+       struct BigNum const *mod);
+int bnLShift_32(struct BigNum *dest, unsigned amt);
+void bnRShift_32(struct BigNum *dest, unsigned amt);
+unsigned bnMakeOdd_32(struct BigNum *n);
diff --git a/lib/bind/cylink/bn68000.c b/lib/bind/cylink/bn68000.c
new file mode 100644 (file)
index 0000000..66132e7
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/*
+ * bn68000.c - bnInit() for Motorola 680x0 family, 16 or 32-bit.
+ *
+ * Written in 1995 by Colin Plumb.
+ */
+
+#include "lbn.h"
+#include "bn16.h"
+#include "bn32.h"
+
+#ifndef BNINCLUDE
+#error You must define BNINCLUDE to lbn68000.h to use assembly primitives.
+#endif
+
+void
+bnInit(void)
+{
+       if (is68020())
+               bnInit_32();
+       else
+               bnInit_16();
+}
diff --git a/lib/bind/cylink/bn8086.c b/lib/bind/cylink/bn8086.c
new file mode 100644 (file)
index 0000000..fecf929
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/*
+ * bn8086.c - bnInit() for Intel x86 family in 16-bit mode.
+ *
+ * Written in 1995 by Colin Plumb.
+ */
+
+#include "lbn.h"
+#include "bn16.h"
+#include "bn32.h"
+
+#ifndef BNINCLUDE
+#error You must define BNINCLUDE to lbn8086.h to use assembly primitives.
+#endif
+
+void
+bnInit(void)
+{
+/*     if (not386())
+               bnInit_16();
+       else */
+               bnInit_32();
+}
diff --git a/lib/bind/cylink/bninit16.c b/lib/bind/cylink/bninit16.c
new file mode 100644 (file)
index 0000000..7e7c99f
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/*
+ * bninit16.c - Provide an init function that sets things up for 16-bit
+ * operation.  This is a seaparate tiny file so you can compile two bn
+ * packages into the library and write a custom init routine.
+ *
+ * Written in 1995 by Colin Plumb.
+ */
+
+#include "bn.h"
+#include "bn16.h"
+
+void
+bnInit(void)
+{
+       bnInit_16();
+}
diff --git a/lib/bind/cylink/bninit32.c b/lib/bind/cylink/bninit32.c
new file mode 100644 (file)
index 0000000..396bd12
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/*
+ * bninit32.c - Provide an init function that sets things up for 32-bit
+ * operation.  This is a seaparate tiny file so you can compile two bn
+ * packages into the library and write a custom init routine.
+ *
+ * Written in 1995 by Colin Plumb.
+ */
+
+#include "bn.h"
+#include "bn32.h"
+
+void
+bnInit(void)
+{
+       bnInit_32();
+}
diff --git a/lib/bind/cylink/bnsize00.h b/lib/bind/cylink/bnsize00.h
new file mode 100644 (file)
index 0000000..7986235
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/*
+ * bnsize00.h - pick the correct machine word size to use.
+ *
+ * Copyright (c) 1995  Colin Plumb.  All rights reserved.
+ * For licensing and other legal details, see the file legal.c.
+ */
+#include "lbn.h"       /* Get basic information */
+
+#if !BNSIZE64 && !BNSIZE32 && !BNSIZE16 && defined(BNWORD64)
+# if defined(BNWORD128) || (defined(lbnMulAdd1_64) && defined(lbnMulSub1_64))
+#  define BNSIZE64 1
+# elif defined(mul64_ppmm) || defined(mul64_ppmma) || defined(mul64_ppmmaa)
+#  define BNSIZE64 1
+# endif
+#endif
+
+#if !BNSIZE64 && !BNSIZE32 && !BNSIZE16 && defined(BNWORD32)
+# if defined(BNWORD64) || (defined(lbnMulAdd1_32) && defined(lbnMulSub1_32))
+#  define BNSIZE32 1
+# elif defined(mul32_ppmm) || defined(mul32_ppmma) || defined(mul32_ppmmaa)
+#  define BNSIZE32 1
+# endif
+#endif
+
+#if !BNSIZE64 && !BNSIZE32 && !BNSIZE16 && defined(BNWORD16)
+# if defined(BNWORD32) || (defined(lbnMulAdd1_16) && defined(lbnMulSub1_16))
+#  define BNSIZE16 1
+# elif defined(mul16_ppmm) || defined(mul16_ppmma) || defined(mul16_ppmmaa)
+#  define BNSIZE16 1
+# endif
+#endif
+
+#if !BNSIZE64 && !BNSIZE32 && !BNSIZE16
+#error Unable to find a viable word size to compile bignum library.
+#endif
diff --git a/lib/bind/cylink/c_asm.h b/lib/bind/cylink/c_asm.h
new file mode 100644 (file)
index 0000000..f291ca9
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/****************************************************************************
+*  FILENAME:  c_asm.h        PRODUCT NAME: CRYPTOGRAPHIC TOOLKIT
+*
+*  FILE STATUS:
+*
+*  DESCRIPTION:     C / ASM Header File
+*
+*  USAGE:           File should be included to use Toolkit Functions
+*
+*
+*   Copyright (c) Cylink Corporation 1994. All rights reserved.
+*
+*  REVISION  HISTORY:
+*
+*  14 Oct 94    GKL     For Second version (big endian support)
+*  26 Oct 94    GKL     (alignment for big endian support )
+*
+****************************************************************************/
+#if !defined( C_ASM_H )
+#define C_ASM_H
+
+#include <sys/types.h>
+#include "cylink.h"
+#include "ctk_endian.h"
+
+#ifdef  __cplusplus
+extern  "C" {
+#endif
+
+
+ int Sum_big (ord *X,
+              ord *Y,
+         ord *Z,
+         int len_X );
+ int Sum (ord *X, ord *Y, ushort len_X );
+  int Sub_big (ord *X,
+              ord *Y,
+         ord *Z,
+         int len_X );
+/*
+  void  Mul_big( ord *X, ord *Y,ord *XY,
+            ushort lx, ushort ly,
+           ushort  elements_in_X,
+          ushort  elements_in_Y);*/
+  void  Mul_big( ord *X, ord *Y,ord *XY,
+               ushort lx, ushort ly);
+
+  void  PReLo_big( ord *X, ord *P,
+                    ushort len_X, ushort el);
+
+  void  Div_big( ord *X, ord *P,
+           ushort len_X, ushort el,
+                ord *div);
+
+int LeftMostBit_big ( ord X );
+int LeftMostEl_big( ord *X, ushort len_X );
+void  RShiftL_big( ord  *X, u_int32_t len_X, u_int32_t  n_bit );
+void  LShiftL_big( ord *X, u_int32_t len_X, u_int32_t n_bit );
+int RShiftMostBit(ord *a, u_int32_t len);
+void ByteLong(uchar *X, u_int32_t X_bytes, u_int32_t *Y);
+void ByteOrd(uchar *X, u_int32_t X_bytes, ord *Y);
+void OrdByte(ord *X, u_int32_t X_bytes, uchar *Y);
+void LongByte(u_int32_t *X, u_int32_t X_bytes, uchar  *Y);
+int BitValue_big( ord  *X, ushort n_bits );
+int BitsValue_big( ord  *X, ushort n_bits, ushort bit_count );
+void ByteSwap32_big( uchar  *X, ushort X_len );
+void Complement_big( ord *X, ushort X_longs);
+void Diagonal_big (ord *X, ushort X_len, ord *X2);
+void Square_big( ord *X, ushort X_len, ord *X2);
+void  Mul_big_1( ord  X, ord *Y, ord *XY, ushort ly );
+int Sum_Q(ord *X, ushort src, ushort len_X );
+
+
+
+/* In-place DES encryption */
+  void DES_encrypt(uchar *keybuf, uchar *block);
+
+/* In-place DES decryption */
+  void DES_decrypt(uchar *keybuf, uchar *block);
+
+/* In-place KAPPA encryption */
+  void KAPPA_encrypt(uchar *a, uchar *k, ushort r);
+
+/* In-place KAPPA decryption */
+  void KAPPA_decrypt(uchar *a, uchar *k, ushort r);
+
+#ifdef  __cplusplus
+}
+#endif
+
+
+#endif   /*C_ASM_H*/
+
diff --git a/lib/bind/cylink/cencrint.h b/lib/bind/cylink/cencrint.h
new file mode 100644 (file)
index 0000000..1d6ecb6
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/****************************************************************************
+*  FILENAME:  cencrint.h      PRODUCT NAME: CRYPTOGRAPHIC TOOLKIT
+*
+*  FILE STATUS:
+*
+*  DESCRIPTION:     Cryptographic Toolkit Internal Functions Header File
+*
+*  USAGE:           File should be included to use Toolkit Functions
+*
+*
+*         Copyright (c) Cylink Corporation 1994. All rights reserved.
+*
+*  REVISION  HISTORY:
+*
+*  23 Aug 94  KPZ     Initial release
+*  24 Sep 94    KPZ     Added prototypes of internal functions
+*  14 Oct 94    GKL     Second version (big endian support)
+*  08 Dec 94    GKL             Added YIELD_context to Expo, VerPrime and GenPrime
+*
+****************************************************************************/
+
+#ifndef CENCRINT_H     /* Prevent multiple inclusions of same header file */
+#define CENCRINT_H
+
+/****************************************************************************
+*  INCLUDE FILES
+****************************************************************************/
+
+/* system files */
+#include <sys/types.h>
+#include "cylink.h"
+#include "ctk_endian.h"
+#include "toolkit.h"
+
+#ifdef  __cplusplus
+extern  "C" {
+#endif
+
+/* Compute a modulo */
+ int PartReduct( u_int16_t X_bytes, ord   *X,
+                 u_int16_t P_bytes, ord   *P,
+               ord   *Z );
+
+/* Compute a modulo product */
+ int Mul( u_int16_t X_bytes, ord   *X,
+     u_int16_t Y_bytes, ord   *Y,
+       u_int16_t P_bytes, ord   *P,
+       ord   *Z );
+/*Compute a modulo squaring*/
+int Mul_Squr( u_int16_t X_bytes, ord    *X,
+            u_int16_t P_bytes, ord    *P,
+                                 ord    *Z );
+int Square( u_int16_t X_bytes,
+                               ord *X,
+                               u_int16_t P_bytes,
+                               ord *P,
+                               ord *Z );
+
+/*Compare two array*/
+int Comp_Mont ( ord *X, ord *P, u_int16_t P_longs );
+/*Compute invers element*/
+ord Inv_Mont ( ord x );
+/*Modulo by the Mongomery*/
+void PartReduct_Mont( ord *X, u_int16_t P_bytes, ord  *P, ord inv );
+/*Computes squaring by the Mongomery modulo*/
+int Mul_Squr_Mont(ord    *X, u_int16_t P_bytes,
+            ord    *P, ord    *Z,
+           ord     inv );
+/*Computes multiply by the montgomery modulo*/
+int Mul_Mont( ord    *X, ord    *Y,
+                                u_int16_t P_bytes, ord    *P,
+                                 ord    *Z, ord     inv );
+
+/* Compute a modulo exponent */
+ int Expo( u_int16_t X_bytes, ord   *X,
+                         u_int16_t Y_bytes, ord   *Y,
+                         u_int16_t P_bytes, ord   *P,
+                               ord   *Z );
+ /*Compute double exponent */
+ int DoubleExpo( u_int16_t X1_bytes,ord    *X1,
+                                        u_int16_t Y1_bytes,ord    *Y1,
+                                        u_int16_t X2_bytes,ord    *X2,
+                                        u_int16_t Y2_bytes,ord    *Y2,
+                                        u_int16_t P_bytes,ord    *P,
+                                                                                ord    *Z);
+/* Compute a modulo inverse element */
+ int Inverse( u_int16_t X_bytes, ord   *X,
+                                u_int16_t P_bytes, ord   *P,
+       ord   *Z );
+
+/* Verify Pseudo Prime number */
+ int VerPrime( u_int16_t P_bytes, ord    *P,
+             u_int16_t k,       ord    *RVAL,
+           YIELD_context *yield_cont ); /*TKL00601*/
+
+/* Generate Random Pseudo Prime number */
+ int GenPrime( u_int16_t P_bytes, ord    *P,
+             u_int16_t k,       ord    *RVAL,
+           YIELD_context *yield_cont ); /*TKL00601*/
+
+/* Transfer bytes to u_int32_t */
+ void  ByteLong( uchar *X,
+          u_int16_t X_bytes,
+                 u_int32_t *Y );
+
+/* Transfer u_int32_t to bytes */
+ void  LongByte( u_int32_t *X,
+              u_int16_t X_bytes,
+                 uchar  *Y );
+
+/* Transfer bytes to ord */
+  void  ByteOrd( uchar *X,
+               u_int16_t X_bytes,
+                 ord *Y );
+
+/* Transfer ord to bytes */
+  void  OrdByte( ord *X,
+            u_int16_t X_bytes,
+                 uchar *Y );
+
+/* Find the left most non zero bit */
+ int LeftMostBit ( ord X );
+
+/* Find the left most element */
+ int LeftMostEl( ord *X,
+             u_int16_t len_X );
+
+/* Shift array to rigth by n_bit */
+ void  RShiftL( ord   *X,
+            u_int16_t  len_X,
+          u_int16_t  n_bit );
+
+/* Shifts array to left by n_bit */
+ void  LShiftL( ord  *X,
+             u_int16_t len_X,
+           u_int16_t n_bit );
+
+/* Find the value of bit */
+ int BitValue( ord *X,
+               u_int16_t n_bits );
+
+/* Perform byte reversal on an array of ordinar type (longword or shortword) */
+ void ByteSwap( uchar  *X,
+                                u_int16_t X_len );
+
+/* Perform byte reversal on an array from LSB to MSB */
+ void BigSwap( uchar  *X,
+                                u_int16_t X_len );
+
+/* Perform byte reversal on an array of longword */
+ void ByteSwap32( uchar  *X,
+                            u_int16_t X_len );
+
+/* Perform short reversal on an array of longword */
+ void WordSwap( uchar  *X,
+                         u_int16_t X_len );
+
+/* Perform  SHS transformation */
+ void shaTransform( u_int32_t *state,
+                                       const uchar *block );
+
+/* Compute modulo addition
+ int Add( ord    *X,
+                                                ord    *Y,
+                                 u_int16_t P_len,
+                                                ord    *P,
+                                 ord    *Z );
+ */
+ int Add( ord    *X,
+                                                ord    *Y,
+                                 u_int16_t P_len,
+                                                ord    *P );
+/*  Initialize Secure Hash Function for generate
+ random number for DSS                                           */
+ void SHAInitK( SHA_context *hash_context );
+
+/* Set parity bits */
+ void SetKeyParity( uchar *key );
+
+/*  Find a least significant non zero bit
+      and sfift array to right            */
+ int RShiftMostBit( ord *a, u_int16_t len );
+
+/*Compute great common divisor */
+ int SteinGCD( ord *m, ord *b, u_int16_t len );
+
+/* Compute a modulo and divisor */
+ int DivRem( u_int16_t X_bytes, ord    *X,
+             u_int16_t P_bytes, ord    *P,
+             ord    *Z,      ord    *D );
+
+/* Generate random number */
+int MyGenRand( u_int16_t A_bytes, ord    *A,
+                               ord    *RVAL);
+
+/* Compute a Secure Hash Function */
+int MySHA( uchar   *message,
+    u_int16_t message_bytes,
+           uchar  *hash_result );
+
+/* Finalize Secure Hash Function */
+ int MySHAFinal( SHA_context *hash_context,
+          uchar       *hash_result );
+
+ void shaTransform_new( u_int32_t *state,
+                   uchar *block );
+
+
+#ifdef  __cplusplus
+}
+#endif
+
+
+#endif /* CENCRINT_H */
+
diff --git a/lib/bind/cylink/ctk_endian.h b/lib/bind/cylink/ctk_endian.h
new file mode 100644 (file)
index 0000000..fd1a89e
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/**********************************************************************\
+*  FILENAME:  ctk_endian.h     PRODUCT NAME:
+*
+*  DESCRIPTION:  header file of defines
+*
+*  USAGE:      Platform-dependend compilation modes header
+*
+*
+*          Copyright (c) Cylink Corporation 1994. All rights reserved.
+*
+*  REVISION  HISTORY:
+*
+\**********************************************************************/
+
+#ifndef CTK_ENDIAN_H  /* Prevent multiple inclusions of same header file */
+#define CTK_ENDIAN_H
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <arpa/nameser_compat.h>
+#include "lbn.h"
+
+#if (defined(BIG_ENDIAN) || defined(_BIG_ENDIAN)) && !(defined(LITTLE_ENDIAN) || defined(_LITTLE_ENDIAN))
+#  undef BIG_ENDIAN
+#  undef _BIG_ENDIAN
+#  define BIG_ENDIAN 4321
+#  define LITTLE_ENDIAN 1234
+#  define BYTE_ORDER BIG_ENDIAN
+
+#elif !(defined(BIG_ENDIAN) || defined(_BIG_ENDIAN)) && (defined(LITTLE_ENDIAN) || defined(_LITTLE_ENDIAN))
+#  undef LITTLE_ENDIAN
+#  undef _LITTLE_ENDIAN
+#  define BIG_ENDIAN 4321
+#  define LITTLE_ENDIAN 1234
+#  define BYTE_ORDER LITTLE_ENDIAN
+#endif
+
+#if !defined(BYTE_ORDER) || \
+    (BYTE_ORDER != BIG_ENDIAN && BYTE_ORDER != LITTLE_ENDIAN)
+        /* you must determine what the correct bit order is for
+         * your compiler - the next line is an intentional error
+         * which will force your compiles to bomb until you fix
+         * the above macros.
+         */
+# if !defined(CTK_LITTLE_ENDIAN) && !defined(CTK_BIG_ENDIAN)
+#  error "Undefined or invalid BYTE_ORDER";
+# endif
+#endif
+
+#if !defined(CTK_BIG_ENDIAN) && !defined(CTK_LITTLE_ENDIAN)
+#  ifdef BYTE_ORDER
+#    if (BYTE_ORDER == LITTLE_ENDIAN) 
+#      define CTK_LITTLE_ENDIAN
+#    elif (BYTE_ORDER == BIG_ENDIAN)
+#      define CTK_BIG_ENDIAN
+#    else 
+#      error CAN NOT determine ENDIAN with BYTE_ORDER
+#    endif
+#  elif defined(_LITTLE_ENDIAN) 
+#    define CTK_LITTLE_ENDIAN
+#  elif defined(_BIG_ENDIAN)
+#    define CTK_BIG_ENDIAN
+#  else 
+#      error CAN NOT determine ENDIAN 
+#  endif
+#endif 
+
+#if !defined(CTK_BIG_ENDIAN) && !defined(CTK_LITTLE_ENDIAN)
+#  error NO CTK_???_ENDIAN defined
+#endif
+
+#if defined( CTK_LITTLE_ENDIAN ) && defined( CTK_BIG_ENDIAN )
+#  error Use only one define CPU type CTK_LITTLE or BIG ENDIAN.
+#endif
+
+#if  !defined( ORD_32 ) && !defined( ORD_16 )
+#  ifdef BNSIZE64
+#     error BNSIZE64 do not know how to do this
+#  elif defined(BNSIZE32)
+#     define ORD_32
+#  elif defined(BNSIZE16)
+#     define ORD_16
+#  elif  !defined( UINT_MAX) /* No <limits.h> */
+#    define ORD_16 /* default */
+#  else 
+#    if ULONG_MAX == 0xffffffff
+#      define ORD_16
+#    else
+#      define ORD_32
+#    endif
+#  endif
+#endif
+
+#if  !defined( ORD_32 ) && !defined( ORD_16 )
+#error Not defined basic word type ORD_32 or ORD_16.
+#endif
+
+#if  defined( ORD_32 ) && defined( ORD_16 )
+#error Use only one define basic word type ORD_32 or ORD_16.
+#endif
+
+
+#ifdef ORD_16
+/* typedef unsigned short ord; deleted by ogud@tis.com 1998/9/14 */
+typedef u_int16_t ord;
+#define BITS_COUNT 16
+#define MAXDIGIT (ord)(0xFFFF)
+#endif
+
+#ifdef ORD_32
+/* typedef unsigned long ord; deleted by ogud@tis.com 1998/9/14 */
+typedef u_int32_t ord;
+#define BITS_COUNT 32
+#define MAXDIGIT (ord)(0xFFFFFFFF)
+#endif /* ORD_32 */
+
+
+
+#define CALLOC(var,type,len)                    \
+                          var=(type *)calloc(len,1);     \
+                                if (var==NULL)                 \
+                                         status=ERR_ALLOC
+#ifdef CTK_BIG_ENDIAN
+#define ALIGN_CALLOC(i,o,l)                     \
+                             CALLOC(o,ord,l)
+#define ALIGN_CALLOC_COPY(i,o,l)                \
+                                CALLOC(o,ord,l);               \
+                                if (o) ByteOrd(i,l,o)
+#define ALIGN_CALLOC_MOVE(i,o,l)                \
+                          CALLOC(o,ord,l);               \
+                                if (o) memcpy(o,i,l)
+#define ALIGN_FREE(o)                           \
+                           free ( o )
+#define ALIGN_COPY_FREE(o,i,l)                  \
+                             if ((o) && (status==SUCCESS))  \
+                                       OrdByte(o,l,i);             \
+                            free (o)
+#define ALIGN_MOVE_FREE(o,i,l)                  \
+                               if ((o) && (status==SUCCESS))  \
+                                       memcpy(i,o,l);              \
+                                   memset(o,0,l);  \
+                                       free (o)
+#else
+#define ALIGN_CALLOC(i,o,l) o=(ord *)i
+#define ALIGN_CALLOC_COPY(i,o,l) o=(ord *)i
+#define ALIGN_CALLOC_MOVE(i,o,l) o=(ord *)i
+#define ALIGN_FREE(o)  ;
+#define ALIGN_COPY_FREE(o,i,l) ;
+#define ALIGN_MOVE_FREE(o,i,l) ;
+#endif
+#define DSS_P_ALIGN_CALLOC_COPY(i,o,l)          \
+              if (i)                            \
+             { ALIGN_CALLOC_COPY(i,o,l);}      \
+              else                              \
+                o = &DSS_P_NUMBERS[DSS_NUM_INDEX[(l-DSS_LENGTH_MIN)/LENGTH_STEP]]
+
+#define DSS_G_ALIGN_CALLOC_COPY(i,o,l)          \
+              if (i)                            \
+              { ALIGN_CALLOC_COPY(i,o,l);}      \
+        else                              \
+                o = &DSS_G_NUMBERS[DSS_NUM_INDEX[(l-DSS_LENGTH_MIN)/LENGTH_STEP]]
+
+#define DSS_Q_ALIGN_CALLOC_COPY(i,o,l)          \
+              if (i)                            \
+              { ALIGN_CALLOC_COPY(i,o,l);}      \
+              else                              \
+                o = DSS_Q_NUMBER
+
+#define DSS_ALIGN_FREE(o,i)           \
+              if (i)                  \
+              { ALIGN_FREE(o);}
+#endif     /* CTK_ENDIAN_H */
diff --git a/lib/bind/cylink/ctk_prime.c b/lib/bind/cylink/ctk_prime.c
new file mode 100644 (file)
index 0000000..0d1c9f2
--- /dev/null
@@ -0,0 +1,435 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/****************************************************************************
+*  FILENAME:  prime.c   PRODUCT NAME: CRYPTOGRAPHIC TOOLKIT
+*
+*  FILE STATUS:
+*
+*  DESCRIPTION:  Cryptographic Toolkit Internal Functions File
+*               Prime Number functions
+*  PRIVATE FUNCTIONS:
+*
+*               int VerPrime( u_int16_t P_bytes, ord *P,
+*                             u_int16_t k, ord *RVAL,
+*                             YIELD_context *yield_cont )
+*               int GenPrime( u_int16_t P_bytes, ord *P,
+*                             u_int16_t k, ord *RVAL,
+*                             YIELD_context *yield_cont )
+*       Copyright (c) Cylink Corporation 1996. All rights reserved.
+*
+*  REVISION  HISTORY:
+*
+*
+****************************************************************************/
+
+/****************************************************************************
+*  INCLUDE FILES
+****************************************************************************/
+
+#include "port_before.h"
+#include <sys/types.h>
+#include "cylink.h"
+#include "ctk_endian.h"
+
+/* system files */
+#ifdef VXD
+#include <vtoolsc.h>
+#else
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#endif
+
+/* program files */
+#include "cylink.h"
+#include "ctk_endian.h"
+#include "toolkit.h"
+#include "cencrint.h"
+#include "port_after.h"
+
+/****************************************************************************
+*  PRIVATE FUNCTIONS DEFINITIONS
+****************************************************************************/
+/****************************************************************************
+*  NAME: int VerPrime( u_int16_t P_bytes,
+*                      ord    *P,
+*                      u_int16_t k,
+*                      ord    *RVAL,
+*                                         YIELD_context *yield_cont )
+*
+*  DESCRIPTION: Verify Pseudo Prime number
+*
+*  INPUTS:
+*      PARAMETERS:
+*            u_int16_t P_bytes     Number of bytes in array
+*            u_int16_t k           Number of testing
+*            ord    *RVAL       Pointer to random number generator value
+*            YIELD_context *yield_cont  Pointer to yield_cont structure (NULL if not used)
+*  OUTPUT:
+*      PARAMETERS:
+*            ord   *P           Pointer to prime number
+*            ord   *RVAL        Pointer to updated value
+*
+*      RETURN:
+*          SUCCESS              No errors
+*          ERR_INPUT_LEN        Invalid length for input data(zero bytes)
+*          ERR_PRIME            Number is not prime
+*  REVISION HISTORY:
+*
+*  24 Sep 94   KPZ     Initial release
+*  14 Oct 94   GKL     Second version (big endian support)
+*  08 Dec 94   GKL    Added YIELD_context
+*
+****************************************************************************/
+
+ int VerPrime( u_int16_t P_bytes,
+                                                ord    *P,
+                                         u_int16_t k,
+                                          ord    *RVAL,
+                                                  YIELD_context *yield_cont ) /*TKL00601*/
+
+{
+       int status = SUCCESS;      /*function return status*/
+   ord *b, *n, *c, *pp;       /*pointers to working buffers */
+        ord *m, *buf, *P_buf;
+   u_int16_t max_bytes;          /*number of maximum bytes*/
+  u_int16_t P_longs;            /*number of longs in Y*/
+        u_int16_t i, j, s, k_b;       /*counters*/
+ u_int16_t exit ;              /*flag for exit*/
+/* product of prime numbers from 3 to 379 (512-bit number) */
+#ifdef ORD_32
+       ord b1[DSS_LENGTH_MIN/sizeof(ord)]={
+                 0x2e30c48fL, 0x0decece9L, 0xbada8f98L, 0x9f7ecb29L,
+             0xa4a11de4L, 0x6ef04659L, 0xcbc38405L, 0x233db117L,
+             0x03e81187L, 0xc1b631a2L, 0x238bfb99L, 0x077ec3baL,
+             0xc5d5f09fL, 0xb0813c28L, 0x7646fa6eL, 0x106aa9fbL };
+#else
+       ord b1[DSS_LENGTH_MIN/sizeof(ord)]={
+              0xc48f, 0x2e30, 0xece9, 0x0dec, 0x8f98, 0xbada, 0xcb29, 0x9f7e,
+         0x1de4, 0xa4a1, 0x4659, 0x6ef0, 0x8405, 0xcbc3, 0xb117, 0x233d,
+         0x1187, 0x03e8, 0x31a2, 0xc1b6, 0xfb99, 0x238b, 0xc3ba, 0x077e,
+                0xf09f, 0xc5d5, 0x3c28, 0xb081, 0xfa6e, 0x7646, 0xa9fb, 0x106a };
+#endif
+       if ( P_bytes % sizeof(ord) != 0 )                /* not multiple 4 (32 bit) */
+    {
+          status = ERR_INPUT_LEN;          /* invalid length for input data */
+                       return status;
+    }
+       if ( P_bytes <= DSS_LENGTH_MIN )
+    {
+                       max_bytes = DSS_LENGTH_MIN;
+       }
+       else
+    {
+                  max_bytes = P_bytes;
+    }
+       buf = (ord *)calloc( max_bytes / sizeof(ord), sizeof(ord) );
+       P_buf = (ord *)calloc( max_bytes / sizeof(ord), sizeof(ord));
+       if( !buf || !P_buf )
+    {
+ if ( buf )
+              free( buf );
+    if( P_buf )
+                        free( P_buf );
+  return ERR_ALLOC;
+       }
+       memcpy( buf, b1, DSS_LENGTH_MIN );
+       memcpy( P_buf, P, P_bytes  );
+
+       if ( (P_buf[0] & 0x1) == 0 )
+    {
+#ifdef DEBUG1
+         printf ("\n P is not pseudoprime");
+#endif
+                          status = ERR_PRIME;
+             free ( buf );
+                  free( P_buf );
+          return status;
+    }
+       P_longs = (u_int16_t) (P_bytes / sizeof(ord));
+       b = (ord *)calloc( P_longs, sizeof(ord) );
+       m = (ord *)malloc( P_longs * sizeof(ord) );
+       n = (ord *)calloc( P_longs, sizeof(ord) );
+       c = (ord *)calloc( P_longs, sizeof(ord) );
+       pp = (ord *)malloc( P_longs * sizeof(ord) );
+       if( !b || !m || !n || !c || !pp )
+    {
+         if( b )
+         free( b );
+      if( m )
+         free( m );
+      if( n )
+         free( n );
+      if( c )
+         free( c );
+      if( pp )
+                               free ( pp );
+       }
+       memcpy( m, P, P_bytes );
+       memcpy( pp, P, P_bytes );
+    /* Compute great common divisor(gcd) */
+       if ( SteinGCD( P_buf, buf, (u_int16_t)(max_bytes / sizeof(ord)) ) == 0 )
+  {
+        pp[0] = pp[0] - 1;                     /* Initialized work buffer */
+        m[0] = m[0] - 1;
+           s = (u_int16_t) RShiftMostBit( m, (u_int16_t)(P_bytes / sizeof(ord)) ); /* Right shift by number of*/
+        exit = 0;                               /* zero bits at rigth    */
+               k_b = 0;
+        while( k_b != k )
+               {
+                     MyGenRand( 4, b, RVAL );    /* generate random number */
+            if ( SteinGCD( P_buf, b , (u_int16_t)(P_bytes / sizeof(ord)) ) ) /* check gcd */
+            {
+#ifdef DEBUG1
+                                                        printf ("\n P is not pseudoprime");
+#endif
+                                                          status = ERR_PRIME;
+                             break;
+                       }
+            k_b++;                          /* increment counter */
+                 if ( ( status = Expo ( 4, b, P_bytes, m,
+                                P_bytes, P, c ) ) != SUCCESS )    /* c=b^m mod(P) */ /*TKL00601*/
+                    {
+                               free( b );
+                              free( m );
+                              free( n );
+                              free( c );
+                              free( pp );
+                             free (buf );
+                                                       free( P_buf );
+                          return status;
+                                 }
+                       if ( c[0] == 1 )    /* if c==1 number is pseudo prime */
+                                               {
+                               for ( i = 1; i < P_bytes / sizeof(ord); i++ )
+                {
+                    if ( c[i] != 0 )
+                    {
+                                         break;
+                                  }
+                                                          }
+                               if ( i == P_bytes / sizeof(ord) )
+                                                          {
+                                       if (yield_cont)  /*TKL00601*/
+#ifdef VXD
+                                         if ( VXD_Yield (yield_cont->yield_proc) )
+#else
+                                          if ( yield_cont->yield_proc(0xFFFF) )
+#endif
+
+                                                                                        {
+                                                                                                          status = ERR_CANCEL;
+                                                    free( b );
+                                                                                                         free( m );
+                                                      free( n );
+                                                      free( c );
+                                                      free( pp );
+                                                     free( P_buf );
+                                                  free (buf );
+                                                    return status;
+                                          }
+#ifdef DEBUG1
+                                                                 printf ("\n P is a pseudoprime %d",k_b);
+#endif
+                                                                 if ( k_b == k )
+                                                                {
+                                               break;
+                                                                 }
+                               }
+            }
+                  else
+            {
+                for ( j = 1; j <= s; j++ )
+                               {
+                    for ( i = 0; i < P_bytes / sizeof(ord); i++ )    /* if c==pp number is pseudo prime */
+                                       {
+                                             if ( c[i] != pp[i] )
+                        {
+                                           break;
+                                          }
+                                       }
+                                       if ( i == P_bytes / sizeof(ord) )
+                                       {
+                                               if (yield_cont) /*TKL00601*/
+#ifdef VXD
+                                          if ( VXD_Yield (yield_cont->yield_proc) )
+#else
+                                                  if ( yield_cont->yield_proc(0xFFFF) )
+#endif
+
+                                                     {
+                                                               status = ERR_CANCEL;
+                                                            free( b );
+                                                              free( m );
+                                                              free( n );
+                                                                                                                         free( c );
+                                                              free( pp );
+                                                                                                                        free( P_buf );
+                                                          free (buf );
+                                                            return status;
+                                                  }
+#ifdef DEBUG1
+                                          printf ("\n P is a pseudoprime %d",k_b);
+#endif
+                                          break;
+                                  }
+                                                                          if ( j == s )
+                                   {
+#ifdef DEBUG1
+                                          printf ("\n P is not pseudoprime");
+#endif
+                                               status = ERR_PRIME;
+                                             exit = 1;
+                                               break;
+                                  }
+                                       else
+                                    {
+                                                                                          if ( (status = Square(P_bytes, c, /*P_bytes,
+                                                                                                                                                                       c,*/ P_bytes, P, c) )
+                                                                                                                                  != SUCCESS )     /* c=c^2mod(p) */
+                                              {
+                                                       free( b );
+                                                      free( m );
+                                                      free( n );
+                                              free( c );
+                                              free( pp );
+                                             free( P_buf );
+                                          free (buf );
+                                                                                       return status;
+                                          }
+                                                                          }
+                }
+                      }
+            if ( exit == 1 )            /* Exit */
+            {
+                                break;
+                  }
+               }
+       }
+          else
+    {
+                          if (yield_cont)  /*TKL00601*/
+#ifdef VXD
+         if ( VXD_Yield (yield_cont->yield_proc) )
+#else
+          if ( yield_cont->yield_proc(0xFFFF) )
+#endif
+
+                     {
+                               status = ERR_CANCEL;
+                                                       free( b );
+                              free( m );
+                                                         free( n );
+                              free( c );
+                              free( pp );
+                             free( P_buf );
+                          free (buf );
+                            return status;
+                  }
+#ifdef DEBUG1
+          printf ("\n P is not pseudoprime");
+#endif
+                          status = ERR_PRIME;
+        }
+          free( b );
+         free( m );
+         free( n );
+         free( c );
+         free( pp );
+        free( P_buf );
+  free (buf );
+       return status;
+}
+
+/****************************************************************************
+*  NAME: int GenPrime( u_int16_t P_bytes,
+*                      ord    *P,
+*                      u_int16_t k,
+*                      ord    *RVAL,
+*                                           YIELD_context *yield_cont )
+*
+*  DESCRIPTION: Generate Random Pseudo Prime number
+*
+*  INPUTS:
+*      PARAMETERS:
+*            u_int16_t P_bytes     Number of bytes in array
+*            u_int16_t k           Number of testing
+*            ord    *RVAL       Pointer to random number generator value
+*            YIELD_context *yield_cont  Pointer to yield_cont structure (NULL if not used)
+*  OUTPUT:
+*      PARAMETERS:
+*            ord   *P           Pointer to prime number
+*            ord   *RVAL        Pointer to updated value
+*
+*      RETURN:
+*          SUCCESS              No errors
+*          ERR_INPUT_LEN        Invalid length for input data(zero bytes)
+*          ERR_PRIME            Number is not prime
+*  REVISION HISTORY:
+*
+*  24 Sep 94   KPZ     Initial release
+*  14 Oct 94   GKL     Second version (big endian support)
+*  08 Dec 94   GKL     Added YIELD_context
+*
+****************************************************************************/
+
+ int GenPrime( u_int16_t P_bytes,
+                                          ord    *P,
+                      u_int16_t k,
+                       ord    *RVAL,
+                           YIELD_context *yield_cont ) /*TKL00601*/
+{
+    int status = SUCCESS;      /* function return status */
+ if ( P_bytes % sizeof(ord) != 0 )    /* not multiple 4 (32 bit) */
+      {
+               status = ERR_INPUT_LEN;          /* invalid length for input data */
+                       return status;
+  }
+          do
+      {
+               MyGenRand( P_bytes, P, RVAL );    /* generate random number */
+          P[0] |= 1;
+              P[(P_bytes/sizeof(ord))-1] |= ((ord)1 << (BITS_COUNT-1));
+               status = VerPrime( P_bytes, P, k, RVAL, yield_cont); /*TKL00601*/
+       } while ((status != SUCCESS) && (status != ERR_CANCEL)); /*TKL00601*/
+   return status;
+}
+
diff --git a/lib/bind/cylink/cylink.h b/lib/bind/cylink/cylink.h
new file mode 100644 (file)
index 0000000..36aeb9c
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/**********************************************************************\
+*  FILENAME:  cylink.h     PRODUCT NAME: 
+*
+*  DESCRIPTION:  Company standard include file
+*
+*  USAGE:          File should be #included
+*
+*
+*         Copyright (c) Cylink Corporation 1994. All rights reserved.
+*
+*  REVISION  HISTORY:
+*
+\**********************************************************************/
+
+#ifndef CYLINK_H  /* Prevent multiple inclusions of same header file */
+#define CYLINK_H
+
+#include <sys/param.h>
+#if (!defined(BSD)) || (BSD < 199306)
+# include <sys/bitypes.h>
+#else
+# include <sys/types.h>
+#endif
+
+#if    ! ( defined(__alpha) && defined(__osf__) ) /* in sys/types.h */
+#if !defined(_H_INTTYPES) && !defined (_H_TYPES)   /* AIX puts this in inttypes.h */
+typedef unsigned char  uchar;
+#endif /* _H_INTTYPES */
+#endif
+
+typedef u_int16_t USHORT;
+typedef u_int32_t ULONG;
+
+#define              FALSE                   0
+#define        TRUE            1
+
+/*-- ANSI-recommended NULL Pointer definition --*/
+#ifndef              NULL
+edefine             NULL    (void *) 0
+#endif
+
+#endif     /* CYLINK_H */
diff --git a/lib/bind/cylink/dss.c b/lib/bind/cylink/dss.c
new file mode 100644 (file)
index 0000000..38cf289
--- /dev/null
@@ -0,0 +1,1202 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/****************************************************************************
+*  FILENAME:  dss.c   PRODUCT NAME: CRYPTOGRAPHIC TOOLKIT
+*
+*  FILE STATUS:
+*
+*  DESCRIPTION:     Cryptographic Toolkit Functions File
+*                   Digital Signature Algorithms
+*  PUBLIC FUNCTIONS:
+*                                   uchar  *RVAL )
+*      int GenDSSKey( u_int16_t dss_p_bytes, uchar  *dss_p,
+*                     uchar *dss_q,       uchar  *dss_g,
+*                     uchar  *dss_x,      uchar  *dss_y,
+*                                         uchar  *XKEY )
+*
+*      int GenDSSNumber( uchar *dss_k,   uchar dss_q,
+*                                        uchar *KKEY )
+*       int GenDSSParameters( u_int16_t dss_p_bytes, uchar  *dss_p,
+*                              uchar  *dss_q,      uchar  *dss_g,
+*                                                  uchar  *RVAL );
+*
+*   Copyright (c) Cylink Corporation 1996. All rights reserved.
+*
+*  REVISION  HISTORY:
+*
+*
+****************************************************************************/
+
+/****************************************************************************
+*  INCLUDE FILES
+****************************************************************************/
+
+#include "port_before.h"
+#include <sys/types.h>
+#include "cylink.h"
+#include "ctk_endian.h"
+
+/* system files */
+#ifdef VXD
+#include <vtoolsc.h>
+#else
+#include <stdlib.h>
+#include <string.h>
+#endif
+
+/* program files */
+#ifdef VXD
+#include "tkvxd.h"
+#endif
+#include "toolkit.h"
+#include "cencrint.h"
+#define  INITIALIZ_PQG   /*TKL01101*/
+#include "dssnum.h"      /*TKL01101*/
+#include "sha.h"
+#include "port_after.h"
+
+#define  BEGIN_PROCESSING do {
+#define  END_PROCESSING  } while (0);
+#define  ERROR_BREAK break
+#define  CONTINUE continue
+
+#define  BEGIN_LOOP do {
+#define  END_LOOP  } while (1);
+#define  BREAK break
+
+
+extern u_int16_t DataOrder;
+
+/****************************************************************************
+*  NAME:  int GenDSSSignature( u_int16_t dss_p_bytes,
+*                              uchar  *dss_p,
+*                              uchar  *dss_q,
+*                              uchar  *dss_g,
+*                              uchar  *dss_x,
+*                              uchar  *dss_k,
+*                              uchar  *r,
+*                              uchar  *s,
+*                              uchar  *hash_result)
+*
+*  DESCRIPTION:  Compute a DSS Signature
+*
+*  INPUTS:
+*      PARAMETERS:
+*          u_int16_t dss_p_bytes  Length of dss_p
+*          uchar *dss_p        Pointer to p prime
+*          uchar *dss_q        Pointer to q prime
+*          uchar *dss_g        Pointer to g
+*          uchar *dss_x        Pointer to secret number
+*          uchar *dss_k        Pointer to random secret number
+*          uchar *hash_result  Pointer to message hashing result
+*
+*
+*  OUTPUT:
+*      PARAMETERS:
+*          uchar *r           Pointer to r part of signature
+*          uchar *s           Pointer to s part of signature
+*
+*      RETURN:
+*          E_SUCCESS         No errors
+*          E_DSS_LEN         Invalid length for dss_p
+*          ERR_ALLOC         Insufficient memory
+*
+*  REVISION HISTORY:
+*
+*  24 Sep 94   KPZ     Initial release
+*  14 Oct 94   GKL     Second version (big endian support)
+*  26 Oct 94   GKL     (alignment for big endian support & ERR_ALLOC)
+*  08 Dec 94   GKL     Changed Expo call
+*
+****************************************************************************/
+
+int GenDSSSignature( u_int16_t dss_p_bytes,
+                     uchar  *dss_p,
+                     uchar  *dss_q,
+                     uchar  *dss_g,
+                     uchar  *dss_x,
+                     uchar  *dss_k,
+                     uchar  *r,
+                     uchar  *s,
+                     uchar  *hash_result)
+
+{
+    int  status = SUCCESS;          /* function return status */
+       ord r_temp[DSS_LENGTH_MAX];      /* r intermidiate value */
+    ord k_inverse[SHA_LENGTH+1]; 
+       ord temp[SHA_LENGTH+1];            /* intermidiate values    */
+       ord *dss_p_a;
+       ord *dss_g_a;
+       ord *dss_q_a;
+       ord *dss_x_a;
+       ord *dss_k_a;
+       ord *hash_result_a;
+       ord *r_a;
+       ord *s_a;
+
+    if ( (dss_p_bytes < DSS_LENGTH_MIN) ||     /* less than minimal */
+               (dss_p_bytes > DSS_LENGTH_MAX) )      /* more than maximal */
+    {
+               status = ERR_DSS_LEN;           /* invalid length for dss_p */
+        return status;
+    }
+    if ( dss_p_bytes & 0x07 )          /* not multiple 8 (64 bit)*/
+    {
+           status = ERR_DSS_LEN;          /* invalid length for dss_p */
+           return status;
+    }
+
+    if (DataOrder)
+    {
+        if (dss_p)
+          BigSwap(dss_p, dss_p_bytes);
+        if (dss_q)
+          BigSwap(dss_q, SHA_LENGTH);
+        if (dss_g)
+          BigSwap(dss_g, dss_p_bytes);
+        BigSwap(dss_x, SHA_LENGTH);
+        BigSwap(dss_k, SHA_LENGTH);
+        BigSwap(hash_result, SHA_LENGTH);
+    }
+
+    DSS_G_ALIGN_CALLOC_COPY(dss_g, dss_g_a, dss_p_bytes);  /*TKL01101*/
+    DSS_P_ALIGN_CALLOC_COPY(dss_p, dss_p_a, dss_p_bytes);  /*TKL01101*/
+    DSS_Q_ALIGN_CALLOC_COPY(dss_q, dss_q_a, SHA_LENGTH);   /*TKL01101*/
+
+ ALIGN_CALLOC_COPY(dss_x, dss_x_a, SHA_LENGTH);
+ ALIGN_CALLOC_COPY(dss_k, dss_k_a, SHA_LENGTH);
+ ALIGN_CALLOC_COPY(hash_result, hash_result_a, SHA_LENGTH);
+ ALIGN_CALLOC(r, r_a, SHA_LENGTH);
+ ALIGN_CALLOC(s, s_a, SHA_LENGTH);
+ if ( status !=  SUCCESS )
+ {
+    if( dss_p_a )
+         DSS_ALIGN_FREE(dss_p_a,dss_p);
+    if( dss_g_a )
+         DSS_ALIGN_FREE(dss_g_a,dss_g);
+    if( dss_q_a )
+         DSS_ALIGN_FREE(dss_q_a,dss_q);
+    if( dss_x_a )
+       {
+         memset ( dss_x_a , 0 , SHA_LENGTH );
+         ALIGN_FREE(dss_x_a);
+    }
+       if( dss_k_a )
+       {
+         ALIGN_FREE(dss_k_a);
+    }
+       if( hash_result_a )
+       {
+         ALIGN_FREE(hash_result_a);
+       }
+       if( r_a )
+       {
+         ALIGN_COPY_FREE(r_a,r,SHA_LENGTH);
+       }
+       if( s_a )
+       {
+         ALIGN_COPY_FREE(s_a,s,SHA_LENGTH);
+       }
+    if (DataOrder)
+    {
+        if (dss_p)
+          BigSwap(dss_p, dss_p_bytes);
+        if (dss_q)
+          BigSwap(dss_q, SHA_LENGTH);
+        if (dss_g)
+          BigSwap(dss_g, dss_p_bytes);
+        BigSwap(dss_x, SHA_LENGTH);
+        BigSwap(dss_k, SHA_LENGTH);
+        BigSwap(hash_result, SHA_LENGTH);
+    }
+       return status;     /* ERR_ALLOC   insufficient memory */
+ }
+
+/* Compute DSS r value */
+ BEGIN_PROCESSING
+        if (( status = Expo ( dss_p_bytes,
+                                                  dss_g_a,
+                                                  SHA_LENGTH,   /* r_temp=(dss_g^dss_k)mod(dss_p)*/
+                                                  dss_k_a,
+                                                  dss_p_bytes,
+                                                  dss_p_a,
+                                                  r_temp )) != SUCCESS )
+        {
+                                                         ERROR_BREAK;
+        }
+        if (( status = PartReduct ( dss_p_bytes,
+                                                                r_temp,
+                                                                SHA_LENGTH,      /* r=(r_temp)mod(dss_q) */
+                                                            dss_q_a,
+                                                            r_a )) != SUCCESS )
+        {
+                               ERROR_BREAK;
+        }
+/* Compute k modulo inverse value */
+        if (( status = Inverse( SHA_LENGTH,  /* k_inverse=dss_k^(-1)mod(dss_q)*/
+                                                         dss_k_a,
+                                                         SHA_LENGTH,
+                                                         dss_q_a,
+                                                         k_inverse )) != SUCCESS  )
+        {
+                       ERROR_BREAK;
+        }
+/* Compute DSS s value */
+        if (( status = Mul ( SHA_LENGTH,    /* temp=(dss_x*r)mod(dss_q) */
+                                                       dss_x_a,
+                                                       SHA_LENGTH,
+                                                       r_a,
+                                                   SHA_LENGTH,
+                                                       dss_q_a,
+                                                       temp )) != SUCCESS )
+        {
+                        ERROR_BREAK;
+        }
+
+       /* Add( temp, hash_result_a,
+                SHA_LENGTH, dss_q_a, temp );   temp=(temp+hash_result)mod(dss_q)*/
+
+        Add( temp, hash_result_a,
+                SHA_LENGTH, dss_q_a );
+        if (( status = Mul ( SHA_LENGTH, /* s=(temp*k_inverse)mod(dss_q) */
+                                                 temp,
+                                             SHA_LENGTH,
+                                                 k_inverse,
+                                                 SHA_LENGTH,
+                                                 dss_q_a,
+                                                 s_a )) != SUCCESS )
+        {
+                               ERROR_BREAK;
+        }
+  END_PROCESSING
+
+  DSS_ALIGN_FREE(dss_p_a,dss_p);  /*TKL01101*/
+  DSS_ALIGN_FREE(dss_g_a,dss_g);  /*TKL01101*/
+  DSS_ALIGN_FREE(dss_q_a,dss_q);  /*TKL01101*/
+  ALIGN_FREE(dss_x_a);
+  ALIGN_FREE(dss_k_a);
+  ALIGN_FREE(hash_result_a);
+  ALIGN_COPY_FREE(r_a,r,SHA_LENGTH);
+  ALIGN_COPY_FREE(s_a,s,SHA_LENGTH);
+
+    if (DataOrder)
+    {
+        if (dss_p)
+          BigSwap(dss_p, dss_p_bytes);
+        if (dss_q)
+          BigSwap(dss_q, SHA_LENGTH);
+        if (dss_g)
+          BigSwap(dss_g, dss_p_bytes);
+        BigSwap(dss_x, SHA_LENGTH);
+        BigSwap(dss_k, SHA_LENGTH);
+        BigSwap(hash_result, SHA_LENGTH);
+        BigSwap(r, SHA_LENGTH);
+        BigSwap(s, SHA_LENGTH);
+    }
+
+  return status;
+}
+
+/****************************************************************************
+*  NAME:  int VerDSSSignature( u_int16_t dss_p_bytes,
+*                              uchar  *dss_p,
+*                              uchar  *dss_q,
+*                              uchar  *dss_g,
+*                              uchar  *dss_y,
+*                              uchar  *r,
+*                              uchar  *s,
+*                              uchar  *hash_result)
+*
+*  DESCRIPTION:  Verify a DSS Signature
+*
+*  INPUTS:
+*      PARAMETERS:
+*          u_int16_t dss_p_bytes      Length of dss_p
+*          uchar *dss_p            Pointer to p prime
+*          uchar *dss_q            Pointer to q prime
+*          uchar *dss_g            Pointer to g
+*          uchar *dss_y            Pointer to public number
+*          uchar *hash_result      Pointer to message hashing result
+*  OUTPUT:
+*      PARAMETERS:
+*
+*      RETURN:
+*          SUCCESS                  No errors
+*          ERR_SIGNATURE            Signature is not valid
+*          ERR_DSS_LEN              Invalid length for dss_p
+*          ERR_ALLOC                Insufficient memory
+*
+*  REVISION HISTORY:
+*
+*  24 Sep 94   KPZ     Initial release
+*  14 Oct 94   GKL     Second version (big endian support)
+*  26 Oct 94   GKL     (alignment for big endian support & ERR_ALLOC)
+*  08 Dec 94   GKL     Changed Expo call
+*  21 Aug 96   AAB       DoubleExpo call
+****************************************************************************/
+
+int VerDSSSignature( u_int16_t dss_p_bytes,
+                                        uchar  *dss_p,
+                                        uchar  *dss_q,
+                                        uchar  *dss_g,
+                                        uchar  *dss_y,
+                                        uchar  *r,
+                                    uchar  *s,
+                                    uchar  *hash_result)
+{
+     int  status = SUCCESS;          /* function return status */
+        ord  w[(SHA_LENGTH / sizeof(ord)) + 1];
+        ord u1[SHA_LENGTH / sizeof(ord)];
+        ord u2[SHA_LENGTH / sizeof(ord)];
+        ord *v;
+        ord *dss_p_a;
+        ord *dss_g_a;
+        ord *dss_q_a;
+        ord *dss_y_a;
+        ord *hash_result_a;
+        ord *r_a;
+        ord *s_a;
+        if ( (dss_p_bytes < DSS_LENGTH_MIN) ||     /* less than minimal */
+                       (dss_p_bytes > DSS_LENGTH_MAX) )      /* more than maximal */
+        {
+                status = ERR_DSS_LEN;           /* invalid length for dss_p */
+                return status;
+        }
+        if ( dss_p_bytes & 0x07 )          /* not multiple 8 (64 bit)*/
+        {
+            status = ERR_DSS_LEN;          /* invalid length for dss_p */
+            return status;
+        }
+
+    if (DataOrder)
+    {
+        if (dss_p)
+          BigSwap(dss_p, dss_p_bytes);
+        if (dss_q)
+          BigSwap(dss_q, SHA_LENGTH);
+        if (dss_g)
+          BigSwap(dss_g, dss_p_bytes);
+        BigSwap(dss_y, dss_p_bytes);
+        BigSwap(hash_result, SHA_LENGTH);
+        BigSwap(r, SHA_LENGTH);
+        BigSwap(s, SHA_LENGTH);
+    }
+
+        DSS_P_ALIGN_CALLOC_COPY(dss_p, dss_p_a, dss_p_bytes);  /*TKL01101*/
+        DSS_Q_ALIGN_CALLOC_COPY(dss_q, dss_q_a, SHA_LENGTH);   /*TKL01101*/
+        DSS_G_ALIGN_CALLOC_COPY(dss_g, dss_g_a, dss_p_bytes);  /*TKL01101*/
+
+        ALIGN_CALLOC_COPY(dss_y, dss_y_a, dss_p_bytes);
+        ALIGN_CALLOC_COPY(hash_result, hash_result_a, SHA_LENGTH);
+        ALIGN_CALLOC_COPY(r, r_a, SHA_LENGTH);
+        ALIGN_CALLOC_COPY(s, s_a, SHA_LENGTH);
+        CALLOC(v,ord,dss_p_bytes);
+
+        if ( status !=  SUCCESS )
+        {
+                if( dss_p_a )
+            {
+                       DSS_ALIGN_FREE(dss_p_a,dss_p);
+                }
+                if( dss_g_a )
+            {
+                       DSS_ALIGN_FREE(dss_g_a,dss_g);
+                }
+                if ( dss_q_a )
+         {
+                       DSS_ALIGN_FREE(dss_q_a,dss_q);
+                }
+                if( dss_y_a )
+            {
+                        ALIGN_FREE(dss_y_a);
+            }
+                if( hash_result_a )
+            {
+                        ALIGN_FREE(hash_result_a);
+                }
+                if( r_a )
+                {
+                        ALIGN_FREE(r_a);
+                }
+                if( s_a )
+                {
+                        ALIGN_FREE(s_a);
+                }
+               if( v )
+        {
+                   free ( v );
+           }
+        if (DataOrder)
+        {
+            if (dss_p)
+                BigSwap(dss_p, dss_p_bytes);
+            if (dss_q)
+                BigSwap(dss_q, SHA_LENGTH);
+            if (dss_g)
+                BigSwap(dss_g, dss_p_bytes);
+            BigSwap(dss_y, dss_p_bytes);
+            BigSwap(hash_result, SHA_LENGTH);
+            BigSwap(r, SHA_LENGTH);
+            BigSwap(s, SHA_LENGTH);
+        }
+
+               return status;     /* ERR_ALLOC   insufficient memory */
+        }
+
+ BEGIN_PROCESSING
+    if (( status = Inverse( SHA_LENGTH,     /* w=dss_k^(-1)mod(dss_q)*/
+                            s_a,
+                            SHA_LENGTH,
+                            dss_q_a,
+                            w )) !=SUCCESS  )
+    {
+        ERROR_BREAK;
+    }
+    if (( status = Mul ( SHA_LENGTH,    /* u1=(hash_result_*w)mod(dss_q) */
+                         hash_result_a,
+                   SHA_LENGTH,
+                         w,
+                  SHA_LENGTH,
+                         dss_q_a,
+                    u1 )) != SUCCESS )
+    {
+        ERROR_BREAK;
+    }
+    if (( status = Mul ( SHA_LENGTH,    /* u2=(r*w)mod(dss_q) */
+                         r_a,
+                         SHA_LENGTH,
+                         w,
+                         SHA_LENGTH,
+                         dss_q_a,
+                                                         u2 )) != SUCCESS )
+        {
+                 ERROR_BREAK;
+        }
+        /* v = dss_g_a^u1*dss_y_a^u2 moddss_p_a */
+       if((status = DoubleExpo( dss_p_bytes, dss_g_a,
+                                                                        SHA_LENGTH, u1,
+                                                                        dss_p_bytes, dss_y_a,
+                                                                        SHA_LENGTH, u2,
+                                                                        dss_p_bytes, dss_p_a, v)) != SUCCESS )
+       {
+
+                 ERROR_BREAK;
+       }
+       if (( status = PartReduct ( dss_p_bytes,         /*v = v mod(dss_q)*/
+                                                                                                                                                         v,
+                                                                                                                                                                 SHA_LENGTH,
+                                                                                                                                                                dss_q_a,
+                                                                                                                                                                        v )) != SUCCESS )
+                {
+                                       ERROR_BREAK;
+        }
+
+                if (( status = memcmp( r_a, v, SHA_LENGTH)) != 0)   /*if v=r sign valid */
+               {
+                                       status = ERR_SIGNATURE;             /* signature is not valid */
+                ERROR_BREAK;
+    }
+ END_PROCESSING
+   free ( v );
+  DSS_ALIGN_FREE(dss_p_a,dss_p);  /*TKL01101*/
+  DSS_ALIGN_FREE(dss_g_a,dss_g);  /*TKL01101*/
+  DSS_ALIGN_FREE(dss_q_a,dss_q);  /*TKL01101*/
+  ALIGN_FREE(dss_y_a);
+  ALIGN_FREE(hash_result_a);
+  ALIGN_FREE(r_a);
+  ALIGN_FREE(s_a);
+
+  if (DataOrder)
+  {
+      if (dss_p)
+          BigSwap(dss_p, dss_p_bytes);
+      if (dss_q)
+          BigSwap(dss_q, SHA_LENGTH);
+      if (dss_g)
+          BigSwap(dss_g, dss_p_bytes);
+      BigSwap(dss_y, dss_p_bytes);
+      BigSwap(hash_result, SHA_LENGTH);
+      BigSwap(r, SHA_LENGTH);
+      BigSwap(s, SHA_LENGTH);
+  }
+
+  return status;
+}
+
+
+/****************************************************************************
+*  NAME:    int GenDSSKey( u_int16_t dss_p_bytes,
+*                          uchar  *dss_p,
+*                          uchar  *dss_q,
+*                          uchar  *dss_g,
+*                          uchar  *dss_x,
+*                          uchar  *dss_y,
+*                          uchar  *XKEY )
+*
+*
+*  DESCRIPTION:  Compute DSS public/secret number pair.
+*
+*  INPUTS:
+*      PARAMETERS:
+*          u_int16_t dss_p_bytes     Length of modulo
+*          uchar *dss_p           Pointer to modulo
+*          uchar *dss_q           Pointer to modulo
+*          uchar *dss_g           Pointer to public key
+*          uchar *XKEY            Pointer to user supplied random number
+*
+*
+*  OUTPUT:
+*      PARAMETERS:
+*          uchar *dss_x           Pointer to secret key
+*          uchar *dss_y           Pointer to public key
+*          uchar *XKEY            Pointer to updated number
+*
+*      RETURN:
+*          SUCCESS               No errors
+*          ERR_INPUT_LEN         Invalid length for input data
+*          ERR_DATA              Generic data error
+*          ERR_ALLOC             Insufficient memory
+*  REVISION HISTORY:
+*
+*  24 Sep 94   KPZ     Initial release
+*  14 Oct 94   GKL     Second version (big endian support)
+*  26 Oct 94   GKL     (alignment for big endian support & ERR_ALLOC)
+*  08 Dec 94   GKL     Changed Expo call
+*
+****************************************************************************/
+
+int GenDSSKey( u_int16_t dss_p_bytes,
+               uchar  *dss_p,
+               uchar  *dss_q,
+               uchar  *dss_g,
+               uchar  *dss_x,
+               uchar  *dss_y,
+               uchar  *XKEY )
+{
+
+        int  status = SUCCESS;          /* function return status */
+        SHA_context hash_context;       /* SHA context structure */
+        uchar M[DSS_LENGTH_MIN];        /* message block */
+        ord *dss_p_a;
+        ord *dss_q_a;
+        ord *dss_g_a;
+        ord *dss_x_a;
+        ord *dss_y_a;
+        ord *XKEY_a;
+        if ( (dss_p_bytes < DSS_LENGTH_MIN) ||     /* less than minimal */
+           (dss_p_bytes > DSS_LENGTH_MAX) )       /* more than maximal */
+     {
+                         status = ERR_DSS_LEN;           /* invalid length for dss_p */
+                                                        return status;
+        }
+        if ( dss_p_bytes & 0x07 )          /* not multiple 8 (64 bit)*/
+        {
+               status = ERR_DSS_LEN;          /* invalid length for dss_p */
+           return status;
+        }
+     if (DataOrder)
+     {
+         if (dss_p)
+             BigSwap(dss_p, dss_p_bytes);
+         if (dss_q)
+             BigSwap(dss_q, SHA_LENGTH);
+         if (dss_g)
+             BigSwap(dss_g, dss_p_bytes);
+     }
+
+        DSS_P_ALIGN_CALLOC_COPY(dss_p, dss_p_a, dss_p_bytes);  /*TKL01101*/
+        DSS_G_ALIGN_CALLOC_COPY(dss_g, dss_g_a, dss_p_bytes);  /*TKL01101*/
+        DSS_Q_ALIGN_CALLOC_COPY(dss_q, dss_q_a, SHA_LENGTH);   /*TKL01101*/
+        ALIGN_CALLOC(dss_x, dss_x_a, SHA_LENGTH);
+        ALIGN_CALLOC(dss_y, dss_y_a, dss_p_bytes);
+        if ( status !=  SUCCESS )
+        {
+               if( dss_p_a )
+                DSS_ALIGN_FREE(dss_p_a,dss_p);
+               if( dss_g_a )
+                DSS_ALIGN_FREE(dss_g_a,dss_g);
+               if( dss_q_a )
+                DSS_ALIGN_FREE(dss_q_a,dss_q);
+               if( dss_x_a )
+           {
+                    memset(dss_x_a, 0, SHA_LENGTH );
+                    ALIGN_COPY_FREE(dss_x_a,dss_x,SHA_LENGTH);
+           }
+               if( dss_y_a )
+           {
+                        ALIGN_COPY_FREE(dss_y_a,dss_y,dss_p_bytes);
+           }
+
+        if (DataOrder)
+        {
+          if (dss_p)
+             BigSwap(dss_p, dss_p_bytes);
+          if (dss_q)
+             BigSwap(dss_q, SHA_LENGTH);
+          if (dss_g)
+             BigSwap(dss_g, dss_p_bytes);
+        }
+               return status;     /* ERR_ALLOC   insufficient memory */
+        }
+
+  BEGIN_PROCESSING
+        SHAInit ( &hash_context );
+        memcpy( M, XKEY, SHA_LENGTH);
+        memset( M + SHA_LENGTH, 0, DSS_LENGTH_MIN - SHA_LENGTH );
+         if ( (status = SHAUpdate( &hash_context, M, DSS_LENGTH_MIN ))
+                       != SUCCESS )
+        {
+                ERROR_BREAK;
+        }
+        if ( (status = MySHAFinal (&hash_context, (uchar *)dss_x_a)) != SUCCESS )
+        {
+               ERROR_BREAK;
+        }
+        if (( status = PartReduct ( SHA_LENGTH,         /* dss_x = dss_x mod(dss_q)*/
+                                                                                 dss_x_a,
+                                                                                 SHA_LENGTH,
+                                                                                 dss_q_a,
+                                                                                 dss_x_a )) != SUCCESS )
+        {
+                 ERROR_BREAK;
+        }
+
+     BigSwap(XKEY, SHA_LENGTH);
+        ALIGN_CALLOC_COPY(XKEY, XKEY_a, SHA_LENGTH);
+        if ( status !=  SUCCESS )
+        {
+               if( XKEY_a )
+           {
+                        ALIGN_COPY_FREE(XKEY_a,XKEY,SHA_LENGTH);
+             BigSwap(XKEY, SHA_LENGTH);
+             return status;     /* ERR_ALLOC   insufficient memory */
+        }
+     }
+
+        Sum_Q((ord*)XKEY_a, 1, SHA_LENGTH / sizeof (ord) );
+
+        Sum_big( XKEY_a, dss_x_a,  /* XKEY=XKEY+dss_x */
+                        XKEY_a, SHA_LENGTH / sizeof(ord) );
+
+     ALIGN_COPY_FREE(XKEY_a,XKEY,SHA_LENGTH);
+     BigSwap(XKEY, SHA_LENGTH);
+
+        if (( status = Expo ( dss_p_bytes,     /*dss_y = g^dss_x mod(dss_p)*/
+                                                                dss_g_a,
+                                                               SHA_LENGTH,
+                                                                                                                       dss_x_a,
+                                                               dss_p_bytes,
+                    dss_p_a,
+                                                                                                                               dss_y_a)) != SUCCESS ) /*TKL00601*/
+    {
+           ERROR_BREAK;
+    }
+  END_PROCESSING
+
+    DSS_ALIGN_FREE(dss_p_a,dss_p);  /*TKL01101*/
+    DSS_ALIGN_FREE(dss_g_a,dss_g);  /*TKL01101*/
+    DSS_ALIGN_FREE(dss_q_a,dss_q);  /*TKL01101*/
+    ALIGN_COPY_FREE(dss_x_a,dss_x,SHA_LENGTH);
+    ALIGN_COPY_FREE(dss_y_a,dss_y,dss_p_bytes);
+    if (DataOrder)
+    {
+         if (dss_p)
+             BigSwap(dss_p, dss_p_bytes);
+         if (dss_q)
+             BigSwap(dss_q, SHA_LENGTH);
+         if (dss_g)
+             BigSwap(dss_g, dss_p_bytes);
+         BigSwap(dss_x, SHA_LENGTH);
+         BigSwap(dss_y, dss_p_bytes);
+    }
+
+    return status;
+}
+
+
+
+/****************************************************************************
+*  NAME:    int GenDSSNumber( uchar *dss_k,
+*                             uchar *dss_q,
+*                             uchar *KKEY )
+*
+*  DESCRIPTION:  Generate secret number
+*
+*  INPUTS:
+*      PARAMETERS:
+*          uchar *KKEY      Pointer to input random number
+*          uchar *dss_q     Pointer to modulo
+*
+*
+*  OUTPUT:
+*      PARAMETERS:
+*          uchar *dss_x      Pointer to secret number
+*          uchar *KKEY       Pointer to updated KKEY
+*
+*      RETURN:
+*          SUCCESS           No errors
+*          ERR_DATA          Generic data error
+*          ERR_ALLOC         Insufficient memory
+*  REVISION HISTORY:
+*
+*  24 Sep 94   KPZ     Initial release
+*  14 Oct 94   GKL     Second version (big endian support)
+*  26 Oct 94   GKL     (alignment for big endian support & ERR_ALLOC)
+*
+****************************************************************************/
+
+int GenDSSNumber( uchar *dss_k,
+                                         uchar *dss_q,
+                                               uchar *KKEY )
+{
+
+ int  status = SUCCESS;        /* function return status */
+        ord *dss_k_a;
+        ord *dss_q_a;
+        ord *KKEY_a;
+        SHA_context hash_context;     /* SHA context structure*/
+        uchar M[DSS_LENGTH_MIN];      /* message block */
+
+     if (DataOrder)
+     {
+         if (dss_q)
+             BigSwap(dss_q, SHA_LENGTH);
+     }
+
+        DSS_Q_ALIGN_CALLOC_COPY(dss_q, dss_q_a, SHA_LENGTH);   /*TKL01101*/
+        ALIGN_CALLOC(dss_k, dss_k_a, SHA_LENGTH);
+        if ( status !=  SUCCESS )
+        {
+                if( dss_q_a )
+                    DSS_ALIGN_FREE(dss_q_a,dss_q);
+                if( dss_k_a )
+            {
+                        ALIGN_COPY_FREE(dss_k_a,dss_k,SHA_LENGTH);
+            }
+         if (DataOrder)
+         {
+            if (dss_q)
+                BigSwap(dss_q, SHA_LENGTH);
+         }
+         return status;     /* ERR_ALLOC   insufficient memory */
+        }
+
+  BEGIN_PROCESSING
+        SHAInitK ( &hash_context );
+        memcpy( M, KKEY, SHA_LENGTH);
+        memset( M + SHA_LENGTH, 0, DSS_LENGTH_MIN - SHA_LENGTH );
+        if ( (status = SHAUpdate( &hash_context, M, DSS_LENGTH_MIN ))
+                       != SUCCESS )
+        {
+                ERROR_BREAK;
+        }
+        if ( (status = MySHAFinal (&hash_context, (uchar *)dss_k_a)) != SUCCESS )
+        {
+                ERROR_BREAK;
+        }
+        if (( status = PartReduct ( SHA_LENGTH,         /* dss_k = dss_k mod(dss_q)*/
+                                                                                 dss_k_a,
+                                                                                 SHA_LENGTH,
+                                                                                                                                                                 dss_q_a,
+                                                                                 dss_k_a )) != SUCCESS )
+        {
+                 ERROR_BREAK;
+        }
+     BigSwap(KKEY, SHA_LENGTH);
+        ALIGN_CALLOC_COPY(KKEY, KKEY_a, SHA_LENGTH );
+        if ( status !=  SUCCESS )
+        {
+                if ( KKEY_a )
+            {
+                        ALIGN_COPY_FREE(KKEY_a,KKEY,SHA_LENGTH);
+             BigSwap(KKEY, SHA_LENGTH);
+                }
+         return status;     /* ERR_ALLOC   insufficient memory */
+        }
+
+        Sum_Q( KKEY_a, 1, SHA_LENGTH / sizeof(ord));
+
+        Sum_big( KKEY_a, dss_k_a,                    /* KKEY=KKEY+dss_k*/
+                 KKEY_a, SHA_LENGTH  / sizeof(ord) );
+
+        ALIGN_COPY_FREE(KKEY_a,KKEY,SHA_LENGTH);
+     BigSwap(KKEY, SHA_LENGTH);
+
+  END_PROCESSING
+
+        DSS_ALIGN_FREE(dss_q_a,dss_q);  /*TKL01101*/
+
+        ALIGN_COPY_FREE(dss_k_a,dss_k,SHA_LENGTH);
+     if (DataOrder)
+     {
+         if (dss_q)
+             BigSwap(dss_q, SHA_LENGTH);
+         BigSwap(dss_k, SHA_LENGTH);
+     }
+
+        return status;
+}
+
+
+/****************************************************************************
+*  NAME: int GenDSSParameters( u_int16_t dss_p_bytes,
+*                               uchar  *dss_p,
+*                               uchar  *dss_q,
+*                               uchar *dss_g,
+*                               uchar  *RVAL,
+*                                                 YIELD_context *yield_cont )
+*
+*  DESCRIPTION: Generate DSS Common Parameters
+*
+*  INPUTS:
+*      PARAMETERS:
+*            u_int16_t dss_p_bytes    Number of bytes in dss_p
+*            uchar  *RVAL          Pointer to user supplied random number
+*            YIELD_context *yield_cont  Pointer to yield_cont structure (NULL if not used)
+*  OUTPUT:
+*      PARAMETERS:
+*            uchar *dss_p          Pointer to N-byte prime number
+*            uchar *dss_q          Pointer to SHA_LENGTH prime number
+*            uchar *dss_g          Pointer to N-byte number
+*      RETURN:
+*          SUCCESS              No errors
+*          ERR_INPUT_LEN        Invalid length for input data(zero bytes)
+*          ERR_DSS_LEN;         Invalid length for dss_p
+*          ERR_ALLOC            Insufficient memory
+*  REVISION HISTORY:
+*
+*  24 Sep 94   KPZ     Initial release
+*  14 Oct 94   GKL     Second version (big endian support)
+*  26 Oct 94   GKL     (alignment for big endian support & ERR_ALLOC)
+*  08 Dec 94   GKL      Added YIELD_context
+*
+****************************************************************************/
+
+ int GenDSSParameters( u_int16_t dss_p_bytes,
+                                        uchar  *dss_p,
+                                       uchar  *dss_q,
+                               uchar  *dss_g,
+                               uchar  *RVAL,
+                        YIELD_context *yield_cont ) /*TKL00701*/
+{
+        int status = SUCCESS;      /* function return status */
+        ord seed[SHA_LENGTH / sizeof (ord)];
+        ord u[SHA_LENGTH / sizeof (ord)];            /* work buffers */
+        ord u1[SHA_LENGTH / sizeof (ord)];
+        ord  *dss_p_a;
+        ord  *dss_q_a;
+        ord  *dss_g_a;
+        ord  *RVAL_a;
+        ord ofone[SHA_LENGTH / sizeof(ord)];
+        ord dss_q2[SHA_LENGTH / sizeof(ord) + 1];  /* dss_q2 = 2 * q */
+        ord v[SHA_LENGTH / sizeof(ord)];
+        ord *w, *c, *c1, *one, *e;           /* Pointers to work buffers */
+        u_int16_t i, n, count, offset, k;          /* counters */
+        u_int16_t dss_p_longs;                 /* number of longs */
+        if ( dss_p_bytes == 0 )    /* invalid length for input data (zero bytes) */
+        {
+                 status = ERR_INPUT_LEN;
+          return status;
+        }
+        if ( (dss_p_bytes < DSS_LENGTH_MIN) ||     /* less than minimal */
+                 (dss_p_bytes > DSS_LENGTH_MAX) )      /* more than maximal */
+        {
+             status = ERR_DSS_LEN;           /* invalid length for dss_p */
+          return status;
+     }
+        if ( dss_p_bytes & 0x07 )          /* not multiple 4 (64 bit)*/
+     {
+                status = ERR_DSS_LEN;          /* invalid length for dss_p */
+            return status;
+        }
+
+        n = (u_int16_t) (dss_p_bytes / SHA_LENGTH);       /* SHA passes count */
+        dss_p_longs = (u_int16_t) (dss_p_bytes / sizeof(ord));  /* number of long in dss_p */
+        CALLOC(w, ord, (n + 1) * SHA_LENGTH);
+        CALLOC(c, ord, dss_p_bytes);
+        CALLOC(c1, ord, dss_p_bytes);
+        CALLOC(one, ord, dss_p_bytes);
+        CALLOC(e,ord, dss_p_bytes - SHA_LENGTH + sizeof(ord));
+        ALIGN_CALLOC_MOVE(RVAL, RVAL_a, SHA_LENGTH);
+        ALIGN_CALLOC(dss_p, dss_p_a, dss_p_bytes);
+        ALIGN_CALLOC(dss_q, dss_q_a, SHA_LENGTH);
+        ALIGN_CALLOC(dss_g, dss_g_a, dss_p_bytes);
+        if ( status !=  SUCCESS )
+        {
+           if( e )
+                       free ( e );
+           if( one )
+                       free ( one );
+           if( c )
+                       free ( c );
+           if( w )
+                       free ( w );
+           if( c1 )
+                   free ( c1 );
+           if( dss_p_a )
+           {
+                   ALIGN_COPY_FREE(dss_p_a, dss_p, dss_p_bytes);
+           }
+               if( dss_q_a )
+           {
+                   ALIGN_COPY_FREE(dss_q_a, dss_q, SHA_LENGTH);
+           }
+               if( dss_g_a )
+           {
+                       ALIGN_COPY_FREE(dss_g_a, dss_g, dss_p_bytes);
+           }
+               if( RVAL_a )
+           {
+                       ALIGN_MOVE_FREE(RVAL_a, RVAL, SHA_LENGTH);
+               }
+        return status;     /* ERR_ALLOC   insufficient memory */
+         }
+        one[0] = 1;
+        BEGIN_PROCESSING   /* Generate DSS Common Parameters */
+
+                         BEGIN_LOOP   /* Generate prime & dss_p */  /*TKL00501*/
+                                       /* generate prime number of length 160-bit */
+                                       do
+                                       {
+                                                MyGenRand( SHA_LENGTH, seed, RVAL_a);  /* generate random number */
+                                                                               /* compute message digest from seed */
+                                                if ( (status = MySHA((uchar *)seed, SHA_LENGTH, (uchar *)u)) != SUCCESS )
+                                                {
+                                                         break;  /* error */
+                                                }
+                                                memcpy(ofone, seed,SHA_LENGTH);
+                                                Sum_Q( ofone, 1, SHA_LENGTH / sizeof(ord) );
+                                       /* compute message digest from seed */
+                                                if ( (status = MySHA( (uchar *)ofone, SHA_LENGTH,(uchar *)dss_q_a)) != SUCCESS )
+                                                {
+                                                                                                       break;  /* error */
+                                                }
+
+                                                for ( i = 0; i < (SHA_LENGTH / sizeof(ord)); i++ )  /* dss_q = dss_q ^ u */
+                                                                                         {
+                                                         dss_q_a[i] = dss_q_a[i] ^ u[i];
+                                                }
+                                         /* set least and most significant bits */
+                                                dss_q_a[SHA_LENGTH / sizeof(ord) - 1] |= ((ord)1 << (BITS_COUNT-1));
+                                                                        dss_q_a[0] |= 0x01;
+                                                       } while ( VerPrime( SHA_LENGTH, dss_q_a, TEST_COUNT, RVAL_a, yield_cont) /*TKL00701*/
+                                                                                                                                != SUCCESS );   /* perform a robust primality test */
+                                                       if (status != SUCCESS )
+                                                                {
+                                                                         ERROR_BREAK;
+                                                        }
+                                                 /* dss_q2 = 2 * dss_q */
+                                                        memcpy( dss_q2, dss_q_a, SHA_LENGTH );
+                                                        dss_q2[SHA_LENGTH / sizeof(ord)] = 0;
+                                                        LShiftL_big( dss_q2, SHA_LENGTH  / sizeof(ord) +1, 1 );
+                                                        count = 0;
+                                                        offset = 2;
+                                                        memset( ofone, 0, SHA_LENGTH );
+                                                                do   /* find dss_p */
+                                                                       {
+                                                                        /* generate random number by dss_p bytes */
+                                                                                 for ( k = 0;  k <= n; k++ )
+                                                                         {
+                                                                                                       ofone[0] = offset + k;
+                                                                                                       /* v = ofone + seed */
+                                                                                                Sum_big( seed, ofone, v, SHA_LENGTH / sizeof(ord) );
+                                                                                               if ( (status = MySHA ( (uchar *)v, SHA_LENGTH,
+                                                                                                                                                        (uchar *)( w + (SHA_LENGTH / sizeof(ord)) * k )))
+                                                                                                                                                                       != SUCCESS ) /* compute message digest */
+                                                                                                       {
+                                                                                                                         break; /* error */
+                                                                                                 }
+                                                                                }
+                                                                                if (status != SUCCESS )
+                                                                                       {
+                                                                                                 break; /* error */
+                                                                                }
+                                                                        /* set most significant bit */
+                                                                         w[dss_p_longs - 1] |= ((ord)1 << (BITS_COUNT-1));
+                                                                                memcpy( c, w, dss_p_bytes);
+                                                                 /* c1 = c mod(dss_q2) */
+                                                                                         if( (status = PartReduct( dss_p_bytes, c,
+                                                                                                                                                                                                                                SHA_LENGTH + sizeof(ord),
+                                                                                                                                                                                                                                       dss_q2, c1)) != SUCCESS )
+                                                                                       {
+                                                                                                       break; /* error */
+                                                                               }
+                                                                        /* c1 = c1 - 1*/
+                                                                                         Sub_big( c1, one, c1, dss_p_longs );
+                                                                /* dss_p = w - c1 */
+                                                                                Sub_big( w, c1, dss_p_a, dss_p_longs );
+                                                                                       if ( dss_p_a[dss_p_bytes / sizeof(ord) - 1] >= (ord)((ord)1 << (BITS_COUNT-1)) )
+                                                                                 {
+                                                                                                       if ( VerPrime ( dss_p_bytes, dss_p_a, TEST_COUNT, RVAL_a, yield_cont) /*TKL00701*/
+                                                                                                                                                                                        == SUCCESS ) /* perform a robust primality test */
+                                                                                                 {
+                                                                                                                         break;
+                                                                                                               }
+                                                                                }
+                                                                                count++;
+                                                                                offset = (u_int16_t) (offset + n + 1);
+                                                               } while ( count < 4096);
+                                                               if (status != SUCCESS )
+                                                                {
+                                                                         ERROR_BREAK;
+                                                        }
+                                                         if (count != 4096)          /*TKL00501*/
+                                                               {
+                                                                         BREAK;                    /*TKL00501*/
+                                                 }
+                END_LOOP     /* Generate dss_p */   /*TKL00501*/
+
+                 if (status != SUCCESS )
+                       {
+                                 ERROR_BREAK;
+         }
+                dss_p_a[0] -= 1;   /* dss_p = dss_p - 1 */
+               if ( (status= DivRem (dss_p_bytes, dss_p_a, SHA_LENGTH, dss_q_a, u1,
+                                                                                                                                 e )) != SUCCESS )  /* e = dss_p / dss_q */
+                 {
+                                 ERROR_BREAK;
+         }
+                dss_p_a[0] += 1;    /* dss_p = dss_p + 1 */
+
+         BEGIN_LOOP   /* Generate dss_g */   /*TKL00501*/
+                                                       MyGenRand( SHA_LENGTH, u, RVAL_a );  /*generate random number*/
+                                         u[SHA_LENGTH / sizeof(ord) - 1] &= ~((ord)1 << (BITS_COUNT-1));       /* u < dss_q */
+                                                if ( (status = Expo( SHA_LENGTH, u, (u_int16_t)(dss_p_bytes - SHA_LENGTH +
+                                                                                                                                                        sizeof(ord)), e, dss_p_bytes, dss_p_a, dss_g_a )) 
+                                                                                                                                                                       != SUCCESS ) /* dss_g = e ^ u mod(dss_p) */
+                                                 {
+                                                                                ERROR_BREAK;
+                                                 }
+                                                         if ( dss_g_a[0] == 1 )   /* check dss_g == 1 */
+                                         {
+                                                                 for ( i = 1; i < (dss_p_bytes / sizeof(ord)); i++ )
+                                                       {
+                                                                               if ( dss_g_a[i] != 0 )
+                                                                                        {
+                                                                                                       break;
+                                                                                        }
+                                                               }
+                                                         if ( i == (dss_p_bytes / sizeof(ord)) )
+                                                                {
+                                                                               CONTINUE;
+                                                               }
+                                                 }
+                                                         BREAK;                                 /*TKL00501*/
+                 END_LOOP   /* Generate dss_g */             /*TKL00501*/
+         END_PROCESSING   /* Generate DSS Common Parameters */
+       free ( e );
+         free ( one );
+       free ( c );
+         free ( w );
+         free ( c1 );
+        ALIGN_COPY_FREE(dss_p_a, dss_p, dss_p_bytes);
+       ALIGN_COPY_FREE(dss_q_a, dss_q, SHA_LENGTH);
+        ALIGN_COPY_FREE(dss_g_a, dss_g, dss_p_bytes);
+       ALIGN_MOVE_FREE(RVAL_a, RVAL, SHA_LENGTH);
+    if (DataOrder)
+    {
+        BigSwap(dss_p, dss_p_bytes);
+        BigSwap(dss_q, SHA_LENGTH);
+        BigSwap(dss_g, dss_p_bytes);
+    }
+       return status;
+}
+
+
+/****************************************************************************
+*  NAME: int GetDSSPQG(u_int16_t dss_p_bytes,
+*                      uchar  *dss_p,
+*                      uchar  *dss_q,
+*                      uchar  *dss_g)
+*
+*  DESCRIPTION: Copy Cylink DSS P,Q,G numbers to *dss_p,*dss_q,*dss_g
+*
+*  INPUTS:
+*      PARAMETERS:
+*            u_int16_t dss_p_bytes    Number of bytes in dss_p
+*            uchar *dss_p          Pointer to N-byte buffer
+*            uchar *dss_q          Pointer to SHA_LENGTH-byte buffer
+*            uchar *dss_g          Pointer to N-byte buffer
+*  OUTPUT:
+*      RETURN:
+*          SUCCESS              No errors
+*          ERR_DSS_LEN;         Invalid length for dss_p
+*  REVISION HISTORY:
+*
+*  22 Apr 95   GKL     Initial release       LOG TKL01201
+*
+****************************************************************************/
+int GetDSSPQG(u_int16_t dss_p_bytes,
+              uchar  *dss_p,
+              uchar  *dss_q,
+              uchar  *dss_g)
+{
+  int  status = SUCCESS;          /* function return status */
+  ord *dss_p_a;
+  ord *dss_g_a;
+
+  if ( (dss_p_bytes < DSS_LENGTH_MIN) ||     /* less than minimal */
+       (dss_p_bytes > DSS_LENGTH_MAX) )      /* more than maximal */
+  {
+      status = ERR_DSS_LEN;           /* invalid length for dss_p */
+      return status;
+  }
+  if ( dss_p_bytes & 0x07 )          /* not multiple 8 (64 bit)*/
+  {
+      status = ERR_DSS_LEN;          /* invalid length for dss_p */
+      return status;
+  }
+  dss_p_a = &DSS_P_NUMBERS[DSS_NUM_INDEX[(dss_p_bytes-DSS_LENGTH_MIN)/LENGTH_STEP]];
+  dss_g_a = &DSS_G_NUMBERS[DSS_NUM_INDEX[(dss_p_bytes-DSS_LENGTH_MIN)/LENGTH_STEP]];
+  OrdByte(dss_p_a,dss_p_bytes,dss_p);
+  OrdByte(dss_g_a,dss_p_bytes,dss_g);
+  OrdByte(DSS_Q_NUMBER,SHA_LENGTH,dss_q);
+  if (DataOrder)
+  {
+      BigSwap(dss_p, dss_p_bytes);
+      BigSwap(dss_q, SHA_LENGTH);
+      BigSwap(dss_g, dss_p_bytes);
+  }
+
+  return status;
+}
+
+
diff --git a/lib/bind/cylink/dssnum.h b/lib/bind/cylink/dssnum.h
new file mode 100644 (file)
index 0000000..82a846f
--- /dev/null
@@ -0,0 +1,724 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/**********************************************************************\
+*  FILENAME:  DSSNum.h   PRODUCT NAME: CRYPTOGRAPHIC TOOLKIT
+*
+*  DESCRIPTION:   Standard Cylink DSS numbers (P Q G) support.
+*
+*  USAGE:       File should be included to get access to
+*               Cylink DSS numbers 
+*
+*
+*      Copyright (c) Cylink Corporation 1995. All rights reserved.
+*
+*  REVISION  HISTORY:
+*    10 APR 95  GKL    Initial release 
+*
+\**********************************************************************/
+#ifndef DSSNUMBER_H    /* Prevent multiple inclusions */
+#define DSSNUMBER_H
+
+#include "ctk_endian.h"
+
+#define LENGTH_MULT_TO_64
+
+#define F0  0
+#define F1  (F0  + 1)
+#define F2  (F1  + 2)
+#define F3  (F2  + 3)
+#define F4  (F3  + 4)
+#define F5  (F4  + 5)
+#define F6  (F5  + 6)
+#define F7  (F6  + 7)
+#define F8  (F7  + 8)
+#define F9  (F8  + 9)
+#define F10 (F9  + 10)
+#define F11 (F10 + 11)
+#define F12 (F11 + 12)
+#define F13 (F12 + 13)
+#define F14 (F13 + 14)
+#define F15 (F14 + 15)
+
+
+#ifdef LENGTH_MULT_TO_64
+#define LENGTH_STEP 8U
+#define LAST_F F8
+#endif
+
+#ifdef LENGTH_MULT_TO_32
+#define LENGTH_STEP 4U
+#define LAST_F (F15 + 16)
+#endif
+
+
+#define DSS_LENS_NUMBER (int) (1 + ( DSS_LENGTH_MAX - DSS_LENGTH_MIN )/LENGTH_STEP)
+
+#define DSS_LAST_INDEX  (DSS_LENGTH_MIN*DSS_LENS_NUMBER + LENGTH_STEP*LAST_F)/sizeof(ord)
+
+#ifndef INITIALIZ_PQG
+
+extern ushort DSS_NUM_INDEX[ DSS_LENS_NUMBER ];
+extern ord DSS_Q_NUMBER[SHA_LENGTH/sizeof(ord)];
+extern ord DSS_P_NUMBERS[DSS_LAST_INDEX];
+extern ord DSS_G_NUMBERS[DSS_LAST_INDEX];
+
+#else
+ushort DSS_NUM_INDEX[ DSS_LENS_NUMBER ] =
+{
+   (DSS_LENGTH_MIN*0  + LENGTH_STEP*0  )/sizeof(ord),
+   (DSS_LENGTH_MIN*1  + LENGTH_STEP*F0 )/sizeof(ord),
+   (DSS_LENGTH_MIN*2  + LENGTH_STEP*F1 )/sizeof(ord),
+   (DSS_LENGTH_MIN*3  + LENGTH_STEP*F2 )/sizeof(ord),
+   (DSS_LENGTH_MIN*4  + LENGTH_STEP*F3 )/sizeof(ord),
+   (DSS_LENGTH_MIN*5  + LENGTH_STEP*F4 )/sizeof(ord),
+   (DSS_LENGTH_MIN*6  + LENGTH_STEP*F5 )/sizeof(ord),
+   (DSS_LENGTH_MIN*7  + LENGTH_STEP*F6 )/sizeof(ord),
+   (DSS_LENGTH_MIN*8  + LENGTH_STEP*F7 )/sizeof(ord)
+#ifdef LENGTH_MULT_TO_32
+   ,
+   (DSS_LENGTH_MIN*9  + LENGTH_STEP*F8 )/sizeof(ord),
+   (DSS_LENGTH_MIN*10 + LENGTH_STEP*F9 )/sizeof(ord),
+   (DSS_LENGTH_MIN*11 + LENGTH_STEP*F10)/sizeof(ord),
+   (DSS_LENGTH_MIN*12 + LENGTH_STEP*F11)/sizeof(ord),
+   (DSS_LENGTH_MIN*13 + LENGTH_STEP*F12)/sizeof(ord),
+   (DSS_LENGTH_MIN*14 + LENGTH_STEP*F13)/sizeof(ord),
+   (DSS_LENGTH_MIN*15 + LENGTH_STEP*F14)/sizeof(ord),
+   (DSS_LENGTH_MIN*16 + LENGTH_STEP*F15)/sizeof(ord)
+#endif
+};
+
+ord DSS_Q_NUMBER[SHA_LENGTH/sizeof(ord)] =
+#ifdef ORD_16
+        {
+          0x8fb7, 0x81f0, 0x6b9e, 0x122a, 0x4dc4, 0x03ca, 0xc896, 0x8d0e, 0xbe3b, 0xed4b
+        };
+#else
+        {
+                         0x81f08fb7L, 0x122a6b9eL, 0x03ca4dc4L, 0x8d0ec896L, 0xed4bbe3bL
+        };
+#endif
+
+
+ord DSS_P_NUMBERS[DSS_LAST_INDEX] =
+#ifdef ORD_16
+        {
+     /* dss_p length = 512*/
+     0x92b7, 0xbd96, 0x9aab, 0x584c, 0xd617, 0xf2f0, 0xda85, 0xd370,
+     0xcc82, 0x273e, 0x6b04, 0xc171, 0x5c32, 0xd3ff, 0x352e, 0xf2f8,
+     0x4fc2, 0x20bc, 0xbdec, 0xe96e, 0x3503, 0x4d89, 0xe92d, 0xeb7d,
+     0x9c1a, 0x7852, 0xfe2a, 0x0a25, 0x4446, 0xce18, 0x7829, 0x95d8,
+#ifdef LENGTH_MULT_TO_32
+     /* dss_p length = 544*/
+     0x12db, 0x0d31, 0x9950, 0x16c9, 0x3045, 0x0acb, 0x3c46, 0x3c5c,
+     0x6c94, 0x2458, 0x0736, 0x13da, 0xa0af, 0x790f, 0xb177, 0xa6ae,
+     0xd111, 0x2bda, 0x697c, 0x49a2, 0xe3e5, 0x6f27, 0x02f5, 0x9bc9,
+     0xd4da, 0x7d9b, 0x89c6, 0x63bc, 0x0b6d, 0xfe2d, 0xc7a1, 0x435f,
+     0x7fad, 0x9e40,
+#endif
+     /* dss_p length = 576*/
+     0x626b, 0x41b5, 0xd218, 0x25bf, 0x1825, 0x42b3, 0x9eb0, 0xc244,
+     0x96ce, 0x22ac, 0x3ac6, 0x713f, 0x321d, 0x398c, 0x3022, 0xbc49,
+     0xdd03, 0x52d5, 0x29f8, 0x2a57, 0x8fa1, 0x2173, 0xee7d, 0xb90d,
+     0xcc64, 0x5fae, 0xaa81, 0xe3d0, 0x648f, 0xfa6e, 0xdc6c, 0x039f,
+   0x2cd6, 0xc552, 0xe2dc, 0xebec,
+#ifdef LENGTH_MULT_TO_32
+     /* dss_p length = 608*/
+     0x35f5, 0xb2af, 0x27d0, 0x398b, 0x493d, 0x6f2e, 0xbe27, 0xe5b5,
+     0x972c, 0x3470, 0x9638, 0xe90e, 0xf7b7, 0x98ad, 0xd091, 0xb4ca,
+     0x3f43, 0x5f58, 0xb6c5, 0xd014, 0x25ee, 0x414d, 0xe2c1, 0x6fd6,
+     0xd737, 0x9be6, 0x66ca, 0xe241, 0x1897, 0xf740, 0xe5df, 0xceb0,
+     0xdb38, 0xabc8, 0x8af8, 0xc58b, 0xc6a0, 0x9a04,
+#endif
+     /* dss_p length = 640*/
+     0x4095, 0xf6bf, 0x7568, 0x4032, 0x5c0f, 0x64f2, 0x5aae, 0xb099,
+     0x346f, 0x0e81, 0x357a, 0x7aeb, 0x0291, 0xfd0a, 0x8d54, 0xce80,
+     0x0c05, 0xbea3, 0x889f, 0x8a1b, 0xf1c1, 0x6049, 0x214a, 0x8ec3,
+     0xb926, 0xdde1, 0x61b4, 0x384e, 0x404b, 0xb6d7, 0x2e2d, 0x4584,
+     0xae6a, 0xcc7a, 0x7bfa, 0x9eb0, 0x3a26, 0x3904, 0x8cac, 0xc036,
+#ifdef LENGTH_MULT_TO_32
+     /* dss_p length = 672*/
+     0x0abb, 0xaea3, 0xc749, 0x757c, 0x3035, 0x29d0, 0x46bd, 0xd56c,
+     0xf49d, 0xa355, 0x1297, 0x8dcb, 0x9802, 0xc58c, 0xf1ec, 0x8aac,
+     0x55dd, 0xb107, 0x0140, 0x26d1, 0x8a5d, 0x8a90, 0xf33e, 0xde0b,
+   0xb844, 0xb429, 0x4db2, 0x9806, 0xf629, 0x4c3b, 0xcd76, 0x2f23,
+     0x6c68, 0x7bf4, 0x2a7e, 0xd982, 0xc89f, 0x16a2, 0xfe84, 0x953c,
+     0x3e4a, 0x8de8,
+#endif
+     /* dss_p length = 704*/
+     0x0113, 0x1535, 0xca0b, 0x8faf, 0xa327, 0x989c, 0x12c8, 0xe512,
+     0x796f, 0x1229, 0x12bf, 0x62c8, 0xa50a, 0x2b99, 0xc93b, 0x450c,
+     0x71ad, 0x0826, 0xf4c6, 0x3913, 0x9b6e, 0x96da, 0xa08d, 0xbc5e,
+     0xd4d3, 0x7b26, 0xf9fd, 0xdd76, 0x4e82, 0x2f06, 0x1f96, 0xbf47,
+     0xcadf, 0x3610, 0x917b, 0x4e94, 0xe2e8, 0x0eaf, 0x1cb9, 0x6b90,
+     0xb917, 0x6d6f, 0x92b9, 0xb329,
+#ifdef LENGTH_MULT_TO_32
+     /* dss_p length = 736*/
+     0x6dad, 0xd878, 0xc913, 0xe61e, 0x87d9, 0xe275, 0xad24, 0xf090,
+     0xe12b, 0xfdfe, 0x39a3, 0xc9a1, 0x8330, 0x138a, 0x4bed, 0xc319,
+     0x8094, 0x88ba, 0x4b80, 0x1325, 0x7852, 0x67e2, 0x715e, 0x7313,
+     0x3b4e, 0x7727, 0x9870, 0x5c6e, 0xe0ce, 0xc67a, 0xd057, 0xf3c5,
+     0x55ea, 0x98ba, 0x6ea0, 0xaee7, 0x31e8, 0x3cd6, 0x0e28, 0x42d1,
+     0x8946, 0xc395, 0x34fc, 0x1b9d, 0x19d1, 0x86f9,
+#endif
+     /* dss_p length = 768*/
+     0xe293, 0xea08, 0xcdd0, 0xf668, 0x8b2a, 0x06db, 0x7c71, 0xadb2,
+     0x943d, 0x6721, 0x54f5, 0xbc44, 0xf7ca, 0x3345, 0x1bf6, 0x0b90,
+     0xb475, 0xd3c4, 0xbdb6, 0x7caa, 0xa45f, 0xe9b4, 0x6e0e, 0x0c1a,
+     0xb5c3, 0x9760, 0x851a, 0x53af, 0x96b7, 0x4979, 0xf162, 0xe951,
+     0x6a54, 0xd020, 0x9ded, 0xdecb, 0xfc81, 0x7d74, 0x5e92, 0x2aee,
+     0x0946, 0x0eb5, 0x3700, 0x9bce, 0x845a, 0xa7a3, 0x157a, 0x8618,
+#ifdef LENGTH_MULT_TO_32
+     /* dss_p length = 800*/
+     0xb0a1, 0xac27, 0xec4e, 0xf623, 0x55e2, 0x2cb6, 0x288b, 0x4b28,
+     0xd74e, 0xbbe6, 0xfdf7, 0xaecd, 0x5758, 0xe251, 0x9074, 0x1aee,
+     0xe6ed, 0x4d5e, 0x01d9, 0x529e, 0xf736, 0x0091, 0x0212, 0xc725,
+     0x60ce, 0x966f, 0x851d, 0x5c4b, 0x80de, 0x34df, 0x1c88, 0x0636,
+     0xbb71, 0x32ce, 0x45cb, 0x86da, 0x4d0e, 0x13e0, 0x7d7d, 0x544b,
+     0x1272, 0x747f, 0xd6a7, 0xfa3b, 0xcb86, 0x6b43, 0x66f5, 0xd012,
+     0xfe7a, 0xa0cb,
+#endif
+     /* dss_p length = 832*/
+     0xed2d, 0x84dd, 0xf274, 0xdd8f, 0xcd5f, 0x7928, 0xbfc6, 0xa522,
+     0xe4e4, 0x50f0, 0xcddf, 0x5842, 0xbb29, 0x7c4d, 0xeef4, 0x6946,
+     0x87f6, 0xe486, 0x61b5, 0xc1b6, 0xadef, 0x575a, 0x360f, 0x724f,
+     0xcb29, 0x591b, 0x9a4c, 0xf7bc, 0x309e, 0xa348, 0x0ff5, 0x94f3,
+     0x932f, 0x9dc6, 0x992c, 0xc6d7, 0x12f6, 0xc2d7, 0x38aa, 0x8c01,
+     0x5dca, 0x74f4, 0xfcfd, 0x4cf4, 0x588a, 0x7837, 0x097e, 0xd2e2,
+     0x6eac, 0x8869, 0xe92f, 0xec62,
+#ifdef LENGTH_MULT_TO_32
+     /* dss_p length = 864*/
+     0x7c21, 0x931e, 0x553d, 0x00f2, 0xa860, 0x940f, 0x411e, 0x7d20,
+     0xb168, 0x52a3, 0x69ee, 0x166e, 0xb9e6, 0x1b23, 0xd5e0, 0xef64,
+     0x2850, 0x724c, 0xc1fe, 0xea73, 0xda8c, 0xe342, 0x1d7b, 0xd256,
+     0x359b, 0x180f, 0xd7f5, 0xca77, 0x06ac, 0x2162, 0xa977, 0x78bb,
+     0x5018, 0x5de2, 0x6061, 0xe217, 0x4d42, 0xfed1, 0x3929, 0xd50f,
+     0xc946, 0x2433, 0x15f8, 0x361b, 0xbf51, 0x3ff0, 0x3efa, 0x3157,
+     0x7350, 0x53a0, 0xd1a4, 0x261b, 0xde5b, 0x9236,
+#endif
+     /* dss_p length = 896*/
+     0x8e21, 0x0364, 0x86d2, 0xe58c, 0x2274, 0x780a, 0x9ffc, 0x4951,
+     0x3f99, 0xbc96, 0x9e60, 0x5a7e, 0x010a, 0x23d4, 0x54d1, 0x48e9,
+     0xfd6b, 0x979c, 0x5202, 0x8af3, 0x5d87, 0xfe8f, 0x3e3c, 0x1e0c,
+     0xe294, 0xcc52, 0xa8d6, 0x480e, 0xa898, 0xd4ce, 0x5949, 0xd341,
+     0xe325, 0xf41b, 0x72d6, 0x6a90, 0x7a8b, 0x6f14, 0x3e2b, 0x6636,
+     0x3748, 0x4eea, 0xa590, 0x03e4, 0x0524, 0x9c32, 0xeb53, 0x02af,
+     0xca71, 0x6792, 0xd673, 0xedf8, 0x6448, 0x59c3, 0x7319, 0x883f,
+#ifdef LENGTH_MULT_TO_32
+     /* dss_p length = 928*/
+     0xc17d, 0xa4e8, 0xea08, 0x8ff8, 0x2cb0, 0x73f5, 0xd7ba, 0xc027,
+     0xb9c8, 0x989d, 0xe5fe, 0xe3a1, 0xf324, 0x39d3, 0xf142, 0x5ba8,
+     0xe6cb, 0x3708, 0xa0b7, 0xed9a, 0xb6b3, 0xe314, 0xf80a, 0x6778,
+     0x4d27, 0x7107, 0x6ee8, 0xb9c2, 0xc6af, 0xab70, 0x53be, 0xc445,
+     0x7926, 0x34bb, 0x5191, 0xe11d, 0x67f1, 0xcc3a, 0x5354, 0xd34d,
+     0xa1ac, 0x08ba, 0x32d4, 0x068a, 0x7c3b, 0x415f, 0xbce0, 0xb549,
+     0x0ecf, 0x538f, 0xb5d0, 0x22a3, 0x1d47, 0xe837, 0x14c0, 0x69dd,
+     0xa02d, 0xce91,
+#endif
+     /* dss_p length = 960*/
+     0x1ff3, 0xf77e, 0xae7a, 0x5a28, 0x43b1, 0xe187, 0x2e04, 0xb3ea,
+     0x7394, 0xa3e8, 0x4985, 0xc9bc, 0x7b7d, 0x1e1c, 0xd99c, 0x55f8,
+     0x447b, 0x5704, 0xd758, 0xbed1, 0xe698, 0x2a5e, 0x5c19, 0xc206,
+     0x6d38, 0x1f88, 0x2ea4, 0x5f15, 0xebfd, 0xd716, 0x8a2a, 0xf960,
+     0x83ac, 0xc493, 0xb966, 0x8f13, 0x4778, 0x9682, 0x4712, 0x84cd,
+     0xbb4e, 0xe567, 0x644f, 0x0780, 0x133d, 0x0b0a, 0xe42e, 0x06e8,
+     0xa4cc, 0x3131, 0x39d9, 0xfaf8, 0x12a3, 0x5550, 0x43b1, 0xb8a9,
+     0xb0eb, 0x0fad, 0x986f, 0xd427,
+#ifdef LENGTH_MULT_TO_32
+     /* dss_p length = 992*/
+     0xbcfd, 0x363f, 0x050a, 0x18f0, 0x78d8, 0xcac9, 0x423a, 0xf31e,
+     0x198f, 0xd0c3, 0xb319, 0x5d1b, 0x917a, 0xc0b0, 0x8d1b, 0x6b91,
+     0xea69, 0xa9d1, 0x02ce, 0x5345, 0x2c80, 0x6992, 0x4dad, 0x7a28,
+     0xbb75, 0xd46d, 0x0faa, 0x5612, 0x6878, 0x8a0e, 0x63b4, 0x46ab,
+     0xaca0, 0x5381, 0xb90a, 0x3e70, 0x19c4, 0xb639, 0xf778, 0xe751,
+     0x5974, 0xb726, 0x589f, 0x8679, 0xeb04, 0xc0b5, 0xdffd, 0x2b32,
+     0x4b51, 0xc632, 0xd8c6, 0x9501, 0x4f94, 0x2026, 0x253a, 0x0d27,
+     0x07bb, 0x0838, 0x2725, 0xa3eb, 0x3c4e, 0x89b6,
+#endif
+     /* dss_p length = 1024*/
+     0xa141, 0xecf7, 0xc6d6, 0x867d, 0xefa3, 0x1cdd, 0x6c9d, 0x6ca5,
+     0x2e2f, 0x68af, 0x90e1, 0x1d3e, 0xd75f, 0x0c2a, 0x844b, 0x36c7,
+     0x3420, 0xfd1a, 0xb9ee, 0xf6e5, 0x5fde, 0xc8ed, 0x0c90, 0xd353,
+     0x6faa, 0x80a4, 0x5bbd, 0xa59d, 0x9e72, 0x3223, 0x8f59, 0xf33d,
+     0x10eb, 0xeccd, 0x184e, 0x3e2a, 0x4c07, 0x564b, 0x4c0a, 0x3263,
+     0xc535, 0x8aeb, 0xf982, 0x2be2, 0xe475, 0x9b87, 0xcca0, 0x4d08,
+     0x3adf, 0x0484, 0xd528, 0x7acd, 0x304d, 0x55a0, 0x70ae, 0x8298,
+     0x6a7a, 0x2298, 0x15c0, 0x7a86, 0x7fc5, 0x654a, 0x14ad, 0xd0aa
+        };
+#else
+        {
+/* dss_p length = 512*/
+          0xbd9692b7L, 0x584c9aabL, 0xf2f0d617L, 0xd370da85L,
+     0x273ecc82L, 0xc1716b04L, 0xd3ff5c32L, 0xf2f8352eL,
+     0x20bc4fc2L, 0xe96ebdecL, 0x4d893503L, 0xeb7de92dL,
+     0x78529c1aL, 0x0a25fe2aL, 0xce184446L, 0x95d87829L,
+#ifdef LENGTH_MULT_TO_32
+     /* dss_p length = 544*/
+         0x0d3112dbL, 0x16c99950L, 0x0acb3045L, 0x3c5c3c46L,
+     0x24586c94L, 0x13da0736L, 0x790fa0afL, 0xa6aeb177L,
+     0x2bdad111L, 0x49a2697cL, 0x6f27e3e5L, 0x9bc902f5L,
+     0x7d9bd4daL, 0x63bc89c6L, 0xfe2d0b6dL, 0x435fc7a1L,
+     0x9e407fadL,
+#endif
+      /* dss_p length = 576*/
+         0x41b5626bL, 0x25bfd218L, 0x42b31825L, 0xc2449eb0L,
+     0x22ac96ceL, 0x713f3ac6L, 0x398c321dL, 0xbc493022L,
+     0x52d5dd03L, 0x2a5729f8L, 0x21738fa1L, 0xb90dee7dL,
+     0x5faecc64L, 0xe3d0aa81L, 0xfa6e648fL, 0x039fdc6cL,
+     0xc5522cd6L, 0xebece2dcL,
+#ifdef LENGTH_MULT_TO_32
+       /* dss_p length = 608*/
+         0xb2af35f5L, 0x398b27d0L, 0x6f2e493dL, 0xe5b5be27L,
+     0x3470972cL, 0xe90e9638L, 0x98adf7b7L, 0xb4cad091L,
+     0x5f583f43L, 0xd014b6c5L, 0x414d25eeL, 0x6fd6e2c1L,
+     0x9be6d737L, 0xe24166caL, 0xf7401897L, 0xceb0e5dfL,
+     0xabc8db38L, 0xc58b8af8L, 0x9a04c6a0L,
+#endif
+    /* dss_p length = 640*/
+         0xf6bf4095L, 0x40327568L, 0x64f25c0fL, 0xb0995aaeL,
+     0x0e81346fL, 0x7aeb357aL, 0xfd0a0291L, 0xce808d54L,
+     0xbea30c05L, 0x8a1b889fL, 0x6049f1c1L, 0x8ec3214aL,
+     0xdde1b926L, 0x384e61b4L, 0xb6d7404bL, 0x45842e2dL,
+     0xcc7aae6aL, 0x9eb07bfaL, 0x39043a26L, 0xc0368cacL,
+#ifdef LENGTH_MULT_TO_32
+     /* dss_p length = 672*/
+         0xaea30abbL, 0x757cc749L, 0x29d03035L, 0xd56c46bdL,
+     0xa355f49dL, 0x8dcb1297L, 0xc58c9802L, 0x8aacf1ecL,
+     0xb10755ddL, 0x26d10140L, 0x8a908a5dL, 0xde0bf33eL,
+     0xb429b844L, 0x98064db2L, 0x4c3bf629L, 0x2f23cd76L,
+     0x7bf46c68L, 0xd9822a7eL, 0x16a2c89fL, 0x953cfe84L,
+     0x8de83e4aL,
+#endif
+      /* dss_p length = 704*/
+         0x15350113L, 0x8fafca0bL, 0x989ca327L, 0xe51212c8L,
+     0x1229796fL, 0x62c812bfL, 0x2b99a50aL, 0x450cc93bL,
+     0x082671adL, 0x3913f4c6L, 0x96da9b6eL, 0xbc5ea08dL,
+     0x7b26d4d3L, 0xdd76f9fdL, 0x2f064e82L, 0xbf471f96L,
+     0x3610cadfL, 0x4e94917bL, 0x0eafe2e8L, 0x6b901cb9L,
+     0x6d6fb917L, 0xb32992b9L,
+#ifdef LENGTH_MULT_TO_32
+       /* dss_p length = 736*/
+         0xd8786dadL, 0xe61ec913L, 0xe27587d9L, 0xf090ad24L,
+     0xfdfee12bL, 0xc9a139a3L, 0x138a8330L, 0xc3194bedL,
+     0x88ba8094L, 0x13254b80L, 0x67e27852L, 0x7313715eL,
+     0x77273b4eL, 0x5c6e9870L, 0xc67ae0ceL, 0xf3c5d057L,
+     0x98ba55eaL, 0xaee76ea0L, 0x3cd631e8L, 0x42d10e28L,
+     0xc3958946L, 0x1b9d34fcL, 0x86f919d1L,
+#endif
+    /* dss_p length = 768*/
+         0xea08e293L, 0xf668cdd0L, 0x06db8b2aL, 0xadb27c71L,
+     0x6721943dL, 0xbc4454f5L, 0x3345f7caL, 0x0b901bf6L,
+     0xd3c4b475L, 0x7caabdb6L, 0xe9b4a45fL, 0x0c1a6e0eL,
+     0x9760b5c3L, 0x53af851aL, 0x497996b7L, 0xe951f162L,
+     0xd0206a54L, 0xdecb9dedL, 0x7d74fc81L, 0x2aee5e92L,
+     0x0eb50946L, 0x9bce3700L, 0xa7a3845aL, 0x8618157aL,
+#ifdef LENGTH_MULT_TO_32
+     /* dss_p length = 800*/
+         0xac27b0a1L, 0xf623ec4eL, 0x2cb655e2L, 0x4b28288bL,
+     0xbbe6d74eL, 0xaecdfdf7L, 0xe2515758L, 0x1aee9074L,
+     0x4d5ee6edL, 0x529e01d9L, 0x0091f736L, 0xc7250212L,
+     0x966f60ceL, 0x5c4b851dL, 0x34df80deL, 0x06361c88L,
+     0x32cebb71L, 0x86da45cbL, 0x13e04d0eL, 0x544b7d7dL,
+     0x747f1272L, 0xfa3bd6a7L, 0x6b43cb86L, 0xd01266f5L,
+     0xa0cbfe7aL,
+#endif
+      /* dss_p length = 832*/
+         0x84dded2dL, 0xdd8ff274L, 0x7928cd5fL, 0xa522bfc6L,
+     0x50f0e4e4L, 0x5842cddfL, 0x7c4dbb29L, 0x6946eef4L,
+     0xe48687f6L, 0xc1b661b5L, 0x575aadefL, 0x724f360fL,
+     0x591bcb29L, 0xf7bc9a4cL, 0xa348309eL, 0x94f30ff5L,
+     0x9dc6932fL, 0xc6d7992cL, 0xc2d712f6L, 0x8c0138aaL,
+     0x74f45dcaL, 0x4cf4fcfdL, 0x7837588aL, 0xd2e2097eL,
+     0x88696eacL, 0xec62e92fL,
+#ifdef LENGTH_MULT_TO_32
+     /* dss_p length = 864*/
+     0x931e7c21L, 0x00f2553dL, 0x940fa860L, 0x7d20411eL,
+     0x52a3b168L, 0x166e69eeL, 0x1b23b9e6L, 0xef64d5e0L,
+     0x724c2850L, 0xea73c1feL, 0xe342da8cL, 0xd2561d7bL,
+     0x180f359bL, 0xca77d7f5L, 0x216206acL, 0x78bba977L,
+     0x5de25018L, 0xe2176061L, 0xfed14d42L, 0xd50f3929L,
+     0x2433c946L, 0x361b15f8L, 0x3ff0bf51L, 0x31573efaL,
+     0x53a07350L, 0x261bd1a4L, 0x9236de5bL,
+#endif
+     /* dss_p length = 896*/
+     0x03648e21L, 0xe58c86d2L, 0x780a2274L, 0x49519ffcL,
+     0xbc963f99L, 0x5a7e9e60L, 0x23d4010aL, 0x48e954d1L,
+     0x979cfd6bL, 0x8af35202L, 0xfe8f5d87L, 0x1e0c3e3cL,
+     0xcc52e294L, 0x480ea8d6L, 0xd4cea898L, 0xd3415949L,
+     0xf41be325L, 0x6a9072d6L, 0x6f147a8bL, 0x66363e2bL,
+     0x4eea3748L, 0x03e4a590L, 0x9c320524L, 0x02afeb53L,
+     0x6792ca71L, 0xedf8d673L, 0x59c36448L, 0x883f7319L,
+#ifdef LENGTH_MULT_TO_32
+     /* dss_p length = 928*/
+     0xa4e8c17dL, 0x8ff8ea08L, 0x73f52cb0L, 0xc027d7baL,
+     0x989db9c8L, 0xe3a1e5feL, 0x39d3f324L, 0x5ba8f142L,
+     0x3708e6cbL, 0xed9aa0b7L, 0xe314b6b3L, 0x6778f80aL,
+     0x71074d27L, 0xb9c26ee8L, 0xab70c6afL, 0xc44553beL,
+     0x34bb7926L, 0xe11d5191L, 0xcc3a67f1L, 0xd34d5354L,
+     0x08baa1acL, 0x068a32d4L, 0x415f7c3bL, 0xb549bce0L,
+     0x538f0ecfL, 0x22a3b5d0L, 0xe8371d47L, 0x69dd14c0L,
+     0xce91a02dL,
+#endif
+     /* dss_p length = 960*/
+     0xf77e1ff3L, 0x5a28ae7aL, 0xe18743b1L, 0xb3ea2e04L,
+     0xa3e87394L, 0xc9bc4985L, 0x1e1c7b7dL, 0x55f8d99cL,
+     0x5704447bL, 0xbed1d758L, 0x2a5ee698L, 0xc2065c19L,
+     0x1f886d38L, 0x5f152ea4L, 0xd716ebfdL, 0xf9608a2aL,
+     0xc49383acL, 0x8f13b966L, 0x96824778L, 0x84cd4712L,
+     0xe567bb4eL, 0x0780644fL, 0x0b0a133dL, 0x06e8e42eL,
+     0x3131a4ccL, 0xfaf839d9L, 0x555012a3L, 0xb8a943b1L,
+     0x0fadb0ebL, 0xd427986fL,
+#ifdef LENGTH_MULT_TO_32
+     /* dss_p length = 992*/
+     0x363fbcfdL, 0x18f0050aL, 0xcac978d8L, 0xf31e423aL,
+     0xd0c3198fL, 0x5d1bb319L, 0xc0b0917aL, 0x6b918d1bL,
+     0xa9d1ea69L, 0x534502ceL, 0x69922c80L, 0x7a284dadL,
+     0xd46dbb75L, 0x56120faaL, 0x8a0e6878L, 0x46ab63b4L,
+     0x5381aca0L, 0x3e70b90aL, 0xb63919c4L, 0xe751f778L,
+     0xb7265974L, 0x8679589fL, 0xc0b5eb04L, 0x2b32dffdL,
+     0xc6324b51L, 0x9501d8c6L, 0x20264f94L, 0x0d27253aL,
+     0x083807bbL, 0xa3eb2725L, 0x89b63c4eL,
+#endif
+     /* dss_p length = 1024*/
+     0xecf7a141L, 0x867dc6d6L, 0x1cddefa3L, 0x6ca56c9dL,
+     0x68af2e2fL, 0x1d3e90e1L, 0x0c2ad75fL, 0x36c7844bL,
+     0xfd1a3420L, 0xf6e5b9eeL, 0xc8ed5fdeL, 0xd3530c90L,
+     0x80a46faaL, 0xa59d5bbdL, 0x32239e72L, 0xf33d8f59L,
+     0xeccd10ebL, 0x3e2a184eL, 0x564b4c07L, 0x32634c0aL,
+     0x8aebc535L, 0x2be2f982L, 0x9b87e475L, 0x4d08cca0L,
+     0x04843adfL, 0x7acdd528L, 0x55a0304dL, 0x829870aeL,
+       0x22986a7aL, 0x7a8615c0L, 0x654a7fc5L, 0xd0aa14adL
+              };
+#endif
+
+ord DSS_G_NUMBERS[DSS_LAST_INDEX] =
+#ifdef ORD_16
+                {
+      /* dss_g length = 512*/
+          0x8b1a, 0xedfe, 0xef16, 0xdb26, 0xeae0, 0x1f1d, 0xaf3a, 0x3e30,
+         0x2bd6, 0x25ec, 0xa451, 0x6255, 0xbc75, 0x499c, 0x4071, 0x5da2,
+         0x1149, 0xc7fc, 0x1402, 0x9b69, 0xc168, 0xb0ea, 0xaf92, 0x6a33,
+         0xf45f, 0xd93a, 0x75a6, 0x263c, 0xb820, 0x7eb1, 0x5f5b, 0x4bd7,
+#ifdef LENGTH_MULT_TO_32
+         /* dss_g length = 544*/
+         0x2772, 0xe0e6, 0xce97, 0x605b, 0x4aa8, 0x2586, 0x095a, 0xb83f,
+         0x8b01, 0xfe53, 0x9250, 0x74ef, 0x74d4, 0xd9fa, 0xb78b, 0xa714,
+         0x106f, 0x03a6, 0xb406, 0xc549, 0xc44d, 0xd559, 0x8100, 0xfef4,
+         0x34a4, 0x1f4c, 0x3c6b, 0x4ae0, 0xe770, 0x158b, 0x3f8d, 0xf73d,
+         0x0cc5, 0x61b7,
+#endif
+     /* dss_g length = 576*/
+     0x3dde, 0x64fd, 0x2b69, 0x03c3, 0xad1d, 0x1751, 0x11dc, 0xfe67,
+     0x6379, 0x76de, 0xe333, 0x3b8f, 0x242f, 0x27d8, 0x5f33, 0x3597,
+     0xb98c, 0x11dc, 0x718c, 0xe3b5, 0xa3d4, 0x58f2, 0x71fa, 0x2675,
+     0x49f9, 0xf2c7, 0x510e, 0xa4e1, 0xeca4, 0x7c64, 0x243b, 0x78fc,
+     0x2ce2, 0x7017, 0x0095, 0x23b6,
+#ifdef LENGTH_MULT_TO_32
+     /* dss_g length = 608*/
+     0xdad8, 0x1e27, 0x41f5, 0xd536, 0x528f, 0x7047, 0x028a, 0x56f5,
+     0xe55f, 0xe20d, 0x612c, 0x520f, 0xebfd, 0x8c86, 0x0924, 0x562a,
+     0x2185, 0xe5ac, 0xa113, 0x4b8c, 0x87da, 0xfa4c, 0x8788, 0x9d8d,
+     0x41c0, 0x9d25, 0x9c77, 0xff33, 0x6861, 0xd10a, 0xc734, 0x8454,
+     0xf803, 0x55ce, 0xfeac, 0x6580, 0x6cd2, 0x482b,
+#endif
+     /* dss_g length = 640*/
+         0x4ff7, 0x2829, 0x8ab0, 0xa0bd, 0x7b1c, 0xf544, 0xe633, 0x6e7b,
+     0x9824, 0x494a, 0xfb7f, 0xc8ad, 0x45b6, 0x956e, 0x0574, 0x5b0d,
+     0xd40c, 0xf807, 0x7372, 0x56fd, 0xdd12, 0x8960, 0x255c, 0x019e,
+     0xfc39, 0x06b3, 0x9f8e, 0x4cd9, 0xe714, 0x77f6, 0x76f7, 0xb573,
+     0x010e, 0x9b52, 0x04d2, 0xe269, 0xd4bb, 0xbdec, 0x089d, 0x7f88,
+#ifdef LENGTH_MULT_TO_32
+     /* dss_g length = 672*/
+     0x3d36, 0xb22d, 0x2144, 0xfda0, 0x1d4a, 0xc144, 0xef8f, 0x70e8,
+     0xfd0f, 0xcbf9, 0x7433, 0xbf29, 0x1657, 0x757b, 0x011d, 0x5c7e,
+     0xa0d3, 0xec5a, 0xd45d, 0xacd6, 0x136a, 0x9454, 0x61fd, 0xc3f6,
+     0x3758, 0x5c89, 0xe4df, 0xd3c9, 0x6f99, 0xa113, 0x0992, 0x16b2,
+     0xf92f, 0xfb67, 0x3f34, 0x57e6, 0xb224, 0xdfd1, 0x43c4, 0x639a,
+     0xccf5, 0x86c4,
+#endif
+     /* dss_g length = 704*/
+     0x1621, 0x8313, 0x216e, 0xcb3b, 0xde00, 0xa11b, 0xf27f, 0xd5d4,
+     0x6d2e, 0xc870, 0x1c47, 0x2e21, 0x780b, 0x1db6, 0x8adf, 0xe5c6,
+     0x837d, 0x7dba, 0x9c8c, 0x28b5, 0xd309, 0xf3fa, 0x6c65, 0xe37f,
+     0x6a1e, 0x2601, 0xbb92, 0x56aa, 0x9c0e, 0x9db1, 0xb782, 0x642b,
+     0x6cc9, 0xb9fb, 0x6a3c, 0x97b9, 0xf1a8, 0xd8a2, 0xfe6b, 0xcb93,
+       0x59ee, 0x32a4, 0x0aa1, 0x58ad,
+#ifdef LENGTH_MULT_TO_32
+     /* dss_g length = 736*/
+     0x648c, 0xa15c, 0x27b2, 0x8137, 0xefb3, 0x0e81, 0x258e, 0xabe0,
+     0x9f2f, 0x6c67, 0xbed6, 0xd201, 0x3647, 0xbe9a, 0x0091, 0xba9a,
+     0x4df1, 0xdc8c, 0x5b15, 0x5a37, 0xb5b1, 0x50f8, 0xdfe6, 0x081b,
+     0x48d7, 0xd40b, 0x7c51, 0x0417, 0x97c7, 0x2565, 0xf960, 0x89b2,
+     0xa1f0, 0x7aac, 0xed6f, 0x20fe, 0x1d98, 0x0eee, 0x48b8, 0xb062,
+     0x70e7, 0xa3f3, 0xbe3f, 0x9183, 0x76ae, 0x6cbc,
+#endif
+     /* dss_g length = 768*/
+     0x6216, 0x4b90, 0xc254, 0x7ab6, 0x7a04, 0xf90f, 0x42dd, 0x58c7,
+     0xd015, 0x904d, 0xfbf7, 0x624a, 0x5010, 0x627f, 0x696c, 0x1a32,
+     0xe0bc, 0xcdfd, 0xe32f, 0xb081, 0x1377, 0x1913, 0x5f96, 0x86c6,
+     0x864a, 0x8429, 0x4bb9, 0xd0c6, 0x3361, 0xbc7d, 0xbd8d, 0xa3b2,
+     0x47d5, 0x5086, 0xed0b, 0x3bb6, 0xdba6, 0x6f2c, 0x707a, 0x434b,
+     0xd4cc, 0x7b10, 0x8ef0, 0x3466, 0x4737, 0x8f27, 0x3399, 0x3716,
+#ifdef LENGTH_MULT_TO_32
+     /* dss_g length = 800*/
+     0x99a7, 0xa90c, 0xdf8e, 0xba50, 0x83b5, 0x7ea0, 0x1d8a, 0xe5bb,
+   0x34c9, 0x8c4d, 0xb151, 0x3aba, 0xee2f, 0x76c8, 0xeebf, 0x3db9,
+     0xc1e0, 0x2b9a, 0x774f, 0xb476, 0x9b93, 0x53b5, 0xc008, 0xed2c,
+     0x0ad4, 0x8af4, 0xc0e6, 0x0e98, 0x2d7b, 0xdb37, 0x7b59, 0x8a31,
+     0x0667, 0x1225, 0xb882, 0x0355, 0x58ba, 0xf079, 0x80d7, 0x8033,
+     0x54bc, 0xf9cd, 0x461e, 0xc70a, 0x9170, 0x1dba, 0xc447, 0xd3e5,
+     0xaf18, 0x04c4,
+#endif
+     /* dss_g length = 832*/
+     0xd1b5, 0x3d20, 0xfbdb, 0xa0b6, 0x0505, 0x4e88, 0xa781, 0x7c65,
+     0xd381, 0x5b6e, 0xfd1e, 0xbb71, 0xe085, 0x855d, 0x6d0b, 0x650a,
+     0xa248, 0x82d0, 0xd4dd, 0x7ea0, 0x16d1, 0x6937, 0x2cc2, 0x2dec,
+     0x5e07, 0x97b4, 0x0c5a, 0xcf21, 0x0299, 0x9b96, 0x4acf, 0xc732,
+     0xfbcf, 0xeefb, 0x0032, 0x40bb, 0xc86e, 0xeacb, 0xae2b, 0x8adb,
+     0x39aa, 0xbb47, 0xaf3a, 0xfd36, 0xf859, 0x97fc, 0x5535, 0x0d3d,
+     0x627a, 0x3f62, 0x1f90, 0x5490,
+#ifdef LENGTH_MULT_TO_32
+     /* dss_g length = 864*/
+     0xbf83, 0x8b52, 0xc2b1, 0x0808, 0x4a3e, 0x6ccb, 0x8aa8, 0xcfdd,
+     0xb046, 0x4948, 0xcdf4, 0x9881, 0x13d8, 0x85b0, 0xa22a, 0x3786,
+     0xe9db, 0xcb8a, 0x89ad, 0x5e27, 0xd925, 0x1fcb, 0x3855, 0x4afd,
+       0x7f67, 0x83be, 0xb092, 0xe061, 0x6703, 0xf21f, 0x403e, 0x4c6a,
+     0xa8bd, 0x536a, 0x89b6, 0xb25e, 0xe165, 0xd259, 0xb765, 0xd7f3,
+     0xc474, 0xd8bc, 0x617d, 0x1a0a, 0xa054, 0x8c28, 0x9fb0, 0x9595,
+     0x6f2d, 0x6254, 0xe1c2, 0xb450, 0xef81, 0x277f,
+#endif
+     /* dss_g length = 896*/
+     0x7490, 0x2aea, 0xd005, 0xa3cc, 0x9211, 0x235a, 0x7b6d, 0xacec,
+     0xfca5, 0x5407, 0x8515, 0x5bc1, 0x8b2a, 0x9388, 0x8ff9, 0xed56,
+     0xf4e9, 0xf31e, 0x7e05, 0x172a, 0x6e2a, 0x8165, 0x7a24, 0x975b,
+     0x1f6e, 0xd4d1, 0x8232, 0xd6ff, 0x2363, 0x4072, 0xa1f1, 0xd18b,
+     0xe574, 0xb032, 0xc330, 0x81b6, 0x6033, 0x07d5, 0x5107, 0xb7cc,
+     0x2c10, 0xbd8e, 0xc6a3, 0xe731, 0xfcd6, 0xe567, 0x3440, 0xbcde,
+     0x1976, 0xdbb3, 0xd15a, 0x4e39, 0xc282, 0x4b0b, 0x82b3, 0x286b,
+#ifdef LENGTH_MULT_TO_32
+     /* dss_g length = 928*/
+     0x9f66, 0xd0e5, 0xd7d2, 0xe875, 0x0707, 0x2dca, 0xa5a2, 0x266d,
+     0x80c2, 0x6d20, 0x69b3, 0x759c, 0x497f, 0x74b4, 0x0f56, 0x4b63,
+     0xa294, 0x4995, 0x3eda, 0xf5c4, 0x7951, 0x3a3d, 0x22e9, 0x617f,
+     0x1906, 0xd45d, 0x047f, 0x2726, 0x27be, 0x660e, 0xc1d3, 0xa588,
+     0xceb2, 0xe300, 0xca06, 0x8620, 0x1110, 0x76ae, 0xf7b8, 0xe368,
+       0x89a7, 0x2ded, 0x2756, 0x3ed6, 0x5449, 0x4bd8, 0xb73d, 0xb406,
+     0x25ec, 0x32f7, 0x989c, 0x6623, 0x6b1f, 0xf7f0, 0x4807, 0x0954,
+     0x51e6, 0x97d0,
+#endif
+     /* dss_g length = 960*/
+     0x4118, 0xe87c, 0x809a, 0x1287, 0x2a0f, 0x51d6, 0x7fc8, 0xdad8,
+     0x8dc6, 0xddce, 0xd27c, 0x898a, 0x96a9, 0xaee1, 0xe44c, 0xd322,
+     0x9d58, 0x3a34, 0xcebd, 0x322a, 0x5b48, 0x9c21, 0x6d04, 0x2d77,
+     0x41f1, 0x5123, 0xaa5f, 0x2192, 0x8175, 0x5cac, 0xf547, 0xdc08,
+     0xb0d9, 0x4f11, 0x85c9, 0xb5bf, 0x7147, 0x9fbf, 0x3c20, 0x7f7a,
+     0xdd8a, 0xa163, 0x0ae4, 0xfcb2, 0x8251, 0x8162, 0xb96e, 0x84f9,
+     0xd652, 0x94ba, 0xbb90, 0x9559, 0xac51, 0x6418, 0xdb54, 0x4739,
+     0x3ec0, 0x9b7c, 0xae96, 0x3e14,
+#ifdef LENGTH_MULT_TO_32
+     /* dss_g length = 992*/
+     0x4eff, 0x399a, 0x5da9, 0x1e5a, 0x9040, 0x4bad, 0xc85d, 0x5b9a,
+     0x825b, 0x5464, 0x7538, 0xe2ea, 0xb957, 0x5def, 0xbfa6, 0x4916,
+     0x89be, 0x93fe, 0xe5da, 0x919f, 0x791c, 0xe7a8, 0xef86, 0xc186,
+     0xbf63, 0xa881, 0x1e38, 0x9abe, 0x8b58, 0x70b4, 0x9dfd, 0x0719,
+     0x85e5, 0xc60a, 0xab36, 0xe07d, 0x0c49, 0xd6fe, 0xfdb4, 0x6619,
+       0xe55d, 0x997e, 0x5f38, 0x824f, 0x47ff, 0xf800, 0xb137, 0x839d,
+     0x2dae, 0xe0db, 0x2a74, 0x2f58, 0x6fb3, 0x1bab, 0x62ed, 0x0e02,
+     0xbef2, 0xd7f1, 0xe566, 0xa9ae, 0xbc35, 0x6357,
+#endif
+     /* dss_g length = 1024*/
+     0x914d, 0x76b2, 0xfee4, 0x9cf7, 0xa136, 0x07a1, 0x3808, 0x1857,
+     0x8f96, 0x870c, 0x1f3c, 0x59f2, 0x6f01, 0x4d4d, 0x580e, 0xafc6,
+     0x99af, 0xff1b, 0xc019, 0x6c1f, 0xe449, 0x1698, 0x4787, 0x0aa2,
+     0x6e68, 0x768d, 0x5ff0, 0x27dc, 0xca9e, 0x630f, 0x01ae, 0x9981,
+     0x688d, 0xf278, 0x7f3d, 0x17ad, 0x48aa, 0x65d6, 0x181f, 0x1802,
+     0x647c, 0x9ef5, 0x7081, 0x5843, 0x1f0d, 0x9364, 0xebe9, 0x6330,
+     0x033a, 0x5d2a, 0xb68a, 0x5639, 0xfa7c, 0xd77e, 0x4bdc, 0x4a62,
+     0x5c6d, 0xfed5, 0xa8aa, 0x5eff, 0x1138, 0xae4a, 0xe993, 0x3a73
+        };
+#else
+        {
+     /* dss_g length = 512*/
+     0xedfe8b1aL, 0xdb26ef16L, 0x1f1deae0L, 0x3e30af3aL,
+   0x25ec2bd6L, 0x6255a451L, 0x499cbc75L, 0x5da24071L,
+     0xc7fc1149L, 0x9b691402L, 0xb0eac168L, 0x6a33af92L,
+     0xd93af45fL, 0x263c75a6L, 0x7eb1b820L, 0x4bd75f5bL,
+#ifdef LENGTH_MULT_TO_32
+     /* dss_g length = 544*/
+     0xe0e62772L, 0x605bce97L, 0x25864aa8L, 0xb83f095aL,
+     0xfe538b01L, 0x74ef9250L, 0xd9fa74d4L, 0xa714b78bL,
+     0x03a6106fL, 0xc549b406L, 0xd559c44dL, 0xfef48100L,
+     0x1f4c34a4L, 0x4ae03c6bL, 0x158be770L, 0xf73d3f8dL,
+     0x61b70cc5L,
+#endif
+     /* dss_g length = 576*/
+     0x64fd3ddeL, 0x03c32b69L, 0x1751ad1dL, 0xfe6711dcL,
+     0x76de6379L, 0x3b8fe333L, 0x27d8242fL, 0x35975f33L,
+     0x11dcb98cL, 0xe3b5718cL, 0x58f2a3d4L, 0x267571faL,
+     0xf2c749f9L, 0xa4e1510eL, 0x7c64eca4L, 0x78fc243bL,
+     0x70172ce2L, 0x23b60095L,
+#ifdef LENGTH_MULT_TO_32
+     /* dss_g length = 608*/
+     0x1e27dad8L, 0xd53641f5L, 0x7047528fL, 0x56f5028aL,
+     0xe20de55fL, 0x520f612cL, 0x8c86ebfdL, 0x562a0924L,
+     0xe5ac2185L, 0x4b8ca113L, 0xfa4c87daL, 0x9d8d8788L,
+     0x9d2541c0L, 0xff339c77L, 0xd10a6861L, 0x8454c734L,
+     0x55cef803L, 0x6580feacL, 0x482b6cd2L,
+#endif
+     /* dss_g length = 640*/
+     0x28294ff7L, 0xa0bd8ab0L, 0xf5447b1cL, 0x6e7be633L,
+     0x494a9824L, 0xc8adfb7fL, 0x956e45b6L, 0x5b0d0574L,
+     0xf807d40cL, 0x56fd7372L, 0x8960dd12L, 0x019e255cL,
+     0x06b3fc39L, 0x4cd99f8eL, 0x77f6e714L, 0xb57376f7L,
+     0x9b52010eL, 0xe26904d2L, 0xbdecd4bbL, 0x7f88089dL,
+#ifdef LENGTH_MULT_TO_32
+     /* dss_g length = 672*/
+     0xb22d3d36L, 0xfda02144L, 0xc1441d4aL, 0x70e8ef8fL,
+     0xcbf9fd0fL, 0xbf297433L, 0x757b1657L, 0x5c7e011dL,
+     0xec5aa0d3L, 0xacd6d45dL, 0x9454136aL, 0xc3f661fdL,
+     0x5c893758L, 0xd3c9e4dfL, 0xa1136f99L, 0x16b20992L,
+     0xfb67f92fL, 0x57e63f34L, 0xdfd1b224L, 0x639a43c4L,
+     0x86c4ccf5L,
+#endif
+     /* dss_g length = 704*/
+     0x83131621L, 0xcb3b216eL, 0xa11bde00L, 0xd5d4f27fL,
+     0xc8706d2eL, 0x2e211c47L, 0x1db6780bL, 0xe5c68adfL,
+     0x7dba837dL, 0x28b59c8cL, 0xf3fad309L, 0xe37f6c65L,
+     0x26016a1eL, 0x56aabb92L, 0x9db19c0eL, 0x642bb782L,
+     0xb9fb6cc9L, 0x97b96a3cL, 0xd8a2f1a8L, 0xcb93fe6bL,
+     0x32a459eeL, 0x58ad0aa1L,
+#ifdef LENGTH_MULT_TO_32
+     /* dss_g length = 736*/
+     0xa15c648cL, 0x813727b2L, 0x0e81efb3L, 0xabe0258eL,
+     0x6c679f2fL, 0xd201bed6L, 0xbe9a3647L, 0xba9a0091L,
+     0xdc8c4df1L, 0x5a375b15L, 0x50f8b5b1L, 0x081bdfe6L,
+     0xd40b48d7L, 0x04177c51L, 0x256597c7L, 0x89b2f960L,
+     0x7aaca1f0L, 0x20feed6fL, 0x0eee1d98L, 0xb06248b8L,
+     0xa3f370e7L, 0x9183be3fL, 0x6cbc76aeL,
+#endif
+     /* dss_g length = 768*/
+     0x4b906216L, 0x7ab6c254L, 0xf90f7a04L, 0x58c742ddL,
+     0x904dd015L, 0x624afbf7L, 0x627f5010L, 0x1a32696cL,
+     0xcdfde0bcL, 0xb081e32fL, 0x19131377L, 0x86c65f96L,
+     0x8429864aL, 0xd0c64bb9L, 0xbc7d3361L, 0xa3b2bd8dL,
+     0x508647d5L, 0x3bb6ed0bL, 0x6f2cdba6L, 0x434b707aL,
+     0x7b10d4ccL, 0x34668ef0L, 0x8f274737L, 0x37163399L,
+#ifdef LENGTH_MULT_TO_32
+     /* dss_g length = 800*/
+     0xa90c99a7L, 0xba50df8eL, 0x7ea083b5L, 0xe5bb1d8aL,
+     0x8c4d34c9L, 0x3abab151L, 0x76c8ee2fL, 0x3db9eebfL,
+     0x2b9ac1e0L, 0xb476774fL, 0x53b59b93L, 0xed2cc008L,
+     0x8af40ad4L, 0x0e98c0e6L, 0xdb372d7bL, 0x8a317b59L,
+     0x12250667L, 0x0355b882L, 0xf07958baL, 0x803380d7L,
+     0xf9cd54bcL, 0xc70a461eL, 0x1dba9170L, 0xd3e5c447L,
+     0x04c4af18L,
+#endif
+     /* dss_g length = 832*/
+     0x3d20d1b5L, 0xa0b6fbdbL, 0x4e880505L, 0x7c65a781L,
+     0x5b6ed381L, 0xbb71fd1eL, 0x855de085L, 0x650a6d0bL,
+     0x82d0a248L, 0x7ea0d4ddL, 0x693716d1L, 0x2dec2cc2L,
+          0x97b45e07L, 0xcf210c5aL, 0x9b960299L, 0xc7324acfL,
+     0xeefbfbcfL, 0x40bb0032L, 0xeacbc86eL, 0x8adbae2bL,
+     0xbb4739aaL, 0xfd36af3aL, 0x97fcf859L, 0x0d3d5535L,
+     0x3f62627aL, 0x54901f90L,
+#ifdef LENGTH_MULT_TO_32
+     /* dss_g length = 864*/
+     0x8b52bf83L, 0x0808c2b1L, 0x6ccb4a3eL, 0xcfdd8aa8L,
+     0x4948b046L, 0x9881cdf4L, 0x85b013d8L, 0x3786a22aL,
+     0xcb8ae9dbL, 0x5e2789adL, 0x1fcbd925L, 0x4afd3855L,
+     0x83be7f67L, 0xe061b092L, 0xf21f6703L, 0x4c6a403eL,
+     0x536aa8bdL, 0xb25e89b6L, 0xd259e165L, 0xd7f3b765L,
+     0xd8bcc474L, 0x1a0a617dL, 0x8c28a054L, 0x95959fb0L,
+     0x62546f2dL, 0xb450e1c2L, 0x277fef81L,
+#endif
+     /* dss_g length = 896*/
+     0x2aea7490L, 0xa3ccd005L, 0x235a9211L, 0xacec7b6dL,
+     0x5407fca5L, 0x5bc18515L, 0x93888b2aL, 0xed568ff9L,
+     0xf31ef4e9L, 0x172a7e05L, 0x81656e2aL, 0x975b7a24L,
+     0xd4d11f6eL, 0xd6ff8232L, 0x40722363L, 0xd18ba1f1L,
+     0xb032e574L, 0x81b6c330L, 0x07d56033L, 0xb7cc5107L,
+     0xbd8e2c10L, 0xe731c6a3L, 0xe567fcd6L, 0xbcde3440L,
+     0xdbb31976L, 0x4e39d15aL, 0x4b0bc282L, 0x286b82b3L,
+#ifdef LENGTH_MULT_TO_32
+     /* dss_g length = 928*/
+     0xd0e59f66L, 0xe875d7d2L, 0x2dca0707L, 0x266da5a2L,
+     0x6d2080c2L, 0x759c69b3L, 0x74b4497fL, 0x4b630f56L,
+     0x4995a294L, 0xf5c43edaL, 0x3a3d7951L, 0x617f22e9L,
+     0xd45d1906L, 0x2726047fL, 0x660e27beL, 0xa588c1d3L,
+     0xe300ceb2L, 0x8620ca06L, 0x76ae1110L, 0xe368f7b8L,
+          0x2ded89a7L, 0x3ed62756L, 0x4bd85449L, 0xb406b73dL,
+     0x32f725ecL, 0x6623989cL, 0xf7f06b1fL, 0x09544807L,
+     0x97d051e6L,
+#endif
+     /* dss_g length = 960*/
+     0xe87c4118L, 0x1287809aL, 0x51d62a0fL, 0xdad87fc8L,
+     0xddce8dc6L, 0x898ad27cL, 0xaee196a9L, 0xd322e44cL,
+     0x3a349d58L, 0x322acebdL, 0x9c215b48L, 0x2d776d04L,
+     0x512341f1L, 0x2192aa5fL, 0x5cac8175L, 0xdc08f547L,
+     0x4f11b0d9L, 0xb5bf85c9L, 0x9fbf7147L, 0x7f7a3c20L,
+     0xa163dd8aL, 0xfcb20ae4L, 0x81628251L, 0x84f9b96eL,
+     0x94bad652L, 0x9559bb90L, 0x6418ac51L, 0x4739db54L,
+     0x9b7c3ec0L, 0x3e14ae96L,
+#ifdef LENGTH_MULT_TO_32
+     /* dss_g length = 992*/
+     0x399a4effL, 0x1e5a5da9L, 0x4bad9040L, 0x5b9ac85dL,
+     0x5464825bL, 0xe2ea7538L, 0x5defb957L, 0x4916bfa6L,
+     0x93fe89beL, 0x919fe5daL, 0xe7a8791cL, 0xc186ef86L,
+        0xa881bf63L, 0x9abe1e38L, 0x70b48b58L, 0x07199dfdL,
+     0xc60a85e5L, 0xe07dab36L, 0xd6fe0c49L, 0x6619fdb4L,
+     0x997ee55dL, 0x824f5f38L, 0xf80047ffL, 0x839db137L,
+     0xe0db2daeL, 0x2f582a74L, 0x1bab6fb3L, 0x0e0262edL,
+     0xd7f1bef2L, 0xa9aee566L, 0x6357bc35L,
+#endif
+     /* dss_g length = 1024*/
+     0x76b2914dL, 0x9cf7fee4L, 0x07a1a136L, 0x18573808L,
+     0x870c8f96L, 0x59f21f3cL, 0x4d4d6f01L, 0xafc6580eL,
+     0xff1b99afL, 0x6c1fc019L, 0x1698e449L, 0x0aa24787L,
+     0x768d6e68L, 0x27dc5ff0L, 0x630fca9eL, 0x998101aeL,
+     0xf278688dL, 0x17ad7f3dL, 0x65d648aaL, 0x1802181fL,
+     0x9ef5647cL, 0x58437081L, 0x93641f0dL, 0x6330ebe9L,
+     0x5d2a033aL, 0x5639b68aL, 0xd77efa7cL, 0x4a624bdcL,
+       0xfed55c6dL, 0x5effa8aaL, 0xae4a1138L, 0x3a73e993L
+        };
+#endif
+
+#endif  /*INITIALIZ_PQG*/
+
+#endif /*DSSNUMBER_H*/
diff --git a/lib/bind/cylink/funcs.h b/lib/bind/cylink/funcs.h
new file mode 100644 (file)
index 0000000..69ae69f
--- /dev/null
@@ -0,0 +1,7 @@
+void RShiftL_big(ord  *X, u_int32_t len_X, u_int32_t n_bit);
+void LShiftL_big(ord *X, u_int32_t len_X, u_int32_t n_bit);
+int RShiftMostBit(ord *a, u_int32_t len);
+void ByteLong(uchar *X, u_int32_t X_bytes, u_int32_t *Y);
+void ByteOrd(uchar *X, u_int32_t X_bytes, ord *Y);
+void OrdByte(ord *X, u_int32_t X_bytes, uchar *Y);
+void LongByte(u_int32_t *X, u_int32_t X_bytes, uchar  *Y);
diff --git a/lib/bind/cylink/kludge.h b/lib/bind/cylink/kludge.h
new file mode 100644 (file)
index 0000000..4b02385
--- /dev/null
@@ -0,0 +1,158 @@
+#ifndef KLUDGE_H
+#define KLUDGE_H
+
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/*
+ * Kludges for not-quite-ANSI systems.
+ * This should always be the last file included, because it may
+ * mess up some system header files.
+ */
+
+/*
+ * Some compilers complain about #if FOO if FOO isn't defined,
+ * so do the ANSI-mandated thing explicitly...
+ */
+#ifndef ASSERT_NEEDS_STDIO
+#define ASSERT_NEEDS_STDIO 0
+#endif
+#ifndef ASSERT_NEEDS_STDLIB
+#define ASSERT_NEEDS_STDLIB 0
+#endif
+#ifndef NO_STDLIB_H
+#define NO_STDLIB_H 0
+#endif
+
+/* SunOS 4.1.x <assert.h> needs "stderr" defined, and "exit" declared... */
+#ifdef assert
+#if ASSERT_NEEDS_STDIO
+#include <stdio.h>
+#endif
+#if ASSERT_NEEDS_STDLIB
+#if !NO_STDLIB_H
+#include <stdlib.h>
+#endif
+#endif
+#endif
+
+#ifndef NO_MEMMOVE
+#define NO_MEMMOVE 0
+#endif
+#if NO_MEMMOVE /* memove() not in libraries */
+#define memmove(dest,src,len) bcopy(src,dest,len)
+#endif
+
+#ifndef NO_MEMCPY
+#define NO_MEMCPY 0
+#endif
+#if NO_MEMCPY  /* memcpy() not in libraries */
+#define memcpy(dest,src,len) bcopy(src,dest,len)
+#endif
+
+#ifndef MEM_PROTOS_BROKEN
+#define MEM_PROTOS_BROKEN 0
+#endif
+#if MEM_PROTOS_BROKEN
+#define memcpy(d,s,l) memcpy((void *)(d), (void const *)(s), l)
+#define memmove(d,s,l) memmove((void *)(d), (void const *)(s), l)
+#define memcmp(d,s,l) memcmp((void const *)(d), (void const *)(s), l)
+#define memset(d,v,l) memset((void *)(d), v, l)
+#endif
+
+/*
+ * If there are no prototypes for the stdio functions, use these to
+ * reduce compiler warnings.  Uses EOF as a giveaway to indicate
+ * that <stdio.h> was #included.
+ */
+#ifndef NO_STDIO_PROTOS
+#define NO_STDIO_PROTOS 0
+#endif
+#if NO_STDIO_PROTOS    /* Missing prototypes for "simple" functions */
+#ifdef EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+int (puts)(char const *);
+int (fputs)(char const *, FILE *);
+int (fflush)(FILE *);
+int (printf)(char const *, ...);
+int (fprintf)(FILE *, char const *, ...);
+/* If we have a sufficiently old-fashioned stdio, it probably uses these... */
+int (_flsbuf)(int, FILE *);
+int (_filbuf)(FILE *);
+#ifdef __cplusplus
+}
+#endif
+#endif /* EOF */
+#endif /* NO_STDIO_PROTOS */
+
+/*
+ * Borland C seems to think that it's a bad idea to decleare a
+ * structure tag and not declare the contents.  I happen to think
+ * it's a *good* idea to use such "opaque" structures wherever
+ * possible.  So shut up.
+ */
+#ifdef __BORLANDC__
+#pragma warn -stu
+#ifndef MSDOS
+#define MSDOS 1
+#endif
+#endif
+
+/* Turn off warning about negation of unsigned values */
+#ifdef _MSC_VER
+#pragma warning(disable:4146)
+#endif
+
+/* Cope with people forgetting to define the OS, if possible... */
+
+#ifndef MSDOS
+#ifdef __MSDOS
+#define MSDOS 1
+#endif
+#endif
+#ifndef MSDOS
+#ifdef __MSDOS__
+#define MSDOS 1
+#endif
+#endif
+
+#endif /* KLUDGE_H */
diff --git a/lib/bind/cylink/lbn.h b/lib/bind/cylink/lbn.h
new file mode 100644 (file)
index 0000000..328f87f
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/*
+ * lbn.h - Low-level bignum header.
+ * Defines various word sizes and useful macros.
+ *
+ * Copyright (c) 1995  Colin Plumb.  All rights reserved.
+ * For licensing and other legal details, see the file legal.c.
+ */
+#ifndef LBN_H
+#define LBN_H
+
+#ifndef HAVE_CONFIG_H
+#define HAVE_CONFIG_H 0
+#endif
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/*
+ * Some compilers complain about #if FOO if FOO isn't defined,
+ * so do the ANSI-mandated thing explicitly...
+ */
+#ifndef NO_LIMITS_H
+#define NO_LIMITS_H 0
+#endif
+
+/* Make sure we have 8-bit bytes */
+#if !NO_LIMITS_H
+#include <limits.h>
+#if UCHAR_MAX != 0xff || CHAR_BIT != 8
+#error The bignum library requires 8-bit unsigned characters.
+#endif
+#endif /* !NO_LIMITS_H */
+
+#ifdef BNINCLUDE       /* If this is defined as, say, foo.h */
+#define STR(x) #x      /* STR(BNINCLUDE) -> "BNINCLUDE" */
+#define XSTR(x) STR(x) /* XSTR(BNINCLUDE) -> STR(foo.h) -> "foo.h" */
+#include XSTR(BNINCLUDE)       /* #include "foo.h" */
+#undef XSTR
+#undef STR
+#endif
+
+/* Figure out the endianness */
+/* Error if more than one is defined */
+#if BN_BIG_ENDIAN && BN_LITTLE_ENDIAN
+#error Only one of BN_BIG_ENDIAN or BN_LITTLE_ENDIAN may be defined
+#endif
+
+/*
+ * If no preference is stated, little-endian C code is slightly more
+ * efficient, so prefer that.  (The endianness here does NOT have to
+ * match the machine's native byte sex; the library's C code will work
+ * either way.  The flexibility is allowed for assembly routines
+ * that do care.
+ */
+#if !defined(BN_BIG_ENDIAN) && !defined(BN_LITTLE_ENDIAN)
+#define BN_LITTLE_ENDIAN 1
+#endif /* !BN_BIG_ENDIAN && !BN_LITTLE_ENDIAN */
+
+/* Macros to choose between big and little endian */
+#if BN_BIG_ENDIAN
+#define BIG(b) b
+#define LITTLE(l) /*nothing*/
+#define BIGLITTLE(b,l) b
+#elif BN_LITTLE_ENDIAN
+#define BIG(b) /*nothing*/
+#define LITTLE(l) l
+#define BIGLITTLE(b,l) l
+#else
+#error One of BN_BIG_ENDIAN or BN_LITTLE_ENDIAN must be defined as 1
+#endif
+
+
+/*
+ * Find a 16-bit unsigned type.
+ * Unsigned short is preferred over unsigned int to make the type chosen
+ * by this file more stable on platforms (such as many 68000 compilers)
+ * which support both 16- and 32-bit ints.
+ */
+#ifndef BNWORD16
+#ifndef USHRT_MAX      /* No <limits.h> available - guess */
+typedef unsigned short bnword16;
+#define BNWORD16 bnword16
+#elif USHRT_MAX == 0xffff
+typedef unsigned short bnword16;
+#define BNWORD16 bnword16
+#elif UINT_MAX == 0xffff
+typedef unsigned bnword16;
+#define BNWORD16 bnword16
+#endif
+#endif /* BNWORD16 */
+
+/*
+ * Find a 32-bit unsigned type.
+ * Unsigned long is preferred over unsigned int to make the type chosen
+ * by this file more stable on platforms (such as many 68000 compilers)
+ * which support both 16- and 32-bit ints.
+ */
+#ifndef BNWORD32
+#ifndef ULONG_MAX      /* No <limits.h> available - guess */
+typedef unsigned long bnword32;
+#define BNWORD32 bnword32
+#elif ULONG_MAX == 0xfffffffful
+typedef unsigned long bnword32;
+#define BNWORD32 bnword32
+#elif UINT_MAX == 0xffffffff
+typedef unsigned bnword32;
+#define BNWORD32 bnword32
+#elif USHRT_MAX == 0xffffffff
+typedef unsigned short bnword32;
+#define BNWORD32 bnword32
+#endif
+#endif /* BNWORD16 */
+
+/*
+ * Find a 64-bit unsigned type.
+ * The conditions here are more complicated to avoid using numbers that
+ * will choke lesser preprocessors (like 0xffffffffffffffff) unless
+ * we're reasonably certain that they'll be acceptable.
+ */
+#if !defined(BNWORD64) && ULONG_MAX > 0xfffffffful
+#if ULONG_MAX == 0xffffffffffffffff
+typedef unsigned long bnword64;
+#define BNWORD64 bnword64
+#endif
+#endif
+
+#if 0
+/*
+ * I would test the value of unsigned long long, but some *preprocessors*
+ * don't constants that long even if the compiler can accept them, so it
+ * doesn't work reliably.  So cross our fingers and hope that it's a 64-bit
+ * type.
+ *
+ * GCC uses ULONG_LONG_MAX.  Solaris uses ULLONG_MAX.  IRIX uses ULONGLONG_MAX.
+ * Are there any other names for this?
+ */
+#if !defined(BNWORD64) && \
+    (defined(ULONG_LONG_MAX) || defined (ULLONG_MAX) || defined(ULONGLONG_MAX))
+typedef unsigned long long bnword64;
+#define BNWORD64 bnword64
+#endif
+#endif
+
+/* We don't even try to find a 128-bit type at the moment */
+
+#endif /* !LBN_H */
diff --git a/lib/bind/cylink/lbn00.c b/lib/bind/cylink/lbn00.c
new file mode 100644 (file)
index 0000000..46e325a
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/*
+ * lbn00.c - auto-size-detecting lbn??.c file.
+ *
+ * Written in 1995 by Colin Plumb.
+ */
+
+#include "port_before.h"
+#include "bnsize00.h"
+
+#if BNSIZE64
+
+/* Include all of the C source file by reference */
+#include "lbn64.c"
+
+#elif BNSIZE32
+
+/* Include all of the C source file by reference */
+#include "lbn32.c"
+
+#else /* BNSIZE16 */
+
+/* Include all of the C source file by reference */
+#include "lbn16.c"
+
+#endif
diff --git a/lib/bind/cylink/lbn16.c b/lib/bind/cylink/lbn16.c
new file mode 100644 (file)
index 0000000..b73636b
--- /dev/null
@@ -0,0 +1,3644 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/*
+ * lbn16.c - Low-level bignum routines, 16-bit version.
+ *
+ * Copyright (c) 1995  Colin Plumb.  All rights reserved.
+ * For licensing and other legal details, see the file legal.c.
+ *
+ * NOTE: the magic constants "16" and "32" appear in many places in this
+ * file, including inside identifiers.  Because it is not possible to
+ * ask "#ifdef" of a macro expansion, it is not possible to use the
+ * preprocessor to conditionalize these properly.  Thus, this file is
+ * intended to be edited with textual search and replace to produce
+ * alternate word size versions.  Any reference to the number of bits
+ * in a word must be the string "16", and that string must not appear
+ * otherwise.  Any reference to twice this number must appear as "32",
+ * which likewise must not appear otherwise.  Is that clear?
+ *
+ * Remember, when doubling the bit size replace the larger number (32)
+ * first, then the smaller (16).  When halving the bit size, do the
+ * opposite.  Otherwise, things will get wierd.  Also, be sure to replace
+ * every instance that appears.  (:%s/foo/bar/g in vi)
+ *
+ * These routines work with a pointer to the least-significant end of
+ * an array of WORD16s.  The BIG(x), LITTLE(y) and BIGLTTLE(x,y) macros
+ * defined in lbn.h (which expand to x on a big-edian machine and y on a
+ * little-endian machine) are used to conditionalize the code to work
+ * either way.  If you have no assembly primitives, it doesn't matter.
+ * Note that on a big-endian machine, the least-significant-end pointer
+ * is ONE PAST THE END.  The bytes are ptr[-1] through ptr[-len].
+ * On little-endian, they are ptr[0] through ptr[len-1].  This makes
+ * perfect sense if you consider pointers to point *between* bytes rather
+ * than at them.
+ *
+ * Because the array index values are unsigned integers, ptr[-i]
+ * may not work properly, since the index -i is evaluated as an unsigned,
+ * and if pointers are wider, zero-extension will produce a positive
+ * number rahter than the needed negative.  The expression used in this
+ * code, *(ptr-i) will, however, work.  (The array syntax is equivalent
+ * to *(ptr+-i), which is a pretty subtle difference.)
+ *
+ * Many of these routines will get very unhappy if fed zero-length inputs.
+ * They use assert() to enforce this.  An higher layer of code must make
+ * sure that these aren't called with zero-length inputs.
+ *
+ * Any of these routines can be replaced with more efficient versions
+ * elsewhere, by just #defining their names.  If one of the names
+ * is #defined, the C code is not compiled in and no declaration is
+ * made.  Use the BNINCLUDE file to do that.  Typically, you compile
+ * asm subroutines with the same name and just, e.g.
+ * #define lbnMulAdd1_16 lbnMulAdd1_16
+ *
+ * If you want to write asm routines, start with lbnMulAdd1_16().
+ * This is the workhorse of modular exponentiation.  lbnMulN1_16() is
+ * also used a fair bit, although not as much and it's defined in terms
+ * of lbnMulAdd1_16 if that has a custom version.  lbnMulSub1_16 and
+ * lbnDiv21_16 are used in the usual division and remainder finding.
+ * (Not the Montgomery reduction used in modular exponentiation, though.)
+ * Once you have lbnMulAdd1_16 defined, writing the other two should
+ * be pretty easy.  (Just make sure you get the sign of the subtraction
+ * in lbnMulSub1_16 right - it's dest = dest - source * k.)
+ *
+ * The only definitions that absolutely need a double-word (BNWORD32)
+ * type are lbnMulAdd1_16 and lbnMulSub1_16; if those are provided,
+ * the rest follows.  lbnDiv21_16, however, is a lot slower unless you
+ * have them, and lbnModQ_16 takes after it.  That one is used quite a
+ * bit for prime sieving.
+ */
+
+#ifndef HAVE_CONFIG_H
+#define HAVE_CONFIG_H 0
+#endif
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/*
+ * Some compilers complain about #if FOO if FOO isn't defined,
+ * so do the ANSI-mandated thing explicitly...
+ */
+#ifndef NO_ASSERT_H
+#define NO_ASSERT_H 0
+#endif
+#ifndef NO_STRING_H
+#define NO_STRING_H 0
+#endif
+#ifndef HAVE_STRINGS_H
+#define HAVE_STRINGS_H 0
+#endif
+#ifndef NEED_MEMORY_H
+#define NEED_MEMORY_H 0
+#endif
+
+#if !NO_ASSERT_H
+#include <assert.h>
+#else
+#define assert(x) (void)0
+#endif
+
+#if !NO_STRING_H
+#include <string.h>    /* For memcpy */
+#elif HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#if NEED_MEMORY_H
+#include <memory.h>
+#endif
+
+#include "lbn.h"
+#include "lbn16.h"
+#include "lbnmem.h"
+#include "legal.h"
+
+#include "kludge.h"
+#include <port_after.h>
+
+#ifndef BNWORD16
+#error 16-bit bignum library requires a 16-bit data type
+#endif
+
+/* Make sure the copyright notice gets included */
+volatile const char * volatile const lbnCopyright_16 = bnCopyright;
+
+/*
+ * Most of the multiply (and Montgomery reduce) routines use an outer
+ * loop that iterates over one of the operands - a so-called operand
+ * scanning approach.  One big advantage of this is that the assembly
+ * support routines are simpler.  The loops can be rearranged to have
+ * an outer loop that iterates over the product, a so-called product
+ * scanning approach.  This has the advantage of writing less data
+ * and doing fewer adds to memory, so is supposedly faster.  Some
+ * code has been written using a product-scanning approach, but
+ * it appears to be slower, so it is turned off by default.  Some
+ * experimentation would be appreciated.
+ *
+ * (The code is also annoying to get right and not very well commented,
+ * one of my pet peeves about math libraries.  I'm sorry.)
+ */
+#ifndef PRODUCT_SCAN
+#define PRODUCT_SCAN 0
+#endif
+
+/*
+ * Copy an array of words.  <Marvin mode on>  Thrilling, isn't it? </Marvin>
+ * This is a good example of how the byte offsets and BIGLITTLE() macros work.
+ * Another alternative would have been
+ * memcpy(dest BIG(-len), src BIG(-len), len*sizeof(BNWORD16)), but I find that
+ * putting operators into conditional macros is confusing.
+ */
+#ifndef lbnCopy_16
+void
+lbnCopy_16(BNWORD16 *dest, BNWORD16 const *src, unsigned len)
+{
+       memcpy(BIGLITTLE(dest-len,dest), BIGLITTLE(src-len,src),
+              len * sizeof(*src));
+}
+#endif /* !lbnCopy_16 */
+
+/*
+ * Fill n words with zero.  This does it manually rather than calling
+ * memset because it can assume alignment to make things faster while
+ * memset can't.  Note how big-endian numbers are naturally addressed
+ * using predecrement, while little-endian is postincrement.
+ */
+#ifndef lbnZero_16
+void
+lbnZero_16(BNWORD16 *num, unsigned len)
+{
+       while (len--)
+               BIGLITTLE(*--num,*num++) = 0;
+}
+#endif /* !lbnZero_16 */
+
+/*
+ * Negate an array of words.
+ * Negation is subtraction from zero.  Negating low-order words
+ * entails doing nothing until a non-zero word is hit.  Once that
+ * is negated, a borrow is generated and never dies until the end
+ * of the number is hit.  Negation with borrow, -x-1, is the same as ~x.
+ * Repeat that until the end of the number.
+ *
+ * Doesn't return borrow out because that's pretty useless - it's
+ * always set unless the input is 0, which is easy to notice in
+ * normalized form.
+ */
+#ifndef lbnNeg_16
+void
+lbnNeg_16(BNWORD16 *num, unsigned len)
+{
+       assert(len);
+
+       /* Skip low-order zero words */
+       while (BIGLITTLE(*--num,*num) == 0) {
+               if (!--len)
+                       return;
+               LITTLE(num++;)
+       }
+       /* Negate the lowest-order non-zero word */
+       *num = -*num;
+       /* Complement all the higher-order words */
+       while (--len) {
+               BIGLITTLE(--num,++num);
+               *num = ~*num;
+       }
+}
+#endif /* !lbnNeg_16 */
+
+
+/*
+ * lbnAdd1_16: add the single-word "carry" to the given number.
+ * Used for minor increments and propagating the carry after
+ * adding in a shorter bignum.
+ *
+ * Technique: If we have a double-width word, presumably the compiler
+ * can add using its carry in inline code, so we just use a larger
+ * accumulator to compute the carry from the first addition.
+ * If not, it's more complex.  After adding the first carry, which may
+ * be > 1, compare the sum and the carry.  If the sum wraps (causing a
+ * carry out from the addition), the result will be less than each of the
+ * inputs, since the wrap subtracts a number (2^16) which is larger than
+ * the other input can possibly be.  If the sum is >= the carry input,
+ * return success immediately.
+ * In either case, if there is a carry, enter a loop incrementing words
+ * until one does not wrap.  Since we are adding 1 each time, the wrap
+ * will be to 0 and we can test for equality.
+ */
+#ifndef lbnAdd1_16     /* If defined, it's provided as an asm subroutine */
+#ifdef BNWORD32
+BNWORD16
+lbnAdd1_16(BNWORD16 *num, unsigned len, BNWORD16 carry)
+{
+       BNWORD32 t;
+       assert(len > 0);        /* Alternative: if (!len) return carry */
+
+       t = (BNWORD32)BIGLITTLE(*--num,*num) + carry;
+       BIGLITTLE(*num,*num++) = (BNWORD16)t;
+       if ((t >> 16) == 0)
+               return 0;
+       while (--len) {
+               if (++BIGLITTLE(*--num,*num++) != 0)
+                       return 0;
+       }
+       return 1;
+}
+#else /* no BNWORD32 */
+BNWORD16
+lbnAdd1_16(BNWORD16 *num, unsigned len, BNWORD16 carry)
+{
+       assert(len > 0);        /* Alternative: if (!len) return carry */
+
+       if ((BIGLITTLE(*--num,*num++) += carry) >= carry)
+               return 0;
+       while (--len) {
+               if (++BIGLITTLE(*--num,*num++) != 0)
+                       return 0;
+       }
+       return 1;
+}
+#endif
+#endif/* !lbnAdd1_16 */
+
+/*
+ * lbnSub1_16: subtract the single-word "borrow" from the given number.
+ * Used for minor decrements and propagating the borrow after
+ * subtracting a shorter bignum.
+ *
+ * Technique: Similar to the add, above.  If there is a double-length type,
+ * use that to generate the first borrow.
+ * If not, after subtracting the first borrow, which may be > 1, compare
+ * the difference and the *negative* of the carry.  If the subtract wraps
+ * (causing a borrow out from the subtraction), the result will be at least
+ * as large as -borrow.  If the result < -borrow, then no borrow out has
+ * appeared and we may return immediately, except when borrow == 0.  To
+ * deal with that case, use the identity that -x = ~x+1, and instead of
+ * comparing < -borrow, compare for <= ~borrow.
+ * Either way, if there is a borrow out, enter a loop decrementing words
+ * until a non-zero word is reached.
+ *
+ * Note the cast of ~borrow to (BNWORD16).  If the size of an int is larger
+ * than BNWORD16, C rules say the number is expanded for the arithmetic, so
+ * the inversion will be done on an int and the value won't be quite what
+ * is expected.
+ */
+#ifndef lbnSub1_16     /* If defined, it's provided as an asm subroutine */
+#ifdef BNWORD32
+BNWORD16
+lbnSub1_16(BNWORD16 *num, unsigned len, BNWORD16 borrow)
+{
+       BNWORD32 t;
+       assert(len > 0);        /* Alternative: if (!len) return borrow */
+
+       t = (BNWORD32)BIGLITTLE(*--num,*num) - borrow;
+       BIGLITTLE(*num,*num++) = (BNWORD16)t;
+       if ((t >> 16) == 0)
+               return 0;
+       while (--len) {
+               if ((BIGLITTLE(*--num,*num++))-- != 0)
+                       return 0;
+       }
+       return 1;
+}
+#else /* no BNWORD32 */
+BNWORD16
+lbnSub1_16(BNWORD16 *num, unsigned len, BNWORD16 borrow)
+{
+       assert(len > 0);        /* Alternative: if (!len) return borrow */
+
+       if ((BIGLITTLE(*--num,*num++) -= borrow) <= (BNWORD16)~borrow)
+               return 0;
+       while (--len) {
+               if ((BIGLITTLE(*--num,*num++))-- != 0)
+                       return 0;
+       }
+       return 1;
+}
+#endif
+#endif /* !lbnSub1_16 */
+
+/*
+ * lbnAddN_16: add two bignums of the same length, returning the carry (0 or 1).
+ * One of the building blocks, along with lbnAdd1, of adding two bignums of
+ * differing lengths.
+ *
+ * Technique: Maintain a word of carry.  If there is no double-width type,
+ * use the same technique as in lbnAdd1, above, to maintain the carry by
+ * comparing the inputs.  Adding the carry sources is used as an OR operator;
+ * at most one of the two comparisons can possibly be true.  The first can
+ * only be true if carry == 1 and x, the result, is 0.  In that case the
+ * second can't possibly be true.
+ */
+#ifndef lbnAddN_16
+#ifdef BNWORD32
+BNWORD16
+lbnAddN_16(BNWORD16 *num1, BNWORD16 const *num2, unsigned len)
+{
+       BNWORD32 t;
+
+       assert(len > 0);
+
+       t = (BNWORD32)BIGLITTLE(*--num1,*num1) + BIGLITTLE(*--num2,*num2++);
+       BIGLITTLE(*num1,*num1++) = (BNWORD16)t;
+       while (--len) {
+               t = (BNWORD32)BIGLITTLE(*--num1,*num1) +
+                   (BNWORD32)BIGLITTLE(*--num2,*num2++) + (t >> 16);
+               BIGLITTLE(*num1,*num1++) = (BNWORD16)t;
+       }
+
+       return (BNWORD16)(t>>16);
+}
+#else /* no BNWORD32 */
+BNWORD16
+lbnAddN_16(BNWORD16 *num1, BNWORD16 const *num2, unsigned len)
+{
+       BNWORD16 x, carry = 0;
+
+       assert(len > 0);        /* Alternative: change loop to test at start */
+
+       do {
+               x = BIGLITTLE(*--num2,*num2++);
+               carry = (x += carry) < carry;
+               carry += (BIGLITTLE(*--num1,*num1++) += x) < x;
+       } while (--len);
+
+       return carry;
+}
+#endif
+#endif /* !lbnAddN_16 */
+
+/*
+ * lbnSubN_16: add two bignums of the same length, returning the carry (0 or 1).
+ * One of the building blocks, along with subn1, of subtracting two bignums of
+ * differing lengths.
+ *
+ * Technique: If no double-width type is availble, maintain a word of borrow.
+ * First, add the borrow to the subtrahend (did you have to learn all those
+ * awful words in elementary school, too?), and if it overflows, set the
+ * borrow again.  Then subtract the modified subtrahend from the next word
+ * of input, using the same technique as in subn1, above.
+ * Adding the borrows is used as an OR operator; at most one of the two
+ * comparisons can possibly be true.  The first can only be true if
+ * borrow == 1 and x, the result, is 0.  In that case the second can't
+ * possibly be true.
+ *
+ * In the double-word case, (BNWORD16)-(t>>16) is subtracted, rather than
+ * adding t>>16, because the shift would need to sign-extend and that's
+ * not guaranteed to happen in ANSI C, even with signed types.
+ */
+#ifndef lbnSubN_16
+#ifdef BNWORD32
+BNWORD16
+lbnSubN_16(BNWORD16 *num1, BNWORD16 const *num2, unsigned len)
+{
+       BNWORD32 t;
+
+       assert(len > 0);
+
+       t = (BNWORD32)BIGLITTLE(*--num1,*num1) - BIGLITTLE(*--num2,*num2++);
+       BIGLITTLE(*num1,*num1++) = (BNWORD16)t;
+
+       while (--len) {
+               t = (BNWORD32)BIGLITTLE(*--num1,*num1) -
+                   (BNWORD32)BIGLITTLE(*--num2,*num2++) - (BNWORD16)-(t >> 16);
+               BIGLITTLE(*num1,*num1++) = (BNWORD16)t;
+       }
+
+       return -(BNWORD16)(t>>16);
+}
+#else
+BNWORD16
+lbnSubN_16(BNWORD16 *num1, BNWORD16 const *num2, unsigned len)
+{
+       BNWORD16 x, borrow = 0;
+
+       assert(len > 0);        /* Alternative: change loop to test at start */
+
+       do {
+               x = BIGLITTLE(*--num2,*num2++);
+               borrow = (x += borrow) < borrow;
+               borrow += (BIGLITTLE(*--num1,*num1++) -= x) > (BNWORD16)~x;
+       } while (--len);
+
+       return borrow;
+}
+#endif
+#endif /* !lbnSubN_16 */
+
+#ifndef lbnCmp_16
+/*
+ * lbnCmp_16: compare two bignums of equal length, returning the sign of
+ * num1 - num2. (-1, 0 or +1).
+ * 
+ * Technique: Change the little-endian pointers to big-endian pointers
+ * and compare from the most-significant end until a difference if found.
+ * When it is, figure out the sign of the difference and return it.
+ */
+int
+lbnCmp_16(BNWORD16 const *num1, BNWORD16 const *num2, unsigned len)
+{
+       BIGLITTLE(num1 -= len, num1 += len);
+       BIGLITTLE(num2 -= len, num2 += len);
+
+       while (len--) {
+               if (BIGLITTLE(*num1++ != *num2++, *--num1 != *--num2)) {
+                       if (BIGLITTLE(num1[-1] < num2[-1], *num1 < *num2))
+                               return -1;
+                       else
+                               return 1;
+               }
+       }
+       return 0;
+}
+#endif /* !lbnCmp_16 */
+
+/*
+ * mul16_ppmmaa(ph,pl,x,y,a,b) is an optional routine that
+ * computes (ph,pl) = x * y + a + b.  mul16_ppmma and mul16_ppmm
+ * are simpler versions.  If you want to be lazy, all of these
+ * can be defined in terms of the others, so here we create any
+ * that have not been defined in terms of the ones that have been.
+ */
+
+/* Define ones with fewer a's in terms of ones with more a's */
+#if !defined(mul16_ppmma) && defined(mul16_ppmmaa)
+#define mul16_ppmma(ph,pl,x,y,a) mul16_ppmmaa(ph,pl,x,y,a,0)
+#endif
+
+#if !defined(mul16_ppmm) && defined(mul16_ppmma)
+#define mul16_ppmm(ph,pl,x,y) mul16_ppmma(ph,pl,x,y,0)
+#endif
+
+/*
+ * Use this definition to test the mul16_ppmm-based operations on machines
+ * that do not provide mul16_ppmm.  Change the final "0" to a "1" to
+ * enable it.
+ */
+#if !defined(mul16_ppmm) && defined(BNWORD32) && 0     /* Debugging */
+#define mul16_ppmm(ph,pl,x,y) \
+       ({BNWORD32 _ = (BNWORD32)(x)*(y); (pl) = _; (ph) = _>>16;})
+#endif
+
+#if defined(mul16_ppmm) && !defined(mul16_ppmma)
+#define mul16_ppmma(ph,pl,x,y,a) \
+       (mul16_ppmm(ph,pl,x,y), (ph) += ((pl) += (a)) < (a))
+#endif
+
+#if defined(mul16_ppmma) && !defined(mul16_ppmmaa)
+#define mul16_ppmmaa(ph,pl,x,y,a,b) \
+       (mul16_ppmma(ph,pl,x,y,a), (ph) += ((pl) += (b)) < (b))
+#endif
+
+/*
+ * lbnMulN1_16: Multiply an n-word input by a 1-word input and store the
+ * n+1-word product.  This uses either the mul16_ppmm and mul16_ppmma
+ * macros, or C multiplication with the BNWORD32 type.  This uses mul16_ppmma
+ * if available, assuming you won't bother defining it unless you can do
+ * better than the normal multiplication.
+ */
+#ifndef lbnMulN1_16
+#ifdef lbnMulAdd1_16   /* If we have this asm primitive, use it. */
+void
+lbnMulN1_16(BNWORD16 *out, BNWORD16 const *in, unsigned len, BNWORD16 k)
+{
+       lbnZero_16(out, len);
+       BIGLITTLE(*(out-len),*(out+len)) = lbnMulAdd1_16(out, in, len, k);
+}
+#elif defined(mul16_ppmm)
+void
+lbnMulN1_16(BNWORD16 *out, BNWORD16 const *in, unsigned len, BNWORD16 k)
+{
+       BNWORD16 prod, carry, carryin;
+
+       assert(len > 0);
+
+       BIG(--out;--in;);
+       mul16_ppmm(carry, *out, *in, k);
+       LITTLE(out++;in++;)
+
+       while (--len) {
+               BIG(--out;--in;)
+               carryin = carry;
+               mul16_ppmma(carry, *out, *in, k, carryin);
+               LITTLE(out++;in++;)
+       }
+       BIGLITTLE(*--out,*out) = carry;
+}
+#elif defined(BNWORD32)
+void
+lbnMulN1_16(BNWORD16 *out, BNWORD16 const *in, unsigned len, BNWORD16 k)
+{
+       BNWORD32 p;
+
+       assert(len > 0);
+
+       p = (BNWORD32)BIGLITTLE(*--in,*in++) * k;
+       BIGLITTLE(*--out,*out++) = (BNWORD16)p;
+
+       while (--len) {
+               p = (BNWORD32)BIGLITTLE(*--in,*in++) * k + (BNWORD16)(p >> 16);
+               BIGLITTLE(*--out,*out++) = (BNWORD16)p;
+       }
+       BIGLITTLE(*--out,*out) = (BNWORD16)(p >> 16);
+}
+#else
+#error No 16x16 -> 32 multiply available for 16-bit bignum package
+#endif
+#endif /* lbnMulN1_16 */
+
+/*
+ * lbnMulAdd1_16: Multiply an n-word input by a 1-word input and add the
+ * low n words of the product to the destination.  *Returns the n+1st word
+ * of the product.*  (That turns out to be more convenient than adding
+ * it into the destination and dealing with a possible unit carry out
+ * of *that*.)  This uses either the mul16_ppmma and mul16_ppmmaa macros,
+ * or C multiplication with the BNWORD32 type.
+ *
+ * If you're going to write assembly primitives, this is the one to
+ * start with.  It is by far the most commonly called function.
+ */
+#ifndef lbnMulAdd1_16
+#if defined(mul16_ppmm)
+BNWORD16
+lbnMulAdd1_16(BNWORD16 *out, BNWORD16 const *in, unsigned len, BNWORD16 k)
+{
+       BNWORD16 prod, carry, carryin;
+
+       assert(len > 0);
+
+       BIG(--out;--in;);
+       carryin = *out;
+       mul16_ppmma(carry, *out, *in, k, carryin);
+       LITTLE(out++;in++;)
+
+       while (--len) {
+               BIG(--out;--in;);
+               carryin = carry;
+               mul16_ppmmaa(carry, prod, *in, k, carryin, *out);
+               *out = prod;
+               LITTLE(out++;in++;)
+       }
+
+       return carry;
+}
+#elif defined(BNWORD32)
+BNWORD16
+lbnMulAdd1_16(BNWORD16 *out, BNWORD16 const *in, unsigned len, BNWORD16 k)
+{
+       BNWORD32 p;
+
+       assert(len > 0);
+
+       p = (BNWORD32)BIGLITTLE(*--in,*in++) * k + BIGLITTLE(*--out,*out);
+       BIGLITTLE(*out,*out++) = (BNWORD16)p;
+
+       while (--len) {
+               p = (BNWORD32)BIGLITTLE(*--in,*in++) * k +
+                   (BNWORD16)(p >> 16) + BIGLITTLE(*--out,*out);
+               BIGLITTLE(*out,*out++) = (BNWORD16)p;
+       }
+
+       return (BNWORD16)(p >> 16);
+}
+#else
+#error No 16x16 -> 32 multiply available for 16-bit bignum package
+#endif
+#endif /* lbnMulAdd1_16 */
+
+/*
+ * lbnMulSub1_16: Multiply an n-word input by a 1-word input and subtract the
+ * n-word product from the destination.  Returns the n+1st word of the product.
+ * This uses either the mul16_ppmm and mul16_ppmma macros, or
+ * C multiplication with the BNWORD32 type.
+ *
+ * This is rather uglier than adding, but fortunately it's only used in
+ * division which is not used too heavily.
+ */
+#ifndef lbnMulN1_16
+#if defined(mul16_ppmm)
+BNWORD16
+lbnMulSub1_16(BNWORD16 *out, BNWORD16 const *in, unsigned len, BNWORD16 k)
+{
+       BNWORD16 prod, carry, carryin;
+
+       assert(len > 0);
+
+       BIG(--in;)
+       mul16_ppmm(carry, prod, *in, k);
+       LITTLE(in++;)
+       carry += (BIGLITTLE(*--out,*out++) -= prod) > (BNWORD16)~prod;
+
+       while (--len) {
+               BIG(--in;);
+               carryin = carry;
+               mul16_ppmma(carry, prod, *in, k, carryin);
+               LITTLE(in++;)
+               carry += (BIGLITTLE(*--out,*out++) -= prod) > (BNWORD16)~prod;
+       }
+
+       return carry;
+}
+#elif defined(BNWORD32)
+BNWORD16
+lbnMulSub1_16(BNWORD16 *out, BNWORD16 const *in, unsigned len, BNWORD16 k)
+{
+       BNWORD32 p;
+       BNWORD16 carry, t;
+
+       assert(len > 0);
+
+       p = (BNWORD32)BIGLITTLE(*--in,*in++) * k;
+       t = BIGLITTLE(*--out,*out);
+       carry = (BNWORD16)(p>>16) + ((BIGLITTLE(*out,*out++)=t-(BNWORD16)p) > t);
+
+       while (--len) {
+               p = (BNWORD32)BIGLITTLE(*--in,*in++) * k + carry;
+               t = BIGLITTLE(*--out,*out);
+               carry = (BNWORD16)(p>>16) +
+                       ( (BIGLITTLE(*out,*out++)=t-(BNWORD16)p) > t );
+       }
+
+       return carry;
+}
+#else
+#error No 16x16 -> 32 multiply available for 16-bit bignum package
+#endif
+#endif /* !lbnMulSub1_16 */
+
+/*
+ * Shift n words left "shift" bits.  0 < shift < 16.  Returns the
+ * carry, any bits shifted off the left-hand side (0 <= carry < 2^shift).
+ */
+#ifndef lbnLshift_16
+BNWORD16
+lbnLshift_16(BNWORD16 *num, unsigned len, unsigned shift)
+{
+       BNWORD16 x, carry;
+
+       assert(shift > 0);
+       assert(shift < 16);
+
+       carry = 0;
+       while (len--) {
+               BIG(--num;)
+               x = *num;
+               *num = (x<<shift) | carry;
+               LITTLE(num++;)
+               carry = x >> (16-shift);
+       }
+       return carry;
+}
+#endif /* !lbnLshift_16 */
+
+/*
+ * An optimized version of the above, for shifts of 1.
+ * Some machines can use add-with-carry tricks for this.
+ */
+#ifndef lbnDouble_16
+BNWORD16
+lbnDouble_16(BNWORD16 *num, unsigned len)
+{
+       BNWORD16 x, carry;
+
+       carry = 0;
+       while (len--) {
+               BIG(--num;)
+               x = *num;
+               *num = (x<<1) | carry;
+               LITTLE(num++;)
+               carry = x >> (16-1);
+       }
+       return carry;
+}
+#endif /* !lbnDouble_16 */
+
+/*
+ * Shift n words right "shift" bits.  0 < shift < 16.  Returns the
+ * carry, any bits shifted off the right-hand side (0 <= carry < 2^shift).
+ */
+#ifndef lbnRshift_16
+BNWORD16
+lbnRshift_16(BNWORD16 *num, unsigned len, unsigned shift)
+{
+       BNWORD16 x, carry = 0;
+
+       assert(shift > 0);
+       assert(shift < 16);
+
+       BIGLITTLE(num -= len, num += len);
+
+       while (len--) {
+               LITTLE(--num;)
+               x = *num;
+               *num = (x>>shift) | carry;
+               BIG(num++;)
+               carry = x << (16-shift);
+       }
+       return carry >> (16-shift);
+}
+#endif /* !lbnRshift_16 */
+
+/* 
+ * Multiply two numbers of the given lengths.  prod and num2 may overlap,
+ * provided that the low len1 bits of prod are free.  (This corresponds
+ * nicely to the place the result is returned from lbnMontReduce_16.)
+ *
+ * TODO: Use Karatsuba multiply.  The overlap constraints may have
+ * to get rewhacked.
+ */
+#ifndef lbnMul_16
+void
+lbnMul_16(BNWORD16 *prod, BNWORD16 const *num1, unsigned len1,
+                          BNWORD16 const *num2, unsigned len2)
+{
+       /* Special case of zero */
+       if (!len1 || !len2) {
+               lbnZero_16(prod, len1+len2);
+               return;
+       }
+
+       /* Multiply first word */
+       lbnMulN1_16(prod, num1, len1, BIGLITTLE(*--num2,*num2++));
+
+       /*
+        * Add in subsequent words, storing the most significant word,
+        * which is new each time.
+        */
+       while (--len2) {
+               BIGLITTLE(--prod,prod++);
+               BIGLITTLE(*(prod-len1-1),*(prod+len1)) =
+                   lbnMulAdd1_16(prod, num1, len1, BIGLITTLE(*--num2,*num2++));
+       }
+}
+#endif /* !lbnMul_16 */
+
+/*
+ * lbnMulX_16 is a square multiply - both inputs are the same length.
+ * It's normally just a macro wrapper around the general multiply,
+ * but might be implementable in assembly more efficiently (such as
+ * when product scanning).
+ */
+#ifndef lbnMulX_16
+#if defined(BNWORD32) && PRODUCT_SCAN
+/*
+ * Test code to see whether product scanning is any faster.  It seems
+ * to make the C code slower, so PRODUCT_SCAN is not defined.
+ */
+static void
+lbnMulX_16(BNWORD16 *prod, BNWORD16 const *num1, BNWORD16 const *num2,
+       unsigned len)
+{
+       BNWORD32 x, y;
+       BNWORD16 const *p1, *p2;
+       unsigned carry;
+       unsigned i, j;
+
+       /* Special case of zero */
+       if (!len)
+               return;
+
+       x = (BNWORD32)BIGLITTLE(num1[-1] * num2[-1], num1[0] * num2[0]);
+       BIGLITTLE(*--prod, *prod++) = (BNWORD16)x;
+       x >>= 16;
+
+       for (i = 1; i < len; i++) {
+               carry = 0;
+               p1 = num1;
+               p2 = BIGLITTLE(num2-i-1,num2+i+1);
+               for (j = 0; j <= i; j++) {
+                       BIG(y = (BNWORD32)*--p1 * *p2++;)
+                       LITTLE(y = (BNWORD32)*p1++ * *--p2;)
+                       x += y;
+                       carry += (x < y);
+               }
+               BIGLITTLE(*--prod,*prod++) = (BNWORD16)x;
+               x = (x >> 16) | (BNWORD32)carry << 16;
+       }
+       for (i = 1; i < len; i++) {
+               carry = 0;
+               p1 = BIGLITTLE(num1-i,num1+i);
+               p2 = BIGLITTLE(num2-len,num2+len);
+               for (j = i; j < len; j++) {
+                       BIG(y = (BNWORD32)*--p1 * *p2++;)
+                       LITTLE(y = (BNWORD32)*p1++ * *--p2;)
+                       x += y;
+                       carry += (x < y);
+               }
+               BIGLITTLE(*--prod,*prod++) = (BNWORD16)x;
+               x = (x >> 16) | (BNWORD32)carry << 16;
+       }
+       
+       BIGLITTLE(*--prod,*prod) = (BNWORD16)x;
+}
+#else /* !defined(BNWORD32) || !PRODUCT_SCAN */
+/* Default trivial macro definition */
+#define lbnMulX_16(prod, num1, num2, len) lbnMul_16(prod, num1, len, num2, len)
+#endif /* !defined(BNWORD32) || !PRODUCT_SCAN */
+#endif /* !lbmMulX_16 */
+
+#if !defined(lbnMontMul_16) && defined(BNWORD32) && PRODUCT_SCAN
+/*
+ * Test code for product-scanning multiply.  This seems to slow the C
+ * code down rather than speed it up.
+ * This does a multiply and Montgomery reduction together, using the
+ * same loops.  The outer loop scans across the product, twice.
+ * The first pass computes the low half of the product and the
+ * Montgomery multipliers.  These are stored in the product array,
+ * which contains no data as of yet.  x and carry add up the columns
+ * and propagate carries forward.
+ *
+ * The second half multiplies the upper half, adding in the modulus
+ * times the Montgomery multipliers.  The results of this multiply
+ * are stored.
+ */
+static void
+lbnMontMul_16(BNWORD16 *prod, BNWORD16 const *num1, BNWORD16 const *num2,
+       BNWORD16 const *mod, unsigned len, BNWORD16 inv)
+{
+       BNWORD32 x, y;
+       BNWORD16 const *p1, *p2, *pm;
+       BNWORD16 *pp;
+       BNWORD16 t;
+       unsigned carry;
+       unsigned i, j;
+
+       /* Special case of zero */
+       if (!len)
+               return;
+
+       /*
+        * This computes directly into the high half of prod, so just
+        * shift the pointer and consider prod only "len" elements long
+        * for the rest of the code.
+        */
+       BIGLITTLE(prod -= len, prod += len);
+
+       /* Pass 1 - compute Montgomery multipliers */
+       /* First iteration can have certain simplifications. */
+       x = (BNWORD32)BIGLITTLE(num1[-1] * num2[-1], num1[0] * num2[0]);
+       BIGLITTLE(prod[-1], prod[0]) = t = inv * (BNWORD16)x;
+       y = (BNWORD32)t * BIGLITTLE(mod[-1],mod[0]);
+       x += y;
+       /* Note: GCC 2.6.3 has a bug if you try to eliminate "carry" */
+       carry = (x < y);
+       assert((BNWORD16)x == 0);
+       x = x >> 16 | (BNWORD32)carry << 16;
+
+       for (i = 1; i < len; i++) {
+               carry = 0;
+               p1 = num1;
+               p2 = BIGLITTLE(num2-i-1,num2+i+1);
+               pp = prod;
+               pm = BIGLITTLE(mod-i-1,mod+i+1);
+               for (j = 0; j < i; j++) {
+                       y = (BNWORD32)BIGLITTLE(*--p1 * *p2++, *p1++ * *--p2);
+                       x += y;
+                       carry += (x < y);
+                       y = (BNWORD32)BIGLITTLE(*--pp * *pm++, *pp++ * *--pm);
+                       x += y;
+                       carry += (x < y);
+               }
+               y = (BNWORD32)BIGLITTLE(p1[-1] * p2[0], p1[0] * p2[-1]);
+               x += y;
+               carry += (x < y);
+               assert(BIGLITTLE(pp == prod-i, pp == prod+i));
+               BIGLITTLE(pp[-1], pp[0]) = t = inv * (BNWORD16)x;
+               assert(BIGLITTLE(pm == mod-1, pm == mod+1));
+               y = (BNWORD32)t * BIGLITTLE(pm[0],pm[-1]);
+               x += y;
+               carry += (x < y);
+               assert((BNWORD16)x == 0);
+               x = x >> 16 | (BNWORD32)carry << 16;
+       }
+
+       /* Pass 2 - compute reduced product and store */
+       for (i = 1; i < len; i++) {
+               carry = 0;
+               p1 = BIGLITTLE(num1-i,num1+i);
+               p2 = BIGLITTLE(num2-len,num2+len);
+               pm = BIGLITTLE(mod-i,mod+i);
+               pp = BIGLITTLE(prod-len,prod+len);
+               for (j = i; j < len; j++) {
+                       y = (BNWORD32)BIGLITTLE(*--p1 * *p2++, *p1++ * *--p2);
+                       x += y;
+                       carry += (x < y);
+                       y = (BNWORD32)BIGLITTLE(*--pm * *pp++, *pm++ * *--pp);
+                       x += y;
+                       carry += (x < y);
+               }
+               assert(BIGLITTLE(pm == mod-len, pm == mod+len));
+               assert(BIGLITTLE(pp == prod-i, pp == prod+i));
+               BIGLITTLE(pp[0],pp[-1]) = (BNWORD16)x;
+               x = (x >> 16) | (BNWORD32)carry << 16;
+       }
+
+       /* Last round of second half, simplified. */
+       BIGLITTLE(*(prod-len),*(prod+len-1)) = (BNWORD16)x;
+       carry = (x >> 16);
+
+       while (carry)
+               carry -= lbnSubN_16(prod, mod, len);
+       while (lbnCmp_16(prod, mod, len) >= 0)
+               (void)lbnSubN_16(prod, mod, len);
+}
+/* Suppress later definition */
+#define lbnMontMul_16 lbnMontMul_16
+#endif
+
+#if !defined(lbnSquare_16) && defined(BNWORD32) && PRODUCT_SCAN
+/*
+ * Trial code for product-scanning squaring.  This seems to slow the C
+ * code down rather than speed it up.
+ */
+void
+lbnSquare_16(BNWORD16 *prod, BNWORD16 const *num, unsigned len)
+{
+       BNWORD32 x, y, z;
+       BNWORD16 const *p1, *p2;
+       unsigned carry;
+       unsigned i, j;
+
+       /* Special case of zero */
+       if (!len)
+               return;
+
+       /* Word 0 of product */
+       x = (BNWORD32)BIGLITTLE(num[-1] * num[-1], num[0] * num[0]);
+       BIGLITTLE(*--prod, *prod++) = (BNWORD16)x;
+       x >>= 16;
+
+       /* Words 1 through len-1 */
+       for (i = 1; i < len; i++) {
+               carry = 0;
+               y = 0;
+               p1 = num;
+               p2 = BIGLITTLE(num-i-1,num+i+1);
+               for (j = 0; j < (i+1)/2; j++) {
+                       BIG(z = (BNWORD32)*--p1 * *p2++;)
+                       LITTLE(z = (BNWORD32)*p1++ * *--p2;)
+                       y += z;
+                       carry += (y < z);
+               }
+               y += z = y;
+               carry += carry + (y < z);
+               if ((i & 1) == 0) {
+                       assert(BIGLITTLE(--p1 == p2, p1 == --p2));
+                       BIG(z = (BNWORD32)*p2 * *p2;)
+                       LITTLE(z = (BNWORD32)*p1 * *p1;)
+                       y += z;
+                       carry += (y < z);
+               }
+               x += y;
+               carry += (x < y);
+               BIGLITTLE(*--prod,*prod++) = (BNWORD16)x;
+               x = (x >> 16) | (BNWORD32)carry << 16;
+       }
+       /* Words len through 2*len-2 */
+       for (i = 1; i < len; i++) {
+               carry = 0;
+               y = 0;
+               p1 = BIGLITTLE(num-i,num+i);
+               p2 = BIGLITTLE(num-len,num+len);
+               for (j = 0; j < (len-i)/2; j++) {
+                       BIG(z = (BNWORD32)*--p1 * *p2++;)
+                       LITTLE(z = (BNWORD32)*p1++ * *--p2;)
+                       y += z;
+                       carry += (y < z);
+               }
+               y += z = y;
+               carry += carry + (y < z);
+               if ((len-i) & 1) {
+                       assert(BIGLITTLE(--p1 == p2, p1 == --p2));
+                       BIG(z = (BNWORD32)*p2 * *p2;)
+                       LITTLE(z = (BNWORD32)*p1 * *p1;)
+                       y += z;
+                       carry += (y < z);
+               }
+               x += y;
+               carry += (x < y);
+               BIGLITTLE(*--prod,*prod++) = (BNWORD16)x;
+               x = (x >> 16) | (BNWORD32)carry << 16;
+       }
+       
+       /* Word 2*len-1 */
+       BIGLITTLE(*--prod,*prod) = (BNWORD16)x;
+}
+/* Suppress later definition */
+#define lbnSquare_16 lbnSquare_16
+#endif
+
+/*
+ * Square a number, using optimized squaring to reduce the number of
+ * primitive multiples that are executed.  There may not be any
+ * overlap of the input and output.
+ *
+ * Technique: Consider the partial products in the multiplication
+ * of "abcde" by itself:
+ *
+ *               a  b  c  d  e
+ *            *  a  b  c  d  e
+ *          ==================
+ *              ae be ce de ee
+ *           ad bd cd dd de
+ *        ac bc cc cd ce
+ *     ab bb bc bd be
+ *  aa ab ac ad ae
+ *
+ * Note that everything above the main diagonal:
+ *              ae be ce de = (abcd) * e
+ *           ad bd cd       = (abc) * d
+ *        ac bc             = (ab) * c
+ *     ab                   = (a) * b
+ *
+ * is a copy of everything below the main diagonal:
+ *                       de
+ *                 cd ce
+ *           bc bd be
+ *     ab ac ad ae
+ *
+ * Thus, the sum is 2 * (off the diagonal) + diagonal.
+ *
+ * This is accumulated beginning with the diagonal (which
+ * consist of the squares of the digits of the input), which is then
+ * divided by two, the off-diagonal added, and multiplied by two
+ * again.  The low bit is simply a copy of the low bit of the
+ * input, so it doesn't need special care.
+ *
+ * TODO: Merge the shift by 1 with the squaring loop.
+ * TODO: Use Karatsuba.  (a*W+b)^2 = a^2 * (W^2+W) + b^2 * (W+1) - (a-b)^2 * W.
+ */
+#ifndef lbnSquare_16
+void
+lbnSquare_16(BNWORD16 *prod, BNWORD16 const *num, unsigned len)
+{
+       BNWORD16 t;
+       BNWORD16 *prodx = prod;         /* Working copy of the argument */
+       BNWORD16 const *numx = num;     /* Working copy of the argument */
+       unsigned lenx = len;            /* Working copy of the argument */
+
+       if (!len)
+               return;
+
+       /* First, store all the squares */
+       while (lenx--) {
+#ifdef mul16_ppmm
+               BNWORD16 ph, pl;
+               t = BIGLITTLE(*--numx,*numx++);
+               mul16_ppmm(ph,pl,t,t);
+               BIGLITTLE(*--prodx,*prodx++) = pl;
+               BIGLITTLE(*--prodx,*prodx++) = ph;
+#elif defined(BNWORD32) /* use BNWORD32 */
+               BNWORD32 p;
+               t = BIGLITTLE(*--numx,*numx++);
+               p = (BNWORD32)t * t;
+               BIGLITTLE(*--prodx,*prodx++) = (BNWORD16)p;
+               BIGLITTLE(*--prodx,*prodx++) = (BNWORD16)(p>>16);
+#else  /* Use lbnMulN1_16 */
+               t = BIGLITTLE(numx[-1],*numx);
+               lbnMulN1_16(prodx, numx, 1, t);
+               BIGLITTLE(--numx,numx++);
+               BIGLITTLE(prodx -= 2, prodx += 2);
+#endif
+       }
+       /* Then, shift right 1 bit */
+       (void)lbnRshift_16(prod, 2*len, 1);
+
+       /* Then, add in the off-diagonal sums */
+       lenx = len;
+       numx = num;
+       prodx = prod;
+       while (--lenx) {
+               t = BIGLITTLE(*--numx,*numx++);
+               BIGLITTLE(--prodx,prodx++);
+               t = lbnMulAdd1_16(prodx, numx, lenx, t);
+               lbnAdd1_16(BIGLITTLE(prodx-lenx,prodx+lenx), lenx+1, t);
+               BIGLITTLE(--prodx,prodx++);
+       }
+
+       /* Shift it back up */
+       lbnDouble_16(prod, 2*len);
+
+       /* And set the low bit appropriately */
+       BIGLITTLE(prod[-1],prod[0]) |= BIGLITTLE(num[-1],num[0]) & 1;
+}
+#endif /* !lbnSquare_16 */
+
+/*
+ * lbnNorm_16 - given a number, return a modified length such that the
+ * most significant digit is non-zero.  Zero-length input is okay.
+ */
+#ifndef lbnNorm_16
+unsigned
+lbnNorm_16(BNWORD16 const *num, unsigned len)
+{
+       BIGLITTLE(num -= len,num += len);
+       while (len && BIGLITTLE(*num++,*--num) == 0)
+               --len;
+       return len;
+}
+#endif /* lbnNorm_16 */
+
+/*
+ * lbnBits_16 - return the number of significant bits in the array.
+ * It starts by normalizing the array.  Zero-length input is okay.
+ * Then assuming there's anything to it, it fetches the high word,
+ * generates a bit length by multiplying the word length by 16, and
+ * subtracts off 16/2, 16/4, 16/8, ... bits if the high bits are clear.
+ */
+#ifndef lbnBits_16
+unsigned
+lbnBits_16(BNWORD16 const *num, unsigned len)
+{
+       BNWORD16 t;
+       unsigned i;
+
+       len = lbnNorm_16(num, len);
+       if (len) {
+               t = BIGLITTLE(*(num-len),*(num+(len-1)));
+               assert(t);
+               len *= 16;
+               i = 16/2;
+               do {
+                       if (t >> i)
+                               t >>= i;
+                       else
+                               len -= i;
+               } while ((i /= 2) != 0);
+       }
+       return len;
+}
+#endif /* lbnBits_16 */
+
+/*
+ * If defined, use hand-rolled divide rather than compiler's native.
+ * If the machine doesn't do it in line, the manual code is probably
+ * faster, since it can assume normalization and the fact that the
+ * quotient will fit into 16 bits, which a general 32-bit divide
+ * in a compiler's run-time library can't do.
+ */
+#ifndef BN_SLOW_DIVIDE_32
+/* Assume that divisors of more than thirty-two bits are slow */
+#define BN_SLOW_DIVIDE_32 (32 > 0x20)
+#endif
+
+/*
+ * Return (nh<<16|nl) % d, and place the quotient digit into *q.
+ * It is guaranteed that nh < d, and that d is normalized (with its high
+ * bit set).  If we have a double-width type, it's easy.  If not, ooh,
+ * yuk!
+ */
+#ifndef lbnDiv21_16
+#if defined(BNWORD32) && !BN_SLOW_DIVIDE_32
+BNWORD16
+lbnDiv21_16(BNWORD16 *q, BNWORD16 nh, BNWORD16 nl, BNWORD16 d)
+{
+       BNWORD32 n = (BNWORD32)nh << 16 | nl;
+
+       /* Divisor must be normalized */
+       assert(d >> (16-1) == 1);
+
+       *q = (BNWORD16)(n / d);
+       return (BNWORD16)(n % d);
+}
+#else
+/*
+ * This is where it gets ugly.
+ *
+ * Do the division in two halves, using Algorithm D from section 4.3.1
+ * of Knuth.  Note Theorem B from that section, that the quotient estimate
+ * is never more than the true quotient, and is never more than two
+ * too low.
+ *
+ * The mapping onto conventional long division is (everything a half word):
+ *        _____________qh___ql_
+ * dh dl ) nh.h nh.l nl.h nl.l
+ *             - (qh * d)
+ *            -----------
+ *              rrrr rrrr nl.l
+ *                  - (ql * d)
+ *                -----------
+ *                  rrrr rrrr
+ *
+ * The implicit 3/2-digit d*qh and d*ql subtractors are computed this way:
+ *   First, estimate a q digit so that nh/dh works.  Subtracting qh*dh from
+ *   the (nh.h nh.l) list leaves a 1/2-word remainder r.  Then compute the
+ *   low part of the subtractor, qh * dl.   This also needs to be subtracted
+ *   from (nh.h nh.l nl.h) to get the final remainder.  So we take the
+ *   remainder, which is (nh.h nh.l) - qh*dl, shift it and add in nl.h, and
+ *   try to subtract qh * dl from that.  Since the remainder is 1/2-word
+ *   long, shifting and adding nl.h results in a single word r.
+ *   It is possible that the remainder we're working with, r, is less than
+ *   the product qh * dl, if we estimated qh too high.  The estimation
+ *   technique can produce a qh that is too large (never too small), leading
+ *   to r which is too small.  In that case, decrement the digit qh, add
+ *   shifted dh to r (to correct for that error), and subtract dl from the
+ *   product we're comparing r with.  That's the "correct" way to do it, but
+ *   just adding dl to r instead of subtracting it from the product is
+ *   equivalent and a lot simpler.  You just have to watch out for overflow.
+ *
+ *   The process is repeated with (rrrr rrrr nl.l) for the low digit of the
+ *   quotient ql.
+ *
+ * The various uses of 16/2 for shifts are because of the note about
+ * automatic editing of this file at the very top of the file.
+ */
+#define highhalf(x) ( (x) >> 16/2 )
+#define lowhalf(x) ( (x) & (((BNWORD16)1 << 16/2)-1) )
+BNWORD16
+lbnDiv21_16(BNWORD16 *q, BNWORD16 nh, BNWORD16 nl, BNWORD16 d)
+{
+       BNWORD16 dh = highhalf(d), dl = lowhalf(d);
+       BNWORD16 qh, ql, prod, r;
+
+       /* Divisor must be normalized */
+       assert((d >> (16-1)) == 1);
+
+       /* Do first half-word of division */
+       qh = nh / dh;
+       r = nh % dh;
+       prod = qh * dl;
+
+       /*
+        * Add next half-word of numerator to remainder and correct.
+        * qh may be up to two too large.
+        */
+       r = (r << (16/2)) | highhalf(nl);
+       if (r < prod) {
+               --qh; r += d;
+               if (r >= d && r < prod) {
+                       --qh; r += d; 
+               }
+       }
+       r -= prod;
+
+       /* Do second half-word of division */
+       ql = r / dh;
+       r = r % dh;
+       prod = ql * dl;
+
+       r = (r << (16/2)) | lowhalf(nl);
+       if (r < prod) {
+               --ql; r += d;
+               if (r >= d && r < prod) {
+                       --ql; r += d;
+               }
+       }
+       r -= prod;
+
+       *q = (qh << (16/2)) | ql;
+
+       return r;
+}
+#endif
+#endif /* lbnDiv21_16 */
+
+
+/*
+ * In the division functions, the dividend and divisor are referred to
+ * as "n" and "d", which stand for "numerator" and "denominator".
+ *
+ * The quotient is (nlen-dlen+1) digits long.  It may be overlapped with
+ * the high (nlen-dlen) words of the dividend, but one extra word is needed
+ * on top to hold the top word.
+ */
+
+/*
+ * Divide an n-word number by a 1-word number, storing the remainder
+ * and n-1 words of the n-word quotient.  The high word is returned.
+ * It IS legal for rem to point to the same address as n, and for
+ * q to point one word higher.
+ *
+ * TODO: If BN_SLOW_DIVIDE_32, add a divnhalf_16 which uses 16-bit
+ *       dividends if the divisor is half that long.
+ * TODO: Shift the dividend on the fly to avoid the last division and
+ *       instead have a remainder that needs shifting.
+ * TODO: Use reciprocals rather than dividing.
+ */
+#ifndef lbnDiv1_16
+BNWORD16
+lbnDiv1_16(BNWORD16 *q, BNWORD16 *rem, BNWORD16 const *n, unsigned len,
+       BNWORD16 d)
+{
+       unsigned shift;
+       unsigned xlen;
+       BNWORD16 r;
+       BNWORD16 qhigh;
+
+       assert(len > 0);
+       assert(d);
+
+       if (len == 1) {
+               r = *n;
+               *rem = r%d;
+               return r/d;
+       }
+
+       shift = 0;
+       r = d;
+       xlen = 16/2;
+       do {
+               if (r >> xlen)
+                       r >>= xlen;
+               else
+                       shift += xlen;
+       } while ((xlen /= 2) != 0);
+       assert((d >> (16-1-shift)) == 1);
+       d <<= shift;
+
+       BIGLITTLE(q -= len-1,q += len-1);
+       BIGLITTLE(n -= len,n += len);
+
+       r = BIGLITTLE(*n++,*--n);
+       if (r < d) {
+               qhigh = 0;
+       } else {
+               qhigh = r/d;
+               r %= d;
+       }
+
+       xlen = len;
+       while (--xlen)
+               r = lbnDiv21_16(BIGLITTLE(q++,--q), r, BIGLITTLE(*n++,*--n), d);
+
+       /*
+        * Final correction for shift - shift the quotient up "shift"
+        * bits, and merge in the extra bits of quotient.  Then reduce
+        * the final remainder mod the real d.
+        */
+       if (shift) {
+               d >>= shift;
+               qhigh = (qhigh << shift) | lbnLshift_16(q, len-1, shift);
+               BIGLITTLE(q[-1],*q) |= r/d;
+               r %= d;
+       }
+       *rem = r;
+
+       return qhigh;
+}
+#endif
+
+/*
+ * This function performs a "quick" modulus of a number with a divisor
+ * d which is guaranteed to be at most sixteen bits, i.e. less than 65536.
+ * This applies regardless of the word size the library is compiled with.
+ *
+ * This function is important to prime generation, for sieving.
+ */
+#ifndef lbnModQ_16
+/* If there's a custom lbnMod21_16, no normalization needed */
+#ifdef lbnMod21_16
+unsigned
+lbnModQ_16(BNWORD16 const *n, unsigned len, unsigned d)
+{
+       unsigned i, shift;
+       BNWORD16 r;
+
+       assert(len > 0);
+
+       BIGLITTLE(n -= len,n += len);
+
+       /* Try using a compare to avoid the first divide */
+       r = BIGLITTLE(*n++,*--n);
+       if (r >= d)
+               r %= d;
+       while (--len)
+               r = lbnMod21_16(r, BIGLITTLE(*n++,*--n), d);
+
+       return r;
+}
+#elif defined(BNWORD32) && !BN_SLOW_DIVIDE_32
+unsigned
+lbnModQ_16(BNWORD16 const *n, unsigned len, unsigned d)
+{
+       BNWORD16 r;
+
+       if (!--len)
+               return BIGLITTLE(n[-1],n[0]) % d;
+
+       BIGLITTLE(n -= len,n += len);
+       r = BIGLITTLE(n[-1],n[0]);
+
+       do {
+               r = (BNWORD16)((((BNWORD32)r<<16) | BIGLITTLE(*n++,*--n)) % d);
+       } while (--len);
+
+       return r;
+}
+#elif 16 >= 0x20
+/*
+ * If the single word size can hold 65535*65536, then this function
+ * is avilable.
+ */
+#ifndef highhalf
+#define highhalf(x) ( (x) >> 16/2 )
+#define lowhalf(x) ( (x) & ((1 << 16/2)-1) )
+#endif
+unsigned
+lbnModQ_16(BNWORD16 const *n, unsigned len, unsigned d)
+{
+       BNWORD16 r, x;
+
+       BIGLITTLE(n -= len,n += len);
+
+       r = BIGLITTLE(*n++,*--n);
+       while (--len) {
+               x = BIGLITTLE(*n++,*--n);
+               r = (r%d << 16/2) | highhalf(x);
+               r = (r%d << 16/2) | lowhalf(x);
+       }
+
+       return r%d;
+}
+#else
+/* Default case - use lbnDiv21_16 */
+unsigned
+lbnModQ_16(BNWORD16 const *n, unsigned len, unsigned d)
+{
+       unsigned i, shift;
+       BNWORD16 r;
+       BNWORD16 q;
+
+       assert(len > 0);
+
+       shift = 0;
+       r = d;
+       i = 16;
+       while (i /= 2) {
+               if (r >> i)
+                       r >>= i;
+               else
+                       shift += i;
+       }
+       assert(d >> (16-1-shift) == 1);
+       d <<= shift;
+
+       BIGLITTLE(n -= len,n += len);
+
+       r = BIGLITTLE(*n++,*--n);
+       if (r >= d)
+               r %= d;
+
+       while (--len)
+               r = lbnDiv21_16(&q, r, BIGLITTLE(*n++,*--n), d);
+
+       /*
+        * Final correction for shift - shift the quotient up "shift"
+        * bits, and merge in the extra bits of quotient.  Then reduce
+        * the final remainder mod the real d.
+        */
+       if (shift)
+               r %= d >> shift;
+
+       return r;
+}
+#endif
+#endif /* lbnModQ_16 */
+
+/*
+ * Reduce n mod d and return the quotient.  That is, find:
+ * q = n / d;
+ * n = n % d;
+ * d is altered during the execution of this subroutine by normalizing it.
+ * It must already have its most significant word non-zero; it is shifted
+ * so its most significant bit is non-zero.
+ *
+ * The quotient q is nlen-dlen+1 words long.  To make it possible to
+ * overlap the quptient with the input (you can store it in the high dlen
+ * words), the high word of the quotient is *not* stored, but is returned.
+ * (If all you want is the remainder, you don't care about it, anyway.)
+ *
+ * This uses algorithm D from Knuth (4.3.1), except that we do binary
+ * (shift) normalization of the divisor.  WARNING: This is hairy!
+ *
+ * This function is used for some modular reduction, but it is not used in
+ * the modular exponentiation loops; they use Montgomery form and the
+ * corresponding, more efficient, Montgomery reduction.  This code
+ * is needed for the conversion to Montgomery form, however, so it
+ * has to be here and it might as well be reasonably efficient.
+ *
+ * The overall operation is as follows ("top" and "up" refer to the
+ * most significant end of the number; "bottom" and "down", the least):
+ *
+ * - Shift the divisor up until the most significant bit is set.
+ * - Shift the dividend up the same amount.  This will produce the
+ *   correct quotient, and the remainder can be recovered by shifting
+ *   it back down the same number of bits.  This may produce an overflow
+ *   word, but the word is always strictly less than the most significant
+ *   divisor word.
+ * - Estimate the first quotient digit qhat:
+ *   - First take the top two words (one of which is the overflow) of the
+ *     dividend and divide by the top word of the divisor:
+ *     qhat = (nh,nm)/dh.  This qhat is >= the correct quotient digit
+ *     and, since dh is normalized, it is at most two over.
+ *   - Second, correct by comparing the top three words.  If
+ *     (dh,dl) * qhat > (nh,nm,ml), decrease qhat and try again.
+ *     The second iteration can be simpler because there can't be a third.
+ *     The computation can be simplified by subtracting dh*qhat from
+ *     both sides, suitably shifted.  This reduces the left side to
+ *     dl*qhat.  On the right, (nh,nm)-dh*qhat is simply the
+ *     remainder r from (nh,nm)%dh, so the right is (r,nl).
+ *     This produces qhat that is almost always correct and at
+ *     most (prob ~ 2/2^16) one too high.
+ * - Subtract qhat times the divisor (suitably shifted) from the dividend.
+ *   If there is a borrow, qhat was wrong, so decrement it
+ *   and add the divisor back in (once).
+ * - Store the final quotient digit qhat in the quotient array q.
+ *
+ * Repeat the quotient digit computation for successive digits of the
+ * quotient until the whole quotient has been computed.  Then shift the
+ * divisor and the remainder down to correct for the normalization.
+ *
+ * TODO: Special case 2-word divisors.
+ * TODO: Use reciprocals rather than dividing.
+ */
+#ifndef divn_16
+BNWORD16
+lbnDiv_16(BNWORD16 *q, BNWORD16 *n, unsigned nlen, BNWORD16 *d, unsigned dlen)
+{
+       BNWORD16 nh,nm,nl;      /* Top three words of the dividend */
+       BNWORD16 dh,dl; /* Top two words of the divisor */
+       BNWORD16 qhat;  /* Extimate of quotient word */
+       BNWORD16 r;     /* Remainder from quotient estimate division */
+       BNWORD16 qhigh; /* High word of quotient */
+       unsigned i;     /* Temp */
+       unsigned shift; /* Bits shifted by normalization */
+       unsigned qlen = nlen-dlen; /* Size of quotient (less 1) */
+#ifdef mul16_ppmm
+       BNWORD16 t16;
+#elif defined(BNWORD32)
+       BNWORD32 t32;
+#else /* use lbnMulN1_16 */
+       BNWORD16 t2[2];
+#define t2high BIGLITTLE(t2[0],t2[1])
+#define t2low BIGLITTLE(t2[1],t2[0])
+#endif
+
+       assert(dlen);
+       assert(nlen >= dlen);
+
+       /*
+        * Special cases for short divisors.  The general case uses the
+        * top top 2 digits of the divisor (d) to estimate a quotient digit,
+        * so it breaks if there are fewer digits available.  Thus, we need
+        * special cases for a divisor of length 1.  A divisor of length
+        * 2 can have a *lot* of administrivia overhead removed removed,
+        * so it's probably worth special-casing that case, too.
+        */
+       if (dlen == 1)
+               return lbnDiv1_16(q, BIGLITTLE(n-1,n), n, nlen,
+                                 BIGLITTLE(d[-1],d[0]));
+
+#if 0
+       /*
+        * @@@ This is not yet written...  The general loop will do,
+        * albeit less efficiently
+        */
+       if (dlen == 2) {
+               /*
+                * divisor two digits long:
+                * use the 3/2 technique from Knuth, but we know
+                * it's exact.
+                */
+               dh = BIGLITTLE(d[-1],d[0]);
+               dl = BIGLITTLE(d[-2],d[1]);
+               shift = 0;
+               if ((sh & ((BNWORD16)1 << 16-1-shift)) == 0) {
+                       do {
+                               shift++;
+                       } while (dh & (BNWORD16)1<<16-1-shift) == 0);
+                       dh = dh << shift | dl >> (16-shift);
+                       dl <<= shift;
+
+
+               }
+
+
+               for (shift = 0; (dh & (BNWORD16)1 << 16-1-shift)) == 0; shift++)
+                       ;
+               if (shift) {
+               }
+               dh = dh << shift | dl >> (16-shift);
+               shift = 0;
+               while (dh
+       }
+#endif
+
+       dh = BIGLITTLE(*(d-dlen),*(d+(dlen-1)));
+       assert(dh);
+
+       /* Normalize the divisor */
+       shift = 0;
+       r = dh;
+       i = 16/2;
+       do {
+               if (r >> i)
+                       r >>= i;
+               else
+                       shift += i;
+       } while ((i /= 2) != 0);
+
+       nh = 0;
+       if (shift) {
+               lbnLshift_16(d, dlen, shift);
+               dh = BIGLITTLE(*(d-dlen),*(d+(dlen-1)));
+               nh = lbnLshift_16(n, nlen, shift);
+       }
+
+       /* Assert that dh is now normalized */
+       assert(dh >> (16-1));
+
+       /* Also get the second-most significant word of the divisor */
+       dl = BIGLITTLE(*(d-(dlen-1)),*(d+(dlen-2)));
+
+       /*
+        * Adjust pointers: n to point to least significant end of first
+        * first subtract, and q to one the most-significant end of the
+        * quotient array.
+        */
+       BIGLITTLE(n -= qlen,n += qlen);
+       BIGLITTLE(q -= qlen,q += qlen);
+
+       /* Fetch the most significant stored word of the dividend */
+       nm = BIGLITTLE(*(n-dlen),*(n+(dlen-1)));
+
+       /*
+        * Compute the first digit of the quotient, based on the
+        * first two words of the dividend (the most significant of which
+        * is the overflow word h).
+        */
+       if (nh) {
+               assert(nh < dh);
+               r = lbnDiv21_16(&qhat, nh, nm, dh);
+       } else if (nm >= dh) {
+               qhat = nm/dh;
+               r = nm % dh;
+       } else {        /* Quotient is zero */
+               qhigh = 0;
+               goto divloop;
+       }
+
+       /* Now get the third most significant word of the dividend */
+       nl = BIGLITTLE(*(n-(dlen-1)),*(n+(dlen-2)));
+
+       /*
+        * Correct qhat, the estimate of quotient digit.
+        * qhat can only be high, and at most two words high,
+        * so the loop can be unrolled and abbreviated.
+        */
+#ifdef mul16_ppmm
+       mul16_ppmm(nm, t16, qhat, dl);
+       if (nm > r || (nm == r && t16 > nl)) {
+               /* Decrement qhat and adjust comparison parameters */
+               qhat--;
+               if ((r += dh) >= dh) {
+                       nm -= (t16 < dl);
+                       t16 -= dl;
+                       if (nm > r || (nm == r && t16 > nl))
+                               qhat--;
+               }
+       }
+#elif defined(BNWORD32)
+       t32 = (BNWORD32)qhat * dl;
+       if (t32 > ((BNWORD32)r << 16) + nl) {
+               /* Decrement qhat and adjust comparison parameters */
+               qhat--;
+               if ((r += dh) > dh) {
+                       t32 -= dl;
+                       if (t32 > ((BNWORD32)r << 16) + nl)
+                               qhat--;
+               }
+       }
+#else /* Use lbnMulN1_16 */
+       lbnMulN1_16(BIGLITTLE(t2+2,t2), &dl, 1, qhat);
+       if (t2high > r || (t2high == r && t2low > nl)) {
+               /* Decrement qhat and adjust comparison parameters */
+               qhat--;
+               if ((r += dh) >= dh) {
+                       t2high -= (t2low < dl);
+                       t2low -= dl;
+                       if (t2high > r || (t2high == r && t2low > nl))
+                               qhat--;
+               }
+       }
+#endif
+
+       /* Do the multiply and subtract */
+       r = lbnMulSub1_16(n, d, dlen, qhat);
+       /* If there was a borrow, add back once. */
+       if (r > nh) {   /* Borrow? */
+               (void)lbnAddN_16(n, d, dlen);
+               qhat--;
+       }
+
+       /* Remember the first quotient digit. */
+       qhigh = qhat;
+
+       /* Now, the main division loop: */
+divloop:
+       while (qlen--) {
+
+               /* Advance n */
+               nh = BIGLITTLE(*(n-dlen),*(n+(dlen-1)));
+               BIGLITTLE(++n,--n);
+               nm = BIGLITTLE(*(n-dlen),*(n+(dlen-1)));
+
+               if (nh == dh) {
+                       qhat = ~(BNWORD16)0;
+                       /* Optimized computation of r = (nh,nm) - qhat * dh */
+                       r = nh + nm;
+                       if (r < nh)
+                               goto subtract;
+               } else {
+                       assert(nh < dh);
+                       r = lbnDiv21_16(&qhat, nh, nm, dh);
+               }
+
+               nl = BIGLITTLE(*(n-(dlen-1)),*(n+(dlen-2)));
+#ifdef mul16_ppmm
+               mul16_ppmm(nm, t16, qhat, dl);
+               if (nm > r || (nm == r && t16 > nl)) {
+                       /* Decrement qhat and adjust comparison parameters */
+                       qhat--;
+                       if ((r += dh) >= dh) {
+                               nm -= (t16 < dl);
+                               t16 -= dl;
+                               if (nm > r || (nm == r && t16 > nl))
+                                       qhat--;
+                       }
+               }
+#elif defined(BNWORD32)
+               t32 = (BNWORD32)qhat * dl;
+               if (t32 > ((BNWORD32)r<<16) + nl) {
+                       /* Decrement qhat and adjust comparison parameters */
+                       qhat--;
+                       if ((r += dh) >= dh) {
+                               t32 -= dl;
+                               if (t32 > ((BNWORD32)r << 16) + nl)
+                                       qhat--;
+                       }
+               }
+#else /* Use lbnMulN1_16 */
+               lbnMulN1_16(BIGLITTLE(t2+2,t2), &dl, 1, qhat);
+               if (t2high > r || (t2high == r && t2low > nl)) {
+                       /* Decrement qhat and adjust comparison parameters */
+                       qhat--;
+                       if ((r += dh) >= dh) {
+                               t2high -= (t2low < dl);
+                               t2low -= dl;
+                               if (t2high > r || (t2high == r && t2low > nl))
+                                       qhat--;
+                       }
+               }
+#endif
+
+               /*
+                * As a point of interest, note that it is not worth checking
+                * for qhat of 0 or 1 and installing special-case code.  These
+                * occur with probability 2^-16, so spending 1 cycle to check
+                * for them is only worth it if we save more than 2^15 cycles,
+                * and a multiply-and-subtract for numbers in the 1024-bit
+                * range just doesn't take that long.
+                */
+subtract:
+               /*
+                * n points to the least significant end of the substring
+                * of n to be subtracted from.  qhat is either exact or
+                * one too large.  If the subtract gets a borrow, it was
+                * one too large and the divisor is added back in.  It's
+                * a dlen+1 word add which is guaranteed to produce a
+                * carry out, so it can be done very simply.
+                */
+               r = lbnMulSub1_16(n, d, dlen, qhat);
+               if (r > nh) {   /* Borrow? */
+                       (void)lbnAddN_16(n, d, dlen);
+                       qhat--;
+               }
+               /* Store the quotient digit */
+               BIGLITTLE(*q++,*--q) = qhat;
+       }
+       /* Tah dah! */
+
+       if (shift) {
+               lbnRshift_16(d, dlen, shift);
+               lbnRshift_16(n, dlen, shift);
+       }
+
+       return qhigh;
+}
+#endif
+
+/*
+ * Find the negative multiplicative inverse of x (x must be odd!) modulo 2^16.
+ *
+ * This just performs Newton's iteration until it gets the
+ * inverse.  The initial estimate is always correct to 3 bits, and
+ * sometimes 4.  The number of valid bits doubles each iteration.
+ * (To prove it, assume x * y == 1 (mod 2^n), and introduce a variable
+ * for the error mod 2^2n.  x * y == 1 + k*2^n (mod 2^2n) and follow
+ * the iteration through.)
+ */
+#ifndef lbnMontInv1_16
+BNWORD16
+lbnMontInv1_16(BNWORD16 const x)
+{
+        BNWORD16 y = x, z;
+
+       assert(x & 1);
+        while ((z = x*y) != 1)
+                y *= 2 - z;
+        return -y;
+}
+#endif /* !lbnMontInv1_16 */
+
+#if defined(BNWORD32) && PRODUCT_SCAN
+/*
+ * Test code for product-scanning Montgomery reduction.
+ * This seems to slow the C code down rather than speed it up.
+ *
+ * The first loop computes the Montgomery multipliers, storing them over
+ * the low half of the number n.
+ *
+ * The second half multiplies the upper half, adding in the modulus
+ * times the Montgomery multipliers.  The results of this multiply
+ * are stored.
+ */
+void
+lbnMontReduce_16(BNWORD16 *n, BNWORD16 const *mod, unsigned mlen, BNWORD16 inv)
+{
+       BNWORD32 x, y;
+       BNWORD16 const *pm;
+       BNWORD16 *pn;
+       BNWORD16 t;
+       unsigned carry;
+       unsigned i, j;
+
+       /* Special case of zero */
+       if (!mlen)
+               return;
+
+       /* Pass 1 - compute Montgomery multipliers */
+       /* First iteration can have certain simplifications. */
+       t = BIGLITTLE(n[-1],n[0]);
+       x = t;
+       t *= inv;
+       BIGLITTLE(n[-1], n[0]) = t;
+       x += (BNWORD32)t * BIGLITTLE(mod[-1],mod[0]); /* Can't overflow */
+       assert((BNWORD16)x == 0);
+       x = x >> 16;
+
+       for (i = 1; i < mlen; i++) {
+               carry = 0;
+               pn = n;
+               pm = BIGLITTLE(mod-i-1,mod+i+1);
+               for (j = 0; j < i; j++) {
+                       y = (BNWORD32)BIGLITTLE(*--pn * *pm++, *pn++ * *--pm);
+                       x += y;
+                       carry += (x < y);
+               }
+               assert(BIGLITTLE(pn == n-i, pn == n+i));
+               y = t = BIGLITTLE(pn[-1], pn[0]);
+               x += y;
+               carry += (x < y);
+               BIGLITTLE(pn[-1], pn[0]) = t = inv * (BNWORD16)x;
+               assert(BIGLITTLE(pm == mod-1, pm == mod+1));
+               y = (BNWORD32)t * BIGLITTLE(pm[0],pm[-1]);
+               x += y;
+               carry += (x < y);
+               assert((BNWORD16)x == 0);
+               x = x >> 16 | (BNWORD32)carry << 16;
+       }
+
+       BIGLITTLE(n -= mlen, n += mlen);
+
+       /* Pass 2 - compute upper words and add to n */
+       for (i = 1; i < mlen; i++) {
+               carry = 0;
+               pm = BIGLITTLE(mod-i,mod+i);
+               pn = n;
+               for (j = i; j < mlen; j++) {
+                       y = (BNWORD32)BIGLITTLE(*--pm * *pn++, *pm++ * *--pn);
+                       x += y;
+                       carry += (x < y);
+               }
+               assert(BIGLITTLE(pm == mod-mlen, pm == mod+mlen));
+               assert(BIGLITTLE(pn == n+mlen-i, pn == n-mlen+i));
+               y = t = BIGLITTLE(*(n-i),*(n+i-1));
+               x += y;
+               carry += (x < y);
+               BIGLITTLE(*(n-i),*(n+i-1)) = (BNWORD16)x;
+               x = (x >> 16) | (BNWORD32)carry << 16;
+       }
+
+       /* Last round of second half, simplified. */
+       t = BIGLITTLE(*(n-mlen),*(n+mlen-1));
+       x += t;
+       BIGLITTLE(*(n-mlen),*(n+mlen-1)) = (BNWORD16)x;
+       carry = (unsigned)(x >> 16);
+
+       while (carry)
+               carry -= lbnSubN_16(n, mod, mlen);
+       while (lbnCmp_16(n, mod, mlen) >= 0)
+               (void)lbnSubN_16(n, mod, mlen);
+}
+#define lbnMontReduce_16 lbnMontReduce_16
+#endif
+
+/*
+ * Montgomery reduce n, modulo mod.  This reduces modulo mod and divides by
+ * 2^(16*mlen).  Returns the result in the *top* mlen words of the argument n.
+ * This is ready for another multiplication using lbnMul_16.
+ *
+ * Montgomery representation is a very useful way to encode numbers when
+ * you're doing lots of modular reduction.  What you do is pick a multiplier
+ * R which is relatively prime to the modulus and very easy to divide by.
+ * Since the modulus is odd, R is closen as a power of 2, so the division
+ * is a shift.  In fact, it's a shift of an integral number of words,
+ * so the shift can be implicit - just drop the low-order words.
+ *
+ * Now, choose R *larger* than the modulus m, 2^(16*mlen).  Then convert
+ * all numbers a, b, etc. to Montgomery form M(a), M(b), etc using the
+ * relationship M(a) = a*R mod m, M(b) = b*R mod m, etc.  Note that:
+ * - The Montgomery form of a number depends on the modulus m.
+ *   A fixed modulus m is assumed throughout this discussion.
+ * - Since R is relaitvely prime to m, multiplication by R is invertible;
+ *   no information about the numbers is lost, they're just scrambled.
+ * - Adding (and subtracting) numbers in this form works just as usual.
+ *   M(a+b) = (a+b)*R mod m = (a*R + b*R) mod m = (M(a) + M(b)) mod m
+ * - Multiplying numbers in this form produces a*b*R*R.  The problem
+ *   is to divide out the excess factor of R, modulo m as well as to
+ *   reduce to the given length mlen.  It turns out that this can be
+ *   done *faster* than a normal divide, which is where the speedup
+ *   in Montgomery division comes from.
+ *
+ * Normal reduction chooses a most-significant quotient digit q and then
+ * subtracts q*m from the number to be reduced.  Choosing q is tricky
+ * and involved (just look at lbnDiv_16 to see!) and is usually
+ * imperfect, requiring a check for correction after the subtraction.
+ *
+ * Montgomery reduction *adds* a multiple of m to the *low-order* part
+ * of the number to be reduced.  This multiple is chosen to make the
+ * low-order part of the number come out to zero.  This can be done
+ * with no trickery or error using a precomputed inverse of the modulus.
+ * In this code, the "part" is one word, but any width can be used.
+ *
+ * Repeating this step sufficiently often results in a value which
+ * is a multiple of R (a power of two, remember) but is still (since
+ * the additions were to the low-order part and thus did not increase
+ * the value of the number being reduced very much) still not much
+ * larger than m*R.  Then implicitly divide by R and subtract off
+ * m until the result is in the correct range.
+ *
+ * Since the low-order part being cancelled is less than R, the
+ * multiple of m added must have a multiplier which is at most R-1.
+ * Assuming that the input is at most m*R-1, the final number is
+ * at most m*(2*R-1)-1 = 2*m*R - m - 1, so subtracting m once from
+ * the high-order part, equivalent to subtracting m*R from the
+ * while number, produces a result which is at most m*R - m - 1,
+ * which divided by R is at most m-1.
+ *
+ * To convert *to* Montgomery form, you need a regular remainder
+ * routine, although you can just compute R*R (mod m) and do the
+ * conversion using Montgomery multiplication.  To convert *from*
+ * Montgomery form, just Montgomery reduce the number to
+ * remove the extra factor of R.
+ * 
+ * TODO: Change to a full inverse and use Karatsuba's multiplication
+ * rather than this word-at-a-time.
+ */
+#ifndef lbnMontReduce_16
+void
+lbnMontReduce_16(BNWORD16 *n, BNWORD16 const *mod, unsigned const mlen,
+                BNWORD16 inv)
+{
+       BNWORD16 t;
+       BNWORD16 c = 0;
+       unsigned len = mlen;
+
+       /* inv must be the negative inverse of mod's least significant word */
+       assert((BNWORD16)(inv * BIGLITTLE(mod[-1],mod[0])) == (BNWORD16)-1);
+
+       assert(len);
+
+       do {
+               t = lbnMulAdd1_16(n, mod, mlen, (BNWORD16)(inv * BIGLITTLE(n[-1],n[0])));
+               c += lbnAdd1_16(BIGLITTLE(n-mlen,n+mlen), len, t);
+               BIGLITTLE(--n,++n);
+       } while (--len);
+
+       /*
+        * All that adding can cause an overflow past the modulus size,
+        * but it's unusual, and never by much, so a subtraction loop
+        * is the right way to deal with it.
+        * This subtraction happens infrequently - I've only ever seen it
+        * invoked once per reduction, and then just under 22.5% of the time.
+        */
+       while (c)
+               c -= lbnSubN_16(n, mod, mlen);
+       while (lbnCmp_16(n, mod, mlen) >= 0)
+               (void)lbnSubN_16(n, mod, mlen);
+}
+#endif /* !lbnMontReduce_16 */
+
+/*
+ * A couple of helpers that you might want to implement atomically
+ * in asm sometime.
+ */
+#ifndef lbnMontMul_16
+/*
+ * Multiply "num1" by "num2", modulo "mod", all of length "len", and
+ * place the result in the high half of "prod".  "inv" is the inverse
+ * of the least-significant word of the modulus, modulo 2^16.
+ * This uses numbers in Montgomery form.  Reduce using "len" and "inv".
+ *
+ * This is implemented as a macro to win on compilers that don't do
+ * inlining, since it's so trivial.
+ */
+#define lbnMontMul_16(prod, n1, n2, mod, len, inv) \
+       (lbnMulX_16(prod, n1, n2, len), lbnMontReduce_16(prod, mod, len, inv))
+#endif /* !lbnMontMul_16 */
+
+#ifndef lbnMontSquare_16
+/*
+ * Square "num", modulo "mod", both of length "len", and place the result
+ * in the high half of "prod".  "inv" is the inverse of the least-significant
+ * word of the modulus, modulo 2^16.
+ * This uses numbers in Montgomery form.  Reduce using "len" and "inv".
+ *
+ * This is implemented as a macro to win on compilers that don't do
+ * inlining, since it's so trivial.
+ */
+#define lbnMontSquare_16(prod, n, mod, len, inv) \
+       (lbnSquare_16(prod, n, len), lbnMontReduce_16(prod, mod, len, inv))
+       
+#endif /* !lbnMontSquare_16 */
+
+/*
+ * Convert a number to Montgomery form - requires mlen + nlen words
+ * of memory in "n".
+ */
+void
+lbnToMont_16(BNWORD16 *n, unsigned nlen, BNWORD16 *mod, unsigned mlen)
+{
+       /* Move n up "mlen" words */
+       lbnCopy_16(BIGLITTLE(n-mlen,n+mlen), n, nlen);
+       lbnZero_16(n, mlen);
+       /* Do the division - dump the quotient in the high-order words */
+       (void)lbnDiv_16(BIGLITTLE(n-mlen,n+mlen), n, mlen+nlen, mod, mlen);
+}
+
+/*
+ * Convert from Montgomery form.  Montgomery reduction is all that is
+ * needed.
+ */
+void
+lbnFromMont_16(BNWORD16 *n, BNWORD16 *mod, unsigned len)
+{
+       /* Zero the high words of n */
+       lbnZero_16(BIGLITTLE(n-len,n+len), len);
+       lbnMontReduce_16(n, mod, len, lbnMontInv1_16(BIGLITTLE(mod[-1],mod[0])));
+       /* Move n down len words */
+       lbnCopy_16(n, BIGLITTLE(n-len,n+len), len);
+}
+
+/*
+ * The windowed exponentiation algorithm, precomputes a table of odd
+ * powers of n up to 2^k.  It takes 2^(k-1)-1 multiplies to compute
+ * the table, and (e-1)/(k+1) multiplies (on average) to perform the
+ * exponentiation.  To minimize the sum, k must vary with e.
+ * The optimal window sizes vary with the exponent length.  Here are
+ * some selected values and the boundary cases.
+ * (An underscore _ has been inserted into some of the numbers to ensure
+ * that magic strings like 16 do not appear in this table.  It should be
+ * ignored.)
+ *
+ * At e =    1 bits, k=1   (0.000000) is best.
+ * At e =    2 bits, k=1   (0.500000) is best.
+ * At e =    4 bits, k=1   (1.500000) is best.
+ * At e =    8 bits, k=2   (3.333333) < k=1   (3.500000)
+ * At e =  1_6 bits, k=2   (6.000000) is best.
+ * At e =   26 bits, k=3   (9.250000) < k=2   (9.333333)
+ * At e =  3_2 bits, k=3  (10.750000) is best.
+ * At e =  6_4 bits, k=3  (18.750000) is best.
+ * At e =   82 bits, k=4  (23.200000) < k=3  (23.250000)
+ * At e =  128 bits, k=4 (3_2.400000) is best.
+ * At e =  242 bits, k=5  (55.1_66667) < k=4 (55.200000)
+ * At e =  256 bits, k=5  (57.500000) is best.
+ * At e =  512 bits, k=5 (100.1_66667) is best.
+ * At e =  674 bits, k=6 (127.142857) < k=5 (127.1_66667)
+ * At e = 1024 bits, k=6 (177.142857) is best.
+ * At e = 1794 bits, k=7 (287.125000) < k=6 (287.142857)
+ * At e = 2048 bits, k=7 (318.875000) is best.
+ * At e = 4096 bits, k=7 (574.875000) is best.
+ *
+ * The numbers in parentheses are the expected number of multiplications
+ * needed to do the computation.  The normal russian-peasant modular
+ * exponentiation technique always uses (e-1)/2.  For exponents as
+ * small as 192 bits (below the range of current factoring algorithms),
+ * half of the multiplies are eliminated, 45.2 as opposed to the naive
+ * 95.5.  Counting the 191 squarings as 3/4 a multiply each (squaring
+ * proper is just over half of multiplying, but the Montgomery
+ * reduction in each case is also a multiply), that's 143.25
+ * multiplies, for totals of 188.45 vs. 238.75 - a 21% savings.
+ * For larger exponents (like 512 bits), it's 483.92 vs. 639.25, a
+ * 24.3% savings.  It asymptotically approaches 25%.
+ *
+ * Given that exponents for which k>7 are useful are uncommon,
+ * a fixed size table for k <= 7 is used for simplicity.
+ * k = 8 is uzeful at 4610 bits, k = 9 at 11522 bits.
+ *
+ * The basic number of squarings needed is e-1, although a k-bit
+ * window (for k > 1) can save, on average, k-2 of those, too.
+ * That savings currently isn't counted here.  It would drive the
+ * crossover points slightly lower.
+ * (Actually, this win is also reduced in the DoubleExpMod case,
+ * meaning we'd have to split the tables.  Except for that, the
+ * multiplies by powers of the two bases are independent, so
+ * the same logic applies to each as the single case.)
+ *
+ * Table entry i is the largest number of bits in an exponent to
+ * process with a window size of i+1.  So the window never goes above 7
+ * bits, requiring 2^(7-1) = 0x40 precomputed multiples.
+ */
+#define BNEXPMOD_MAX_WINDOW    7
+static unsigned const bnExpModThreshTable[BNEXPMOD_MAX_WINDOW] = {
+       7, 25, 81, 241, 673, 1793, (unsigned)-1
+};
+
+/*
+ * Perform modular exponentiation, as fast as possible!  This uses
+ * Montgomery reduction, optimized squaring, and windowed exponentiation.
+ * The modulus "mod" MUST be odd!
+ *
+ * This returns 0 on success, -1 on out of memory.
+ *
+ * The window algorithm:
+ * The idea is to keep a running product of b1 = n^(high-order bits of exp),
+ * and then keep appending exponent bits to it.  The following patterns
+ * apply to a 3-bit window (k = 3):
+ * To append   0: square
+ * To append   1: square, multiply by n^1
+ * To append  10: square, multiply by n^1, square
+ * To append  11: square, square, multiply by n^3
+ * To append 100: square, multiply by n^1, square, square
+ * To append 101: square, square, square, multiply by n^5
+ * To append 110: square, square, multiply by n^3, square
+ * To append 111: square, square, square, multiply by n^7
+ *
+ * Since each pattern involves only one multiply, the longer the pattern
+ * the better, except that a 0 (no multiplies) can be appended directly.
+ * We precompute a table of odd powers of n, up to 2^k, and can then
+ * multiply k bits of exponent at a time.  Actually, assuming random
+ * exponents, there is on average one zero bit between needs to
+ * multiply (1/2 of the time there's none, 1/4 of the time there's 1,
+ * 1/8 of the time, there's 2, 1/16 of the time, there's 3, etc.), so
+ * you have to do one multiply per k+1 bits of exponent.
+ *
+ * The loop walks down the exponent, squaring the result buffer as
+ * it goes.  There is a wbits+1 bit lookahead buffer, buf, that is
+ * filled with the upcoming exponent bits.  (What is read after the
+ * end of the exponent is unimportant, but it is filled with zero here.)
+ * When the most-significant bit of this buffer becomes set, i.e.
+ * (buf & tblmask) != 0, we have to decide what pattern to multiply
+ * by, and when to do it.  We decide, remember to do it in future
+ * after a suitable number of squarings have passed (e.g. a pattern
+ * of "100" in the buffer requires that we multiply by n^1 immediately;
+ * a pattern of "110" calls for multiplying by n^3 after one more
+ * squaring), clear the buffer, and continue.
+ *
+ * When we start, there is one more optimization: the result buffer
+ * is implcitly one, so squaring it or multiplying by it can be
+ * optimized away.  Further, if we start with a pattern like "100"
+ * in the lookahead window, rather than placing n into the buffer
+ * and then starting to square it, we have already computed n^2
+ * to compute the odd-powers table, so we can place that into
+ * the buffer and save a squaring.
+ *
+ * This means that if you have a k-bit window, to compute n^z,
+ * where z is the high k bits of the exponent, 1/2 of the time
+ * it requires no squarings.  1/4 of the time, it requires 1
+ * squaring, ... 1/2^(k-1) of the time, it reqires k-2 squarings.
+ * And the remaining 1/2^(k-1) of the time, the top k bits are a
+ * 1 followed by k-1 0 bits, so it again only requires k-2
+ * squarings, not k-1.  The average of these is 1.  Add that
+ * to the one squaring we have to do to compute the table,
+ * and you'll see that a k-bit window saves k-2 squarings
+ * as well as reducing the multiplies.  (It actually doesn't
+ * hurt in the case k = 1, either.)
+ *
+ * n must have mlen words allocated.  Although fewer may be in use
+ * when n is passed in, all are in use on exit.
+ */
+int
+lbnExpMod_16(BNWORD16 *result, BNWORD16 const *n, unsigned nlen,
+       BNWORD16 const *e, unsigned elen, BNWORD16 *mod, unsigned mlen)
+{
+       BNWORD16 *table[1 << (BNEXPMOD_MAX_WINDOW-1)];
+                               /* Table of odd powers of n */
+       unsigned ebits;         /* Exponent bits */
+       unsigned wbits;         /* Window size */
+       unsigned tblmask;       /* Mask of exponentiation window */
+       BNWORD16 bitpos;        /* Mask of current look-ahead bit */
+       unsigned buf;           /* Buffer of exponent bits */
+       unsigned multpos;       /* Where to do pending multiply */
+       BNWORD16 const *mult;   /* What to multiply by */
+       unsigned i;             /* Loop counter */
+       int isone;              /* Flag: accum. is implicitly one */
+       BNWORD16 *a, *b;        /* Working buffers/accumulators */
+       BNWORD16 *t;            /* Pointer into the working buffers */
+       BNWORD16 inv;           /* mod^-1 modulo 2^16 */
+
+       assert(mlen);
+       assert(nlen <= mlen);
+
+       /* First, a couple of trivial cases. */
+       elen = lbnNorm_16(e, elen);
+       if (!elen) {
+               /* x ^ 0 == 1 */
+               lbnZero_16(result, mlen);
+               BIGLITTLE(result[-1],result[0]) = 1;
+               return 0;
+       }
+       ebits = lbnBits_16(e, elen);
+       if (ebits == 1) {
+               /* x ^ 1 == x */
+               if (n != result)
+                       lbnCopy_16(result, n, nlen);
+               if (mlen > nlen)
+                       lbnZero_16(BIGLITTLE(result-nlen,result+nlen),
+                                  mlen-nlen);
+               return 0;
+       }
+
+       /* Okay, now move the exponent pointer to the most-significant word */
+       e = BIGLITTLE(e-elen, e+elen-1);
+
+       /* Look up appropriate k-1 for the exponent - tblmask = 1<<(k-1) */
+       wbits = 0;
+       while (ebits > bnExpModThreshTable[wbits])
+               wbits++;
+
+       /* Allocate working storage: two product buffers and the tables. */
+       LBNALLOC(a, 2*mlen);
+       if (!a)
+               return -1;
+       LBNALLOC(b, 2*mlen);
+       if (!b) {
+               LBNFREE(a, 2*mlen);
+               return -1;
+       }
+
+       /* Convert to the appropriate table size: tblmask = 1<<(k-1) */
+       tblmask = 1u << wbits;
+
+       /* We have the result buffer available, so use it. */
+       table[0] = result;
+
+       /*
+        * Okay, we now have a minimal-sized table - expand it.
+        * This is allowed to fail!  If so, scale back the table size
+        * and proceed.
+        */
+       for (i = 1; i < tblmask; i++) {
+               LBNALLOC(t, mlen);
+               if (!t) /* Out of memory!  Quit the loop. */
+                       break;
+               table[i] = t;
+       }
+
+       /* If we stopped, with i < tblmask, shrink the tables appropriately */
+       while (tblmask > i) {
+               wbits--;
+               tblmask >>= 1;
+       }
+       /* Free up our overallocations */
+       while (--i > tblmask)
+               LBNFREE(table[i], mlen);
+
+       /* Okay, fill in the table */
+
+       /* Compute the necessary modular inverse */
+       inv = lbnMontInv1_16(mod[BIGLITTLE(-1,0)]);     /* LSW of modulus */
+
+       /* Convert n to Montgomery form */
+
+       /* Move n up "mlen" words into a */
+       t = BIGLITTLE(a-mlen, a+mlen);
+       lbnCopy_16(t, n, nlen);
+       lbnZero_16(a, mlen);
+       /* Do the division - lose the quotient into the high-order words */
+       (void)lbnDiv_16(t, a, mlen+nlen, mod, mlen);
+       /* Copy into first table entry */
+       lbnCopy_16(table[0], a, mlen);
+
+       /* Square a into b */
+       lbnMontSquare_16(b, a, mod, mlen, inv);
+
+       /* Use high half of b to initialize the table */
+       t = BIGLITTLE(b-mlen, b+mlen);
+       for (i = 1; i < tblmask; i++) {
+               lbnMontMul_16(a, t, table[i-1], mod, mlen, inv);
+               lbnCopy_16(table[i], BIGLITTLE(a-mlen, a+mlen), mlen);
+       }
+
+       /* We might use b = n^2 later... */
+
+       /* Initialze the fetch pointer */
+       bitpos = (BNWORD16)1 << ((ebits-1) & (16-1));   /* Initialize mask */
+
+       /* This should point to the msbit of e */
+       assert((*e & bitpos) != 0);
+
+       /*
+        * Pre-load the window.  Becuase the window size is
+        * never larger than the exponent size, there is no need to
+        * detect running off the end of e in here.
+        *
+        * The read-ahead is controlled by elen and the bitpos mask.
+        * Note that this is *ahead* of ebits, which tracks the
+        * most significant end of the window.  The purpose of this
+        * initialization is to get the two wbits+1 bits apart,
+        * like they should be.
+        *
+        * Note that bitpos and e1len together keep track of the
+        * lookahead read pointer in the exponent that is used here.
+        */
+       buf = 0;
+       for (i = 0; i <= wbits; i++) {
+               buf = (buf << 1) | ((*e & bitpos) != 0);
+               bitpos >>= 1;
+               if (!bitpos) {
+                       BIGLITTLE(e++,e--);
+                       bitpos = (BNWORD16)1 << (16-1);
+                       elen--;
+               }
+       }
+       assert(buf & tblmask);
+
+       /*
+        * Set the pending multiply positions to a location that will
+        * never be encountered, thus ensuring that nothing will happen
+        * until the need for a multiply appears and one is scheduled.
+        */
+       multpos = ebits;        /* A NULL value */
+       mult = 0;       /* Force a crash if we use these */
+
+       /*
+        * Okay, now begins the real work.  The first step is
+        * slightly magic, so it's done outside the main loop,
+        * but it's very similar to what's inside.
+        */
+       ebits--;        /* Start processing the first bit... */
+       isone = 1;
+
+       /*
+        * This is just like the multiply in the loop, except that
+        * - We know the msbit of buf is set, and
+        * - We have the extra value n^2 floating around.
+        * So, do the usual computation, and if the result is that
+        * the buffer should be multiplied by n^1 immediately
+        * (which we'd normally then square), we multiply it
+        * (which reduces to a copy, which reduces to setting a flag)
+        * by n^2 and skip the squaring.  Thus, we do the
+        * multiply and the squaring in one step.
+        */
+       assert(buf & tblmask);
+       multpos = ebits - wbits;
+       while ((buf & 1) == 0) {
+               buf >>= 1;
+               multpos++;
+       }
+       /* Intermediates can wrap, but final must NOT */
+       assert(multpos <= ebits);
+       mult = table[buf>>1];
+       buf = 0;
+
+       /* Special case: use already-computed value sitting in buffer */
+       if (multpos == ebits)
+               isone = 0;
+
+       /*
+        * At this point, the buffer (which is the high half of b) holds
+        * either 1 (implicitly, as the "isone" flag is set), or n^2.
+        */
+
+       /*
+        * The main loop.  The procedure is:
+        * - Advance the window
+        * - If the most-significant bit of the window is set,
+        *   schedule a multiply for the appropriate time in the
+        *   future (may be immediately)
+        * - Perform any pending multiples
+        * - Check for termination
+        * - Square the buffer
+        *
+        * At any given time, the acumulated product is held in
+        * the high half of b.
+        */
+       for (;;) {
+               ebits--;
+
+               /* Advance the window */
+               assert(buf < tblmask);
+               buf <<= 1;
+               /*
+                * This reads ahead of the current exponent position
+                * (controlled by ebits), so we have to be able to read
+                * past the lsb of the exponents without error.
+                */
+               if (elen) {
+                       buf |= ((*e & bitpos) != 0);
+                       bitpos >>= 1;
+                       if (!bitpos) {
+                               BIGLITTLE(e++,e--);
+                               bitpos = (BNWORD16)1 << (16-1);
+                               elen--;
+                       }
+               }
+
+               /* Examine the window for pending multiplies */
+               if (buf & tblmask) {
+                       multpos = ebits - wbits;
+                       while ((buf & 1) == 0) {
+                               buf >>= 1;
+                               multpos++;
+                       }
+                       /* Intermediates can wrap, but final must NOT */
+                       assert(multpos <= ebits);
+                       mult = table[buf>>1];
+                       buf = 0;
+               }
+
+               /* If we have a pending multiply, do it */
+               if (ebits == multpos) {
+                       /* Multiply by the table entry remembered previously */
+                       t = BIGLITTLE(b-mlen, b+mlen);
+                       if (isone) {
+                               /* Multiply by 1 is a trivial case */
+                               lbnCopy_16(t, mult, mlen);
+                               isone = 0;
+                       } else {
+                               lbnMontMul_16(a, t, mult, mod, mlen, inv);
+                               /* Swap a and b */
+                               t = a; a = b; b = t;
+                       }
+               }
+
+               /* Are we done? */
+               if (!ebits)
+                       break;
+
+               /* Square the input */
+               if (!isone) {
+                       t = BIGLITTLE(b-mlen, b+mlen);
+                       lbnMontSquare_16(a, t, mod, mlen, inv);
+                       /* Swap a and b */
+                       t = a; a = b; b = t;
+               }
+       } /* for (;;) */
+
+       assert(!isone);
+       assert(!buf);
+
+       /* DONE! */
+
+       /* Convert result out of Montgomery form */
+       t = BIGLITTLE(b-mlen, b+mlen);
+       lbnCopy_16(b, t, mlen);
+       lbnZero_16(t, mlen);
+       lbnMontReduce_16(b, mod, mlen, inv);
+       lbnCopy_16(result, t, mlen);
+       /*
+        * Clean up - free intermediate storage.
+        * Do NOT free table[0], which is the result
+        * buffer.
+        */
+       while (--tblmask)
+               LBNFREE(table[tblmask], mlen);
+       LBNFREE(b, 2*mlen);
+       LBNFREE(a, 2*mlen);
+
+       return 0;       /* Success */
+}
+
+/*
+ * Compute and return n1^e1 * n2^e2 mod "mod".
+ * result may be either input buffer, or something separate.
+ * It must be "mlen" words long.
+ *
+ * There is a current position in the exponents, which is kept in e1bits.
+ * (The exponents are swapped if necessary so e1 is the longer of the two.)
+ * At any given time, the value in the accumulator is
+ * n1^(e1>>e1bits) * n2^(e2>>e1bits) mod "mod".
+ * As e1bits is counted down, this is updated, by squaring it and doing
+ * any necessary multiplies.
+ * To decide on the necessary multiplies, two windows, each w1bits+1 bits
+ * wide, are maintained in buf1 and buf2, which read *ahead* of the
+ * e1bits position (with appropriate handling of the case when e1bits
+ * drops below w1bits+1).  When the most-significant bit of either window
+ * becomes set, indicating that something needs to be multiplied by
+ * the accumulator or it will get out of sync, the window is examined
+ * to see which power of n1 or n2 to multiply by, and when (possibly
+ * later, if the power is greater than 1) the multiply should take
+ * place.  Then the multiply and its location are remembered and the
+ * window is cleared.
+ *
+ * If we had every power of n1 in the table, the multiply would always
+ * be w1bits steps in the future.  But we only keep the odd powers,
+ * so instead of waiting w1bits squarings and then multiplying
+ * by n1^k, we wait w1bits-k squarings and multiply by n1.
+ *
+ * Actually, w2bits can be less than w1bits, but the window is the same
+ * size, to make it easier to keep track of where we're reading.  The
+ * appropriate number of low-order bits of the window are just ignored.
+ */
+int
+lbnDoubleExpMod_16(BNWORD16 *result,
+                   BNWORD16 const *n1, unsigned n1len,
+                   BNWORD16 const *e1, unsigned e1len,
+                   BNWORD16 const *n2, unsigned n2len,
+                   BNWORD16 const *e2, unsigned e2len,
+                   BNWORD16 *mod, unsigned mlen)
+{
+       BNWORD16 *table1[1 << (BNEXPMOD_MAX_WINDOW-1)];
+                                       /* Table of odd powers of n1 */
+       BNWORD16 *table2[1 << (BNEXPMOD_MAX_WINDOW-1)];
+                                       /* Table of odd powers of n2 */
+       unsigned e1bits, e2bits;        /* Exponent bits */
+       unsigned w1bits, w2bits;        /* Window sizes */
+       unsigned tblmask;               /* Mask of exponentiation window */
+       BNWORD16 bitpos;                /* Mask of current look-ahead bit */
+       unsigned buf1, buf2;            /* Buffer of exponent bits */
+       unsigned mult1pos, mult2pos;    /* Where to do pending multiply */
+       BNWORD16 const *mult1, *mult2;  /* What to multiply by */
+       unsigned i;                     /* Loop counter */
+       int isone;                      /* Flag: accum. is implicitly one */
+       BNWORD16 *a, *b;                /* Working buffers/accumulators */
+       const BNWORD16 *ct;             /* Temp pointer */
+       BNWORD16 *t;                    /* Pointer into the working buffers */
+       BNWORD16 inv;                   /* mod^-1 modulo 2^16 */
+
+       assert(mlen);
+       assert(n1len <= mlen);
+       assert(n2len <= mlen);
+
+       /* First, a couple of trivial cases. */
+       e1len = lbnNorm_16(e1, e1len);
+       e2len = lbnNorm_16(e2, e2len);
+
+       /* Ensure that the first exponent is the longer */
+       e1bits = lbnBits_16(e1, e1len);
+       e2bits = lbnBits_16(e2, e2len);
+       if (e1bits < e2bits) {
+               i = e1len; e1len = e2len; e2len = i;
+               i = e1bits; e1bits = e2bits; e2bits = i;
+               ct = (const BNWORD16 *)n1; n1 = n2; n2 = ct; 
+               ct = (const BNWORD16 *)e1; e1 = e2; e2 = ct; 
+       }
+       assert(e1bits >= e2bits);
+
+       /* Handle a trivial case */
+       if (!e2len)
+               return lbnExpMod_16(result, n1, n1len, e1, e1len, mod, mlen);
+       assert(e2bits);
+
+       /* The code below breaks if the exponents aren't at least 2 bits */
+       if (e1bits == 1) {
+               assert(e2bits == 1);
+
+               LBNALLOC(a, n1len+n2len);
+               if (!a)
+                       return -1;
+
+               lbnMul_16(a, n1, n1len, n2, n2len);
+               /* Do a direct modular reduction */
+               if (n1len + n2len >= mlen)
+                       (void)lbnDiv_16(a+mlen, a, n1len+n2len, mod, mlen);
+               lbnCopy_16(result, a, mlen);
+               LBNFREE(a, n1len+n2len);
+               return 0;
+       }
+
+       /* Okay, now move the exponent pointers to the most-significant word */
+       e1 = BIGLITTLE(e1-e1len, e1+e1len-1);
+       e2 = BIGLITTLE(e2-e2len, e2+e2len-1);
+
+       /* Look up appropriate k-1 for the exponent - tblmask = 1<<(k-1) */
+       w1bits = 0;
+       while (e1bits > bnExpModThreshTable[w1bits])
+               w1bits++;
+       w2bits = 0;
+       while (e2bits > bnExpModThreshTable[w2bits])
+               w2bits++;
+
+       assert(w1bits >= w2bits);
+
+       /* Allocate working storage: two product buffers and the tables. */
+       LBNALLOC(a, 2*mlen);
+       if (!a)
+               return -1;
+       LBNALLOC(b, 2*mlen);
+       if (!b) {
+               LBNFREE(a, 2*mlen);
+               return -1;
+       }
+
+       /* Convert to the appropriate table size: tblmask = 1<<(k-1) */
+       tblmask = 1u << w1bits;
+       /* Use buf2 for its size, temporarily */
+       buf2 = 1u << w2bits;
+
+       LBNALLOC(t, mlen);
+       if (!t) {
+               LBNFREE(b, 2*mlen);
+               LBNFREE(a, 2*mlen);
+               return -1;
+       }
+       table1[0] = t;
+       table2[0] = result;
+
+       /*
+        * Okay, we now have some minimal-sized tables - expand them.
+        * This is allowed to fail!  If so, scale back the table sizes
+        * and proceed.  We allocate both tables at the same time
+        * so if it fails partway through, they'll both be a reasonable
+        * size rather than one huge and one tiny.
+        * When i passes buf2 (the number of entries in the e2 window,
+        * which may be less than the number of entries in the e1 window),
+        * stop allocating e2 space.
+        */
+       for (i = 1; i < tblmask; i++) {
+               LBNALLOC(t, mlen);
+               if (!t) /* Out of memory!  Quit the loop. */
+                       break;
+               table1[i] = t;
+               if (i < buf2) {
+                       LBNALLOC(t, mlen);
+                       if (!t) {
+                               LBNFREE(table1[i], mlen);
+                               break;
+                       }
+                       table2[i] = t;
+               }
+       }
+
+       /* If we stopped, with i < tblmask, shrink the tables appropriately */
+       while (tblmask > i) {
+               w1bits--;
+               tblmask >>= 1;
+       }
+       /* Free up our overallocations */
+       while (--i > tblmask) {
+               if (i < buf2)
+                       LBNFREE(table2[i], mlen);
+               LBNFREE(table1[i], mlen);
+       }
+       /* And shrink the second window too, if needed */
+       if (w2bits > w1bits) {
+               w2bits = w1bits;
+               buf2 = tblmask;
+       }
+
+       /*
+        * From now on, use the w2bits variable for the difference
+        * between w1bits and w2bits.
+        */
+       w2bits = w1bits-w2bits;
+
+       /* Okay, fill in the tables */
+
+       /* Compute the necessary modular inverse */
+       inv = lbnMontInv1_16(mod[BIGLITTLE(-1,0)]);     /* LSW of modulus */
+
+       /* Convert n1 to Montgomery form */
+
+       /* Move n1 up "mlen" words into a */
+       t = BIGLITTLE(a-mlen, a+mlen);
+       lbnCopy_16(t, n1, n1len);
+       lbnZero_16(a, mlen);
+       /* Do the division - lose the quotient into the high-order words */
+       (void)lbnDiv_16(t, a, mlen+n1len, mod, mlen);
+       /* Copy into first table entry */
+       lbnCopy_16(table1[0], a, mlen);
+
+       /* Square a into b */
+       lbnMontSquare_16(b, a, mod, mlen, inv);
+
+       /* Use high half of b to initialize the first table */
+       t = BIGLITTLE(b-mlen, b+mlen);
+       for (i = 1; i < tblmask; i++) {
+               lbnMontMul_16(a, t, table1[i-1], mod, mlen, inv);
+               lbnCopy_16(table1[i], BIGLITTLE(a-mlen, a+mlen), mlen);
+       }
+
+       /* Convert n2 to Montgomery form */
+
+       t = BIGLITTLE(a-mlen, a+mlen);
+       /* Move n2 up "mlen" words into a */
+       lbnCopy_16(t, n2, n2len);
+       lbnZero_16(a, mlen);
+       /* Do the division - lose the quotient into the high-order words */
+       (void)lbnDiv_16(t, a, mlen+n2len, mod, mlen);
+       /* Copy into first table entry */
+       lbnCopy_16(table2[0], a, mlen);
+
+       /* Square it into a */
+       lbnMontSquare_16(a, table2[0], mod, mlen, inv);
+       /* Copy to b, low half */
+       lbnCopy_16(b, t, mlen);
+
+       /* Use b to initialize the second table */
+       for (i = 1; i < buf2; i++) {
+               lbnMontMul_16(a, b, table2[i-1], mod, mlen, inv);
+               lbnCopy_16(table2[i], t, mlen);
+       }
+
+       /*
+        * Okay, a recap: at this point, the low part of b holds
+        * n2^2, the high part holds n1^2, and the tables are
+        * initialized with the odd powers of n1 and n2 from 1
+        * through 2*tblmask-1 and 2*buf2-1.
+        *
+        * We might use those squares in b later, or we might not.
+        */
+
+       /* Initialze the fetch pointer */
+       bitpos = (BNWORD16)1 << ((e1bits-1) & (16-1));  /* Initialize mask */
+
+       /* This should point to the msbit of e1 */
+       assert((*e1 & bitpos) != 0);
+
+       /*
+        * Pre-load the windows.  Becuase the window size is
+        * never larger than the exponent size, there is no need to
+        * detect running off the end of e1 in here.
+        *
+        * The read-ahead is controlled by e1len and the bitpos mask.
+        * Note that this is *ahead* of e1bits, which tracks the
+        * most significant end of the window.  The purpose of this
+        * initialization is to get the two w1bits+1 bits apart,
+        * like they should be.
+        *
+        * Note that bitpos and e1len together keep track of the
+        * lookahead read pointer in the exponent that is used here.
+        * e2len is not decremented, it is only ever compared with
+        * e1len as *that* is decremented.
+        */
+       buf1 = buf2 = 0;
+       for (i = 0; i <= w1bits; i++) {
+               buf1 = (buf1 << 1) | ((*e1 & bitpos) != 0);
+               if (e1len <= e2len)
+                       buf2 = (buf2 << 1) | ((*e2 & bitpos) != 0);
+               bitpos >>= 1;
+               if (!bitpos) {
+                       BIGLITTLE(e1++,e1--);
+                       if (e1len <= e2len)
+                               BIGLITTLE(e2++,e2--);
+                       bitpos = (BNWORD16)1 << (16-1);
+                       e1len--;
+               }
+       }
+       assert(buf1 & tblmask);
+
+       /*
+        * Set the pending multiply positions to a location that will
+        * never be encountered, thus ensuring that nothing will happen
+        * until the need for a multiply appears and one is scheduled.
+        */
+       mult1pos = mult2pos = e1bits;   /* A NULL value */
+       mult1 = mult2 = 0;      /* Force a crash if we use these */
+
+       /*
+        * Okay, now begins the real work.  The first step is
+        * slightly magic, so it's done outside the main loop,
+        * but it's very similar to what's inside.
+        */
+       isone = 1;      /* Buffer is implicitly 1, so replace * by copy */
+       e1bits--;       /* Start processing the first bit... */
+
+       /*
+        * This is just like the multiply in the loop, except that
+        * - We know the msbit of buf1 is set, and
+        * - We have the extra value n1^2 floating around.
+        * So, do the usual computation, and if the result is that
+        * the buffer should be multiplied by n1^1 immediately
+        * (which we'd normally then square), we multiply it
+        * (which reduces to a copy, which reduces to setting a flag)
+        * by n1^2 and skip the squaring.  Thus, we do the
+        * multiply and the squaring in one step.
+        */
+       assert(buf1 & tblmask);
+       mult1pos = e1bits - w1bits;
+       while ((buf1 & 1) == 0) {
+               buf1 >>= 1;
+               mult1pos++;
+       }
+       /* Intermediates can wrap, but final must NOT */
+       assert(mult1pos <= e1bits);
+       mult1 = table1[buf1>>1];
+       buf1 = 0;
+
+       /* Special case: use already-computed value sitting in buffer */
+       if (mult1pos == e1bits)
+               isone = 0;
+
+       /*
+        * The first multiply by a power of n2.  Similar, but
+        * we might not even want to schedule a multiply if e2 is
+        * shorter than e1, and the window might be shorter so
+        * we have to leave the low w2bits bits alone.
+        */
+       if (buf2 & tblmask) {
+               /* Remember low-order bits for later */
+               i = buf2 & ((1u << w2bits) - 1);
+               buf2 >>= w2bits;
+               mult2pos = e1bits - w1bits + w2bits;
+               while ((buf2 & 1) == 0) {
+                       buf2 >>= 1;
+                       mult2pos++;
+               }
+               assert(mult2pos <= e1bits);
+               mult2 = table2[buf2>>1];
+               buf2 = i;
+
+               if (mult2pos == e1bits) {
+                       t = BIGLITTLE(b-mlen, b+mlen);
+                       if (isone) {
+                               lbnCopy_16(t, b, mlen); /* Copy low to high */
+                               isone = 0;
+                       } else {
+                               lbnMontMul_16(a, t, b, mod, mlen, inv);
+                               t = a; a = b; b = t;
+                       }
+               }
+       }
+
+       /*
+        * At this point, the buffer (which is the high half of b)
+        * holds either 1 (implicitly, as the "isone" flag is set),
+        * n1^2, n2^2 or n1^2 * n2^2.
+        */
+
+       /*
+        * The main loop.  The procedure is:
+        * - Advance the windows
+        * - If the most-significant bit of a window is set,
+        *   schedule a multiply for the appropriate time in the
+        *   future (may be immediately)
+        * - Perform any pending multiples
+        * - Check for termination
+        * - Square the buffers
+        *
+        * At any given time, the acumulated product is held in
+        * the high half of b.
+        */
+       for (;;) {
+               e1bits--;
+
+               /* Advance the windows */
+               assert(buf1 < tblmask);
+               buf1 <<= 1;
+               assert(buf2 < tblmask);
+               buf2 <<= 1;
+               /*
+                * This reads ahead of the current exponent position
+                * (controlled by e1bits), so we have to be able to read
+                * past the lsb of the exponents without error.
+                */
+               if (e1len) {
+                       buf1 |= ((*e1 & bitpos) != 0);
+                       if (e1len <= e2len)
+                               buf2 |= ((*e2 & bitpos) != 0);
+                       bitpos >>= 1;
+                       if (!bitpos) {
+                               BIGLITTLE(e1++,e1--);
+                               if (e1len <= e2len)
+                                       BIGLITTLE(e2++,e2--);
+                               bitpos = (BNWORD16)1 << (16-1);
+                               e1len--;
+                       }
+               }
+
+               /* Examine the first window for pending multiplies */
+               if (buf1 & tblmask) {
+                       mult1pos = e1bits - w1bits;
+                       while ((buf1 & 1) == 0) {
+                               buf1 >>= 1;
+                               mult1pos++;
+                       }
+                       /* Intermediates can wrap, but final must NOT */
+                       assert(mult1pos <= e1bits);
+                       mult1 = table1[buf1>>1];
+                       buf1 = 0;
+               }
+
+               /*
+                * Examine the second window for pending multiplies.
+                * Window 2 can be smaller than window 1, but we
+                * keep the same number of bits in buf2, so we need
+                * to ignore any low-order bits in the buffer when
+                * computing what to multiply by, and recompute them
+                * later.
+                */
+               if (buf2 & tblmask) {
+                       /* Remember low-order bits for later */
+                       i = buf2 & ((1u << w2bits) - 1);
+                       buf2 >>= w2bits;
+                       mult2pos = e1bits - w1bits + w2bits;
+                       while ((buf2 & 1) == 0) {
+                               buf2 >>= 1;
+                               mult2pos++;
+                       }
+                       assert(mult2pos <= e1bits);
+                       mult2 = table2[buf2>>1];
+                       buf2 = i;
+               }
+
+
+               /* If we have a pending multiply for e1, do it */
+               if (e1bits == mult1pos) {
+                       /* Multiply by the table entry remembered previously */
+                       t = BIGLITTLE(b-mlen, b+mlen);
+                       if (isone) {
+                               /* Multiply by 1 is a trivial case */
+                               lbnCopy_16(t, mult1, mlen);
+                               isone = 0;
+                       } else {
+                               lbnMontMul_16(a, t, mult1, mod, mlen, inv);
+                               /* Swap a and b */
+                               t = a; a = b; b = t;
+                       }
+               }
+
+               /* If we have a pending multiply for e2, do it */
+               if (e1bits == mult2pos) {
+                       /* Multiply by the table entry remembered previously */
+                       t = BIGLITTLE(b-mlen, b+mlen);
+                       if (isone) {
+                               /* Multiply by 1 is a trivial case */
+                               lbnCopy_16(t, mult2, mlen);
+                               isone = 0;
+                       } else {
+                               lbnMontMul_16(a, t, mult2, mod, mlen, inv);
+                               /* Swap a and b */
+                               t = a; a = b; b = t;
+                       }
+               }
+
+               /* Are we done? */
+               if (!e1bits)
+                       break;
+
+               /* Square the buffer */
+               if (!isone) {
+                       t = BIGLITTLE(b-mlen, b+mlen);
+                       lbnMontSquare_16(a, t, mod, mlen, inv);
+                       /* Swap a and b */
+                       t = a; a = b; b = t;
+               }
+       } /* for (;;) */
+
+       assert(!isone);
+       assert(!buf1);
+       assert(!buf2);
+
+       /* DONE! */
+
+       /* Convert result out of Montgomery form */
+       t = BIGLITTLE(b-mlen, b+mlen);
+       lbnCopy_16(b, t, mlen);
+       lbnZero_16(t, mlen);
+       lbnMontReduce_16(b, mod, mlen, inv);
+       lbnCopy_16(result, t, mlen);
+
+       /* Clean up - free intermediate storage */
+       buf2 = tblmask >> w2bits;
+       while (--tblmask) {
+               if (tblmask < buf2)
+                       LBNFREE(table2[tblmask], mlen);
+               LBNFREE(table1[tblmask], mlen);
+       }
+       t = table1[0];
+       LBNFREE(t, mlen);
+       LBNFREE(b, 2*mlen);
+       LBNFREE(a, 2*mlen);
+
+       return 0;       /* Success */
+}
+
+/*
+ * 2^exp (mod mod).  This is an optimized version for use in Fermat
+ * tests.  The input value of n is ignored; it is returned with
+ * "mlen" words valid.
+ */
+int
+lbnTwoExpMod_16(BNWORD16 *n, BNWORD16 const *exp, unsigned elen,
+       BNWORD16 *mod, unsigned mlen)
+{
+       unsigned e;     /* Copy of high words of the exponent */
+       unsigned bits;  /* Assorted counter of bits */
+       BNWORD16 const *bitptr;
+       BNWORD16 bitword, bitpos;
+       BNWORD16 *a, *b, *a1;
+       BNWORD16 inv;
+
+       assert(mlen);
+
+       bitptr = BIGLITTLE(exp-elen, exp+elen-1);
+       bitword = *bitptr;
+       assert(bitword);
+
+       /* Clear n for future use. */
+       lbnZero_16(n, mlen);
+
+       bits = lbnBits_16(exp, elen);
+       
+       /* First, a couple of trivial cases. */
+       if (bits <= 1) {
+               /* 2 ^ 0 == 1,  2 ^ 1 == 2 */
+               BIGLITTLE(n[-1],n[0]) = (BNWORD16)1<<elen;
+               return 0;
+       }
+
+       /* Set bitpos to the most significant bit */
+       bitpos = (BNWORD16)1 << ((bits-1) & (16-1));
+
+       /* Now, count the bits in the modulus. */
+       bits = lbnBits_16(mod, mlen);
+       assert(bits > 1);       /* a 1-bit modulus is just stupid... */
+
+       /*
+        * We start with 1<<e, where "e" is as many high bits of the
+        * exponent as we can manage without going over the modulus.
+        * This first loop finds "e".
+        */
+       e = 1;
+       while (elen) {
+               /* Consume the first bit */
+               bitpos >>= 1;
+               if (!bitpos) {
+                       if (!--elen)
+                               break;
+                       bitword = BIGLITTLE(*++bitptr,*--bitptr);
+                       bitpos = (BNWORD16)1<<(16-1);
+               }
+               e = (e << 1) | ((bitpos & bitword) != 0);
+               if (e >= bits) {        /* Overflow!  Back out. */
+                       e >>= 1;
+                       break;
+               }
+       }
+       /*
+        * The bit in "bitpos" being examined by the bit buffer has NOT
+        * been consumed yet.  This may be past the end of the exponent,
+        * in which case elen == 1.
+        */
+
+       /* Okay, now, set bit "e" in n.  n is already zero. */
+       inv = (BNWORD16)1 << (e & (16-1));
+       e /= 16;
+       BIGLITTLE(n[-e-1],n[e]) = inv;
+       /*
+        * The effective length of n in words is now "e+1".
+        * This is used a little bit later.
+        */
+
+       if (!elen)
+               return 0;       /* That was easy! */
+
+       /*
+        * We have now processed the first few bits.  The next step
+        * is to convert this to Montgomery form for further squaring.
+        */
+
+       /* Allocate working storage: two product buffers */
+       LBNALLOC(a, 2*mlen);
+       if (!a)
+               return -1;
+       LBNALLOC(b, 2*mlen);
+       if (!b) {
+               LBNFREE(a, 2*mlen);
+               return -1;
+       }
+
+       /* Convert n to Montgomery form */
+       inv = BIGLITTLE(mod[-1],mod[0]);        /* LSW of modulus */
+       assert(inv & 1);        /* Modulus must be odd */
+       inv = lbnMontInv1_16(inv);
+       /* Move n (length e+1, remember?) up "mlen" words into b */
+       /* Note that we lie about a1 for a bit - it's pointing to b */
+       a1 = BIGLITTLE(b-mlen,b+mlen);
+       lbnCopy_16(a1, n, e+1);
+       lbnZero_16(b, mlen);
+       /* Do the division - dump the quotient into the high-order words */
+       (void)lbnDiv_16(a1, b, mlen+e+1, mod, mlen);
+       /*
+        * Now do the first squaring and modular reduction to put
+        * the number up in a1 where it belongs.
+        */
+       lbnMontSquare_16(a, b, mod, mlen, inv);
+       /* Fix up a1 to point to where it should go. */
+       a1 = BIGLITTLE(a-mlen,a+mlen);
+
+       /*
+        * Okay, now, a1 holds the number being accumulated, and
+        * b is a scratch register.  Start working:
+        */
+       for (;;) {
+               /*
+                * Is the bit set?  If so, double a1 as well.
+                * A modular doubling like this is very cheap.
+                */
+               if (bitpos & bitword) {
+                       /*
+                        * Double the number.  If there was a carry out OR
+                        * the result is greater than the modulus, subract
+                        * the modulus.
+                        */
+                       if (lbnDouble_16(a1, mlen) ||
+                           lbnCmp_16(a1, mod, mlen) > 0)
+                               (void)lbnSubN_16(a1, mod, mlen);
+               }
+
+               /* Advance to the next exponent bit */
+               bitpos >>= 1;
+               if (!bitpos) {
+                       if (!--elen)
+                               break;  /* Done! */
+                       bitword = BIGLITTLE(*++bitptr,*--bitptr);
+                       bitpos = (BNWORD16)1<<(16-1);
+               }
+
+               /*
+                * The elen/bitword/bitpos bit buffer is known to be
+                * non-empty, i.e. there is at least one more unconsumed bit.
+                * Thus, it's safe to square the number.
+                */
+               lbnMontSquare_16(b, a1, mod, mlen, inv);
+               /* Rename result (in b) back to a (a1, really). */
+               a1 = b; b = a; a = a1;
+               a1 = BIGLITTLE(a-mlen,a+mlen);
+       }
+
+       /* DONE!  Just a little bit of cleanup... */
+
+       /*
+        * Convert result out of Montgomery form... this is
+        * just a Montgomery reduction.
+        */
+       lbnCopy_16(a, a1, mlen);
+       lbnZero_16(a1, mlen);
+       lbnMontReduce_16(a, mod, mlen, inv);
+       lbnCopy_16(n, a1, mlen);
+
+       /* Clean up - free intermediate storage */
+       LBNFREE(b, 2*mlen);
+       LBNFREE(a, 2*mlen);
+
+       return 0;       /* Success */
+}
+
+
+/*
+ * Returns a substring of the big-endian array of bytes representation
+ * of the bignum array based on two parameters, the least significant
+ * byte number (0 to start with the least significant byte) and the
+ * length.  I.e. the number returned is a representation of
+ * (bn / 2^(8*lsbyte)) % 2 ^ (8*buflen).
+ *
+ * It is an error if the bignum is not at least buflen + lsbyte bytes
+ * long.
+ *
+ * This code assumes that the compiler has the minimal intelligence 
+ * neded to optimize divides and modulo operations on an unsigned data
+ * type with a power of two.
+ */
+void
+lbnExtractBigBytes_16(BNWORD16 const *n, unsigned char *buf,
+       unsigned lsbyte, unsigned buflen)
+{
+       BNWORD16 t = 0; /* Needed to shut up uninitialized var warnings */
+       unsigned shift;
+
+       lsbyte += buflen;
+
+       shift = (8 * lsbyte) % 16;
+       lsbyte /= (16/8);       /* Convert to word offset */
+       BIGLITTLE(n -= lsbyte, n += lsbyte);
+
+       if (shift)
+               t = BIGLITTLE(n[-1],n[0]);
+
+       while (buflen--) {
+               if (!shift) {
+                       t = BIGLITTLE(*n++,*--n);
+                       shift = 16;
+               }
+               shift -= 8;
+               *buf++ = (unsigned char)(t>>shift);
+       }
+}
+
+/*
+ * Merge a big-endian array of bytes into a bignum array.
+ * The array had better be big enough.  This is
+ * equivalent to extracting the entire bignum into a
+ * large byte array, copying the input buffer into the
+ * middle of it, and converting back to a bignum.
+ *
+ * The buf is "len" bytes long, and its *last* byte is at
+ * position "lsbyte" from the end of the bignum.
+ *
+ * Note that this is a pain to get right.  Fortunately, it's hardly
+ * critical for efficiency.
+ */
+void
+lbnInsertBigBytes_16(BNWORD16 *n, unsigned char const *buf,
+                  unsigned lsbyte,  unsigned buflen)
+{
+       BNWORD16 t = 0; /* Shut up uninitialized varibale warnings */
+
+       lsbyte += buflen;
+
+       BIGLITTLE(n -= lsbyte/(16/8), n += lsbyte/(16/8));
+
+       /* Load up leading odd bytes */
+       if (lsbyte % (16/8)) {
+               t = BIGLITTLE(*--n,*n++);
+               t >>= (lsbyte * 8) % 16;
+       }
+
+       /* The main loop - merge into t, storing at each word boundary. */
+       while (buflen--) {
+               t = (t << 8) | *buf++;
+               if ((--lsbyte % (16/8)) == 0)
+                       BIGLITTLE(*n++,*--n) = t;
+       }
+
+       /* Merge odd bytes in t into last word */
+       lsbyte = (lsbyte * 8) % 16;
+       if (lsbyte) {
+               t <<= lsbyte;
+               t |= (((BNWORD16)1 << lsbyte) - 1) & BIGLITTLE(n[0],n[-1]);
+               BIGLITTLE(n[0],n[-1]) = t;
+       }
+
+       return;
+}
+
+/*
+ * Returns a substring of the little-endian array of bytes representation
+ * of the bignum array based on two parameters, the least significant
+ * byte number (0 to start with the least significant byte) and the
+ * length.  I.e. the number returned is a representation of
+ * (bn / 2^(8*lsbyte)) % 2 ^ (8*buflen).
+ *
+ * It is an error if the bignum is not at least buflen + lsbyte bytes
+ * long.
+ *
+ * This code assumes that the compiler has the minimal intelligence 
+ * neded to optimize divides and modulo operations on an unsigned data
+ * type with a power of two.
+ */
+void
+lbnExtractLittleBytes_16(BNWORD16 const *n, unsigned char *buf,
+       unsigned lsbyte, unsigned buflen)
+{
+       BNWORD16 t = 0; /* Needed to shut up uninitialized var warnings */
+
+       BIGLITTLE(n -= lsbyte/(16/8), n += lsbyte/(16/8));
+
+       if (lsbyte % (16/8)) {
+               t = BIGLITTLE(*--n,*n++);
+               t >>= (lsbyte % (16/8)) * 8 ;
+       }
+
+       while (buflen--) {
+               if ((lsbyte++ % (16/8)) == 0)
+                       t = BIGLITTLE(*--n,*n++);
+               *buf++ = (unsigned char)t;
+               t >>= 8;
+       }
+}
+
+/*
+ * Merge a little-endian array of bytes into a bignum array.
+ * The array had better be big enough.  This is
+ * equivalent to extracting the entire bignum into a
+ * large byte array, copying the input buffer into the
+ * middle of it, and converting back to a bignum.
+ *
+ * The buf is "len" bytes long, and its first byte is at
+ * position "lsbyte" from the end of the bignum.
+ *
+ * Note that this is a pain to get right.  Fortunately, it's hardly
+ * critical for efficiency.
+ */
+void
+lbnInsertLittleBytes_16(BNWORD16 *n, unsigned char const *buf,
+                  unsigned lsbyte,  unsigned buflen)
+{
+       BNWORD16 t = 0; /* Shut up uninitialized varibale warnings */
+
+       /* Move to most-significant end */
+       lsbyte += buflen;
+       buf += buflen;
+
+       BIGLITTLE(n -= lsbyte/(16/8), n += lsbyte/(16/8));
+
+       /* Load up leading odd bytes */
+       if (lsbyte % (16/8)) {
+               t = BIGLITTLE(*--n,*n++);
+               t >>= (lsbyte * 8) % 16;
+       }
+
+       /* The main loop - merge into t, storing at each word boundary. */
+       while (buflen--) {
+               t = (t << 8) | *--buf;
+               if ((--lsbyte % (16/8)) == 0)
+                       BIGLITTLE(*n++,*--n) = t;
+       }
+
+       /* Merge odd bytes in t into last word */
+       lsbyte = (lsbyte * 8) % 16;
+       if (lsbyte) {
+               t <<= lsbyte;
+               t |= (((BNWORD16)1 << lsbyte) - 1) & BIGLITTLE(n[0],n[-1]);
+               BIGLITTLE(n[0],n[-1]) = t;
+       }
+
+       return;
+}
+
+#ifdef DEADCODE        /* This was a precursor to the more flexible lbnExtractBytes */
+/*
+ * Convert a big-endian array of bytes to a bignum.
+ * Returns the number of words in the bignum.
+ * Note the expression "16/8" for the number of bytes per word.
+ * This is so the word-size adjustment will work.
+ */
+unsigned
+lbnFromBytes_16(BNWORD16 *a, unsigned char const *b, unsigned blen)
+{
+       BNWORD16 t;
+       unsigned alen = (blen + (16/8-1))/(16/8);
+       BIGLITTLE(a -= alen, a += alen);
+
+       while (blen) {
+               t = 0;
+               do {
+                       t = t << 8 | *b++;
+               } while (--blen & (16/8-1));
+               BIGLITTLE(*a++,*--a) = t;
+       }
+       return alen;
+}
+#endif
+
+/*
+ * Computes the GCD of a and b.  Modifies both arguments;
+ * when it returns, one of them is the GCD and the other is trash.
+ * The return value is the length of the GCD, with the sign telling
+ * whether it is in a (+ve) or b (-ve).  Both inputs must have
+ * one extra word of precision.  alen must be >= blen.
+ *
+ * TODO: use the binary algorithm (Knuth section 4.5.2, algorithm B).
+ * This is based on taking out common powers of 2, then repeatedly:
+ * gcd(2*u,v) = gcd(u,2*v) = gcd(u,v) - isolated powers of 2 can be deleted.
+ * gcd(u,v) = gcd(u-v,v) - the numbers can be easily reduced.
+ * It gets less reduction per step, but the steps are much faster than
+ * the division case.
+ */
+int
+lbnGcd_16(BNWORD16 *a, unsigned alen, BNWORD16 *b, unsigned blen)
+{
+       assert(alen >= blen);
+
+       while (blen != 0) {
+               (void)lbnDiv_16(BIGLITTLE(a-blen,a+blen), a, alen, b, blen);
+               alen = lbnNorm_16(a, blen);
+               if (alen == 0)
+                       return -(int)blen;
+               (void)lbnDiv_16(BIGLITTLE(b-alen,b+alen), b, blen, a, alen);
+               blen = lbnNorm_16(b, alen);
+       }
+       return alen;
+}
+
+/*
+ * Invert "a" modulo "mod" using the extended Euclidean algorithm.
+ * Note that this only computes one of the cosequences, and uses the
+ * theorem that the signs flip every step and the absolute value of
+ * the cosequence values are always bounded by the modulus to avoid
+ * having to work with negative numbers.
+ * gcd(a,mod) had better equal 1.  Returns 1 if the GCD is NOT 1.
+ * a must be one word longer than "mod".  It is overwritten with the
+ * result.
+ * TODO: Use Richard Schroeppel's *much* faster algorithm.
+ */
+int
+lbnInv_16(BNWORD16 *a, unsigned alen, BNWORD16 const *mod, unsigned mlen)
+{
+       BNWORD16 *b;    /* Hold a copy of mod during GCD reduction */
+       BNWORD16 *p;    /* Temporary for products added to t0 and t1 */
+       BNWORD16 *t0, *t1;      /* Inverse accumulators */
+       BNWORD16 cy;
+       unsigned blen, t0len, t1len, plen;
+
+       alen = lbnNorm_16(a, alen);
+       if (!alen)
+               return 1;       /* No inverse */
+
+       mlen = lbnNorm_16(mod, mlen);
+
+       assert (alen <= mlen);
+
+       /* Inverse of 1 is 1 */
+       if (alen == 1 && BIGLITTLE(a[-1],a[0]) == 1) {
+               lbnZero_16(BIGLITTLE(a-alen,a+alen), mlen-alen);
+               return 0;
+       }
+
+       /* Allocate a pile of space */
+       LBNALLOC(b, mlen+1);
+       if (b) {
+               /*
+                * Although products are guaranteed to always be less than the
+                * modulus, it can involve multiplying two 3-word numbers to
+                * get a 5-word result, requiring a 6th word to store a 0
+                * temporarily.  Thus, mlen + 1.
+                */
+               LBNALLOC(p, mlen+1);
+               if (p) {
+                       LBNALLOC(t0, mlen);
+                       if (t0) {
+                               LBNALLOC(t1, mlen);
+                               if (t1)
+                                               goto allocated;
+                               LBNFREE(t0, mlen);
+                       }
+                       LBNFREE(p, mlen+1);
+               }
+               LBNFREE(b, mlen+1);
+       }
+       return -1;
+
+allocated:
+
+       /* Set t0 to 1 */
+       t0len = 1;
+       BIGLITTLE(t0[-1],t0[0]) = 1;
+       
+       /* b = mod */
+       lbnCopy_16(b, mod, mlen);
+       /* blen = mlen (implicitly) */
+       
+       /* t1 = b / a; b = b % a */
+       cy = lbnDiv_16(t1, b, mlen, a, alen);
+       *(BIGLITTLE(t1-(mlen-alen)-1,t1+(mlen-alen))) = cy;
+       t1len = lbnNorm_16(t1, mlen-alen+1);
+       blen = lbnNorm_16(b, alen);
+
+       /* while (b > 1) */
+       while (blen > 1 || BIGLITTLE(b[-1],b[0]) != (BNWORD16)1) {
+               /* q = a / b; a = a % b; */
+               if (alen < blen || (alen == blen && lbnCmp_16(a, a, alen) < 0))
+                       assert(0);
+               cy = lbnDiv_16(BIGLITTLE(a-blen,a+blen), a, alen, b, blen);
+               *(BIGLITTLE(a-alen-1,a+alen)) = cy;
+               plen = lbnNorm_16(BIGLITTLE(a-blen,a+blen), alen-blen+1);
+               assert(plen);
+               alen = lbnNorm_16(a, blen);
+               if (!alen)
+                       goto failure;   /* GCD not 1 */
+
+               /* t0 += q * t1; */
+               assert(plen+t1len <= mlen+1);
+               lbnMul_16(p, BIGLITTLE(a-blen,a+blen), plen, t1, t1len);
+               plen = lbnNorm_16(p, plen + t1len);
+               assert(plen <= mlen);
+               if (plen > t0len) {
+                       lbnZero_16(BIGLITTLE(t0-t0len,t0+t0len), plen-t0len);
+                       t0len = plen;
+               }
+               cy = lbnAddN_16(t0, p, plen);
+               if (cy) {
+                       if (t0len > plen) {
+                               cy = lbnAdd1_16(BIGLITTLE(t0-plen,t0+plen),
+                                               t0len-plen, cy);
+                       }
+                       if (cy) {
+                               BIGLITTLE(t0[-t0len-1],t0[t0len]) = cy;
+                               t0len++;
+                       }
+               }
+
+               /* if (a <= 1) return a ? t0 : FAIL; */
+               if (alen <= 1 && BIGLITTLE(a[-1],a[0]) == (BNWORD16)1) {
+                       if (alen == 0)
+                               goto failure;   /* FAIL */
+                       assert(t0len <= mlen);
+                       lbnCopy_16(a, t0, t0len);
+                       lbnZero_16(BIGLITTLE(a-t0len, a+t0len), mlen-t0len);
+                       goto success;
+               }
+
+               /* q = b / a; b = b % a; */
+               if (blen < alen || (blen == alen && lbnCmp_16(b, a, alen) < 0))
+                       assert(0);
+               cy = lbnDiv_16(BIGLITTLE(b-alen,b+alen), b, blen, a, alen);
+               *(BIGLITTLE(b-blen-1,b+blen)) = cy;
+               plen = lbnNorm_16(BIGLITTLE(b-alen,b+alen), blen-alen+1);
+               assert(plen);
+               blen = lbnNorm_16(b, alen);
+               if (!blen)
+                       goto failure;   /* GCD not 1 */
+
+               /* t1 += q * t0; */
+               assert(plen+t0len <= mlen+1);
+               lbnMul_16(p, BIGLITTLE(b-alen,b+alen), plen, t0, t0len);
+               plen = lbnNorm_16(p, plen + t0len);
+               assert(plen <= mlen);
+               if (plen > t1len) {
+                       lbnZero_16(BIGLITTLE(t1-t1len,t1+t1len), plen-t1len);
+                       t1len = plen;
+               }
+               cy = lbnAddN_16(t1, p, plen);
+               if (cy) {
+                       if (t1len > plen) {
+                               cy = lbnAdd1_16(BIGLITTLE(t1-plen,t0+plen),
+                                               t1len-plen, cy);
+                       }
+                       if (cy) {
+                               BIGLITTLE(t1[-t1len-1],t1[t1len]) = cy;
+                               t1len++;
+                       }
+               }
+       }
+
+       if (!blen)
+               goto failure;   /* gcd(a, mod) != 1 -- FAIL */
+
+       /* return mod-t1 */
+       lbnCopy_16(a, mod, mlen);
+       assert(t1len <= mlen);
+       cy = lbnSubN_16(a, t1, t1len);
+       if (cy) {
+               assert(mlen > t1len);
+               cy = lbnSub1_16(BIGLITTLE(a-t1len, a+t1len), mlen-t1len, cy);
+               assert(!cy);
+       }
+
+success:
+       LBNFREE(t1, mlen);
+       LBNFREE(t0, mlen);
+       LBNFREE(p, mlen+1);
+       LBNFREE(b, mlen+1);
+       
+       return 0;
+
+failure:
+       LBNFREE(t1, mlen);
+       LBNFREE(t0, mlen);
+       LBNFREE(p, mlen+1);
+       LBNFREE(b, mlen+1);
+       
+       return 1;
+}
diff --git a/lib/bind/cylink/lbn16.h b/lib/bind/cylink/lbn16.h
new file mode 100644 (file)
index 0000000..e011e4e
--- /dev/null
@@ -0,0 +1,181 @@
+#ifndef LBN16_H
+#define LBN16_H
+
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+#include "lbn.h"
+
+#ifndef BNWORD16
+#error 16-bit bignum library requires a 16-bit data type
+#endif
+
+#ifndef lbnCopy_16
+void lbnCopy_16(BNWORD16 *dest, BNWORD16 const *src, unsigned len);
+#endif
+#ifndef lbnZero_16
+void lbnZero_16(BNWORD16 *num, unsigned len);
+#endif
+#ifndef lbnNeg_16
+void lbnNeg_16(BNWORD16 *num, unsigned len);
+#endif
+
+#ifndef lbnAdd1_16
+BNWORD16 lbnAdd1_16(BNWORD16 *num, unsigned len, BNWORD16 carry);
+#endif
+#ifndef lbnSub1_16
+BNWORD16 lbnSub1_16(BNWORD16 *num, unsigned len, BNWORD16 borrow);
+#endif
+
+#ifndef lbnAddN_16
+BNWORD16 lbnAddN_16(BNWORD16 *num1, BNWORD16 const *num2, unsigned len);
+#endif
+#ifndef lbnSubN_16
+BNWORD16 lbnSubN_16(BNWORD16 *num1, BNWORD16 const *num2, unsigned len);
+#endif
+
+#ifndef lbnCmp_16
+int lbnCmp_16(BNWORD16 const *num1, BNWORD16 const *num2, unsigned len);
+#endif
+
+#ifndef lbnMulN1_16
+void lbnMulN1_16(BNWORD16 *out, BNWORD16 const *in, unsigned len, BNWORD16 k);
+#endif
+#ifndef lbnMulAdd1_16
+BNWORD16
+lbnMulAdd1_16(BNWORD16 *out, BNWORD16 const *in, unsigned len, BNWORD16 k);
+#endif
+#ifndef lbnMulSub1_16
+BNWORD16 lbnMulSub1_16(BNWORD16 *out, BNWORD16 const *in, unsigned len, BNWORD16 k);
+#endif
+
+#ifndef lbnLshift_16
+BNWORD16 lbnLshift_16(BNWORD16 *num, unsigned len, unsigned shift);
+#endif
+#ifndef lbnDouble_16
+BNWORD16 lbnDouble_16(BNWORD16 *num, unsigned len);
+#endif
+#ifndef lbnRshift_16
+BNWORD16 lbnRshift_16(BNWORD16 *num, unsigned len, unsigned shift);
+#endif
+
+#ifndef lbnMul_16
+void lbnMul_16(BNWORD16 *prod, BNWORD16 const *num1, unsigned len1,
+       BNWORD16 const *num2, unsigned len2);
+#endif
+#ifndef lbnSquare_16
+void lbnSquare_16(BNWORD16 *prod, BNWORD16 const *num, unsigned len);
+#endif
+
+#ifndef lbnNorm_16
+unsigned lbnNorm_16(BNWORD16 const *num, unsigned len);
+#endif
+#ifndef lbnBits_16
+unsigned lbnBits_16(BNWORD16 const *num, unsigned len);
+#endif
+
+#ifndef lbnExtractBigBytes_16
+void lbnExtractBigBytes_16(BNWORD16 const *bn, unsigned char *buf,
+       unsigned lsbyte, unsigned buflen);
+#endif
+#ifndef lbnInsertBigytes_16
+void lbnInsertBigBytes_16(BNWORD16 *n, unsigned char const *buf,
+       unsigned lsbyte,  unsigned buflen);
+#endif
+#ifndef lbnExtractLittleBytes_16
+void lbnExtractLittleBytes_16(BNWORD16 const *bn, unsigned char *buf,
+       unsigned lsbyte, unsigned buflen);
+#endif
+#ifndef lbnInsertLittleBytes_16
+void lbnInsertLittleBytes_16(BNWORD16 *n, unsigned char const *buf,
+       unsigned lsbyte,  unsigned buflen);
+#endif
+
+#ifndef lbnDiv21_16
+BNWORD16 lbnDiv21_16(BNWORD16 *q, BNWORD16 nh, BNWORD16 nl, BNWORD16 d);
+#endif
+#ifndef lbnDiv1_16
+BNWORD16 lbnDiv1_16(BNWORD16 *q, BNWORD16 *rem,
+       BNWORD16 const *n, unsigned len, BNWORD16 d);
+#endif
+#ifndef lbnModQ_16
+unsigned lbnModQ_16(BNWORD16 const *n, unsigned len, unsigned d);
+#endif
+#ifndef lbnDiv_16
+BNWORD16
+lbnDiv_16(BNWORD16 *q, BNWORD16 *n, unsigned nlen, BNWORD16 *d, unsigned dlen);
+#endif
+
+#ifndef lbnMontInv1_16
+BNWORD16 lbnMontInv1_16(BNWORD16 const x);
+#endif
+#ifndef lbnMontReduce_16
+void lbnMontReduce_16(BNWORD16 *n, BNWORD16 const *mod, unsigned const mlen,
+                BNWORD16 inv);
+#endif
+#ifndef lbnToMont_16
+void lbnToMont_16(BNWORD16 *n, unsigned nlen, BNWORD16 *mod, unsigned mlen);
+#endif
+#ifndef lbnFromMont_16
+void lbnFromMont_16(BNWORD16 *n, BNWORD16 *mod, unsigned len);
+#endif
+
+#ifndef lbnExpMod_16
+int lbnExpMod_16(BNWORD16 *result, BNWORD16 const *n, unsigned nlen,
+       BNWORD16 const *exp, unsigned elen, BNWORD16 *mod, unsigned mlen);
+#endif
+#ifndef lbnDoubleExpMod_16
+int lbnDoubleExpMod_16(BNWORD16 *result,
+       BNWORD16 const *n1, unsigned n1len, BNWORD16 const *e1, unsigned e1len,
+       BNWORD16 const *n2, unsigned n2len, BNWORD16 const *e2, unsigned e2len,
+       BNWORD16 *mod, unsigned mlen);
+#endif
+#ifndef lbnTwoExpMod_16
+int lbnTwoExpMod_16(BNWORD16 *n, BNWORD16 const *exp, unsigned elen,
+       BNWORD16 *mod, unsigned mlen);
+#endif
+#ifndef lbnGcd_16
+int lbnGcd_16(BNWORD16 *a, unsigned alen, BNWORD16 *b, unsigned blen);
+#endif
+#ifndef lbnInv_16
+int lbnInv_16(BNWORD16 *a, unsigned alen, BNWORD16 const *mod, unsigned mlen);
+#endif
+
+#endif /* LBN16_H */
diff --git a/lib/bind/cylink/lbn32.c b/lib/bind/cylink/lbn32.c
new file mode 100644 (file)
index 0000000..44ac41c
--- /dev/null
@@ -0,0 +1,3643 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/*
+ * lbn32.c - Low-level bignum routines, 32-bit version.
+ *
+ * Copyright (c) 1995  Colin Plumb.  All rights reserved.
+ * For licensing and other legal details, see the file legal.c.
+ *
+ * NOTE: the magic constants "32" and "64" appear in many places in this
+ * file, including inside identifiers.  Because it is not possible to
+ * ask "#ifdef" of a macro expansion, it is not possible to use the
+ * preprocessor to conditionalize these properly.  Thus, this file is
+ * intended to be edited with textual search and replace to produce
+ * alternate word size versions.  Any reference to the number of bits
+ * in a word must be the string "32", and that string must not appear
+ * otherwise.  Any reference to twice this number must appear as "64",
+ * which likewise must not appear otherwise.  Is that clear?
+ *
+ * Remember, when doubling the bit size replace the larger number (64)
+ * first, then the smaller (32).  When halving the bit size, do the
+ * opposite.  Otherwise, things will get wierd.  Also, be sure to replace
+ * every instance that appears.  (:%s/foo/bar/g in vi)
+ *
+ * These routines work with a pointer to the least-significant end of
+ * an array of WORD32s.  The BIG(x), LITTLE(y) and BIGLTTLE(x,y) macros
+ * defined in lbn.h (which expand to x on a big-edian machine and y on a
+ * little-endian machine) are used to conditionalize the code to work
+ * either way.  If you have no assembly primitives, it doesn't matter.
+ * Note that on a big-endian machine, the least-significant-end pointer
+ * is ONE PAST THE END.  The bytes are ptr[-1] through ptr[-len].
+ * On little-endian, they are ptr[0] through ptr[len-1].  This makes
+ * perfect sense if you consider pointers to point *between* bytes rather
+ * than at them.
+ *
+ * Because the array index values are unsigned integers, ptr[-i]
+ * may not work properly, since the index -i is evaluated as an unsigned,
+ * and if pointers are wider, zero-extension will produce a positive
+ * number rahter than the needed negative.  The expression used in this
+ * code, *(ptr-i) will, however, work.  (The array syntax is equivalent
+ * to *(ptr+-i), which is a pretty subtle difference.)
+ *
+ * Many of these routines will get very unhappy if fed zero-length inputs.
+ * They use assert() to enforce this.  An higher layer of code must make
+ * sure that these aren't called with zero-length inputs.
+ *
+ * Any of these routines can be replaced with more efficient versions
+ * elsewhere, by just #defining their names.  If one of the names
+ * is #defined, the C code is not compiled in and no declaration is
+ * made.  Use the BNINCLUDE file to do that.  Typically, you compile
+ * asm subroutines with the same name and just, e.g.
+ * #define lbnMulAdd1_32 lbnMulAdd1_32
+ *
+ * If you want to write asm routines, start with lbnMulAdd1_32().
+ * This is the workhorse of modular exponentiation.  lbnMulN1_32() is
+ * also used a fair bit, although not as much and it's defined in terms
+ * of lbnMulAdd1_32 if that has a custom version.  lbnMulSub1_32 and
+ * lbnDiv21_32 are used in the usual division and remainder finding.
+ * (Not the Montgomery reduction used in modular exponentiation, though.)
+ * Once you have lbnMulAdd1_32 defined, writing the other two should
+ * be pretty easy.  (Just make sure you get the sign of the subtraction
+ * in lbnMulSub1_32 right - it's dest = dest - source * k.)
+ *
+ * The only definitions that absolutely need a double-word (BNWORD64)
+ * type are lbnMulAdd1_32 and lbnMulSub1_32; if those are provided,
+ * the rest follows.  lbnDiv21_32, however, is a lot slower unless you
+ * have them, and lbnModQ_32 takes after it.  That one is used quite a
+ * bit for prime sieving.
+ */
+
+#ifndef HAVE_CONFIG_H
+#define HAVE_CONFIG_H 0
+#endif
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/*
+ * Some compilers complain about #if FOO if FOO isn't defined,
+ * so do the ANSI-mandated thing explicitly...
+ */
+#ifndef NO_ASSERT_H
+#define NO_ASSERT_H 0
+#endif
+#ifndef NO_STRING_H
+#define NO_STRING_H 0
+#endif
+#ifndef HAVE_STRINGS_H
+#define HAVE_STRINGS_H 0
+#endif
+#ifndef NEED_MEMORY_H
+#define NEED_MEMORY_H 0
+#endif
+
+#if !NO_ASSERT_H
+#include <assert.h>
+#else
+#define assert(x) (void)0
+#endif
+
+#if !NO_STRING_H
+#include <string.h>    /* For memcpy */
+#elif HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#if NEED_MEMORY_H
+#include <memory.h>
+#endif
+
+#include "lbn.h"
+#include "lbn32.h"
+#include "lbnmem.h"
+#include "legal.h"
+
+#include "kludge.h"
+#include <port_after.h>
+
+#ifndef BNWORD32
+#error 32-bit bignum library requires a 32-bit data type
+#endif
+
+/* Make sure the copyright notice gets included */
+volatile const char * volatile const lbnCopyright_32 = bnCopyright;
+
+/*
+ * Most of the multiply (and Montgomery reduce) routines use an outer
+ * loop that iterates over one of the operands - a so-called operand
+ * scanning approach.  One big advantage of this is that the assembly
+ * support routines are simpler.  The loops can be rearranged to have
+ * an outer loop that iterates over the product, a so-called product
+ * scanning approach.  This has the advantage of writing less data
+ * and doing fewer adds to memory, so is supposedly faster.  Some
+ * code has been written using a product-scanning approach, but
+ * it appears to be slower, so it is turned off by default.  Some
+ * experimentation would be appreciated.
+ *
+ * (The code is also annoying to get right and not very well commented,
+ * one of my pet peeves about math libraries.  I'm sorry.)
+ */
+#ifndef PRODUCT_SCAN
+#define PRODUCT_SCAN 0
+#endif
+
+/*
+ * Copy an array of words.  <Marvin mode on>  Thrilling, isn't it? </Marvin>
+ * This is a good example of how the byte offsets and BIGLITTLE() macros work.
+ * Another alternative would have been
+ * memcpy(dest BIG(-len), src BIG(-len), len*sizeof(BNWORD32)), but I find that
+ * putting operators into conditional macros is confusing.
+ */
+#ifndef lbnCopy_32
+void
+lbnCopy_32(BNWORD32 *dest, BNWORD32 const *src, unsigned len)
+{
+       memcpy(BIGLITTLE(dest-len,dest), BIGLITTLE(src-len,src),
+              len * sizeof(*src));
+}
+#endif /* !lbnCopy_32 */
+
+/*
+ * Fill n words with zero.  This does it manually rather than calling
+ * memset because it can assume alignment to make things faster while
+ * memset can't.  Note how big-endian numbers are naturally addressed
+ * using predecrement, while little-endian is postincrement.
+ */
+#ifndef lbnZero_32
+void
+lbnZero_32(BNWORD32 *num, unsigned len)
+{
+       while (len--)
+               BIGLITTLE(*--num,*num++) = 0;
+}
+#endif /* !lbnZero_32 */
+
+/*
+ * Negate an array of words.
+ * Negation is subtraction from zero.  Negating low-order words
+ * entails doing nothing until a non-zero word is hit.  Once that
+ * is negated, a borrow is generated and never dies until the end
+ * of the number is hit.  Negation with borrow, -x-1, is the same as ~x.
+ * Repeat that until the end of the number.
+ *
+ * Doesn't return borrow out because that's pretty useless - it's
+ * always set unless the input is 0, which is easy to notice in
+ * normalized form.
+ */
+#ifndef lbnNeg_32
+void
+lbnNeg_32(BNWORD32 *num, unsigned len)
+{
+       assert(len);
+
+       /* Skip low-order zero words */
+       while (BIGLITTLE(*--num,*num) == 0) {
+               if (!--len)
+                       return;
+               LITTLE(num++;)
+       }
+       /* Negate the lowest-order non-zero word */
+       *num = -*num;
+       /* Complement all the higher-order words */
+       while (--len) {
+               BIGLITTLE(--num,++num);
+               *num = ~*num;
+       }
+}
+#endif /* !lbnNeg_32 */
+
+
+/*
+ * lbnAdd1_32: add the single-word "carry" to the given number.
+ * Used for minor increments and propagating the carry after
+ * adding in a shorter bignum.
+ *
+ * Technique: If we have a double-width word, presumably the compiler
+ * can add using its carry in inline code, so we just use a larger
+ * accumulator to compute the carry from the first addition.
+ * If not, it's more complex.  After adding the first carry, which may
+ * be > 1, compare the sum and the carry.  If the sum wraps (causing a
+ * carry out from the addition), the result will be less than each of the
+ * inputs, since the wrap subtracts a number (2^32) which is larger than
+ * the other input can possibly be.  If the sum is >= the carry input,
+ * return success immediately.
+ * In either case, if there is a carry, enter a loop incrementing words
+ * until one does not wrap.  Since we are adding 1 each time, the wrap
+ * will be to 0 and we can test for equality.
+ */
+#ifndef lbnAdd1_32     /* If defined, it's provided as an asm subroutine */
+#ifdef BNWORD64
+BNWORD32
+lbnAdd1_32(BNWORD32 *num, unsigned len, BNWORD32 carry)
+{
+       BNWORD64 t;
+       assert(len > 0);        /* Alternative: if (!len) return carry */
+
+       t = (BNWORD64)BIGLITTLE(*--num,*num) + carry;
+       BIGLITTLE(*num,*num++) = (BNWORD32)t;
+       if ((t >> 32) == 0)
+               return 0;
+       while (--len) {
+               if (++BIGLITTLE(*--num,*num++) != 0)
+                       return 0;
+       }
+       return 1;
+}
+#else /* no BNWORD64 */
+BNWORD32
+lbnAdd1_32(BNWORD32 *num, unsigned len, BNWORD32 carry)
+{
+       assert(len > 0);        /* Alternative: if (!len) return carry */
+
+       if ((BIGLITTLE(*--num,*num++) += carry) >= carry)
+               return 0;
+       while (--len) {
+               if (++BIGLITTLE(*--num,*num++) != 0)
+                       return 0;
+       }
+       return 1;
+}
+#endif
+#endif/* !lbnAdd1_32 */
+
+/*
+ * lbnSub1_32: subtract the single-word "borrow" from the given number.
+ * Used for minor decrements and propagating the borrow after
+ * subtracting a shorter bignum.
+ *
+ * Technique: Similar to the add, above.  If there is a double-length type,
+ * use that to generate the first borrow.
+ * If not, after subtracting the first borrow, which may be > 1, compare
+ * the difference and the *negative* of the carry.  If the subtract wraps
+ * (causing a borrow out from the subtraction), the result will be at least
+ * as large as -borrow.  If the result < -borrow, then no borrow out has
+ * appeared and we may return immediately, except when borrow == 0.  To
+ * deal with that case, use the identity that -x = ~x+1, and instead of
+ * comparing < -borrow, compare for <= ~borrow.
+ * Either way, if there is a borrow out, enter a loop decrementing words
+ * until a non-zero word is reached.
+ *
+ * Note the cast of ~borrow to (BNWORD32).  If the size of an int is larger
+ * than BNWORD32, C rules say the number is expanded for the arithmetic, so
+ * the inversion will be done on an int and the value won't be quite what
+ * is expected.
+ */
+#ifndef lbnSub1_32     /* If defined, it's provided as an asm subroutine */
+#ifdef BNWORD64
+BNWORD32
+lbnSub1_32(BNWORD32 *num, unsigned len, BNWORD32 borrow)
+{
+       BNWORD64 t;
+       assert(len > 0);        /* Alternative: if (!len) return borrow */
+
+       t = (BNWORD64)BIGLITTLE(*--num,*num) - borrow;
+       BIGLITTLE(*num,*num++) = (BNWORD32)t;
+       if ((t >> 32) == 0)
+               return 0;
+       while (--len) {
+               if ((BIGLITTLE(*--num,*num++))-- != 0)
+                       return 0;
+       }
+       return 1;
+}
+#else /* no BNWORD64 */
+BNWORD32
+lbnSub1_32(BNWORD32 *num, unsigned len, BNWORD32 borrow)
+{
+       assert(len > 0);        /* Alternative: if (!len) return borrow */
+
+       if ((BIGLITTLE(*--num,*num++) -= borrow) <= (BNWORD32)~borrow)
+               return 0;
+       while (--len) {
+               if ((BIGLITTLE(*--num,*num++))-- != 0)
+                       return 0;
+       }
+       return 1;
+}
+#endif
+#endif /* !lbnSub1_32 */
+
+/*
+ * lbnAddN_32: add two bignums of the same length, returning the carry (0 or 1).
+ * One of the building blocks, along with lbnAdd1, of adding two bignums of
+ * differing lengths.
+ *
+ * Technique: Maintain a word of carry.  If there is no double-width type,
+ * use the same technique as in lbnAdd1, above, to maintain the carry by
+ * comparing the inputs.  Adding the carry sources is used as an OR operator;
+ * at most one of the two comparisons can possibly be true.  The first can
+ * only be true if carry == 1 and x, the result, is 0.  In that case the
+ * second can't possibly be true.
+ */
+#ifndef lbnAddN_32
+#ifdef BNWORD64
+BNWORD32
+lbnAddN_32(BNWORD32 *num1, BNWORD32 const *num2, unsigned len)
+{
+       BNWORD64 t;
+
+       assert(len > 0);
+
+       t = (BNWORD64)BIGLITTLE(*--num1,*num1) + BIGLITTLE(*--num2,*num2++);
+       BIGLITTLE(*num1,*num1++) = (BNWORD32)t;
+       while (--len) {
+               t = (BNWORD64)BIGLITTLE(*--num1,*num1) +
+                   (BNWORD64)BIGLITTLE(*--num2,*num2++) + (t >> 32);
+               BIGLITTLE(*num1,*num1++) = (BNWORD32)t;
+       }
+
+       return (BNWORD32)(t>>32);
+}
+#else /* no BNWORD64 */
+BNWORD32
+lbnAddN_32(BNWORD32 *num1, BNWORD32 const *num2, unsigned len)
+{
+       BNWORD32 x, carry = 0;
+
+       assert(len > 0);        /* Alternative: change loop to test at start */
+
+       do {
+               x = BIGLITTLE(*--num2,*num2++);
+               carry = (x += carry) < carry;
+               carry += (BIGLITTLE(*--num1,*num1++) += x) < x;
+       } while (--len);
+
+       return carry;
+}
+#endif
+#endif /* !lbnAddN_32 */
+
+/*
+ * lbnSubN_32: add two bignums of the same length, returning the carry (0 or 1).
+ * One of the building blocks, along with subn1, of subtracting two bignums of
+ * differing lengths.
+ *
+ * Technique: If no double-width type is availble, maintain a word of borrow.
+ * First, add the borrow to the subtrahend (did you have to learn all those
+ * awful words in elementary school, too?), and if it overflows, set the
+ * borrow again.  Then subtract the modified subtrahend from the next word
+ * of input, using the same technique as in subn1, above.
+ * Adding the borrows is used as an OR operator; at most one of the two
+ * comparisons can possibly be true.  The first can only be true if
+ * borrow == 1 and x, the result, is 0.  In that case the second can't
+ * possibly be true.
+ *
+ * In the double-word case, (BNWORD32)-(t>>32) is subtracted, rather than
+ * adding t>>32, because the shift would need to sign-extend and that's
+ * not guaranteed to happen in ANSI C, even with signed types.
+ */
+#ifndef lbnSubN_32
+#ifdef BNWORD64
+BNWORD32
+lbnSubN_32(BNWORD32 *num1, BNWORD32 const *num2, unsigned len)
+{
+       BNWORD64 t;
+
+       assert(len > 0);
+
+       t = (BNWORD64)BIGLITTLE(*--num1,*num1) - BIGLITTLE(*--num2,*num2++);
+       BIGLITTLE(*num1,*num1++) = (BNWORD32)t;
+
+       while (--len) {
+               t = (BNWORD64)BIGLITTLE(*--num1,*num1) -
+                   (BNWORD64)BIGLITTLE(*--num2,*num2++) - (BNWORD32)-(t >> 32);
+               BIGLITTLE(*num1,*num1++) = (BNWORD32)t;
+       }
+
+       return -(BNWORD32)(t>>32);
+}
+#else
+BNWORD32
+lbnSubN_32(BNWORD32 *num1, BNWORD32 const *num2, unsigned len)
+{
+       BNWORD32 x, borrow = 0;
+
+       assert(len > 0);        /* Alternative: change loop to test at start */
+
+       do {
+               x = BIGLITTLE(*--num2,*num2++);
+               borrow = (x += borrow) < borrow;
+               borrow += (BIGLITTLE(*--num1,*num1++) -= x) > (BNWORD32)~x;
+       } while (--len);
+
+       return borrow;
+}
+#endif
+#endif /* !lbnSubN_32 */
+
+#ifndef lbnCmp_32
+/*
+ * lbnCmp_32: compare two bignums of equal length, returning the sign of
+ * num1 - num2. (-1, 0 or +1).
+ * 
+ * Technique: Change the little-endian pointers to big-endian pointers
+ * and compare from the most-significant end until a difference if found.
+ * When it is, figure out the sign of the difference and return it.
+ */
+int
+lbnCmp_32(BNWORD32 const *num1, BNWORD32 const *num2, unsigned len)
+{
+       BIGLITTLE(num1 -= len, num1 += len);
+       BIGLITTLE(num2 -= len, num2 += len);
+
+       while (len--) {
+               if (BIGLITTLE(*num1++ != *num2++, *--num1 != *--num2)) {
+                       if (BIGLITTLE(num1[-1] < num2[-1], *num1 < *num2))
+                               return -1;
+                       else
+                               return 1;
+               }
+       }
+       return 0;
+}
+#endif /* !lbnCmp_32 */
+
+/*
+ * mul32_ppmmaa(ph,pl,x,y,a,b) is an optional routine that
+ * computes (ph,pl) = x * y + a + b.  mul32_ppmma and mul32_ppmm
+ * are simpler versions.  If you want to be lazy, all of these
+ * can be defined in terms of the others, so here we create any
+ * that have not been defined in terms of the ones that have been.
+ */
+
+/* Define ones with fewer a's in terms of ones with more a's */
+#if !defined(mul32_ppmma) && defined(mul32_ppmmaa)
+#define mul32_ppmma(ph,pl,x,y,a) mul32_ppmmaa(ph,pl,x,y,a,0)
+#endif
+
+#if !defined(mul32_ppmm) && defined(mul32_ppmma)
+#define mul32_ppmm(ph,pl,x,y) mul32_ppmma(ph,pl,x,y,0)
+#endif
+
+/*
+ * Use this definition to test the mul32_ppmm-based operations on machines
+ * that do not provide mul32_ppmm.  Change the final "0" to a "1" to
+ * enable it.
+ */
+#if !defined(mul32_ppmm) && defined(BNWORD64) && 0     /* Debugging */
+#define mul32_ppmm(ph,pl,x,y) \
+       ({BNWORD64 _ = (BNWORD64)(x)*(y); (pl) = _; (ph) = _>>32;})
+#endif
+
+#if defined(mul32_ppmm) && !defined(mul32_ppmma)
+#define mul32_ppmma(ph,pl,x,y,a) \
+       (mul32_ppmm(ph,pl,x,y), (ph) += ((pl) += (a)) < (a))
+#endif
+
+#if defined(mul32_ppmma) && !defined(mul32_ppmmaa)
+#define mul32_ppmmaa(ph,pl,x,y,a,b) \
+       (mul32_ppmma(ph,pl,x,y,a), (ph) += ((pl) += (b)) < (b))
+#endif
+
+/*
+ * lbnMulN1_32: Multiply an n-word input by a 1-word input and store the
+ * n+1-word product.  This uses either the mul32_ppmm and mul32_ppmma
+ * macros, or C multiplication with the BNWORD64 type.  This uses mul32_ppmma
+ * if available, assuming you won't bother defining it unless you can do
+ * better than the normal multiplication.
+ */
+#ifndef lbnMulN1_32
+#ifdef lbnMulAdd1_32   /* If we have this asm primitive, use it. */
+void
+lbnMulN1_32(BNWORD32 *out, BNWORD32 const *in, unsigned len, BNWORD32 k)
+{
+       lbnZero_32(out, len);
+       BIGLITTLE(*(out-len),*(out+len)) = lbnMulAdd1_32(out, in, len, k);
+}
+#elif defined(mul32_ppmm)
+void
+lbnMulN1_32(BNWORD32 *out, BNWORD32 const *in, unsigned len, BNWORD32 k)
+{
+       BNWORD32 prod, carry, carryin;
+
+       assert(len > 0);
+
+       BIG(--out;--in;);
+       mul32_ppmm(carry, *out, *in, k);
+       LITTLE(out++;in++;)
+
+       while (--len) {
+               BIG(--out;--in;)
+               carryin = carry;
+               mul32_ppmma(carry, *out, *in, k, carryin);
+               LITTLE(out++;in++;)
+       }
+       BIGLITTLE(*--out,*out) = carry;
+}
+#elif defined(BNWORD64)
+void
+lbnMulN1_32(BNWORD32 *out, BNWORD32 const *in, unsigned len, BNWORD32 k)
+{
+       BNWORD64 p;
+
+       assert(len > 0);
+
+       p = (BNWORD64)BIGLITTLE(*--in,*in++) * k;
+       BIGLITTLE(*--out,*out++) = (BNWORD32)p;
+
+       while (--len) {
+               p = (BNWORD64)BIGLITTLE(*--in,*in++) * k + (BNWORD32)(p >> 32);
+               BIGLITTLE(*--out,*out++) = (BNWORD32)p;
+       }
+       BIGLITTLE(*--out,*out) = (BNWORD32)(p >> 32);
+}
+#else
+#error No 32x32 -> 64 multiply available for 32-bit bignum package
+#endif
+#endif /* lbnMulN1_32 */
+
+/*
+ * lbnMulAdd1_32: Multiply an n-word input by a 1-word input and add the
+ * low n words of the product to the destination.  *Returns the n+1st word
+ * of the product.*  (That turns out to be more convenient than adding
+ * it into the destination and dealing with a possible unit carry out
+ * of *that*.)  This uses either the mul32_ppmma and mul32_ppmmaa macros,
+ * or C multiplication with the BNWORD64 type.
+ *
+ * If you're going to write assembly primitives, this is the one to
+ * start with.  It is by far the most commonly called function.
+ */
+#ifndef lbnMulAdd1_32
+#if defined(mul32_ppmm)
+BNWORD32
+lbnMulAdd1_32(BNWORD32 *out, BNWORD32 const *in, unsigned len, BNWORD32 k)
+{
+       BNWORD32 prod, carry, carryin;
+
+       assert(len > 0);
+
+       BIG(--out;--in;);
+       carryin = *out;
+       mul32_ppmma(carry, *out, *in, k, carryin);
+       LITTLE(out++;in++;)
+
+       while (--len) {
+               BIG(--out;--in;);
+               carryin = carry;
+               mul32_ppmmaa(carry, prod, *in, k, carryin, *out);
+               *out = prod;
+               LITTLE(out++;in++;)
+       }
+
+       return carry;
+}
+#elif defined(BNWORD64)
+BNWORD32
+lbnMulAdd1_32(BNWORD32 *out, BNWORD32 const *in, unsigned len, BNWORD32 k)
+{
+       BNWORD64 p;
+
+       assert(len > 0);
+
+       p = (BNWORD64)BIGLITTLE(*--in,*in++) * k + BIGLITTLE(*--out,*out);
+       BIGLITTLE(*out,*out++) = (BNWORD32)p;
+
+       while (--len) {
+               p = (BNWORD64)BIGLITTLE(*--in,*in++) * k +
+                   (BNWORD32)(p >> 32) + BIGLITTLE(*--out,*out);
+               BIGLITTLE(*out,*out++) = (BNWORD32)p;
+       }
+
+       return (BNWORD32)(p >> 32);
+}
+#else
+#error No 32x32 -> 64 multiply available for 32-bit bignum package
+#endif
+#endif /* lbnMulAdd1_32 */
+
+/*
+ * lbnMulSub1_32: Multiply an n-word input by a 1-word input and subtract the
+ * n-word product from the destination.  Returns the n+1st word of the product.
+ * This uses either the mul32_ppmm and mul32_ppmma macros, or
+ * C multiplication with the BNWORD64 type.
+ *
+ * This is rather uglier than adding, but fortunately it's only used in
+ * division which is not used too heavily.
+ */
+#ifndef lbnMulN1_32
+#if defined(mul32_ppmm)
+BNWORD32
+lbnMulSub1_32(BNWORD32 *out, BNWORD32 const *in, unsigned len, BNWORD32 k)
+{
+       BNWORD32 prod, carry, carryin;
+
+       assert(len > 0);
+
+       BIG(--in;)
+       mul32_ppmm(carry, prod, *in, k);
+       LITTLE(in++;)
+       carry += (BIGLITTLE(*--out,*out++) -= prod) > (BNWORD32)~prod;
+
+       while (--len) {
+               BIG(--in;);
+               carryin = carry;
+               mul32_ppmma(carry, prod, *in, k, carryin);
+               LITTLE(in++;)
+               carry += (BIGLITTLE(*--out,*out++) -= prod) > (BNWORD32)~prod;
+       }
+
+       return carry;
+}
+#elif defined(BNWORD64)
+BNWORD32
+lbnMulSub1_32(BNWORD32 *out, BNWORD32 const *in, unsigned len, BNWORD32 k)
+{
+       BNWORD64 p;
+       BNWORD32 carry, t;
+
+       assert(len > 0);
+
+       p = (BNWORD64)BIGLITTLE(*--in,*in++) * k;
+       t = BIGLITTLE(*--out,*out);
+       carry = (BNWORD32)(p>>32) + ((BIGLITTLE(*out,*out++)=t-(BNWORD32)p) > t);
+
+       while (--len) {
+               p = (BNWORD64)BIGLITTLE(*--in,*in++) * k + carry;
+               t = BIGLITTLE(*--out,*out);
+               carry = (BNWORD32)(p>>32) +
+                       ( (BIGLITTLE(*out,*out++)=t-(BNWORD32)p) > t );
+       }
+
+       return carry;
+}
+#else
+#error No 32x32 -> 64 multiply available for 32-bit bignum package
+#endif
+#endif /* !lbnMulSub1_32 */
+
+/*
+ * Shift n words left "shift" bits.  0 < shift < 32.  Returns the
+ * carry, any bits shifted off the left-hand side (0 <= carry < 2^shift).
+ */
+#ifndef lbnLshift_32
+BNWORD32
+lbnLshift_32(BNWORD32 *num, unsigned len, unsigned shift)
+{
+       BNWORD32 x, carry;
+
+       assert(shift > 0);
+       assert(shift < 32);
+
+       carry = 0;
+       while (len--) {
+               BIG(--num;)
+               x = *num;
+               *num = (x<<shift) | carry;
+               LITTLE(num++;)
+               carry = x >> (32-shift);
+       }
+       return carry;
+}
+#endif /* !lbnLshift_32 */
+
+/*
+ * An optimized version of the above, for shifts of 1.
+ * Some machines can use add-with-carry tricks for this.
+ */
+#ifndef lbnDouble_32
+BNWORD32
+lbnDouble_32(BNWORD32 *num, unsigned len)
+{
+       BNWORD32 x, carry;
+
+       carry = 0;
+       while (len--) {
+               BIG(--num;)
+               x = *num;
+               *num = (x<<1) | carry;
+               LITTLE(num++;)
+               carry = x >> (32-1);
+       }
+       return carry;
+}
+#endif /* !lbnDouble_32 */
+
+/*
+ * Shift n words right "shift" bits.  0 < shift < 32.  Returns the
+ * carry, any bits shifted off the right-hand side (0 <= carry < 2^shift).
+ */
+#ifndef lbnRshift_32
+BNWORD32
+lbnRshift_32(BNWORD32 *num, unsigned len, unsigned shift)
+{
+       BNWORD32 x, carry = 0;
+
+       assert(shift > 0);
+       assert(shift < 32);
+
+       BIGLITTLE(num -= len, num += len);
+
+       while (len--) {
+               LITTLE(--num;)
+               x = *num;
+               *num = (x>>shift) | carry;
+               BIG(num++;)
+               carry = x << (32-shift);
+       }
+       return carry >> (32-shift);
+}
+#endif /* !lbnRshift_32 */
+
+/* 
+ * Multiply two numbers of the given lengths.  prod and num2 may overlap,
+ * provided that the low len1 bits of prod are free.  (This corresponds
+ * nicely to the place the result is returned from lbnMontReduce_32.)
+ *
+ * TODO: Use Karatsuba multiply.  The overlap constraints may have
+ * to get rewhacked.
+ */
+#ifndef lbnMul_32
+void
+lbnMul_32(BNWORD32 *prod, BNWORD32 const *num1, unsigned len1,
+                          BNWORD32 const *num2, unsigned len2)
+{
+       /* Special case of zero */
+       if (!len1 || !len2) {
+               lbnZero_32(prod, len1+len2);
+               return;
+       }
+
+       /* Multiply first word */
+       lbnMulN1_32(prod, num1, len1, BIGLITTLE(*--num2,*num2++));
+
+       /*
+        * Add in subsequent words, storing the most significant word,
+        * which is new each time.
+        */
+       while (--len2) {
+               BIGLITTLE(--prod,prod++);
+               BIGLITTLE(*(prod-len1-1),*(prod+len1)) =
+                   lbnMulAdd1_32(prod, num1, len1, BIGLITTLE(*--num2,*num2++));
+       }
+}
+#endif /* !lbnMul_32 */
+
+/*
+ * lbnMulX_32 is a square multiply - both inputs are the same length.
+ * It's normally just a macro wrapper around the general multiply,
+ * but might be implementable in assembly more efficiently (such as
+ * when product scanning).
+ */
+#ifndef lbnMulX_32
+#if defined(BNWORD64) && PRODUCT_SCAN
+/*
+ * Test code to see whether product scanning is any faster.  It seems
+ * to make the C code slower, so PRODUCT_SCAN is not defined.
+ */
+static void
+lbnMulX_32(BNWORD32 *prod, BNWORD32 const *num1, BNWORD32 const *num2,
+       unsigned len)
+{
+       BNWORD64 x, y;
+       BNWORD32 const *p1, *p2;
+       unsigned carry;
+       unsigned i, j;
+
+       /* Special case of zero */
+       if (!len)
+               return;
+
+       x = (BNWORD64)BIGLITTLE(num1[-1] * num2[-1], num1[0] * num2[0]);
+       BIGLITTLE(*--prod, *prod++) = (BNWORD32)x;
+       x >>= 32;
+
+       for (i = 1; i < len; i++) {
+               carry = 0;
+               p1 = num1;
+               p2 = BIGLITTLE(num2-i-1,num2+i+1);
+               for (j = 0; j <= i; j++) {
+                       BIG(y = (BNWORD64)*--p1 * *p2++;)
+                       LITTLE(y = (BNWORD64)*p1++ * *--p2;)
+                       x += y;
+                       carry += (x < y);
+               }
+               BIGLITTLE(*--prod,*prod++) = (BNWORD32)x;
+               x = (x >> 32) | (BNWORD64)carry << 32;
+       }
+       for (i = 1; i < len; i++) {
+               carry = 0;
+               p1 = BIGLITTLE(num1-i,num1+i);
+               p2 = BIGLITTLE(num2-len,num2+len);
+               for (j = i; j < len; j++) {
+                       BIG(y = (BNWORD64)*--p1 * *p2++;)
+                       LITTLE(y = (BNWORD64)*p1++ * *--p2;)
+                       x += y;
+                       carry += (x < y);
+               }
+               BIGLITTLE(*--prod,*prod++) = (BNWORD32)x;
+               x = (x >> 32) | (BNWORD64)carry << 32;
+       }
+       
+       BIGLITTLE(*--prod,*prod) = (BNWORD32)x;
+}
+#else /* !defined(BNWORD64) || !PRODUCT_SCAN */
+/* Default trivial macro definition */
+#define lbnMulX_32(prod, num1, num2, len) lbnMul_32(prod, num1, len, num2, len)
+#endif /* !defined(BNWORD64) || !PRODUCT_SCAN */
+#endif /* !lbmMulX_32 */
+
+#if !defined(lbnMontMul_32) && defined(BNWORD64) && PRODUCT_SCAN
+/*
+ * Test code for product-scanning multiply.  This seems to slow the C
+ * code down rather than speed it up.
+ * This does a multiply and Montgomery reduction together, using the
+ * same loops.  The outer loop scans across the product, twice.
+ * The first pass computes the low half of the product and the
+ * Montgomery multipliers.  These are stored in the product array,
+ * which contains no data as of yet.  x and carry add up the columns
+ * and propagate carries forward.
+ *
+ * The second half multiplies the upper half, adding in the modulus
+ * times the Montgomery multipliers.  The results of this multiply
+ * are stored.
+ */
+static void
+lbnMontMul_32(BNWORD32 *prod, BNWORD32 const *num1, BNWORD32 const *num2,
+       BNWORD32 const *mod, unsigned len, BNWORD32 inv)
+{
+       BNWORD64 x, y;
+       BNWORD32 const *p1, *p2, *pm;
+       BNWORD32 *pp;
+       BNWORD32 t;
+       unsigned carry;
+       unsigned i, j;
+
+       /* Special case of zero */
+       if (!len)
+               return;
+
+       /*
+        * This computes directly into the high half of prod, so just
+        * shift the pointer and consider prod only "len" elements long
+        * for the rest of the code.
+        */
+       BIGLITTLE(prod -= len, prod += len);
+
+       /* Pass 1 - compute Montgomery multipliers */
+       /* First iteration can have certain simplifications. */
+       x = (BNWORD64)BIGLITTLE(num1[-1] * num2[-1], num1[0] * num2[0]);
+       BIGLITTLE(prod[-1], prod[0]) = t = inv * (BNWORD32)x;
+       y = (BNWORD64)t * BIGLITTLE(mod[-1],mod[0]);
+       x += y;
+       /* Note: GCC 2.6.3 has a bug if you try to eliminate "carry" */
+       carry = (x < y);
+       assert((BNWORD32)x == 0);
+       x = x >> 32 | (BNWORD64)carry << 32;
+
+       for (i = 1; i < len; i++) {
+               carry = 0;
+               p1 = num1;
+               p2 = BIGLITTLE(num2-i-1,num2+i+1);
+               pp = prod;
+               pm = BIGLITTLE(mod-i-1,mod+i+1);
+               for (j = 0; j < i; j++) {
+                       y = (BNWORD64)BIGLITTLE(*--p1 * *p2++, *p1++ * *--p2);
+                       x += y;
+                       carry += (x < y);
+                       y = (BNWORD64)BIGLITTLE(*--pp * *pm++, *pp++ * *--pm);
+                       x += y;
+                       carry += (x < y);
+               }
+               y = (BNWORD64)BIGLITTLE(p1[-1] * p2[0], p1[0] * p2[-1]);
+               x += y;
+               carry += (x < y);
+               assert(BIGLITTLE(pp == prod-i, pp == prod+i));
+               BIGLITTLE(pp[-1], pp[0]) = t = inv * (BNWORD32)x;
+               assert(BIGLITTLE(pm == mod-1, pm == mod+1));
+               y = (BNWORD64)t * BIGLITTLE(pm[0],pm[-1]);
+               x += y;
+               carry += (x < y);
+               assert((BNWORD32)x == 0);
+               x = x >> 32 | (BNWORD64)carry << 32;
+       }
+
+       /* Pass 2 - compute reduced product and store */
+       for (i = 1; i < len; i++) {
+               carry = 0;
+               p1 = BIGLITTLE(num1-i,num1+i);
+               p2 = BIGLITTLE(num2-len,num2+len);
+               pm = BIGLITTLE(mod-i,mod+i);
+               pp = BIGLITTLE(prod-len,prod+len);
+               for (j = i; j < len; j++) {
+                       y = (BNWORD64)BIGLITTLE(*--p1 * *p2++, *p1++ * *--p2);
+                       x += y;
+                       carry += (x < y);
+                       y = (BNWORD64)BIGLITTLE(*--pm * *pp++, *pm++ * *--pp);
+                       x += y;
+                       carry += (x < y);
+               }
+               assert(BIGLITTLE(pm == mod-len, pm == mod+len));
+               assert(BIGLITTLE(pp == prod-i, pp == prod+i));
+               BIGLITTLE(pp[0],pp[-1]) = (BNWORD32)x;
+               x = (x >> 32) | (BNWORD64)carry << 32;
+       }
+
+       /* Last round of second half, simplified. */
+       BIGLITTLE(*(prod-len),*(prod+len-1)) = (BNWORD32)x;
+       carry = (x >> 32);
+
+       while (carry)
+               carry -= lbnSubN_32(prod, mod, len);
+       while (lbnCmp_32(prod, mod, len) >= 0)
+               (void)lbnSubN_32(prod, mod, len);
+}
+/* Suppress later definition */
+#define lbnMontMul_32 lbnMontMul_32
+#endif
+
+#if !defined(lbnSquare_32) && defined(BNWORD64) && PRODUCT_SCAN
+/*
+ * Trial code for product-scanning squaring.  This seems to slow the C
+ * code down rather than speed it up.
+ */
+void
+lbnSquare_32(BNWORD32 *prod, BNWORD32 const *num, unsigned len)
+{
+       BNWORD64 x, y, z;
+       BNWORD32 const *p1, *p2;
+       unsigned carry;
+       unsigned i, j;
+
+       /* Special case of zero */
+       if (!len)
+               return;
+
+       /* Word 0 of product */
+       x = (BNWORD64)BIGLITTLE(num[-1] * num[-1], num[0] * num[0]);
+       BIGLITTLE(*--prod, *prod++) = (BNWORD32)x;
+       x >>= 32;
+
+       /* Words 1 through len-1 */
+       for (i = 1; i < len; i++) {
+               carry = 0;
+               y = 0;
+               p1 = num;
+               p2 = BIGLITTLE(num-i-1,num+i+1);
+               for (j = 0; j < (i+1)/2; j++) {
+                       BIG(z = (BNWORD64)*--p1 * *p2++;)
+                       LITTLE(z = (BNWORD64)*p1++ * *--p2;)
+                       y += z;
+                       carry += (y < z);
+               }
+               y += z = y;
+               carry += carry + (y < z);
+               if ((i & 1) == 0) {
+                       assert(BIGLITTLE(--p1 == p2, p1 == --p2));
+                       BIG(z = (BNWORD64)*p2 * *p2;)
+                       LITTLE(z = (BNWORD64)*p1 * *p1;)
+                       y += z;
+                       carry += (y < z);
+               }
+               x += y;
+               carry += (x < y);
+               BIGLITTLE(*--prod,*prod++) = (BNWORD32)x;
+               x = (x >> 32) | (BNWORD64)carry << 32;
+       }
+       /* Words len through 2*len-2 */
+       for (i = 1; i < len; i++) {
+               carry = 0;
+               y = 0;
+               p1 = BIGLITTLE(num-i,num+i);
+               p2 = BIGLITTLE(num-len,num+len);
+               for (j = 0; j < (len-i)/2; j++) {
+                       BIG(z = (BNWORD64)*--p1 * *p2++;)
+                       LITTLE(z = (BNWORD64)*p1++ * *--p2;)
+                       y += z;
+                       carry += (y < z);
+               }
+               y += z = y;
+               carry += carry + (y < z);
+               if ((len-i) & 1) {
+                       assert(BIGLITTLE(--p1 == p2, p1 == --p2));
+                       BIG(z = (BNWORD64)*p2 * *p2;)
+                       LITTLE(z = (BNWORD64)*p1 * *p1;)
+                       y += z;
+                       carry += (y < z);
+               }
+               x += y;
+               carry += (x < y);
+               BIGLITTLE(*--prod,*prod++) = (BNWORD32)x;
+               x = (x >> 32) | (BNWORD64)carry << 32;
+       }
+       
+       /* Word 2*len-1 */
+       BIGLITTLE(*--prod,*prod) = (BNWORD32)x;
+}
+/* Suppress later definition */
+#define lbnSquare_32 lbnSquare_32
+#endif
+
+/*
+ * Square a number, using optimized squaring to reduce the number of
+ * primitive multiples that are executed.  There may not be any
+ * overlap of the input and output.
+ *
+ * Technique: Consider the partial products in the multiplication
+ * of "abcde" by itself:
+ *
+ *               a  b  c  d  e
+ *            *  a  b  c  d  e
+ *          ==================
+ *              ae be ce de ee
+ *           ad bd cd dd de
+ *        ac bc cc cd ce
+ *     ab bb bc bd be
+ *  aa ab ac ad ae
+ *
+ * Note that everything above the main diagonal:
+ *              ae be ce de = (abcd) * e
+ *           ad bd cd       = (abc) * d
+ *        ac bc             = (ab) * c
+ *     ab                   = (a) * b
+ *
+ * is a copy of everything below the main diagonal:
+ *                       de
+ *                 cd ce
+ *           bc bd be
+ *     ab ac ad ae
+ *
+ * Thus, the sum is 2 * (off the diagonal) + diagonal.
+ *
+ * This is accumulated beginning with the diagonal (which
+ * consist of the squares of the digits of the input), which is then
+ * divided by two, the off-diagonal added, and multiplied by two
+ * again.  The low bit is simply a copy of the low bit of the
+ * input, so it doesn't need special care.
+ *
+ * TODO: Merge the shift by 1 with the squaring loop.
+ * TODO: Use Karatsuba.  (a*W+b)^2 = a^2 * (W^2+W) + b^2 * (W+1) - (a-b)^2 * W.
+ */
+#ifndef lbnSquare_32
+void
+lbnSquare_32(BNWORD32 *prod, BNWORD32 const *num, unsigned len)
+{
+       BNWORD32 t;
+       BNWORD32 *prodx = prod;         /* Working copy of the argument */
+       BNWORD32 const *numx = num;     /* Working copy of the argument */
+       unsigned lenx = len;            /* Working copy of the argument */
+
+       if (!len)
+               return;
+
+       /* First, store all the squares */
+       while (lenx--) {
+#ifdef mul32_ppmm
+               BNWORD32 ph, pl;
+               t = BIGLITTLE(*--numx,*numx++);
+               mul32_ppmm(ph,pl,t,t);
+               BIGLITTLE(*--prodx,*prodx++) = pl;
+               BIGLITTLE(*--prodx,*prodx++) = ph;
+#elif defined(BNWORD64) /* use BNWORD64 */
+               BNWORD64 p;
+               t = BIGLITTLE(*--numx,*numx++);
+               p = (BNWORD64)t * t;
+               BIGLITTLE(*--prodx,*prodx++) = (BNWORD32)p;
+               BIGLITTLE(*--prodx,*prodx++) = (BNWORD32)(p>>32);
+#else  /* Use lbnMulN1_32 */
+               t = BIGLITTLE(numx[-1],*numx);
+               lbnMulN1_32(prodx, numx, 1, t);
+               BIGLITTLE(--numx,numx++);
+               BIGLITTLE(prodx -= 2, prodx += 2);
+#endif
+       }
+       /* Then, shift right 1 bit */
+       (void)lbnRshift_32(prod, 2*len, 1);
+
+       /* Then, add in the off-diagonal sums */
+       lenx = len;
+       numx = num;
+       prodx = prod;
+       while (--lenx) {
+               t = BIGLITTLE(*--numx,*numx++);
+               BIGLITTLE(--prodx,prodx++);
+               t = lbnMulAdd1_32(prodx, numx, lenx, t);
+               lbnAdd1_32(BIGLITTLE(prodx-lenx,prodx+lenx), lenx+1, t);
+               BIGLITTLE(--prodx,prodx++);
+       }
+
+       /* Shift it back up */
+       lbnDouble_32(prod, 2*len);
+
+       /* And set the low bit appropriately */
+       BIGLITTLE(prod[-1],prod[0]) |= BIGLITTLE(num[-1],num[0]) & 1;
+}
+#endif /* !lbnSquare_32 */
+
+/*
+ * lbnNorm_32 - given a number, return a modified length such that the
+ * most significant digit is non-zero.  Zero-length input is okay.
+ */
+#ifndef lbnNorm_32
+unsigned
+lbnNorm_32(BNWORD32 const *num, unsigned len)
+{
+       BIGLITTLE(num -= len,num += len);
+       while (len && BIGLITTLE(*num++,*--num) == 0)
+               --len;
+       return len;
+}
+#endif /* lbnNorm_32 */
+
+/*
+ * lbnBits_32 - return the number of significant bits in the array.
+ * It starts by normalizing the array.  Zero-length input is okay.
+ * Then assuming there's anything to it, it fetches the high word,
+ * generates a bit length by multiplying the word length by 32, and
+ * subtracts off 32/2, 32/4, 32/8, ... bits if the high bits are clear.
+ */
+#ifndef lbnBits_32
+unsigned
+lbnBits_32(BNWORD32 const *num, unsigned len)
+{
+       BNWORD32 t;
+       unsigned i;
+
+       len = lbnNorm_32(num, len);
+       if (len) {
+               t = BIGLITTLE(*(num-len),*(num+(len-1)));
+               assert(t);
+               len *= 32;
+               i = 32/2;
+               do {
+                       if (t >> i)
+                               t >>= i;
+                       else
+                               len -= i;
+               } while ((i /= 2) != 0);
+       }
+       return len;
+}
+#endif /* lbnBits_32 */
+
+/*
+ * If defined, use hand-rolled divide rather than compiler's native.
+ * If the machine doesn't do it in line, the manual code is probably
+ * faster, since it can assume normalization and the fact that the
+ * quotient will fit into 32 bits, which a general 64-bit divide
+ * in a compiler's run-time library can't do.
+ */
+#ifndef BN_SLOW_DIVIDE_64
+/* Assume that divisors of more than thirty-two bits are slow */
+#define BN_SLOW_DIVIDE_64 (64 > 0x20)
+#endif
+
+/*
+ * Return (nh<<32|nl) % d, and place the quotient digit into *q.
+ * It is guaranteed that nh < d, and that d is normalized (with its high
+ * bit set).  If we have a double-width type, it's easy.  If not, ooh,
+ * yuk!
+ */
+#ifndef lbnDiv21_32
+#if defined(BNWORD64) && !BN_SLOW_DIVIDE_64
+BNWORD32
+lbnDiv21_32(BNWORD32 *q, BNWORD32 nh, BNWORD32 nl, BNWORD32 d)
+{
+       BNWORD64 n = (BNWORD64)nh << 32 | nl;
+
+       /* Divisor must be normalized */
+       assert(d >> (32-1) == 1);
+
+       *q = n / d;
+       return n % d;
+}
+#else
+/*
+ * This is where it gets ugly.
+ *
+ * Do the division in two halves, using Algorithm D from section 4.3.1
+ * of Knuth.  Note Theorem B from that section, that the quotient estimate
+ * is never more than the true quotient, and is never more than two
+ * too low.
+ *
+ * The mapping onto conventional long division is (everything a half word):
+ *        _____________qh___ql_
+ * dh dl ) nh.h nh.l nl.h nl.l
+ *             - (qh * d)
+ *            -----------
+ *              rrrr rrrr nl.l
+ *                  - (ql * d)
+ *                -----------
+ *                  rrrr rrrr
+ *
+ * The implicit 3/2-digit d*qh and d*ql subtractors are computed this way:
+ *   First, estimate a q digit so that nh/dh works.  Subtracting qh*dh from
+ *   the (nh.h nh.l) list leaves a 1/2-word remainder r.  Then compute the
+ *   low part of the subtractor, qh * dl.   This also needs to be subtracted
+ *   from (nh.h nh.l nl.h) to get the final remainder.  So we take the
+ *   remainder, which is (nh.h nh.l) - qh*dl, shift it and add in nl.h, and
+ *   try to subtract qh * dl from that.  Since the remainder is 1/2-word
+ *   long, shifting and adding nl.h results in a single word r.
+ *   It is possible that the remainder we're working with, r, is less than
+ *   the product qh * dl, if we estimated qh too high.  The estimation
+ *   technique can produce a qh that is too large (never too small), leading
+ *   to r which is too small.  In that case, decrement the digit qh, add
+ *   shifted dh to r (to correct for that error), and subtract dl from the
+ *   product we're comparing r with.  That's the "correct" way to do it, but
+ *   just adding dl to r instead of subtracting it from the product is
+ *   equivalent and a lot simpler.  You just have to watch out for overflow.
+ *
+ *   The process is repeated with (rrrr rrrr nl.l) for the low digit of the
+ *   quotient ql.
+ *
+ * The various uses of 32/2 for shifts are because of the note about
+ * automatic editing of this file at the very top of the file.
+ */
+#define highhalf(x) ( (x) >> 32/2 )
+#define lowhalf(x) ( (x) & (((BNWORD32)1 << 32/2)-1) )
+BNWORD32
+lbnDiv21_32(BNWORD32 *q, BNWORD32 nh, BNWORD32 nl, BNWORD32 d)
+{
+       BNWORD32 dh = highhalf(d), dl = lowhalf(d);
+       BNWORD32 qh, ql, prod, r;
+
+       /* Divisor must be normalized */
+       assert((d >> (32-1)) == 1);
+
+       /* Do first half-word of division */
+       qh = nh / dh;
+       r = nh % dh;
+       prod = qh * dl;
+
+       /*
+        * Add next half-word of numerator to remainder and correct.
+        * qh may be up to two too large.
+        */
+       r = (r << (32/2)) | highhalf(nl);
+       if (r < prod) {
+               --qh; r += d;
+               if (r >= d && r < prod) {
+                       --qh; r += d; 
+               }
+       }
+       r -= prod;
+
+       /* Do second half-word of division */
+       ql = r / dh;
+       r = r % dh;
+       prod = ql * dl;
+
+       r = (r << (32/2)) | lowhalf(nl);
+       if (r < prod) {
+               --ql; r += d;
+               if (r >= d && r < prod) {
+                       --ql; r += d;
+               }
+       }
+       r -= prod;
+
+       *q = (qh << (32/2)) | ql;
+
+       return r;
+}
+#endif
+#endif /* lbnDiv21_32 */
+
+
+/*
+ * In the division functions, the dividend and divisor are referred to
+ * as "n" and "d", which stand for "numerator" and "denominator".
+ *
+ * The quotient is (nlen-dlen+1) digits long.  It may be overlapped with
+ * the high (nlen-dlen) words of the dividend, but one extra word is needed
+ * on top to hold the top word.
+ */
+
+/*
+ * Divide an n-word number by a 1-word number, storing the remainder
+ * and n-1 words of the n-word quotient.  The high word is returned.
+ * It IS legal for rem to point to the same address as n, and for
+ * q to point one word higher.
+ *
+ * TODO: If BN_SLOW_DIVIDE_64, add a divnhalf_32 which uses 32-bit
+ *       dividends if the divisor is half that long.
+ * TODO: Shift the dividend on the fly to avoid the last division and
+ *       instead have a remainder that needs shifting.
+ * TODO: Use reciprocals rather than dividing.
+ */
+#ifndef lbnDiv1_32
+BNWORD32
+lbnDiv1_32(BNWORD32 *q, BNWORD32 *rem, BNWORD32 const *n, unsigned len,
+       BNWORD32 d)
+{
+       unsigned shift;
+       unsigned xlen;
+       BNWORD32 r;
+       BNWORD32 qhigh;
+
+       assert(len > 0);
+       assert(d);
+
+       if (len == 1) {
+               r = *n;
+               *rem = r%d;
+               return r/d;
+       }
+
+       shift = 0;
+       r = d;
+       xlen = 32/2;
+       do {
+               if (r >> xlen)
+                       r >>= xlen;
+               else
+                       shift += xlen;
+       } while ((xlen /= 2) != 0);
+       assert((d >> (32-1-shift)) == 1);
+       d <<= shift;
+
+       BIGLITTLE(q -= len-1,q += len-1);
+       BIGLITTLE(n -= len,n += len);
+
+       r = BIGLITTLE(*n++,*--n);
+       if (r < d) {
+               qhigh = 0;
+       } else {
+               qhigh = r/d;
+               r %= d;
+       }
+
+       xlen = len;
+       while (--xlen)
+               r = lbnDiv21_32(BIGLITTLE(q++,--q), r, BIGLITTLE(*n++,*--n), d);
+
+       /*
+        * Final correction for shift - shift the quotient up "shift"
+        * bits, and merge in the extra bits of quotient.  Then reduce
+        * the final remainder mod the real d.
+        */
+       if (shift) {
+               d >>= shift;
+               qhigh = (qhigh << shift) | lbnLshift_32(q, len-1, shift);
+               BIGLITTLE(q[-1],*q) |= r/d;
+               r %= d;
+       }
+       *rem = r;
+
+       return qhigh;
+}
+#endif
+
+/*
+ * This function performs a "quick" modulus of a number with a divisor
+ * d which is guaranteed to be at most sixteen bits, i.e. less than 65536.
+ * This applies regardless of the word size the library is compiled with.
+ *
+ * This function is important to prime generation, for sieving.
+ */
+#ifndef lbnModQ_32
+/* If there's a custom lbnMod21_32, no normalization needed */
+#ifdef lbnMod21_32
+unsigned
+lbnModQ_32(BNWORD32 const *n, unsigned len, unsigned d)
+{
+       unsigned i, shift;
+       BNWORD32 r;
+
+       assert(len > 0);
+
+       BIGLITTLE(n -= len,n += len);
+
+       /* Try using a compare to avoid the first divide */
+       r = BIGLITTLE(*n++,*--n);
+       if (r >= d)
+               r %= d;
+       while (--len)
+               r = lbnMod21_32(r, BIGLITTLE(*n++,*--n), d);
+
+       return r;
+}
+#elif defined(BNWORD64) && !BN_SLOW_DIVIDE_64
+unsigned
+lbnModQ_32(BNWORD32 const *n, unsigned len, unsigned d)
+{
+       BNWORD32 r;
+
+       if (!--len)
+               return BIGLITTLE(n[-1],n[0]) % d;
+
+       BIGLITTLE(n -= len,n += len);
+       r = BIGLITTLE(n[-1],n[0]);
+
+       do {
+               r = (BNWORD32)((((BNWORD64)r<<32) | BIGLITTLE(*n++,*--n)) % d);
+       } while (--len);
+
+       return r;
+}
+#elif 32 >= 0x20
+/*
+ * If the single word size can hold 65535*65536, then this function
+ * is avilable.
+ */
+#ifndef highhalf
+#define highhalf(x) ( (x) >> 32/2 )
+#define lowhalf(x) ( (x) & ((1 << 32/2)-1) )
+#endif
+unsigned
+lbnModQ_32(BNWORD32 const *n, unsigned len, unsigned d)
+{
+       BNWORD32 r, x;
+
+       BIGLITTLE(n -= len,n += len);
+
+       r = BIGLITTLE(*n++,*--n);
+       while (--len) {
+               x = BIGLITTLE(*n++,*--n);
+               r = (r%d << 32/2) | highhalf(x);
+               r = (r%d << 32/2) | lowhalf(x);
+       }
+
+       return r%d;
+}
+#else
+/* Default case - use lbnDiv21_32 */
+unsigned
+lbnModQ_32(BNWORD32 const *n, unsigned len, unsigned d)
+{
+       unsigned i, shift;
+       BNWORD32 r;
+       BNWORD32 q;
+
+       assert(len > 0);
+
+       shift = 0;
+       r = d;
+       i = 32;
+       while (i /= 2) {
+               if (r >> i)
+                       r >>= i;
+               else
+                       shift += i;
+       }
+       assert(d >> (32-1-shift) == 1);
+       d <<= shift;
+
+       BIGLITTLE(n -= len,n += len);
+
+       r = BIGLITTLE(*n++,*--n);
+       if (r >= d)
+               r %= d;
+
+       while (--len)
+               r = lbnDiv21_32(&q, r, BIGLITTLE(*n++,*--n), d);
+
+       /*
+        * Final correction for shift - shift the quotient up "shift"
+        * bits, and merge in the extra bits of quotient.  Then reduce
+        * the final remainder mod the real d.
+        */
+       if (shift)
+               r %= d >> shift;
+
+       return r;
+}
+#endif
+#endif /* lbnModQ_32 */
+
+/*
+ * Reduce n mod d and return the quotient.  That is, find:
+ * q = n / d;
+ * n = n % d;
+ * d is altered during the execution of this subroutine by normalizing it.
+ * It must already have its most significant word non-zero; it is shifted
+ * so its most significant bit is non-zero.
+ *
+ * The quotient q is nlen-dlen+1 words long.  To make it possible to
+ * overlap the quptient with the input (you can store it in the high dlen
+ * words), the high word of the quotient is *not* stored, but is returned.
+ * (If all you want is the remainder, you don't care about it, anyway.)
+ *
+ * This uses algorithm D from Knuth (4.3.1), except that we do binary
+ * (shift) normalization of the divisor.  WARNING: This is hairy!
+ *
+ * This function is used for some modular reduction, but it is not used in
+ * the modular exponentiation loops; they use Montgomery form and the
+ * corresponding, more efficient, Montgomery reduction.  This code
+ * is needed for the conversion to Montgomery form, however, so it
+ * has to be here and it might as well be reasonably efficient.
+ *
+ * The overall operation is as follows ("top" and "up" refer to the
+ * most significant end of the number; "bottom" and "down", the least):
+ *
+ * - Shift the divisor up until the most significant bit is set.
+ * - Shift the dividend up the same amount.  This will produce the
+ *   correct quotient, and the remainder can be recovered by shifting
+ *   it back down the same number of bits.  This may produce an overflow
+ *   word, but the word is always strictly less than the most significant
+ *   divisor word.
+ * - Estimate the first quotient digit qhat:
+ *   - First take the top two words (one of which is the overflow) of the
+ *     dividend and divide by the top word of the divisor:
+ *     qhat = (nh,nm)/dh.  This qhat is >= the correct quotient digit
+ *     and, since dh is normalized, it is at most two over.
+ *   - Second, correct by comparing the top three words.  If
+ *     (dh,dl) * qhat > (nh,nm,ml), decrease qhat and try again.
+ *     The second iteration can be simpler because there can't be a third.
+ *     The computation can be simplified by subtracting dh*qhat from
+ *     both sides, suitably shifted.  This reduces the left side to
+ *     dl*qhat.  On the right, (nh,nm)-dh*qhat is simply the
+ *     remainder r from (nh,nm)%dh, so the right is (r,nl).
+ *     This produces qhat that is almost always correct and at
+ *     most (prob ~ 2/2^32) one too high.
+ * - Subtract qhat times the divisor (suitably shifted) from the dividend.
+ *   If there is a borrow, qhat was wrong, so decrement it
+ *   and add the divisor back in (once).
+ * - Store the final quotient digit qhat in the quotient array q.
+ *
+ * Repeat the quotient digit computation for successive digits of the
+ * quotient until the whole quotient has been computed.  Then shift the
+ * divisor and the remainder down to correct for the normalization.
+ *
+ * TODO: Special case 2-word divisors.
+ * TODO: Use reciprocals rather than dividing.
+ */
+#ifndef divn_32
+BNWORD32
+lbnDiv_32(BNWORD32 *q, BNWORD32 *n, unsigned nlen, BNWORD32 *d, unsigned dlen)
+{
+       BNWORD32 nh,nm,nl;      /* Top three words of the dividend */
+       BNWORD32 dh,dl; /* Top two words of the divisor */
+       BNWORD32 qhat;  /* Extimate of quotient word */
+       BNWORD32 r;     /* Remainder from quotient estimate division */
+       BNWORD32 qhigh; /* High word of quotient */
+       unsigned i;     /* Temp */
+       unsigned shift; /* Bits shifted by normalization */
+       unsigned qlen = nlen-dlen; /* Size of quotient (less 1) */
+#ifdef mul32_ppmm
+       BNWORD32 t32;
+#elif defined(BNWORD64)
+       BNWORD64 t64;
+#else /* use lbnMulN1_32 */
+       BNWORD32 t2[2];
+#define t2high BIGLITTLE(t2[0],t2[1])
+#define t2low BIGLITTLE(t2[1],t2[0])
+#endif
+
+       assert(dlen);
+       assert(nlen >= dlen);
+
+       /*
+        * Special cases for short divisors.  The general case uses the
+        * top top 2 digits of the divisor (d) to estimate a quotient digit,
+        * so it breaks if there are fewer digits available.  Thus, we need
+        * special cases for a divisor of length 1.  A divisor of length
+        * 2 can have a *lot* of administrivia overhead removed removed,
+        * so it's probably worth special-casing that case, too.
+        */
+       if (dlen == 1)
+               return lbnDiv1_32(q, BIGLITTLE(n-1,n), n, nlen,
+                                 BIGLITTLE(d[-1],d[0]));
+
+#if 0
+       /*
+        * @@@ This is not yet written...  The general loop will do,
+        * albeit less efficiently
+        */
+       if (dlen == 2) {
+               /*
+                * divisor two digits long:
+                * use the 3/2 technique from Knuth, but we know
+                * it's exact.
+                */
+               dh = BIGLITTLE(d[-1],d[0]);
+               dl = BIGLITTLE(d[-2],d[1]);
+               shift = 0;
+               if ((sh & ((BNWORD32)1 << 32-1-shift)) == 0) {
+                       do {
+                               shift++;
+                       } while (dh & (BNWORD32)1<<32-1-shift) == 0);
+                       dh = dh << shift | dl >> (32-shift);
+                       dl <<= shift;
+
+
+               }
+
+
+               for (shift = 0; (dh & (BNWORD32)1 << 32-1-shift)) == 0; shift++)
+                       ;
+               if (shift) {
+               }
+               dh = dh << shift | dl >> (32-shift);
+               shift = 0;
+               while (dh
+       }
+#endif
+
+       dh = BIGLITTLE(*(d-dlen),*(d+(dlen-1)));
+       assert(dh);
+
+       /* Normalize the divisor */
+       shift = 0;
+       r = dh;
+       i = 32/2;
+       do {
+               if (r >> i)
+                       r >>= i;
+               else
+                       shift += i;
+       } while ((i /= 2) != 0);
+
+       nh = 0;
+       if (shift) {
+               lbnLshift_32(d, dlen, shift);
+               dh = BIGLITTLE(*(d-dlen),*(d+(dlen-1)));
+               nh = lbnLshift_32(n, nlen, shift);
+       }
+
+       /* Assert that dh is now normalized */
+       assert(dh >> (32-1));
+
+       /* Also get the second-most significant word of the divisor */
+       dl = BIGLITTLE(*(d-(dlen-1)),*(d+(dlen-2)));
+
+       /*
+        * Adjust pointers: n to point to least significant end of first
+        * first subtract, and q to one the most-significant end of the
+        * quotient array.
+        */
+       BIGLITTLE(n -= qlen,n += qlen);
+       BIGLITTLE(q -= qlen,q += qlen);
+
+       /* Fetch the most significant stored word of the dividend */
+       nm = BIGLITTLE(*(n-dlen),*(n+(dlen-1)));
+
+       /*
+        * Compute the first digit of the quotient, based on the
+        * first two words of the dividend (the most significant of which
+        * is the overflow word h).
+        */
+       if (nh) {
+               assert(nh < dh);
+               r = lbnDiv21_32(&qhat, nh, nm, dh);
+       } else if (nm >= dh) {
+               qhat = nm/dh;
+               r = nm % dh;
+       } else {        /* Quotient is zero */
+               qhigh = 0;
+               goto divloop;
+       }
+
+       /* Now get the third most significant word of the dividend */
+       nl = BIGLITTLE(*(n-(dlen-1)),*(n+(dlen-2)));
+
+       /*
+        * Correct qhat, the estimate of quotient digit.
+        * qhat can only be high, and at most two words high,
+        * so the loop can be unrolled and abbreviated.
+        */
+#ifdef mul32_ppmm
+       mul32_ppmm(nm, t32, qhat, dl);
+       if (nm > r || (nm == r && t32 > nl)) {
+               /* Decrement qhat and adjust comparison parameters */
+               qhat--;
+               if ((r += dh) >= dh) {
+                       nm -= (t32 < dl);
+                       t32 -= dl;
+                       if (nm > r || (nm == r && t32 > nl))
+                               qhat--;
+               }
+       }
+#elif defined(BNWORD64)
+       t64 = (BNWORD64)qhat * dl;
+       if (t64 > ((BNWORD64)r << 32) + nl) {
+               /* Decrement qhat and adjust comparison parameters */
+               qhat--;
+               if ((r += dh) > dh) {
+                       t64 -= dl;
+                       if (t64 > ((BNWORD64)r << 32) + nl)
+                               qhat--;
+               }
+       }
+#else /* Use lbnMulN1_32 */
+       lbnMulN1_32(BIGLITTLE(t2+2,t2), &dl, 1, qhat);
+       if (t2high > r || (t2high == r && t2low > nl)) {
+               /* Decrement qhat and adjust comparison parameters */
+               qhat--;
+               if ((r += dh) >= dh) {
+                       t2high -= (t2low < dl);
+                       t2low -= dl;
+                       if (t2high > r || (t2high == r && t2low > nl))
+                               qhat--;
+               }
+       }
+#endif
+
+       /* Do the multiply and subtract */
+       r = lbnMulSub1_32(n, d, dlen, qhat);
+       /* If there was a borrow, add back once. */
+       if (r > nh) {   /* Borrow? */
+               (void)lbnAddN_32(n, d, dlen);
+               qhat--;
+       }
+
+       /* Remember the first quotient digit. */
+       qhigh = qhat;
+
+       /* Now, the main division loop: */
+divloop:
+       while (qlen--) {
+
+               /* Advance n */
+               nh = BIGLITTLE(*(n-dlen),*(n+(dlen-1)));
+               BIGLITTLE(++n,--n);
+               nm = BIGLITTLE(*(n-dlen),*(n+(dlen-1)));
+
+               if (nh == dh) {
+                       qhat = ~(BNWORD32)0;
+                       /* Optimized computation of r = (nh,nm) - qhat * dh */
+                       r = nh + nm;
+                       if (r < nh)
+                               goto subtract;
+               } else {
+                       assert(nh < dh);
+                       r = lbnDiv21_32(&qhat, nh, nm, dh);
+               }
+
+               nl = BIGLITTLE(*(n-(dlen-1)),*(n+(dlen-2)));
+#ifdef mul32_ppmm
+               mul32_ppmm(nm, t32, qhat, dl);
+               if (nm > r || (nm == r && t32 > nl)) {
+                       /* Decrement qhat and adjust comparison parameters */
+                       qhat--;
+                       if ((r += dh) >= dh) {
+                               nm -= (t32 < dl);
+                               t32 -= dl;
+                               if (nm > r || (nm == r && t32 > nl))
+                                       qhat--;
+                       }
+               }
+#elif defined(BNWORD64)
+               t64 = (BNWORD64)qhat * dl;
+               if (t64 > ((BNWORD64)r<<32) + nl) {
+                       /* Decrement qhat and adjust comparison parameters */
+                       qhat--;
+                       if ((r += dh) >= dh) {
+                               t64 -= dl;
+                               if (t64 > ((BNWORD64)r << 32) + nl)
+                                       qhat--;
+                       }
+               }
+#else /* Use lbnMulN1_32 */
+               lbnMulN1_32(BIGLITTLE(t2+2,t2), &dl, 1, qhat);
+               if (t2high > r || (t2high == r && t2low > nl)) {
+                       /* Decrement qhat and adjust comparison parameters */
+                       qhat--;
+                       if ((r += dh) >= dh) {
+                               t2high -= (t2low < dl);
+                               t2low -= dl;
+                               if (t2high > r || (t2high == r && t2low > nl))
+                                       qhat--;
+                       }
+               }
+#endif
+
+               /*
+                * As a point of interest, note that it is not worth checking
+                * for qhat of 0 or 1 and installing special-case code.  These
+                * occur with probability 2^-32, so spending 1 cycle to check
+                * for them is only worth it if we save more than 2^15 cycles,
+                * and a multiply-and-subtract for numbers in the 1024-bit
+                * range just doesn't take that long.
+                */
+subtract:
+               /*
+                * n points to the least significant end of the substring
+                * of n to be subtracted from.  qhat is either exact or
+                * one too large.  If the subtract gets a borrow, it was
+                * one too large and the divisor is added back in.  It's
+                * a dlen+1 word add which is guaranteed to produce a
+                * carry out, so it can be done very simply.
+                */
+               r = lbnMulSub1_32(n, d, dlen, qhat);
+               if (r > nh) {   /* Borrow? */
+                       (void)lbnAddN_32(n, d, dlen);
+                       qhat--;
+               }
+               /* Store the quotient digit */
+               BIGLITTLE(*q++,*--q) = qhat;
+       }
+       /* Tah dah! */
+
+       if (shift) {
+               lbnRshift_32(d, dlen, shift);
+               lbnRshift_32(n, dlen, shift);
+       }
+
+       return qhigh;
+}
+#endif
+
+/*
+ * Find the negative multiplicative inverse of x (x must be odd!) modulo 2^32.
+ *
+ * This just performs Newton's iteration until it gets the
+ * inverse.  The initial estimate is always correct to 3 bits, and
+ * sometimes 4.  The number of valid bits doubles each iteration.
+ * (To prove it, assume x * y == 1 (mod 2^n), and introduce a variable
+ * for the error mod 2^2n.  x * y == 1 + k*2^n (mod 2^2n) and follow
+ * the iteration through.)
+ */
+#ifndef lbnMontInv1_32
+BNWORD32
+lbnMontInv1_32(BNWORD32 const x)
+{
+        BNWORD32 y = x, z;
+
+       assert(x & 1);
+        while ((z = x*y) != 1)
+                y *= 2 - z;
+        return -y;
+}
+#endif /* !lbnMontInv1_32 */
+
+#if defined(BNWORD64) && PRODUCT_SCAN
+/*
+ * Test code for product-scanning Montgomery reduction.
+ * This seems to slow the C code down rather than speed it up.
+ *
+ * The first loop computes the Montgomery multipliers, storing them over
+ * the low half of the number n.
+ *
+ * The second half multiplies the upper half, adding in the modulus
+ * times the Montgomery multipliers.  The results of this multiply
+ * are stored.
+ */
+void
+lbnMontReduce_32(BNWORD32 *n, BNWORD32 const *mod, unsigned mlen, BNWORD32 inv)
+{
+       BNWORD64 x, y;
+       BNWORD32 const *pm;
+       BNWORD32 *pn;
+       BNWORD32 t;
+       unsigned carry;
+       unsigned i, j;
+
+       /* Special case of zero */
+       if (!mlen)
+               return;
+
+       /* Pass 1 - compute Montgomery multipliers */
+       /* First iteration can have certain simplifications. */
+       t = BIGLITTLE(n[-1],n[0]);
+       x = t;
+       t *= inv;
+       BIGLITTLE(n[-1], n[0]) = t;
+       x += (BNWORD64)t * BIGLITTLE(mod[-1],mod[0]); /* Can't overflow */
+       assert((BNWORD32)x == 0);
+       x = x >> 32;
+
+       for (i = 1; i < mlen; i++) {
+               carry = 0;
+               pn = n;
+               pm = BIGLITTLE(mod-i-1,mod+i+1);
+               for (j = 0; j < i; j++) {
+                       y = (BNWORD64)BIGLITTLE(*--pn * *pm++, *pn++ * *--pm);
+                       x += y;
+                       carry += (x < y);
+               }
+               assert(BIGLITTLE(pn == n-i, pn == n+i));
+               y = t = BIGLITTLE(pn[-1], pn[0]);
+               x += y;
+               carry += (x < y);
+               BIGLITTLE(pn[-1], pn[0]) = t = inv * (BNWORD32)x;
+               assert(BIGLITTLE(pm == mod-1, pm == mod+1));
+               y = (BNWORD64)t * BIGLITTLE(pm[0],pm[-1]);
+               x += y;
+               carry += (x < y);
+               assert((BNWORD32)x == 0);
+               x = x >> 32 | (BNWORD64)carry << 32;
+       }
+
+       BIGLITTLE(n -= mlen, n += mlen);
+
+       /* Pass 2 - compute upper words and add to n */
+       for (i = 1; i < mlen; i++) {
+               carry = 0;
+               pm = BIGLITTLE(mod-i,mod+i);
+               pn = n;
+               for (j = i; j < mlen; j++) {
+                       y = (BNWORD64)BIGLITTLE(*--pm * *pn++, *pm++ * *--pn);
+                       x += y;
+                       carry += (x < y);
+               }
+               assert(BIGLITTLE(pm == mod-mlen, pm == mod+mlen));
+               assert(BIGLITTLE(pn == n+mlen-i, pn == n-mlen+i));
+               y = t = BIGLITTLE(*(n-i),*(n+i-1));
+               x += y;
+               carry += (x < y);
+               BIGLITTLE(*(n-i),*(n+i-1)) = (BNWORD32)x;
+               x = (x >> 32) | (BNWORD64)carry << 32;
+       }
+
+       /* Last round of second half, simplified. */
+       t = BIGLITTLE(*(n-mlen),*(n+mlen-1));
+       x += t;
+       BIGLITTLE(*(n-mlen),*(n+mlen-1)) = (BNWORD32)x;
+       carry = (unsigned)(x >> 32);
+
+       while (carry)
+               carry -= lbnSubN_32(n, mod, mlen);
+       while (lbnCmp_32(n, mod, mlen) >= 0)
+               (void)lbnSubN_32(n, mod, mlen);
+}
+#define lbnMontReduce_32 lbnMontReduce_32
+#endif
+
+/*
+ * Montgomery reduce n, modulo mod.  This reduces modulo mod and divides by
+ * 2^(32*mlen).  Returns the result in the *top* mlen words of the argument n.
+ * This is ready for another multiplication using lbnMul_32.
+ *
+ * Montgomery representation is a very useful way to encode numbers when
+ * you're doing lots of modular reduction.  What you do is pick a multiplier
+ * R which is relatively prime to the modulus and very easy to divide by.
+ * Since the modulus is odd, R is closen as a power of 2, so the division
+ * is a shift.  In fact, it's a shift of an integral number of words,
+ * so the shift can be implicit - just drop the low-order words.
+ *
+ * Now, choose R *larger* than the modulus m, 2^(32*mlen).  Then convert
+ * all numbers a, b, etc. to Montgomery form M(a), M(b), etc using the
+ * relationship M(a) = a*R mod m, M(b) = b*R mod m, etc.  Note that:
+ * - The Montgomery form of a number depends on the modulus m.
+ *   A fixed modulus m is assumed throughout this discussion.
+ * - Since R is relaitvely prime to m, multiplication by R is invertible;
+ *   no information about the numbers is lost, they're just scrambled.
+ * - Adding (and subtracting) numbers in this form works just as usual.
+ *   M(a+b) = (a+b)*R mod m = (a*R + b*R) mod m = (M(a) + M(b)) mod m
+ * - Multiplying numbers in this form produces a*b*R*R.  The problem
+ *   is to divide out the excess factor of R, modulo m as well as to
+ *   reduce to the given length mlen.  It turns out that this can be
+ *   done *faster* than a normal divide, which is where the speedup
+ *   in Montgomery division comes from.
+ *
+ * Normal reduction chooses a most-significant quotient digit q and then
+ * subtracts q*m from the number to be reduced.  Choosing q is tricky
+ * and involved (just look at lbnDiv_32 to see!) and is usually
+ * imperfect, requiring a check for correction after the subtraction.
+ *
+ * Montgomery reduction *adds* a multiple of m to the *low-order* part
+ * of the number to be reduced.  This multiple is chosen to make the
+ * low-order part of the number come out to zero.  This can be done
+ * with no trickery or error using a precomputed inverse of the modulus.
+ * In this code, the "part" is one word, but any width can be used.
+ *
+ * Repeating this step sufficiently often results in a value which
+ * is a multiple of R (a power of two, remember) but is still (since
+ * the additions were to the low-order part and thus did not increase
+ * the value of the number being reduced very much) still not much
+ * larger than m*R.  Then implicitly divide by R and subtract off
+ * m until the result is in the correct range.
+ *
+ * Since the low-order part being cancelled is less than R, the
+ * multiple of m added must have a multiplier which is at most R-1.
+ * Assuming that the input is at most m*R-1, the final number is
+ * at most m*(2*R-1)-1 = 2*m*R - m - 1, so subtracting m once from
+ * the high-order part, equivalent to subtracting m*R from the
+ * while number, produces a result which is at most m*R - m - 1,
+ * which divided by R is at most m-1.
+ *
+ * To convert *to* Montgomery form, you need a regular remainder
+ * routine, although you can just compute R*R (mod m) and do the
+ * conversion using Montgomery multiplication.  To convert *from*
+ * Montgomery form, just Montgomery reduce the number to
+ * remove the extra factor of R.
+ * 
+ * TODO: Change to a full inverse and use Karatsuba's multiplication
+ * rather than this word-at-a-time.
+ */
+#ifndef lbnMontReduce_32
+void
+lbnMontReduce_32(BNWORD32 *n, BNWORD32 const *mod, unsigned const mlen,
+                BNWORD32 inv)
+{
+       BNWORD32 t;
+       BNWORD32 c = 0;
+       unsigned len = mlen;
+
+       /* inv must be the negative inverse of mod's least significant word */
+       assert((BNWORD32)(inv * BIGLITTLE(mod[-1],mod[0])) == (BNWORD32)-1);
+
+       assert(len);
+
+       do {
+               t = lbnMulAdd1_32(n, mod, mlen, inv * BIGLITTLE(n[-1],n[0]));
+               c += lbnAdd1_32(BIGLITTLE(n-mlen,n+mlen), len, t);
+               BIGLITTLE(--n,++n);
+       } while (--len);
+
+       /*
+        * All that adding can cause an overflow past the modulus size,
+        * but it's unusual, and never by much, so a subtraction loop
+        * is the right way to deal with it.
+        * This subtraction happens infrequently - I've only ever seen it
+        * invoked once per reduction, and then just under 22.5% of the time.
+        */
+       while (c)
+               c -= lbnSubN_32(n, mod, mlen);
+       while (lbnCmp_32(n, mod, mlen) >= 0)
+               (void)lbnSubN_32(n, mod, mlen);
+}
+#endif /* !lbnMontReduce_32 */
+
+/*
+ * A couple of helpers that you might want to implement atomically
+ * in asm sometime.
+ */
+#ifndef lbnMontMul_32
+/*
+ * Multiply "num1" by "num2", modulo "mod", all of length "len", and
+ * place the result in the high half of "prod".  "inv" is the inverse
+ * of the least-significant word of the modulus, modulo 2^32.
+ * This uses numbers in Montgomery form.  Reduce using "len" and "inv".
+ *
+ * This is implemented as a macro to win on compilers that don't do
+ * inlining, since it's so trivial.
+ */
+#define lbnMontMul_32(prod, n1, n2, mod, len, inv) \
+       (lbnMulX_32(prod, n1, n2, len), lbnMontReduce_32(prod, mod, len, inv))
+#endif /* !lbnMontMul_32 */
+
+#ifndef lbnMontSquare_32
+/*
+ * Square "num", modulo "mod", both of length "len", and place the result
+ * in the high half of "prod".  "inv" is the inverse of the least-significant
+ * word of the modulus, modulo 2^32.
+ * This uses numbers in Montgomery form.  Reduce using "len" and "inv".
+ *
+ * This is implemented as a macro to win on compilers that don't do
+ * inlining, since it's so trivial.
+ */
+#define lbnMontSquare_32(prod, n, mod, len, inv) \
+       (lbnSquare_32(prod, n, len), lbnMontReduce_32(prod, mod, len, inv))
+       
+#endif /* !lbnMontSquare_32 */
+
+/*
+ * Convert a number to Montgomery form - requires mlen + nlen words
+ * of memory in "n".
+ */
+void
+lbnToMont_32(BNWORD32 *n, unsigned nlen, BNWORD32 *mod, unsigned mlen)
+{
+       /* Move n up "mlen" words */
+       lbnCopy_32(BIGLITTLE(n-mlen,n+mlen), n, nlen);
+       lbnZero_32(n, mlen);
+       /* Do the division - dump the quotient in the high-order words */
+       (void)lbnDiv_32(BIGLITTLE(n-mlen,n+mlen), n, mlen+nlen, mod, mlen);
+}
+
+/*
+ * Convert from Montgomery form.  Montgomery reduction is all that is
+ * needed.
+ */
+void
+lbnFromMont_32(BNWORD32 *n, BNWORD32 *mod, unsigned len)
+{
+       /* Zero the high words of n */
+       lbnZero_32(BIGLITTLE(n-len,n+len), len);
+       lbnMontReduce_32(n, mod, len, lbnMontInv1_32(BIGLITTLE(mod[-1],mod[0])));
+       /* Move n down len words */
+       lbnCopy_32(n, BIGLITTLE(n-len,n+len), len);
+}
+
+/*
+ * The windowed exponentiation algorithm, precomputes a table of odd
+ * powers of n up to 2^k.  It takes 2^(k-1)-1 multiplies to compute
+ * the table, and (e-1)/(k+1) multiplies (on average) to perform the
+ * exponentiation.  To minimize the sum, k must vary with e.
+ * The optimal window sizes vary with the exponent length.  Here are
+ * some selected values and the boundary cases.
+ * (An underscore _ has been inserted into some of the numbers to ensure
+ * that magic strings like 32 do not appear in this table.  It should be
+ * ignored.)
+ *
+ * At e =    1 bits, k=1   (0.000000) is best.
+ * At e =    2 bits, k=1   (0.500000) is best.
+ * At e =    4 bits, k=1   (1.500000) is best.
+ * At e =    8 bits, k=2   (3.333333) < k=1   (3.500000)
+ * At e =  1_6 bits, k=2   (6.000000) is best.
+ * At e =   26 bits, k=3   (9.250000) < k=2   (9.333333)
+ * At e =  3_2 bits, k=3  (10.750000) is best.
+ * At e =  6_4 bits, k=3  (18.750000) is best.
+ * At e =   82 bits, k=4  (23.200000) < k=3  (23.250000)
+ * At e =  128 bits, k=4 (3_2.400000) is best.
+ * At e =  242 bits, k=5  (55.1_66667) < k=4 (55.200000)
+ * At e =  256 bits, k=5  (57.500000) is best.
+ * At e =  512 bits, k=5 (100.1_66667) is best.
+ * At e =  674 bits, k=6 (127.142857) < k=5 (127.1_66667)
+ * At e = 1024 bits, k=6 (177.142857) is best.
+ * At e = 1794 bits, k=7 (287.125000) < k=6 (287.142857)
+ * At e = 2048 bits, k=7 (318.875000) is best.
+ * At e = 4096 bits, k=7 (574.875000) is best.
+ *
+ * The numbers in parentheses are the expected number of multiplications
+ * needed to do the computation.  The normal russian-peasant modular
+ * exponentiation technique always uses (e-1)/2.  For exponents as
+ * small as 192 bits (below the range of current factoring algorithms),
+ * half of the multiplies are eliminated, 45.2 as opposed to the naive
+ * 95.5.  Counting the 191 squarings as 3/4 a multiply each (squaring
+ * proper is just over half of multiplying, but the Montgomery
+ * reduction in each case is also a multiply), that's 143.25
+ * multiplies, for totals of 188.45 vs. 238.75 - a 21% savings.
+ * For larger exponents (like 512 bits), it's 483.92 vs. 639.25, a
+ * 24.3% savings.  It asymptotically approaches 25%.
+ *
+ * Given that exponents for which k>7 are useful are uncommon,
+ * a fixed size table for k <= 7 is used for simplicity.
+ * k = 8 is uzeful at 4610 bits, k = 9 at 11522 bits.
+ *
+ * The basic number of squarings needed is e-1, although a k-bit
+ * window (for k > 1) can save, on average, k-2 of those, too.
+ * That savings currently isn't counted here.  It would drive the
+ * crossover points slightly lower.
+ * (Actually, this win is also reduced in the DoubleExpMod case,
+ * meaning we'd have to split the tables.  Except for that, the
+ * multiplies by powers of the two bases are independent, so
+ * the same logic applies to each as the single case.)
+ *
+ * Table entry i is the largest number of bits in an exponent to
+ * process with a window size of i+1.  So the window never goes above 7
+ * bits, requiring 2^(7-1) = 0x40 precomputed multiples.
+ */
+#define BNEXPMOD_MAX_WINDOW    7
+static unsigned const bnExpModThreshTable[BNEXPMOD_MAX_WINDOW] = {
+       7, 25, 81, 241, 673, 1793, (unsigned)-1
+};
+
+/*
+ * Perform modular exponentiation, as fast as possible!  This uses
+ * Montgomery reduction, optimized squaring, and windowed exponentiation.
+ * The modulus "mod" MUST be odd!
+ *
+ * This returns 0 on success, -1 on out of memory.
+ *
+ * The window algorithm:
+ * The idea is to keep a running product of b1 = n^(high-order bits of exp),
+ * and then keep appending exponent bits to it.  The following patterns
+ * apply to a 3-bit window (k = 3):
+ * To append   0: square
+ * To append   1: square, multiply by n^1
+ * To append  10: square, multiply by n^1, square
+ * To append  11: square, square, multiply by n^3
+ * To append 100: square, multiply by n^1, square, square
+ * To append 101: square, square, square, multiply by n^5
+ * To append 110: square, square, multiply by n^3, square
+ * To append 111: square, square, square, multiply by n^7
+ *
+ * Since each pattern involves only one multiply, the longer the pattern
+ * the better, except that a 0 (no multiplies) can be appended directly.
+ * We precompute a table of odd powers of n, up to 2^k, and can then
+ * multiply k bits of exponent at a time.  Actually, assuming random
+ * exponents, there is on average one zero bit between needs to
+ * multiply (1/2 of the time there's none, 1/4 of the time there's 1,
+ * 1/8 of the time, there's 2, 1/32 of the time, there's 3, etc.), so
+ * you have to do one multiply per k+1 bits of exponent.
+ *
+ * The loop walks down the exponent, squaring the result buffer as
+ * it goes.  There is a wbits+1 bit lookahead buffer, buf, that is
+ * filled with the upcoming exponent bits.  (What is read after the
+ * end of the exponent is unimportant, but it is filled with zero here.)
+ * When the most-significant bit of this buffer becomes set, i.e.
+ * (buf & tblmask) != 0, we have to decide what pattern to multiply
+ * by, and when to do it.  We decide, remember to do it in future
+ * after a suitable number of squarings have passed (e.g. a pattern
+ * of "100" in the buffer requires that we multiply by n^1 immediately;
+ * a pattern of "110" calls for multiplying by n^3 after one more
+ * squaring), clear the buffer, and continue.
+ *
+ * When we start, there is one more optimization: the result buffer
+ * is implcitly one, so squaring it or multiplying by it can be
+ * optimized away.  Further, if we start with a pattern like "100"
+ * in the lookahead window, rather than placing n into the buffer
+ * and then starting to square it, we have already computed n^2
+ * to compute the odd-powers table, so we can place that into
+ * the buffer and save a squaring.
+ *
+ * This means that if you have a k-bit window, to compute n^z,
+ * where z is the high k bits of the exponent, 1/2 of the time
+ * it requires no squarings.  1/4 of the time, it requires 1
+ * squaring, ... 1/2^(k-1) of the time, it reqires k-2 squarings.
+ * And the remaining 1/2^(k-1) of the time, the top k bits are a
+ * 1 followed by k-1 0 bits, so it again only requires k-2
+ * squarings, not k-1.  The average of these is 1.  Add that
+ * to the one squaring we have to do to compute the table,
+ * and you'll see that a k-bit window saves k-2 squarings
+ * as well as reducing the multiplies.  (It actually doesn't
+ * hurt in the case k = 1, either.)
+ *
+ * n must have mlen words allocated.  Although fewer may be in use
+ * when n is passed in, all are in use on exit.
+ */
+int
+lbnExpMod_32(BNWORD32 *result, BNWORD32 const *n, unsigned nlen,
+       BNWORD32 const *e, unsigned elen, BNWORD32 *mod, unsigned mlen)
+{
+       BNWORD32 *table[1 << (BNEXPMOD_MAX_WINDOW-1)];
+                               /* Table of odd powers of n */
+       unsigned ebits;         /* Exponent bits */
+       unsigned wbits;         /* Window size */
+       unsigned tblmask;       /* Mask of exponentiation window */
+       BNWORD32 bitpos;        /* Mask of current look-ahead bit */
+       unsigned buf;           /* Buffer of exponent bits */
+       unsigned multpos;       /* Where to do pending multiply */
+       BNWORD32 const *mult;   /* What to multiply by */
+       unsigned i;             /* Loop counter */
+       int isone;              /* Flag: accum. is implicitly one */
+       BNWORD32 *a, *b;        /* Working buffers/accumulators */
+       BNWORD32 *t;            /* Pointer into the working buffers */
+       BNWORD32 inv;           /* mod^-1 modulo 2^32 */
+
+       assert(mlen);
+       assert(nlen <= mlen);
+
+       /* First, a couple of trivial cases. */
+       elen = lbnNorm_32(e, elen);
+       if (!elen) {
+               /* x ^ 0 == 1 */
+               lbnZero_32(result, mlen);
+               BIGLITTLE(result[-1],result[0]) = 1;
+               return 0;
+       }
+       ebits = lbnBits_32(e, elen);
+       if (ebits == 1) {
+               /* x ^ 1 == x */
+               if (n != result)
+                       lbnCopy_32(result, n, nlen);
+               if (mlen > nlen)
+                       lbnZero_32(BIGLITTLE(result-nlen,result+nlen),
+                                  mlen-nlen);
+               return 0;
+       }
+
+       /* Okay, now move the exponent pointer to the most-significant word */
+       e = BIGLITTLE(e-elen, e+elen-1);
+
+       /* Look up appropriate k-1 for the exponent - tblmask = 1<<(k-1) */
+       wbits = 0;
+       while (ebits > bnExpModThreshTable[wbits])
+               wbits++;
+
+       /* Allocate working storage: two product buffers and the tables. */
+       LBNALLOC(a, 2*mlen);
+       if (!a)
+               return -1;
+       LBNALLOC(b, 2*mlen);
+       if (!b) {
+               LBNFREE(a, 2*mlen);
+               return -1;
+       }
+
+       /* Convert to the appropriate table size: tblmask = 1<<(k-1) */
+       tblmask = 1u << wbits;
+
+       /* We have the result buffer available, so use it. */
+       table[0] = result;
+
+       /*
+        * Okay, we now have a minimal-sized table - expand it.
+        * This is allowed to fail!  If so, scale back the table size
+        * and proceed.
+        */
+       for (i = 1; i < tblmask; i++) {
+               LBNALLOC(t, mlen);
+               if (!t) /* Out of memory!  Quit the loop. */
+                       break;
+               table[i] = t;
+       }
+
+       /* If we stopped, with i < tblmask, shrink the tables appropriately */
+       while (tblmask > i) {
+               wbits--;
+               tblmask >>= 1;
+       }
+       /* Free up our overallocations */
+       while (--i > tblmask)
+               LBNFREE(table[i], mlen);
+
+       /* Okay, fill in the table */
+
+       /* Compute the necessary modular inverse */
+       inv = lbnMontInv1_32(mod[BIGLITTLE(-1,0)]);     /* LSW of modulus */
+
+       /* Convert n to Montgomery form */
+
+       /* Move n up "mlen" words into a */
+       t = BIGLITTLE(a-mlen, a+mlen);
+       lbnCopy_32(t, n, nlen);
+       lbnZero_32(a, mlen);
+       /* Do the division - lose the quotient into the high-order words */
+       (void)lbnDiv_32(t, a, mlen+nlen, mod, mlen);
+       /* Copy into first table entry */
+       lbnCopy_32(table[0], a, mlen);
+
+       /* Square a into b */
+       lbnMontSquare_32(b, a, mod, mlen, inv);
+
+       /* Use high half of b to initialize the table */
+       t = BIGLITTLE(b-mlen, b+mlen);
+       for (i = 1; i < tblmask; i++) {
+               lbnMontMul_32(a, t, table[i-1], mod, mlen, inv);
+               lbnCopy_32(table[i], BIGLITTLE(a-mlen, a+mlen), mlen);
+       }
+
+       /* We might use b = n^2 later... */
+
+       /* Initialze the fetch pointer */
+       bitpos = (BNWORD32)1 << ((ebits-1) & (32-1));   /* Initialize mask */
+
+       /* This should point to the msbit of e */
+       assert((*e & bitpos) != 0);
+
+       /*
+        * Pre-load the window.  Becuase the window size is
+        * never larger than the exponent size, there is no need to
+        * detect running off the end of e in here.
+        *
+        * The read-ahead is controlled by elen and the bitpos mask.
+        * Note that this is *ahead* of ebits, which tracks the
+        * most significant end of the window.  The purpose of this
+        * initialization is to get the two wbits+1 bits apart,
+        * like they should be.
+        *
+        * Note that bitpos and e1len together keep track of the
+        * lookahead read pointer in the exponent that is used here.
+        */
+       buf = 0;
+       for (i = 0; i <= wbits; i++) {
+               buf = (buf << 1) | ((*e & bitpos) != 0);
+               bitpos >>= 1;
+               if (!bitpos) {
+                       BIGLITTLE(e++,e--);
+                       bitpos = (BNWORD32)1 << (32-1);
+                       elen--;
+               }
+       }
+       assert(buf & tblmask);
+
+       /*
+        * Set the pending multiply positions to a location that will
+        * never be encountered, thus ensuring that nothing will happen
+        * until the need for a multiply appears and one is scheduled.
+        */
+       multpos = ebits;        /* A NULL value */
+       mult = 0;       /* Force a crash if we use these */
+
+       /*
+        * Okay, now begins the real work.  The first step is
+        * slightly magic, so it's done outside the main loop,
+        * but it's very similar to what's inside.
+        */
+       ebits--;        /* Start processing the first bit... */
+       isone = 1;
+
+       /*
+        * This is just like the multiply in the loop, except that
+        * - We know the msbit of buf is set, and
+        * - We have the extra value n^2 floating around.
+        * So, do the usual computation, and if the result is that
+        * the buffer should be multiplied by n^1 immediately
+        * (which we'd normally then square), we multiply it
+        * (which reduces to a copy, which reduces to setting a flag)
+        * by n^2 and skip the squaring.  Thus, we do the
+        * multiply and the squaring in one step.
+        */
+       assert(buf & tblmask);
+       multpos = ebits - wbits;
+       while ((buf & 1) == 0) {
+               buf >>= 1;
+               multpos++;
+       }
+       /* Intermediates can wrap, but final must NOT */
+       assert(multpos <= ebits);
+       mult = table[buf>>1];
+       buf = 0;
+
+       /* Special case: use already-computed value sitting in buffer */
+       if (multpos == ebits)
+               isone = 0;
+
+       /*
+        * At this point, the buffer (which is the high half of b) holds
+        * either 1 (implicitly, as the "isone" flag is set), or n^2.
+        */
+
+       /*
+        * The main loop.  The procedure is:
+        * - Advance the window
+        * - If the most-significant bit of the window is set,
+        *   schedule a multiply for the appropriate time in the
+        *   future (may be immediately)
+        * - Perform any pending multiples
+        * - Check for termination
+        * - Square the buffer
+        *
+        * At any given time, the acumulated product is held in
+        * the high half of b.
+        */
+       for (;;) {
+               ebits--;
+
+               /* Advance the window */
+               assert(buf < tblmask);
+               buf <<= 1;
+               /*
+                * This reads ahead of the current exponent position
+                * (controlled by ebits), so we have to be able to read
+                * past the lsb of the exponents without error.
+                */
+               if (elen) {
+                       buf |= ((*e & bitpos) != 0);
+                       bitpos >>= 1;
+                       if (!bitpos) {
+                               BIGLITTLE(e++,e--);
+                               bitpos = (BNWORD32)1 << (32-1);
+                               elen--;
+                       }
+               }
+
+               /* Examine the window for pending multiplies */
+               if (buf & tblmask) {
+                       multpos = ebits - wbits;
+                       while ((buf & 1) == 0) {
+                               buf >>= 1;
+                               multpos++;
+                       }
+                       /* Intermediates can wrap, but final must NOT */
+                       assert(multpos <= ebits);
+                       mult = table[buf>>1];
+                       buf = 0;
+               }
+
+               /* If we have a pending multiply, do it */
+               if (ebits == multpos) {
+                       /* Multiply by the table entry remembered previously */
+                       t = BIGLITTLE(b-mlen, b+mlen);
+                       if (isone) {
+                               /* Multiply by 1 is a trivial case */
+                               lbnCopy_32(t, mult, mlen);
+                               isone = 0;
+                       } else {
+                               lbnMontMul_32(a, t, mult, mod, mlen, inv);
+                               /* Swap a and b */
+                               t = a; a = b; b = t;
+                       }
+               }
+
+               /* Are we done? */
+               if (!ebits)
+                       break;
+
+               /* Square the input */
+               if (!isone) {
+                       t = BIGLITTLE(b-mlen, b+mlen);
+                       lbnMontSquare_32(a, t, mod, mlen, inv);
+                       /* Swap a and b */
+                       t = a; a = b; b = t;
+               }
+       } /* for (;;) */
+
+       assert(!isone);
+       assert(!buf);
+
+       /* DONE! */
+
+       /* Convert result out of Montgomery form */
+       t = BIGLITTLE(b-mlen, b+mlen);
+       lbnCopy_32(b, t, mlen);
+       lbnZero_32(t, mlen);
+       lbnMontReduce_32(b, mod, mlen, inv);
+       lbnCopy_32(result, t, mlen);
+       /*
+        * Clean up - free intermediate storage.
+        * Do NOT free table[0], which is the result
+        * buffer.
+        */
+       while (--tblmask)
+               LBNFREE(table[tblmask], mlen);
+       LBNFREE(b, 2*mlen);
+       LBNFREE(a, 2*mlen);
+
+       return 0;       /* Success */
+}
+
+/*
+ * Compute and return n1^e1 * n2^e2 mod "mod".
+ * result may be either input buffer, or something separate.
+ * It must be "mlen" words long.
+ *
+ * There is a current position in the exponents, which is kept in e1bits.
+ * (The exponents are swapped if necessary so e1 is the longer of the two.)
+ * At any given time, the value in the accumulator is
+ * n1^(e1>>e1bits) * n2^(e2>>e1bits) mod "mod".
+ * As e1bits is counted down, this is updated, by squaring it and doing
+ * any necessary multiplies.
+ * To decide on the necessary multiplies, two windows, each w1bits+1 bits
+ * wide, are maintained in buf1 and buf2, which read *ahead* of the
+ * e1bits position (with appropriate handling of the case when e1bits
+ * drops below w1bits+1).  When the most-significant bit of either window
+ * becomes set, indicating that something needs to be multiplied by
+ * the accumulator or it will get out of sync, the window is examined
+ * to see which power of n1 or n2 to multiply by, and when (possibly
+ * later, if the power is greater than 1) the multiply should take
+ * place.  Then the multiply and its location are remembered and the
+ * window is cleared.
+ *
+ * If we had every power of n1 in the table, the multiply would always
+ * be w1bits steps in the future.  But we only keep the odd powers,
+ * so instead of waiting w1bits squarings and then multiplying
+ * by n1^k, we wait w1bits-k squarings and multiply by n1.
+ *
+ * Actually, w2bits can be less than w1bits, but the window is the same
+ * size, to make it easier to keep track of where we're reading.  The
+ * appropriate number of low-order bits of the window are just ignored.
+ */
+int
+lbnDoubleExpMod_32(BNWORD32 *result,
+                   BNWORD32 const *n1, unsigned n1len,
+                   BNWORD32 const *e1, unsigned e1len,
+                   BNWORD32 const *n2, unsigned n2len,
+                   BNWORD32 const *e2, unsigned e2len,
+                   BNWORD32 *mod, unsigned mlen)
+{
+       BNWORD32 *table1[1 << (BNEXPMOD_MAX_WINDOW-1)];
+                                       /* Table of odd powers of n1 */
+       BNWORD32 *table2[1 << (BNEXPMOD_MAX_WINDOW-1)];
+                                       /* Table of odd powers of n2 */
+       unsigned e1bits, e2bits;        /* Exponent bits */
+       unsigned w1bits, w2bits;        /* Window sizes */
+       unsigned tblmask;               /* Mask of exponentiation window */
+       BNWORD32 bitpos;                /* Mask of current look-ahead bit */
+       unsigned buf1, buf2;            /* Buffer of exponent bits */
+       unsigned mult1pos, mult2pos;    /* Where to do pending multiply */
+       BNWORD32 const *mult1, *mult2;  /* What to multiply by */
+       unsigned i;                     /* Loop counter */
+       int isone;                      /* Flag: accum. is implicitly one */
+       BNWORD32 *a, *b;                /* Working buffers/accumulators */
+       BNWORD32 *t;                    /* Pointer into the working buffers */
+       BNWORD32 inv;                   /* mod^-1 modulo 2^32 */
+
+       assert(mlen);
+       assert(n1len <= mlen);
+       assert(n2len <= mlen);
+
+       /* First, a couple of trivial cases. */
+       e1len = lbnNorm_32(e1, e1len);
+       e2len = lbnNorm_32(e2, e2len);
+
+       /* Ensure that the first exponent is the longer */
+       e1bits = lbnBits_32(e1, e1len);
+       e2bits = lbnBits_32(e2, e2len);
+       if (e1bits < e2bits) {
+               i = e1len; e1len = e2len; e2len = i;
+               i = e1bits; e1bits = e2bits; e2bits = i;
+               t = (BNWORD32 *)n1; n1 = n2; n2 = t; 
+               t = (BNWORD32 *)e1; e1 = e2; e2 = t; 
+       }
+       assert(e1bits >= e2bits);
+
+       /* Handle a trivial case */
+       if (!e2len)
+               return lbnExpMod_32(result, n1, n1len, e1, e1len, mod, mlen);
+       assert(e2bits);
+
+       /* The code below breaks if the exponents aren't at least 2 bits */
+       if (e1bits == 1) {
+               assert(e2bits == 1);
+
+               LBNALLOC(a, n1len+n2len);
+               if (!a)
+                       return -1;
+
+               lbnMul_32(a, n1, n1len, n2, n2len);
+               /* Do a direct modular reduction */
+               if (n1len + n2len >= mlen)
+                       (void)lbnDiv_32(a+mlen, a, n1len+n2len, mod, mlen);
+               lbnCopy_32(result, a, mlen);
+               LBNFREE(a, n1len+n2len);
+               return 0;
+       }
+
+       /* Okay, now move the exponent pointers to the most-significant word */
+       e1 = BIGLITTLE(e1-e1len, e1+e1len-1);
+       e2 = BIGLITTLE(e2-e2len, e2+e2len-1);
+
+       /* Look up appropriate k-1 for the exponent - tblmask = 1<<(k-1) */
+       w1bits = 0;
+       while (e1bits > bnExpModThreshTable[w1bits])
+               w1bits++;
+       w2bits = 0;
+       while (e2bits > bnExpModThreshTable[w2bits])
+               w2bits++;
+
+       assert(w1bits >= w2bits);
+
+       /* Allocate working storage: two product buffers and the tables. */
+       LBNALLOC(a, 2*mlen);
+       if (!a)
+               return -1;
+       LBNALLOC(b, 2*mlen);
+       if (!b) {
+               LBNFREE(a, 2*mlen);
+               return -1;
+       }
+
+       /* Convert to the appropriate table size: tblmask = 1<<(k-1) */
+       tblmask = 1u << w1bits;
+       /* Use buf2 for its size, temporarily */
+       buf2 = 1u << w2bits;
+
+       LBNALLOC(t, mlen);
+       if (!t) {
+               LBNFREE(b, 2*mlen);
+               LBNFREE(a, 2*mlen);
+               return -1;
+       }
+       table1[0] = t;
+       table2[0] = result;
+
+       /*
+        * Okay, we now have some minimal-sized tables - expand them.
+        * This is allowed to fail!  If so, scale back the table sizes
+        * and proceed.  We allocate both tables at the same time
+        * so if it fails partway through, they'll both be a reasonable
+        * size rather than one huge and one tiny.
+        * When i passes buf2 (the number of entries in the e2 window,
+        * which may be less than the number of entries in the e1 window),
+        * stop allocating e2 space.
+        */
+       for (i = 1; i < tblmask; i++) {
+               LBNALLOC(t, mlen);
+               if (!t) /* Out of memory!  Quit the loop. */
+                       break;
+               table1[i] = t;
+               if (i < buf2) {
+                       LBNALLOC(t, mlen);
+                       if (!t) {
+                               LBNFREE(table1[i], mlen);
+                               break;
+                       }
+                       table2[i] = t;
+               }
+       }
+
+       /* If we stopped, with i < tblmask, shrink the tables appropriately */
+       while (tblmask > i) {
+               w1bits--;
+               tblmask >>= 1;
+       }
+       /* Free up our overallocations */
+       while (--i > tblmask) {
+               if (i < buf2)
+                       LBNFREE(table2[i], mlen);
+               LBNFREE(table1[i], mlen);
+       }
+       /* And shrink the second window too, if needed */
+       if (w2bits > w1bits) {
+               w2bits = w1bits;
+               buf2 = tblmask;
+       }
+
+       /*
+        * From now on, use the w2bits variable for the difference
+        * between w1bits and w2bits.
+        */
+       w2bits = w1bits-w2bits;
+
+       /* Okay, fill in the tables */
+
+       /* Compute the necessary modular inverse */
+       inv = lbnMontInv1_32(mod[BIGLITTLE(-1,0)]);     /* LSW of modulus */
+
+       /* Convert n1 to Montgomery form */
+
+       /* Move n1 up "mlen" words into a */
+       t = BIGLITTLE(a-mlen, a+mlen);
+       lbnCopy_32(t, n1, n1len);
+       lbnZero_32(a, mlen);
+       /* Do the division - lose the quotient into the high-order words */
+       (void)lbnDiv_32(t, a, mlen+n1len, mod, mlen);
+       /* Copy into first table entry */
+       lbnCopy_32(table1[0], a, mlen);
+
+       /* Square a into b */
+       lbnMontSquare_32(b, a, mod, mlen, inv);
+
+       /* Use high half of b to initialize the first table */
+       t = BIGLITTLE(b-mlen, b+mlen);
+       for (i = 1; i < tblmask; i++) {
+               lbnMontMul_32(a, t, table1[i-1], mod, mlen, inv);
+               lbnCopy_32(table1[i], BIGLITTLE(a-mlen, a+mlen), mlen);
+       }
+
+       /* Convert n2 to Montgomery form */
+
+       t = BIGLITTLE(a-mlen, a+mlen);
+       /* Move n2 up "mlen" words into a */
+       lbnCopy_32(t, n2, n2len);
+       lbnZero_32(a, mlen);
+       /* Do the division - lose the quotient into the high-order words */
+       (void)lbnDiv_32(t, a, mlen+n2len, mod, mlen);
+       /* Copy into first table entry */
+       lbnCopy_32(table2[0], a, mlen);
+
+       /* Square it into a */
+       lbnMontSquare_32(a, table2[0], mod, mlen, inv);
+       /* Copy to b, low half */
+       lbnCopy_32(b, t, mlen);
+
+       /* Use b to initialize the second table */
+       for (i = 1; i < buf2; i++) {
+               lbnMontMul_32(a, b, table2[i-1], mod, mlen, inv);
+               lbnCopy_32(table2[i], t, mlen);
+       }
+
+       /*
+        * Okay, a recap: at this point, the low part of b holds
+        * n2^2, the high part holds n1^2, and the tables are
+        * initialized with the odd powers of n1 and n2 from 1
+        * through 2*tblmask-1 and 2*buf2-1.
+        *
+        * We might use those squares in b later, or we might not.
+        */
+
+       /* Initialze the fetch pointer */
+       bitpos = (BNWORD32)1 << ((e1bits-1) & (32-1));  /* Initialize mask */
+
+       /* This should point to the msbit of e1 */
+       assert((*e1 & bitpos) != 0);
+
+       /*
+        * Pre-load the windows.  Becuase the window size is
+        * never larger than the exponent size, there is no need to
+        * detect running off the end of e1 in here.
+        *
+        * The read-ahead is controlled by e1len and the bitpos mask.
+        * Note that this is *ahead* of e1bits, which tracks the
+        * most significant end of the window.  The purpose of this
+        * initialization is to get the two w1bits+1 bits apart,
+        * like they should be.
+        *
+        * Note that bitpos and e1len together keep track of the
+        * lookahead read pointer in the exponent that is used here.
+        * e2len is not decremented, it is only ever compared with
+        * e1len as *that* is decremented.
+        */
+       buf1 = buf2 = 0;
+       for (i = 0; i <= w1bits; i++) {
+               buf1 = (buf1 << 1) | ((*e1 & bitpos) != 0);
+               if (e1len <= e2len)
+                       buf2 = (buf2 << 1) | ((*e2 & bitpos) != 0);
+               bitpos >>= 1;
+               if (!bitpos) {
+                       BIGLITTLE(e1++,e1--);
+                       if (e1len <= e2len)
+                               BIGLITTLE(e2++,e2--);
+                       bitpos = (BNWORD32)1 << (32-1);
+                       e1len--;
+               }
+       }
+       assert(buf1 & tblmask);
+
+       /*
+        * Set the pending multiply positions to a location that will
+        * never be encountered, thus ensuring that nothing will happen
+        * until the need for a multiply appears and one is scheduled.
+        */
+       mult1pos = mult2pos = e1bits;   /* A NULL value */
+       mult1 = mult2 = 0;      /* Force a crash if we use these */
+
+       /*
+        * Okay, now begins the real work.  The first step is
+        * slightly magic, so it's done outside the main loop,
+        * but it's very similar to what's inside.
+        */
+       isone = 1;      /* Buffer is implicitly 1, so replace * by copy */
+       e1bits--;       /* Start processing the first bit... */
+
+       /*
+        * This is just like the multiply in the loop, except that
+        * - We know the msbit of buf1 is set, and
+        * - We have the extra value n1^2 floating around.
+        * So, do the usual computation, and if the result is that
+        * the buffer should be multiplied by n1^1 immediately
+        * (which we'd normally then square), we multiply it
+        * (which reduces to a copy, which reduces to setting a flag)
+        * by n1^2 and skip the squaring.  Thus, we do the
+        * multiply and the squaring in one step.
+        */
+       assert(buf1 & tblmask);
+       mult1pos = e1bits - w1bits;
+       while ((buf1 & 1) == 0) {
+               buf1 >>= 1;
+               mult1pos++;
+       }
+       /* Intermediates can wrap, but final must NOT */
+       assert(mult1pos <= e1bits);
+       mult1 = table1[buf1>>1];
+       buf1 = 0;
+
+       /* Special case: use already-computed value sitting in buffer */
+       if (mult1pos == e1bits)
+               isone = 0;
+
+       /*
+        * The first multiply by a power of n2.  Similar, but
+        * we might not even want to schedule a multiply if e2 is
+        * shorter than e1, and the window might be shorter so
+        * we have to leave the low w2bits bits alone.
+        */
+       if (buf2 & tblmask) {
+               /* Remember low-order bits for later */
+               i = buf2 & ((1u << w2bits) - 1);
+               buf2 >>= w2bits;
+               mult2pos = e1bits - w1bits + w2bits;
+               while ((buf2 & 1) == 0) {
+                       buf2 >>= 1;
+                       mult2pos++;
+               }
+               assert(mult2pos <= e1bits);
+               mult2 = table2[buf2>>1];
+               buf2 = i;
+
+               if (mult2pos == e1bits) {
+                       t = BIGLITTLE(b-mlen, b+mlen);
+                       if (isone) {
+                               lbnCopy_32(t, b, mlen); /* Copy low to high */
+                               isone = 0;
+                       } else {
+                               lbnMontMul_32(a, t, b, mod, mlen, inv);
+                               t = a; a = b; b = t;
+                       }
+               }
+       }
+
+       /*
+        * At this point, the buffer (which is the high half of b)
+        * holds either 1 (implicitly, as the "isone" flag is set),
+        * n1^2, n2^2 or n1^2 * n2^2.
+        */
+
+       /*
+        * The main loop.  The procedure is:
+        * - Advance the windows
+        * - If the most-significant bit of a window is set,
+        *   schedule a multiply for the appropriate time in the
+        *   future (may be immediately)
+        * - Perform any pending multiples
+        * - Check for termination
+        * - Square the buffers
+        *
+        * At any given time, the acumulated product is held in
+        * the high half of b.
+        */
+       for (;;) {
+               e1bits--;
+
+               /* Advance the windows */
+               assert(buf1 < tblmask);
+               buf1 <<= 1;
+               assert(buf2 < tblmask);
+               buf2 <<= 1;
+               /*
+                * This reads ahead of the current exponent position
+                * (controlled by e1bits), so we have to be able to read
+                * past the lsb of the exponents without error.
+                */
+               if (e1len) {
+                       buf1 |= ((*e1 & bitpos) != 0);
+                       if (e1len <= e2len)
+                               buf2 |= ((*e2 & bitpos) != 0);
+                       bitpos >>= 1;
+                       if (!bitpos) {
+                               BIGLITTLE(e1++,e1--);
+                               if (e1len <= e2len)
+                                       BIGLITTLE(e2++,e2--);
+                               bitpos = (BNWORD32)1 << (32-1);
+                               e1len--;
+                       }
+               }
+
+               /* Examine the first window for pending multiplies */
+               if (buf1 & tblmask) {
+                       mult1pos = e1bits - w1bits;
+                       while ((buf1 & 1) == 0) {
+                               buf1 >>= 1;
+                               mult1pos++;
+                       }
+                       /* Intermediates can wrap, but final must NOT */
+                       assert(mult1pos <= e1bits);
+                       mult1 = table1[buf1>>1];
+                       buf1 = 0;
+               }
+
+               /*
+                * Examine the second window for pending multiplies.
+                * Window 2 can be smaller than window 1, but we
+                * keep the same number of bits in buf2, so we need
+                * to ignore any low-order bits in the buffer when
+                * computing what to multiply by, and recompute them
+                * later.
+                */
+               if (buf2 & tblmask) {
+                       /* Remember low-order bits for later */
+                       i = buf2 & ((1u << w2bits) - 1);
+                       buf2 >>= w2bits;
+                       mult2pos = e1bits - w1bits + w2bits;
+                       while ((buf2 & 1) == 0) {
+                               buf2 >>= 1;
+                               mult2pos++;
+                       }
+                       assert(mult2pos <= e1bits);
+                       mult2 = table2[buf2>>1];
+                       buf2 = i;
+               }
+
+
+               /* If we have a pending multiply for e1, do it */
+               if (e1bits == mult1pos) {
+                       /* Multiply by the table entry remembered previously */
+                       t = BIGLITTLE(b-mlen, b+mlen);
+                       if (isone) {
+                               /* Multiply by 1 is a trivial case */
+                               lbnCopy_32(t, mult1, mlen);
+                               isone = 0;
+                       } else {
+                               lbnMontMul_32(a, t, mult1, mod, mlen, inv);
+                               /* Swap a and b */
+                               t = a; a = b; b = t;
+                       }
+               }
+
+               /* If we have a pending multiply for e2, do it */
+               if (e1bits == mult2pos) {
+                       /* Multiply by the table entry remembered previously */
+                       t = BIGLITTLE(b-mlen, b+mlen);
+                       if (isone) {
+                               /* Multiply by 1 is a trivial case */
+                               lbnCopy_32(t, mult2, mlen);
+                               isone = 0;
+                       } else {
+                               lbnMontMul_32(a, t, mult2, mod, mlen, inv);
+                               /* Swap a and b */
+                               t = a; a = b; b = t;
+                       }
+               }
+
+               /* Are we done? */
+               if (!e1bits)
+                       break;
+
+               /* Square the buffer */
+               if (!isone) {
+                       t = BIGLITTLE(b-mlen, b+mlen);
+                       lbnMontSquare_32(a, t, mod, mlen, inv);
+                       /* Swap a and b */
+                       t = a; a = b; b = t;
+               }
+       } /* for (;;) */
+
+       assert(!isone);
+       assert(!buf1);
+       assert(!buf2);
+
+       /* DONE! */
+
+       /* Convert result out of Montgomery form */
+       t = BIGLITTLE(b-mlen, b+mlen);
+       lbnCopy_32(b, t, mlen);
+       lbnZero_32(t, mlen);
+       lbnMontReduce_32(b, mod, mlen, inv);
+       lbnCopy_32(result, t, mlen);
+
+       /* Clean up - free intermediate storage */
+       buf2 = tblmask >> w2bits;
+       while (--tblmask) {
+               if (tblmask < buf2)
+                       LBNFREE(table2[tblmask], mlen);
+               LBNFREE(table1[tblmask], mlen);
+       }
+       t = table1[0];
+       LBNFREE(t, mlen);
+       LBNFREE(b, 2*mlen);
+       LBNFREE(a, 2*mlen);
+
+       return 0;       /* Success */
+}
+
+/*
+ * 2^exp (mod mod).  This is an optimized version for use in Fermat
+ * tests.  The input value of n is ignored; it is returned with
+ * "mlen" words valid.
+ */
+int
+lbnTwoExpMod_32(BNWORD32 *n, BNWORD32 const *exp, unsigned elen,
+       BNWORD32 *mod, unsigned mlen)
+{
+       unsigned e;     /* Copy of high words of the exponent */
+       unsigned bits;  /* Assorted counter of bits */
+       BNWORD32 const *bitptr;
+       BNWORD32 bitword, bitpos;
+       BNWORD32 *a, *b, *a1;
+       BNWORD32 inv;
+
+       assert(mlen);
+
+       bitptr = BIGLITTLE(exp-elen, exp+elen-1);
+       bitword = *bitptr;
+       assert(bitword);
+
+       /* Clear n for future use. */
+       lbnZero_32(n, mlen);
+
+       bits = lbnBits_32(exp, elen);
+       
+       /* First, a couple of trivial cases. */
+       if (bits <= 1) {
+               /* 2 ^ 0 == 1,  2 ^ 1 == 2 */
+               BIGLITTLE(n[-1],n[0]) = (BNWORD32)1<<elen;
+               return 0;
+       }
+
+       /* Set bitpos to the most significant bit */
+       bitpos = (BNWORD32)1 << ((bits-1) & (32-1));
+
+       /* Now, count the bits in the modulus. */
+       bits = lbnBits_32(mod, mlen);
+       assert(bits > 1);       /* a 1-bit modulus is just stupid... */
+
+       /*
+        * We start with 1<<e, where "e" is as many high bits of the
+        * exponent as we can manage without going over the modulus.
+        * This first loop finds "e".
+        */
+       e = 1;
+       while (elen) {
+               /* Consume the first bit */
+               bitpos >>= 1;
+               if (!bitpos) {
+                       if (!--elen)
+                               break;
+                       bitword = BIGLITTLE(*++bitptr,*--bitptr);
+                       bitpos = (BNWORD32)1<<(32-1);
+               }
+               e = (e << 1) | ((bitpos & bitword) != 0);
+               if (e >= bits) {        /* Overflow!  Back out. */
+                       e >>= 1;
+                       break;
+               }
+       }
+       /*
+        * The bit in "bitpos" being examined by the bit buffer has NOT
+        * been consumed yet.  This may be past the end of the exponent,
+        * in which case elen == 1.
+        */
+
+       /* Okay, now, set bit "e" in n.  n is already zero. */
+       inv = (BNWORD32)1 << (e & (32-1));
+       e /= 32;
+       BIGLITTLE(n[-e-1],n[e]) = inv;
+       /*
+        * The effective length of n in words is now "e+1".
+        * This is used a little bit later.
+        */
+
+       if (!elen)
+               return 0;       /* That was easy! */
+
+       /*
+        * We have now processed the first few bits.  The next step
+        * is to convert this to Montgomery form for further squaring.
+        */
+
+       /* Allocate working storage: two product buffers */
+       LBNALLOC(a, 2*mlen);
+       if (!a)
+               return -1;
+       LBNALLOC(b, 2*mlen);
+       if (!b) {
+               LBNFREE(a, 2*mlen);
+               return -1;
+       }
+
+       /* Convert n to Montgomery form */
+       inv = BIGLITTLE(mod[-1],mod[0]);        /* LSW of modulus */
+       assert(inv & 1);        /* Modulus must be odd */
+       inv = lbnMontInv1_32(inv);
+       /* Move n (length e+1, remember?) up "mlen" words into b */
+       /* Note that we lie about a1 for a bit - it's pointing to b */
+       a1 = BIGLITTLE(b-mlen,b+mlen);
+       lbnCopy_32(a1, n, e+1);
+       lbnZero_32(b, mlen);
+       /* Do the division - dump the quotient into the high-order words */
+       (void)lbnDiv_32(a1, b, mlen+e+1, mod, mlen);
+       /*
+        * Now do the first squaring and modular reduction to put
+        * the number up in a1 where it belongs.
+        */
+       lbnMontSquare_32(a, b, mod, mlen, inv);
+       /* Fix up a1 to point to where it should go. */
+       a1 = BIGLITTLE(a-mlen,a+mlen);
+
+       /*
+        * Okay, now, a1 holds the number being accumulated, and
+        * b is a scratch register.  Start working:
+        */
+       for (;;) {
+               /*
+                * Is the bit set?  If so, double a1 as well.
+                * A modular doubling like this is very cheap.
+                */
+               if (bitpos & bitword) {
+                       /*
+                        * Double the number.  If there was a carry out OR
+                        * the result is greater than the modulus, subract
+                        * the modulus.
+                        */
+                       if (lbnDouble_32(a1, mlen) ||
+                           lbnCmp_32(a1, mod, mlen) > 0)
+                               (void)lbnSubN_32(a1, mod, mlen);
+               }
+
+               /* Advance to the next exponent bit */
+               bitpos >>= 1;
+               if (!bitpos) {
+                       if (!--elen)
+                               break;  /* Done! */
+                       bitword = BIGLITTLE(*++bitptr,*--bitptr);
+                       bitpos = (BNWORD32)1<<(32-1);
+               }
+
+               /*
+                * The elen/bitword/bitpos bit buffer is known to be
+                * non-empty, i.e. there is at least one more unconsumed bit.
+                * Thus, it's safe to square the number.
+                */
+               lbnMontSquare_32(b, a1, mod, mlen, inv);
+               /* Rename result (in b) back to a (a1, really). */
+               a1 = b; b = a; a = a1;
+               a1 = BIGLITTLE(a-mlen,a+mlen);
+       }
+
+       /* DONE!  Just a little bit of cleanup... */
+
+       /*
+        * Convert result out of Montgomery form... this is
+        * just a Montgomery reduction.
+        */
+       lbnCopy_32(a, a1, mlen);
+       lbnZero_32(a1, mlen);
+       lbnMontReduce_32(a, mod, mlen, inv);
+       lbnCopy_32(n, a1, mlen);
+
+       /* Clean up - free intermediate storage */
+       LBNFREE(b, 2*mlen);
+       LBNFREE(a, 2*mlen);
+
+       return 0;       /* Success */
+}
+
+
+/*
+ * Returns a substring of the big-endian array of bytes representation
+ * of the bignum array based on two parameters, the least significant
+ * byte number (0 to start with the least significant byte) and the
+ * length.  I.e. the number returned is a representation of
+ * (bn / 2^(8*lsbyte)) % 2 ^ (8*buflen).
+ *
+ * It is an error if the bignum is not at least buflen + lsbyte bytes
+ * long.
+ *
+ * This code assumes that the compiler has the minimal intelligence 
+ * neded to optimize divides and modulo operations on an unsigned data
+ * type with a power of two.
+ */
+void
+lbnExtractBigBytes_32(BNWORD32 const *n, unsigned char *buf,
+       unsigned lsbyte, unsigned buflen)
+{
+       BNWORD32 t = 0; /* Needed to shut up uninitialized var warnings */
+       unsigned shift;
+
+       lsbyte += buflen;
+
+       shift = (8 * lsbyte) % 32;
+       lsbyte /= (32/8);       /* Convert to word offset */
+       BIGLITTLE(n -= lsbyte, n += lsbyte);
+
+       if (shift)
+               t = BIGLITTLE(n[-1],n[0]);
+
+       while (buflen--) {
+               if (!shift) {
+                       t = BIGLITTLE(*n++,*--n);
+                       shift = 32;
+               }
+               shift -= 8;
+               *buf++ = (unsigned char)(t>>shift);
+       }
+}
+
+/*
+ * Merge a big-endian array of bytes into a bignum array.
+ * The array had better be big enough.  This is
+ * equivalent to extracting the entire bignum into a
+ * large byte array, copying the input buffer into the
+ * middle of it, and converting back to a bignum.
+ *
+ * The buf is "len" bytes long, and its *last* byte is at
+ * position "lsbyte" from the end of the bignum.
+ *
+ * Note that this is a pain to get right.  Fortunately, it's hardly
+ * critical for efficiency.
+ */
+void
+lbnInsertBigBytes_32(BNWORD32 *n, unsigned char const *buf,
+                  unsigned lsbyte,  unsigned buflen)
+{
+       BNWORD32 t = 0; /* Shut up uninitialized varibale warnings */
+
+       lsbyte += buflen;
+
+       BIGLITTLE(n -= lsbyte/(32/8), n += lsbyte/(32/8));
+
+       /* Load up leading odd bytes */
+       if (lsbyte % (32/8)) {
+               t = BIGLITTLE(*--n,*n++);
+               t >>= (lsbyte * 8) % 32;
+       }
+
+       /* The main loop - merge into t, storing at each word boundary. */
+       while (buflen--) {
+               t = (t << 8) | *buf++;
+               if ((--lsbyte % (32/8)) == 0)
+                       BIGLITTLE(*n++,*--n) = t;
+       }
+
+       /* Merge odd bytes in t into last word */
+       lsbyte = (lsbyte * 8) % 32;
+       if (lsbyte) {
+               t <<= lsbyte;
+               t |= (((BNWORD32)1 << lsbyte) - 1) & BIGLITTLE(n[0],n[-1]);
+               BIGLITTLE(n[0],n[-1]) = t;
+       }
+
+       return;
+}
+
+/*
+ * Returns a substring of the little-endian array of bytes representation
+ * of the bignum array based on two parameters, the least significant
+ * byte number (0 to start with the least significant byte) and the
+ * length.  I.e. the number returned is a representation of
+ * (bn / 2^(8*lsbyte)) % 2 ^ (8*buflen).
+ *
+ * It is an error if the bignum is not at least buflen + lsbyte bytes
+ * long.
+ *
+ * This code assumes that the compiler has the minimal intelligence 
+ * neded to optimize divides and modulo operations on an unsigned data
+ * type with a power of two.
+ */
+void
+lbnExtractLittleBytes_32(BNWORD32 const *n, unsigned char *buf,
+       unsigned lsbyte, unsigned buflen)
+{
+       BNWORD32 t = 0; /* Needed to shut up uninitialized var warnings */
+
+       BIGLITTLE(n -= lsbyte/(32/8), n += lsbyte/(32/8));
+
+       if (lsbyte % (32/8)) {
+               t = BIGLITTLE(*--n,*n++);
+               t >>= (lsbyte % (32/8)) * 8 ;
+       }
+
+       while (buflen--) {
+               if ((lsbyte++ % (32/8)) == 0)
+                       t = BIGLITTLE(*--n,*n++);
+               *buf++ = (unsigned char)t;
+               t >>= 8;
+       }
+}
+
+/*
+ * Merge a little-endian array of bytes into a bignum array.
+ * The array had better be big enough.  This is
+ * equivalent to extracting the entire bignum into a
+ * large byte array, copying the input buffer into the
+ * middle of it, and converting back to a bignum.
+ *
+ * The buf is "len" bytes long, and its first byte is at
+ * position "lsbyte" from the end of the bignum.
+ *
+ * Note that this is a pain to get right.  Fortunately, it's hardly
+ * critical for efficiency.
+ */
+void
+lbnInsertLittleBytes_32(BNWORD32 *n, unsigned char const *buf,
+                  unsigned lsbyte,  unsigned buflen)
+{
+       BNWORD32 t = 0; /* Shut up uninitialized varibale warnings */
+
+       /* Move to most-significant end */
+       lsbyte += buflen;
+       buf += buflen;
+
+       BIGLITTLE(n -= lsbyte/(32/8), n += lsbyte/(32/8));
+
+       /* Load up leading odd bytes */
+       if (lsbyte % (32/8)) {
+               t = BIGLITTLE(*--n,*n++);
+               t >>= (lsbyte * 8) % 32;
+       }
+
+       /* The main loop - merge into t, storing at each word boundary. */
+       while (buflen--) {
+               t = (t << 8) | *--buf;
+               if ((--lsbyte % (32/8)) == 0)
+                       BIGLITTLE(*n++,*--n) = t;
+       }
+
+       /* Merge odd bytes in t into last word */
+       lsbyte = (lsbyte * 8) % 32;
+       if (lsbyte) {
+               t <<= lsbyte;
+               t |= (((BNWORD32)1 << lsbyte) - 1) & BIGLITTLE(n[0],n[-1]);
+               BIGLITTLE(n[0],n[-1]) = t;
+       }
+
+       return;
+}
+
+#ifdef DEADCODE        /* This was a precursor to the more flexible lbnExtractBytes */
+/*
+ * Convert a big-endian array of bytes to a bignum.
+ * Returns the number of words in the bignum.
+ * Note the expression "32/8" for the number of bytes per word.
+ * This is so the word-size adjustment will work.
+ */
+unsigned
+lbnFromBytes_32(BNWORD32 *a, unsigned char const *b, unsigned blen)
+{
+       BNWORD32 t;
+       unsigned alen = (blen + (32/8-1))/(32/8);
+       BIGLITTLE(a -= alen, a += alen);
+
+       while (blen) {
+               t = 0;
+               do {
+                       t = t << 8 | *b++;
+               } while (--blen & (32/8-1));
+               BIGLITTLE(*a++,*--a) = t;
+       }
+       return alen;
+}
+#endif
+
+/*
+ * Computes the GCD of a and b.  Modifies both arguments;
+ * when it returns, one of them is the GCD and the other is trash.
+ * The return value is the length of the GCD, with the sign telling
+ * whether it is in a (+ve) or b (-ve).  Both inputs must have
+ * one extra word of precision.  alen must be >= blen.
+ *
+ * TODO: use the binary algorithm (Knuth section 4.5.2, algorithm B).
+ * This is based on taking out common powers of 2, then repeatedly:
+ * gcd(2*u,v) = gcd(u,2*v) = gcd(u,v) - isolated powers of 2 can be deleted.
+ * gcd(u,v) = gcd(u-v,v) - the numbers can be easily reduced.
+ * It gets less reduction per step, but the steps are much faster than
+ * the division case.
+ */
+int
+lbnGcd_32(BNWORD32 *a, unsigned alen, BNWORD32 *b, unsigned blen)
+{
+       assert(alen >= blen);
+
+       while (blen != 0) {
+               (void)lbnDiv_32(BIGLITTLE(a-blen,a+blen), a, alen, b, blen);
+               alen = lbnNorm_32(a, blen);
+               if (alen == 0)
+                       return -(int)blen;
+               (void)lbnDiv_32(BIGLITTLE(b-alen,b+alen), b, blen, a, alen);
+               blen = lbnNorm_32(b, alen);
+       }
+       return alen;
+}
+
+/*
+ * Invert "a" modulo "mod" using the extended Euclidean algorithm.
+ * Note that this only computes one of the cosequences, and uses the
+ * theorem that the signs flip every step and the absolute value of
+ * the cosequence values are always bounded by the modulus to avoid
+ * having to work with negative numbers.
+ * gcd(a,mod) had better equal 1.  Returns 1 if the GCD is NOT 1.
+ * a must be one word longer than "mod".  It is overwritten with the
+ * result.
+ * TODO: Use Richard Schroeppel's *much* faster algorithm.
+ */
+int
+lbnInv_32(BNWORD32 *a, unsigned alen, BNWORD32 const *mod, unsigned mlen)
+{
+       BNWORD32 *b;    /* Hold a copy of mod during GCD reduction */
+       BNWORD32 *p;    /* Temporary for products added to t0 and t1 */
+       BNWORD32 *t0, *t1;      /* Inverse accumulators */
+       BNWORD32 cy;
+       unsigned blen, t0len, t1len, plen;
+
+       alen = lbnNorm_32(a, alen);
+       if (!alen)
+               return 1;       /* No inverse */
+
+       mlen = lbnNorm_32(mod, mlen);
+
+       assert (alen <= mlen);
+
+       /* Inverse of 1 is 1 */
+       if (alen == 1 && BIGLITTLE(a[-1],a[0]) == 1) {
+               lbnZero_32(BIGLITTLE(a-alen,a+alen), mlen-alen);
+               return 0;
+       }
+
+       /* Allocate a pile of space */
+       LBNALLOC(b, mlen+1);
+       if (b) {
+               /*
+                * Although products are guaranteed to always be less than the
+                * modulus, it can involve multiplying two 3-word numbers to
+                * get a 5-word result, requiring a 6th word to store a 0
+                * temporarily.  Thus, mlen + 1.
+                */
+               LBNALLOC(p, mlen+1);
+               if (p) {
+                       LBNALLOC(t0, mlen);
+                       if (t0) {
+                               LBNALLOC(t1, mlen);
+                               if (t1)
+                                               goto allocated;
+                               LBNFREE(t0, mlen);
+                       }
+                       LBNFREE(p, mlen+1);
+               }
+               LBNFREE(b, mlen+1);
+       }
+       return -1;
+
+allocated:
+
+       /* Set t0 to 1 */
+       t0len = 1;
+       BIGLITTLE(t0[-1],t0[0]) = 1;
+       
+       /* b = mod */
+       lbnCopy_32(b, mod, mlen);
+       /* blen = mlen (implicitly) */
+       
+       /* t1 = b / a; b = b % a */
+       cy = lbnDiv_32(t1, b, mlen, a, alen);
+       *(BIGLITTLE(t1-(mlen-alen)-1,t1+(mlen-alen))) = cy;
+       t1len = lbnNorm_32(t1, mlen-alen+1);
+       blen = lbnNorm_32(b, alen);
+
+       /* while (b > 1) */
+       while (blen > 1 || BIGLITTLE(b[-1],b[0]) != (BNWORD32)1) {
+               /* q = a / b; a = a % b; */
+               if (alen < blen || (alen == blen && lbnCmp_32(a, a, alen) < 0))
+                       assert(0);
+               cy = lbnDiv_32(BIGLITTLE(a-blen,a+blen), a, alen, b, blen);
+               *(BIGLITTLE(a-alen-1,a+alen)) = cy;
+               plen = lbnNorm_32(BIGLITTLE(a-blen,a+blen), alen-blen+1);
+               assert(plen);
+               alen = lbnNorm_32(a, blen);
+               if (!alen)
+                       goto failure;   /* GCD not 1 */
+
+               /* t0 += q * t1; */
+               assert(plen+t1len <= mlen+1);
+               lbnMul_32(p, BIGLITTLE(a-blen,a+blen), plen, t1, t1len);
+               plen = lbnNorm_32(p, plen + t1len);
+               assert(plen <= mlen);
+               if (plen > t0len) {
+                       lbnZero_32(BIGLITTLE(t0-t0len,t0+t0len), plen-t0len);
+                       t0len = plen;
+               }
+               cy = lbnAddN_32(t0, p, plen);
+               if (cy) {
+                       if (t0len > plen) {
+                               cy = lbnAdd1_32(BIGLITTLE(t0-plen,t0+plen),
+                                               t0len-plen, cy);
+                       }
+                       if (cy) {
+                               BIGLITTLE(t0[-t0len-1],t0[t0len]) = cy;
+                               t0len++;
+                       }
+               }
+
+               /* if (a <= 1) return a ? t0 : FAIL; */
+               if (alen <= 1 && BIGLITTLE(a[-1],a[0]) == (BNWORD32)1) {
+                       if (alen == 0)
+                               goto failure;   /* FAIL */
+                       assert(t0len <= mlen);
+                       lbnCopy_32(a, t0, t0len);
+                       lbnZero_32(BIGLITTLE(a-t0len, a+t0len), mlen-t0len);
+                       goto success;
+               }
+
+               /* q = b / a; b = b % a; */
+               if (blen < alen || (blen == alen && lbnCmp_32(b, a, alen) < 0))
+                       assert(0);
+               cy = lbnDiv_32(BIGLITTLE(b-alen,b+alen), b, blen, a, alen);
+               *(BIGLITTLE(b-blen-1,b+blen)) = cy;
+               plen = lbnNorm_32(BIGLITTLE(b-alen,b+alen), blen-alen+1);
+               assert(plen);
+               blen = lbnNorm_32(b, alen);
+               if (!blen)
+                       goto failure;   /* GCD not 1 */
+
+               /* t1 += q * t0; */
+               assert(plen+t0len <= mlen+1);
+               lbnMul_32(p, BIGLITTLE(b-alen,b+alen), plen, t0, t0len);
+               plen = lbnNorm_32(p, plen + t0len);
+               assert(plen <= mlen);
+               if (plen > t1len) {
+                       lbnZero_32(BIGLITTLE(t1-t1len,t1+t1len), plen-t1len);
+                       t1len = plen;
+               }
+               cy = lbnAddN_32(t1, p, plen);
+               if (cy) {
+                       if (t1len > plen) {
+                               cy = lbnAdd1_32(BIGLITTLE(t1-plen,t0+plen),
+                                               t1len-plen, cy);
+                       }
+                       if (cy) {
+                               BIGLITTLE(t1[-t1len-1],t1[t1len]) = cy;
+                               t1len++;
+                       }
+               }
+       }
+
+       if (!blen)
+               goto failure;   /* gcd(a, mod) != 1 -- FAIL */
+
+       /* return mod-t1 */
+       lbnCopy_32(a, mod, mlen);
+       assert(t1len <= mlen);
+       cy = lbnSubN_32(a, t1, t1len);
+       if (cy) {
+               assert(mlen > t1len);
+               cy = lbnSub1_32(BIGLITTLE(a-t1len, a+t1len), mlen-t1len, cy);
+               assert(!cy);
+       }
+
+success:
+       LBNFREE(t1, mlen);
+       LBNFREE(t0, mlen);
+       LBNFREE(p, mlen+1);
+       LBNFREE(b, mlen+1);
+       
+       return 0;
+
+failure:
+       LBNFREE(t1, mlen);
+       LBNFREE(t0, mlen);
+       LBNFREE(p, mlen+1);
+       LBNFREE(b, mlen+1);
+       
+       return 1;
+}
diff --git a/lib/bind/cylink/lbn32.h b/lib/bind/cylink/lbn32.h
new file mode 100644 (file)
index 0000000..2915e9e
--- /dev/null
@@ -0,0 +1,181 @@
+#ifndef LBN32_H
+#define LBN32_H
+
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+#include "lbn.h"
+
+#ifndef BNWORD32
+#error 32-bit bignum library requires a 32-bit data type
+#endif
+
+#ifndef lbnCopy_32
+void lbnCopy_32(BNWORD32 *dest, BNWORD32 const *src, unsigned len);
+#endif
+#ifndef lbnZero_32
+void lbnZero_32(BNWORD32 *num, unsigned len);
+#endif
+#ifndef lbnNeg_32
+void lbnNeg_32(BNWORD32 *num, unsigned len);
+#endif
+
+#ifndef lbnAdd1_32
+BNWORD32 lbnAdd1_32(BNWORD32 *num, unsigned len, BNWORD32 carry);
+#endif
+#ifndef lbnSub1_32
+BNWORD32 lbnSub1_32(BNWORD32 *num, unsigned len, BNWORD32 borrow);
+#endif
+
+#ifndef lbnAddN_32
+BNWORD32 lbnAddN_32(BNWORD32 *num1, BNWORD32 const *num2, unsigned len);
+#endif
+#ifndef lbnSubN_32
+BNWORD32 lbnSubN_32(BNWORD32 *num1, BNWORD32 const *num2, unsigned len);
+#endif
+
+#ifndef lbnCmp_32
+int lbnCmp_32(BNWORD32 const *num1, BNWORD32 const *num2, unsigned len);
+#endif
+
+#ifndef lbnMulN1_32
+void lbnMulN1_32(BNWORD32 *out, BNWORD32 const *in, unsigned len, BNWORD32 k);
+#endif
+#ifndef lbnMulAdd1_32
+BNWORD32
+lbnMulAdd1_32(BNWORD32 *out, BNWORD32 const *in, unsigned len, BNWORD32 k);
+#endif
+#ifndef lbnMulSub1_32
+BNWORD32 lbnMulSub1_32(BNWORD32 *out, BNWORD32 const *in, unsigned len, BNWORD32 k);
+#endif
+
+#ifndef lbnLshift_32
+BNWORD32 lbnLshift_32(BNWORD32 *num, unsigned len, unsigned shift);
+#endif
+#ifndef lbnDouble_32
+BNWORD32 lbnDouble_32(BNWORD32 *num, unsigned len);
+#endif
+#ifndef lbnRshift_32
+BNWORD32 lbnRshift_32(BNWORD32 *num, unsigned len, unsigned shift);
+#endif
+
+#ifndef lbnMul_32
+void lbnMul_32(BNWORD32 *prod, BNWORD32 const *num1, unsigned len1,
+       BNWORD32 const *num2, unsigned len2);
+#endif
+#ifndef lbnSquare_32
+void lbnSquare_32(BNWORD32 *prod, BNWORD32 const *num, unsigned len);
+#endif
+
+#ifndef lbnNorm_32
+unsigned lbnNorm_32(BNWORD32 const *num, unsigned len);
+#endif
+#ifndef lbnBits_32
+unsigned lbnBits_32(BNWORD32 const *num, unsigned len);
+#endif
+
+#ifndef lbnExtractBigBytes_32
+void lbnExtractBigBytes_32(BNWORD32 const *bn, unsigned char *buf,
+       unsigned lsbyte, unsigned buflen);
+#endif
+#ifndef lbnInsertBigytes_32
+void lbnInsertBigBytes_32(BNWORD32 *n, unsigned char const *buf,
+       unsigned lsbyte,  unsigned buflen);
+#endif
+#ifndef lbnExtractLittleBytes_32
+void lbnExtractLittleBytes_32(BNWORD32 const *bn, unsigned char *buf,
+       unsigned lsbyte, unsigned buflen);
+#endif
+#ifndef lbnInsertLittleBytes_32
+void lbnInsertLittleBytes_32(BNWORD32 *n, unsigned char const *buf,
+       unsigned lsbyte,  unsigned buflen);
+#endif
+
+#ifndef lbnDiv21_32
+BNWORD32 lbnDiv21_32(BNWORD32 *q, BNWORD32 nh, BNWORD32 nl, BNWORD32 d);
+#endif
+#ifndef lbnDiv1_32
+BNWORD32 lbnDiv1_32(BNWORD32 *q, BNWORD32 *rem,
+       BNWORD32 const *n, unsigned len, BNWORD32 d);
+#endif
+#ifndef lbnModQ_32
+unsigned lbnModQ_32(BNWORD32 const *n, unsigned len, unsigned d);
+#endif
+#ifndef lbnDiv_32
+BNWORD32
+lbnDiv_32(BNWORD32 *q, BNWORD32 *n, unsigned nlen, BNWORD32 *d, unsigned dlen);
+#endif
+
+#ifndef lbnMontInv1_32
+BNWORD32 lbnMontInv1_32(BNWORD32 const x);
+#endif
+#ifndef lbnMontReduce_32
+void lbnMontReduce_32(BNWORD32 *n, BNWORD32 const *mod, unsigned const mlen,
+                BNWORD32 inv);
+#endif
+#ifndef lbnToMont_32
+void lbnToMont_32(BNWORD32 *n, unsigned nlen, BNWORD32 *mod, unsigned mlen);
+#endif
+#ifndef lbnFromMont_32
+void lbnFromMont_32(BNWORD32 *n, BNWORD32 *mod, unsigned len);
+#endif
+
+#ifndef lbnExpMod_32
+int lbnExpMod_32(BNWORD32 *result, BNWORD32 const *n, unsigned nlen,
+       BNWORD32 const *exp, unsigned elen, BNWORD32 *mod, unsigned mlen);
+#endif
+#ifndef lbnDoubleExpMod_32
+int lbnDoubleExpMod_32(BNWORD32 *result,
+       BNWORD32 const *n1, unsigned n1len, BNWORD32 const *e1, unsigned e1len,
+       BNWORD32 const *n2, unsigned n2len, BNWORD32 const *e2, unsigned e2len,
+       BNWORD32 *mod, unsigned mlen);
+#endif
+#ifndef lbnTwoExpMod_32
+int lbnTwoExpMod_32(BNWORD32 *n, BNWORD32 const *exp, unsigned elen,
+       BNWORD32 *mod, unsigned mlen);
+#endif
+#ifndef lbnGcd_32
+int lbnGcd_32(BNWORD32 *a, unsigned alen, BNWORD32 *b, unsigned blen);
+#endif
+#ifndef lbnInv_32
+int lbnInv_32(BNWORD32 *a, unsigned alen, BNWORD32 const *mod, unsigned mlen);
+#endif
+
+#endif /* LBN32_H */
diff --git a/lib/bind/cylink/lbn68000.c b/lib/bind/cylink/lbn68000.c
new file mode 100644 (file)
index 0000000..2c302ca
--- /dev/null
@@ -0,0 +1,500 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/*
+ * lbn68000.c - 16-bit bignum primitives for the 68000 (or 68010) processors.
+ *
+ * Copyright (c) 1995  Colin Plumb.  All rights reserved.
+ * For licensing and other legal details, see the file legal.c.
+ *
+ * This was written for Metrowerks C, and while it should be reasonably
+ * portable, NOTE that Metrowerks lets a callee trash a0, a1, d0, d1, and d2.
+ * Some 680x0 compilers make d2 callee-save, so instructions to save it
+ * will have to be added.
+ * 
+ * This code supports 16 or 32-bit ints, based on UINT_MAX.
+ * Regardless of UINT_MAX, only bignums up to 64K words (1 million bits)
+ * are supported.  (68k hackers will recognize this as a consequence of
+ * using dbra.)
+ *
+ * These primitives use little-endian word order.
+ * (The order of bytes within words is irrelevant to this issue.)
+ */
+
+#include <limits.h>
+
+#include "lbn.h"        /* Should include lbn68000.h */
+
+/*
+ * The Metrowerks C compiler (1.2.2) produces bad 68k code for the
+ * following input, which happens to be the inner loop of lbnSub1,
+ * so a few less than critical routines have been recoded in assembly
+ * to avoid the bug.  (Optimizer on or off does not matter.)
+ * 
+ * unsigned
+ * decrement(unsigned *num, unsigned len)
+ * {
+ *      do {
+ *              if ((*num++)-- != 0)
+ *                      return 0;
+ *      } while (--len);
+ *      return 1;
+ * }
+ */
+asm BNWORD16
+lbnSub1_16(BNWORD16 *num, unsigned len, BNWORD16 borrow)
+{
+        movea.l 4(sp),a0        /* num */
+#if UINT_MAX == 0xffff
+        move.w  10(sp),d0       /* borrow */
+#else
+        move.w  12(sp),d0       /* borrow */
+#endif
+        sub.w   d0,(a0)+
+        bcc             done
+#if UINT_MAX == 0xffff
+        move.w  8(sp),d0        /* len */
+#else
+        move.w  10(sp),d0       /* len */
+#endif
+        subq.w  #2,d0
+        bcs             done
+loop:
+        subq.w  #1,(a0)+
+        dbcc    d0,loop
+done:
+        moveq.l #0,d0
+        addx.w  d0,d0
+        rts
+}
+
+asm BNWORD16
+lbnAdd1_16(BNWORD16 *num, unsigned len, BNWORD16 carry)
+{
+        movea.l 4(sp),a0        /* num */
+#if UINT_MAX == 0xffff
+        move.w  10(sp),d0       /* carry */
+#else
+        move.w  12(sp),d0       /* carry */
+#endif
+        add.w   d0,(a0)+
+        bcc             done
+#if UINT_MAX == 0xffff
+        move.w  8(sp),d0        /* len */
+#else
+        move.w  10(sp),d0       /* len */
+#endif
+        subq.w  #2,d0
+        bcs             done
+loop:
+        addq.w  #1,(a0)+
+        dbcc    d0,loop
+done:
+        moveq.l #0,d0
+        addx.w  d0,d0
+        rts
+}
+
+asm void
+lbnMulN1_16(BNWORD16 *out, BNWORD16 const *in, unsigned len, BNWORD16 k)
+{
+        move.w  d3,-(sp)        /* 2 bytes of stack frame */
+        move.l  2+4(sp),a1      /* out */
+        move.l  2+8(sp),a0      /* in */
+#if UINT_MAX == 0xffff
+        move.w  2+12(sp),d3     /* len */
+        move.w  2+14(sp),d2     /* k */
+#else
+        move.w  2+14(sp),d3     /* len (low 16 bits) */
+        move.w  2+16(sp),d2     /* k */
+#endif
+
+        move.w  (a0)+,d1        /* First multiply */
+        mulu.w  d2,d1
+        move.w  d1,(a1)+
+        clr.w   d1
+        swap    d1
+
+        subq.w  #1,d3           /* Setup for loop unrolling */
+        lsr.w   #1,d3
+        bcs.s   m16_even
+        beq.s   m16_short
+        
+        subq.w  #1,d3           /* Set up software pipeline properly */
+        move.l  d1,d0
+        
+m16_loop:
+        move.w  (a0)+,d1
+        mulu.w  d2,d1
+        add.l   d0,d1
+        move.w  d1,(a1)+
+        clr.w  d1
+        swap   d1
+m16_even:
+
+        move.w  (a0)+,d0
+        mulu.w  d2,d0
+        add.l   d1,d0
+        move.w  d0,(a1)+
+        clr.w   d0
+        swap    d0
+
+        dbra    d3,m16_loop
+        
+        move.w  d0,(a1)
+        move.w  (sp)+,d3
+        rts
+m16_short:
+        move.w  d1,(a1)
+        move.w  (sp)+,d3
+        rts
+}
+
+
+asm BNWORD16
+lbnMulAdd1_16(BNWORD16 *out, BNWORD16 const *in, unsigned len, BNWORD16 k)
+{
+        move.w  d4,-(sp) 
+        clr.w   d4
+        move.w  d3,-(sp)        /* 4 bytes of stack frame */
+        move.l  4+4(sp),a1      /* out */
+        move.l  4+8(sp),a0      /* in */
+#if UINT_MAX == 0xffff
+        move.w  4+12(sp),d3     /* len */
+        move.w  4+14(sp),d2     /* k */
+#else
+        move.w  4+14(sp),d3     /* len (low 16 bits) */
+        move.w  4+16(sp),d2     /* k */
+#endif
+
+        move.w  (a0)+,d1        /* First multiply */
+        mulu.w  d2,d1
+        add.w   d1,(a1)+
+        clr.w   d1
+        swap    d1
+        addx.w  d4,d1
+
+        subq.w  #1,d3           /* Setup for loop unrolling */
+        lsr.w   #1,d3
+        bcs.s   ma16_even
+        beq.s   ma16_short
+        
+        subq.w  #1,d3           /* Set up software pipeline properly */
+        move.l  d1,d0
+        
+ma16_loop:
+        move.w  (a0)+,d1
+        mulu.w  d2,d1
+        add.l   d0,d1
+        add.w   d1,(a1)+
+        clr.w   d1
+        swap    d1
+        addx.w  d4,d1
+ma16_even:
+
+        move.w  (a0)+,d0
+        mulu.w  d2,d0
+        add.l   d1,d0
+        add.w   d0,(a1)+
+        clr.w   d0
+        swap    d0
+        addx.w  d4,d0
+
+        dbra    d3,ma16_loop
+        
+        move.w  (sp)+,d3
+        move.w  (sp)+,d4
+        rts
+ma16_short:
+        move.w  (sp)+,d3
+        move.l  d1,d0   
+        move.w  (sp)+,d4
+        rts
+}
+
+
+
+asm BNWORD16
+lbnMulSub1_16(BNWORD16 *out, BNWORD16 const *in, unsigned len, BNWORD16 k)
+{
+        move.w  d4,-(sp) 
+        clr.w   d4
+        move.w  d3,-(sp)        /* 4 bytes of stack frame */
+        move.l  4+4(sp),a1      /* out */
+        move.l  4+8(sp),a0      /* in */
+#if UINT_MAX == 0xffff
+        move.w  4+12(sp),d3     /* len */
+        move.w  4+14(sp),d2     /* k */
+#else
+        move.w  4+14(sp),d3     /* len (low 16 bits) */
+        move.w  4+16(sp),d2     /* k */
+#endif
+
+        move.w  (a0)+,d1        /* First multiply */
+        mulu.w  d2,d1
+        sub.w   d1,(a1)+
+        clr.w   d1
+        swap    d1
+        addx.w  d4,d1
+
+        subq.w  #1,d3           /* Setup for loop unrolling */
+        lsr.w   #1,d3
+        bcs.s   ms16_even
+        beq.s   ms16_short
+        
+        subq.w  #1,d3           /* Set up software pipeline properly */
+        move.l  d1,d0
+        
+ms16_loop:
+        move.w  (a0)+,d1
+        mulu.w  d2,d1
+        add.l   d0,d1
+        sub.w   d1,(a1)+
+        clr.w   d1
+        swap    d1
+        addx.w  d4,d1
+ms16_even:
+
+        move.w  (a0)+,d0
+        mulu.w  d2,d0
+        add.l   d1,d0
+        sub.w   d0,(a1)+
+        clr.w   d0
+        swap    d0
+        addx.w  d4,d0
+
+        dbra    d3,ms16_loop
+        
+        move.w  (sp)+,d3
+        move.w  (sp)+,d4
+        rts
+ms16_short:
+        move.w  (sp)+,d3
+        move.l  d1,d0   
+        move.w  (sp)+,d4
+        rts
+}
+
+/* The generic long/short divide doesn't know that nh < d */
+asm BNWORD16
+lbnDiv21_16(BNWORD16 *q, BNWORD16 nh, BNWORD16 nl, BNWORD16 d)
+{
+        move.l  8(sp),d0               /* nh *and* nl */
+        divu.w 12(sp),d0
+        move.l 4(sp),a0
+        move.w d0,(a0)
+        clr.w  d0
+        swap   d0
+        rts
+}
+
+asm unsigned
+lbnModQ_16(BNWORD16 const *n, unsigned len, BNWORD16 d)
+{
+        move.l  4(sp),a0        /* n */
+        moveq.l        #0,d1
+#if UINT_MAX == 0xffff
+        move.w  8(sp),d1        /* len */
+        move.w  10(sp),d2       /* d */
+#else
+        move.w  10(sp),d1       /* len (low 16 bits) */
+        move.w  12(sp),d2       /* d */
+#endif
+
+               add.l   d1,a0
+               add.l   d1,a0                   /* n += len */
+               moveq.l #0,d0
+        subq.w  #1,d1
+
+mq16_loop:
+        move.w  -(a0),d0               /* Assemble remainder and new word */
+        divu.w  d2,d0          /* Put remainder in high half of d0 */
+        dbra    d1,mq16_loop    
+                        
+mq16_done:
+        clr.w   d0
+        swap    d0
+        rts
+}
+
+/*
+ * Detect if this is a 32-bit processor (68020+ *or* CPU32).
+ * Both the 68020+ and CPU32 processors (which have 32x32->64-bit
+ * multiply, what the 32-bit math library wants) support scaled indexed
+ * addressing.  The 68000 and 68010 ignore the scale selection
+ * bits, treating it as *1 all the time.  So a 32-bit processor
+ * will evaluate -2(a0,a0.w*2) as 1+1*2-2 = 1.
+ * A 16-bit processor will compute 1+1-2 = 0.
+ *
+ * Thus, the return value will indicate whether the chip this is
+ * running on supports 32x32->64-bit multiply (mulu.l).
+ */
+asm int
+is68020(void)
+{
+        machine 68020
+        lea     1,a0
+#if 0
+        lea     -2(a0,a0.w*2),a0       /* Metrowerks won't assemble this, arrgh */
+#else
+        dc.w    0x41f0, 0x82fe
+#endif
+        move.l a0,d0
+        rts
+}
+/*
+ * Since I had to hand-assemble that fancy addressing mode, I had to study
+ * up on 680x0 addressing modes.
+ * A summary of 680x0 addressing modes.
+ * A 68000 effective address specifies an operand on an instruction, which
+ * may be a register or in memory.  It is made up of a 3-bit mode and a
+ * 3-bit register specifier.  The meanings of the various modes are:
+ *
+ * 000 reg - Dn, n specified by "reg"
+ * 001 reg - An, n specified by "reg"
+ * 010 reg - (An)
+ * 011 reg - (An)+
+ * 100 reg - -(An)
+ * 101 reg - d16(An), one 16-bit displacement word follows, sign-extended
+ * 110 reg - Fancy addressing mode off of An, see extension word below
+ * 111 000 - abs.W, one 16-bit signed absolute address follows
+ * 111 001 - abs.L, one 32-bit absolute address follows
+ * 111 010 - d16(PC), one 16-bit displacemnt word follows, sign-extended
+ * 111 011 - Fancy addressing mode off of PC, see extension word below
+ * 111 100 - #immediate, followed by 16 or 32 bits of immediate value
+ * 111 101 - unused, reserved
+ * 111 110 - unused, reserved
+ * 111 111 - unused, reserved
+ *
+ * Memory references are to data space, except that PC-relative references
+ * are to program space, and are read-only.
+ *
+ * Fancy addressing modes are followed by a 16-bit extension word, and come
+ * in "brief" and "full" forms.
+ * The "brief" form looks like this.  Bit 8 is 0 to indicate this form:
+ *
+ * 1   1   1   1   1   1   1  
+ * 6   5   4   3   2   1   0   9   8   7   6   5   4   3   2   1   0
+ * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ * |A/D|  register |L/W| scale | 0 |   8-bit signed displacement   |
+ * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ *
+ * The basic effective address specifies a 32-bit base register - A0 through
+ * A7 or PC (the address of the following instruction).
+ * The A/D and register fields specify an index register.  A/D is 1 for
+ * address registers, and 0 for data registers.  L/W specifies the length
+ * of the index register, 1 for 32 bits, and 0 for 16 bits (sign-extended).
+ * The scale field is a left shift amount (0 to 3 bits) to apply to the
+ * sign-extended index register.  The final address is d8(An,Rn.X*SCALE),
+ * also written (d8,An,Rn.X*SCALE).  X is "W" or "L", SCALE is 1, 2, 4 or 8.
+ * "*1" may be omitted, as may a d8 of 0.
+ *
+ * The 68000 supports this form, but only with a scale field of 0.
+ * It does NOT (says the MC68030 User's Manual MC68030UM/AD, section 2.7)
+ * decode the scale field and the following format bit.  They are treated
+ * as 0.
+ * I recall (I don't have the data book handy) that the CPU32 processor
+ * core used in the 683xx series processors supports variable scales,
+ * but only the brief extension word form.  I suspect it decodes the
+ * format bit and traps if it is not zero, but I don't recall.
+ *
+ * The "full" form (680x0, x >= 2 processors only) looks like this: 
+ *
+ * 1   1   1   1   1   1   1  
+ * 6   5   4   3   2   1   0   9   8   7   6   5   4   3   2   1   0
+ * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ * |A/D|  register |L/W| scale | 1 | BS| IS|BD size| 0 | P |OD size|
+ * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ *
+ * The first 8 bits are interpreted the same way as in the brief form,
+ * except that bit 8 is set to 1 to indicate the full form.
+ * BS, Base Suppress, if set, causes a value of 0 to be used in place of
+ * the base register value.  If this is set, the base register
+ * specified is irrelevant, except that if it is the PC, the fetch is
+ * still done from program space.  The specifier "ZPC" can be used in
+ * place of "PC" in the effective address mnemonic to represent this
+ * case.
+ * IS, Index Suppress, if set, causes a value of 0 to be used in place
+ * of the scaled index register. In this case, the first 7 bits of the
+ * extension word are irrelevant.
+ * BD size specifies the base displacement size.  A value of 00
+ * in this field is illegal, while 01, 10 and 11 indicate that the
+ * extension word is followed by 0, 1 or 2 16-bit words of base displacement
+ * (zero, sign-extended to 32 bits, and most-significant word first,
+ * respectively) to add to the base register value.
+ * Bit 3 is unused.
+ * The P bit is the pre/post indexing bit, and only applies if an outer
+ * displacement is used.  This is explained later.
+ * OD size specifies the size of an outer displacement.  In the simple
+ * case, this field is set to 00 and the effective address is
+ * (disp,An,Rn.X*SCALE) or (disp,PC,Rn.X*SCALE).
+ * In this case the P bit must be 0.  Any of those compnents may be
+ * suppressed, with a BD size of 01, the BS bit, or the IS bit.
+ * If the OD size is not 00, it encodes an outer displacement in the same
+ * manner as the BD size, and 0, 1 or 2 16-bit words of outer displacement
+ * follow the base displacement in the instruction stream.  In this case,
+ * this is a double-indirect addressing mode.  The base, base displacement,
+ * and possibly the index, specify a 32-bit memory word which holds a value
+ * which is fetched, and the outer displacement and possibly the index are
+ * added to produce the address of the operand.
+ * If the P bit is 0, this is pre-indexed, and the index value is added
+ * before the fetch of the indirect word, producing an effective address
+ * of ([disp,An,Rn.X*SCALE],disp).  If the P bit is 1, the post-indexed case,
+ * the memory word is fectched from base+base displacement, then the index
+ * and outer displacement are added to compute the address of the operand.
+ * This effective address is written ([disp,An],Rn.X*SCALE,disp).
+ * (In both cases, "An" may also be "PC" or "ZPC".)
+ * Any of the components may be omitted.  If the index is omitted (using the
+ * IS bit), the P bit is irrelevant, but must be written as 0.
+ * Thus, legal combinations of IS, P and OD size are:
+ * 0 0 00 - (disp,An,Rn.X*SCALE), also written disp(An,Rn.X*SCALE)
+ * 0 0 01 - ([disp,An,Rn.X*SCALE])
+ * 0 0 10 - ([disp,An,Rn.X*SCALE],d16)
+ * 0 0 11 - ([disp,An,Rn.X*SCALE],d32)
+ * 0 1 01 - ([disp,An],Rn.X*SCALE)
+ * 0 1 10 - ([disp,An],Rn.X*SCALE,d16)
+ * 0 1 11 - ([disp,An],Rn.X*SCALE,d32)
+ * 1 0 00 - (disp,An), also written disp(An)
+ * 1 0 01 - ([disp,An])
+ * 1 0 10 - ([disp,An],d16)
+ * 1 0 11 - ([disp,An],d32)
+ */ 
+
+/* 45678901234567890123456789012345678901234567890123456789012345678901234567 */
diff --git a/lib/bind/cylink/lbn68000.h b/lib/bind/cylink/lbn68000.h
new file mode 100644 (file)
index 0000000..f52e799
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/*
+ * lbn68000.h - 16-bit bignum primitives for the 68000 (or 68010) processors.
+ *
+ * These primitives use little-endian word order.
+ * (The order of bytes within words is irrelevant.)
+ */
+#define BN_LITTLE_ENDIAN 1
+
+typedef unsigned short bnword16
+#define BNWORD16 bnword16
+
+bnword16 lbnSub1_16(bnword16 *num, unsigned len, bnword16 borrow);
+bnword16 lbnAdd1_16(bnword16 *num, unsigned len, bnword16 carry);
+void lbnMulN1_16(bnword16 *out, bnword16 const *in, unsigned len, bnword16 k);
+bnword16
+lbnMulAdd1_16(bnword16 *out, bnword16 const *in, unsigned len, bnword16 k);
+bnword16
+lbnMulSub1_16(bnword16 *out, bnword16 const *in, unsigned len, bnword16 k);
+bnword16 lbnDiv21_16(bnword16 *q, bnword16 nh, bnword16 nl, bnword16 d);
+unsigned lbnModQ_16(bnword16 const *n, unsigned len, bnword16 d);
+
+int is68020(void);
+
+/* #define the values to exclude the C versions */
+#define lbnSub1_16 lbnSub1_16
+#define lbnAdd1_16 lbnAdd1_16
+#define lbnMulN1_16 lbnMulN1_16
+#define lbnMulAdd1_16 lbnMulAdd1_16
+#define lbnMulSub1_16 lbnMulSub1_16
+#define lbnDiv21_16 lbnDiv21_16
+#define lbnModQ_16 lbnModQ_16
+
+/* Also include the 68020 definitions for 16/32 bit switching versions. */
+#include <lbn68020.h>
diff --git a/lib/bind/cylink/lbn68020.c b/lib/bind/cylink/lbn68020.c
new file mode 100644 (file)
index 0000000..6b52f59
--- /dev/null
@@ -0,0 +1,349 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/*
+ * lbn68020.c - 32-bit bignum primitives for the 68020+ (0r 683xx) processors.
+ *
+ * Copyright (c) 1995  Colin Plumb.  All rights reserved.
+ * For licensing and other legal details, see the file legal.c.
+ *
+ * This was written for Metrowerks C, and while it should be reasonably
+ * portable, NOTE that Metrowerks lets a callee trash a0, a1, d0, d1, and d2.
+ * Some 680x0 compilers make d2 callee-save, so instructions to save it
+ * will have to be added.
+ * 
+ * This code supports 16 or 32-bit ints, based on UINT_MAX.
+ * Regardless of UINT_MAX, only bignums up to 64K words (2 million bits)
+ * are supported.  (68k hackers will recognize this as a consequence of
+ * using dbra.)
+ *
+ * These primitives use little-endian word order.
+ * (The order of bytes within words is irrelevant to this issue.)
+ *
+ * TODO: Schedule this for the 68040's pipeline.  (When I get a 68040 manual.)
+ */
+
+#include <limits.h>
+
+#include "lbn.h"        /* Should include lbn68020.h */
+
+/*
+ * The Metrowerks C compiler (1.2.2) produces bad 68k code for the
+ * following input, which happens to be the inner loop of lbnSub1,
+ * so a few less than critical routines have been recoded in assembly
+ * to avoid the bug.  (Optimizer on or off does not matter.)
+ * 
+ * unsigned
+ * decrement(unsigned *num, unsigned len)
+ * {
+ *      do {
+ *              if ((*num++)-- != 0)
+ *                      return 0;
+ *      } while (--len);
+ *      return 1;
+ * }
+ */
+asm BNWORD32
+lbnSub1_32(BNWORD32 *num, unsigned len, BNWORD32 borrow)
+{
+        movea.l 4(sp),a0        /* num */
+#if UINT_MAX == 0xffff
+        move.l  10(sp),d0       /* borrow */
+#else
+        move.l  12(sp),d0       /* borrow */
+#endif
+        sub.l   d0,(a0)+
+        bcc             done
+#if UINT_MAX == 0xffff
+        move.w  8(sp),d0        /* len */
+#else
+        move.w  10(sp),d0       /* len */
+#endif
+        subq.w  #2,d0
+        bcs             done
+loop:
+        subq.l  #1,(a0)+
+        dbcc    d0,loop
+done:
+        moveq.l #0,d0
+        addx.w  d0,d0
+        rts
+}
+
+asm BNWORD32
+lbnAdd1_32(BNWORD32 *num, unsigned len, BNWORD32 carry)
+{
+        movea.l 4(sp),a0        /* num */
+#if UINT_MAX == 0xffff
+        move.l  10(sp),d0       /* carry */
+#else
+        move.l  12(sp),d0       /* carry */
+#endif
+        add.l   d0,(a0)+
+        bcc             done
+#if UINT_MAX == 0xffff
+        move.w  8(sp),d0        /* len */
+#else
+        move.w  10(sp),d0       /* len */
+#endif
+        subq.w  #2,d0
+        bcs             done
+loop:
+        addq.l  #1,(a0)+
+        dbcc    d0,loop
+done:
+        moveq.l #0,d0
+        addx.w  d0,d0
+        rts
+}
+
+asm void
+lbnMulN1_32(BNWORD32 *out, BNWORD32 const *in, unsigned len, BNWORD32 k)
+{
+        machine 68020
+        
+        movem.l d3-d5,-(sp)     /* 12 bytes of extra data */
+        moveq.l #0,d4
+        move.l  16(sp),a1       /* out */
+        move.l  20(sp),a0       /* in */
+#if UINT_MAX == 0xffff
+        move.w  24(sp),d5       /* len */
+        move.l  26(sp),d2       /* k */
+#else
+        move.w  26(sp),d5       /* len */
+        move.l  28(sp),d2       /* k */
+#endif
+
+        move.l  (a0)+,d3        /* First multiply */
+        mulu.l  d2,d1:d3        /* dc.w    0x4c02, 0x3401 */
+        move.l  d3,(a1)+
+
+        subq.w  #1,d5           /* Setup for loop unrolling */
+        lsr.w   #1,d5
+        bcs.s   m32_even
+        beq.s   m32_short
+        
+        subq.w  #1,d5           /* Set up software pipeline properly */
+        move.l  d1,d0
+        
+m32_loop:
+        move.l  (a0)+,d3
+        mulu.l  d2,d1:d3        /* dc.w    0x4c02, 0x3401 */
+        add.l   d0,d3
+        addx.l  d4,d1
+        move.l  d3,(a1)+
+m32_even:
+
+        move.l  (a0)+,d3
+        mulu.l  d2,d0:d3        /* dc.w    0x4c02, 0x3400 */
+        add.l   d1,d3
+        addx.l  d4,d0
+        move.l  d3,(a1)+
+
+        dbra    d5,m32_loop
+        
+        move.l  d0,(a1)
+        movem.l (sp)+,d3-d5
+        rts
+m32_short:
+        move.l  d1,(a1)
+        movem.l (sp)+,d3-d5
+        rts
+}
+
+
+asm BNWORD32
+lbnMulAdd1_32(BNWORD32 *out, BNWORD32 const *in, unsigned len, BNWORD32 k)
+{
+        machine 68020
+        movem.l d3-d5,-(sp)     /* 12 bytes of extra data */
+        moveq.l #0,d4
+        move.l  16(sp),a1       /* out */
+        move.l  20(sp),a0       /* in */
+#if UINT_MAX == 0xffff
+        move.w  24(sp),d5       /* len */
+        move.l  26(sp),d2       /* k */
+#else
+        move.w  26(sp),d5       /* len */
+        move.l  28(sp),d2       /* k */
+#endif
+
+        move.l  (a0)+,d3        /* First multiply */
+        mulu.l  d2,d1:d3        /* dc.w    0x4c02, 0x3401 */
+        add.l   d3,(a1)+
+        addx.l  d4,d1
+
+        subq.w  #1,d5           /* Setup for loop unrolling */
+        lsr.w   #1,d5
+        bcs.s   ma32_even
+        beq.s   ma32_short
+        
+        subq.w  #1,d5           /* Set up software pipeline properly */
+        move.l  d1,d0
+        
+ma32_loop:
+        move.l  (a0)+,d3
+        mulu.l  d2,d1:d3        /* dc.w    0x4c02, 0x3401 */
+        add.l   d0,d3
+        addx.l  d4,d1
+        add.l   d3,(a1)+
+        addx.l  d4,d1
+ma32_even:
+
+        move.l  (a0)+,d3
+        mulu.l  d2,d0:d3        /* dc.w    0x4c02, 0x3400 */
+        add.l   d1,d3
+        addx.l  d4,d0
+        add.l   d3,(a1)+
+        addx.l  d4,d0
+
+        dbra    d5,ma32_loop
+        
+        movem.l (sp)+,d3-d5
+        rts
+ma32_short:
+        move.l  d1,d0   
+        movem.l (sp)+,d3-d5
+        rts
+}
+
+
+asm BNWORD32
+lbnMulSub1_32(BNWORD32 *out, BNWORD32 const *in, unsigned len, BNWORD32 k)
+{
+        machine 68020
+        movem.l d3-d5,-(sp)     /* 12 bytes of extra data */
+        moveq.l #0,d4
+        move.l  16(sp),a1       /* out */
+        move.l  20(sp),a0       /* in */
+#if UINT_MAX == 0xffff
+        move.w  24(sp),d5       /* len */
+        move.l  26(sp),d2       /* k */
+#else
+        move.w  26(sp),d5       /* len */
+        move.l  28(sp),d2       /* k */
+#endif
+
+        move.l  (a0)+,d3        /* First multiply */
+        mulu.l  d2,d1:d3        /* dc.w    0x4c02, 0x3401 */
+        sub.l   d3,(a1)+
+        addx.l  d4,d1
+
+        subq.w  #1,d5           /* Setup for loop unrolling */
+        lsr.w   #1,d5
+        bcs.s   ms32_even
+        beq.s   ms32_short
+        
+        subq.w  #1,d5           /* Set up software pipeline properly */
+        move.l  d1,d0
+        
+ms32_loop:
+        move.l  (a0)+,d3
+        mulu.l  d2,d1:d3        /* dc.w    0x4c02, 0x3401 */
+        add.l   d0,d3
+        addx.l  d4,d1
+        sub.l   d3,(a1)+
+        addx.l  d4,d1
+ms32_even:
+
+        move.l  (a0)+,d3
+        mulu.l  d2,d0:d3        /* dc.w    0x4c02, 0x3400 */
+        add.l   d1,d3
+        addx.l  d4,d0
+        sub.l   d3,(a1)+
+        addx.l  d4,d0
+
+        dbra    d5,ms32_loop
+        
+        movem.l (sp)+,d3-d5
+        rts
+        
+ms32_short:
+        move.l  d1,d0
+        movem.l (sp)+,d3-d5
+        rts
+}
+
+
+asm BNWORD32
+lbnDiv21_32(BNWORD32 *q, BNWORD32 nh, BNWORD32 nl, BNWORD32 d)
+{
+        machine 68020
+        move.l  8(sp),d0
+        move.l  12(sp),d1
+        move.l  4(sp),a0
+        divu.l  16(sp),d0:d1    /*  dc.w    0x4c6f, 0x1400, 16 */
+        move.l  d1,(a0)
+        rts
+}
+
+asm unsigned
+lbnModQ_32(BNWORD32 const *n, unsigned len, unsigned d)
+{
+        machine 68020
+        move.l  4(sp),a0        /* n */
+        move.l  d3,a1
+#if UINT_MAX == 0xffff
+        moveq.l #0,d2
+        move.w  8(sp),d1        /* len */
+        move.w  10(sp),d2       /* d */
+#else
+        move.w  10(sp),d1       /* len */
+        move.l  12(sp),d2       /* d */
+#endif
+        dc.w    0x41f0, 0x1cfc  /* lea  -4(a0,d1.L*4),a0 */
+
+       /* First time, divide 32/32 - may be faster than 64/32 */
+        move.l  (a0),d3
+        divul.l d2,d0:d3        /* dc.w    0x4c02, 0x3000 */
+        subq.w  #2,d1
+        bmi    mq32_done
+
+mq32_loop:
+        move.l  -(a0),d3
+        divu.l  d2,d0:d3        /* dc.w    0x4c02,0x3400 */
+        dbra    d1,mq32_loop    
+                        
+mq32_done:
+        move.l  a1,d3
+        rts
+}
+
+/* 45678901234567890123456789012345678901234567890123456789012345678901234567 */
diff --git a/lib/bind/cylink/lbn68020.h b/lib/bind/cylink/lbn68020.h
new file mode 100644 (file)
index 0000000..17f6fb2
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/*
+ * lbn68020.h - 32-bit bignum primitives for the 68020 (or 683xx) processors.
+ *
+ * These primitives use little-endian word order.
+ * (The order of bytes within words is irrelevant.)
+ */
+#define BN_LITTLE_ENDIAN 1
+
+typedef unsigned long bnword32
+#define BNWORD32 bnword32
+
+bnword32 lbnSub1_32(bnword32 *num, unsigned len, bnword32 borrow);
+bnword32 lbnAdd1_32(bnword32 *num, unsigned len, bnword32 carry);
+void lbnMulN1_32(bnword32 *out, bnword32 const *in, unsigned len, bnword32 k);
+bnword32
+lbnMulAdd1_32(bnword32 *out, bnword32 const *in, unsigned len, bnword32 k);
+bnword32
+lbnMulSub1_32(bnword32 *out, bnword32 const *in, unsigned len, bnword32 k);
+bnword32 lbnDiv21_32(bnword32 *q, bnword32 nh, bnword32 nl, bnword32 d);
+unsigned lbnModQ_32(bnword32 const *n, unsigned len, unsigned d);
+
+/* #define the values to exclude the C versions */
+#define lbnSub1_32 lbnSub1_32
+#define lbnAdd1_32 lbnAdd1_32
+#define lbnMulN1_32 lbnMulN1_32
+#define lbnMulAdd1_32 lbnMulAdd1_32
+#define lbnMulSub1_32 lbnMulSub1_32
+#define lbnDiv21_32 lbnDiv21_32
+#define lbnModQ_32 lbnModQ_32
diff --git a/lib/bind/cylink/lbn80386.h b/lib/bind/cylink/lbn80386.h
new file mode 100644 (file)
index 0000000..8054174
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/*
+ * lbn80386.h - This file defines the interfaces to the 80386
+ * assembly primitives.  It is intended to be included in "lbn.h"
+ * via the "#include BNINCLUDE" mechanism.
+ */
+#define BN_LITTLE_ENDIAN 1
+
+typedef unsigned long bnword32;
+#define BNWORD32 bnword32
+
+/* MS-DOS needs the calling convention described to it. */
+#ifndef MSDOS
+#ifdef __MSDOS__
+#define MSDOS 1
+#endif
+#endif
+
+#ifdef MSDOS
+#define CDECL __cdecl
+#else
+#define CDECL /*nothing*/
+#endif
+
+#ifdef __cplusplus
+/* These assembly-language primitives use C names */
+extern "C" {
+#endif
+
+/* Function prototypes for the asm routines */
+void CDECL
+lbnMulN1_32(bnword32 *out, bnword32 const *in, unsigned len, bnword32 k);
+#define lbnMulN1_32 lbnMulN1_32
+            
+bnword32 CDECL
+lbnMulAdd1_32(bnword32 *out, bnword32 const *in, unsigned len, bnword32 k);
+#define lbnMulAdd1_32 lbnMulAdd1_32
+       
+bnword32 CDECL
+lbnMulSub1_32(bnword32 *out, bnword32 const *in, unsigned len, bnword32 k);
+#define lbnMulSub1_32 lbnMulSub1_32
+
+bnword32 CDECL
+lbnDiv21_32(bnword32 *q, bnword32 nh, bnword32 nl, bnword32 d);
+#define lbnDiv21_32 lbnDiv21_32
+
+unsigned CDECL
+lbnModQ_32(bnword32 const *n, unsigned len, bnword32 d);
+#define lbnModQ_32 lbnModQ_32
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#if __GNUC__
+/*
+ * Use the (massively cool) GNU inline-assembler extension to define
+ * inline expansions for various operations.
+ *
+ * The massively cool part is that the assembler can have inputs
+ * and outputs, and you specify the operands and which effective
+ * addresses are legal and they get substituted into the code.
+ * (For example, some of the code requires a zero.  Rather than
+ * specify an immediate constant, the expansion specifies an operand
+ * of zero which can be in various places.  This lets GCC use an
+ * immediate zero, or a register which contains zero if it's available.)
+ *
+ * The syntax is asm("asm_code" : outputs : inputs : trashed)
+ * %0, %1 and so on in the asm code are substituted by the operands
+ * in left-to-right order (outputs, then inputs).
+ * The operands contain constraint strings and values to use.
+ * Outputs must be lvalues, inputs may be rvalues.  In the constraints:
+ * "a" means that the operand must be in eax.
+ * "d" means that the operand must be in edx.
+ * "g" means that the operand may be any effective address.
+ * "=" means that the operand is assigned to.
+ * "%" means that this operand and the following one may be
+ *     interchanged if desirable.
+ * "bcDSmn" means that the operand must be in ebx, ecx, esi, edi, memory,
+ *          or an immediate constant.  (This is almost the same as "g"
+ *          but allowing it in eax wouldn't help because x is already
+ *          assigned there, and it must not be in edx, since edx is
+ *          overwritten by the multiply before a and b are read.)
+ *
+ * Note that GCC uses AT&T assembler syntax, which is rather
+ * different from Intel syntax.  The length (b, w or l) of the
+ * operation is appended to the opcode, and the *second* operand
+ * is the destination, not the first.  Finally, the register names
+ * are all preceded with "%".  (Doubled here because % is a
+ * magic character.)
+ */
+
+/* (ph<<32) + pl = x*y */
+#define mul32_ppmm(ph,pl,x,y)  \
+       __asm__("mull %3" : "=d"(ph), "=a"(pl) : "%a"(x), "g"(y))
+
+/* (ph<<32) + pl = x*y + a */
+#define mul32_ppmma(ph,pl,x,y,a)       \
+       __asm__("mull %3\n\t"           \
+               "addl %4,%%eax\n\t"     \
+               "adcl %5,%%edx"         \
+               : "=&d"(ph), "=a"(pl)   \
+               : "%a"(x), "g"(y), "bcDSmn"(a), "bcDSmn"(0))
+
+/* (ph<<32) + pl = x*y + a + b */
+#define mul32_ppmmaa(ph,pl,x,y,a,b)    \
+       __asm__("mull %3\n\t"           \
+               "addl %4,%%eax\n\t"     \
+               "adcl %6,%%edx\n\t"     \
+               "addl %5,%%eax\n\t"     \
+               "adcl %6,%%edx"         \
+               : "=&d"(ph), "=a"(pl)   \
+               : "%a"(x), "g"(y), "%bcDSmn"(a), "bcDSmn"(b), "bcDSmn"(0))
+
+/* q = ((nh<<32) + nl) / d, return remainder.  nh guaranteed < d. */
+#undef lbnDiv21_32
+#define lbnDiv21_32(q,nh,nl,d) \
+       ({unsigned _;   \
+         __asm__("divl %4" : "=d"(_), "=a"(*q) : "d"(nh), "a"(nl), "g"(d)); \
+         _;})
+
+/* No quotient, just return remainder ((nh<<32) + nl) % d */
+#define lbnMod21_32(nh,nl,d)   \
+       ({unsigned _;   \
+         __asm__("divl %3" : "=d"(_) : "d"(nh), "a"(nl), "g"(d) : "ax"); \
+         _;})
+
+#endif /* __GNUC__ */
diff --git a/lib/bind/cylink/lbn8086.h b/lib/bind/cylink/lbn8086.h
new file mode 100644 (file)
index 0000000..863c5a0
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/*
+ * lbn8086.h - This file defines the interfaces to the 8086
+ * assembly primitives for 16-bit MS-DOS environments.
+ * It is intended to be included in "lbn.h"
+ * via the "#include BNINCLUDE" mechanism.
+ */
+#define BN_LITTLE_ENDIAN 1
+
+#ifdef __cplusplus
+/* These assembly-language primitives use C names */
+extern "C" {
+#endif
+
+/* Set up the appropriate types */
+typedef unsigned short bnword16;
+#define BNWORD16 bnword16
+typedef unsigned long bnword32;
+#define BNWORD32 bnword32
+
+void __cdecl __far
+lbnMulN1_16(bnword16 __far *out, bnword16 const __far *in,
+            unsigned len, bnword16 k);
+#define lbnMulN1_16 lbnMulN1_16
+            
+bnword16 __cdecl __far
+lbnMulAdd1_16(bnword16 __far *out, bnword16 const __far *in,
+              unsigned len, bnword16 k);
+#define lbnMulAdd1_16 lbnMulAdd1_16
+       
+bnword16 __cdecl __far
+lbnMulSub1_16(bnword16 __far *out, bnword16 const __far *in,
+              unsigned len, bnword16 k);
+#define lbnMulSub1_16 lbnMulSub1_16
+
+bnword16 __cdecl __far
+lbnDiv21_16(bnword16 __far *q, bnword16 nh, bnword16 nl, bnword16 d);
+#define lbnDiv21_16 lbnDiv21_16
+
+bnword16 __cdecl __far
+lbnModQ_16(bnword16 const __far *n, unsigned len, bnword16 d);
+#define lbnModQ_16 lbnModQ_16
+
+
+
+void __cdecl __far
+lbnMulN1_32(bnword32 __far *out, bnword32 const __far *in,
+            unsigned len, bnword32 k);
+#define lbnMulN1_32 lbnMulN1_32
+            
+bnword32 __cdecl __far
+lbnMulAdd1_32(bnword32 __far *out, bnword32 const __far *in,
+              unsigned len, bnword32 k);
+#define lbnMulAdd1_32 lbnMulAdd1_32
+       
+bnword32 __cdecl __far
+lbnMulSub1_32(bnword32 __far *out, bnword32 const __far *in,
+              unsigned len, bnword32 k);
+#define lbnMulSub1_32 lbnMulSub1_32
+
+bnword32 __cdecl __far
+lbnDiv21_32(bnword32 __far *q, bnword32 nh, bnword32 nl, bnword32 d);
+#define lbnDiv21_32 lbnDiv21_32
+
+bnword16 __cdecl __far
+lbnModQ_32(bnword32 const __far *n, unsigned len, bnword32 d);
+#define lbnModQ_32 lbnModQ_32
+
+int __cdecl __far not386(void);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/lib/bind/cylink/lbnmem.c b/lib/bind/cylink/lbnmem.c
new file mode 100644 (file)
index 0000000..6fac3ed
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/*
+ * lbnmem.c - low-level bignum memory handling.
+ *
+ * Copyright (c) 1995  Colin Plumb.  All rights reserved.
+ * For licensing and other legal details, see the file legal.c.
+ *
+ * Note that in all cases, the pointers passed around
+ * are pointers to the *least* significant end of the word.
+ * On big-endian machines, these are pointers to the *end*
+ * of the allocated range.
+ *
+ * BNSECURE is a simple level of security; for more security
+ * change these function to use locked unswappable memory.
+ */
+
+#include "port_before.h"
+
+#ifndef HAVE_CONFIG_H
+#define HAVE_CONFIG_H 0
+#endif
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/*
+ * Some compilers complain about #if FOO if FOO isn't defined,
+ * so do the ANSI-mandated thing explicitly...
+ */
+#ifndef NO_STDLIB_H
+#define NO_STDLIB_H 0
+#endif
+#ifndef NO_STRING_H
+#define NO_STRING_H 0
+#endif
+#ifndef HAVE_STRINGS_H
+#define HAVE_STRINGS_H 0
+#endif
+#ifndef NEED_MEMORY_H
+#define NEED_MEMORY_H 0
+#endif
+
+#if !NO_STDLIB_H
+#include <stdlib.h>    /* For malloc() & co. */
+#else
+void *malloc();
+void *realloc();
+void free();
+#endif
+
+#if !NO_STRING_H
+#include <string.h>    /* For memset */
+#elif HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#if NEED_MEMORY_H
+#include <memory.h>
+#endif
+
+#ifndef DBMALLOC
+#define DBMALLOC 0
+#endif
+#if DBMALLOC
+/* Development debugging */
+#include "../dbmalloc/malloc.h"
+#endif
+
+#include "lbn.h"
+#include "lbnmem.h"
+
+#include "kludge.h"
+
+#ifndef lbnMemWipe
+void
+lbnMemWipe(void *ptr, unsigned bytes)
+{
+       memset(ptr, 0, bytes);
+}
+#define lbnMemWipe(ptr, bytes) memset(ptr, 0, bytes)
+#endif
+
+#ifndef lbnMemAlloc
+void *
+lbnMemAlloc(unsigned bytes)
+{
+       return malloc(bytes);
+}
+#define lbnMemAlloc(bytes) malloc(bytes)
+#endif
+
+#ifndef lbnMemFree
+void
+lbnMemFree(void *ptr, unsigned bytes)
+{
+       lbnMemWipe(ptr, bytes);
+       free(ptr);
+}
+#endif
+
+#ifndef lbnRealloc
+#if defined(lbnMemRealloc) || !BNSECURE
+void *
+lbnRealloc(void *ptr, unsigned oldbytes, unsigned newbytes)
+{
+       if (ptr) {
+               BIG(ptr = (char *)ptr - oldbytes;)
+               if (newbytes < oldbytes)
+                       memmove(ptr, (char *)ptr + oldbytes-newbytes, oldbytes);
+       }
+#ifdef lbnMemRealloc
+       ptr = lbnMemRealloc(ptr, oldbytes, newbytes);
+#else
+       ptr = realloc(ptr, newbytes);
+#endif
+       if (ptr) {
+               if (newbytes > oldbytes)
+                       memmove((char *)ptr + newbytes-oldbytes, ptr, oldbytes);
+               BIG(ptr = (char *)ptr + newbytes;)
+       }
+
+       return ptr;
+}
+
+#else /* BNSECURE */
+
+void *
+lbnRealloc(void *oldptr, unsigned oldbytes, unsigned newbytes)
+{
+       void *newptr = lbnMemAlloc(newbytes);
+
+       if (!newptr)
+               return newptr;
+       if (!oldptr)
+               return BIGLITTLE((char *)newptr+newbytes, newptr);
+
+       /*
+        * The following copies are a bit non-obvious in the big-endian case
+        * because one of the pointers points to the *end* of allocated memory.
+        */
+       if (newbytes > oldbytes) {      /* Copy all of old into part of new */
+               BIG(newptr = (char *)newptr + newbytes;)
+               BIG(oldptr = (char *)oldptr - oldbytes;)
+               memcpy(BIGLITTLE((char *)newptr-oldbytes, newptr), oldptr,
+                      oldbytes);
+       } else {        /* Copy part of old into all of new */
+               memcpy(newptr, BIGLITTLE((char *)oldptr-newbytes, oldptr),
+                      newbytes);
+               BIG(newptr = (char *)newptr + newbytes;)
+               BIG(oldptr = (char *)oldptr - oldbytes;)
+       }
+
+       lbnMemFree(oldptr, oldbytes);
+       return newptr;
+}
+#endif /* BNSECURE */
+#endif /* !lbnRealloc */
diff --git a/lib/bind/cylink/lbnmem.h b/lib/bind/cylink/lbnmem.h
new file mode 100644 (file)
index 0000000..a3f1537
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/*
+ * Operations on the usual buffers of bytes
+ */
+#ifndef BNSECURE
+#define BNSECURE 1
+#endif
+
+/*
+ * These operations act on buffers of memory, just like malloc & free.
+ * One exception: it is not legal to pass a NULL pointer to lbnMemFree.
+ */
+
+#ifndef lbnMemAlloc
+void *lbnMemAlloc(unsigned bytes);
+#endif
+
+#ifndef lbnMemFree
+void lbnMemFree(void *ptr, unsigned bytes);
+#endif
+
+/* This wipes out a buffer of bytes if necessary needed. */
+
+#ifndef lbnMemWipe
+#if BNSECURE
+void lbnMemWipe(void *ptr, unsigned bytes);
+#else
+#define lbnMemWipe(ptr, bytes) (void)(ptr,bytes)
+#endif
+#endif /* !lbnMemWipe */
+
+/*
+ * lbnRealloc is NOT like realloc(); it's endian-sensitive!
+ * If lbnMemRealloc is #defined, lbnRealloc will be defined in terms of it.
+ * It is legal to pass a NULL pointer to lbnRealloc, although oldbytes
+ * will always be sero.
+ */
+#ifndef lbnRealloc
+void *lbnRealloc(void *ptr, unsigned oldbytes, unsigned newbytes);
+#endif
+
+
+/*
+ * These macros are the ones actually used most often in the math library.
+ * They take and return pointers to the *end* of the given buffer, and
+ * take sizes in terms of words, not bytes.
+ *
+ * Note that LBNALLOC takes the pointer as an argument instead of returning
+ * the value.
+ *
+ * Note also that these macros are only useable if you have included
+ * lbn.h (for the BIG and BIGLITTLE macros), which this file does NOT include.
+ */
+
+#define LBNALLOC(p,words) BIGLITTLE( \
+       if ( ((p) = lbnMemAlloc((words)*sizeof*(p))) != 0) (p) += (words), \
+       (p) = lbnMemAlloc((words) * sizeof*(p)) \
+       )
+#define LBNFREE(p,words) lbnMemFree((p) BIG(-(words)), (words) * sizeof*(p))
+#define LBNREALLOC(p,old,new) \
+       lbnRealloc(p, (old) * sizeof*(p), (new) * sizeof*(p))
+#define LBNWIPE(p,words) lbnMemWipe((p) BIG(-(words)), (words) * sizeof*(p))
+
diff --git a/lib/bind/cylink/lbnppc.c b/lib/bind/cylink/lbnppc.c
new file mode 100644 (file)
index 0000000..ed44e17
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+#include "lbnppc.h"
+
+/*
+ * lbnppc.c - Assembly primitives for the bignum library, PowerPC version.
+ *
+ * Copyright (c) 1995  Colin Plumb.  All rights reserved.
+ * For licensing and other legal details, see the file legal.c
+ *
+ * Register usage during function calls is:
+ * r0 - volatile
+ * r1 - stack pointer, preserved
+ * r2 - TOC pointer, preserved
+ * r3 - First argument and return value register
+ * r4-r10 - More argument registers, volatile
+ * r11-r12 - Volatile
+ * r13-r31 - Preserved
+ * LR, CTR, XER and MQ are all volatile.
+ * LR holds return address on entry.
+ *
+ * On the PPC 601, unrolling the loops more doesn't seem to speed things
+ * up at all.  I'd be curious if other chips differed.
+ */
+#if __MWERKS__ < 0x800
+
+#include "ppcasm.h"    /* PowerPC assembler */
+/*
+ * MulN1 expects (*out, *in, len, k), count >= 1
+ *                r3    r4   r5   r6
+ */
+static const unsigned mulN1[] = {
+       PPC_LWZ(7,4,0),         /* Load first word of in in r7 */
+       PPC_MULLW(8,7,6),       /* Low half of multiply in r8 */
+       PPC_MTCTR(5),           /* Move len into CTR */
+       PPC_ADDIC(0,0,0),       /* Clear carry bit for loop */
+       PPC_MULHWU(5,7,6),      /* High half of multiply in r5 */
+       PPC_STW(8,3,0),
+       PPC_BC(18,31,7),        /* Branch to Label if --ctr == 0 */
+/* Loop: */
+       PPC_LWZU(7,4,4),        /* r7 = *++in */
+       PPC_MULLW(8,7,6),       /* r8 = low word of product */
+       PPC_ADDE(8,8,5),        /* Add carry word r5 and bit CF to r8 */
+       PPC_STWU(8,3,4),        /* *++out = r8 */
+       PPC_MULHWU(5,7,6),      /* r5 is high word of product, for carry word */
+       PPC_BC(16,31,-5),       /* Branch to Loop if --ctr != 0 */
+/* Label: */
+       PPC_ADDZE(5,5),         /* Add carry flag to r5 */
+       PPC_STW(5,3,4),         /* out[1] = r5 */
+       PPC_BLR()
+};
+
+/*
+ * MulAdd1 expects (*out, *in, len, k), count >= 1
+ *                  r3    r4   r5   r6
+ */
+static unsigned const mulAdd1[] = {
+       PPC_LWZ(7,4,0),         /* Load first word of in in r7 */
+       PPC_LWZ(0,3,0),         /* Load first word of out into r0 */
+       PPC_MULLW(8,7,6),       /* Low half of multiply in r8 */
+       PPC_MTCTR(5),           /* Move len into CTR */
+       PPC_MULHWU(5,7,6),      /* High half of multiply in r5 */
+       PPC_ADDC(8,8,0),        /* r8 = r8 + r0 */
+       PPC_STW(8,3,0),         /* Store result to memory */
+       PPC_BC(18,31,10),       /* Branch to Label if --ctr == 0 */
+/* Loop: */
+       PPC_LWZU(7,4,4),        /* r7 = *++in */
+       PPC_LWZU(0,3,4),        /* r0 = *++out */
+       PPC_MULLW(8,7,6),       /* r8 = low word of product */
+       PPC_ADDE(8,8,5),        /* Add carry word r5 and carry bit CF to r8 */
+       PPC_MULHWU(5,7,6),      /* r5 is high word of product, for carry word */
+       PPC_ADDZE(5,5),         /* Add carry bit from low add to r5 */
+       PPC_ADDC(8,8,0),        /* r8 = r8 + r0 */
+       PPC_STW(8,3,0),         /* *out = r8 */
+       PPC_BC(16,31,-8),       /* Branch to Loop if --ctr != 0 */
+/* Label: */
+       PPC_ADDZE(3,5),         /* Add carry flag to r5 and move to r3 */
+       PPC_BLR()
+};
+
+/*
+ * MulSub1 expects (*out, *in, len, k), count >= 1
+ *                  r3    r4   r5   r6
+ *
+ * Multiply and subtract is rather a pain.  If the subtract of the
+ * low word of the product from out[i] generates a borrow, we want to
+ * increment the carry word (initially in the range 0..0xfffffffe).
+ * However, the PPC's carry bit CF is *clear* after a subtract, so
+ * we want to add (1-CF) to the carry word.  This is done using two
+ * instructions:
+ *
+ * SUBFME, subtract from minus one extended.  This computes
+ *   rD = ~rS + 0xffffffff + CF.  Since rS is from 0 to 0xfffffffe,
+ *   ~rS is from 1 through 0xffffffff, and the sum with 0xffffffff+CF is
+ *   from 0 through 0xfffffffff, setting the carry flag unconditionally, and
+ * NOR, which is used as a bitwise invert NOT instruction.
+ *
+ * The SUBFME performs the computation rD = ~rS + 0xffffffff + CF,
+ * = (-rS - 1) + (CF - 1) = -(rS - CF + 1) - 1 = ~(rS + 1-CF),
+ * which is the bitwise complement of the value we want.
+ * We want to add the complement of that result to the low word of the
+ * product, which is just what a subtract would do, if only we could get
+ * the carry flag clear.  But it's always set, except for SUBFE, and the
+ * operation we just performed unconditionally *sets* the carry flag.  Ugh.
+ * So find the complement in a separate instruction.
+ */
+static unsigned const mulSub1[] = {
+       PPC_LWZ(7,4,0),         /* Load first word of in in r7 */
+       PPC_LWZ(0,3,0),         /* Load first word of out into r0 */
+       PPC_MTCTR(5),           /* Move len into CTR */
+       PPC_MULLW(8,7,6),       /* Low half of multiply in r8 */
+       PPC_MULHWU(5,7,6),      /* High half of multiply in r5 */
+       PPC_SUBFC(8,8,0),       /* r8 = r0 - r8, setting CF */
+       PPC_STW(8,3,0),         /* Store result to memory */
+       PPC_SUBFME(5,5),        /* First of two insns to add (1-CF) to r5 */
+       PPC_BC(18,31,12),       /* Branch to Label if --ctr == 0 */
+/* Loop: */
+       PPC_LWZU(7,4,4),        /* r7 = *++in */
+       PPC_LWZU(0,3,4),        /* r0 = *++out */
+       PPC_NOR(5,5,5),         /* Second of two insns to add (1-CF) to r5 */
+       PPC_MULLW(8,7,6),       /* r8 = low word of product */
+       PPC_ADDC(8,8,5),        /* Add carry word r5 to r8 */
+       PPC_MULHWU(5,7,6),      /* r5 is high word of product, for carry word */
+       PPC_ADDZE(5,5),         /* Add carry bit from low add to r5 */
+       PPC_SUBFC(8,8,0),       /* r8 = r0 - r8, setting CF */
+       PPC_STW(8,3,0),         /* *out = r8 */
+       PPC_SUBFME(5,5),        /* First of two insns to add (1-CF) to r5 */
+       PPC_BC(16,31,-10),      /* Branch to Loop if --ctr != 0 */
+/* Label: */
+       PPC_NOR(3,5,5),         /* Finish adding (1-CF) to r5, store in r3 */
+       PPC_BLR()
+};
+
+#if 0
+/*
+ * Args: BNWORD32 *n, BNWORD32 const *mod, unsigned mlen, BNWORD32 inv)
+ *                r3                  r4            r5             r6
+ * r7, r8 and r9 are the triple-width accumulator.
+ * r0 and r10 are temporary registers.
+ * r11 and r12 are temporary pointers into n and mod, respectively. 
+ * r2 (!) is another temporary register.
+ */
+static unsigned const montReduce[] = {
+       PPC_MTCTR(5),   /* ??? */
+       PPC_LWZ(7,3,0),         /* Load low word of n into r7 */
+       PPC_LWZ(10,4,0),        /* Fetch low word of mod */
+       PPC_MULLW(0,7,6),       /* Invert r7 into r0 */
+       PPC_STW(0,3,0),         /* Store back for future use */
+       PPC_MULHWU(8,10,7),     /* Get high word of whatnot */
+       PPC_MULLW(10,10,7),     /* Get low word of it */
+       PPC_ADDC(7,7,10),       /* Add low word of product to r7 */
+       PPC_ADDZE(8,8),         /* Add carry to high word */
+       PPC_
+       
+
+       PPC_MULHW(8,7,6),
+       PPC_ADDC(7,7,0),        /* Add inverse back to r7 */
+       PPC_ADDZE(8,8),
+       PPC_
+       
+       PPC_LWZU(
+/* Loop: */
+       PPC_LWZU(0,11,4),
+       PPC_LWZU(10,23,-4),
+       PPC_MULLW(2,0,10),
+       PPC_ADDC(7,7,2),
+       PPC_MULHWU(0,0,10),
+       PPC_ADDE(8,8,0),
+       PPC_ADDZE(9,9),
+       PPC_BC(16,31,-7),       /* Branch to Loop if --ctr != 0 */
+
+       PPC_ADDIC_(count,-1),
+       PPC_LWZU(0,x,4),
+       PPC_ADDC(0,7,0),
+       PPC_STW(0,x,0),
+       PPC_ADDZE(7,8),
+       PPC_ADDZE(8,9),
+       PPC_LI(9,0),
+       PPC_BC(xx,2,yy),
+       
+};
+#endif
+
+/*
+ * Three overlapped transition vectors for three functions.
+ * A PowerPC transition vector for a (potentially) inter-module
+ * jump or call consists of two words, an instruction address
+ * and a Table Of Contents (TOC) pointer, which is loaded into
+ * r1.  Since none of the routines here have global variables,
+ * they don't need a TOC pointer, so the value is unimportant.
+ * This array places an unintersting 32-bit value after each address.
+ */
+unsigned const * const lbnPPC_tv[] = {
+       mulN1,
+       mulAdd1,
+       mulSub1,
+       0
+};
+
+#else /* __MWERKS >= 0x800 */
+
+/*
+ * MulN1 expects (*out, *in, len, k), count >= 1
+ *                r3    r4   r5   r6
+ */
+asm void
+lbnMulN1_32(register unsigned *out, register unsigned const *in,
+       register unsigned len, register unsigned k)
+{
+       lwz     r7,0(in)        /* Load first word of in in r7 */
+       mtctr   len                     /* Move len into CTR */
+       mullw   r8,r7,k         /* Low half of multiply in r8 */
+       addic   r0,r0,0         /* Clear carry bit for loop */
+       mulhwu  len,r7,k        /* High half of multiply in len */
+       stw     r8,0(out)       /* *out = r8 */
+       mulhwu  len,r7,k        /* len is high word of product, for carry */
+       bdz-    label           /* Branch to Label if --ctr == 0 */
+loop:
+       lwzu    r7,4(in)        /* r7 = *++in */
+       mullw   r8,r7,k         /* Low half of multiply in r8 */
+       adde    r8,r8,len       /* Add carry word len and bit CF to r8 */
+       stwu    r8,4(out)       /* *++out = r8 */
+       mulhwu  len,r7,k        /* len is high word of product, for carry */
+       bdnz+   loop            /* Branch to Loop if --ctr != 0 */
+label:
+       addze   len,len         /* Add carry flag to carry word */
+       stw     len,4(out)
+       blr
+}
+
+/*
+ * MulAdd1 expects (*out, *in, len, k), count >= 1
+ *                  r3    r4   r5   r6
+ */
+asm unsigned
+lbnMulAdd1_32(register unsigned *out, register unsigned const *in,
+       register unsigned len, register unsigned k)
+{
+       lwz     r7,0(in)        /* Load first word of in in r7 */
+       lwz     r0,0(out)       /* Load first word of out into r0 */
+       mullw   r8,r7,k         /* Low half of multiply in r8 */
+       mtctr   len             /* Move len into CTR */
+       mulhwu  len,r7,k        /* High half of multiply in len */
+       addc    r8,r8,r0        /* r8 = r8 + r0 */
+       stw     r8,0(out)       /* Store result to memory */
+       bdz-    label           /* Branch to Label if --ctr == 0 */
+loop:
+       lwzu    r7,4(in)        /* r7 = *++in */
+       lwzu    r0,4(out)       /* r0 = *++out */
+       mullw   r8,r7,k         /* r8 = low word of product */
+       adde    r8,r8,len       /* Add carry word len and carry bit CF to r8 */
+       mulhwu  len,r7,k        /* len is high word of product, for carry */
+       addze   len,len         /* Add carry bit from low add to r5 */
+       addc    r8,r8,r0        /* r8 = r8 + r0 */
+       stw     r8,0(out)       /* *out = r8 */
+       bdnz+   loop            /* Branch to Loop if --ctr != 0 */
+label:
+       addze   r3,r5           /* Add carry flag to r5 and move to r3 */
+       blr
+}
+
+/*
+ * MulSub1 expects (*out, *in, len, k), count >= 1
+ *                  r3    r4   r5   r6
+ *
+ * Multiply and subtract is rather a pain.  If the subtract of the
+ * low word of the product from out[i] generates a borrow, we want to
+ * increment the carry word (initially in the range 0..0xfffffffe).
+ * However, the PPC's carry bit CF is *clear* after a subtract, so
+ * we want to add (1-CF) to the carry word.  This is done using two
+ * instructions:
+ *
+ * SUBFME, subtract from minus one extended.  This computes
+ *   rD = ~rS + 0xffffffff + CF.  Since rS is from 0 to 0xfffffffe,
+ *   ~rS is from 1 through 0xffffffff, and the sum with 0xffffffff+CF is
+ *   from 0 through 0xfffffffff, setting the carry flag unconditionally, and
+ * NOR, which is used as a bitwise invert NOT instruction.
+ *
+ * The SUBFME performs the computation rD = ~rS + 0xffffffff + CF,
+ * = (-rS - 1) + (CF - 1) = -(rS - CF + 1) - 1 = ~(rS + 1-CF),
+ * which is the bitwise complement of the value we want.
+ * We want to add the complement of that result to the low word of the
+ * product, which is just what a subtract would do, if only we could get
+ * the carry flag clear.  But it's always set, except for SUBFE, and the
+ * operation we just performed unconditionally *sets* the carry flag.  Ugh.
+ * So find the complement in a separate instruction.
+ */
+asm unsigned
+lbnMulSub1_32(register unsigned *out, register unsigned const *in,
+       register unsigned len, register unsigned k)
+{
+       lwz     r7,0(in)        /* Load first word of in in r7 */
+       lwz     r0,0(out)       /* Load first word of out into r0 */
+       mtctr   len             /* Move len into CTR */
+       mullw   r8,r7,k         /* Low half of multiply in r8 */
+       mulhwu  len,r7,k        /* High half of multiply in len */
+       subfc   r8,r8,r0        /* r8 = r0 - r8, setting CF */
+       stw     r8,0(out)       /* Store result to memory */
+       subfme  len,len         /* First of two insns to add (1-CF) to len */
+       bdz-    label           /* Branch to Label if --ctr == 0 */
+loop:
+       lwzu    r7,4(in)        /* r7 = *++in */
+       lwzu    r0,4(out)       /* r0 = *++out */
+       nor     len,len,len     /* Second of two insns to add (1-CF) to len */
+       mullw   r8,r7,k         /* r8 = low word of product */
+       addc    r8,r8,len       /* Add carry word len to r8 */
+       mulhwu  len,r7,k        /* len is high word of product, for carry */
+       addze   len,len         /* Add carry bit from low add to len */
+       subfc   r8,r8,r0        /* r8 = r0 - r8 */
+       stw     r8,0(out)       /* *out = r8 */
+       subfme  len,len         /* First of two insns to add (1-CF) to len */
+       bdnz+   loop            /* Branch to Loop if --ctr != 0 */
+label:
+       nor     r3,r5,r5        /* Finish adding (1-CF) to len, store in r3 */
+       blr
+}
+
+#endif /* __MWERKS >= 0x800 */
+/* 45678901234567890123456789012345678901234567890123456789012345678901234567 */
diff --git a/lib/bind/cylink/lbnppc.h b/lib/bind/cylink/lbnppc.h
new file mode 100644 (file)
index 0000000..6d03d21
--- /dev/null
@@ -0,0 +1,98 @@
+#ifndef LBNPPC_H
+#define LBNPPC_H
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+
+/*
+ * Assembly-language routines for the Power PC processor.
+ * Annoyingly, the Power PC does not have 64/32->32 bit divide,
+ * so the C code should be reasonably fast.  But it does have
+ * 32x32->64-bit multiplies, and these routines provide access
+ * to that.
+ *
+ * In versions of CodeWarrior before 8.0, there was no PPC assembler,
+ * so a kludged-up one in CPP is used.  This requires casting an
+ * array of unsigneds to function pointer type, and a function pointer
+ * is not a pointer to the code, but rather a pointer to a (code,TOC)
+ * pointer pair which we fake up.
+ *
+ * CodeWarrior 8.0 supports PCC assembly, which is used directly.
+ */
+
+/*
+ * Bignums are stored in arrays of 32-bit words, and the least
+ * significant 32-bit word has the lowest address, thus "little-endian".
+ * The C code is slightly more efficient this way, so unless the
+ * processor cares (the PowerPC, like most RISCs, doesn't), it is
+ * best to use BN_LITTLE_ENDIAN.
+ * Note that this has NOTHING to do with the order of bytes within a 32-bit
+ * word; the math library is insensitive to that.
+ */
+#define BN_LITTLE_ENDIAN 1
+
+typedef unsigned bnword32;
+#define BNWORD32 bnword32
+
+#if __MWERKS__ < 0x800
+
+/* Shared transition vector array */
+extern unsigned const * const lbnPPC_tv[];
+
+/* A function pointer on the PowerPC is a pointer to a transition vector */
+#define lbnMulN1_32 \
+((void (*)(bnword32 *, bnword32 const *, unsigned, bnword32))(lbnPPC_tv+0))
+#define lbnMulAdd1_32 \
+((bnword32 (*)(bnword32 *, bnword32 const *, unsigned, bnword32))(lbnPPC_tv+1))
+#define lbnMulSub1_32 \
+((bnword32 (*)(bnword32 *, bnword32 const *, unsigned, bnword32))(lbnPPC_tv+2))
+
+#else /* __MWERKS__ >= 0x800 */
+
+void lbnMulN1_32(bnword32 *, bnword32 const *, unsigned, bnword32);
+#define lbnMulN1_32 lbnMulN1_32
+bnword32 lbnMulAdd1_32(bnword32 *, bnword32 const *, unsigned, bnword32);
+#define lbnMulAdd1_32 lbnMulAdd1_32
+bnword32 lbnMulSub1_32(bnword32 *, bnword32 const *, unsigned, bnword32);
+#define lbnMulSub1_32 lbnMulSub1_32
+
+#endif /* __MWERKS__ >= 0x800 */
+
+#endif /* LBNPPC_H */
diff --git a/lib/bind/cylink/legal.c b/lib/bind/cylink/legal.c
new file mode 100644 (file)
index 0000000..f750ed8
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+
+/* Force inclusion of this... */
+#include "legal.h"
+volatile const char bnCopyright[] =
+       "bnlib 1.0.1 Copyright (c) 1995,1996 Colin Plumb.";
diff --git a/lib/bind/cylink/legal.h b/lib/bind/cylink/legal.h
new file mode 100644 (file)
index 0000000..51d8552
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/*
+ * ANSI C standard, section 3.5.3: "An object that has volatile-qualified
+ * type may be modified in ways unknown to the implementation or have
+ * other unknown side effects."  Yes, we can't expect a compiler to
+ * understand law...
+ */
+extern volatile const char bnCopyright[];
diff --git a/lib/bind/cylink/math.c b/lib/bind/cylink/math.c
new file mode 100644 (file)
index 0000000..2f3a800
--- /dev/null
@@ -0,0 +1,1151 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/****************************************************************************
+*  FILENAME: math.c   PRODUCT NAME: CRYPTOGRAPHIC TOOLKIT
+*
+*  FILE STATUS:
+*
+*  DESCRIPTION: Math Routines for the ToolKit 
+*
+*  PUBLIC FUNCTIONS:
+*
+*         int Sum_big (ord *X,
+*                      ord *Y,
+*                      ord *Z,
+*                      u_int16_t len_X )
+*
+*         int Sub_big (ord *X,
+*                      ord *Y,
+*                      ord *Z,
+*                      u_int16_t len_X )
+*
+*         void  Mul_big( ord *X, ord *Y,ord *XY,
+*                        u_int16_t lx, u_int16_t ly)
+*
+*
+*  PRIVATE FUNCTIONS:
+*
+*  REVISION  HISTORY:
+*
+*  14 Oct 94   GKL     Initial release
+*  26 Oct 94   GKL     (alignment for big endian support )
+*
+****************************************************************************/
+
+/****************************************************************************
+*  INCLUDE FILES
+****************************************************************************/
+/* bn files */
+#include "port_before.h"
+#include "bn.h"
+/* system files */
+#ifdef VXD
+#include <vtoolsc.h>
+#else
+#include <stdlib.h>
+#include <string.h>
+#endif
+/* program files */
+#include "cylink.h"
+#include "ctk_endian.h"
+#include "toolkit.h"
+#include "port_after.h"
+
+/****************************************************************************
+*   NAME: void BigNumInit( void )
+*
+*
+*  DESCRIPTION:  Initialize BigNum
+*
+*  INPUTS:
+*     PARAMETERS:
+*  OUTPUT:
+*     PARAMETERS:
+*
+*     RETURN:
+*
+*
+*  REVISION HISTORY:
+*
+*  29 Sep 96        Initial release
+*
+****************************************************************************/
+
+void BigNumInit()
+{
+static int bignuminit = 0;
+if(!bignuminit){
+       bnInit();
+       bignuminit = 1;
+ }
+}
+/****************************************************************************
+*   NAME: int Sum_big (ord *X,
+*                      ord *Y,
+*                      ord *Z,
+*                      u_int16_t len_X )
+*
+*  DESCRIPTION:  Compute addition.
+*
+*  INPUTS:
+*     PARAMETERS:
+*           ord  *X        Pointer to first array
+*           ord  *Y        Pointer to second array
+*           int  len_X     Number of longs in X_l
+*  OUTPUT:
+*     PARAMETERS:
+*           ord *Z         Pointer to result arrray
+*
+*     RETURN:
+*            Carry bit
+*
+*  REVISION HISTORY:
+*
+*  24 Sep 94   KPZ     Initial release
+*  14 Oct 94   GKL     Second version (big endian support)
+*
+****************************************************************************/
+
+ int Sum_big (ord *X,
+                         ord *Y,
+                         ord *Z,
+                         u_int16_t len_X )
+{
+
+struct BigNum src2,temp_bn;
+ord *temp;
+BigNumInit();
+
+/*bnInit();
+bnBegin(&src2);
+bnBegin(&temp_bn);
+*/
+temp = (ord *) malloc((len_X*sizeof(ord)) + sizeof(ord));
+temp_bn.size = len_X;
+temp_bn.ptr = temp;
+temp_bn.allocated = len_X + 1;
+
+src2.ptr = Y;
+src2.size = len_X;
+src2.allocated = len_X;
+
+memcpy(temp,X,len_X*sizeof(ord));
+bnAdd(&temp_bn,&src2);
+memcpy(Z,temp_bn.ptr,len_X*sizeof(ord));
+/*bn package increments the size of dest by 1 if the carry bit is 1*/
+free(temp);
+if (temp_bn.size > len_X)
+       return 1;
+else
+       return 0;
+}
+
+ int Sum (ord *X, ord *Y, u_int16_t len_X )
+{
+
+struct BigNum dest,src;
+/*ord *temp;*/
+BigNumInit();
+#if 0
+bnInit();
+bnBegin(&src2);
+bnBegin(&temp_bn);
+
+temp = (ord *) malloc((len_X*sizeof(ord)) + sizeof(ord));
+temp_bn.size = len_X;
+temp_bn.ptr = temp;
+temp_bn.allocated = len_X + 1;
+#endif
+
+dest.ptr = X;
+dest.size = len_X-1;
+dest.allocated = len_X;
+
+src.ptr = Y;
+src.size = len_X;
+src.allocated = len_X;
+
+/*memcpy(temp,X,len_X*sizeof(ord));*/
+bnAdd(&dest,&src);
+/*memcpy(Z,temp_bn.ptr,len_X*sizeof(ord));*/
+/*bn package increments the size of dest by 1 if the carry bit is 1*/
+/*free(temp);*/
+if (dest.size > (u_int16_t)(len_X -1))
+       return 1;
+else
+       return 0;
+}
+
+
+/****************************************************************************
+*   NAME: int Sum_Q(ord *X,
+*                      u_int16_t src,
+*                      u_int16_t len_X )
+*  DESCRIPTION:  Compute addition X += src.
+*
+*  INPUTS:
+*     PARAMETERS:
+*           ord  *X        Pointer to first array
+*           u_int16_t  src    Second operand must be <65535
+*           int  len_X     Number of ords in X_l
+*  OUTPUT:
+*     PARAMETERS:
+*           ord *X         Pointer to result arrray
+*
+*     RETURN:
+*            SUCCESS or -1
+*
+*  REVISION HISTORY:
+*
+*  21 Sep 96   AAB     Initial release
+****************************************************************************/
+ int Sum_Q(ord *X, u_int16_t src, u_int16_t len_X )
+ {
+  int status = SUCCESS;
+  struct BigNum des;
+  BigNumInit();
+  /*bnInit();*/
+  des.ptr = X;
+  des.size = len_X;
+  des.allocated = len_X;
+  status = bnAddQ(&des, src);
+  return status;
+ }
+
+
+/****************************************************************************
+*  NAME:  int Sub_big (ord *X,
+*                      ord *Y,
+*                      ord *Z,
+*                      u_int16_t len_X )
+*
+*
+*  DESCRIPTION:  Compute subtraction.
+*
+*  INPUTS:
+*     PARAMETERS:
+*           ord   *X        Pointer to first array
+*           ord   *Y        Pointer to second array
+*           u_int16_t   len_X     Number of longs in X_l
+*  OUTPUT:
+*     PARAMETERS:
+*           ord  *Z         Pointer to result arrray
+*
+*     RETURN:
+*            Carry bit
+*
+*  REVISION HISTORY:
+*
+*  24 Sep 94   KPZ     Initial release
+*  14 Oct 94   GKL     Second version (big endian support)
+*
+****************************************************************************/
+
+int Sub_big  (ord *X,
+                         ord *Y,
+                         ord *Z,
+                         u_int16_t len_X )
+{
+/* carry is not returned in bn version */
+struct BigNum dest, src;
+int status;
+ord *temp;
+BigNumInit();
+/*bnInit();
+bnBegin(&dest);
+bnBegin(&src);
+*/
+src.ptr = Y;
+src.size = len_X;
+src.allocated = len_X;
+
+temp = (ord*)malloc(len_X*sizeof(ord));
+dest.ptr = temp;
+dest.size = len_X;
+dest.allocated = len_X;
+memcpy(dest.ptr,X,len_X*sizeof(ord));
+
+status = bnSub(&dest,&src);
+memcpy(Z,dest.ptr,len_X*sizeof(ord));
+free(temp);
+return status;
+}
+
+#if 0
+/****************************************************************************
+*  NAME:   void  Mul_big( ord  *X, ord *Y, ord *XY,
+*                         u_int16_t lx, u_int16_t ly)
+*
+*
+*
+*  DESCRIPTION:  Compute a product.
+*
+*  INPUTS:
+*     PARAMETERS:
+*            ord  *X                 Pointer to first long array
+*            ord  *Y                 Pointer to second long array
+*            u_int16_t lx               Leftmost non zero element of first array
+*            u_int16_t ly               Leftmost non zero element of second array
+*  OUTPUT:
+*     PARAMETERS:
+*            ord  *XY              Pointer to result
+*
+*     RETURN:
+*
+*
+*  REVISION HISTORY:
+*
+*  24 Sep 94   KPZ     Initial release
+*  14 Oct 94   GKL     Second version (big endian support)
+*  08 Sep 95   AAB     Comment out calloc and discard the elements_in_X,
+*                  elements_in_Y
+****************************************************************************/
+void  Mul_big( ord  *X, ord *Y, ord *XY,
+                                                u_int16_t lx, u_int16_t ly )
+{
+struct BigNum dest, src1, src2;
+BigNumInit();
+/*bnInit();*/
+bnBegin(&dest);
+/*
+bnBegin(&src1);
+bnBegin(&src2);
+*/
+src1.size = lx + 1;
+src1.ptr = X;
+src1.allocated = lx + 1;
+
+src2.ptr = Y;
+src2.size = ly + 1;
+src2.allocated = ly + 1;
+
+dest.ptr = XY;
+dest.size = lx + ly + 2;
+dest.allocated = lx + ly + 2;
+
+/* Call bn routine */
+bnMul(&dest, &src1,&src2);
+}
+
+#endif
+/****************************************************************************
+*  NAME:   void  Mul_big_1( ord  X, ord *Y, ord *XY,
+*                                 u_int16_t lx, u_int16_t ly )
+*
+*
+*
+*  DESCRIPTION:  Compute a product.
+*
+*  INPUTS:
+*     PARAMETERS:
+*            ord  X                  Number
+*            ord  *Y                 Pointer to long array
+*            u_int16_t ly               Leftmost non zero element of second array
+*  OUTPUT:
+*     PARAMETERS:
+*            ord  *XY              Pointer to result
+*
+*     RETURN:
+*
+*
+*  REVISION HISTORY:
+*
+*  08 Oct 95   AAB     Initial relaese
+*
+****************************************************************************/
+void  Mul_big_1( ord  X, ord *Y, ord *XY,
+                               u_int16_t ly )
+{
+struct BigNum dest, src;
+BigNumInit();
+/*bnInit();
+bnBegin(&dest);
+bnBegin(&src);
+*/
+src.ptr = Y;
+src.size = ly + 1;
+src.allocated = ly + 1;
+
+dest.ptr = XY;
+dest.size = ly + 2;
+dest.allocated = ly + 2;
+
+bnMulQ(&dest, &src, (unsigned)X);
+
+}
+
+/****************************************************************************
+*  NAME: int Mul( u_int16_t X_bytes,
+*                 ord        *X,
+*                 u_int16_t Y_bytes,
+*                 ord       *Y,
+*                 u_int16_t P_bytes,
+*                 ord   *P,
+*                 ord   *Z )
+*
+*  DESCRIPTION:  Compute a modulo product
+*
+*  INPUTS:
+*      PARAMETERS:
+*            ord   *X           Pointer to first operand
+*            u_int16_t X_bytes     Number of bytes in X
+*            ord   *Y           Pointer to second operand
+*            u_int16_t Y_bytes     Number of bytes in Y
+*            ord   *P           Pointer to modulo
+*            u_int16_t P_bytes     Number of bytes in P
+*
+*  OUTPUT:
+*      PARAMETERS:
+*            ord   *Z           Pointer to result
+*
+*      RETURN:
+*          SUCCESS              No errors
+*          ERR_INPUT_LEN        Invalid length for input data (zero bytes)
+*
+*  REVISION HISTORY:
+*
+*  24 Sep 94   KPZ     Initial release
+*  14 Oct 94   GKL     Second version (big endian support)
+*
+****************************************************************************/
+
+int Mul( u_int16_t X_bytes,
+                       ord *X,
+                u_int16_t Y_bytes,
+                       ord *Y,
+                u_int16_t P_bytes,
+                ord *P,
+                ord *Z )
+
+{
+       int status = SUCCESS;       /*function return status*/
+       u_int16_t X_longs;             /*number of longs in X*/
+       u_int16_t Y_longs;             /*number of longs in Y*/
+       ord *XY;                    /*pointer to product (temporary)*/
+
+
+struct BigNum dest, src1,src2, mod;
+BigNumInit();
+/*bnInit();
+bnBegin(&dest);
+bnBegin(&src1);
+bnBegin(&src2);
+bnBegin(&mod);
+*/
+
+src1.size = X_bytes/sizeof(ord);
+src1.ptr = X;
+src1.allocated = X_bytes/sizeof(ord);
+
+src2.size = Y_bytes/sizeof(ord);
+src2.ptr = Y;
+src2.allocated =Y_bytes/sizeof(ord);
+
+mod.size = P_bytes/sizeof(ord);
+mod.ptr = P;
+mod.allocated = P_bytes/sizeof(ord);
+
+        if ( P_bytes == 0 || X_bytes == 0 || Y_bytes == 0 )
+       {
+                status = ERR_INPUT_LEN;
+               return status;
+       }
+       if ( (X_bytes % sizeof(ord) != 0) ||
+                 (Y_bytes % sizeof(ord) != 0) ||
+                (P_bytes % sizeof(ord) != 0) )
+       {
+                status = ERR_INPUT_LEN;
+               return status;
+       }
+       X_longs = (u_int16_t) (X_bytes / sizeof(ord));
+       Y_longs = (u_int16_t) (Y_bytes / sizeof(ord));
+       XY = (ord *)calloc( X_longs +  Y_longs, sizeof(ord) );
+       if( !XY  )
+       {
+               return ERR_ALLOC;
+       }
+dest.size = X_longs + Y_longs;
+dest.ptr = XY;
+dest.allocated = X_longs + Y_longs;
+
+bnMul (&dest,&src1,&src2);
+
+status = bnMod(&dest, &dest, &mod);
+memcpy(Z, dest.ptr, P_bytes);
+free( XY );
+       return status;
+}
+
+/****************************************************************************
+*  NAME: int Square( u_int16_t X_bytes,
+*                         ord    *X,
+*                     u_int16_t P_bytes,
+*                        ord    *P,
+*                     ord   *Z )
+*
+*  DESCRIPTION:  Compute a modulo square
+*
+*  INPUTS:
+*      PARAMETERS:
+*            ord   *X           Pointer to array to be squared
+*            u_int16_t X_bytes     Number of bytes in X
+*            ord   *P           Pointer to modulo
+*            u_int16_t P_bytes     Number of bytes in P
+*
+*  OUTPUT:
+*      PARAMETERS:
+*            ord   *Z           Pointer to result
+*
+*      RETURN:
+*          SUCCESS              No errors
+*          ERR_INPUT_LEN        Invalid length for input data (zero bytes)
+*
+*  REVISION HISTORY:
+*
+*  1  Sep 95   AAB     Initial release
+****************************************************************************/
+
+int Square( u_int16_t X_bytes,
+                               ord *X,
+                               u_int16_t P_bytes,
+                               ord *P,
+                               ord *Z )
+
+{
+        int status = SUCCESS;       /*function return status*/
+
+ord *XY;
+struct BigNum dest, src, mod;
+BigNumInit();
+/*bnInit();
+bnBegin(&dest);
+bnBegin(&src);
+bnBegin(&mod);
+*/
+       if ( P_bytes == 0 || X_bytes == 0 )
+       {
+                status = ERR_INPUT_LEN;
+               return status;
+        }
+       if ( (X_bytes % sizeof(ord) != 0) ||
+                 (P_bytes % sizeof(ord) != 0) )
+        {
+                status = ERR_INPUT_LEN;
+               return status;
+        }
+       XY = (ord *)malloc( 2*X_bytes );
+        if( !XY )
+        {
+                return ERR_ALLOC;
+        }
+
+src.size = X_bytes/sizeof(ord);
+src.ptr = X;
+src.allocated = X_bytes/sizeof(ord);
+
+dest.size = 2*X_bytes/sizeof(ord);
+dest.ptr = XY;
+dest.allocated = 2*X_bytes/sizeof(ord);
+
+mod.size = P_bytes/sizeof(ord);
+mod.ptr = P;
+mod.allocated = P_bytes/sizeof(ord);
+
+status = bnSquare(&dest, &src);
+status = bnMod(&dest, &dest, &mod);
+memcpy(Z, dest.ptr, P_bytes);
+free(XY);
+return status;
+}
+
+
+/****************************************************************************
+*  NAME: int PartReduct( u_int16_t X_bytes,
+*                        ord  *X,
+*                        u_int16_t P_bytes,
+*                        ord  *P,
+*                        ord *Z )
+*
+*  DESCRIPTION:  Compute a modulo
+*
+*  INPUTS:
+*      PARAMETERS:
+*            ord   *X              Pointer to array
+*            u_int16_t X_bytes        Number of bytes in X
+*            ord   *P              Pointer to modulo
+*            u_int16_t P_bytes        Number of bytes in P
+*
+*  OUTPUT:
+*      PARAMETERS:
+*            ord   *Z              Pointer to result
+*
+*      RETURN:
+*          SUCCESS             No errors
+*          ERR_INPUT_LEN       Invalid length for input data (zero bytes)
+*  REVISION HISTORY:
+*
+*  24 Sep 94   KPZ     Initial release
+*  14 Oct 94   GKL     Second version (big endian support)
+*
+****************************************************************************/
+
+int PartReduct( u_int16_t X_bytes,
+         ord *X,
+         u_int16_t P_bytes,
+         ord   *P,
+         ord   *Z )
+{
+        int status = SUCCESS;       /*function return status */
+
+
+struct BigNum dest, /*src,*/ d;
+ord *temp;
+BigNumInit();
+/*bnInit();
+bnBegin(&dest);
+bnBegin(&src);
+bnBegin(&d);
+
+src.size = X_bytes/sizeof(ord);
+src.ptr = X;
+src.allocated = X_bytes/sizeof(ord);
+*/
+d.size = P_bytes/sizeof(ord);
+d.ptr = P;
+d.allocated = P_bytes/sizeof(ord);
+
+temp = (ord*)malloc(X_bytes);
+dest.size = X_bytes/sizeof(ord);
+dest.ptr = temp;
+dest.allocated = X_bytes/sizeof(ord);
+memcpy(dest.ptr, X, X_bytes);
+
+status = bnMod(&dest, &dest, &d);
+
+memcpy(Z, dest.ptr, P_bytes);
+free(temp);
+
+return status;
+
+}
+
+/****************************************************************************
+*  NAME: int Expo( u_int16_t X_bytes,
+*                  ord    *X,
+*                  u_int16_t Y_bytes,
+*                  ord    *Y,
+*                  u_int16_t P_bytes,
+*                  ord    *P,
+*                  ord    *Z,
+*                  YIELD_context *yield_cont )
+*
+*  DESCRIPTION:  Compute a modulo exponent
+*
+*  INPUTS:
+*      PARAMETERS:
+*            ord   *X           Pointer to base array
+*            u_int16_t X_bytes     Number of bytes in base
+*            ord   *Y           Pointer to exponent array
+*            u_int16_t Y_bytes     Number of bytes in exponent
+*            ord   *P           Pointer to modulo
+*            u_int16_t P_bytes     Number of bytes in  P
+*            YIELD_context *yield_cont  Pointer to yield_cont structure (NULL if not used)
+*
+*  OUTPUT:
+*      PARAMETERS:
+*            ord   *Z            Pointer to result
+*
+*  RETURN:
+*          SUCCESS               No errors
+*          ERR_INPUT_LEN         Invalid length for input data(zero bytes)
+*
+*  REVISION HISTORY:
+*
+*  24 Sep 94   KPZ     Initial release
+*  14 Oct 94   GKL     Second version (big endian support)
+*  08 Dec 94   GKL     Added YIELD_context
+*  01 Sep 95           Fast exponentation algorithm
+****************************************************************************/
+
+int Expo( u_int16_t X_bytes, ord    *X,
+                u_int16_t Y_bytes, ord    *Y,
+                u_int16_t P_bytes, ord    *P,
+                ord   *Z )
+{
+
+int status = SUCCESS;     /*function return status*/
+
+struct BigNum dest, n, exp, mod;
+BigNumInit();
+#if 0
+/*bnInit();*/
+bnBegin(&dest);
+bnBegin(&n);
+bnBegin(&exp);
+bnBegin(&mod);
+#endif
+
+n.size = X_bytes/sizeof(ord);
+n.ptr = X;
+n.allocated = X_bytes/sizeof(ord);
+
+exp.ptr = Y;
+exp.size = Y_bytes/sizeof(ord);
+exp.allocated = Y_bytes/sizeof(ord);
+
+mod.ptr = P;
+mod.size = P_bytes/sizeof(ord);
+mod.allocated = P_bytes/sizeof(ord);
+
+dest.ptr = Z;
+dest.size = P_bytes/sizeof(ord);
+dest.allocated = P_bytes/sizeof(ord);
+
+/* Call bn routine */
+
+status = bnExpMod(&dest, &n,
+                                 &exp, &mod);
+
+return status;
+}
+
+
+/****************************************************************************
+*  NAME: int DoubleExpo( u_int16_t X1_bytes,
+*                  ord    *X1,
+*                  u_int16_t Y1_bytes,
+*                  ord    *Y1,
+*                                       u_int16_t X2_bytes,
+*                  ord    *X2,
+*                  u_int16_t Y2_bytes,
+*                  ord    *Y2,
+*                  u_int16_t P_bytes,
+*                  ord    *P,
+*                  ord    *Z)
+*
+*  DESCRIPTION:  Compute a modulo exponent
+*
+*  INPUTS:
+*      PARAMETERS:
+*            ord   *X1           Pointer to first base array
+*            u_int16_t X1_bytes     Number of bytes in first base
+*            ord   *Y1           Pointer to first exponent array
+*            u_int16_t Y1_bytes     Number of bytes in first exponent
+*            ord   *X2           Pointer to second base array
+*            u_int16_t X2_bytes     Number of bytes in second base
+*            ord   *Y2           Pointer to second exponent array
+*            u_int16_t Y2_bytes     Number of bytes in second exponent            ord   *P           Pointer to modulo
+*            ord   *P           Pointer to modulo
+*            u_int16_t P_bytes     Number of bytes in
+*
+*  OUTPUT:
+*      PARAMETERS:
+*            ord   *Z            Pointer to result
+*
+*  RETURN:
+*          SUCCESS               No errors
+*          ERR_INPUT_LEN         Invalid length for input data(zero bytes)
+*
+*  REVISION HISTORY:
+*
+*  21 Aug 96   AAB     Initial release
+****************************************************************************/
+
+
+int DoubleExpo( u_int16_t X1_bytes,ord    *X1,
+                                        u_int16_t Y1_bytes,ord    *Y1,
+                                        u_int16_t X2_bytes,ord    *X2,
+                                        u_int16_t Y2_bytes,ord    *Y2,
+                                        u_int16_t P_bytes,ord    *P,
+                                                                                ord    *Z)
+{
+int status = SUCCESS;     /*function return status*/
+struct BigNum res, n1, e1, n2, e2, mod;
+BigNumInit();
+
+n1.size = X1_bytes/sizeof(ord);
+n1.ptr = X1;
+n1.allocated = X1_bytes/sizeof(ord);
+
+e1.size = Y1_bytes/sizeof(ord);
+e1.ptr = Y1;
+e1.allocated = Y1_bytes/sizeof(ord);
+
+n2.size = X2_bytes/sizeof(ord);
+n2.ptr = X2;
+n2.allocated = X2_bytes/sizeof(ord);
+
+e2.size = Y2_bytes/sizeof(ord);
+e2.ptr = Y2;
+e2.allocated = Y2_bytes/sizeof(ord);
+
+mod.ptr = P;
+mod.size = P_bytes/sizeof(ord);
+mod.allocated = P_bytes/sizeof(ord);
+
+res.ptr = Z;
+res.size = P_bytes/sizeof(ord);
+res.allocated = P_bytes/sizeof(ord);
+status = bnDoubleExpMod(&res, &n1, &e1, &n2, &e2, &mod);
+return status;
+}
+
+/****************************************************************************
+*  NAME: int Inverse( u_int16_t X_bytes,
+*                     ord    *X,
+*                     u_int16_t P_bytes,
+*                     ord    *P,
+*                     ord    *Z )
+*
+*
+*
+*
+*  DESCRIPTION:  Compute a modulo inverse element
+*
+*  INPUTS:
+*      PARAMETERS:
+*            ord   *X           Pointer to array
+*            u_int16_t X_bytes     Number of bytes in array
+*            ord   *P           Pointer to modulo
+*            u_int16_t P_bytes     Number of bytes in  P
+*
+*  OUTPUT:
+*      PARAMETERS:
+*            ord   *Z           Pointer to result
+*
+*      RETURN:
+*          SUCCESS              No errors
+*          ERR_INPUT_LEN        Invalid length for input data(zero bytes)
+*          ERR_INPUT_VALUE  Invalid input value
+*
+*  REVISION HISTORY:
+*
+*  24 Sep 94   KPZ     Initial release
+*  14 Oct 94   GKL     Second version (big endian support)
+*  08 Nov 94   GKL     Added input parameters check
+*  01 Sep 95           Improve fuction
+****************************************************************************/
+
+int Inverse( u_int16_t X_bytes,
+                         ord    *X,
+                         u_int16_t P_bytes,
+                        ord    *P,
+                               ord    *Z )
+{
+int status = SUCCESS;   /* function return status */
+
+struct BigNum dest, src, mod;
+BigNumInit();
+/*bnInit();
+bnBegin(&dest);
+bnBegin(&src);
+bnBegin(&mod);
+*/
+src.size = X_bytes/sizeof(ord);
+src.ptr = X;
+src.allocated = X_bytes/sizeof(ord);
+
+mod.ptr = P;
+mod.size = P_bytes/sizeof(ord);
+mod.allocated = P_bytes/sizeof(ord);
+
+dest.ptr = Z;
+dest.size = (P_bytes/sizeof(ord))  ;
+dest.allocated = (P_bytes/sizeof(ord)) + 1;
+status = bnInv(&dest,&src,&mod);
+return status;
+}
+
+
+/****************************************************************************
+*  NAME:     void Add( ord    *X,
+*                      ord    *Y,
+*                      u_int16_t P_len,
+*                      ord    *P,
+*                      ord    *Z )
+
+*
+*  DESCRIPTION:  Compute modulo addition
+*
+*  INPUTS:
+*          PARAMETERS:
+*                         ord   *X              Pointer to first operand
+*                         ord   *Y              Pointer to second operand
+*                         u_int16_t P_len  Length of modulo
+*                         ord   *P              Pointer to modulo
+*  OUTPUT:
+*             ord   *Z          Pointer to result
+*          RETURN:
+*
+*  REVISION HISTORY:
+*
+*  24 sep 94    KPZ             Initial release
+*  10 Oct 94    KPZ     Fixed bugs
+*  14 Oct 94    GKL     Second version (big endian support)
+*
+****************************************************************************/
+ /*
+ int Add( ord *X,
+                 ord *Y,
+         u_int16_t P_len,
+                 ord *P,
+                       ord *Z )
+{
+       int status = SUCCESS;
+       ord *temp;
+       struct BigNum dest, src, mod;
+
+bnInit();
+bnBegin(&dest);
+bnBegin(&src);
+bnBegin(&mod);
+
+temp = (ord*)malloc(P_len + sizeof(ord));
+memcpy(temp, X, P_len);
+
+dest.size = P_len/sizeof(ord);
+dest.ptr = temp;
+dest.allocated = P_len/sizeof(ord) + 1;
+
+src.ptr = Y;
+src.size = P_len/sizeof(ord);
+src.allocated = P_len/sizeof(ord);
+
+mod.ptr = P;
+mod.size = P_len/sizeof(ord);
+mod.allocated = P_len/sizeof(ord);
+
+status = bnAdd(&dest,&src);
+status = bnMod(&dest,&dest,&mod);
+memcpy(Z,temp,P_len);
+free(temp);
+return status;
+}
+ */
+ int Add( ord *X,
+                 ord *Y,
+         u_int16_t P_len,
+                 ord *P)
+{
+       int status = SUCCESS;
+/*     ord *temp;*/
+       struct BigNum dest, src, mod;
+
+BigNumInit();
+/*bnInit();
+bnBegin(&dest);
+bnBegin(&src);
+bnBegin(&mod);
+*/
+/*
+temp = (ord*)malloc(P_len + sizeof(ord));
+memcpy(temp, X, P_len);
+*/
+dest.size = P_len/sizeof(ord);
+/*dest.ptr = temp;*/
+dest.ptr = X;
+dest.allocated = P_len/sizeof(ord) + 1;
+
+src.ptr = Y;
+src.size = P_len/sizeof(ord);
+src.allocated = P_len/sizeof(ord);
+
+mod.ptr = P;
+mod.size = P_len/sizeof(ord);
+mod.allocated = P_len/sizeof(ord);
+
+status = bnAdd(&dest,&src);
+status = bnMod(&dest,&dest,&mod);
+/*
+memcpy(Z,temp,P_len);
+free(temp);
+*/
+return status;
+}
+
+
+
+
+/****************************************************************************
+*  NAME:     int SteinGCD( ord *m,
+*                          ord *b
+*                          u_int16_t len )
+*
+*  DESCRIPTION:  Compute great common divisor
+*
+*  INPUTS:
+*          PARAMETERS:
+*           ord *m           Pointer to first number
+*           ord *b           Pointer to second number
+*           u_int16_t len       Number of elements in number
+*  OUTPUT:
+*
+*  RETURN:
+*           TRUE                   if gcd != 1
+*           FALSE                                  if gcd == 1
+*  REVISION HISTORY:
+*
+*
+*  24 Sep 94    KPZ     Initial release
+*  14 Oct 94    GKL     Second version (big endian support)
+*  01 Sep 95    AAB     Speed up
+*
+****************************************************************************/
+
+
+/* test if GCD equal 1 */
+int  SteinGCD ( ord  *m,
+                 ord  *n,
+                               u_int16_t len )
+{
+
+int status;
+struct BigNum dest, a, b;
+ord *temp;
+BigNumInit();
+/*bnInit();
+bnBegin(&dest);
+bnBegin(&a);
+bnBegin(&b);
+*/
+a.size = len;
+a.ptr = m;
+a.allocated = len;
+
+b.size = len;
+b.ptr = n;
+b.allocated = len;
+
+temp = (ord*)malloc((len+1)*sizeof(ord));
+dest.size = len;
+dest.ptr = temp;
+dest.allocated = len+1;
+
+status = bnGcd(&dest, &a, &b);
+
+if (*(ord *)(dest.ptr) == 0x01 && dest.size == 1)
+ status = 0;
+else
+ status = 1;
+
+free(temp);
+
+return status;
+
+}
+
+
+/****************************************************************************
+*  NAME: int DivRem( u_int16_t X_bytes,
+*                    ord    *X,
+*                    u_int16_t P_bytes,
+*                    ord    *P,
+*                    ord    *Z,
+*                    ord    *D)
+*
+*  DESCRIPTION:  Compute a modulo and quotient
+*
+*  INPUTS:
+*          PARAMETERS:
+*                    ord   *X              Pointer to array
+*                    u_int16_t X_bytes        Number of bytes in X
+*                    ord   *P              Pointer to modulo
+*                    u_int16_t P_bytes        Number of bytes in  P
+*
+*  OUTPUT:
+*          PARAMETERS:
+*            ord   *Z              Pointer to result
+*            ord   *D                      Pointer to quotient
+*          RETURN:
+*                  SUCCESS             No errors
+*          ERR_INPUT_LEN       Invalid length for input data (zero bytes)
+*  REVISION HISTORY:
+*
+*  24 Sep 94   KPZ              Initial release
+*  10 Oct 94   KPZ      Fixed bugs
+*  14 Oct 94   GKL      Second version (big endian support)
+*
+****************************************************************************/
+
+int DivRem( u_int16_t X_bytes,
+                ord    *X,
+         u_int16_t P_bytes,
+                ord    *P,
+         ord    *Z,
+         ord    *D)
+{
+       int status = SUCCESS;       /* function return status */
+
+struct BigNum q, r, /*n,*/ d;
+ord *temp;
+BigNumInit();
+/*bnInit();
+bnBegin(&q);
+bnBegin(&r);
+bnBegin(&n);
+bnBegin(&d);
+
+n.size = X_bytes/sizeof(ord);
+n.ptr = X;
+n.allocated = X_bytes/sizeof(ord);
+*/
+d.size = P_bytes/sizeof(ord);
+d.ptr = P;
+d.allocated = P_bytes/sizeof(ord);
+
+q.size = (X_bytes/sizeof(ord)) - (P_bytes/sizeof(ord)) + 1;
+q.ptr = D;
+q.allocated = (X_bytes/sizeof(ord)) - (P_bytes/sizeof(ord)) + 1;
+
+temp = (ord *)malloc(X_bytes);
+r.size = X_bytes/sizeof(ord);
+r.ptr = temp;
+r.allocated = X_bytes/sizeof(ord);
+memcpy(r.ptr, X, X_bytes);
+
+status = bnDivMod(&q, &r, &r, &d);
+
+memcpy(Z, r.ptr, P_bytes);
+free(temp);
+
+return status;
+
+}
diff --git a/lib/bind/cylink/ppcasm.h b/lib/bind/cylink/ppcasm.h
new file mode 100644 (file)
index 0000000..ad55cfe
--- /dev/null
@@ -0,0 +1,575 @@
+#ifndef PPCASM_H
+#define PPCASM_H
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/*
+ * A PowerPC assembler in the C preprocessor.
+ * This assumes that ints are 32 bits, and uses them for the values.
+ *
+ * An assembly-language routine is simply an array of unsigned ints,
+ * initialized with the macros defined here.
+ *
+ * In the PowerPC, a generic function pointer does *not* point to the
+ * first word of code, but to a two (or possibly more) word "transition
+ * vector."  The first word of the TV points to the function's code.
+ * The second word is the function's TOC (Table Of Contents) pointer,
+ * which is loaded into r2.  The function's global variables are
+ * accessed via the TOC pointed to by r2.  TOC pointers are changed,
+ * for example, when a dynamically linked library is called, so the
+ * library can have private global variables.
+ *
+ * Saving r2 and reloading r2 each function call is a hassle that
+ * I'd really rather avoid, since a lot of useful assembly language routines
+ * can be written without global variables at all, so they don't need a TOC
+ * pointer.  But I haven't figured out how to persuade CodeWarrior 7 to
+ * generate an intra-TOC call to an array.  (CodeWarrior 8 supports
+ * PowerPC asm, which obviates the need to do the cast-to-function-pointer
+ * trick, which obviates the need for cross-TOC calls.)
+ *
+ * The basic PowerPC calling conventions for integers are:
+ * r0  - scratch.  May be modified by function calls.
+ * r1  - stack pointer.  Must be preserved across function calls.
+ *       See IMPORTANT notes on stack frame format below.
+ *       This must *ALWAYS*, at every instruction boundary, be 16-byte
+ *       aligned and point to a valid stack frame.  If a procedure
+ *       needs to create a stack frame, the recommended way is to do:
+ *       stwu r1,-frame_size(r1)
+ *       and on exit, recover with one of:
+ *       addi r1,r1,frame_size,   OR
+ *       lwz r1,0(r1)
+ * r2  - TOC pointer.  Points to the current table of contents.
+ *       Must be preserved across function calls.
+ * r3  - First argument register and return value register.
+ *       Arguments are passed in r3 through r10, and values returned in
+ *       r3 through r6, as needed.  (Usually only r3 for single word.)
+ * r4-r10 - More argument registers
+ * r11 - Scratch, may be modified by function calls.
+ *       On entry to indirect function calls, this points to the
+ *       transition vector, and additional words may be loaded
+ *       at offsets from it.  Some conventions use r12 instead.
+ * r12 - Scratch, may be modified by function calls.
+ * r13-r31 - Callee-save registers, may not be modified by function
+ *       calls.
+ * The LR, CTR and XER may be modified by function calls, as may the MQ
+ * register, on those processors for which it is implemented.
+ * CR fields 0, 1, 5, 6 and 7 are scratch and may be modified by function
+ * calls.  CR fields 2, 3 and 4 must be preserved across function calls.
+ *
+ * Stack frame format - READ
+ *
+ * r1 points to a stack frame, which must *ALWAYS*, meaning after each and
+ * every instruction, without excpetion, point to a valid 16-byte-aligned
+ * stack frame, defined as follows:
+ * - The 296 bytes below r1 (from -296(r1) to -1(r1)) are the so-called Red
+ *   Zone reserved for leaf procedures, which may use it without allocating
+ *   a stack frame and without decrementing r1.  The size comes from the room
+ *   needed to store all the callee-save registers: 19 64-bit integer registers
+ *   and 18 64-bit floating-point registers. (18+19)*8 = 296.  So any
+ *   procedure can save all the registers it needs to save before creating
+ *   a stack frame and moving r1.
+ *   The bytes at -297(r1) and below may be used by interrupt and exception
+ *   handlers *at any time*.  Anything placed there may disappear before
+ *   the next instruction.
+ *   The word at 0(r1) is the previous r1, and so on in a linked list.
+ *   This is the minimum needed to be a valid stack frame, but some other
+ *   offsets from r1 are preallocated by the calling procedure for the called
+ *   procedure's use.  These are:
+ *   Offset 0:  Link to previous stack frame - saved r1, if the called
+ *              procedure alters it.
+ *   Offset 4:  Saved CR, if the called procedure alters the callee-save
+ *              fields.  There's no important reason to save it here,
+ *              but the space is reserved and you might as well use it
+ *              for its intended purpose unless you have good reason to
+ *              do otherwise.  (This may help some debuggers.)
+ *   Offset 8:  Saved LR, if the called procedure needs to save it for
+ *              later function return.  Saving the LR here helps a debugger
+ *              track the chain of return addresses on the stack.
+ *              Note that a called procedure does not need to preserve the
+ *              LR for it's caller's sake, but it uually wants to preserve
+ *              the value for its own sake until it finishes and it's
+ *              time to return.  At that point, this is usually loaded
+ *              back into the LR and the branch accomplished with BLR.
+ *              However, if you want to be preverse, you could load it
+ *              into the CTR and use BCTR instead.
+ *   Offset 12: Reserved to compiler.  I can't find what this is for.
+ *   Offset 16: Reserved to compiler.  I can't find what this is for.
+ *   Offset 20: Saved TOC pointer.  In a cross-TOC call, the old TOC (r2)
+ *              is saved here before r2 is loaded with the new TOC value.
+ *              Again, it's not important to use this slot for this, but
+ *              you might as well.
+ * Beginning at offset 24 is the argument area.  This area is at least 8 words
+ * (32 bytes; I don't know what happens with 64 bits) long, and may be longer,
+ * up to the length of the longest argument list in a function called by
+ * the function which allocated this stack frame.  Generally, arguments
+ * to functions are passed in registers, but if those functions notice
+ * the address of the arguments being taken, the registers are stored
+ * into the space reserved for them in this area and then used from memory.
+ * Additional arguments that will not fit into registers are also stored
+ * here.  Variadic functions (like printf) generally start by saving
+ * all the integer argument registers from the "..." onwards to this space.
+ * For that reason, the space must be large enough to store all the argument
+ * registers, even if they're never used.
+ * (It could probably be safely shrunk if you're not calling any variadic
+ * functions, but be careful!)
+ * 
+ * Offsets above that are private to the calling function and shouldn't
+ * be messed with.  Generally, what appears there is locals, then saved
+ * registers.
+ *
+ *
+ * The floating-point instruction set isn't implemented yet (I'm too
+ * lazy, as I don't need it yet), but for when it is, the register
+ * usage convention is:
+ * FPSCR - Scratch, except for floating point exception enable fields,
+ * which should only be modified by functions defined to do so.
+ * fr0  - scratch
+ * fr1  - first floating point parameter and return value, scratch
+ * fr2  - second floating point parameter and return value (if needed), scratch
+ * fr3  - third floating point parameter and return value (if needed), scratch
+ * fr4  - fourth floating point parameter and return value (if needed), scratch
+ * fr5-fr13 - More floating point argument registers, scratch
+ * fr14-fr31 - Callee-save registers, may not be modified across a function call
+ *
+ * Complex values store the real part in the lower-numberd register of a pair.
+ * When mixing floating-point and integer arguments, reserve space (one register
+ * for single-precision, two for double-precision values) in the integer
+ * argument list for the floating-point values.  Those integer registers
+ * generally have undefined values, UNLESS there is no prototype for the call,
+ * in which case they should contain a copy of the floating-point value's
+ * bit pattern to cope with wierd software.
+ * If the floating point arguments go past the end of the integer registers,
+ * they are stored in the argument area as well as being passed in here.
+ *
+ * After the argument area comes the calling function's private storage.
+ * Typically, there are locals, followed by saved GP rgisters, followed
+ * by saved FP registers.
+ *
+ * Suggested instruction for allocating a stack frame:
+ *        stwu r1,-frame_size(r1)
+ * Suggested instructions for deallocating a stack frame:
+ *        addi r1,r1,frame_size
+ * or
+ *        lwz r1,0(r1)
+ * If frame_size is too big, you'll have to load the offset into a temp
+ * register, but be sure that r1 is updated atomically.
+ *
+ *
+ * Basic PowerPC instructions look like this:
+ *
+ *                      1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |   Opcode  | | | | | | | | | | | | | | | | | | | | | | | | | | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * Branch instructions look like this:
+ *
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |   Opcode  |             Branch offset                     |A|L|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * The L, or LK, or Link bit indicates that the return address for the
+ * branch should be copied to the link register (LR).
+ * The A, or AA, or absolute address bit, indicates that the address
+ * of the current instruction (NOTE: not next instruction!) should NOT
+ * be added to the branch offset; it is relative to address 0.
+ *
+ * Conditional branches looks like this:
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |   Opcode  |    BO   |   BI    |      Branch offset        |A|L|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * The BI field specifies the condition bit of interest (from the CR).
+ * The BO field specifies what's interesting.  You can branch on a
+ * combination of a bit of the condition register and --ctr, the CTR
+ * register.  Two bits encode the branch condition to use:
+ *   BRANCH IF
+ * 00--- = Bit BI is 0
+ * 01--- = Bit BI is 1
+ * 1z--- = don't care about bit BI (always true)
+ *   AND
+ * --00- = --ctr != 0
+ * --01- = --ctr == 0
+ * --1z- = don't decrement ctr (always true)
+ * The last bit us used as a branch prediction bit.  If set, it reverses
+ * the usual backward-branch-taken heuristic.
+ *
+ * y = branch prediction bit.  z = unused, must be 0
+ * 0000y - branch if --ctr != 0 && BI == 0
+ *         don't branch if --ctr == 0 || BI != 0
+ * 0001y - branch if --ctr == 0 && BI == 0
+ *         don't branch if --ctr != 0 || BI != 0
+ * 001zy - branch if BI == 0
+ *         don't branch if BI != 0
+ * 0100y - branch if --ctr != 0 && BI != 0
+ *         don't branch if --ctr == 0 || BI == 0
+ * 0101y - branch if --ctr == 0 && BI != 0
+ *         don't branch if --ctr != 0 || BI == 0
+ * 011zy - branch if BI != 0
+ *         don't branch if BI == 0
+ * 1z00y - branch if --ctr != 0
+ *         don't branch if --ctr == 0
+ * 1z01y - branch if --ctr == 0
+ *         don't branch if --ctr != 0
+ * 1z1zz - branch always
+ * If y is 1, the usual branch prediction (usually not taken, taken for
+ * backwards branches with immediate offsets) is reversed.
+ *
+ * Instructions with 2 operands and a 16-bit immediate field look like this:
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |   Opcode  |     D   |    A    |    16-bit immediate value     |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * Now, there are three variations of note.  In some instructions, the 16-bit
+ * value is sign-extended.  In others, it's zero-extended.  These are noted
+ * below as "simm" (signed immediate) and "uimm", respectively.  Also, which
+ * field is the destination and which is the source sometimes switches.
+ * Sometimes it's d = a OP imm, and sometimes it's a = s OP imm.  In the
+ * latter cases, the "d" field is referred to as "s" ("source" instead of
+ * "destination".  These are logical and shift instructions.  (Store also
+ * refers to the s register, but that's the source of the value to be stored.)
+ * The assembly mnemonics, however, always lists the destination first,
+ * swapping the order in the instruction if necessary.
+ * Third, quite often, if r0 is specified for the source a, then the constant
+ * value 0 is used instead.  Thus, r0 is of limited use - it can be used for
+ * some things, but not all.
+ *
+ * Instructions with three register operands look like this:
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |   Opcode  |     D   |    A    |    B    |     Subopcode     |C|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * For most of the instructions of interest the Opcode is 31 and the subopcode
+ * determines what the instruction does.  For a few instructions (mostly loads
+ * and stores), if the A field is 0, the constant 0 is used.  The "C"
+ * bit (also known as the "RC" bit) controls whether or not the condition
+ * codes are updated.  If it is set (indicated by a "." suffix on the official
+ * PowerPC opcodes, and a "_" suffix on these macros), condition code register
+ * field 0 (for integer instructions; field 1 for floating point) is updated
+ * to reflect the result of the operation.
+ * Some arithmetic instructions use the most significant bit of the subopcode
+ * field as an overflow enable bit (o suffix).
+ *
+ * Then there are the rotate and mask instructions, which have 5 operands, and
+ * fill the subopcode field with 2 more 5-bit fields.  See below for them.
+ *
+ * NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
+ * These macros fully parenthesize their arguments, but are not themselves
+ * fully parenthesized.  They are intended to be used for initializer lists,
+ * and if you want to do tricks with their numeric values, wrap them in
+ * parentheses.
+ */
+
+#define PPC_MAJOR(x)   ((x)<<26)       /* Major opcode (0..63) */
+#define PPC_MINOR(x)   ((x)<<1)        /* Minor opcode (0..1023) */
+#define PPC_RC 1               /* Record carry (. suffix, represented as _) */
+#define PPC_OE 1024            /* Overflow enable (o suffix) */
+#define PPC_DEST(reg)  ((reg)<<21)     /* Dest register field */
+#define PPC_SRCA(reg)  ((reg)<<16)     /* First source register field */
+#define PPC_SRCB(reg)  ((reg)<<11)     /* Second source register field */
+#define PPC_AA 2       /* Branch is absolute, relative to address 0 */
+#define PPC_LK 1       /* Branch with link (L suffix) */
+
+/* Unconditional branch (dest is 26 bits, +/- 2^25 bytes) */
+#define PPC_B(dest)    PPC_MAJOR(18)|(((dest)<<2) & 0x03fffffc)
+#define PPC_BA(dest)   PPC_B(dest)|PPC_AA
+#define PPC_BL(dest)   PPC_B(dest)|PPC_LK
+#define PPC_BLA(dest)  PPC_B(dest)|PPC_AA|PPC_LK
+
+/* Three-operand instructions */
+#define PPC_TYPE31(minor,d,a,b)        \
+       PPC_MAJOR(31)|PPC_DEST(d)|PPC_SRCA(a)|PPC_SRCB(b)|PPC_MINOR(minor)
+#define PPC_ADD(d,a,b)         PPC_TYPE31(266,d,a,b)
+#define PPC_ADD_(d,a,b)        PPC_TYPE31(266,d,a,b)|PPC_RC
+#define PPC_ADDO(d,a,b)        PPC_TYPE31(266,d,a,b)|PPC_OE
+#define PPC_ADDO_(d,a,b)       PPC_TYPE31(266,d,a,b)|PPC_OE|PPC_RC
+#define PPC_ADDC(d,a,b)        PPC_TYPE31(10,d,a,b)
+#define PPC_ADDC_(d,a,b)       PPC_TYPE31(10,d,a,b)|PPC_RC
+#define PPC_ADDCO(d,a,b)       PPC_TYPE31(10,d,a,b)|PPC_OE
+#define PPC_ADDCO_(d,a,b)      PPC_TYPE31(10,d,a,b)|PPC_OE|PPC_RC
+#define PPC_ADDE(d,a,b)        PPC_TYPE31(138,d,a,b)
+#define PPC_ADDE_(d,a,b)       PPC_TYPE31(138,d,a,b)|PPC_RC
+#define PPC_ADDEO(d,a,b)       PPC_TYPE31(138,d,a,b)|PPC_OE
+#define PPC_ADDEO_(d,a,b)      PPC_TYPE31(138,d,a,b)|PPC_OE|PPC_RC
+#define PPC_ADDME(d,a)         PPC_TYPE31(234,d,a,0)
+#define PPC_ADDME_(d,a)        PPC_TYPE31(234,d,a,0)|PPC_RC
+#define PPC_ADDMEO(d,a)        PPC_TYPE31(234,d,a,0)|PPC_OE
+#define PPC_ADDMEO_(d,a)       PPC_TYPE31(234,d,a,0)|PPC_OE|PPC_RC
+#define PPC_ADDZE(d,a)         PPC_TYPE31(202,d,a,0)
+#define PPC_ADDZE_(d,a)        PPC_TYPE31(202,d,a,0)|PPC_RC
+#define PPC_ADDZEO(d,a)        PPC_TYPE31(202,d,a,0)|PPC_OE
+#define PPC_ADDZEO_(d,a)       PPC_TYPE31(202,d,a,0)|PPC_OE|PPC_RC
+#define PPC_AND(a,s,b)         PPC_TYPE31(28,s,a,b)
+#define PPC_AND_(a,s,b)        PPC_TYPE31(28,s,a,b)|PPC_RC
+#define PPC_ANDC(a,s,b)        PPC_TYPE31(60,s,a,b)
+#define PPC_ANDC_(a,s,b)       PPC_TYPE31(60,s,a,b)|PPC_RC
+#define PPC_CMP(cr,a,b)        PPC_TYPE31(0,(cr)<<2,a,b)
+#define PPC_CMPL(cr,a,b)       PPC_TYPE31(32,(cr)<<2,a,b)
+#define PPC_CNTLZW(a,s)        PPC_TYPE31(26,s,a,0)
+#define PPC_CNTLZW_(a,s)       PPC_TYPE31(26,s,a,0)|PPC_RC
+#define PPC_DCBF(a,b)          PPC_TYPE31(86,0,a,b)
+#define PPC_DCBI(a,b)          PPC_TYPE31(470,0,a,b)
+#define PPC_DCBST(a,b)         PPC_TYPE31(54,0,a,b)
+#define PPC_DCBT(a,b)          PPC_TYPE31(278,0,a,b)
+#define PPC_DCBTST(a,b)        PPC_TYPE31(246,0,a,b)
+#define PPC_DCBZ(a,b)          PPC_TYPE31(1014,0,a,b)
+#define PPC_DIVW(d,a,b)        PPC_TYPE31(491,d,a,b)
+#define PPC_DIVW_(d,a,b)       PPC_TYPE31(491,d,a,b)|PPC_RC
+#define PPC_DIVWO(d,a,b)       PPC_TYPE31(491,d,a,b)|PPC_OE
+#define PPC_DIVWO_(d,a,b)      PPC_TYPE31(491,d,a,b)|PPC_OE|PPC_RC
+#define PPC_DIVWU(d,a,b)       PPC_TYPE31(459,d,a,b)
+#define PPC_DIVWU_(d,a,b)      PPC_TYPE31(459,d,a,b)|PPC_RC
+#define PPC_DIVWUO(d,a,b)      PPC_TYPE31(459,d,a,b)|PPC_OE
+#define PPC_DIVWUO_(d,a,b)     PPC_TYPE31(459,d,a,b)|PPC_OE|PPC_RC
+#define PPC_EIEIO()            PPC_TYPE31(854,0,0,0)
+#define PPC_EQV(a,s,b)         PPC_TYPE31(284,s,a,b)
+#define PPC_EQV_(a,s,b)        PPC_TYPE31(284,s,a,b)|PPC_RC
+#define PPC_EXTSB(a,s,b)       PPC_TYPE31(954,s,a,b)
+#define PPC_EXTSB_(a,s,b)      PPC_TYPE31(954,s,a,b)|PPC_RC
+#define PPC_EXTSH(a,s,b)       PPC_TYPE31(922,s,a,b)
+#define PPC_EXTSH_(a,s,b)      PPC_TYPE31(922,s,a,b)|PPC_RC
+#define PPC_ICBI(a,b)          PPC_TYPE31(982,0,a,b)
+#define PPC_ISYNC()            PPC_TYPE31(150,0,0,0)
+#define PPC_LBZUX(d,a,b)       PPC_TYPE31(119,d,a,b)
+#define PPC_LBZX(d,a,b)        PPC_TYPE31(87,d,a,b)
+#define PPC_LHAUX(d,a,b)       PPC_TYPE31(375,d,a,b)
+#define PPC_LHAX(d,a,b)        PPC_TYPE31(343,d,a,b)
+#define PPC_LHBRX(d,a,b)       PPC_TYPE31(790,d,a,b)
+#define PPC_LHZUX(d,a,b)       PPC_TYPE31(311,d,a,b)
+#define PPC_LHZX(d,a,b)        PPC_TYPE31(279,d,a,b)
+#define PPC_LSWI(d,a,nb)       PPC_TYPE31(597,d,a,nb)
+#define PPC_LSWX(d,a,b)        PPC_TYPE31(533,d,a,b)
+#define PPC_LSARX(d,a,b)       PPC_TYPE31(20,d,a,b)
+#define PPC_LSBRX(d,a,b)       PPC_TYPE31(534,d,a,b)
+#define PPC_MCRXR(crd)         PPC_TYPE31(512,(crd)<<2,0,0)
+#define PPC_MFCR(d)            PPC_TYPE31(19,d,0,0)
+#define PPC_MFSPR(d,spr)       PPC_TYPE31(339,d,(spr)&31,(spr)>>5)
+#define PPC_MFTB(d)            PPC_TYPE31(371,d,12,8)
+#define PPC_MFTBU(d)           PPC_TYPE31(371,d,13,8)
+#define PPC_MTCRF(mask,s)      PPC_TYPE31(144,s,0,(mask)&0xff)
+#define PPC_MTSPR(s,spr)       PPC_TYPE31(467,s,(spr)&31,(spr)>>5)
+#define PPC_MULHW(d,a,b)       PPC_TYPE31(75,d,a,b)
+#define PPC_MULHW_(d,a,b)      PPC_TYPE31(75,d,a,b)|PPC_RC
+#define PPC_MULHWU(d,a,b)      PPC_TYPE31(11,d,a,b)
+#define PPC_MULHWU_(d,a,b)     PPC_TYPE31(11,d,a,b)|PPC_RC
+#define PPC_MULLW(d,a,b)       PPC_TYPE31(235,d,a,b)
+#define PPC_MULLW_(d,a,b)      PPC_TYPE31(235,d,a,b)|PPC_RC
+#define PPC_MULLWO(d,a,b)      PPC_TYPE31(235,d,a,b)|PPC_OE
+#define PPC_MULLWO_(d,a,b)     PPC_TYPE31(235,d,a,b)|PPC_OE|PPC_RC
+#define PPC_NAND(a,s,b)        PPC_TYPE31(476,s,a,b)
+#define PPC_NAND_(a,s,b)       PPC_TYPE31(476,s,a,b)|PPC_RC
+#define PPC_NEG(d,a)           PPC_TYPE31(104,d,a,b)
+#define PPC_NEG_(d,a)          PPC_TYPE31(104,d,a,b)|PPC_RC
+#define PPC_NEGO(d,a)          PPC_TYPE31(104,d,a,b)|PPC_OE
+#define PPC_NEGO_(d,a)         PPC_TYPE31(104,d,a,b)|PPC_OE|PPC_RC
+#define PPC_NOR(a,s,b)         PPC_TYPE31(124,s,a,b)
+#define PPC_NOR_(a,s,b)        PPC_TYPE31(124,s,a,b)|PPC_RC
+#define PPC_OR(a,s,b)          PPC_TYPE31(444,s,a,b)
+#define PPC_OR_(a,s,b)         PPC_TYPE31(444,s,a,b)|PPC_RC
+#define PPC_ORC(a,s,b)         PPC_TYPE31(412,s,a,b)
+#define PPC_ORC_(a,s,b)        PPC_TYPE31(412,s,a,b)|PPC_RC
+#define PPC_SLW(a,s,b)         PPC_TYPE31(24,s,a,b)
+#define PPC_SLW_(a,s,b)        PPC_TYPE31(24,s,a,b)|PPC_RC
+#define PPC_SRAW(a,s,b)        PPC_TYPE31(792,s,a,b)
+#define PPC_SRAW_(a,s,b)       PPC_TYPE31(792,s,a,b)|PPC_RC
+#define PPC_SRAWI(a,s,sh)      PPC_TYPE31(824,s,a,sh)
+#define PPC_SRAWI_(a,s,sh)     PPC_TYPE31(824,s,a,sh)|PPC_RC
+#define PPC_SRW(a,s,b)         PPC_TYPE31(536,s,a,b)
+#define PPC_SRW_(a,s,b)        PPC_TYPE31(536,s,a,b)|PPC_RC
+#define PPC_STBUX(s,a,b)       PPC_TYPE31(247,s,a,b)
+#define PPC_STBX(s,a,b)        PPC_TYPE31(215,s,a,b)
+#define PPC_STHBRX(s,a,b)      PPC_TYPE31(918,s,a,b)
+#define PPC_STHUX(s,a,b)       PPC_TYPE31(439,s,a,b)
+#define PPC_STHX(s,a,b)        PPC_TYPE31(407,s,a,b)
+#define PPC_STSWI(s,a,nb)      PPC_TYPE31(725,s,a,nb)
+#define PPC_STSWX(s,a,b)       PPC_TYPE31(661,s,a,b)
+#define PPC_STWBRX(s,a,b)      PPC_TYPE31(662,s,a,b)
+#define PPC_STWCX_(s,a,b)      PPC_TYPE31(150,s,a,b)|PPC_RC
+#define PPC_STWUX(s,a,b)       PPC_TYPE31(183,s,a,b)
+#define PPC_STWX(s,a,b)        PPC_TYPE31(151,s,a,b)
+#define PPC_SUBF(d,a,b)        PPC_TYPE31(40,d,a,b)
+#define PPC_SUBF_(d,a,b)       PPC_TYPE31(40,d,a,b)|PPC_RC
+#define PPC_SUBFO(d,a,b)       PPC_TYPE31(40,d,a,b)|PPC_OE
+#define PPC_SUBFO_(d,a,b)      PPC_TYPE31(40,d,a,b)|PPC_OE|PPC_RC
+#define PPC_SUB(d,b,a)         PPC_SUBF(d,a,b)
+#define PPC_SUB_(d,b,a)                PPC_SUBF_(d,a,b)
+#define PPC_SUBO(d,b,a)                PPC_SUBFO(d,a,b)
+#define PPC_SUBO_(d,b,a)       PPC_SUBFO_(d,a,b)
+#define PPC_SUBFC(d,a,b)       PPC_TYPE31(8,d,a,b)
+#define PPC_SUBFC_(d,a,b)      PPC_TYPE31(8,d,a,b)|PPC_RC
+#define PPC_SUBFCO(d,a,b)      PPC_TYPE31(8,d,a,b)|PPC_OE
+#define PPC_SUBFCO_(d,a,b)     PPC_TYPE31(8,d,a,b)|PPC_OE|PPC_RC
+#define PPC_SUBFE(d,a,b)       PPC_TYPE31(136,d,a,b)
+#define PPC_SUBFE_(d,a,b)      PPC_TYPE31(136,d,a,b)|PPC_RC
+#define PPC_SUBFEO(d,a,b)      PPC_TYPE31(136,d,a,b)|PPC_OE
+#define PPC_SUBFEO_(d,a,b)     PPC_TYPE31(136,d,a,b)|PPC_OE|PPC_RC
+#define PPC_SUBFME(d,a)        PPC_TYPE31(232,d,a,0)
+#define PPC_SUBFME_(d,a)       PPC_TYPE31(232,d,a,0)|PPC_RC
+#define PPC_SUBFMEO(d,a)       PPC_TYPE31(232,d,a,0)|PPC_OE
+#define PPC_SUBFMEO_(d,a)      PPC_TYPE31(232,d,a,0)|PPC_OE|PPC_RC
+#define PPC_SUBFZE(d,a)        PPC_TYPE31(200,d,a,0)
+#define PPC_SUBFZE_(d,a)       PPC_TYPE31(200,d,a,0)|PPC_RC
+#define PPC_SUBFZEO(d,a)       PPC_TYPE31(200,d,a,0)|PPC_OE
+#define PPC_SUBFZEO_(d,a)      PPC_TYPE31(200,d,a,0)|PPC_OE|PPC_RC
+#define PPC_SYNC()             PPC_TYPE31(598,0,0,0)
+#define PPC_TW(to,a,b)         PPC_TYPE31(4,to,a,b)
+#define PPC_XOR(a,s,b)         PPC_TYPE31(316,s,a,b)   
+
+/* Immediate-operand instructions.  Take a 16-bit immediate operand */
+#define PPC_IMM(major,d,a,imm) \
+       PPC_MAJOR(major)|PPC_DEST(d)|PPC_SRCA(a)|((imm)&0xffff)
+/* Trap word immediate */
+#define PPV_TWI(to,a,simm)     PPC_IMM(3,to,a,simm)
+/* Integer arithmetic */
+#define PPC_MULLI(d,a,simm)    PPC_IMM(7,d,a,simm)
+#define PPC_SUBFIC(s,a,simm)   PPC_IMM(8,s,a,simm)
+#define PPC_CMPLI(cr,a,uimm)   PPC_IMM(10,(cr)<<2,a,uimm)
+#define PPC_CMPI(cr,a,simm)    PPC_IMM(11,(cr)<<2,a,simm)
+#define PPC_ADDIC(d,a,simm)    PPC_IMM(12,d,a,simm)
+#define PPC_ADDIC_(d,a,simm)   PPC_IMM(13,d,a,simm)
+#define PPC_ADDI(d,a,simm)     PPC_IMM(14,d,a,simm)
+#define PPC_ADDIS(d,a,simm)    PPC_IMM(15,d,a,simm)
+
+/* Conditional branch (dest is 16 bits, +/- 2^15 bytes) */
+#define PPC_BC(bo,bi,dest)     PPC_IMM(16,bo,bi,((dest)<<2)&0xfffc)
+#define PPC_BCA(bo,bi,dest)    PPC_BC(bo,bi,dest)|PPC_AA
+#define PPC_BCL(bo,bi,dest)    PPC_BC(bo,bi,dest)|PPC_LK
+#define PPC_BCLA(bo,bi,dest)   PPC_BC(bo,bi,dest)|PPC_AA|PPC_LK
+
+/* Logical operations */
+#define PPC_ORI(a,s,uimm)      PPC_IMM(24,s,a,uimm)
+#define PPC_ORIS(a,s,uimm)     PPC_IMM(25,s,a,uimm)
+#define PPC_XORI(a,s,uimm)     PPC_IMM(26,s,a,uimm)
+#define PPC_XORIS(a,s,uimm)    PPC_IMM(27,s,a,uimm)
+#define PPC_ANDI_(a,s,uimm)    PPC_IMM(28,s,a,uimm)
+#define PPC_ANDIS(a,s,uimm)    PPC_IMM(29,s,a,uimm)
+
+/* Load/store */
+#define PPC_LWZ(d,a,simm)      PPC_IMM(32,d,a,simm)
+#define PPC_LWZU(d,a,simm)     PPC_IMM(33,d,a,simm)
+#define PPC_LBZ(d,a,simm)      PPC_IMM(34,d,a,simm)
+#define PPC_LBZU(d,a,simm)     PPC_IMM(35,d,a,simm)
+#define PPC_STW(s,a,simm)      PPC_IMM(36,s,a,simm)
+#define PPC_STWU(s,a,simm)     PPC_IMM(37,s,a,simm)
+#define PPC_STB(s,a,simm)      PPC_IMM(38,s,a,simm)
+#define PPC_STBU(s,a,simm)     PPC_IMM(39,s,a,simm)
+#define PPC_LHZ(d,a,simm)      PPC_IMM(40,d,a,simm)
+#define PPC_LHZU(d,a,simm)     PPC_IMM(41,d,a,simm)
+#define PPC_LHA(d,a,simm)      PPC_IMM(42,d,a,simm)
+#define PPC_STH(s,a,simm)      PPC_IMM(44,s,a,simm)
+#define PPC_STHU(s,a,simm)     PPC_IMM(45,s,a,simm)
+#define PPC_LHAU(d,a,simm)     PPC_IMM(43,d,a,simm)
+#define PPC_LMW(d,a,simm)      PPC_IMM(46,d,a,simm)
+#define PPC_STMW(s,a,simm)     PPC_IMM(47,s,a,simm)
+
+/* Major number = 19 - condition register operations.  d, a and b are CR bits */
+#define PPC_TYPE19(minor,d,a,b) \
+       PPC_MAJOR(19)|PPC_DEST(d)|PPC_SRCA(a)|PPC_SRCB(b)|PPC_MINOR(minor)
+#define PPC_MCRF(d,s)          PPC_TYPE19(0,(d)<<2,(s)<<2,0)
+#define PPC_CRNOR(d,a,b)       PPC_TYPE19(33,d,a,b)
+#define PPC_CRANDC(d,a,b)      PPC_TYPE19(129,d,a,b)
+#define PPC_CRXOR(d,a,b)       PPC_TYPE19(193,d,a,b)
+#define PPC_CRNAND(d,a,b)      PPC_TYPE19(225,d,a,b)
+#define PPC_CRAND(d,a,b)       PPC_TYPE19(257,d,a,b)
+#define PPC_CREQV(d,a,b)       PPC_TYPE19(289,d,a,b)
+#define PPC_CRORC(d,a,b)       PPC_TYPE19(417,d,a,b)
+#define PPC_CROR(d,a,b)        PPC_TYPE19(449,d,a,b)
+
+/* Indirect conditional branch */
+#define PPC_BCLR(bo,bi)        PPC_TYPE19(16,bo,bi,0)
+#define PPC_BCLRL(bo,bi)       PPC_TYPE19(16,bo,bi,0)|PPC_LK
+#define PPC_BCCTR(bo,bi)       PPC_TYPE19(528,bo,bi,0)
+#define PPC_BCCTRL(bo,bi)      PPC_TYPE19(528,bo,bi,0)|PPC_LK
+#define PPC_BLR()              PPC_BCLR(20,31)
+#define PPC_BCTR()             PPC_BCCTR(20,31)
+
+/* Other */
+#define  PPC_RLWIMI(a,s,sh,mb,me) \
+       PPC_MAJOR(20)|PPC_DEST(s)|PPC_SRCA(A)|PPC_SRCB(sh)|(mb)<<6|(me)<<1 
+#define  PPC_RLWIMI_(a,s,sh,mb,me)     PPC_RLWIMI(a,s,sh,mb,me)|PPC_RC
+#define  PPC_RLWINM(a,s,sh,mb,me) \
+       PPC_MAJOR(21)|PPC_DEST(s)|PPC_SRCA(A)|PPC_SRCB(sh)|(mb)<<6|(me)<<1 
+#define  PPC_RLWINM_(a,s,sh,mb,me)     PPC_RLWINM(a,s,sh,mb,me)|PPC_RC
+#define  PPC_RLWNM(a,s,b,mb,me) \
+       PPC_MAJOR(23)|PPC_DEST(s)|PPC_SRCA(A)|PPC_SRCB(b)|(mb)<<6|(me)<<1 
+#define  PPC_RLWNM_(a,s,b,mb,me)       PPC_RLWNM(a,s,b,mb,me)|PPC_RC
+
+#define PPC_SC()                       PPC_MAJOR(17)|2
+/* Major number = 63 Floating-point operations (not implemented for now) */
+
+/* Simplified Mnemonics */
+/* Fabricate immediate subtract out of add negative */
+#define PPC_SUBI(d,a,simm)     PPC_ADDI(d,a,-(simm))
+#define PPC_SUBIS(d,a,simm)    PPC_ADDIS(d,a,-(simm))
+#define PPC_SUBIC(d,a,simm)    PPC_ADDIC(d,a,-(simm))
+#define PPC_SUBIC_(d,a,simm)   PPC_ADDIC_(d,a,-(simm))
+/* Fabricate subtract out of subtract from */
+#define PPC_SUBC(d,b,a)                PPC_SUBFC(d,a,b)
+#define PPC_SUBC_(d,b,a)       PPC_SUBFC_(d,a,b)
+#define PPC_SUBCO(d,b,a)       PPC_SUBFCO(d,a,b)
+#define PPC_SUBCO_(d,b,a)      PPC_SUBFCO_(d,a,b)
+/* Messy compare bits omitted */
+/* Shift and rotate omitted */
+/* Branch coding omitted */
+#define PPC_CRSET(d)           PPC_CREQV(d,d,d)
+#define PPC_CRCLR(d)           PPC_CRXOR(d,d,d)
+#define PPC_CRMOVE(d,s)                PPC_CROR(d,s,s)
+#define PPC_CRNOT(d,s)         PPC_CRNOR(d,s,s)
+/* Trap menmonics omitted */
+/* Menmonics for user-accessible SPRs */
+#define PPC_MFXER(d)           PPC_MFSPR(d,1)          
+#define PPC_MFLR(d)            PPC_MFSPR(d,8)          
+#define PPC_MFCTR(d)           PPC_MFSPR(d,9)          
+#define PPC_MTXER(s)           PPC_MTSPR(s,1)          
+#define PPC_MTLR(s)            PPC_MTSPR(s,8)          
+#define PPC_MTCTR(s)           PPC_MTSPR(s,9)          
+/* Recommended mnemonics */
+#define PPC_NOP()              PPC_ORI(0,0,0)
+#define PPC_LI(d,simm)         PPC_ADDI(d,0,simm)
+#define PPC_LIS(d,simm)                PPC_ADDIS(d,0,simm)
+#define PPC_LA(d,a,simm)       PPC_ADDI(d,a,simm)
+#define PPC_MR(d,s)            PPC_OR(d,s,s)
+#define PPC_NOT(d,s)           PPC_NOR(d,s,s)
+#define PPC_MTCR(s)            PPC_MTCRF(0xff,s)
+
+#endif /* PPCASM_H */
+
+/* 45678901234567890123456789012345678901234567890123456789012345678901234567 */
diff --git a/lib/bind/cylink/rand.c b/lib/bind/cylink/rand.c
new file mode 100644 (file)
index 0000000..7051482
--- /dev/null
@@ -0,0 +1,333 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/****************************************************************************
+*  FILENAME:  rand.c   PRODUCT NAME: CRYPTOGRAPHIC TOOLKIT
+*
+*  FILE STATUS:
+*
+*  DESCRIPTION:     Cryptographic Toolkit Functions File
+*                   Random Number Generation Files
+*  PUBLIC FUNCTIONS:
+*      int InitRand( u_int16_t SEED_bytes, uchar  *SEED,
+*                                       uchar  *RVAL )
+*      int GenRand( u_int16_t A_bytes, uchar  *A,
+*                                   uchar  *RVAL )
+*      int MyGenRand( u_int16_t A_bytes,
+*                  ord    *A,
+*                  ord    *RVAL )
+
+*   Copyright (c) Cylink Corporation 1994. All rights reserved.
+*
+*  REVISION  HISTORY:
+*
+*  24 Sep 94   KPZ     Initial release
+*  10 Oct 94   KPZ     Added Shamir Key Sharing functions
+*  10 Oct 94   KPZ     Modified SHA functions for arbitrary message length
+*  12 Oct 94   KPZ     Modified SHA functions (new standard)
+*  14 Oct 94   GKL     Second version (big endian support)
+*  26 Oct 94   GKL     (alignment for big endian support & ERR_ALLOC)
+*
+****************************************************************************/
+
+/****************************************************************************
+*  INCLUDE FILES
+****************************************************************************/
+
+#include "port_before.h"
+
+/* system files */
+#ifdef VXD
+#include <vtoolsc.h>
+#else
+#include <stdlib.h>
+#include <string.h>
+#endif
+
+/* program files */
+#ifdef VXD
+#include "tkvxd.h"
+#endif
+#include "cylink.h"
+#include "ctk_endian.h"
+#include "toolkit.h"
+#include "cencrint.h"
+#include "sha.h"
+
+#include "port_after.h"
+extern u_int16_t DataOrder;
+/****************************************************************************
+*  PUBLIC FUNCTIONS DEFINITIONS
+****************************************************************************/
+
+/****************************************************************************
+*  NAME:    int InitRand( u_int16_t SEED_bytes,
+*                         uchar  *SEED,
+*                         uchar  *RVAL)
+*
+*  DESCRIPTION:  Initialize Random number Generator
+*
+*  INPUTS:
+*      PARAMETERS:
+*          u_int16_t SEED_bytes  Length of SEED
+*          uchar *SEED        Pointer to SEED value
+*
+*  OUTPUT:
+*      PARAMETERS:
+*          uchar *RVAL        Pointer to RVAL
+*
+*      RETURN:
+*          SUCCESS            No errors
+*          ERR_INPUT_LEN      Invalid length for input data
+*          ERR_DATA           Generic data error
+*  REVISION HISTORY:
+*
+*  24 Sep 94   KPZ     Initial release
+*
+****************************************************************************/
+
+int InitRand( u_int16_t SEED_bytes,
+              uchar  *SEED,
+        uchar  *RVAL )
+{
+    int  status = SUCCESS;          /* function return status */
+    if ( SEED_bytes == 0 )
+    {
+            status = ERR_INPUT_LEN;
+        return status;
+    }
+    if ( SEED_bytes < SHA_LENGTH )
+    {
+        status = ERR_DATA;
+        return status;
+    }
+    memcpy( RVAL, SEED, SHA_LENGTH);
+      return status;
+}
+
+
+/****************************************************************************
+*  NAME:    int GenRand( u_int16_t A_bytes,
+*                        uchar  *A,
+*                        uchar  *RVAL)
+*
+*  DESCRIPTION:  Generate random number.
+*
+*  INPUTS:
+*      PARAMETERS:
+*          u_int16_t A_bytes       Length of A
+*          uchar *A             Pointer to A value
+*
+*  OUTPUT:
+*      PARAMETERS:
+*          uchar *RVAL          Pointer to RVAL
+*
+*      RETURN:
+*          SUCCESS              No errors
+*          ERR_INPUT_LEN        Invalid length for input data
+*          ERR_DATA             Generic data error
+*          ERR_ALLOC            Insufficient memory
+*  REVISION HISTORY:
+*
+*  24 Sep 94   KPZ     Initial release
+*  14 Oct 94   GKL     Second version (big endian support)
+*  26 Oct 94   GKL     (alignment for big endian support & ERR_ALLOC)
+*
+****************************************************************************/
+int GenRand( u_int16_t A_bytes,
+             uchar  *A,
+             uchar  *RVAL )
+{
+   int  status = SUCCESS;          /* function return status */
+    ord *RVAL_a;
+    SHA_context hash_context;       /* SHA context structure */
+        uchar M[DSS_LENGTH_MIN];        /* message block */
+    uchar hash_result[SHA_LENGTH];
+    u_int16_t i;
+    u_int16_t sha_block;              /* number of sha blocks */
+    u_int16_t sha_rem;                /* size of last block */
+    if ( A_bytes == 0 )
+    {
+     status = ERR_INPUT_LEN;
+         return status;
+    }
+    sha_block = (u_int16_t) (A_bytes / SHA_LENGTH);   /* number of sha blocks */
+    sha_rem = (u_int16_t) (A_bytes % SHA_LENGTH);     /* size of last block */
+    if ( sha_rem == 0 )                 /* last block = SHA_LENGTH */
+    {
+        sha_block--;
+    }
+    for ( i = 0; i <= sha_block; i++)
+    {
+        SHAInit ( &hash_context );
+        memcpy( M, RVAL, SHA_LENGTH);
+        memset( M + SHA_LENGTH, 0, DSS_LENGTH_MIN - SHA_LENGTH );
+        if ( (status = SHAUpdate( &hash_context, M, DSS_LENGTH_MIN ))
+          != SUCCESS )
+        {
+           return status;                        /* error */
+        }
+        if ( (status=MySHAFinal (&hash_context, hash_result )) != SUCCESS )
+        {
+           return status;                       /* error */
+        }
+    
+        BigSwap(RVAL, SHA_LENGTH);
+        ALIGN_CALLOC_COPY(RVAL, RVAL_a, SHA_LENGTH);
+        if ( status !=  SUCCESS )
+        {
+            ALIGN_COPY_FREE(RVAL_a,RVAL,SHA_LENGTH);
+            BigSwap(RVAL, SHA_LENGTH);
+            return status;     /* ERR_ALLOC   insufficient memory */
+           }
+           Sum_Q( RVAL_a, 1, SHA_LENGTH / sizeof(ord) );
+           Sum_big( RVAL_a,                 /* RVAL=RVAL+hash_result*/
+                                 (ord *)hash_result,
+                                RVAL_a, SHA_LENGTH / sizeof(ord) );
+        ALIGN_COPY_FREE(RVAL_a,RVAL,SHA_LENGTH);
+        BigSwap(RVAL, SHA_LENGTH);
+#ifdef CTK_BIG_ENDIAN
+        ByteSwap(hash_result,SHA_LENGTH);
+#endif
+        BigSwap(hash_result, SHA_LENGTH);
+        if ( i == sha_block  && sha_rem != 0 )  /* last block < SHA_LENGTH*/
+        {
+           memcpy( A + i * SHA_LENGTH, hash_result,
+                sha_rem * sizeof (uchar));
+        }
+        else            /* last block = SHA_LENGTH*/
+        {
+           memcpy( A + i * SHA_LENGTH, hash_result,
+               SHA_LENGTH * sizeof (uchar));
+        }
+    }
+    return status;
+}
+
+
+
+/****************************************************************************
+*  NAME:        int MyGenRand( u_int16_t A_bytes,
+*                              ord    *A,
+*                              ord    *RVAL)
+*
+*  DESCRIPTION:  Generate random number.
+*
+*  INPUTS:
+*          PARAMETERS:
+*                  u_int16_t A_bytes               Length of A
+*              ord   *A             Pointer to A value
+*
+*  OUTPUT:
+*          PARAMETERS:
+*          ord   *RVAL          Pointer to RVAL
+*
+*          RETURN:
+*                  SUCCESS              No errors
+*          ERR_INPUT_LEN        Invalid length for input data
+*                  ERR_DATA                         Generic data error
+*  REVISION HISTORY:
+*
+*  24 Sep 94   KPZ         Initial release
+*  14 Oct 94   GKL     Second version (big endian support)
+*
+****************************************************************************/
+int MyGenRand( u_int16_t A_bytes,
+               ord    *A,
+               ord    *RVAL )
+{
+   int  status = SUCCESS;          /* function return status */
+    SHA_context hash_context;       /* SHA context structure */
+         uchar M[DSS_LENGTH_MIN];        /* message block */
+    uchar hash_result[SHA_LENGTH];
+       u_int16_t i;
+    u_int16_t sha_block;              /* number of sha blocks */
+    u_int16_t sha_rem;                /* size of last block */
+    if ( A_bytes == 0 )
+    {
+         status = ERR_INPUT_LEN;
+         return status;
+    }
+    sha_block = (u_int16_t) (A_bytes / SHA_LENGTH);   /* number of sha blocks */
+    sha_rem = (u_int16_t) (A_bytes % SHA_LENGTH);     /* size of last block */
+    if ( sha_rem == 0 )                 /* last block = SHA_LENGTH */
+       {
+           sha_block--;
+    }
+    for ( i = 0; i <= sha_block; i++)
+    {
+        SHAInit ( &hash_context );
+        memcpy( M, RVAL, SHA_LENGTH);
+               memset( M + SHA_LENGTH, 0, DSS_LENGTH_MIN - SHA_LENGTH );
+        if ( (status = SHAUpdate( &hash_context, M, DSS_LENGTH_MIN ))
+                         != SUCCESS )
+        {
+                   return status;                        /* error */
+        }
+        if ( (status=MySHAFinal (&hash_context, hash_result )) != SUCCESS )
+        {
+            return status;                       /* error */
+        }
+#ifdef CTK_BIG_ENDIAN
+               ByteSwap((uchar*)RVAL,SHA_LENGTH);
+#endif
+        BigSwap((uchar*)RVAL, SHA_LENGTH);
+               Sum_Q(RVAL, 1,SHA_LENGTH / sizeof(ord));
+               Sum_big( RVAL,                 /* RVAL=RVAL+hash_result*/
+                               (ord*)hash_result,
+                                         RVAL, SHA_LENGTH / sizeof(ord) );
+        BigSwap((uchar*)RVAL, SHA_LENGTH);
+#ifdef CTK_BIG_ENDIAN
+        ByteSwap((uchar*)RVAL,SHA_LENGTH);
+#endif
+         if ( i == sha_block  && sha_rem != 0 )  /* last block < SHA_LENGTH*/
+                {
+             memcpy( &A[ i*SHA_LENGTH / sizeof(ord)], hash_result,
+                 sha_rem * sizeof (uchar));
+         }
+                else                                   /* last block = SHA_LENGTH*/
+         {
+             memcpy( &A[ i*SHA_LENGTH / sizeof(ord)], hash_result,
+                                   SHA_LENGTH * sizeof (uchar));
+         }
+     }
+     return status;
+}
+
diff --git a/lib/bind/cylink/sha.c b/lib/bind/cylink/sha.c
new file mode 100644 (file)
index 0000000..5d94f36
--- /dev/null
@@ -0,0 +1,698 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/****************************************************************************
+*  FILENAME:  cencrint.c   PRODUCT NAME: CRYPTOGRAPHIC TOOLKIT
+*
+*  FILE STATUS:
+*
+*  DESCRIPTION:             Cryptographic Toolkit Internal Functions File
+*
+*  PRIVATE FUNCTIONS:
+*
+*
+*               void shaTransform( u_int32_t *state, uchar *block )
+*               void SHAInitK( SHA_context *hash_context )
+*               int MySHA( uchar *message, u_int16_t message_bytes,
+*                          uchar *hash_result )
+*               int MySHAFinal( SHA_context *hash_context, uchar *hash_result )
+*
+*
+*       Copyright (c) Cylink Corporation 1994. All rights reserved.
+*
+*  REVISION  HISTORY:
+*
+*
+*  24 Sep 94   KPZ   Initial release
+*  10 Oct 94   KPZ   Fixed bugs in Add(), DivRem()
+*  12 Oct 94   KPZ   Modified shaTransform()
+*  14 Oct 94   GKL   Second version (big endian support)
+*  26 Oct 94   GKL   (alignment for big endian support & ERR_ALLOC)
+*  08 Nov 94   GKL      Added input parameters check to Inverse
+*  08 Dec 94   GKL   Added YIELD_context to Expo, VerPrime and GenPrime
+*
+****************************************************************************/
+
+/****************************************************************************
+*  INCLUDE FILES
+****************************************************************************/
+
+#include "port_before.h"
+#include <sys/types.h>
+
+/* system files */
+#ifdef VXD
+#include <vtoolsc.h>
+#else
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#endif
+
+/* program files */
+#include "cylink.h"
+#include "ctk_endian.h"
+#include "toolkit.h"
+#include "cencrint.h"
+#include "sha.h"
+#include "port_after.h"
+extern u_int16_t DataOrder;
+
+/****************************************************************************
+*  NAME:  int SHA( uchar   *message,
+*                  u_int16_t message_bytes,
+*                  uchar  *hash_result )
+*
+*  DESCRIPTION:  Compute a Secure Hash Function.
+*
+*  INPUTS:
+*      PARAMETERS:
+*         uchar *message          Pointer to message
+*         u_int16_t message_bytes    Number of bytes in message
+*         uchar *hash_result      Pointer to message digest
+*
+*  OUTPUT:
+*      PARAMETERS:
+*         uchar *hash_result      Message digest
+*
+*      RETURN:
+*          SUCCESS                 No errors
+*          ERR_INPUT_LEN           Invalid length for input data(zero bytes)
+*  REVISION HISTORY:
+*
+*  24 Sep 94    KPZ     Initial release
+*
+****************************************************************************/
+
+int SHA( uchar   *message,
+         u_int16_t message_bytes,
+         uchar  *hash_result )
+{
+     SHA_context hash_context;     /* SHA context structure */
+    int status = SUCCESS;         /* function return status */
+    if (message_bytes == 0 )
+    {
+        status = ERR_INPUT_LEN;
+        return status;            /* invalid length for input data */
+    }
+    SHAInit ( &hash_context );    /* initialize SHA */
+    if ( (status = SHAUpdate( &hash_context, message, message_bytes ))
+          != SUCCESS )
+    {
+       return status;            /* error */
+    }
+    if ((status=SHAFinal (&hash_context, hash_result)) != SUCCESS )
+    {
+       return status;           /* error */
+    }
+
+    return status;
+}
+
+/****************************************************************************
+*  PRIVATE FUNCTIONS DEFINITIONS
+****************************************************************************/
+
+
+/****************************************************************************
+*  NAME:     void shaTransform( u_int32_t *state,
+*                               uchar *block )
+*
+*  DESCRIPTION:  Perform  SHS transformation.
+*
+*  INPUTS:
+*          PARAMETERS:
+*           SHA_context *hash_context  Pointer to SHA_context structure
+*  OUTPUT:
+*
+*           SHA_context *hash_context  Pointer to SHA_context structure
+*                                      (updated)
+*  REVISION HISTORY:
+*
+*  24 sep 94    KPZ     Initial release
+*  12 Oct 94    KPZ     Modified buffers copy
+*  14 Oct 94    GKL     Second version (big endian support)
+*  1  Sep 95    AAB     Speedup the function
+****************************************************************************/
+
+ void shaTransform( u_int32_t *state,
+                                       const uchar *block )
+{
+   u_int32_t W[80];
+   u_int32_t A,B,C,D,E;  /*,temp;*/
+   memcpy( W, block, 64);                 /*TKL00201*/
+#ifdef CTK_LITTLE_ENDIAN                      /*TKL00201*/
+      ByteSwap32( (uchar *)W, 64);        /*TKL00201*/
+#endif                                    /*TKL00201*/
+   /* Expand the 16 words into 80 words */
+   expand(16);expand(17);expand(18);expand(19);expand(20);expand(21);
+   expand(22);expand(23);expand(24);expand(25);expand(26);expand(27);
+   expand(28);expand(29);expand(30);expand(31);expand(32);expand(33);
+   expand(34);expand(35);expand(36);expand(37);expand(38);expand(39);
+   expand(40);expand(41);expand(42);expand(43);expand(44);expand(45);
+   expand(46);expand(47);expand(48);expand(49);expand(50);expand(51);
+   expand(52);expand(53);expand(54);expand(55);expand(56);expand(57);
+   expand(58);expand(59);expand(60);expand(61);expand(62);expand(63);
+   expand(64);expand(65);expand(66);expand(67);expand(68);expand(69);
+   expand(70);expand(71);expand(72);expand(73);expand(74);expand(75);
+   expand(76);expand(77);expand(78);expand(79);
+  /*Set up first buffer*/
+         A = state[0];
+   B = state[1];
+   C = state[2];
+   D = state[3];
+   E = state[4];
+
+ /* Heavy mangling, in 4 sub-rounds of 20 iterations each. */
+    subRound( A, B, C, D, E, f1, k1SHA, W[ 0] );
+    subRound( E, A, B, C, D, f1, k1SHA, W[ 1] );
+    subRound( D, E, A, B, C, f1, k1SHA, W[ 2] );
+    subRound( C, D, E, A, B, f1, k1SHA, W[ 3] );
+    subRound( B, C, D, E, A, f1, k1SHA, W[ 4] );
+       subRound( A, B, C, D, E, f1, k1SHA, W[ 5] );
+    subRound( E, A, B, C, D, f1, k1SHA, W[ 6] );
+       subRound( D, E, A, B, C, f1, k1SHA, W[ 7] );
+    subRound( C, D, E, A, B, f1, k1SHA, W[ 8] );
+    subRound( B, C, D, E, A, f1, k1SHA, W[ 9] );
+    subRound( A, B, C, D, E, f1, k1SHA, W[10] );
+    subRound( E, A, B, C, D, f1, k1SHA, W[11] );
+    subRound( D, E, A, B, C, f1, k1SHA, W[12] );
+    subRound( C, D, E, A, B, f1, k1SHA, W[13] );
+    subRound( B, C, D, E, A, f1, k1SHA, W[14] );
+    subRound( A, B, C, D, E, f1, k1SHA, W[15] );
+       subRound( E, A, B, C, D, f1, k1SHA, W[16] );
+    subRound( D, E, A, B, C, f1, k1SHA, W[17] );
+       subRound( C, D, E, A, B, f1, k1SHA, W[18] );
+    subRound( B, C, D, E, A, f1, k1SHA, W[19] );
+
+    subRound( A, B, C, D, E, f2, k2SHA, W[20]);
+     subRound( E, A, B, C, D, f2, k2SHA, W[21]);
+     subRound( D, E, A, B, C, f2, k2SHA, W[22]);
+     subRound( C, D, E, A, B, f2, k2SHA, W[23]);
+     subRound( B, C, D, E, A, f2, k2SHA, W[24]);
+     subRound( A, B, C, D, E, f2, k2SHA, W[25]);
+        subRound( E, A, B, C, D, f2, k2SHA, W[26]);
+     subRound( D, E, A, B, C, f2, k2SHA, W[27]);
+        subRound( C, D, E, A, B, f2, k2SHA, W[28]);
+     subRound( B, C, D, E, A, f2, k2SHA, W[29]);
+     subRound( A, B, C, D, E, f2, k2SHA, W[30]);
+     subRound( E, A, B, C, D, f2, k2SHA, W[31]);
+     subRound( D, E, A, B, C, f2, k2SHA, W[32]);
+     subRound( C, D, E, A, B, f2, k2SHA, W[33]);
+     subRound( B, C, D, E, A, f2, k2SHA, W[34]);
+     subRound( A, B, C, D, E, f2, k2SHA, W[35]);
+     subRound( E, A, B, C, D, f2, k2SHA, W[36]);
+        subRound( D, E, A, B, C, f2, k2SHA, W[37]);
+     subRound( C, D, E, A, B, f2, k2SHA, W[38]);
+        subRound( B, C, D, E, A, f2, k2SHA, W[39]);
+
+     subRound( A, B, C, D, E, f3, k3SHA, W[40]);
+     subRound( E, A, B, C, D, f3, k3SHA, W[41]);
+     subRound( D, E, A, B, C, f3, k3SHA, W[42]);
+     subRound( C, D, E, A, B, f3, k3SHA, W[43]);
+     subRound( B, C, D, E, A, f3, k3SHA, W[44]);
+     subRound( A, B, C, D, E, f3, k3SHA, W[45]);
+     subRound( E, A, B, C, D, f3, k3SHA, W[46]);
+        subRound( D, E, A, B, C, f3, k3SHA, W[47]);
+     subRound( C, D, E, A, B, f3, k3SHA, W[48]);
+        subRound( B, C, D, E, A, f3, k3SHA, W[49]);
+     subRound( A, B, C, D, E, f3, k3SHA, W[50]);
+     subRound( E, A, B, C, D, f3, k3SHA, W[51]);
+     subRound( D, E, A, B, C, f3, k3SHA, W[52]);
+     subRound( C, D, E, A, B, f3, k3SHA, W[53]);
+     subRound( B, C, D, E, A, f3, k3SHA, W[54]);
+     subRound( A, B, C, D, E, f3, k3SHA, W[55]);
+     subRound( E, A, B, C, D, f3, k3SHA, W[56]);
+     subRound( D, E, A, B, C, f3, k3SHA, W[57]);
+        subRound( C, D, E, A, B, f3, k3SHA, W[58]);
+     subRound( B, C, D, E, A, f3, k3SHA, W[59]);
+
+     subRound( A, B, C, D, E, f4, k4SHA, W[60]);
+     subRound( E, A, B, C, D, f4, k4SHA, W[61]);
+     subRound( D, E, A, B, C, f4, k4SHA, W[62]);
+     subRound( C, D, E, A, B, f4, k4SHA, W[63]);
+     subRound( B, C, D, E, A, f4, k4SHA, W[64]);
+     subRound( A, B, C, D, E, f4, k4SHA, W[65]);
+     subRound( E, A, B, C, D, f4, k4SHA, W[66]);
+     subRound( D, E, A, B, C, f4, k4SHA, W[67]);
+        subRound( C, D, E, A, B, f4, k4SHA, W[68]);
+     subRound( B, C, D, E, A, f4, k4SHA, W[69]);
+        subRound( A, B, C, D, E, f4, k4SHA, W[70]);
+     subRound( E, A, B, C, D, f4, k4SHA, W[71]);
+     subRound( D, E, A, B, C, f4, k4SHA, W[72]);
+     subRound( C, D, E, A, B, f4, k4SHA, W[73]);
+     subRound( B, C, D, E, A, f4, k4SHA, W[74]);
+     subRound( A, B, C, D, E, f4, k4SHA, W[75]);
+     subRound( E, A, B, C, D, f4, k4SHA, W[76]);
+     subRound( D, E, A, B, C, f4, k4SHA, W[77]);
+     subRound( C, D, E, A, B, f4, k4SHA, W[78]);
+        subRound( B, C, D, E, A, f4, k4SHA, W[79]);
+
+        state[0] += A;
+  state[1] += B;
+  state[2] += C;
+  state[3] += D;
+  state[4] += E;
+
+}
+
+
+
+
+/****************************************************************************
+*  NAME:  void SHAInitK( SHA_context *hash_context )
+*
+*  DESCRIPTION: Initialize Secure Hash Function for generate
+*               random number for DSS.
+*
+*  INPUTS:
+*          PARAMETERS:
+*              SHA_context *hash_context   SHA context structure
+*  OUTPUT:
+*          PARAMETERS:
+*             SHA_context *hash_context    Initialized SHA context structure
+*
+*          RETURN:
+*
+*  REVISION HISTORY:
+*
+*  24 Sep 94    KPZ             Initial release
+*  14 Oct 94    GKL     Second version (big endian support)
+*
+****************************************************************************/
+
+void SHAInitK( SHA_context *hash_context )
+{
+/*Set up first buffer*/
+   hash_context->state[0] = 0xEFCDAB89L;
+   hash_context->state[1] = 0x98BADCFEL;
+   hash_context->state[2] = 0x10325476L;
+   hash_context->state[3] = 0xC3D2E1F0L;
+   hash_context->state[4] = 0x67452301L;
+/*Initialise buffer */
+   memset( hash_context->buffer, 0, sizeof(hash_context->buffer));
+   memset( hash_context->count, 0,  sizeof(hash_context->count));
+}
+
+
+/****************************************************************************
+*  NAME:  int MySHA( uchar   *message,
+*                    u_int16_t message_bytes,
+*                    uchar  *hash_result )
+*
+*  DESCRIPTION:  Compute a Secure Hash Function.
+*
+*  INPUTS:
+*          PARAMETERS:
+*                 uchar *message          Pointer to message
+*                 u_int16_t message_bytes    Number of bytes in message
+*         uchar *hash_result      Pointer to message digest
+*
+*  OUTPUT:
+*          PARAMETERS:
+*         uchar *hash_result      Message digest
+*
+*          RETURN:
+*                  SUCCESS                 No errors
+*          ERR_INPUT_LEN           Invalid length for input data(zero bytes)
+*  REVISION HISTORY:
+*
+*  24 Sep 94    KPZ             Initial release
+*
+****************************************************************************/
+int MySHA( uchar   *message,
+           u_int16_t message_bytes,
+      uchar  *hash_result )
+{
+       SHA_context hash_context;     /* SHA context structure */
+       int status = SUCCESS;         /* function return status */
+         if (message_bytes == 0 )
+        {
+               status = ERR_INPUT_LEN;
+         return status;            /* invalid length for input data */
+   }
+       SHAInit ( &hash_context );    /* initialize SHA */
+#ifdef CTK_BIG_ENDIAN
+    ByteSwap(message,message_bytes);
+#endif
+    status = SHAUpdate( &hash_context, message, message_bytes );
+#ifdef CTK_BIG_ENDIAN
+       ByteSwap(message,message_bytes);
+#endif
+    if ( status != SUCCESS )
+    {
+                          return status;            /* error */
+   }
+    if ((status=MySHAFinal (&hash_context, hash_result)) != SUCCESS )
+  {
+               return status;           /* error */
+    }
+       return status;
+}
+
+/****************************************************************************
+*  NAME:  int MySHAFinal( SHA_context *hash_context,
+*                         uchar       *hash_result )
+*  DESCRIPTION:  Finalize Secure Hash Function
+*
+*  INPUTS:
+*          PARAMETERS:
+*              SHA_context *hash_context    SHA context structure
+*                uchar *hash_result     Pointer to hash
+*  OUTPUT:
+*          PARAMETERS:
+*              uchar *hash_result        Final value
+*          RETURN:
+*                  SUCCESS               No errors
+*          ERR_INPUT_LEN         Invalid length for input data (zero bytes)
+*  REVISION HISTORY:
+*
+*  24 Sep 94   KPZ         Initial release
+*  10 Oct 94   KPZ     Modified for arbitrary message length
+*  14 Oct 94   GKL     Second version (big endian support)
+*
+****************************************************************************/
+  int MySHAFinal( SHA_context *hash_context,
+             uchar       *hash_result )
+{
+   int status = SUCCESS;         /* function return status */
+      uchar bits[8];
+  u_int16_t index, padLen;
+   u_int32_t ex;
+       uchar PADDING[64] = {         /* padding string */
+              0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+         if ( hash_context->count[0] == 0 && hash_context->count[1] == 0 )
+       {
+          status= ERR_INPUT_LEN;
+          return status;
+       }
+ /* Save number of bits */
+     LongByte( &hash_context->count[1] , 4, bits );
+  LongByte( &hash_context->count[0] , 4, bits + 4 );
+      ByteSwap32( bits, 8 );
+ /* Pad out to 56 mod 64.*/
+   index = (u_int16_t )((hash_context->count[0] >> 3) & 0x3f);
+               padLen = (u_int16_t) ((index < 56) ? (56 - index) : (120 - index));
+   SHAUpdate( hash_context, PADDING, padLen );
+
+ /* Append length (before padding) */
+    SHAUpdate (hash_context, bits, 8);
+
+ /* Set order of hash_context */
+       ex = hash_context->state[0];
+  hash_context->state[0] = hash_context->state[4];
+    hash_context->state[4] = ex;
+    ex = hash_context->state[1];
+       hash_context->state[1] = hash_context->state[3];
+    hash_context->state[3] = ex;
+  /* Store state in digest */
+    memcpy(hash_result,hash_context->state,SHA_LENGTH);
+  /* Zeroize sensitive information.*/
+    memset( hash_context, 0, sizeof(hash_context) );
+#if defined ( ORD_16 )  && defined( CTK_BIG_ENDIAN )
+       WordSwap(hash_result,SHA_LENGTH);
+#endif
+    return status;
+}
+
+
+/****************************************************************************
+*  NAME:  int SHAUpdate( SHA_context *hash_context,
+*                        uchar        *message,
+*                        u_int16_t      message_bytes )
+*  DESCRIPTION:  Update Secure Hash Function
+*
+*  INPUTS:
+*      PARAMETERS:
+*          SHA_context *hash_context        SHA context structure
+*          uchar       *message             Pointer to message
+*          u_int16_t       message_bytes       Number of bytes
+*  OUTPUT:
+*      PARAMETERS:
+*          SHA_context  *hash_context       Updated SHA context structure
+*
+*      RETURN:
+*          SUCCESS          No errors
+*          ERR_INPUT_LEN    Invalid length for input data (zero bytes)
+*  REVISION HISTORY:
+*
+*  24 Sep 94   KPZ      Initial release
+*  10 Oct 94   KPZ      Modified for arbitrary message length
+*
+****************************************************************************/
+
+int SHAUpdate( SHA_context *hash_context,
+            const uchar        *message,
+          u_int16_t      message_bytes )
+
+{
+    int status = SUCCESS;         /* function return status */
+    u_int16_t i, index, partLen;
+    if ( message_bytes == 0 )
+    {
+        status = ERR_INPUT_LEN;   /*invalid length for input data (zero bytes)*/
+        return status;
+    }
+
+  /* Compute number of bytes mod 64 */
+    index = (u_int16_t)((hash_context->count[0] >> 3) & 0x3F);
+
+  /* Update number of bits */
+    if ( (hash_context->count[0] += ((u_int32_t )message_bytes << 3))
+              < ((u_int32_t )message_bytes << 3) )
+    {
+   hash_context->count[1]++;
+    }
+    hash_context->count[1] += ((u_int32_t )message_bytes >> 29);
+
+    partLen = (u_int16_t) (64 - index);
+  /* Transform as many times as possible.*/
+    if ( message_bytes >= partLen )
+    {
+  memcpy( &hash_context->buffer[index], message, partLen );
+       shaTransform( hash_context->state, hash_context->buffer );
+
+      for ( i = partLen; (u_int16_t)(i + 63) < message_bytes; i += 64 )
+  {
+           shaTransform ( hash_context->state, &message[i] );
+  }
+       index = 0;
+    }
+    else
+    {
+     i = 0;
+    }
+  /* Buffer remaining input */
+    memcpy( &hash_context->buffer[index], &message[i],
+             message_bytes - i );
+    return status;
+}
+
+
+/****************************************************************************
+*  NAME:  void SHAInit( SHA_context *hash_context )
+*
+*  DESCRIPTION:  Initialize Secure Hash Function
+*
+*  INPUTS:
+*      PARAMETERS:
+*              SHA_context *hash_context   SHA context structure
+*  OUTPUT:
+*      PARAMETERS:
+*             SHA_context *hash_context    Initialized SHA context structure
+*
+*      RETURN:
+*
+*  REVISION HISTORY:
+*
+*  24 Sep 94    KPZ     Initial release
+*
+****************************************************************************/
+
+void SHAInit( SHA_context *hash_context )
+{
+/*Set up first buffer*/
+    hash_context->state[0] = h0SHA;
+    hash_context->state[1] = h1SHA;
+    hash_context->state[2] = h2SHA;                  
+    hash_context->state[3] = h3SHA;
+    hash_context->state[4] = h4SHA;
+
+/* Initialise buffer */
+    memset( hash_context->buffer, 0, sizeof(hash_context->buffer));
+ /*Initialize bit count*/
+    hash_context->count[0] = hash_context->count[1] = 0;
+}
+
+/****************************************************************************
+*  NAME:  int SHAFinal( SHA_context *hash_context,
+*                       uchar       *hash_result )
+*  DESCRIPTION:  Finalize Secure Hash Function
+*
+*  INPUTS:
+*      PARAMETERS:
+*          SHA_context *hash_context    SHA context structure
+*                uchar *hash_result     Pointer to hash
+*  OUTPUT:
+*      PARAMETERS:
+*              uchar *hash_result        Final value
+*      RETURN:
+*          SUCCESS               No errors
+*          ERR_INPUT_LEN         Invalid length for input data (zero bytes)
+*  REVISION HISTORY:
+*
+*  24 Sep 94   KPZ     Initial release
+*  10 Oct 94   KPZ     Modified for arbitrary message length
+*  14 Oct 94   GKL     Second version (big endian support)
+*
+****************************************************************************/
+
+
+int SHAFinal( SHA_context *hash_context,
+                                uchar       *hash_result )
+{
+    int status = SUCCESS;         /* function return status */
+    status =  MySHAFinal( hash_context, hash_result );
+#ifdef CTK_BIG_ENDIAN
+    if (status == SUCCESS)
+    {
+        ByteSwap(hash_result, SHA_LENGTH);
+    }
+#endif
+    if (DataOrder)
+    {
+        BigSwap(hash_result, SHA_LENGTH);
+    }
+    return status;
+}
+
+/****************************************************************************
+*  NAME: int GetPasswordKeySHA( u_int16_t Password_bytes,
+*                               uchar  *Password,
+*                               uchar  *salt,
+*                               u_int16_t Count,
+*                               uchar  *K,
+*                               uchar  *IV )
+*
+*  DESCRIPTION: Get Password-Based DES/KAPPA Key by SHA
+*
+*  INPUTS:
+*      PARAMETERS:
+*            u_int16_t Password_bytes    Number of bytes in password
+*            uchar  *Password         Pointer to password
+*            uchar  *salt             Pointer to salt(8-byte)
+*            u_int16_t Count             Number of iteration
+*  OUTPUT:
+*      PARAMETERS:
+*            uchar *K                Pointer to DES/KAPPA key
+*            uchar *IV               Pointer to initialization vector
+*      RETURN:
+*          SUCCESS              No errors
+*          ERR_COUNT            Invalid iteration count (zero)
+*          ERR_INPUT_LEN        Invalid length for input data(zero bytes)
+*          ERR_ALLOC            Insufficient memory
+*  REVISION HISTORY:
+*
+*  24 Sep 94   KPZ     Initial release
+*  26 Oct 94   GKL     (ERR_ALLOC)
+*
+****************************************************************************/
+ int GetPasswordKeySHA( u_int16_t Password_bytes,
+                        uchar  *Password,
+                        uchar  *salt,
+                        u_int16_t Count,
+                        uchar  *K,
+                        uchar  *IV )
+
+{
+    int status = SUCCESS;      /* function return status */
+    uchar digest[SHA_LENGTH];
+        uchar *buf;
+    if ( Count == 0 )          /* invalid iteration count (zero) */
+    {
+        status = ERR_COUNT;
+        return status;
+    }
+    CALLOC(buf,uchar,Password_bytes + 8);
+    if ( status !=  SUCCESS )
+    {
+       return status;     /* ERR_ALLOC   insufficient memory */
+    }
+    if ( Password_bytes != 0 )  /* if number of bytes password non equals zero */
+        {
+    memcpy( buf, Password, Password_bytes );
+    }
+    memcpy( buf + Password_bytes, salt, 8);
+/* Compute message digest */
+    status = SHA( buf, (u_int16_t)(Password_bytes + 8), digest);
+    if (!DataOrder)
+    {
+        BigSwap(digest, SHA_LENGTH);
+    }
+
+    if ( status != SUCCESS )
+    {
+        free ( buf );
+        return status;
+    }
+    Count --;            /* decrement Count */
+/* Count times compute message digest */
+    while ( Count != 0 )
+    {
+        if ( (status = SHA( digest, SHA_LENGTH, digest)) != SUCCESS )
+        {
+            free ( buf );
+            return status;
+        }
+        if (!DataOrder)
+        {
+            BigSwap(digest, SHA_LENGTH);
+        }
+        Count --;
+    }
+    memcpy( K, digest, 8 );
+    memcpy( IV, digest + SHA_LENGTH -8, 8 );
+    free ( buf );
+    return status;
+}
diff --git a/lib/bind/cylink/sha.h b/lib/bind/cylink/sha.h
new file mode 100644 (file)
index 0000000..a860608
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/****************************************************************************
+*  FILENAME:  sha.h           PRODUCT NAME: CRYPTOGRAPHIC TOOLKIT
+*
+*  FILE STATUS:
+*
+*  DESCRIPTION:     Cryptographic Toolkit Internal Functions Header File
+*
+*  USAGE:           File should be included in Toolkit functions files
+*
+*
+*       Copyright (c) Cylink Corporation 1994. All rights reserved.
+*
+*  REVISION  HISTORY:
+*
+*  24 Sep 94  KPZ             Initial release
+*
+****************************************************************************/
+#ifndef SHA_H
+#define SHA_H
+#include "cylink.h"
+
+#define       SHS_BLOCKSIZE      64
+/*
+#define FSHA(x,y,z) ( ( x & y ) | ( ~x & z ) )
+#define GSHA(x,y,z) ( x ^ y ^ z )
+#define HSHA(x,y,z) ( ( x & y ) | ( x & z ) | ( y & z ) )
+#define ISHA(x,y,z) (x ^ y ^ z)
+*/
+/*#define f1(x,y,z)     ( (x & y) | (~x & z) )          // Rounds  0-19 */
+#define f1(x,y,z)     ( z ^ (x & (y ^ z) ) )          /* Rounds  0-19 */
+#define f2(x,y,z)     ( x ^ y ^ z )                   /* Rounds 20-39 */
+/*#define f3(x,y,z)   ( (x & y) | (x & z) | (y & z) ) // Rounds 40-59 */
+#define f3(x,y,z)     ( (x & y) | (z & (x | y) ) )    /* Rounds 40-59 */
+#define f4(x,y,z)     ( x ^ y ^ z )                   /* Rounds 60-79 */
+
+
+#define RotateLeft(x,n) (( x << n )|( x >> (32-n) ) )  /*Circular left shift operation*/
+
+/*SHS Constants */
+#define k1SHA  0x5a827999L
+#define k2SHA  0x6ed9eba1L
+#define k3SHA  0x8f1bbcdcL
+#define k4SHA  0xca62c1d6L
+
+/*SHS initial value */
+#define h0SHA  0x67452301L
+#define h1SHA  0xefcdab89L
+#define h2SHA  0x98badcfeL
+#define h3SHA  0x10325476L
+#define h4SHA  0xc3d2e1f0L
+
+/*The initial expanding function*/
+#define expand(count) \
+   {\
+        W[count] = W[count-3] ^ W[count-8] ^ W[count-14] ^ W[count-16];\
+        W[count] = RotateLeft( W[count], 1 );\
+        }
+
+/*New variant */
+#define subRound(a, b, c, d, e, f, k, data) \
+  ( e += RotateLeft(a,5) + f(b, c, d) + k + data, b = RotateLeft( b,30) )
+
+
+
+/*The four sub_rounds*/
+/*
+#define subR1(count) \
+  {\
+   temp=RotateLeft(A,5) + FSHA(B,C,D) + E +W[count] +k1SHA;\
+   E = D; \
+   D = C; \
+   C = RotateLeft(B,30); \
+   B = A; \
+   A = temp; \
+  }
+
+#define subR2(count) \
+  {\
+   temp=RotateLeft(A,5) + GSHA(B,C,D) + E +W[count] +k2SHA;\
+   E = D; \
+   D = C; \
+   C = RotateLeft(B,30);\
+   B = A; \
+   A = temp; \
+  }
+
+#define subR3(count) \
+  {\
+   temp=RotateLeft(A,5) + HSHA(B,C,D) + E +W[count] +k3SHA;\
+   E = D; \
+   D = C; \
+   C = RotateLeft(B,30);\
+   B = A; \
+   A = temp; \
+  }
+
+#define subR4(count) \
+  {\
+   temp=RotateLeft(A,5) + ISHA(B,C,D) + E + W[count] +k4SHA;\
+   E = D; \
+   D = C; \
+   C = RotateLeft(B,30);\
+   B = A; \
+   A = temp; \
+  }
+*/
+#endif  /* SHA_H */
+
diff --git a/lib/bind/cylink/sizetest.c b/lib/bind/cylink/sizetest.c
new file mode 100644 (file)
index 0000000..8d219f5
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+#include "bnsize00.h"
+
+#if BNSIZE16
+#error Using 16-bit math library
+#elif BNSIZE32
+#error Using 32-bit math library
+#elif BNSIZE64
+#error Using 64-bit math library
+#else
+#error No math library size defined
+#endif
diff --git a/lib/bind/cylink/swap.c b/lib/bind/cylink/swap.c
new file mode 100644 (file)
index 0000000..e37c67e
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/****************************************************************************
+*  FILENAME: swap.c   PRODUCT NAME: CRYPTOGRAPHIC TOOLKIT
+*
+*  FILE STATUS:
+*
+*  DESCRIPTION: Byte and Word Swap functions 
+*
+*  PUBLIC FUNCTIONS:
+*
+*
+*  PRIVATE FUNCTIONS:
+*
+*  REVISION  HISTORY:
+*
+*  14 Oct 94   GKL     Initial release
+*  26 Oct 94   GKL     (alignment for big endian support )
+*
+****************************************************************************/
+
+/****************************************************************************
+*  INCLUDE FILES
+****************************************************************************/
+/* system files */
+
+#include "port_before.h"
+#ifdef VXD
+#include <vtoolsc.h>
+#else
+#include <stdlib.h>
+#include <string.h>
+#endif
+/* program files */
+#include "cylink.h"
+#include "ctk_endian.h"
+#include "toolkit.h"
+#include "port_after.h"
+
+u_int16_t DataOrder = 0;
+
+/*Reset bytes in long*/
+/*extern void ByteSwap32_asm( uchar  *X, u_int16_t X_len );*/ /*kz*/
+
+/****************************************************************************
+*  NAME:     void ByteSwap32 (uchar  *array,
+*                             u_int16_t X_len )
+*
+*  DESCRIPTION:  Perform byte reversal on an array of longword.
+*
+*  INPUTS:
+*          PARAMETERS:
+*            uchar  *X            Pointer to array
+*                        u_int16_t X_len             Number of bytes
+*  OUTPUT:
+*            uchar  *X            Pointer to array
+*
+*  REVISION HISTORY:
+*
+*  24 Sep 94    KPZ             Initial release
+*  14 Oct 94    GKL     Second version (big endian support)
+*
+****************************************************************************/
+
+
+void ByteSwap32( uchar  *X, u_int16_t X_len )
+{
+  u_int16_t i;        /*counter*/
+  uchar a;      /*temporary char*/
+        for ( i = 0; i < X_len; i += 4)
+ {
+               a = X[i];
+               X[i] = X[i+3];
+              X[i+3] = a;
+              a = X[i+1];
+              X[i+1] = X[i+2];
+              X[i+2] = a;
+     }
+/*#endif*/ /*kz*/
+}
+
+
+/****************************************************************************
+*  NAME:     void ByteSwap (uchar  *array,
+*                           u_int16_t X_len )
+*
+*  DESCRIPTION:  Perform byte reversal on an array of longword or shortword.
+*
+*  INPUTS:
+*          PARAMETERS:
+*            uchar  *X            Pointer to array
+*            u_int16_t X_len             Number of bytes
+*  OUTPUT:
+*            uchar  *X            Pointer to array
+*
+*  REVISION HISTORY:
+*
+*  24 Sep 94    KPZ             Initial release
+*  14 Oct 94    GKL     Second version (big endian support)
+*
+****************************************************************************/
+
+void ByteSwap( uchar  *X,
+               u_int16_t X_len )
+{
+#ifdef ORD_16
+    u_int16_t i;        /*counter*/
+    uchar a;      /*tempriory char for revers*/
+       for ( i = 0; i < X_len; i += 2)
+    {
+               a = X[i];
+        X[i] = X[i+1];
+        X[i+1] = a;
+    }
+#endif
+#ifdef ORD_32
+      ByteSwap32(X,X_len);
+#endif
+}
+
+/*kz longbyte deleted */
+
+/****************************************************************************
+*  NAME:     void WordSwap (uchar  *array,
+*                           u_int16_t X_len )
+*
+*  DESCRIPTION:  Perform short reversal on an array of longword.
+*
+*  INPUTS:
+*          PARAMETERS:
+*            uchar  *X            Pointer to array
+*                        u_int16_t X_len             Number of bytes
+*  OUTPUT:
+*            uchar  *X            Pointer to array
+*
+*  REVISION HISTORY:
+*
+*  14 Oct 94    GKL     Initial release
+*
+****************************************************************************/
+void WordSwap( uchar  *X,
+               u_int16_t X_len )
+{
+       u_int16_t i;        /*counter*/
+    u_int16_t a;      /*tempriory u_int16_t*/
+
+    for ( i = 0; i < X_len; i += 4)
+    {
+        a = *(u_int16_t*)(&X[i]);
+        *(u_int16_t*)(&X[i])=*(u_int16_t*)(&X[i+2]);
+        *(u_int16_t*)(&X[i+2])=a;
+    }
+}
+
+void BigSwap( uchar *buffer,
+              u_int16_t bufferLength)
+{
+    uchar temp;
+    u_int16_t i;
+
+    for (i = 0; i < (u_int16_t)(bufferLength/2); i++)
+    {
+        temp = buffer[i];
+        buffer[i] = buffer[bufferLength - 1 - i]; 
+        buffer[bufferLength - 1 - i] = temp; 
+    }
+}
+
+void SetDataOrder ( u_int16_t dataOrder)
+{
+    DataOrder = dataOrder;
+}
diff --git a/lib/bind/cylink/toolkit.h b/lib/bind/cylink/toolkit.h
new file mode 100644 (file)
index 0000000..9497f3e
--- /dev/null
@@ -0,0 +1,393 @@
+/*
+ * Cylink Corporation Â© 1998
+ * 
+ * This software is licensed by Cylink to the Internet Software Consortium to
+ * promote implementation of royalty free public key cryptography within IETF
+ * standards.  Cylink wishes to expressly thank the contributions of Dr.
+ * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
+ * their contributions to Internet Security.  In accordance with the terms of
+ * this license, ISC is authorized to distribute and sublicense this software
+ * for the practice of IETF standards.  
+ *
+ * The software includes BigNum, written by Colin Plumb and licensed by Philip
+ * R. Zimmermann for royalty free use and distribution with Cylink's
+ * software.  Use of BigNum as a stand alone product or component is
+ * specifically prohibited.
+ *
+ * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
+ * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
+ * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
+ * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ *
+ * Cylink or its representatives shall not be liable for tort, indirect,
+ * special or consequential damages such as loss of profits or loss of
+ * goodwill from the use or inability to use the software for any purpose or
+ * for any reason whatsoever.
+ *
+ * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
+ * with the rules and regulations promulgated from time to time by the Bureau
+ * of Export Administration, United States Department of Commerce, which
+ * restrict the export and re-export of certain products and technical data.
+ * If the export of the Foundations Suite is controlled under such rules and
+ * regulations, then the Foundations Suite shall not be exported or
+ * re-exported, directly or indirectly, (a) without all export or re-export
+ * licenses and governmental approvals required by any applicable laws, or (b)
+ * in violation of any applicable prohibition against the export or re-export
+ * of any part of the Foundations Suite. All export licenses for software
+ * containing the Foundations Suite are the sole responsibility of the licensee.
+ */
+/****************************************************************************
+*  FILENAME:  toolkit.h       PRODUCT NAME: CRYPTOGRAPHIC TOOLKIT
+*
+*  FILE STATUS:
+*
+*  DESCRIPTION:     Cryptographic Toolkit Functions Header File
+*
+*  USAGE:            File should be included to use Toolkit Functions
+*
+*
+*         Copyright (c) Cylink Corporation 1994. All rights reserved.
+*
+*  REVISION  HISTORY:
+*
+*  23 Aug 94  KPZ     Initial release
+*  24 Sep 94    KPZ Added prototypes of Toolkit functions
+*  14 Oct 94    GKL Second version (big endian support)
+*  08 Dec 94    GKL Added YIELD_context to GenDSSParameters
+*
+****************************************************************************/
+
+#ifndef TOOLKIT_H     /* Prevent multiple inclusions of same header file */
+#define TOOLKIT_H
+
+
+/* Error types */
+
+#define SUCCESS       0      /* no errors */
+#define ERR_DATA -1      /* generic data error */
+#define ERR_ALLOC       -2      /* insufficient memory */
+#define ERR_INPUT_LEN  -3      /* invalid length for input data (zero bytes) */
+#define ERR_DSS_LEN     -4      /* invalid length for dss_p */
+#define ERR_DH_LEN        -5      /* invalid length for DH_modulus */
+#define ERR_BLOCK_LEN     -7      /* invalid length for input block for ECB/CBC */
+#define ERR_HASH_LEN    -8      /* invalid length for hash_result */
+#define ERR_MODE    -9      /* invalid value of encryption mode */
+#define ERR_NUMBER        -10     /* invalid number of testings (zero) */
+#define ERR_POSITION     -11     /* invalid value of  triplet_position   */
+#define ERR_COUNT     -12     /* invalid iteration count (zero) */
+#define ERR_SIGNATURE       -21     /* signature is not valid */
+#define ERR_PRIME       -22     /* number is not prime */
+#define ERR_WEAK        -23     /* weak key */
+#define ERR_INPUT_VALUE -24     /* invalid input value */
+/* additional error types for CEPA */
+#define ERR_KEY_LENGTH  -25     /* invalid value of key length */
+#define ERR_ROUNDS      -26     /* invalid value of rounds number */
+#define ERR_CANCEL      -30     /* canceled by user */
+#define ERR_MODULUS_ZERO -31    /* invalid modulo */
+#define ERR_UNSUPPORTED  -40     /* unsupported crypto method */
+#define ERR_OP_CODE             -41            /*invalid operation code*/
+
+
+
+/* Lengths of variables */
+#define DH_LENGTH_MIN    64  /* 512-bit minimal length for DH functions */
+#define DSS_LENGTH_MIN   64  /* 512-bit minimal length for DSS functions */
+#define DSS_LENGTH_MAX  128  /* 1024-bit maximal length for DSS functions */
+#define SHA_LENGTH       20  /* 160-bit length for SHA hash result */
+
+/* Number of random bases for Miller test */
+#define TEST_COUNT        40
+
+#define LITTLE_ORDER 0
+#define BIG_ORDER    1
+
+/* Key lengths */      /* add to toolkit.h */
+#define KEY_40BIT   40  /* 40-bit key */
+#define KEY_64BIT   64  /* 64-bit key */
+#define KEY_128BIT  128  /* 128-bit key */
+#define CEPA_MAX_ROUNDS 12
+
+/* Operation codes for MultiPrecArithm() */
+#define EXPO   0x21
+#define MUL            0x22
+/*#define ADD          0x23*/
+
+/****************************************************************************
+*  INCLUDE FILES
+****************************************************************************/
+
+/* system files */
+#include "cylink.h"
+#include "ctk_endian.h"
+/* callback function */
+#ifdef VXD
+typedef int (* YIELD_PROC)( void );
+#else
+typedef int (* YIELD_PROC)(int ); /*TKL00601*/
+#endif
+
+typedef struct {                   /*TKL00601*/
+       YIELD_PROC yield_proc;
+  void *     handle;         /* Application specific information */
+}YIELD_context;
+
+
+/* Secure Hash Algorithm structure */
+typedef struct
+{
+    u_int32_t state[ 5 ];      /* state */
+      u_int32_t count[ 2 ];          /* number of bits */
+ uchar buffer[ 64 ];     /* input buffer */
+} SHA_context;
+
+
+#ifdef  __cplusplus
+extern  "C" {
+#endif
+/* Copy Cylink DSS Common Parameters */    /*TKL01201*/
+   int GetDSSPQG(u_int16_t dss_p_bytes,
+                 uchar  *dss_p,
+          uchar  *dss_q,
+          uchar  *dss_g);
+
+/* Compute a Secure Hash Function */
+ int SHA( uchar   *message, u_int16_t message_bytes,
+                                                                       uchar  *hash_result );
+/* Initialize Secure Hash Function */
+ void SHAInit( SHA_context *hash_context );
+
+/* Update Secure Hash Function */
+ int SHAUpdate( SHA_context *hash_context,
+                const uchar        *message,
+                u_int16_t      message_bytes );
+/* Finalize Secure Hash Function */
+ int SHAFinal( SHA_context *hash_context,
+               uchar       *hash_result );
+/* Compute a DSS Signature */
+ int GenDSSSignature( u_int16_t dss_p_bytes, uchar  *dss_p,
+                uchar  *dss_q,      uchar  *dss_g,
+                      uchar  *dss_x,      uchar  *dss_k,
+                      uchar  *r,          uchar  *s,
+                      uchar  *hash_result );
+/* Verify a DSS Signature */
+ int VerDSSSignature( u_int16_t dss_p_bytes, uchar  *dss_p,
+                      uchar  *dss_q,      uchar  *dss_g,
+                      uchar  *dss_y,      uchar  *r,
+                      uchar  *s,          uchar  *hash_result);
+/* Initialize Random number Generator */
+ int InitRand( u_int16_t SEED_bytes, uchar  *SEED,
+                                                                                        uchar  *RVAL );
+/* Generate random number */
+ int GenRand( u_int16_t A_bytes, uchar  *A,
+                           uchar  *RVAL );
+/* Compute DSS public/secret number pair */
+ int GenDSSKey( u_int16_t dss_p_bytes, uchar  *dss_p,
+                uchar  *dss_q,      uchar  *dss_g,
+                uchar  *dss_x,      uchar  *dss_y,
+                                    uchar  *XKEY );
+/* Generate secret number */
+ int GenDSSNumber( uchar *dss_k, uchar *dss_q,
+                                                              uchar *KKEY );
+
+/* Compute a Diffie-Hellman Shared number */
+ int GetDHSharedNumber( u_int16_t DH_modulus_bytes, uchar  *DH_secret,
+                        uchar  *DH_public,       uchar  *DH_shared,
+                        uchar  *DH_modulus );
+/* Set Key by Diffie_Hellman shared number */
+ int SetDESKAPPAKey( u_int16_t DH_modulus_bytes, uchar  *DH_shared,
+                     uchar  *K );
+/* Expand DES key */
+ void DESKeyExpand( uchar *key, uchar *K1 );
+
+/* Encrypt a block of data with single DES */
+ int DESEncrypt( uchar  *des_iv,       uchar  *des_key,
+                 u_int16_t des_mode,      uchar  *input_array,
+                 uchar  *output_array, u_int16_t input_array_bytes );
+
+/* Decrypt a block of data with single DES */
+ int DESDecrypt( uchar  *des_iv,  uchar  *des_key,
+                 u_int16_t des_mode, uchar  *data_array,
+                                 u_int16_t data_array_bytes );
+
+/* One-Time-Pad Signature with a Diffie-Hellman shared number */
+ int DHOneTimePad( u_int16_t DH_modulus_bytes, uchar  *DH_shared,
+                   uchar  *X,               uchar  *Y );
+
+/* Compute a Diffie-Hellman pair */
+ int GenDHPair( u_int16_t DH_modulus_bytes, uchar  *DH_secret,
+               uchar  *DH_public,       uchar  *DH_base,
+               uchar  *DH_modulus,      uchar  *RVAL );
+
+ int GetPasswordKeySHA( u_int16_t Password_bytes, uchar  *Password,
+                                               uchar  *salt,          u_int16_t Count,
+                                            uchar  *K,             uchar  *IV );
+
+/* Generate DSS Common Parameters */
+ int GenDSSParameters( u_int16_t dss_p_bytes, uchar  *dss_p,
+                                          uchar  *dss_q,      uchar  *dss_g,
+                                      uchar  *RVAL, YIELD_context *yield_cont ); /*TKL00701*/
+
+/* Produce a Shamir Key-Sharing Triplet for Secret Number */
+int GenShamirTriplet( u_int16_t SecretNumber_bytes, uchar *SecretNumber,
+                                       uchar *first_value,        uchar *second_value,
+                                                                                                         uchar *third_value,        uchar *RVAL );
+
+/* Reconstract a Secret Number from Shamir Key-Sharing Duplex */
+int GetNumberShamirDuplex( u_int16_t SecretNumber_bytes,
+                              uchar  *value_A,
+                                u_int16_t A_position,                                                      uchar  *value_B,
+                                u_int16_t B_position,
+                              uchar  *SecretNumber );
+int SFDHEncrypt( u_int16_t DH_modulus_bytes,
+                                          uchar  *DH_modulus,
+                                     uchar  *DH_base,
+                                        uchar  *DH_public,
+                                                                                                 uchar  *DH_random_public,
+                                                                                                       uchar  *DH_shared,
+                                                                                                 uchar  *RVAL );
+int SFDHDecrypt( u_int16_t DH_modulus_bytes,
+                                                                                                        uchar  *DH_modulus,
+                                                                                                uchar  *DH_secret,
+                                                                                                 uchar  *DH_random_public,
+                                                                                                       uchar  *DH_shared );
+/* Check DES key weakness */
+int CheckDESKeyWeakness( uchar *key );
+
+int SetCipherKey( u_int16_t DH_shared_bytes,
+                                 uchar  *DH_shared,
+                                uchar  *Key,
+                                u_int16_t cryptoMethod );
+/* Non-Pipelined Triple DES encrypt*/
+int TDESEncrypt( uchar  *des_iv,
+                                                uchar  *des_key1,uchar *des_key2, uchar *des_key3,
+                                                u_int16_t des_mode,
+                                                uchar  *input_array,
+                                                uchar  *output_array,
+                                                u_int16_t input_array_bytes );
+/* Non-Pipelined Triple DES decrypt*/
+int TDESDecrypt( uchar  *des_iv,
+                                                uchar  *des_key1,uchar *des_key2, uchar *des_key3,
+                                                u_int16_t des_mode,
+                                                uchar  *data_array,
+                                                u_int16_t data_array_bytes );
+/*Pipeline Triple DES encrypt*/
+int PTDESEncrypt( uchar  *iv1, uchar *iv2, uchar *iv3,
+                                               uchar  *des_key1,uchar *des_key2, uchar *des_key3,
+                                               u_int16_t des_mode,
+                                               uchar  *input_array,
+                                               uchar  *output_array,
+                                               u_int16_t input_array_bytes );
+/*Pipeline Triple DES decrypt*/
+int PTDESDecrypt( uchar  *iv1, uchar *iv2, uchar *iv3,
+                                               uchar  *des_key1,uchar *des_key2, uchar *des_key3,
+                                               u_int16_t des_mode,
+                                               uchar  *data_array,
+                                               u_int16_t input_array_bytes );
+ int PCBC1Encrypt( uchar  *iv1, uchar *iv2, uchar *iv3,
+                                               uchar  *des_key1,uchar *des_key2, uchar *des_key3,
+                                               uchar  *msg1,uchar *msg2, uchar *msg3,
+                                               uchar  *out1,uchar *out2, uchar *out3,
+                                               u_int16_t input_array_bytes );
+ int PCBC1Decrypt( uchar  *iv1, uchar *iv2, uchar *iv3,
+                                               uchar  *des_key1,uchar *des_key2, uchar *des_key3,
+                                               uchar  *out1,uchar *out2, uchar *out3,
+                                               u_int16_t input_array_bytes );
+
+/*CEPA enc/dec */
+int CepaKeyExpand( uchar *key,
+                                       u_int16_t key_length,
+                                       u_int16_t number_of_rounds,
+                                       uchar *expanded_key );
+
+int CepaCsp( u_int16_t key_length,
+                         uchar *csp);
+
+int CepaEncrypt( uchar  *iv,
+                               uchar  *key,
+                               u_int16_t mode,
+                               uchar  *csp,
+                               u_int16_t r,
+                               uchar  *input_array,
+                               uchar  *output_array,
+                               u_int16_t input_array_bytes );
+
+int CepaDecrypt( uchar  *iv,
+                               uchar  *key,
+                               u_int16_t mode,
+                               uchar  *csp,
+                               u_int16_t r,
+                               uchar  *data_array,
+                               u_int16_t data_array_bytes );
+void BigNumInit(void);
+void SetDataOrder ( u_int16_t dataOrder);
+
+int GetDHSecretShared( u_int16_t DH_modulus_bytes, u_int16_t DH_secret_bytes, uchar  *DH_secret,
+                       uchar  *DH_public,       uchar  *DH_shared,
+                       uchar  *DH_modulus);
+int GenDHKey( u_int16_t DH_modulus_bytes, u_int16_t DH_secret_bytes, uchar  *DH_secret,
+             uchar  *DH_public,       uchar  *DH_base,
+             uchar  *DH_modulus,      uchar  *RVAL );
+int SFDHInitiate( u_int16_t DH_modulus_bytes, u_int16_t DH_secret_bytes,
+                       uchar  *DH_modulus, uchar  *DH_base,
+                       uchar  *DH_public, uchar  *DH_random_public,
+                       uchar  *DH_shared, uchar  *RVAL );
+int SFDHComplete( u_int16_t DH_modulus_bytes, u_int16_t DH_secret_bytes,
+                       uchar  *DH_modulus,
+                       uchar  *DH_secret, uchar  *DH_random_public,
+                       uchar  *DH_shared );
+
+int SplitKey( u_int16_t Secretnumber_bytes, uchar *SecretNumber,
+              uchar *first_value,       uchar *second_value,
+              uchar *third_value,      uchar *RVAL );
+int UnsplitKey( u_int16_t Secretnumber_bytes, uchar  *value_A,
+                u_int16_t A_position,        uchar  *value_B,
+                u_int16_t B_position,        uchar  *SecretNumber );
+int SAFERKeyExpand( uchar *key, u_int16_t key_length,
+        uchar *expanded_key );
+int SAFEREncrypt( uchar  *iv, uchar  *key, u_int16_t mode, u_int16_t key_length, 
+               uchar  *input_array, uchar  *output_array, u_int16_t input_array_bytes );
+int SAFERDecrypt( uchar  *iv, uchar  *key, u_int16_t mode, u_int16_t r_length,
+               uchar  *data_array, u_int16_t data_array_bytes );
+
+
+       void ByteSwap( uchar  *X, u_int16_t X_len);
+       void ByteSwap32( uchar  *X, u_int16_t X_len);
+       void WordSwap( uchar  *X, u_int16_t X_len);
+       void BigSwap( uchar *buffer, u_int16_t bufferLength);
+        int Sum_big (ord *X, ord *Y, ord *Z, u_int16_t len_X);
+        int Sum_Q(ord *X, u_int16_t src, u_int16_t len_X);
+       void  LShiftL_big( ord *X, u_int32_t len_X, u_int32_t n_bit );
+       int Sub_big  (ord *X, ord *Y, ord *Z, u_int16_t len_X);
+       int DivRem( u_int16_t X_bytes, ord *X, u_int16_t P_bytes, ord *P,
+                  ord *Z, ord *D);
+       int  SteinGCD (ord *m, ord *n, u_int16_t len);
+        int Add( ord *X, ord *Y, u_int16_t P_len, ord *P);
+       int Inverse(u_int16_t X_bytes, ord *X, u_int16_t P_bytes, ord *P,
+                   ord *Z);
+       int DoubleExpo(u_int16_t X1_bytes, ord *X1, u_int16_t Y1_bytes,
+                      ord *Y1, u_int16_t X2_bytes, ord *X2,
+                      u_int16_t Y2_bytes, ord *Y2, u_int16_t P_bytes,
+                      ord *P, ord *Z);
+       int Sum (ord *X, ord *Y, u_int16_t len_X);
+       void  Mul_big_1( ord  X, ord *Y, ord *XY, u_int16_t ly);
+       int Mul( u_int16_t X_bytes, ord *X, u_int16_t Y_bytes, ord *Y,
+                 u_int16_t P_bytes, ord *P, ord *Z );
+
+       int Square(u_int16_t X_bytes, ord *X, u_int16_t P_bytes, ord *P,
+                  ord *Z);
+
+       int PartReduct(u_int16_t X_bytes, ord *X, u_int16_t P_bytes, ord *P,
+                        ord *Z);
+       int Expo(u_int16_t X_bytes, ord *X, u_int16_t Y_bytes, ord *Y,
+                u_int16_t P_bytes, ord *P, ord *Z);
+
+
+#ifdef  __cplusplus
+}
+#endif
+
+
+#endif /* TOOLKIT_H */
+
diff --git a/lib/bind/dnssafe/Makefile.in b/lib/bind/dnssafe/Makefile.in
new file mode 100644 (file)
index 0000000..a79417d
--- /dev/null
@@ -0,0 +1,41 @@
+OBJS=  ahcbcpad.@O@ ahchdig.@O@ ahchencr.@O@ ahchgen.@O@ ahchrand.@O@ \
+       ahdigest.@O@ ahencryp.@O@ ahgen.@O@ ahrandom.@O@ ahrsaenc.@O@ \
+       ahrsaepr.@O@ ahrsaepu.@O@ aichdig.@O@ aichenc8.@O@ aichencn.@O@ \
+       aichencr.@O@ aichgen.@O@ aichrand.@O@ aimd5.@O@ aimd5ran.@O@ \
+       ainfotyp.@O@ ainull.@O@ airsaepr.@O@ airsaepu.@O@ airsakgn.@O@ \
+       airsaprv.@O@ airsapub.@O@ algchoic.@O@ algobj.@O@ amcrte.@O@ \
+       ammd5.@O@ ammd5r.@O@ amrkg.@O@ amrsae.@O@ balg.@O@ bgclrbit.c \
+       bgmdmpyx.@O@ bgmdsqx.@O@ bgmodexp.@O@ bgpegcd.@O@ big2exp.@O@ \
+       bigabs.@O@ bigacc.@O@ bigarith.@O@ bigcmp.@O@ bigconst.@O@ \
+       biginv.@O@ biglen.@O@ bigmodx.@O@ bigmpy.@O@ bigpdiv.@O@ \
+       bigpmpy.@O@ bigpmpyh.@O@ bigpmpyl.@O@ bigpsq.@O@ bigqrx.@O@ \
+       bigsmod.@O@ bigtocan.@O@ bigu.@O@ bigunexp.@O@ binfocsh.@O@ \
+       bkey.@O@ bmempool.@O@ cantobig.@O@ crt2.@O@ digest.@O@ \
+       digrand.@O@ encrypt.@O@ generate.@O@ intbits.@O@ intitem.@O@ \
+       keyobj.@O@ ki8byte.@O@ kifulprv.@O@ kiitem.@O@ kinfotyp.@O@ \
+       kipkcrpr.@O@ kirsacrt.@O@ kirsapub.@O@ md5.@O@ md5rand.@O@ \
+       prime.@O@ random.@O@ rsa.@O@ rsakeygn.@O@ seccbcd.@O@ \
+       seccbce.@O@ surrendr.@O@
+
+SRCS=  ahcbcpad.c ahchdig.c ahchencr.c ahchgen.c ahchrand.c ahdigest.c \
+       ahencryp.c ahgen.c ahrandom.c ahrsaenc.c ahrsaepr.c ahrsaepu.c \
+       aichdig.c aichenc8.c aichencn.c aichencr.c aichgen.c aichrand.c \
+       aimd5.c aimd5ran.c ainfotyp.c ainull.c airsaepr.c airsaepu.c \
+       airsakgn.c airsaprv.c airsapub.c algchoic.c algobj.c amcrte.c \
+       ammd5.c ammd5r.c amrkg.c amrsae.c balg.c bgclrbit.c bgmdmpyx.c \
+       bgmdsqx.c bgmodexp.c bgpegcd.c big2exp.c bigabs.c bigacc.c \
+       bigarith.c bigcmp.c bigconst.c biginv.c biglen.c bigmodx.c \
+       bigmpy.c bigpdiv.c bigpmpy.c bigpmpyh.c bigpmpyl.c bigpsq.c \
+       bigqrx.c bigsmod.c bigtocan.c bigu.c bigunexp.c binfocsh.c \
+       bkey.c bmempool.c cantobig.c crt2.c digest.c digrand.c encrypt.c \
+       generate.c intbits.c intitem.c keyobj.c ki8byte.c kifulprv.c \
+       kiitem.c kinfotyp.c kipkcrpr.c kirsacrt.c kirsapub.c md5.c \
+       md5rand.c prime.c random.c rsa.c rsakeygn.c seccbcd.c seccbce.c \
+       surrendr.c
+
+TARGETS= ${OBJS}
+
+CINCLUDES= -I.. -I../include
+CWARNINGS= -Werror
+
+@BIND9_MAKE_RULES@
diff --git a/lib/bind/dnssafe/ahcbcpad.c b/lib/bind/dnssafe/ahcbcpad.c
new file mode 100644 (file)
index 0000000..2763583
--- /dev/null
@@ -0,0 +1,176 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+/* Define this so that the type of the 'this' pointer in the
+     virtual functions will be correct for this derived class.
+ */
+struct AHSecretCBCPad;
+#define THIS_ENCRYPT_DECRYPT struct AHSecretCBCPad
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "balg.h"
+#include "ahcbcpad.h"
+#include "port_after.h"
+
+#define GENERATE_BREAK(type) { \
+    status = type; \
+    break; \
+  }
+
+/* Inherit the base class destructor, block size,
+     and decrypt init and update routines.
+ */
+static AHEncryptDecryptVTable V_TABLE = {
+  AHChooseEncryptDestructor, AHChooseEncryptGetBlockLen,
+  AHSecretCBCPadEncryptInit, AHChooseEncryptDecryptInit,
+  AHSecretCBCPadEncryptUpdate, AHChooseEncryptDecryptUpdate,
+  AHSecretCBCPadEncryptFinal, AHSecretCBCPadDecryptFinal
+};
+
+AHSecretCBCPad *AHSecretCBCPadConstructor2 (handler, infoType, info)
+AHSecretCBCPad *handler;
+struct B_AlgorithmInfoType *infoType;
+POINTER info;
+{
+  if (handler == (AHSecretCBCPad *)NULL_PTR) {
+    /* This constructor is being used to do a new */
+    if ((handler = (AHSecretCBCPad *)T_malloc (sizeof (*handler)))
+        == (AHSecretCBCPad *)NULL_PTR)
+      return (handler);
+  }
+
+  /* Construct base class with the infoType and info. */
+  AHChooseEncryptConstructor2
+    (&handler->chooseEncryptDecrypt, infoType, info);
+
+  handler->chooseEncryptDecrypt.encryptDecrypt.vTable = &V_TABLE;
+  return (handler);
+}
+
+int AHSecretCBCPadEncryptInit (handler, key, chooser, surrenderContext)
+AHSecretCBCPad *handler;
+B_Key *key;
+B_ALGORITHM_CHOOSER chooser;
+A_SURRENDER_CTX *surrenderContext;
+{
+  /* For encryption, we need to track the input length */
+  handler->_inputRemainder = 0;
+
+  return (AHChooseEncryptEncryptInit
+          (handler, key, chooser, surrenderContext));
+}
+
+int AHSecretCBCPadEncryptUpdate
+  (handler, partOut, partOutLen, maxPartOutLen, partIn, partInLen,
+   randomAlgorithm, surrenderContext)
+AHSecretCBCPad *handler;
+unsigned char *partOut;
+unsigned int *partOutLen;
+unsigned int maxPartOutLen;
+const unsigned char *partIn;
+unsigned int partInLen;
+B_Algorithm *randomAlgorithm;
+A_SURRENDER_CTX *surrenderContext;
+{
+  /* For encryption, we need to track the input length */
+  handler->_inputRemainder = (handler->_inputRemainder + partInLen) % 8;
+  
+  return (AHChooseEncryptEncryptUpdate
+          (handler, partOut, partOutLen, maxPartOutLen, partIn, partInLen,
+           randomAlgorithm, surrenderContext));
+}
+
+int AHSecretCBCPadEncryptFinal
+  (handler, partOut, partOutLen, maxPartOutLen, randomAlgorithm,
+   surrenderContext)
+AHSecretCBCPad *handler;
+unsigned char *partOut;
+unsigned int *partOutLen;
+unsigned int maxPartOutLen;
+B_Algorithm *randomAlgorithm;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+  unsigned char finalBuffer[8];
+  unsigned int padLen, dummyPartOutLen;
+
+  padLen = 8 - handler->_inputRemainder;
+  T_memset ((POINTER)finalBuffer, padLen, padLen);
+
+  /* Add the pad bytes.  This should force the output of the final block.
+   */
+  if ((status = AHChooseEncryptEncryptUpdate
+       (handler, partOut, partOutLen, maxPartOutLen, finalBuffer, padLen,
+        randomAlgorithm, surrenderContext)) != 0)
+    return (status);
+
+  /* The encrypt final operation should have no output. */
+  if ((status = AHChooseEncryptEncryptFinal
+       (handler, (unsigned char *)NULL_PTR, &dummyPartOutLen, 0,
+        (B_Algorithm *)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR)) != 0)
+    return (status);
+
+  /* Restart the context. */
+  handler->_inputRemainder = 0;
+
+  /* No need to zeroize the finalBuffer since it only contains pad bytes. */
+  return (0);
+}
+
+int AHSecretCBCPadDecryptFinal
+  (handler, partOut, partOutLen, maxPartOutLen, randomAlgorithm,
+   surrenderContext)
+AHSecretCBCPad *handler;
+unsigned char *partOut;
+unsigned int *partOutLen;
+unsigned int maxPartOutLen;
+B_Algorithm *randomAlgorithm;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+  unsigned char finalBuffer[16], *padBuffer;
+  unsigned int padLen, localPartOutLen, i;
+  
+  do {
+    /* For now, the DecrypyFinal operations is set to output 16 bytes.
+     */
+    if ((status = AHChooseEncryptDecryptFinal
+         (handler, finalBuffer, &localPartOutLen, sizeof (finalBuffer),
+          randomAlgorithm, surrenderContext)) != 0)
+      break;
+
+    if (localPartOutLen == 8)
+      padBuffer = finalBuffer;
+    else if (localPartOutLen == 16)
+      padBuffer = finalBuffer + 8;
+    else
+      GENERATE_BREAK (BE_INPUT_LEN);
+
+    /* Check that padding is one 1 to eight 8's.
+     */
+    if ((padLen = (unsigned int)padBuffer[7]) == 0 || padLen > 8)
+      GENERATE_BREAK (BE_INPUT_DATA);
+    for (i = 8 - padLen; i < 8; i++) {
+      if ((unsigned int)padBuffer[i] != padLen)
+        GENERATE_BREAK (BE_INPUT_DATA);
+    }
+
+    if ((*partOutLen = localPartOutLen - padLen) > maxPartOutLen)
+      GENERATE_BREAK (BE_OUTPUT_LEN);
+
+    T_memcpy
+      ((POINTER)partOut, (POINTER)finalBuffer, *partOutLen);
+  } while (0);
+
+  T_memset ((POINTER)finalBuffer, 0, sizeof (finalBuffer));
+  return (status);
+}
+
diff --git a/lib/bind/dnssafe/ahcbcpad.h b/lib/bind/dnssafe/ahcbcpad.h
new file mode 100644 (file)
index 0000000..70c300b
--- /dev/null
@@ -0,0 +1,37 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _AHCBCPAD_H_
+#define _AHCBCPAD_H_
+
+#include "ahchencr.h"
+
+typedef struct AHSecretCBCPad {
+  AHChooseEncryptDecrypt chooseEncryptDecrypt;                 /* base class */
+
+  unsigned int _inputRemainder;    /* Used for encrypt to compute pad length */
+} AHSecretCBCPad;
+
+AHSecretCBCPad *AHSecretCBCPadConstructor2 PROTO_LIST
+  ((AHSecretCBCPad *, struct B_AlgorithmInfoType *, POINTER));
+
+int AHSecretCBCPadEncryptInit PROTO_LIST
+  ((THIS_ENCRYPT_DECRYPT *, B_Key *, B_ALGORITHM_CHOOSER,
+    A_SURRENDER_CTX *));
+int AHSecretCBCPadEncryptUpdate PROTO_LIST
+  ((THIS_ENCRYPT_DECRYPT *, unsigned char *, unsigned int *,
+    unsigned int, const unsigned char *, unsigned int, B_Algorithm *,
+    A_SURRENDER_CTX *));
+int AHSecretCBCPadEncryptFinal PROTO_LIST
+  ((THIS_ENCRYPT_DECRYPT *, unsigned char *, unsigned int *,
+    unsigned int, B_Algorithm *, A_SURRENDER_CTX *));
+int AHSecretCBCPadDecryptFinal PROTO_LIST
+  ((THIS_ENCRYPT_DECRYPT *, unsigned char *, unsigned int *,
+    unsigned int, B_Algorithm *, A_SURRENDER_CTX *));
+
+#endif
diff --git a/lib/bind/dnssafe/ahchdig.c b/lib/bind/dnssafe/ahchdig.c
new file mode 100644 (file)
index 0000000..43e1530
--- /dev/null
@@ -0,0 +1,132 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+/* Define this so that the type of the 'this' pointer in the
+     virtual functions will be correct for this derived class.
+ */
+struct AHChooseDigest;
+#define THIS_DIGEST struct AHChooseDigest
+
+#include "port_before.h"
+#include "global.h"
+#include "algae.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "balg.h"
+#include "balgmeth.h"
+#include "ahchdig.h"
+#include "amdigest.h"
+#include "port_after.h"
+
+static int InitDigestAlga PROTO_LIST
+  ((AlgaChoice *, POINTER, B_ALGORITHM_METHOD *, A_SURRENDER_CTX *));
+
+static AHDigestVTable V_TABLE = {
+  AHChooseDigestDestructor, AHChooseDigestInit, AHChooseDigestUpdate,
+  AHChooseDigestFinal
+};
+
+AHChooseDigest *AHChooseDigestConstructor2 (handler, infoType, info)
+AHChooseDigest *handler;
+struct B_AlgorithmInfoType *infoType;
+POINTER info;
+{
+  if (handler == (AHChooseDigest *)NULL_PTR) {
+    /* This constructor is being used to do a new */
+    if ((handler = (AHChooseDigest *)T_malloc (sizeof (*handler)))
+        == (AHChooseDigest *)NULL_PTR)
+      return (handler);
+  }
+
+  /* Construct base class */
+  AHDigestConstructor (&handler->digest);
+
+  ALGA_CHOICE_Constructor (&handler->algaChoice, InitDigestAlga);
+  handler->algaChoice._algorithmInfoType = infoType;
+  handler->algaChoice._algorithmInfo = info;
+
+  handler->digest.vTable = &V_TABLE;
+
+  return (handler);
+}
+
+void AHChooseDigestDestructor (handler)
+AHChooseDigest *handler;
+{
+  ALGA_CHOICE_Destructor (&handler->algaChoice);
+  /* There is no desructor to call for the base class. */
+}
+
+int AHChooseDigestInit (handler, key, chooser, surrenderContext)
+AHChooseDigest *handler;
+B_Key *key;
+B_ALGORITHM_CHOOSER chooser;
+A_SURRENDER_CTX *surrenderContext;
+{
+  return (AlgaChoiceChoose
+          (&handler->algaChoice, 0, key, chooser, surrenderContext));
+}
+
+int AHChooseDigestUpdate (handler, partIn, partInLen, surrenderContext)
+AHChooseDigest *handler;
+const unsigned char *partIn;
+unsigned int partInLen;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+  
+  if ((status = (*((A_DIGEST_ALGA *)handler->algaChoice._alga)->Update)
+       (handler->algaChoice.context.z.context, partIn, partInLen,
+        surrenderContext)) != 0)
+    return (ConvertAlgaeError (status));
+  return (0);    
+}
+
+int AHChooseDigestFinal
+  (handler, partOut, partOutLen, maxPartOutLen, surrenderContext)
+AHChooseDigest *handler;
+unsigned char *partOut;
+unsigned int *partOutLen;
+unsigned int maxPartOutLen;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+  
+  if ((status = (*((A_DIGEST_ALGA *)handler->algaChoice._alga)->Final)
+       (handler->algaChoice.context.z.context, partOut, partOutLen,
+        maxPartOutLen, surrenderContext)) != 0)
+    return (ConvertAlgaeError (status));
+  return (0);    
+}
+
+static int InitDigestAlga
+  (algaChoice, keyInfo, algorithmMethod, surrenderContext)
+AlgaChoice *algaChoice;
+POINTER keyInfo;
+B_ALGORITHM_METHOD *algorithmMethod;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+  unsigned int contextSize;
+
+UNUSED_ARG (keyInfo)
+  if ((status = (*((A_DIGEST_ALGA *)algorithmMethod->alga)->Query)
+       (&contextSize, algaChoice->_algorithmInfo)) != 0)
+    return (ConvertAlgaeError (status));
+
+  if ((status = ResizeContextMakeNewContext
+       (&algaChoice->context, contextSize)) != 0)
+    return (status);
+
+  if ((status = (*((A_DIGEST_ALGA *)algorithmMethod->alga)->Init)
+       (algaChoice->context.z.context, algaChoice->_algorithmInfo,
+        surrenderContext)) != 0)
+    return (ConvertAlgaeError (status));
+
+  return (0);
+}
diff --git a/lib/bind/dnssafe/ahchdig.h b/lib/bind/dnssafe/ahchdig.h
new file mode 100644 (file)
index 0000000..627422b
--- /dev/null
@@ -0,0 +1,32 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _AHCHDIG_H_
+#define _AHCHDIG_H_ 1
+
+#include "ahdigest.h"
+#include "algchoic.h"
+
+typedef struct AHChooseDigest {
+  AHDigest digest;                                             /* base class */
+  AlgaChoice algaChoice;
+} AHChooseDigest;
+
+AHChooseDigest *AHChooseDigestConstructor2 PROTO_LIST
+  ((AHChooseDigest *, struct B_AlgorithmInfoType *, POINTER));
+void AHChooseDigestDestructor PROTO_LIST ((THIS_DIGEST *));
+
+int AHChooseDigestInit PROTO_LIST
+  ((THIS_DIGEST *, B_Key *, B_ALGORITHM_CHOOSER, A_SURRENDER_CTX *));
+int AHChooseDigestUpdate PROTO_LIST
+  ((THIS_DIGEST *, const unsigned char *, unsigned int, A_SURRENDER_CTX *));
+int AHChooseDigestFinal PROTO_LIST
+  ((THIS_DIGEST *, unsigned char *, unsigned int *, unsigned int,
+    A_SURRENDER_CTX *));
+
+#endif
diff --git a/lib/bind/dnssafe/ahchencr.c b/lib/bind/dnssafe/ahchencr.c
new file mode 100644 (file)
index 0000000..af839ff
--- /dev/null
@@ -0,0 +1,268 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+/* Define this so that the type of the 'this' pointer in the
+     virtual functions will be correct for this derived class.
+ */
+struct AHChooseEncryptDecrypt;
+#define THIS_ENCRYPT_DECRYPT struct AHChooseEncryptDecrypt
+
+#include "port_before.h"
+#include "global.h"
+#include "algae.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "balg.h"
+#include "balgmeth.h"
+#include "ahchencr.h"
+#include "amencdec.h"
+#include "port_after.h"
+
+static int InitEncryptDecryptAlga PROTO_LIST
+  ((AlgaChoice *, POINTER, B_ALGORITHM_METHOD *, A_SURRENDER_CTX *));
+
+static AHEncryptDecryptVTable V_TABLE = {
+  AHChooseEncryptDestructor, AHChooseEncryptGetBlockLen,
+  AHChooseEncryptEncryptInit, AHChooseEncryptDecryptInit,
+  AHChooseEncryptEncryptUpdate, AHChooseEncryptDecryptUpdate,
+  AHChooseEncryptEncryptFinal, AHChooseEncryptDecryptFinal
+};
+
+/* In C++:
+AHChooseEncryptDecrypt::AHChooseEncryptDecrypt
+  (B_AlgorithmInfoType *infoType, POINTER info)
+  : algaChoice (InitEncryptDecryptAlga)
+{
+  algaChoice.setAlgorithmInfoType (infoType);
+  algaChoice.setAlgorithmInfo (info);
+}
+ */
+AHChooseEncryptDecrypt *AHChooseEncryptConstructor2 (handler, infoType, info)
+AHChooseEncryptDecrypt *handler;
+struct B_AlgorithmInfoType *infoType;
+POINTER info;
+{
+  if (handler == (AHChooseEncryptDecrypt *)NULL_PTR) {
+    /* This constructor is being used to do a new */
+    if ((handler = (AHChooseEncryptDecrypt *)T_malloc (sizeof (*handler)))
+        == (AHChooseEncryptDecrypt *)NULL_PTR)
+      return (handler);
+  }
+
+  /* Construct base class */
+  AHEncryptDecryptConstructor (&handler->encryptDecrypt);
+
+  ALGA_CHOICE_Constructor (&handler->algaChoice, InitEncryptDecryptAlga);
+  handler->algaChoice._algorithmInfoType = infoType;
+  handler->algaChoice._algorithmInfo = info;
+
+  handler->encryptDecrypt.vTable = &V_TABLE;
+
+  return (handler);
+}
+
+void AHChooseEncryptDestructor (handler)
+AHChooseEncryptDecrypt *handler;
+{
+  ALGA_CHOICE_Destructor (&handler->algaChoice);
+  /* There is no desructor to call for the base class. */
+}
+
+int AHChooseEncryptGetBlockLen (handler, blockLen)
+AHChooseEncryptDecrypt *handler;
+unsigned int *blockLen;
+{
+  int status;
+
+  if ((status = (*((A_ENCRYPT_DECRYPT_ALGA *)handler->algaChoice._alga)->
+                 GetBlockLen)
+       (handler->algaChoice.context.z.context, blockLen)) != 0)
+    return (ConvertAlgaeError (status));
+  return (0);
+}
+
+/* In C++:
+int AHChooseEncryptDecrypt::encryptInit
+  (B_Key *key, B_ALGORITHM_CHOOSER chooser, A_SURRENDER_CTX *surrenderContext)
+{
+  return (algaChoice.choose (1, key, chooser, surrenderContext));
+}
+ */
+int AHChooseEncryptEncryptInit (handler, key, chooser, surrenderContext)
+AHChooseEncryptDecrypt *handler;
+B_Key *key;
+B_ALGORITHM_CHOOSER chooser;
+A_SURRENDER_CTX *surrenderContext;
+{
+  return (AlgaChoiceChoose
+          (&handler->algaChoice, 1, key, chooser, surrenderContext));
+}
+
+int AHChooseEncryptDecryptInit (handler, key, chooser, surrenderContext)
+AHChooseEncryptDecrypt *handler;
+B_Key *key;
+B_ALGORITHM_CHOOSER chooser;
+A_SURRENDER_CTX *surrenderContext;
+{
+  return (AlgaChoiceChoose
+          (&handler->algaChoice, 0, key, chooser, surrenderContext));
+}
+
+/* In C++:
+int AHChooseEncryptDecrypt::encryptUpdate
+  (unsigned char *partOut, unsigned int *partOutLen,
+   unsigned int maxPartOutLen, unsigned char *partIn, unsigned int partInLen,
+   B_Algorithm *randomAlgorithm, A_SURRENDER_CTX *surrenderContext)
+{
+  int status;
+
+  if ((status = (*((A_ENCRYPT_DECRYPT_ALGA *)algaChoice.alga ()) ->Update)
+       (algaChoice.context (), partOut, partOutLen, maxPartOutLen,
+        partIn, partInLen, surrenderContext)) != 0)
+    return (ConvertAlgaeError (status));
+  return (0);
+}  
+ */
+int AHChooseEncryptEncryptUpdate
+  (handler, partOut, partOutLen, maxPartOutLen, partIn, partInLen,
+   randomAlgorithm, surrenderContext)
+AHChooseEncryptDecrypt *handler;
+unsigned char *partOut;
+unsigned int *partOutLen;
+unsigned int maxPartOutLen;
+const unsigned char *partIn;
+unsigned int partInLen;
+B_Algorithm *randomAlgorithm;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+
+UNUSED_ARG (randomAlgorithm)
+
+  if ((status = (*((A_ENCRYPT_DECRYPT_ALGA *)handler->algaChoice._alga)->
+                 Update)
+       (handler->algaChoice.context.z.context, partOut, partOutLen,
+        maxPartOutLen, partIn, partInLen, surrenderContext)) != 0)
+    return (ConvertAlgaeError (status));
+  return (0);
+}
+
+int AHChooseEncryptDecryptUpdate
+  (handler, partOut, partOutLen, maxPartOutLen, partIn, partInLen,
+   randomAlgorithm, surrenderContext)
+AHChooseEncryptDecrypt *handler;
+unsigned char *partOut;
+unsigned int *partOutLen;
+unsigned int maxPartOutLen;
+const unsigned char *partIn;
+unsigned int partInLen;
+B_Algorithm *randomAlgorithm;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+
+UNUSED_ARG (randomAlgorithm)
+
+  if ((status = (*((A_ENCRYPT_DECRYPT_ALGA *)handler->algaChoice._alga)->
+                 Update)
+       (handler->algaChoice.context.z.context, partOut, partOutLen,
+        maxPartOutLen, partIn, partInLen, surrenderContext)) != 0)
+    return (ConvertAlgaeError (status));
+  return (0);
+}
+
+int AHChooseEncryptEncryptFinal
+  (handler, partOut, partOutLen, maxPartOutLen, randomAlgorithm,
+   surrenderContext)
+AHChooseEncryptDecrypt *handler;
+unsigned char *partOut;
+unsigned int *partOutLen;
+unsigned int maxPartOutLen;
+B_Algorithm *randomAlgorithm;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+
+UNUSED_ARG (randomAlgorithm)
+
+  if ((status = (*((A_ENCRYPT_DECRYPT_ALGA *)handler->algaChoice._alga)->Final)
+       (handler->algaChoice.context.z.context, partOut, partOutLen,
+        maxPartOutLen, surrenderContext)) != 0)
+    return (ConvertAlgaeError (status));
+  return (0);
+}
+
+int AHChooseEncryptDecryptFinal
+  (handler, partOut, partOutLen, maxPartOutLen, randomAlgorithm,
+   surrenderContext)
+AHChooseEncryptDecrypt *handler;
+unsigned char *partOut;
+unsigned int *partOutLen;
+unsigned int maxPartOutLen;
+B_Algorithm *randomAlgorithm;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+
+UNUSED_ARG (randomAlgorithm)
+
+  if ((status = (*((A_ENCRYPT_DECRYPT_ALGA *)handler->algaChoice._alga)->Final)
+       (handler->algaChoice.context.z.context, partOut, partOutLen,
+        maxPartOutLen, surrenderContext)) != 0)
+    return (ConvertAlgaeError (status));
+  return (0);
+}
+
+/* In C++:
+static int InitEncryptDecryptAlga
+  (AlgaChoice *algaChoice, POINTER keyInfo, POINTER alga,
+   A_SURRENDER_CTX *surrenderContext)
+{
+  int status;
+  unsigned int contextSize;
+
+  if ((status = (*((A_ENCRYPT_DECRYPT_ALGA *)alga)->Query)
+       (&contextSize, keyInfo, algaChoice->algorithmInfo ())) != 0)
+    return (ConvertAlgaeError (status));
+
+  if ((status = algaChoice->makeNewContext (contextSize)) != 0)
+    return (status);
+
+  if ((status = (*((A_ENCRYPT_DECRYPT_ALGA *)alga)->Init)
+       (algaChoice->context (), keyInfo, algaChoice->algorithmInfo (),
+        surrenderContext)) != 0)
+    return (ConvertAlgaeError (status));
+
+  return (0);
+}
+ */
+static int InitEncryptDecryptAlga
+  (algaChoice, keyInfo, algorithmMethod, surrenderContext)
+AlgaChoice *algaChoice;
+POINTER keyInfo;
+B_ALGORITHM_METHOD *algorithmMethod;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+  unsigned int contextSize;
+
+  if ((status = (*((A_ENCRYPT_DECRYPT_ALGA *)algorithmMethod->alga)->Query)
+       (&contextSize, keyInfo, algaChoice->_algorithmInfo)) != 0)
+    return (ConvertAlgaeError (status));
+
+  if ((status = ResizeContextMakeNewContext
+       (&algaChoice->context, contextSize)) != 0)
+    return (status);
+
+  if ((status = (*((A_ENCRYPT_DECRYPT_ALGA *)algorithmMethod->alga)->Init)
+       (algaChoice->context.z.context, keyInfo, algaChoice->_algorithmInfo,
+        surrenderContext)) != 0)
+    return (ConvertAlgaeError (status));
+
+  return (0);
+}
diff --git a/lib/bind/dnssafe/ahchencr.h b/lib/bind/dnssafe/ahchencr.h
new file mode 100644 (file)
index 0000000..9672e3f
--- /dev/null
@@ -0,0 +1,74 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _AHCHENCR_H_
+#define _AHCHENCR_H_ 1
+
+#include "ahencryp.h"
+#include "algchoic.h"
+
+/* In C++:
+class AHChooseEncryptDecrypt : public AHEncryptDecrypt {
+public:
+  AHChooseEncryptDecrypt (B_AlgorithmInfoType *, POINTER);
+  virtual ~AHChooseEncryptDecrypt () {};
+
+  virtual int getBlockLen (unsigned int *);
+  virtual int encryptInit (B_Key *, B_ALGORITHM_CHOOSER, A_SURRENDER_CTX *);
+  virtual int decryptInit (B_Key *, B_ALGORITHM_CHOOSER, A_SURRENDER_CTX *);
+  virtual int encryptUpdate
+    (unsigned char *, unsigned int *, unsigned int, unsigned char *,
+     unsigned int, B_Algorithm *, A_SURRENDER_CTX *);
+  virtual int decryptUpdate
+    (unsigned char *, unsigned int *, unsigned int, unsigned char *,
+     unsigned int, B_Algorithm *, A_SURRENDER_CTX *);
+  virtual int encryptFinal
+    (unsigned char *, unsigned int *, unsigned int, B_Algorithm *,
+     A_SURRENDER_CTX *);
+  virtual int decryptFinal
+    (unsigned char *, unsigned int *, unsigned int, B_Algorithm *,
+     A_SURRENDER_CTX *);
+
+private:
+  AlgaChoice algaChoice;
+};
+ */
+
+typedef struct AHChooseEncryptDecrypt {
+  AHEncryptDecrypt encryptDecrypt;                             /* base class */
+  AlgaChoice algaChoice;
+} AHChooseEncryptDecrypt;
+
+AHChooseEncryptDecrypt *AHChooseEncryptConstructor2 PROTO_LIST
+  ((AHChooseEncryptDecrypt *, struct B_AlgorithmInfoType *, POINTER));
+void AHChooseEncryptDestructor PROTO_LIST ((THIS_ENCRYPT_DECRYPT *));
+
+int AHChooseEncryptGetBlockLen PROTO_LIST
+  ((THIS_ENCRYPT_DECRYPT *, unsigned int *));
+int AHChooseEncryptEncryptInit PROTO_LIST
+  ((THIS_ENCRYPT_DECRYPT *, B_Key *, B_ALGORITHM_CHOOSER,
+    A_SURRENDER_CTX *));
+int AHChooseEncryptDecryptInit PROTO_LIST
+  ((THIS_ENCRYPT_DECRYPT *, B_Key *, B_ALGORITHM_CHOOSER,
+    A_SURRENDER_CTX *));
+int AHChooseEncryptEncryptUpdate PROTO_LIST
+  ((THIS_ENCRYPT_DECRYPT *, unsigned char *, unsigned int *,
+    unsigned int, const unsigned char *, unsigned int, B_Algorithm *,
+    A_SURRENDER_CTX *));
+int AHChooseEncryptDecryptUpdate PROTO_LIST
+  ((THIS_ENCRYPT_DECRYPT *, unsigned char *, unsigned int *,
+    unsigned int, const unsigned char *, unsigned int, B_Algorithm *,
+    A_SURRENDER_CTX *));
+int AHChooseEncryptEncryptFinal PROTO_LIST
+  ((THIS_ENCRYPT_DECRYPT *, unsigned char *, unsigned int *,
+    unsigned int, B_Algorithm *, A_SURRENDER_CTX *));
+int AHChooseEncryptDecryptFinal PROTO_LIST
+  ((THIS_ENCRYPT_DECRYPT *, unsigned char *, unsigned int *,
+    unsigned int, B_Algorithm *, A_SURRENDER_CTX *));
+
+#endif
diff --git a/lib/bind/dnssafe/ahchgen.c b/lib/bind/dnssafe/ahchgen.c
new file mode 100644 (file)
index 0000000..a524a4b
--- /dev/null
@@ -0,0 +1,218 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+/* Define this so that the type of the 'this' pointer in the
+     virtual functions will be correct for this derived class.
+ */
+struct AHChooseGenerate;
+#define THIS_GENERATE struct AHChooseGenerate
+
+/* Define this so that the type of the AlgaChoice pointer in the
+     INIT_ALGA functions will be correct for this derived class.
+ */
+struct GenerateAlgaChoice;
+#define THIS_ALGA_CHOICE struct GenerateAlgaChoice
+
+#include "port_before.h"
+#include "global.h"
+#include "algae.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "balg.h"
+#include "balgmeth.h"
+#include "ahchgen.h"
+#include "amgen.h"
+#include "port_after.h"
+
+static int InitGenerateAlga PROTO_LIST
+  ((GenerateAlgaChoice *, POINTER, B_ALGORITHM_METHOD *, A_SURRENDER_CTX *));
+static int GenerateResult PROTO_LIST
+  ((GenerateAlgaChoice *, POINTER *, B_Algorithm *, A_SURRENDER_CTX *));
+
+static AHGenerateVTable V_TABLE = {
+  AHChooseGenerateDestructor, AHChooseGenerateInit, AHChooseGenerateKeypair,
+  AHChooseGenerateParameters
+};
+
+AHChooseGenerate *AHChooseGenerateConstructor2 (handler, infoType, info)
+AHChooseGenerate *handler;
+struct B_AlgorithmInfoType *infoType;
+POINTER info;
+{
+  if (handler == (AHChooseGenerate *)NULL_PTR) {
+    /* This constructor is being used to do a new */
+    if ((handler = (AHChooseGenerate *)T_malloc (sizeof (*handler)))
+        == (AHChooseGenerate *)NULL_PTR)
+      return (handler);
+  }
+
+  /* Construct base class */
+  AHGenerateConstructor (&handler->generate);
+
+  ALGA_CHOICE_Constructor
+    (&handler->generateAlgaChoice.algaChoice, InitGenerateAlga);
+  ResizeContextConstructor (&handler->generateAlgaChoice.secondContext);
+  ResizeContextConstructor (&handler->generateAlgaChoice.randomBlock);
+
+  /* Set algaChoice.
+   */
+  handler->generateAlgaChoice.algaChoice._algorithmInfoType = infoType;
+  handler->generateAlgaChoice.algaChoice._algorithmInfo = info;
+
+  handler->generate.vTable = &V_TABLE;
+
+  return (handler);
+}
+
+void AHChooseGenerateDestructor (handler)
+AHChooseGenerate *handler;
+{
+  ResizeContextDestructor (&handler->generateAlgaChoice.secondContext);
+  ResizeContextDestructor (&handler->generateAlgaChoice.randomBlock);
+  ALGA_CHOICE_Destructor (&handler->generateAlgaChoice.algaChoice);
+  /* There is no desructor to call for the base class. */
+}
+
+int AHChooseGenerateInit (handler, chooser, surrenderContext)
+AHChooseGenerate *handler;
+B_ALGORITHM_CHOOSER chooser;
+A_SURRENDER_CTX *surrenderContext;
+{
+  return (AlgaChoiceChoose
+          (&handler->generateAlgaChoice.algaChoice, 0, (B_Key *)NULL_PTR,
+           chooser, surrenderContext));
+}
+
+int AHChooseGenerateKeypair
+  (handler, publicKey, privateKey, randomAlgorithm, surrenderContext)
+AHChooseGenerate *handler;
+B_Key *publicKey;
+B_Key *privateKey;
+B_Algorithm *randomAlgorithm;
+A_SURRENDER_CTX *surrenderContext;
+{
+  POINTER result;
+  int status;  
+  
+  if ((status = GenerateResult
+       (&handler->generateAlgaChoice, &result, randomAlgorithm,
+        surrenderContext)) != 0)
+    return (status);
+  if ((status = B_KeySetInfo
+       (publicKey, handler->generateAlgaChoice._resultInfoType, result)) != 0)
+    return (status);
+  return (B_KeySetInfo
+          (privateKey, handler->generateAlgaChoice._resultInfoType, result));
+}
+
+int AHChooseGenerateParameters
+  (handler, resultAlgorithm, randomAlgorithm, surrenderContext)
+AHChooseGenerate *handler;
+B_Algorithm *resultAlgorithm;
+B_Algorithm *randomAlgorithm;
+A_SURRENDER_CTX *surrenderContext;
+{
+  POINTER result;
+  int status;  
+  
+  if ((status = GenerateResult
+       (&handler->generateAlgaChoice, &result, randomAlgorithm,
+        surrenderContext)) != 0)
+    return (status);
+
+  /* Force the resultInfoType into a B_AlgorithmInfoType since it is
+       supplied in the chooser as a B_KeyInfoType. */
+  return (B_AlgorithmSetInfo
+          (resultAlgorithm, (struct B_AlgorithmInfoType *)
+           handler->generateAlgaChoice._resultInfoType, result));
+}
+
+static int InitGenerateAlga
+  (generateAlgaChoice, keyInfo, algorithmMethod, surrenderContext)
+GenerateAlgaChoice *generateAlgaChoice;
+POINTER keyInfo;
+B_ALGORITHM_METHOD *algorithmMethod;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+  unsigned int contextSize, secondContextSize;
+
+UNUSED_ARG (keyInfo)
+  /* Note that this also gets the resultInfoType which will be used later
+       by GenerateResult. */
+  if ((status = (*((A_GENERATE_ALGA *)algorithmMethod->alga)->Query)
+       (&contextSize, &secondContextSize, &generateAlgaChoice->_randomBlockLen,
+        &generateAlgaChoice->_resultInfoType,
+        generateAlgaChoice->algaChoice._algorithmInfo)) != 0)
+    return (ConvertAlgaeError (status));
+
+  /* Create the context.
+   */
+  if ((status = ResizeContextMakeNewContext
+       (&generateAlgaChoice->algaChoice.context, contextSize)) != 0)
+    return (status);
+
+  /* Create the second context which is only passed during Init, but
+       must persist for all operations. */
+  if ((status = ResizeContextMakeNewContext
+       (&generateAlgaChoice->secondContext, secondContextSize)) != 0)
+    return (status);
+
+  /* Create randomBlock which will be filled in during GenerateResult. */
+  if ((status = ResizeContextMakeNewContext
+       (&generateAlgaChoice->randomBlock, generateAlgaChoice->_randomBlockLen))
+      != 0)
+    return (status);
+
+  if ((status = (*((A_GENERATE_ALGA *)algorithmMethod->alga)->Init)
+       (generateAlgaChoice->algaChoice.context.z.context,
+        generateAlgaChoice->secondContext.z.context,
+        generateAlgaChoice->algaChoice._algorithmInfo, surrenderContext)) != 0)
+    return (ConvertAlgaeError (status));
+
+   return (0);
+}
+
+/* Call the generate procedure repeatedly with a new random block
+     until it succeeds.
+ */
+static int GenerateResult
+  (generateAlgaChoice, result, randomAlgorithm, surrenderContext)
+GenerateAlgaChoice *generateAlgaChoice;
+POINTER *result;
+B_Algorithm *randomAlgorithm;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+
+  /* Fill in the random block and try generating as long as the
+       the generate operation returns BE_NEED_RANDOM.
+   */
+  while (1) {
+    if ((status = B_AlgorithmGenerateRandomBytes
+         (randomAlgorithm,
+          (unsigned char *)generateAlgaChoice->randomBlock.z.context,
+          generateAlgaChoice->_randomBlockLen, surrenderContext)) != 0)
+      return (status);
+
+    if ((status = (*((A_GENERATE_ALGA *)
+                     generateAlgaChoice->algaChoice._alga)->Generate)
+         (generateAlgaChoice->algaChoice.context.z.context, result,
+          (unsigned char *)generateAlgaChoice->randomBlock.z.context,
+          surrenderContext)) != 0) {
+      if (status != AE_NEED_RANDOM)
+        return (ConvertAlgaeError (status));
+      
+      /* Else continue and try again */
+    }
+    else
+      /* Success, so return */
+      return (0);
+  }
+}
+
diff --git a/lib/bind/dnssafe/ahchgen.h b/lib/bind/dnssafe/ahchgen.h
new file mode 100644 (file)
index 0000000..8e7ecf3
--- /dev/null
@@ -0,0 +1,44 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _AHCHGEN_H_
+#define _AHCHGEN_H_ 1
+
+#include "ahgen.h"
+#include "algchoic.h"
+
+/* Make a new class derived from an AlgaChoice which records the
+     result algorithm info type and needed randomBlockLen.
+ */
+typedef struct GenerateAlgaChoice {
+  AlgaChoice algaChoice;                                       /* base class */
+
+  struct B_KeyInfoType *_resultInfoType;
+  ResizeContext secondContext;                           /* used for scratch */
+  ResizeContext randomBlock;
+  unsigned int _randomBlockLen;
+} GenerateAlgaChoice;
+
+typedef struct AHChooseGenerate {
+  AHGenerate generate;                                         /* base class */
+
+  GenerateAlgaChoice generateAlgaChoice;
+} AHChooseGenerate;
+
+AHChooseGenerate *AHChooseGenerateConstructor2 PROTO_LIST
+  ((AHChooseGenerate *, struct B_AlgorithmInfoType *, POINTER));
+void AHChooseGenerateDestructor PROTO_LIST ((THIS_GENERATE *));
+
+int AHChooseGenerateInit PROTO_LIST
+  ((THIS_GENERATE *, B_ALGORITHM_CHOOSER, A_SURRENDER_CTX *));
+int AHChooseGenerateKeypair PROTO_LIST
+  ((THIS_GENERATE *, B_Key *, B_Key *, B_Algorithm *, A_SURRENDER_CTX *));
+int AHChooseGenerateParameters PROTO_LIST
+  ((THIS_GENERATE *, B_Algorithm *, B_Algorithm *, A_SURRENDER_CTX *));
+
+#endif
diff --git a/lib/bind/dnssafe/ahchrand.c b/lib/bind/dnssafe/ahchrand.c
new file mode 100644 (file)
index 0000000..579a7b2
--- /dev/null
@@ -0,0 +1,130 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+/* Define this so that the type of the 'this' pointer in the
+     virtual functions will be correct for this derived class.
+ */
+struct AHChooseRandom;
+#define THIS_RANDOM struct AHChooseRandom
+
+#include "port_before.h"
+#include "global.h"
+#include "algae.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "balg.h"
+#include "balgmeth.h"
+#include "ahchrand.h"
+#include "amrandom.h"
+#include "port_after.h"
+
+static int InitRandomAlga PROTO_LIST
+  ((AlgaChoice *, POINTER, B_ALGORITHM_METHOD *, A_SURRENDER_CTX *));
+
+static AHRandomVTable V_TABLE = {
+  AHChooseRandomDestructor, AHChooseRandomInit, AHChooseRandomUpdate,
+  AHChooseRandomGenerateBytes
+};
+
+AHChooseRandom *AHChooseRandomConstructor2 (handler, infoType, info)
+AHChooseRandom *handler;
+struct B_AlgorithmInfoType *infoType;
+POINTER info;
+{
+  if (handler == (AHChooseRandom *)NULL_PTR) {
+    /* This constructor is being used to do a new */
+    if ((handler = (AHChooseRandom *)T_malloc (sizeof (*handler)))
+        == (AHChooseRandom *)NULL_PTR)
+      return (handler);
+  }
+
+  /* Construct base class */
+  AHRandomConstructor (&handler->random);
+
+  ALGA_CHOICE_Constructor (&handler->algaChoice, InitRandomAlga);
+  handler->algaChoice._algorithmInfoType = infoType;
+  handler->algaChoice._algorithmInfo = info;
+
+  handler->random.vTable = &V_TABLE;
+
+  return (handler);
+}
+
+void AHChooseRandomDestructor (handler)
+AHChooseRandom *handler;
+{
+  ALGA_CHOICE_Destructor (&handler->algaChoice);
+  /* There is no desructor to call for the base class. */
+}
+
+int AHChooseRandomInit (handler, chooser, surrenderContext)
+AHChooseRandom *handler;
+B_ALGORITHM_CHOOSER chooser;
+A_SURRENDER_CTX *surrenderContext;
+{
+  return (AlgaChoiceChoose
+          (&handler->algaChoice, 0, (B_Key *)NULL_PTR, chooser,
+           surrenderContext));
+}
+
+int AHChooseRandomUpdate (handler, input, inputLen, surrenderContext)
+AHChooseRandom *handler;
+unsigned char *input;
+unsigned int inputLen;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+  
+  if ((status = (*((A_RANDOM_ALGA *)handler->algaChoice._alga)->Update)
+       (handler->algaChoice.context.z.context, input, inputLen,
+        surrenderContext)) != 0)
+    return (ConvertAlgaeError (status));
+  return (0);    
+}
+
+int AHChooseRandomGenerateBytes (handler, output, outputLen, surrenderContext)
+AHChooseRandom *handler;
+unsigned char *output;
+unsigned int outputLen;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+  
+  if ((status = (*((A_RANDOM_ALGA *)handler->algaChoice._alga)->Generate)
+       (handler->algaChoice.context.z.context, output, outputLen,
+        surrenderContext)) != 0)
+    return (ConvertAlgaeError (status));
+  return (0);    
+}
+
+static int InitRandomAlga
+  (algaChoice, keyInfo, algorithmMethod, surrenderContext)
+AlgaChoice *algaChoice;
+POINTER keyInfo;
+B_ALGORITHM_METHOD *algorithmMethod;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+  unsigned int contextSize;
+
+UNUSED_ARG (keyInfo)
+  if ((status = (*((A_RANDOM_ALGA *)algorithmMethod->alga)->Query)
+       (&contextSize, algaChoice->_algorithmInfo)) != 0)
+    return (ConvertAlgaeError (status));
+
+  if ((status = ResizeContextMakeNewContext
+       (&algaChoice->context, contextSize)) != 0)
+    return (status);
+
+  if ((status = (*((A_RANDOM_ALGA *)algorithmMethod->alga)->Init)
+       (algaChoice->context.z.context, algaChoice->_algorithmInfo,
+        surrenderContext)) != 0)
+    return (ConvertAlgaeError (status));
+
+  return (0);
+}
diff --git a/lib/bind/dnssafe/ahchrand.h b/lib/bind/dnssafe/ahchrand.h
new file mode 100644 (file)
index 0000000..51e0f98
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _AHCHRAND_H_
+#define _AHCHRAND_H_ 1
+
+#include "ahrandom.h"
+#include "algchoic.h"
+
+typedef struct AHChooseRandom {
+  AHRandom random;                                             /* base class */
+  AlgaChoice algaChoice;
+} AHChooseRandom;
+
+AHChooseRandom *AHChooseRandomConstructor2 PROTO_LIST
+  ((AHChooseRandom *, struct B_AlgorithmInfoType *, POINTER));
+void AHChooseRandomDestructor PROTO_LIST ((THIS_RANDOM *));
+
+int AHChooseRandomInit PROTO_LIST
+  ((THIS_RANDOM *, B_ALGORITHM_CHOOSER, A_SURRENDER_CTX *));
+int AHChooseRandomUpdate PROTO_LIST
+  ((THIS_RANDOM *, unsigned char *, unsigned int, A_SURRENDER_CTX *));
+int AHChooseRandomGenerateBytes PROTO_LIST
+  ((THIS_RANDOM *, unsigned char *, unsigned int, A_SURRENDER_CTX *));
+
+#endif
diff --git a/lib/bind/dnssafe/ahdigest.c b/lib/bind/dnssafe/ahdigest.c
new file mode 100644 (file)
index 0000000..c741163
--- /dev/null
@@ -0,0 +1,93 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "balg.h"
+#include "ahdigest.h"
+#include "port_after.h"
+
+static void TypedAHDigestDestructor PROTO_LIST ((B_TypeCheck *));
+
+void AHDigestConstructor (handler)
+AHDigest *handler;
+{
+  /* Construct base class, setting type tag. */
+  B_TYPE_CHECK_Constructor
+    (&handler->typeCheck, TypedAHDigestDestructor);
+
+  /* Don't set vTable since this is a pure virtual base class. */
+}
+
+int B_AlgorithmDigestInit
+  (algorithm, key, algorithmChooser, surrenderContext)
+B_Algorithm *algorithm;
+B_Key *key;
+B_ALGORITHM_CHOOSER algorithmChooser;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+
+  if ((status = B_AlgorithmCheckType
+       (algorithm, TypedAHDigestDestructor)) != 0)
+    return (status);
+
+  if ((status =
+       (*((AHDigest *)algorithm->z.handler)->vTable->DigestInit)
+       ((AHDigest *)algorithm->z.handler, key, algorithmChooser,
+        surrenderContext)) != 0)
+    return (status);
+
+  algorithm->z.initFlag = 1;
+  return (0);
+}
+
+int B_AlgorithmDigestUpdate (algorithm, partIn, partInLen, surrenderContext)
+B_Algorithm *algorithm;
+const unsigned char *partIn;
+unsigned int partInLen;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+
+  if ((status = B_AlgorithmCheckTypeAndInitFlag
+       (algorithm, TypedAHDigestDestructor)) != 0)
+    return (status);
+
+  return ((*((AHDigest *)algorithm->z.handler)->vTable->DigestUpdate)
+          ((AHDigest *)algorithm->z.handler, partIn, partInLen,
+           surrenderContext));
+}
+
+int B_AlgorithmDigestFinal
+  (algorithm, partOut, partOutLen, maxPartOutLen, surrenderContext)
+B_Algorithm *algorithm;
+unsigned char *partOut;
+unsigned int *partOutLen;
+unsigned int maxPartOutLen;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+
+  if ((status = B_AlgorithmCheckTypeAndInitFlag
+       (algorithm, TypedAHDigestDestructor)) != 0)
+    return (status);
+
+  return ((*((AHDigest *)algorithm->z.handler)->vTable->DigestFinal)
+          ((AHDigest *)algorithm->z.handler, partOut, partOutLen,
+           maxPartOutLen, surrenderContext));
+}
+
+static void TypedAHDigestDestructor (typeCheck)
+B_TypeCheck *typeCheck;
+{
+  (*((AHDigest *)typeCheck)->vTable->Destructor) ((AHDigest *)typeCheck);
+}
+
diff --git a/lib/bind/dnssafe/ahdigest.h b/lib/bind/dnssafe/ahdigest.h
new file mode 100644 (file)
index 0000000..fe0299a
--- /dev/null
@@ -0,0 +1,48 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _AHDIGEST_H_
+#define _AHDIGEST_H_ 1
+
+#include "btypechk.h"
+
+/* Use the THIS_DIGEST macro to define the type of object in the
+     virtual function prototype.  It defaults to the most base class, but
+     derived modules may define the macro to a more derived class before
+     including this header file.
+ */
+#ifndef THIS_DIGEST
+#define THIS_DIGEST struct AHDigest
+#endif
+
+struct AHDigest;
+
+typedef struct {
+  void (*Destructor) PROTO_LIST ((THIS_DIGEST *));
+  int (*DigestInit) PROTO_LIST
+    ((THIS_DIGEST *, B_Key *, B_ALGORITHM_CHOOSER, A_SURRENDER_CTX *));
+  int (*DigestUpdate) PROTO_LIST
+    ((THIS_DIGEST *, const unsigned char *, unsigned int, A_SURRENDER_CTX *));
+  int (*DigestFinal) PROTO_LIST
+    ((THIS_DIGEST *, unsigned char *, unsigned int *, unsigned int,
+      A_SURRENDER_CTX *));
+} AHDigestVTable;
+
+typedef struct AHDigest {
+  B_TypeCheck typeCheck;                                        /* inherited */
+  AHDigestVTable *vTable;                                    /* pure virtual */
+} AHDigest;
+
+/* The constructor does not set the vTable since this is a pure base class.
+ */
+void AHDigestConstructor PROTO_LIST ((AHDigest *));
+/* No destructor because it is pure virtual. Also, do not call destructor
+     for B_TypeCheck, since this will just re-invoke this virtual
+     destructor. */
+
+#endif
diff --git a/lib/bind/dnssafe/ahencryp.c b/lib/bind/dnssafe/ahencryp.c
new file mode 100644 (file)
index 0000000..acb8014
--- /dev/null
@@ -0,0 +1,171 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "balg.h"
+#include "ahencryp.h"
+#include "port_after.h"
+
+static void TypedAHEncryptDecryptDestructor PROTO_LIST ((B_TypeCheck *));
+
+void AHEncryptDecryptConstructor (handler)
+AHEncryptDecrypt *handler;
+{
+  /* Construct base class, setting type tag. */
+  B_TYPE_CHECK_Constructor
+    (&handler->typeCheck, TypedAHEncryptDecryptDestructor);
+
+  /* Don't set vTable since this is a pure virtual base class. */
+}
+
+int B_AlgorithmEncryptInit
+  (algorithm, key, algorithmChooser, surrenderContext)
+B_Algorithm *algorithm;
+B_Key *key;
+B_ALGORITHM_CHOOSER algorithmChooser;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+
+  if ((status = B_AlgorithmCheckType
+       (algorithm, TypedAHEncryptDecryptDestructor)) != 0)
+    return (status);
+
+  if ((status =
+       (*((AHEncryptDecrypt *)algorithm->z.handler)->vTable->EncryptInit)
+       ((AHEncryptDecrypt *)algorithm->z.handler, key, algorithmChooser,
+        surrenderContext)) != 0)
+    return (status);
+
+  algorithm->z.initFlag = 1;
+  return (0);
+}
+
+int B_AlgorithmDecryptInit
+  (algorithm, key, algorithmChooser, surrenderContext)
+B_Algorithm *algorithm;
+B_Key *key;
+B_ALGORITHM_CHOOSER algorithmChooser;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+
+  if ((status = B_AlgorithmCheckType
+       (algorithm, TypedAHEncryptDecryptDestructor)) != 0)
+    return (status);
+
+  if ((status =
+       (*((AHEncryptDecrypt *)algorithm->z.handler)->vTable->DecryptInit)
+       ((AHEncryptDecrypt *)algorithm->z.handler, key, algorithmChooser,
+        surrenderContext)) != 0)
+    return (status);
+
+  algorithm->z.initFlag = 1;
+  return (0);
+}
+
+int B_AlgorithmEncryptUpdate
+  (algorithm, partOut, partOutLen, maxPartOutLen, partIn, partInLen,
+   randomAlgorithm, surrenderContext)
+B_Algorithm *algorithm;
+unsigned char *partOut;
+unsigned int *partOutLen;
+unsigned int maxPartOutLen;
+unsigned char *partIn;
+unsigned int partInLen;
+B_Algorithm *randomAlgorithm;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+
+  if ((status = B_AlgorithmCheckTypeAndInitFlag
+       (algorithm, TypedAHEncryptDecryptDestructor)) != 0)
+    return (status);
+
+  return ((*((AHEncryptDecrypt *)algorithm->z.handler)->vTable->EncryptUpdate)
+          ((AHEncryptDecrypt *)algorithm->z.handler, partOut, partOutLen,
+           maxPartOutLen, partIn, partInLen, randomAlgorithm,
+           surrenderContext));
+}
+
+int B_AlgorithmDecryptUpdate
+  (algorithm, partOut, partOutLen, maxPartOutLen, partIn, partInLen,
+   randomAlgorithm, surrenderContext)
+B_Algorithm *algorithm;
+unsigned char *partOut;
+unsigned int *partOutLen;
+unsigned int maxPartOutLen;
+const unsigned char *partIn;
+unsigned int partInLen;
+B_Algorithm *randomAlgorithm;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+
+  if ((status = B_AlgorithmCheckTypeAndInitFlag
+       (algorithm, TypedAHEncryptDecryptDestructor)) != 0)
+    return (status);
+
+  return ((*((AHEncryptDecrypt *)algorithm->z.handler)->vTable->DecryptUpdate)
+          ((AHEncryptDecrypt *)algorithm->z.handler, partOut, partOutLen,
+           maxPartOutLen, partIn, partInLen, randomAlgorithm,
+           surrenderContext));
+}
+
+int B_AlgorithmEncryptFinal
+  (algorithm, partOut, partOutLen, maxPartOutLen, randomAlgorithm,
+   surrenderContext)
+B_Algorithm *algorithm;
+unsigned char *partOut;
+unsigned int *partOutLen;
+unsigned int maxPartOutLen;
+B_Algorithm *randomAlgorithm;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+
+  if ((status = B_AlgorithmCheckTypeAndInitFlag
+       (algorithm, TypedAHEncryptDecryptDestructor)) != 0)
+    return (status);
+
+  return ((*((AHEncryptDecrypt *)algorithm->z.handler)->vTable->EncryptFinal)
+          ((AHEncryptDecrypt *)algorithm->z.handler, partOut, partOutLen,
+           maxPartOutLen, randomAlgorithm, surrenderContext));
+}
+
+int B_AlgorithmDecryptFinal
+  (algorithm, partOut, partOutLen, maxPartOutLen, randomAlgorithm,
+   surrenderContext)
+B_Algorithm *algorithm;
+unsigned char *partOut;
+unsigned int *partOutLen;
+unsigned int maxPartOutLen;
+B_Algorithm *randomAlgorithm;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+
+  if ((status = B_AlgorithmCheckTypeAndInitFlag
+       (algorithm, TypedAHEncryptDecryptDestructor)) != 0)
+    return (status);
+
+  return ((*((AHEncryptDecrypt *)algorithm->z.handler)->vTable->DecryptFinal)
+          ((AHEncryptDecrypt *)algorithm->z.handler, partOut, partOutLen,
+           maxPartOutLen, randomAlgorithm, surrenderContext));
+}
+
+static void TypedAHEncryptDecryptDestructor (typeCheck)
+B_TypeCheck *typeCheck;
+{
+  (*((AHEncryptDecrypt *)typeCheck)->vTable->Destructor)
+    ((AHEncryptDecrypt *)typeCheck);
+}
+
diff --git a/lib/bind/dnssafe/ahencryp.h b/lib/bind/dnssafe/ahencryp.h
new file mode 100644 (file)
index 0000000..b02c514
--- /dev/null
@@ -0,0 +1,85 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _AHENCRYP_H_
+#define _AHENCRYP_H_ 1
+
+#include "btypechk.h"
+
+/* In C++:
+class AHEncryptDecrypt : public B_TypeCheck {
+  AHEncryptDecrypt ();
+  virtual ~AHEncryptDecrypt () = 0;
+  
+  virtual int getBlockLen (unsigned int *) = 0;
+  virtual int encryptInit
+    (B_Key *, B_ALGORITHM_CHOOSER, A_SURRENDER_CTX *) = 0;
+  virtual int decryptInit
+    (B_Key *, B_ALGORITHM_CHOOSER, A_SURRENDER_CTX *) = 0;
+  virtual int encryptUpdate
+    (unsigned char *, unsigned int *, unsigned int, unsigned char *,
+     unsigned int, B_Algorithm *, A_SURRENDER_CTX *) = 0;
+  virtual int decryptUpdate
+    (unsigned char *, unsigned int *, unsigned int, unsigned char *,
+     unsigned int, B_Algorithm *, A_SURRENDER_CTX *) = 0;
+  virtual int encryptFinal
+    (unsigned char *, unsigned int *, unsigned int, B_Algorithm *,
+     A_SURRENDER_CTX *) = 0;
+  virtual int decryptFinal
+    (unsigned char *, unsigned int *, unsigned int, B_Algorithm *,
+     A_SURRENDER_CTX *) = 0;
+};
+ */
+
+/* Use the THIS_ENCRYPT_DECRYPT macro to define the type of object in the
+     virtual function prototype.  It defaults to the most base class, but
+     derived modules may define the macro to a more derived class before
+     including this header file.
+ */
+#ifndef THIS_ENCRYPT_DECRYPT
+#define THIS_ENCRYPT_DECRYPT struct AHEncryptDecrypt
+#endif
+
+struct AHEncryptDecrypt;
+
+typedef struct {
+  void (*Destructor) PROTO_LIST ((THIS_ENCRYPT_DECRYPT *));
+  int (*GetBlockLen) PROTO_LIST ((THIS_ENCRYPT_DECRYPT *, unsigned int *));
+  int (*EncryptInit) PROTO_LIST
+    ((THIS_ENCRYPT_DECRYPT *, B_Key *, B_ALGORITHM_CHOOSER,
+      A_SURRENDER_CTX *));
+  int (*DecryptInit) PROTO_LIST
+    ((THIS_ENCRYPT_DECRYPT *, B_Key *, B_ALGORITHM_CHOOSER,
+      A_SURRENDER_CTX *));
+  int (*EncryptUpdate) PROTO_LIST
+    ((THIS_ENCRYPT_DECRYPT *, unsigned char *, unsigned int *, unsigned int,
+      const unsigned char *, unsigned int, B_Algorithm *, A_SURRENDER_CTX *));
+  int (*DecryptUpdate) PROTO_LIST
+    ((THIS_ENCRYPT_DECRYPT *, unsigned char *, unsigned int *, unsigned int,
+      const unsigned char *, unsigned int, B_Algorithm *, A_SURRENDER_CTX *));
+  int (*EncryptFinal) PROTO_LIST
+    ((THIS_ENCRYPT_DECRYPT *, unsigned char *, unsigned int *, unsigned int,
+      B_Algorithm *, A_SURRENDER_CTX *));
+  int (*DecryptFinal) PROTO_LIST
+    ((THIS_ENCRYPT_DECRYPT *, unsigned char *, unsigned int *, unsigned int,
+      B_Algorithm *, A_SURRENDER_CTX *));
+} AHEncryptDecryptVTable;
+
+typedef struct AHEncryptDecrypt {
+  B_TypeCheck typeCheck;                                        /* inherited */
+  AHEncryptDecryptVTable *vTable;                            /* pure virtual */
+} AHEncryptDecrypt;
+
+/* The constructor does not set the vTable since this is a pure base class.
+ */
+void AHEncryptDecryptConstructor PROTO_LIST ((AHEncryptDecrypt *));
+/* No destructor because it is pure virtual. Also, do not call destructor
+     for B_TypeCheck, since this will just re-invoke this virtual
+     destructor. */
+
+#endif
diff --git a/lib/bind/dnssafe/ahgen.c b/lib/bind/dnssafe/ahgen.c
new file mode 100644 (file)
index 0000000..518dc69
--- /dev/null
@@ -0,0 +1,92 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "balg.h"
+#include "ahgen.h"
+#include "port_after.h"
+
+static void TypedAHGenerateDestructor PROTO_LIST ((B_TypeCheck *));
+
+void AHGenerateConstructor (handler)
+AHGenerate *handler;
+{
+  /* Construct base class, setting type tag. */
+  B_TYPE_CHECK_Constructor
+    (&handler->typeCheck, TypedAHGenerateDestructor);
+
+  /* Don't set vTable since this is a pure virtual base class. */
+}
+
+int B_AlgorithmGenerateInit (algorithm, algorithmChooser, surrenderContext)
+B_Algorithm *algorithm;
+B_ALGORITHM_CHOOSER algorithmChooser;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+
+  if ((status = B_AlgorithmCheckType
+       (algorithm, TypedAHGenerateDestructor)) != 0)
+    return (status);
+
+  if ((status =
+       (*((AHGenerate *)algorithm->z.handler)->vTable->GenerateInit)
+       ((AHGenerate *)algorithm->z.handler, algorithmChooser,
+        surrenderContext)) != 0)
+    return (status);
+
+  algorithm->z.initFlag = 1;
+  return (0);
+}
+
+int B_AlgorithmGenerateKeypair
+  (algorithm, publicKey, privateKey, randomAlgorithm, surrenderContext)
+B_Algorithm *algorithm;
+B_Key *publicKey;
+B_Key *privateKey;
+B_Algorithm *randomAlgorithm;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+
+  if ((status = B_AlgorithmCheckTypeAndInitFlag
+       (algorithm, TypedAHGenerateDestructor)) != 0)
+    return (status);
+
+  return ((*((AHGenerate *)algorithm->z.handler)->vTable->GenerateKeypair)
+          ((AHGenerate *)algorithm->z.handler, publicKey, privateKey,
+           randomAlgorithm, surrenderContext));
+}
+
+int B_AlgorithmGenerateParameters
+  (algorithm, resultAlgorithm, randomAlgorithm, surrenderContext)
+B_Algorithm *algorithm;
+B_Algorithm *resultAlgorithm;
+B_Algorithm *randomAlgorithm;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+
+  if ((status = B_AlgorithmCheckTypeAndInitFlag
+       (algorithm, TypedAHGenerateDestructor)) != 0)
+    return (status);
+
+  return ((*((AHGenerate *)algorithm->z.handler)->vTable->GenerateParameters)
+          ((AHGenerate *)algorithm->z.handler, resultAlgorithm,
+           randomAlgorithm, surrenderContext));
+}
+
+static void TypedAHGenerateDestructor (typeCheck)
+B_TypeCheck *typeCheck;
+{
+  (*((AHGenerate *)typeCheck)->vTable->Destructor) ((AHGenerate *)typeCheck);
+}
+
diff --git a/lib/bind/dnssafe/ahgen.h b/lib/bind/dnssafe/ahgen.h
new file mode 100644 (file)
index 0000000..7240e2e
--- /dev/null
@@ -0,0 +1,47 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _AHGEN_H_
+#define _AHGEN_H_ 1
+
+#include "btypechk.h"
+
+/* Use the THIS_GENERATE macro to define the type of object in the
+     virtual function prototype.  It defaults to the most base class, but
+     derived modules may define the macro to a more derived class before
+     including this header file.
+ */
+#ifndef THIS_GENERATE
+#define THIS_GENERATE struct AHGenerate
+#endif
+
+struct AHGenerate;
+
+typedef struct {
+  void (*Destructor) PROTO_LIST ((THIS_GENERATE *));
+  int (*GenerateInit) PROTO_LIST
+    ((THIS_GENERATE *, B_ALGORITHM_CHOOSER, A_SURRENDER_CTX *));
+  int (*GenerateKeypair) PROTO_LIST
+    ((THIS_GENERATE *, B_Key *, B_Key *, B_Algorithm *, A_SURRENDER_CTX *));
+  int (*GenerateParameters) PROTO_LIST
+    ((THIS_GENERATE *, B_Algorithm *, B_Algorithm *, A_SURRENDER_CTX *));
+} AHGenerateVTable;
+
+typedef struct AHGenerate {
+  B_TypeCheck typeCheck;                                        /* inherited */
+  AHGenerateVTable *vTable;                                  /* pure virtual */
+} AHGenerate;
+
+/* The constructor does not set the vTable since this is a pure base class.
+ */
+void AHGenerateConstructor PROTO_LIST ((AHGenerate *));
+/* No destructor because it is pure virtual. Also, do not call destructor
+     for B_TypeCheck, since this will just re-invoke this virtual
+     destructor. */
+
+#endif
diff --git a/lib/bind/dnssafe/ahrandom.c b/lib/bind/dnssafe/ahrandom.c
new file mode 100644 (file)
index 0000000..304b14b
--- /dev/null
@@ -0,0 +1,99 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "balg.h"
+#include "ahrandom.h"
+#include "port_after.h"
+
+static void TypedAHRandomDestructor PROTO_LIST ((B_TypeCheck *));
+
+void AHRandomConstructor (handler)
+AHRandom *handler;
+{
+  /* Construct base class, setting type tag. */
+  B_TYPE_CHECK_Constructor
+    (&handler->typeCheck, TypedAHRandomDestructor);
+
+  /* Don't set vTable since this is a pure virtual base class. */
+}
+
+int B_AlgorithmRandomInit (algorithm, algorithmChooser, surrenderContext)
+B_Algorithm *algorithm;
+B_ALGORITHM_CHOOSER algorithmChooser;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+
+  if ((status = B_AlgorithmCheckType (algorithm, TypedAHRandomDestructor))
+      != 0)
+    return (status);
+
+  if ((status =
+       (*((AHRandom *)algorithm->z.handler)->vTable->RandomInit)
+       ((AHRandom *)algorithm->z.handler, algorithmChooser, surrenderContext))
+      != 0)
+    return (status);
+
+  algorithm->z.initFlag = 1;
+  return (0);
+}
+
+int B_AlgorithmRandomUpdate (algorithm, input, inputLen, surrenderContext)
+B_Algorithm *algorithm;
+unsigned char *input;
+unsigned int inputLen;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+
+  if ((status = B_AlgorithmCheckTypeAndInitFlag
+       (algorithm, TypedAHRandomDestructor)) != 0)
+    return (status == BE_ALGORITHM_NOT_INITIALIZED ?
+            BE_RANDOM_NOT_INITIALIZED : status);
+
+  return ((*((AHRandom *)algorithm->z.handler)->vTable->RandomUpdate)
+          ((AHRandom *)algorithm->z.handler, input, inputLen,
+           surrenderContext));
+}
+
+int B_AlgorithmGenerateRandomBytes
+  (algorithm, output, outputLen, surrenderContext)
+B_Algorithm *algorithm;
+unsigned char *output;
+unsigned int outputLen;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+
+  /* As a special case, check here for a null this pointer when the object
+       is actually being used since many routines take a "dummy" null
+       random algorithm.
+   */
+  if (algorithm == (B_Algorithm *)NULL_PTR)
+    return (BE_RANDOM_OBJ);
+
+  if ((status = B_AlgorithmCheckTypeAndInitFlag
+       (algorithm, TypedAHRandomDestructor)) != 0)
+    return (status == BE_ALGORITHM_NOT_INITIALIZED ?
+            BE_RANDOM_NOT_INITIALIZED : status);
+
+  return ((*((AHRandom *)algorithm->z.handler)->vTable->GenerateBytes)
+          ((AHRandom *)algorithm->z.handler, output, outputLen,
+           surrenderContext));
+}
+
+static void TypedAHRandomDestructor (typeCheck)
+B_TypeCheck *typeCheck;
+{
+  (*((AHRandom *)typeCheck)->vTable->Destructor) ((AHRandom *)typeCheck);
+}
+
diff --git a/lib/bind/dnssafe/ahrandom.h b/lib/bind/dnssafe/ahrandom.h
new file mode 100644 (file)
index 0000000..aeb4f3b
--- /dev/null
@@ -0,0 +1,47 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _AHRANDOM_H_
+#define _AHRANDOM_H_ 1
+
+#include "btypechk.h"
+
+/* Use the THIS_RANDOM macro to define the type of object in the
+     virtual function prototype.  It defaults to the most base class, but
+     derived modules may define the macro to a more derived class before
+     including this header file.
+ */
+#ifndef THIS_RANDOM
+#define THIS_RANDOM struct AHRandom
+#endif
+
+struct AHRandom;
+
+typedef struct {
+  void (*Destructor) PROTO_LIST ((THIS_RANDOM *));
+  int (*RandomInit) PROTO_LIST
+    ((THIS_RANDOM *, B_ALGORITHM_CHOOSER, A_SURRENDER_CTX *));
+  int (*RandomUpdate) PROTO_LIST
+    ((THIS_RANDOM *, unsigned char *, unsigned int, A_SURRENDER_CTX *));
+  int (*GenerateBytes) PROTO_LIST
+    ((THIS_RANDOM *, unsigned char *, unsigned int, A_SURRENDER_CTX *));
+} AHRandomVTable;
+
+typedef struct AHRandom {
+  B_TypeCheck typeCheck;                                        /* inherited */
+  AHRandomVTable *vTable;                                    /* pure virtual */
+} AHRandom;
+
+/* The constructor does not set the vTable since this is a pure base class.
+ */
+void AHRandomConstructor PROTO_LIST ((AHRandom *));
+/* No destructor because it is pure virtual. Also, do not call destructor
+     for B_TypeCheck, since this will just re-invoke this virtual
+     destructor. */
+
+#endif
diff --git a/lib/bind/dnssafe/ahrsaenc.c b/lib/bind/dnssafe/ahrsaenc.c
new file mode 100644 (file)
index 0000000..c345d91
--- /dev/null
@@ -0,0 +1,244 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+/* Define this so that the type of the 'this' pointer in the
+     virtual functions will be correct for this derived class.
+ */
+struct AH_RSAEncryption;
+#define THIS_ENCRYPT_DECRYPT struct AH_RSAEncryption
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "balg.h"
+#include "ahrsaenc.h"
+#include "port_after.h"
+
+static int AH_RSAEncryptionInitHelper PROTO_LIST ((AH_RSAEncryption *, int));
+
+static AHEncryptDecryptVTable V_TABLE = {
+  AH_RSAEncryptionDestructor, AH_RSAEncryptionGetBlockLen,
+  AH_RSAEncryptionEncryptInit, AH_RSAEncryptionDecryptInit,
+  AH_RSAEncryptionUpdate,
+  AH_RSAEncryptionUpdate,
+  AH_RSAEncryptionEncryptFinal, AH_RSAEncryptionDecryptFinal
+};
+
+void AH_RSAEncryptionConstructor1 (handler, infoType)
+AH_RSAEncryption *handler;
+struct B_AlgorithmInfoType *infoType;
+{
+  /* Construct base class with the infoType.  Assume info is NULL_PTR. */
+  AHChooseEncryptConstructor2
+    (&handler->chooseEncryptDecrypt, infoType, NULL_PTR);
+
+  T_memset ((POINTER)&handler->z, 0, sizeof (handler->z));
+  /* Set the AHEncryptDecrypt vTable, but don't set the RSAEncryption vTable
+      since it is pure virtual. */
+  handler->chooseEncryptDecrypt.encryptDecrypt.vTable = &V_TABLE;
+}
+
+void AH_RSAEncryptionDestructor (handler)
+AH_RSAEncryption *handler;
+{
+  T_memset ((POINTER)handler->z.block, 0, handler->z.blockLen);
+  T_free ((POINTER)handler->z.block);
+
+  /* Call base class destructor */
+  AHChooseEncryptDestructor (handler);
+}
+
+int AH_RSAEncryptionGetBlockLen (handler, blockLen)
+AH_RSAEncryption *handler;
+unsigned int *blockLen;
+{
+UNUSED_ARG (handler)
+UNUSED_ARG (blockLen)
+  return (BE_NOT_SUPPORTED);
+}
+
+int AH_RSAEncryptionEncryptInit (handler, key, chooser, surrenderContext)
+AH_RSAEncryption *handler;
+B_Key *key;
+B_ALGORITHM_CHOOSER chooser;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+
+  if ((status = AHChooseEncryptEncryptInit
+       (handler, key, chooser, surrenderContext)) != 0)
+    return (status);
+
+  return (AH_RSAEncryptionInitHelper (handler, 1));
+}
+
+int AH_RSAEncryptionDecryptInit (handler, key, chooser, surrenderContext)
+AH_RSAEncryption *handler;
+B_Key *key;
+B_ALGORITHM_CHOOSER chooser;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+
+  if ((status = AHChooseEncryptDecryptInit
+       (handler, key, chooser, surrenderContext)) != 0)
+    return (status);
+
+  return (AH_RSAEncryptionInitHelper (handler, 0));
+}
+
+/* Accumulate into the z.block.
+ */
+int AH_RSAEncryptionUpdate
+  (handler, partOut, partOutLen, maxPartOutLen, partIn, partInLen,
+   randomAlgorithm, surrenderContext)
+AH_RSAEncryption *handler;
+unsigned char *partOut;
+unsigned int *partOutLen;
+unsigned int maxPartOutLen;
+const unsigned char *partIn;
+unsigned int partInLen;
+B_Algorithm *randomAlgorithm;
+A_SURRENDER_CTX *surrenderContext;
+{
+UNUSED_ARG (partOut)
+UNUSED_ARG (maxPartOutLen)
+UNUSED_ARG (randomAlgorithm)
+UNUSED_ARG (surrenderContext)
+  *partOutLen = 0;
+    
+  if (handler->_inputLen + partInLen > handler->_maxInputLen)
+    return (BE_INPUT_LEN);
+  T_memcpy
+    ((POINTER)(handler->z.block + handler->_inputLen), (CPOINTER)partIn,
+     partInLen);
+  handler->_inputLen += partInLen;
+  return (0);
+}
+
+int AH_RSAEncryptionEncryptFinal
+  (handler, partOut, partOutLen, maxPartOutLen, randomAlgorithm,
+   surrenderContext)
+AH_RSAEncryption *handler;
+unsigned char *partOut;
+unsigned int *partOutLen;
+unsigned int maxPartOutLen;
+B_Algorithm *randomAlgorithm;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+  unsigned int dummyPartOutLen;
+  
+  /* Encode methodContext in place. */
+  if ((status = (*handler->vTable->EncodeBlock)
+       (handler, randomAlgorithm, surrenderContext)) != 0)
+    return (status);
+
+  /* This should not return BE_INPUT_DATA since it is well-formatted. */
+  if ((status = AHChooseEncryptEncryptUpdate
+       (handler, partOut, partOutLen, maxPartOutLen, handler->z.block,
+        handler->z.blockLen, (B_Algorithm *)NULL_PTR, surrenderContext)) != 0)
+    return (status);
+
+  /* Expect final to return zero bytes. */
+  if ((status = AHChooseEncryptEncryptFinal
+       (handler, (unsigned char *)NULL_PTR, &dummyPartOutLen, 0,
+        (B_Algorithm *)NULL_PTR, surrenderContext)) != 0)
+    return (status);
+    
+  /* Restart the handle for new input. */
+  handler->_inputLen = 0;
+  return (0);
+}
+
+int AH_RSAEncryptionDecryptFinal
+  (handler, partOut, partOutLen, maxPartOutLen, randomAlgorithm,
+   surrenderContext)
+AH_RSAEncryption *handler;
+unsigned char *partOut;
+unsigned int *partOutLen;
+unsigned int maxPartOutLen;
+B_Algorithm *randomAlgorithm;
+A_SURRENDER_CTX *surrenderContext;
+{
+  ITEM output;
+  int status;
+  unsigned int decryptedLen, dummyPartOutLen;
+  
+UNUSED_ARG (randomAlgorithm)
+  /* Decrypt block in place.  The block lenghts are already within limits.
+   */
+  if ((status = AHChooseEncryptDecryptUpdate
+       (handler, handler->z.block, &decryptedLen, handler->z.blockLen,
+        handler->z.block, handler->_inputLen, (B_Algorithm *)NULL_PTR,
+        surrenderContext)) != 0)
+    return (status);
+  /* Expect final to return zero bytes. */
+  if ((status = AHChooseEncryptDecryptFinal
+       (handler, (unsigned char *)NULL_PTR, &dummyPartOutLen, 0,
+        (B_Algorithm *)NULL_PTR, surrenderContext)) != 0)
+    return (status);
+    
+  /* Restart the handle for new input. */
+  handler->_inputLen = 0;
+      
+  /* Now decode the block and copy the result to the partOut.
+   */
+  if ((status = (*handler->vTable->DecodeBlock)
+       (handler, &output, decryptedLen)) != 0)
+    return (status);
+      
+  if (output.len > handler->z.blockLen - 11)
+    /* This implies that the block was encrypted with less than
+       8 bytes of padding */
+    return (BE_INPUT_DATA);
+      
+  if ((*partOutLen = output.len) > maxPartOutLen)
+    return (BE_OUTPUT_LEN);      
+  T_memcpy ((POINTER)partOut, (POINTER)output.data, output.len);
+
+  return (0);
+}
+
+static int AH_RSAEncryptionInitHelper (handler, encryptFlag)
+AH_RSAEncryption *handler;
+int encryptFlag;
+{
+  int status;
+  unsigned int newBlockLen;
+
+  if ((status = AHChooseEncryptGetBlockLen (handler, &newBlockLen)) != 0)
+    return (status);
+
+  if (newBlockLen < 12)
+    /* PKCS Requires at least 12 bytes of modulus */
+    return (BE_NOT_SUPPORTED);
+
+  /* During encrypt, this will ensure that there are 8 bytes of padding.
+     During decrypt, the DecodeBlock procedure must check that the block
+       was encrypted with 8 bytes of padding.
+   */
+  handler->_maxInputLen = encryptFlag ? (newBlockLen - 11) : newBlockLen;
+
+  handler->_inputLen = 0;
+  
+  /* Zeroize old block and realloc to new size.
+   */
+  T_memset ((POINTER)handler->z.block, 0, handler->z.blockLen);
+  if ((handler->z.block = (unsigned char *)T_realloc
+       ((POINTER)handler->z.block, newBlockLen))
+      == (unsigned char *)NULL_PTR) {
+    handler->z.blockLen = 0;
+    return (BE_ALLOC);
+  }
+  
+  handler->z.blockLen = newBlockLen;
+  return (0);
+}
+
diff --git a/lib/bind/dnssafe/ahrsaenc.h b/lib/bind/dnssafe/ahrsaenc.h
new file mode 100644 (file)
index 0000000..5abb1e3
--- /dev/null
@@ -0,0 +1,68 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _AHRSAENC_H_
+#define _AHRSAENC_H_
+
+#include "ahchencr.h"
+
+struct AH_RSAEncryption;
+
+/* For EncodeBlock, the block to encode is left justified in the
+     z.block with length given by z._inputLen.  EncodeBlock encodes the block
+     in place to fill it out to z.blockLen.
+   For DecodeBlock, return the contents in the given ITEM by decoding
+     the z.block value which has length given by decryptedLen.  This
+     procedure must also ensure that the block was encrypted with 8 bytes
+     of padding.
+ */
+typedef struct {
+  int (*EncodeBlock) PROTO_LIST
+    ((THIS_ENCRYPT_DECRYPT *, B_Algorithm * /* randomAlgorithm */,
+      A_SURRENDER_CTX *));
+  int (*DecodeBlock) PROTO_LIST
+    ((THIS_ENCRYPT_DECRYPT *, ITEM *, unsigned int /* decryptedLen */));
+} AH_RSAEncryptionVTable;
+
+typedef struct AH_RSAEncryption {
+  AHChooseEncryptDecrypt chooseEncryptDecrypt;                 /* base class */
+
+  struct {
+    unsigned char *block;
+    unsigned int blockLen;
+  } z;                                            /* Zeroized by constructor */
+
+  unsigned int _inputLen;            /* Length of data accumulated by Update */
+  unsigned int _maxInputLen;     /* used during update to check for overflow */
+  AH_RSAEncryptionVTable *vTable;                            /* pure virtual */
+} AH_RSAEncryption;
+
+void AH_RSAEncryptionConstructor1 PROTO_LIST
+  ((AH_RSAEncryption *, struct B_AlgorithmInfoType *));
+void AH_RSAEncryptionDestructor PROTO_LIST ((AH_RSAEncryption *));
+
+int AH_RSAEncryptionGetBlockLen PROTO_LIST
+  ((THIS_ENCRYPT_DECRYPT *, unsigned int *));
+int AH_RSAEncryptionEncryptInit PROTO_LIST
+  ((THIS_ENCRYPT_DECRYPT *, B_Key *, B_ALGORITHM_CHOOSER,
+    A_SURRENDER_CTX *));
+int AH_RSAEncryptionDecryptInit PROTO_LIST
+  ((THIS_ENCRYPT_DECRYPT *, B_Key *, B_ALGORITHM_CHOOSER,
+    A_SURRENDER_CTX *));
+int AH_RSAEncryptionUpdate PROTO_LIST
+  ((THIS_ENCRYPT_DECRYPT *, unsigned char *, unsigned int *,
+    unsigned int, const unsigned char *, unsigned int, B_Algorithm *,
+    A_SURRENDER_CTX *));
+int AH_RSAEncryptionEncryptFinal PROTO_LIST
+  ((THIS_ENCRYPT_DECRYPT *, unsigned char *, unsigned int *,
+    unsigned int, B_Algorithm *, A_SURRENDER_CTX *));
+int AH_RSAEncryptionDecryptFinal PROTO_LIST
+  ((THIS_ENCRYPT_DECRYPT *, unsigned char *, unsigned int *,
+    unsigned int, B_Algorithm *, A_SURRENDER_CTX *));
+
+#endif
diff --git a/lib/bind/dnssafe/ahrsaepr.c b/lib/bind/dnssafe/ahrsaepr.c
new file mode 100644 (file)
index 0000000..3105868
--- /dev/null
@@ -0,0 +1,101 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+/* Define this so that the type of the 'this' pointer in the
+     virtual functions will be correct for this derived class.
+ */
+struct AH_RSAEncryption;
+#define THIS_ENCRYPT_DECRYPT struct AH_RSAEncryption
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "balg.h"
+#include "ahrsaepr.h"
+#include "port_after.h"
+
+static int EncodeBlock1 PROTO_LIST
+  ((AH_RSAEncryptionPrivate *, B_Algorithm *, A_SURRENDER_CTX *));
+static int DecodeBlock2 PROTO_LIST
+  ((AH_RSAEncryptionPrivate *, ITEM *, unsigned int));
+
+static AH_RSAEncryptionVTable ENCRYPTION_V_TABLE =
+  {EncodeBlock1, DecodeBlock2};
+
+extern struct B_AlgorithmInfoType AIT_RSAPrivate;
+
+AH_RSAEncryptionPrivate *AH_RSAEncrypPrivateConstructor (handler)
+AH_RSAEncryptionPrivate *handler;
+{
+  if (handler == (AH_RSAEncryptionPrivate *)NULL_PTR) {
+    /* This constructor is being used to do a new */
+    if ((handler = (AH_RSAEncryptionPrivate *)T_malloc (sizeof (*handler)))
+        == (AH_RSAEncryptionPrivate *)NULL_PTR)
+      return (handler);
+  }
+
+  /* Construct base class */
+  AH_RSAEncryptionConstructor1 (handler, &AIT_RSAPrivate);
+  
+  handler->vTable = &ENCRYPTION_V_TABLE;
+  return (handler);
+}
+
+/* block1 starts out with the input bytes of length inputLen left-justified.
+   Returns 0, BE_INPUT_LEN.
+ */
+static int EncodeBlock1 (handler, randomAlgorithm, surrenderContext)
+AH_RSAEncryptionPrivate *handler;
+B_Algorithm *randomAlgorithm;
+A_SURRENDER_CTX *surrenderContext;
+{
+  unsigned int padLen;
+
+UNUSED_ARG (randomAlgorithm)
+UNUSED_ARG (surrenderContext)
+  if ((handler->_inputLen + 3) > handler->z.blockLen)
+    /* input is too large to make a block 1 */
+    return (BE_INPUT_LEN);
+
+  padLen = handler->z.blockLen - (handler->_inputLen + 3);
+  T_memmove
+    ((POINTER)(handler->z.block + padLen + 3), (POINTER)handler->z.block,
+     handler->_inputLen);
+
+  handler->z.block[0] = 0;
+  handler->z.block[1] = 1;
+  T_memset ((POINTER)(handler->z.block + 2), 0xff, padLen);
+  handler->z.block[2 + padLen] = 0;
+  return (0);
+}
+
+static int DecodeBlock2 (handler, output, block2Len)
+AH_RSAEncryptionPrivate *handler;
+ITEM *output;
+unsigned int block2Len;
+{
+  unsigned int i;
+  
+  if ((handler->z.block[0] != 0) || (handler->z.block[1] != 2))
+    return (BE_INPUT_DATA);
+    
+  /* Should be able to find the data after the first zero byte following
+       the random bytes. */
+  for (i = 2; i < block2Len && handler->z.block[i] != 0; i++);
+  i++;
+    
+  if (i > block2Len)
+    /* The data is not zero terminated. */
+    return (BE_INPUT_DATA);
+    
+  output->len = block2Len - i;
+  output->data = handler->z.block + i;
+  return (0);
+}
+
diff --git a/lib/bind/dnssafe/ahrsaepr.h b/lib/bind/dnssafe/ahrsaepr.h
new file mode 100644 (file)
index 0000000..f5847bc
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _AHRSAEPR_H_
+#define _AHRSAEPR_H_
+
+#include "ahrsaenc.h"
+
+/* structure is identical to base class, so just re-typedef. */
+typedef AH_RSAEncryption AH_RSAEncryptionPrivate;
+
+AH_RSAEncryptionPrivate *AH_RSAEncrypPrivateConstructor PROTO_LIST
+  ((AH_RSAEncryptionPrivate *));
+
+#endif
diff --git a/lib/bind/dnssafe/ahrsaepu.c b/lib/bind/dnssafe/ahrsaepu.c
new file mode 100644 (file)
index 0000000..b290d5a
--- /dev/null
@@ -0,0 +1,114 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+/* Define this so that the type of the 'this' pointer in the
+     virtual functions will be correct for this derived class.
+ */
+struct AH_RSAEncryption;
+#define THIS_ENCRYPT_DECRYPT struct AH_RSAEncryption
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "balg.h"
+#include "ahrsaepu.h"
+#include "port_after.h"
+
+static int EncodeBlock2 PROTO_LIST
+  ((AH_RSAEncryptionPublic *, B_Algorithm *, A_SURRENDER_CTX *));
+static int DecodeBlock1 PROTO_LIST
+  ((AH_RSAEncryptionPublic *, ITEM *, unsigned int));
+
+static AH_RSAEncryptionVTable ENCRYPTION_V_TABLE =
+  {EncodeBlock2, DecodeBlock1};
+
+extern struct B_AlgorithmInfoType AIT_RSAPublic;
+
+AH_RSAEncryptionPublic *AH_RSAEncrypPublicConstructor (handler)
+AH_RSAEncryptionPublic *handler;
+{
+  if (handler == (AH_RSAEncryptionPublic *)NULL_PTR) {
+    /* This constructor is being used to do a new */
+    if ((handler = (AH_RSAEncryptionPublic *)T_malloc (sizeof (*handler)))
+        == (AH_RSAEncryptionPublic *)NULL_PTR)
+      return (handler);
+  }
+
+  /* Construct base class */
+  AH_RSAEncryptionConstructor1 (handler, &AIT_RSAPublic);
+  
+  handler->vTable = &ENCRYPTION_V_TABLE;
+  return (handler);
+}
+
+/* block starts out with the input bytes of length inputLen left-justified.
+ */
+static int EncodeBlock2 (handler, randomAlgorithm, surrenderContext)
+AH_RSAEncryptionPublic *handler;
+B_Algorithm *randomAlgorithm;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+  unsigned char randomByte;
+  unsigned int padLen, i;
+
+  if ((handler->_inputLen + 3) > handler->z.blockLen)
+    /* input is too large to make a block 2 */
+    return (BE_INPUT_LEN);
+
+  padLen = handler->z.blockLen - (handler->_inputLen + 3);
+  T_memmove
+    ((POINTER)(handler->z.block + padLen + 3), (POINTER)handler->z.block,
+     handler->_inputLen);
+
+  handler->z.block[0] = 0;
+  handler->z.block[1] = 2;
+
+  /* Pad out with random bytes, making sure that none of the bytes is zero.
+   */
+  for (i = 2; i < (padLen + 2); i++) {
+    do {
+      if ((status = B_AlgorithmGenerateRandomBytes
+           (randomAlgorithm, &randomByte, 1, surrenderContext)) != 0)
+        return (status);
+    } while (randomByte == 0);
+    
+    handler->z.block[i] = randomByte;
+  }
+  
+  handler->z.block[2 + padLen] = 0;
+  return (0);
+}
+
+static int DecodeBlock1 (handler, output, block1Len)
+AH_RSAEncryptionPublic *handler;
+ITEM *output;
+unsigned int block1Len;
+{
+  unsigned int i;
+  
+  /* Locate the digestInfo within the PKCS block 1.
+   */
+  if (handler->z.block[0] != 0 || handler->z.block[1] != 1)
+    return (BE_INPUT_DATA);
+    
+  /* Should be able to find the data after the first zero byte following
+       the 0xff. */
+  for (i = 2; i < block1Len && handler->z.block[i] == 0xff; i++);
+  i++;
+    
+  if (i > block1Len || handler->z.block[i - 1] != 0)
+    /* The data is not zero terminated, or a byte other than 0xff. */
+    return (BE_INPUT_DATA);
+
+  output->len = block1Len - i;
+  output->data = handler->z.block + i;
+  return (0);
+}
+
diff --git a/lib/bind/dnssafe/ahrsaepu.h b/lib/bind/dnssafe/ahrsaepu.h
new file mode 100644 (file)
index 0000000..0c13e20
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _AHRSAEPU_H_
+#define _AHRSAEPU_H_
+
+#include "ahrsaenc.h"
+
+/* structure is identical to base class, so just re-typedef. */
+typedef AH_RSAEncryption AH_RSAEncryptionPublic;
+
+AH_RSAEncryptionPublic *AH_RSAEncrypPublicConstructor PROTO_LIST
+  ((AH_RSAEncryptionPublic *));
+
+#endif
diff --git a/lib/bind/dnssafe/aichdig.c b/lib/bind/dnssafe/aichdig.c
new file mode 100644 (file)
index 0000000..d0bc944
--- /dev/null
@@ -0,0 +1,38 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "balg.h"
+#include "ahchdig.h"
+#include "aichdig.h"
+#include "port_after.h"
+
+B_TypeCheck *AITChooseDigestNullNewHandler PROTO_LIST
+  ((B_AlgorithmInfoType *, B_Algorithm *));
+
+B_AlgorithmInfoTypeVTable AITChooseDigestNull_V_TABLE =
+  {AITNullAddInfo, AITChooseDigestNullNewHandler,
+   B_AlgorithmInfoTypeMakeError};
+
+/* This always uses NULL_PTR for the info.
+ */
+B_TypeCheck *AITChooseDigestNullNewHandler (infoType, algorithm)
+B_AlgorithmInfoType *infoType;
+B_Algorithm *algorithm;
+{
+UNUSED_ARG (algorithm)
+
+  /* Pass in NULL_PTR so that constructor will allocate.
+   */
+  return ((B_TypeCheck *)AHChooseDigestConstructor2
+          ((AHChooseDigest *)NULL_PTR, infoType, NULL_PTR));
+}
+
diff --git a/lib/bind/dnssafe/aichdig.h b/lib/bind/dnssafe/aichdig.h
new file mode 100644 (file)
index 0000000..e8228d9
--- /dev/null
@@ -0,0 +1,17 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _AICHDIG_H_
+#define _AICHDIG_H_ 1
+
+#include "ainfotyp.h"
+#include "ainull.h"
+
+extern B_AlgorithmInfoTypeVTable AITChooseDigestNull_V_TABLE;
+
+#endif
diff --git a/lib/bind/dnssafe/aichenc8.c b/lib/bind/dnssafe/aichenc8.c
new file mode 100644 (file)
index 0000000..595812a
--- /dev/null
@@ -0,0 +1,35 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "balg.h"
+#include "aichenc8.h"
+#include "port_after.h"
+
+B_AlgorithmInfoTypeVTable AITChooseEncrypt8_V_TABLE =
+  {AIT_8AddInfo, AITChooseEncryptNewHandler, B_AlgorithmInfoTypeMakeError};
+
+int AIT_8AddInfo (infoType, algorithm, info)
+B_AlgorithmInfoType *infoType;
+B_Algorithm *algorithm;
+POINTER info;
+{
+  POINTER newInfo;
+  int status;
+  
+  if ((status = B_MemoryPoolAllocAndCopy
+       (&algorithm->infoCache.memoryPool, &newInfo, info, 8)) != 0)
+    return (status);
+  
+  return (B_InfoCacheAddInfo
+          (&algorithm->infoCache, (POINTER)infoType, newInfo));
+}
+
diff --git a/lib/bind/dnssafe/aichenc8.h b/lib/bind/dnssafe/aichenc8.h
new file mode 100644 (file)
index 0000000..4c2096b
--- /dev/null
@@ -0,0 +1,19 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _AICHENC8_H_
+#define _AICHENC8_H_ 1
+
+#include "aichencr.h"
+
+extern B_AlgorithmInfoTypeVTable AITChooseEncrypt8_V_TABLE;
+
+int AIT_8AddInfo PROTO_LIST
+  ((THIS_ALGORITHM_INFO_TYPE *, B_Algorithm *, POINTER));
+
+#endif
diff --git a/lib/bind/dnssafe/aichencn.c b/lib/bind/dnssafe/aichencn.c
new file mode 100644 (file)
index 0000000..40e71df
--- /dev/null
@@ -0,0 +1,19 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "balg.h"
+#include "aichencn.h"
+#include "port_after.h"
+
+B_AlgorithmInfoTypeVTable AITChooseEncryptNull_V_TABLE =
+  {AITNullAddInfo, AITChooseEncryptNewHandler, B_AlgorithmInfoTypeMakeError};
+
diff --git a/lib/bind/dnssafe/aichencn.h b/lib/bind/dnssafe/aichencn.h
new file mode 100644 (file)
index 0000000..1130157
--- /dev/null
@@ -0,0 +1,17 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _AICHENCN_H_
+#define _AICHENCN_H_ 1
+
+#include "aichencr.h"
+#include "ainull.h"
+
+extern B_AlgorithmInfoTypeVTable AITChooseEncryptNull_V_TABLE;
+
+#endif
diff --git a/lib/bind/dnssafe/aichencr.c b/lib/bind/dnssafe/aichencr.c
new file mode 100644 (file)
index 0000000..bc13242
--- /dev/null
@@ -0,0 +1,33 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "balg.h"
+#include "ahchencr.h"
+#include "aichencr.h"
+#include "port_after.h"
+
+B_TypeCheck *AITChooseEncryptNewHandler (infoType, algorithm)
+B_AlgorithmInfoType *infoType;
+B_Algorithm *algorithm;
+{
+  POINTER info;
+
+  if (B_InfoCacheFindInfo (&algorithm->infoCache, &info, (POINTER)infoType)
+      != 0)
+    /* This really shouldn't happen since the info was just added. */
+    return ((B_TypeCheck *)NULL_PTR);
+
+  /* Pass in NULL_PTR so that constructor will allocate. */
+  return ((B_TypeCheck *)AHChooseEncryptConstructor2
+          ((AHChooseEncryptDecrypt *)NULL_PTR, infoType, info));
+}
+
diff --git a/lib/bind/dnssafe/aichencr.h b/lib/bind/dnssafe/aichencr.h
new file mode 100644 (file)
index 0000000..2d99bfb
--- /dev/null
@@ -0,0 +1,17 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _AICHENCR_H_
+#define _AICHENCR_H_ 1
+
+#include "ainfotyp.h"
+
+struct B_TypeCheck *AITChooseEncryptNewHandler PROTO_LIST
+  ((B_AlgorithmInfoType *, B_Algorithm *));
+
+#endif
diff --git a/lib/bind/dnssafe/aichgen.c b/lib/bind/dnssafe/aichgen.c
new file mode 100644 (file)
index 0000000..66bd4c3
--- /dev/null
@@ -0,0 +1,33 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "balg.h"
+#include "ahchgen.h"
+#include "aichgen.h"
+#include "port_after.h"
+
+B_TypeCheck *AITChooseGenerateNewHandler (infoType, algorithm)
+B_AlgorithmInfoType *infoType;
+B_Algorithm *algorithm;
+{
+  POINTER info;
+
+  if (B_InfoCacheFindInfo (&algorithm->infoCache, &info, (POINTER)infoType)
+      != 0)
+    /* This really shouldn't happen since the info was just added. */
+    return ((B_TypeCheck *)NULL_PTR);
+
+  /* Pass in NULL_PTR so that constructor will allocate. */
+  return ((B_TypeCheck *)AHChooseGenerateConstructor2
+          ((AHChooseGenerate *)NULL_PTR, infoType, info));
+}
+
diff --git a/lib/bind/dnssafe/aichgen.h b/lib/bind/dnssafe/aichgen.h
new file mode 100644 (file)
index 0000000..eebd9b7
--- /dev/null
@@ -0,0 +1,17 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _AICHGEN_H_
+#define _AICHGEN_H_ 1
+
+#include "ainfotyp.h"
+
+struct B_TypeCheck *AITChooseGenerateNewHandler PROTO_LIST
+  ((B_AlgorithmInfoType *, B_Algorithm *));
+
+#endif
diff --git a/lib/bind/dnssafe/aichrand.c b/lib/bind/dnssafe/aichrand.c
new file mode 100644 (file)
index 0000000..8f4ec72
--- /dev/null
@@ -0,0 +1,38 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "balg.h"
+#include "ahchrand.h"
+#include "aichrand.h"
+#include "port_after.h"
+
+B_TypeCheck *AITChooseRandomNullNewHandler PROTO_LIST
+  ((B_AlgorithmInfoType *, B_Algorithm *));
+
+B_AlgorithmInfoTypeVTable AITChooseRandomNull_V_TABLE =
+  {AITNullAddInfo, AITChooseRandomNullNewHandler,
+   B_AlgorithmInfoTypeMakeError};
+
+/* This always uses NULL_PTR for the info.
+ */
+B_TypeCheck *AITChooseRandomNullNewHandler (infoType, algorithm)
+B_AlgorithmInfoType *infoType;
+B_Algorithm *algorithm;
+{
+UNUSED_ARG (algorithm)
+
+  /* Pass in NULL_PTR so that constructor will allocate.
+   */
+  return ((B_TypeCheck *)AHChooseRandomConstructor2
+          ((AHChooseRandom *)NULL_PTR, infoType, NULL_PTR));
+}
+
diff --git a/lib/bind/dnssafe/aichrand.h b/lib/bind/dnssafe/aichrand.h
new file mode 100644 (file)
index 0000000..6f188e1
--- /dev/null
@@ -0,0 +1,17 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _AICHRAND_H_
+#define _AICHRAND_H_ 1
+
+#include "ainfotyp.h"
+#include "ainull.h"
+
+extern B_AlgorithmInfoTypeVTable AITChooseRandomNull_V_TABLE;
+
+#endif
diff --git a/lib/bind/dnssafe/aimd5.c b/lib/bind/dnssafe/aimd5.c
new file mode 100644 (file)
index 0000000..520fb40
--- /dev/null
@@ -0,0 +1,27 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "balg.h"
+#include "aichdig.h"
+#include "port_after.h"
+
+B_AlgorithmInfoType AIT_MD5 = {&AITChooseDigestNull_V_TABLE};
+
+int AI_MD5 (infoType)
+POINTER *infoType;
+{
+  *infoType = (POINTER)&AIT_MD5;
+
+  /* Return 0 to indicate a B_AlgorithmInfoType, not a B_KeyInfoType */
+  return (0);
+}
+
diff --git a/lib/bind/dnssafe/aimd5ran.c b/lib/bind/dnssafe/aimd5ran.c
new file mode 100644 (file)
index 0000000..7a2cd2b
--- /dev/null
@@ -0,0 +1,27 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "balg.h"
+#include "aichrand.h"
+#include "port_after.h"
+
+B_AlgorithmInfoType AIT_MD5Random = {&AITChooseRandomNull_V_TABLE};
+
+int AI_MD5Random (infoType)
+POINTER *infoType;
+{
+  *infoType = (POINTER)&AIT_MD5Random;
+
+  /* Return 0 to indicate a B_AlgorithmInfoType, not a B_KeyInfoType */
+  return (0);
+}
+
diff --git a/lib/bind/dnssafe/ainfotyp.c b/lib/bind/dnssafe/ainfotyp.c
new file mode 100644 (file)
index 0000000..4d077a6
--- /dev/null
@@ -0,0 +1,32 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "balg.h"
+#include "ainfotyp.h"
+#include "port_after.h"
+
+/* This is the default routine which algorithm info types point MakeInfo to
+     if not redefined by a derived class.
+ */
+int B_AlgorithmInfoTypeMakeError (infoType, info, algorithm)
+B_AlgorithmInfoType *infoType;
+POINTER *info;
+B_Algorithm *algorithm;
+{
+UNUSED_ARG (infoType)
+UNUSED_ARG (info)
+UNUSED_ARG (algorithm)
+
+  /* Should already have been found in the cache. */
+  return (BE_WRONG_ALGORITHM_INFO);
+}
+
diff --git a/lib/bind/dnssafe/ainfotyp.h b/lib/bind/dnssafe/ainfotyp.h
new file mode 100644 (file)
index 0000000..fa9f4a6
--- /dev/null
@@ -0,0 +1,39 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _AINFOTYP_H_
+#define _AINFOTYP_H_ 1
+
+/* Use the THIS_ALGORITHM_INFO_TYPE macro to define the type of object in the
+     virtual function prototype.  It defaults to the most base class, but
+     derived modules may define the macro to a more derived class before
+     including this header file.
+ */
+#ifndef THIS_ALGORITHM_INFO_TYPE
+#define THIS_ALGORITHM_INFO_TYPE struct B_AlgorithmInfoType
+#endif
+
+struct B_AlgorithmInfoType;
+
+typedef struct {
+  int (*AddInfo) PROTO_LIST
+    ((THIS_ALGORITHM_INFO_TYPE *, B_Algorithm *, POINTER));
+  struct B_TypeCheck * (*NewHandler) PROTO_LIST
+    ((THIS_ALGORITHM_INFO_TYPE *, B_Algorithm *));
+  int (*MakeInfo) PROTO_LIST
+    ((THIS_ALGORITHM_INFO_TYPE *, POINTER *, B_Algorithm *));
+} B_AlgorithmInfoTypeVTable;
+
+typedef struct B_AlgorithmInfoType {
+  B_AlgorithmInfoTypeVTable *vTable;
+} B_AlgorithmInfoType;
+
+int B_AlgorithmInfoTypeMakeError PROTO_LIST
+  ((THIS_ALGORITHM_INFO_TYPE *, POINTER *, B_Algorithm *));
+
+#endif
diff --git a/lib/bind/dnssafe/ainull.c b/lib/bind/dnssafe/ainull.c
new file mode 100644 (file)
index 0000000..9a6b322
--- /dev/null
@@ -0,0 +1,28 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "balg.h"
+#include "ainfotyp.h"
+#include "ainull.h"
+#include "port_after.h"
+
+int AITNullAddInfo (infoType, algorithm, info)
+B_AlgorithmInfoType *infoType;
+B_Algorithm *algorithm;
+POINTER info;
+{
+UNUSED_ARG (info)
+  /* Cache null parameters. */
+  return (B_InfoCacheAddInfo
+          (&algorithm->infoCache, (POINTER)infoType, NULL_PTR));
+}
+
diff --git a/lib/bind/dnssafe/ainull.h b/lib/bind/dnssafe/ainull.h
new file mode 100644 (file)
index 0000000..3b48901
--- /dev/null
@@ -0,0 +1,10 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+int AITNullAddInfo PROTO_LIST
+  ((THIS_ALGORITHM_INFO_TYPE *, B_Algorithm *, POINTER));
diff --git a/lib/bind/dnssafe/airsaepr.c b/lib/bind/dnssafe/airsaepr.c
new file mode 100644 (file)
index 0000000..0de3340
--- /dev/null
@@ -0,0 +1,47 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "balg.h"
+#include "ainfotyp.h"
+#include "ainull.h"
+#include "ahrsaepr.h"
+#include "port_after.h"
+
+B_TypeCheck *AIT_PKCS_RSAPrivateNewHandler PROTO_LIST
+  ((B_AlgorithmInfoType *, B_Algorithm *));
+
+static B_AlgorithmInfoTypeVTable V_TABLE =
+  {AITNullAddInfo, AIT_PKCS_RSAPrivateNewHandler,
+   B_AlgorithmInfoTypeMakeError};
+
+B_AlgorithmInfoType AIT_PKCS_RSAPrivate = {&V_TABLE};
+
+int AI_PKCS_RSAPrivate (infoType)
+POINTER *infoType;
+{
+  *infoType = (POINTER)&AIT_PKCS_RSAPrivate;
+
+  /* Return 0 to indicate a B_AlgorithmInfoType, not a B_KeyInfoType */
+  return (0);
+}
+
+B_TypeCheck *AIT_PKCS_RSAPrivateNewHandler (infoType, algorithm)
+B_AlgorithmInfoType *infoType;
+B_Algorithm *algorithm;
+{
+UNUSED_ARG (infoType)
+UNUSED_ARG (algorithm)
+  /* Pass in NULL_PTR so that constructor will allocate. */
+  return ((B_TypeCheck *)AH_RSAEncrypPrivateConstructor
+          ((AH_RSAEncryptionPrivate *)NULL_PTR));
+}
+
diff --git a/lib/bind/dnssafe/airsaepu.c b/lib/bind/dnssafe/airsaepu.c
new file mode 100644 (file)
index 0000000..2521d98
--- /dev/null
@@ -0,0 +1,47 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "balg.h"
+#include "ainfotyp.h"
+#include "ainull.h"
+#include "ahrsaepu.h"
+#include "port_after.h"
+
+B_TypeCheck *AIT_PKCS_RSAPublicNewHandler PROTO_LIST
+  ((B_AlgorithmInfoType *, B_Algorithm *));
+
+static B_AlgorithmInfoTypeVTable V_TABLE =
+  {AITNullAddInfo, AIT_PKCS_RSAPublicNewHandler,
+   B_AlgorithmInfoTypeMakeError};
+
+B_AlgorithmInfoType AIT_PKCS_RSAPublic = {&V_TABLE};
+
+int AI_PKCS_RSAPublic (infoType)
+POINTER *infoType;
+{
+  *infoType = (POINTER)&AIT_PKCS_RSAPublic;
+
+  /* Return 0 to indicate a B_AlgorithmInfoType, not a B_KeyInfoType */
+  return (0);
+}
+
+B_TypeCheck *AIT_PKCS_RSAPublicNewHandler (infoType, algorithm)
+B_AlgorithmInfoType *infoType;
+B_Algorithm *algorithm;
+{
+UNUSED_ARG (infoType)
+UNUSED_ARG (algorithm)
+  /* Pass in NULL_PTR so that constructor will allocate. */
+  return ((B_TypeCheck *)AH_RSAEncrypPublicConstructor
+          ((AH_RSAEncryptionPublic *)NULL_PTR));
+}
+
diff --git a/lib/bind/dnssafe/airsakgn.c b/lib/bind/dnssafe/airsakgn.c
new file mode 100644 (file)
index 0000000..3ac7657
--- /dev/null
@@ -0,0 +1,62 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "balg.h"
+#include "intitem.h"
+#include "aichgen.h"
+#include "port_after.h"
+
+int AIT_RSAKeyGenAddInfo PROTO_LIST
+  ((THIS_ALGORITHM_INFO_TYPE *, B_Algorithm *, POINTER));
+
+static A_RSA_KEY_GEN_PARAMS STATIC_KEY_GEN_PARAMS;
+static ITEM *KEY_GEN_PARAMS_ITEMS[] = {&STATIC_KEY_GEN_PARAMS.publicExponent};
+
+static B_AlgorithmInfoTypeVTable V_TABLE =
+  {AIT_RSAKeyGenAddInfo, AITChooseGenerateNewHandler,
+   B_AlgorithmInfoTypeMakeError};
+
+B_AlgorithmInfoType AIT_RSAKeyGen = {&V_TABLE};
+
+int AI_RSAKeyGen (infoType)
+POINTER *infoType;
+{
+  *infoType = (POINTER)&AIT_RSAKeyGen;
+
+  /* Return 0 to indicate a B_AlgorithmInfoType, not a B_KeyInfoType */
+  return (0);
+}
+
+int AIT_RSAKeyGenAddInfo (infoType, algorithm, info)
+B_AlgorithmInfoType *infoType;
+B_Algorithm *algorithm;
+POINTER info;
+{
+  A_RSA_KEY_GEN_PARAMS *newInfo;
+  int status;
+  
+  if ((status = B_MemoryPoolAlloc
+       (&algorithm->infoCache.memoryPool, (POINTER *)&newInfo,
+        sizeof (A_RSA_KEY_GEN_PARAMS))) != 0)
+      return (status);
+  if ((status = AllocAndCopyIntegerItems
+       ((POINTER)newInfo, info, (POINTER)&STATIC_KEY_GEN_PARAMS,
+        KEY_GEN_PARAMS_ITEMS,
+        sizeof (KEY_GEN_PARAMS_ITEMS) / sizeof (KEY_GEN_PARAMS_ITEMS[0]),
+        &algorithm->infoCache.memoryPool)) != 0)
+    return (status);
+
+  newInfo->modulusBits = ((A_RSA_KEY_GEN_PARAMS *)info)->modulusBits;
+  return (B_InfoCacheAddInfo
+          (&algorithm->infoCache, (POINTER)infoType, (POINTER)newInfo));
+}
+
diff --git a/lib/bind/dnssafe/airsaprv.c b/lib/bind/dnssafe/airsaprv.c
new file mode 100644 (file)
index 0000000..36b6b82
--- /dev/null
@@ -0,0 +1,27 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "balg.h"
+#include "aichencn.h"
+#include "port_after.h"
+
+B_AlgorithmInfoType AIT_RSAPrivate = {&AITChooseEncryptNull_V_TABLE};
+
+int AI_RSAPrivate (infoType)
+POINTER *infoType;
+{
+  *infoType = (POINTER)&AIT_RSAPrivate;
+
+  /* Return 0 to indicate a B_AlgorithmInfoType, not a B_KeyInfoType */
+  return (0);
+}
+
diff --git a/lib/bind/dnssafe/airsapub.c b/lib/bind/dnssafe/airsapub.c
new file mode 100644 (file)
index 0000000..7ff5acb
--- /dev/null
@@ -0,0 +1,27 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "balg.h"
+#include "aichencn.h"
+#include "port_after.h"
+
+B_AlgorithmInfoType AIT_RSAPublic = {&AITChooseEncryptNull_V_TABLE};
+
+int AI_RSAPublic (infoType)
+POINTER *infoType;
+{
+  *infoType = (POINTER)&AIT_RSAPublic;
+
+  /* Return 0 to indicate a B_AlgorithmInfoType, not a B_KeyInfoType */
+  return (0);
+}
+
diff --git a/lib/bind/dnssafe/algae.h b/lib/bind/dnssafe/algae.h
new file mode 100644 (file)
index 0000000..db4d5bc
--- /dev/null
@@ -0,0 +1,66 @@
+/* Copyright (C) RSA Data Security, Inc. created 1992, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _ALGAE_H_
+#define _ALGAE_H_ 1
+
+#ifndef T_CALL
+#define T_CALL
+#endif
+
+/* Used to reduce the stack size in routines with big scratch buffers.
+   If set to 1, this will make ALGAE allocate these buffers on the heap.
+ */
+#ifndef USE_ALLOCED_FRAME
+#define USE_ALLOCED_FRAME 1
+#endif
+
+#include "atypes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define AE_CANCEL 0x0001
+#define AE_DATA 0x0002
+#define AE_EXPONENT_EVEN 0x0003
+#define AE_EXPONENT_LEN 0x0004
+#define AE_INPUT_DATA 0x0005
+#define AE_INPUT_LEN 0x0006
+#define AE_MODULUS_LEN 0x0007
+#define AE_NEED_RANDOM 0x0008
+#define AE_NOT_SUPPORTED 0x0009
+#define AE_OUTPUT_LEN 0x000a
+#define AE_NOT_INITIALIZED 0x000b
+#define AE_KEY_LEN 0x000c
+#define AE_KEY_INFO 0x000d
+#define AE_SEQUENCE 0x000e
+#define AE_PARAMS 0x000f
+
+#if USE_ALLOCED_FRAME
+/* Needed only for big number code heap allocation of scratch arrays.
+ */
+#define AE_ALLOC 0x0080
+POINTER T_malloc PROTO_LIST ((unsigned int));
+void T_free PROTO_LIST ((POINTER));
+#endif
+
+/* Routines supplied by the implementor.
+ */
+void T_memset PROTO_LIST ((POINTER, int, unsigned int));
+void T_memcpy PROTO_LIST ((POINTER, CPOINTER, unsigned int));
+void T_memmove PROTO_LIST ((POINTER, POINTER, unsigned int));
+int T_memcmp PROTO_LIST ((CPOINTER, CPOINTER, unsigned int));
+
+unsigned int A_IntegerBits PROTO_LIST ((const unsigned char *, unsigned int));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/bind/dnssafe/algchoic.c b/lib/bind/dnssafe/algchoic.c
new file mode 100644 (file)
index 0000000..2943ca8
--- /dev/null
@@ -0,0 +1,169 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "algae.h"
+#include "balgmeth.h"
+#include "bkey.h"
+#include "algchoic.h"
+#include "port_after.h"
+
+/* In C++:
+ResizeContext::ResizeContext ()
+{
+  T_memset ((POINTER)&z, 0, sizeof (z));
+}
+ */
+void ResizeContextConstructor (resizeContext)
+ResizeContext *resizeContext;
+{
+  T_memset ((POINTER)&resizeContext->z, 0, sizeof (resizeContext->z));
+}
+
+/* In C++:
+ResizeContext::~ResizeContext ()
+{
+  T_memset (z.context, 0, z.contextSize);
+  T_free (z.context);
+}
+ */
+void ResizeContextDestructor (resizeContext)
+ResizeContext *resizeContext;
+{
+  T_memset (resizeContext->z.context, 0, resizeContext->z.contextSize);
+  T_free (resizeContext->z.context);
+}
+
+/* If the resizeContext's context is already the requested size, do nothing.
+   Otherwise, this memsets the existing context to zero, then allocates
+     the context as a buffer of the requested size.
+   If the allocate fails, the context size is set to
+     zero so that later calls will not zeroize non-existing buffers.
+ */
+int ResizeContextMakeNewContext (resizeContext, contextSize)
+ResizeContext *resizeContext;
+unsigned int contextSize;
+{
+  if (resizeContext->z.contextSize == contextSize)
+    return (0);
+
+  /* Take care of zeroizing the previous context.
+   */
+  T_memset (resizeContext->z.context, 0, resizeContext->z.contextSize);
+
+  if ((resizeContext->z.context = T_realloc
+       (resizeContext->z.context, contextSize)) == NULL_PTR) {
+    resizeContext->z.contextSize = 0;
+    return (BE_ALLOC);
+  }
+    
+  resizeContext->z.contextSize = contextSize;
+  return (0);
+}
+
+int AlgaChoiceChoose (algaChoice, encryptFlag, key, chooser, surrenderContext)
+AlgaChoice *algaChoice;
+int encryptFlag;
+B_Key *key;
+B_ALGORITHM_CHOOSER chooser;
+A_SURRENDER_CTX *surrenderContext;
+{
+  POINTER keyInfo;
+  int status, overallStatus;
+
+  /* Each alga init callback returns BE_NOT_SUPPORTED if the Query fails.
+     Each also may return a more specific error like BE_MODULUS_LEN if the
+       method is not supported, so return the more specific error if possible.
+   */
+  overallStatus = BE_METHOD_NOT_IN_CHOOSER;
+
+  for (; *chooser != (B_ALGORITHM_METHOD *)NULL_PTR; chooser++) {
+    if ((*chooser)->algorithmInfoType != algaChoice->_algorithmInfoType ||
+        (*chooser)->encryptFlag != encryptFlag)
+      /* Wrong type of algorithm, or the encryptFlag is wrong */
+      continue;
+
+    if ((*chooser)->keyInfoType != (struct B_KeyInfoType *)NULL_PTR) {
+      if ((status = B_KeyGetInfo
+           (key, &keyInfo, (*chooser)->keyInfoType)) != 0) {
+        if (IS_FATAL_BSAFE_ERROR (status))
+          return (status);
+      
+        /* Update the overall status with this more specific error. */
+        overallStatus = status;
+        continue;
+      }
+    }
+    else
+      keyInfo = NULL_PTR;
+
+    if ((status = (*algaChoice->_InitAlga)
+         (algaChoice, keyInfo, *chooser, surrenderContext)) != 0) {
+      if (IS_FATAL_BSAFE_ERROR (status))
+        return (status);
+
+      /* Update the overall status with this more specific error. */
+      overallStatus = status;
+      continue;
+    }
+
+    /* Succeeded */
+    algaChoice->_alga = (*chooser)->alga;
+    return (0);
+  }
+
+  return (overallStatus);
+}
+
+/* Convert the ALGAE error to a BSAFE2 error.
+   This does not check for zero since BSAFE should not bother to call
+     this function if there is no error.
+ */
+int ConvertAlgaeError (type)
+int type;
+{
+  switch (type) {
+  case AE_CANCEL:
+    return (BE_CANCEL);
+  case AE_DATA:
+    return (BE_DATA);
+  case AE_EXPONENT_EVEN:
+    return (BE_EXPONENT_EVEN);
+  case AE_EXPONENT_LEN:
+    return (BE_EXPONENT_LEN);
+  case AE_INPUT_DATA:
+    return (BE_INPUT_DATA);
+  case AE_INPUT_LEN:
+    return (BE_INPUT_LEN);
+  case AE_KEY_INFO:
+    return (BE_KEY_INFO);
+  case AE_KEY_LEN:
+    return (BE_KEY_LEN);
+  case AE_MODULUS_LEN:
+    return (BE_MODULUS_LEN);
+  case AE_NOT_INITIALIZED:
+    return (BE_NOT_INITIALIZED);
+  case AE_NOT_SUPPORTED:
+    return (BE_NOT_SUPPORTED);
+  case AE_OUTPUT_LEN:
+    return (BE_OUTPUT_LEN);
+  case AE_PARAMS:
+    return (BE_ALGORITHM_INFO);
+    
+#if USE_ALLOCED_FRAME
+  case AE_ALLOC:
+    return (BE_ALLOC);
+#endif
+
+  default:
+    return (BE_DATA);
+  }
+}
+
diff --git a/lib/bind/dnssafe/algchoic.h b/lib/bind/dnssafe/algchoic.h
new file mode 100644 (file)
index 0000000..5743441
--- /dev/null
@@ -0,0 +1,111 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _ALGCHOICE_H_
+#define _ALGCHOICE_H_ 1
+
+#define IS_FATAL_BSAFE_ERROR(status) \
+  (status == BE_ALLOC || status == BE_HARDWARE || status == BE_CANCEL)
+
+/* Use the THIS_ALGA_CHOICE macro to define the type of object in the
+     INIT_ALGA prototype.  It defaults to the AlgaChoice, but
+     derived modules may define the macro to a more derived class before
+     including this header file.
+ */
+struct AlgaChoice;
+#ifndef THIS_ALGA_CHOICE
+#define THIS_ALGA_CHOICE struct AlgaChoice
+#endif
+
+/* In C++:
+class ResizeContext {
+public:
+  ResizeContext ();
+  ~ResizeContext ();
+  int makeNewContext (unsigned int contextSize);
+  POINTER context () {return z.context;}
+
+private:
+  struct {
+    POINTER context;
+    unsigned int contextSize;
+  } z;
+};
+
+class AlgaChoice;
+typedef int (*INIT_ALGA)
+  (THIS_ALGA_CHOICE *algaChoice, POINTER keyInfo,
+   struct B_ALGORITHM_METHOD *algorithmMethod,
+   A_SURRENDER_CTX *surrenderContext);
+
+class AlgaChoice {
+public:
+  AlgaChoice (INIT_ALGA InitAlga) : _InitAlga (InitAlga) {}
+  ~AlgaChoice () {}
+  int choose
+    (int encryptFlag, B_Key *key, B_ALGORITHM_CHOOSER chooser,
+     A_SURRENDER_CTX *surrenderContext);
+  int makeNewContext (unsigned int contextSize) {
+    context.makeNewContext (contextSize); }
+  POINTER alga () {return _alga;}
+  POINTER algorithmInfo () {return _algorithmInfo;}
+  POINTER context () {return context.context ();}
+  void setAlgorithmInfoType (B_AlgorithmInfoType *algorithmInfoType) {
+    _algorithmInfoType = algorithmInfoType;
+  }
+  void setAlgorithmInfo (POINTER algorithmInfo) {
+    _algorithmInfo = algorithmInfo;
+  }
+
+private:
+  POINTER _alga;
+  B_AlgorithmInfoType *_algorithmInfoType;
+  POINTER _algorithmInfo;
+  INIT_ALGA _InitAlga;
+
+  ResizeContext context;
+};
+ */
+struct B_AlgorithmInfoType;
+
+typedef struct ResizeContext {
+  struct {
+    POINTER context;
+    unsigned int contextSize;
+  } z;                                            /* zeriozed by constructor */
+} ResizeContext;
+
+typedef int (*INIT_ALGA) PROTO_LIST
+  ((THIS_ALGA_CHOICE *, POINTER, struct B_ALGORITHM_METHOD *,
+    A_SURRENDER_CTX *));
+
+typedef struct AlgaChoice {
+  POINTER _alga;
+  struct B_AlgorithmInfoType *_algorithmInfoType;
+  POINTER _algorithmInfo;
+  INIT_ALGA _InitAlga;
+
+  ResizeContext context;
+} AlgaChoice;
+
+void ResizeContextConstructor PROTO_LIST ((ResizeContext *));
+void ResizeContextDestructor PROTO_LIST ((ResizeContext *));
+int ResizeContextMakeNewContext PROTO_LIST ((ResizeContext *, unsigned int));
+
+#define ALGA_CHOICE_Constructor(algaChoice, InitAlga)\
+  (ResizeContextConstructor (&(algaChoice)->context), \
+   (algaChoice)->_InitAlga = (InitAlga))
+#define ALGA_CHOICE_Destructor(algaChoice)\
+  (ResizeContextDestructor (&(algaChoice)->context))
+
+int AlgaChoiceChoose PROTO_LIST
+  ((AlgaChoice *, int, B_Key *, B_ALGORITHM_CHOOSER, A_SURRENDER_CTX *));
+
+int ConvertAlgaeError PROTO_LIST ((int));
+
+#endif
diff --git a/lib/bind/dnssafe/algobj.c b/lib/bind/dnssafe/algobj.c
new file mode 100644 (file)
index 0000000..78e9d7e
--- /dev/null
@@ -0,0 +1,123 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "balg.h"
+#include "ainfotyp.h"
+#include "keyobj.h"
+#include "algobj.h"
+#include "port_after.h"
+
+static char ALGORITHM_TYPE_TAG = 0;
+
+int B_CreateAlgorithmObject (algorithmObject)
+B_ALGORITHM_OBJ *algorithmObject;
+{
+  AlgorithmWrap *algorithmWrap;
+
+  if ((*algorithmObject = T_malloc (sizeof (*algorithmWrap))) == NULL_PTR)
+    return (BE_ALLOC);
+
+  algorithmWrap = (AlgorithmWrap *)*algorithmObject;
+
+  /* First construct base class */
+  B_AlgorithmConstructor (&algorithmWrap->algorithm);
+  
+  algorithmWrap->typeTag = &ALGORITHM_TYPE_TAG;
+  algorithmWrap->selfCheck = algorithmWrap;
+  return (0);
+}
+
+void B_DestroyAlgorithmObject (algorithmObject)
+B_ALGORITHM_OBJ *algorithmObject;
+{
+  AlgorithmWrap *algorithmWrap = (AlgorithmWrap *)*algorithmObject;
+
+  if (AlgorithmWrapCheck (algorithmWrap) == 0) {
+    /* zeroize self check to invalidate memory. */
+    algorithmWrap->selfCheck = (AlgorithmWrap *)NULL_PTR;
+
+    /* Call base class descructor */
+    B_AlgorithmDestructor (&algorithmWrap->algorithm);
+
+    T_free ((POINTER)algorithmWrap);
+  }
+
+  *algorithmObject = NULL_PTR;
+}
+
+int B_SetAlgorithmInfo (algorithmObject, infoType, info)
+B_ALGORITHM_OBJ algorithmObject;
+B_INFO_TYPE infoType;
+POINTER info;
+{
+  B_AlgorithmInfoType *algorithmInfoType;
+  int status;
+  
+  if ((status = AlgorithmWrapCheck (THE_ALG_WRAP)) != 0)
+    return (status);
+
+  /* Get the AlgorithmInfoType from the B_INFO_TYPE, which returns
+       zero for an AlgorithmInfoType, non-zero for KeyInfoType
+   */
+  if ((*infoType) ((POINTER *)&algorithmInfoType) != 0)
+    return (BE_KEY_OPERATION_UNKNOWN);
+  
+  return (B_AlgorithmSetInfo
+          (&THE_ALG_WRAP->algorithm, algorithmInfoType, info));
+}
+
+int B_GetAlgorithmInfo (info, algorithmObject, infoType)
+POINTER *info;
+B_ALGORITHM_OBJ algorithmObject;
+B_INFO_TYPE infoType;
+{
+  B_AlgorithmInfoType *algorithmInfoType;
+  int status;
+  
+  if ((status = AlgorithmWrapCheck (THE_ALG_WRAP)) != 0)
+    return (status);
+
+  /* Get the AlgorithmInfoType from the B_INFO_TYPE, which returns
+       zero for an AlgorithmInfoType, non-zero for KeyInfoType
+   */
+  if ((*infoType) ((POINTER *)&algorithmInfoType) != 0)
+    return (BE_KEY_OPERATION_UNKNOWN);
+  
+  return (B_AlgorithmGetInfo
+          (&THE_ALG_WRAP->algorithm, info, algorithmInfoType));
+}
+
+/* Return 0 if this is a valid AlgorithmWrap object. Return BE_ALGORITHM_OBJ if
+     algorithmWrap is NULL_PTR or invalid.
+ */
+int AlgorithmWrapCheck (algorithmWrap)
+AlgorithmWrap *algorithmWrap;
+{
+  return ((algorithmWrap != (AlgorithmWrap *)NULL_PTR &&
+           algorithmWrap->selfCheck == algorithmWrap &&
+           algorithmWrap->typeTag == &ALGORITHM_TYPE_TAG) ?
+          0 : BE_ALGORITHM_OBJ);
+}
+
+/* Like AlgorithmWrapCheck except returns BE_RANDOM_OBJ for error.
+   Also, return OK status if randomAlgorithm is NULL_PTR.
+ */
+int RandomAlgorithmCheck (randomAlgorithm)
+B_ALGORITHM_OBJ randomAlgorithm;
+{
+  if (randomAlgorithm == NULL_PTR)
+    return (0);
+
+  return (AlgorithmWrapCheck ((AlgorithmWrap *)randomAlgorithm) ?
+          BE_RANDOM_OBJ : 0);
+}
+
diff --git a/lib/bind/dnssafe/algobj.h b/lib/bind/dnssafe/algobj.h
new file mode 100644 (file)
index 0000000..7f87cfa
--- /dev/null
@@ -0,0 +1,19 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#define THE_ALG_WRAP ((AlgorithmWrap *)algorithmObject)
+
+typedef struct AlgorithmWrap {
+  B_Algorithm algorithm;
+  char *typeTag;
+  struct AlgorithmWrap *selfCheck;
+} AlgorithmWrap;
+
+int AlgorithmWrapCheck PROTO_LIST ((AlgorithmWrap *));
+int RandomAlgorithmCheck PROTO_LIST ((B_ALGORITHM_OBJ));
+
diff --git a/lib/bind/dnssafe/amcrte.c b/lib/bind/dnssafe/amcrte.c
new file mode 100644 (file)
index 0000000..ed771ea
--- /dev/null
@@ -0,0 +1,119 @@
+/* Copyright (C) RSA Data Security, Inc. created 1994, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "algae.h"
+#include "bsafe2.h"
+#include "balgmeth.h"
+#include "crt2.h"
+#include "amencdec.h"
+#include "port_after.h"
+
+static int RSA_CRT2Query PROTO_LIST ((unsigned int *, POINTER, POINTER));
+static int RSA_CRT2Init PROTO_LIST
+  ((POINTER, POINTER, POINTER, A_SURRENDER_CTX *));
+static int RSA_CRT2Update PROTO_LIST
+  ((POINTER, unsigned char *, unsigned int *, unsigned int,
+    const unsigned char *, unsigned int, A_SURRENDER_CTX *));
+static int RSA_CRT2Final PROTO_LIST
+  ((POINTER, unsigned char *, unsigned int *, unsigned int,
+    A_SURRENDER_CTX *));
+static int RSA_CRT2GetMaxOutputLen PROTO_LIST
+  ((POINTER, unsigned int *, unsigned int));
+static int RSA_CRT2GetBlockLen PROTO_LIST ((POINTER, unsigned int *));
+
+extern struct B_AlgorithmInfoType AIT_RSAPrivate;
+extern struct B_KeyInfoType KIT_RSA_CRT;
+
+static A_ENCRYPT_DECRYPT_ALGA A_RSA_CRT2_CRYPT = {
+  RSA_CRT2Query, RSA_CRT2Init, RSA_CRT2Update, RSA_CRT2Final,
+  RSA_CRT2GetMaxOutputLen, RSA_CRT2GetBlockLen
+};
+
+B_ALGORITHM_METHOD AM_RSA_CRT_DECRYPT =
+  {&AIT_RSAPrivate, 0, &KIT_RSA_CRT, (POINTER)&A_RSA_CRT2_CRYPT};
+B_ALGORITHM_METHOD AM_RSA_CRT_ENCRYPT =
+  {&AIT_RSAPrivate, 1, &KIT_RSA_CRT, (POINTER)&A_RSA_CRT2_CRYPT};
+
+static int RSA_CRT2Query (contextLen, key, params)
+unsigned int *contextLen;
+POINTER key;
+POINTER params;
+{
+UNUSED_ARG (params)
+
+  if (A_IntegerBits
+      (((A_RSA_CRT_KEY *)key)->modulus.data,
+       ((A_RSA_CRT_KEY *)key)->modulus.len) > MAX_RSA_MODULUS_BITS)
+    /* Key size is too big to handle. */
+    return (AE_MODULUS_LEN);
+
+  *contextLen = sizeof (A_RSA_CRT2_CTX);
+  return (0);
+}
+
+static int RSA_CRT2Init (context, key, params, surrenderContext)
+POINTER context;
+POINTER key;
+POINTER params;
+A_SURRENDER_CTX *surrenderContext;
+{
+UNUSED_ARG (params)
+UNUSED_ARG (surrenderContext)
+
+  return (A_RSA_CRT2Init ((A_RSA_CRT2_CTX *)context, (A_RSA_CRT_KEY *)key));
+}
+
+static int RSA_CRT2Update
+  (context, output, outputLen, maxOutputLen, input, inputLen, surrenderContext)
+POINTER context;
+unsigned char *output;
+unsigned int *outputLen;
+unsigned int maxOutputLen;
+const unsigned char *input;
+unsigned int inputLen;
+A_SURRENDER_CTX *surrenderContext;
+{
+  return (A_RSA_CRT2Update
+          ((A_RSA_CRT2_CTX *)context, output, outputLen, maxOutputLen, input,
+           inputLen, surrenderContext));
+}
+
+static int RSA_CRT2Final
+  (context, output, outputLen, maxOutputLen, surrenderContext)
+POINTER context;
+unsigned char *output;
+unsigned int *outputLen;
+unsigned int maxOutputLen;
+A_SURRENDER_CTX * surrenderContext;
+{
+UNUSED_ARG (output)
+UNUSED_ARG (maxOutputLen)
+UNUSED_ARG (surrenderContext)
+
+  *outputLen = 0;
+  return (A_RSA_CRT2Final ((A_RSA_CRT2_CTX *)context));
+}
+
+static int RSA_CRT2GetMaxOutputLen (context, outputLen, inputLen)
+POINTER context;
+unsigned int *outputLen;
+unsigned int inputLen;
+{
+  *outputLen = A_RSA_CRT2_MAX_OUTPUT_LEN ((A_RSA_CRT2_CTX *)context, inputLen);
+  return (0);
+}
+
+static int RSA_CRT2GetBlockLen (context, blockLen)
+POINTER context;
+unsigned int *blockLen;
+{
+  *blockLen = A_RSA_CRT2_BLOCK_LEN ((A_RSA_CRT2_CTX *)context);
+  return(0);
+}
diff --git a/lib/bind/dnssafe/amdigest.h b/lib/bind/dnssafe/amdigest.h
new file mode 100644 (file)
index 0000000..ec176eb
--- /dev/null
@@ -0,0 +1,19 @@
+/* Copyright (C) RSA Data Security, Inc. created 1994, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+typedef struct {
+  int (*Query) PROTO_LIST ((unsigned int *, POINTER));
+  int (*Init) PROTO_LIST ((POINTER, POINTER, A_SURRENDER_CTX *));
+  int (*Update) PROTO_LIST
+    ((POINTER, const unsigned char *, unsigned int, A_SURRENDER_CTX *));
+  int (*Final) PROTO_LIST
+    ((POINTER, unsigned char *, unsigned int *, unsigned int,
+      A_SURRENDER_CTX *));
+  int (*GetMaxOutputLen) PROTO_LIST ((POINTER, unsigned int *));
+} A_DIGEST_ALGA;
+
diff --git a/lib/bind/dnssafe/amencdec.h b/lib/bind/dnssafe/amencdec.h
new file mode 100644 (file)
index 0000000..21ab2c8
--- /dev/null
@@ -0,0 +1,21 @@
+/* Copyright (C) RSA Data Security, Inc. created 1994, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+typedef struct {
+  int (*Query) PROTO_LIST ((unsigned int *, POINTER, POINTER));
+  int (*Init) PROTO_LIST ((POINTER, POINTER, POINTER, A_SURRENDER_CTX *));
+  int (*Update) PROTO_LIST
+    ((POINTER, unsigned char *, unsigned int *, unsigned int,
+      const unsigned char *, unsigned int, A_SURRENDER_CTX *));
+  int (*Final) PROTO_LIST
+    ((POINTER, unsigned char *, unsigned int *, unsigned int,
+      A_SURRENDER_CTX *));
+  int (*GetMaxOutputLen) PROTO_LIST ((POINTER, unsigned int *, unsigned int));
+  int (*GetBlockLen) PROTO_LIST ((POINTER, unsigned int *));
+} A_ENCRYPT_DECRYPT_ALGA;
+
diff --git a/lib/bind/dnssafe/amgen.h b/lib/bind/dnssafe/amgen.h
new file mode 100644 (file)
index 0000000..ffdf457
--- /dev/null
@@ -0,0 +1,19 @@
+/* Copyright (C) RSA Data Security, Inc. created 1994, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+struct B_KeyInfoType;
+
+typedef struct {
+  int (*Query) PROTO_LIST
+    ((unsigned int *, unsigned int *, unsigned int *, struct B_KeyInfoType **,
+      POINTER));
+  int (*Init) PROTO_LIST ((POINTER, POINTER, POINTER, A_SURRENDER_CTX *));
+  int (*Generate) PROTO_LIST
+    ((POINTER, POINTER *, unsigned char *, A_SURRENDER_CTX *));
+} A_GENERATE_ALGA;
+
diff --git a/lib/bind/dnssafe/ammd5.c b/lib/bind/dnssafe/ammd5.c
new file mode 100644 (file)
index 0000000..cea0aa4
--- /dev/null
@@ -0,0 +1,102 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "algae.h"
+#include "bsafe2.h"
+#include "balgmeth.h"
+#include "md5.h"
+#include "amdigest.h"
+#include "port_after.h"
+
+static int MD5Query PROTO_LIST ((unsigned int *, POINTER));
+static int MD5Init PROTO_LIST ((POINTER, POINTER, A_SURRENDER_CTX*));
+static int MD5Update PROTO_LIST
+  ((POINTER, const unsigned char *, unsigned int, A_SURRENDER_CTX*));
+static int MD5Final PROTO_LIST
+  ((POINTER, unsigned char *, unsigned int *, unsigned int, A_SURRENDER_CTX*));
+static int MD5GetMaxOutputLen PROTO_LIST ((POINTER, unsigned int *));
+
+static A_DIGEST_ALGA A_MD5_DIGEST = {
+  MD5Query, MD5Init, MD5Update, MD5Final, MD5GetMaxOutputLen
+};
+
+extern struct B_AlgorithmInfoType AIT_MD5;
+
+B_ALGORITHM_METHOD AM_MD5 =
+  {&AIT_MD5, 0, (struct B_KeyInfoType *)NULL_PTR, (POINTER)&A_MD5_DIGEST};
+
+/* Returns 0.
+ */
+static int MD5Query (contextLen, params)
+unsigned int *contextLen;
+POINTER params;
+{
+UNUSED_ARG (params)
+
+  *contextLen = sizeof (A_MD5_CTX);
+  return (0);
+}
+
+/* Returns 0.
+ */
+static int MD5Init (context, params, surrenderContext)
+POINTER context;
+POINTER params;
+A_SURRENDER_CTX *surrenderContext;
+{
+UNUSED_ARG (params)
+UNUSED_ARG (surrenderContext)
+
+  A_MD5Init ((A_MD5_CTX *)context);
+  return (0);
+}
+
+/* Returns 0.
+ */
+static int MD5Update (context, input, inputLen, surrenderContext)
+POINTER context;
+const unsigned char *input;
+unsigned int inputLen;
+A_SURRENDER_CTX *surrenderContext;
+{
+UNUSED_ARG (surrenderContext)
+
+  A_MD5Update ((A_MD5_CTX *)context, input, inputLen);
+  return (0);
+}
+
+/* Returns 0, AE_OUTPUT_LEN if maxDigestLen is too small.
+ */
+static int MD5Final
+  (context, digest, digestLen, maxDigestLen, surrenderContext)
+POINTER context;
+unsigned char *digest;
+unsigned int *digestLen;
+unsigned int maxDigestLen;
+A_SURRENDER_CTX *surrenderContext;
+{
+UNUSED_ARG (surrenderContext)
+
+  if ((*digestLen = A_MD5_DIGEST_LEN) > maxDigestLen)
+    return (AE_OUTPUT_LEN);
+
+  A_MD5Final ((A_MD5_CTX *)context, digest);
+  return (0);
+}
+
+static int MD5GetMaxOutputLen (context, outputLen)
+POINTER context;
+unsigned int *outputLen;
+{
+UNUSED_ARG (context)
+
+  *outputLen = A_MD5_DIGEST_LEN;
+  return(0);
+}
diff --git a/lib/bind/dnssafe/ammd5r.c b/lib/bind/dnssafe/ammd5r.c
new file mode 100644 (file)
index 0000000..900a872
--- /dev/null
@@ -0,0 +1,79 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "algae.h"
+#include "bsafe2.h"
+#include "balgmeth.h"
+#include "md5rand.h"
+#include "amrandom.h"
+#include "port_after.h"
+
+static int MD5RandomQuery PROTO_LIST ((unsigned int *, POINTER));
+static int MD5RandomInit PROTO_LIST ((POINTER, POINTER, A_SURRENDER_CTX *));
+static int MD5RandomUpdate PROTO_LIST
+  ((POINTER, unsigned char *, unsigned int, A_SURRENDER_CTX *));
+static int MD5RandomGenerateBytes PROTO_LIST
+  ((POINTER, unsigned char *, unsigned int, A_SURRENDER_CTX *));
+
+extern struct B_AlgorithmInfoType AIT_MD5Random;
+
+static A_RANDOM_ALGA A_MD5_RANDOM =
+  {MD5RandomQuery, MD5RandomInit, MD5RandomUpdate, MD5RandomGenerateBytes};
+
+B_ALGORITHM_METHOD AM_MD5_RANDOM =
+  {&AIT_MD5Random, 0, (struct B_KeyInfoType *)NULL_PTR,
+   (POINTER)&A_MD5_RANDOM};
+
+static int MD5RandomQuery (contextLen, params)
+unsigned int *contextLen;
+POINTER params;
+{
+UNUSED_ARG (params)
+
+  *contextLen = sizeof (A_MD5_RANDOM_CTX);
+  return (0);
+}
+
+static int MD5RandomInit (context, params, surrenderContext)
+POINTER context;
+POINTER params;
+A_SURRENDER_CTX *surrenderContext;
+{
+UNUSED_ARG (params)
+UNUSED_ARG (surrenderContext)
+
+  A_MD5RandomInit ((A_MD5_RANDOM_CTX *)context);
+  return (0);
+}
+
+static int MD5RandomUpdate (context, input, inputLen, surrenderContext)
+POINTER context;
+unsigned char *input;
+unsigned int inputLen;
+A_SURRENDER_CTX *surrenderContext;
+{
+UNUSED_ARG (surrenderContext)
+
+  A_MD5RandomUpdate ((A_MD5_RANDOM_CTX *)context, input, inputLen);
+  return (0);
+}
+
+static int MD5RandomGenerateBytes
+  (context, output, outputLen, surrenderContext)
+POINTER context;
+unsigned char *output;
+unsigned int outputLen;
+A_SURRENDER_CTX *surrenderContext;
+{
+UNUSED_ARG (surrenderContext)
+
+  A_MD5RandomGenerateBytes ((A_MD5_RANDOM_CTX *)context, output, outputLen);
+  return (0);
+}
diff --git a/lib/bind/dnssafe/amrandom.h b/lib/bind/dnssafe/amrandom.h
new file mode 100644 (file)
index 0000000..3b9539a
--- /dev/null
@@ -0,0 +1,17 @@
+/* Copyright (C) RSA Data Security, Inc. created 1994, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+typedef struct {
+  int (*Query) PROTO_LIST ((unsigned int *, POINTER));
+  int (*Init) PROTO_LIST ((POINTER, POINTER, A_SURRENDER_CTX *));
+  int (*Update) PROTO_LIST
+    ((POINTER, unsigned char *, unsigned int, A_SURRENDER_CTX *));
+  int (*Generate) PROTO_LIST
+    ((POINTER, unsigned char *, unsigned int, A_SURRENDER_CTX *));
+} A_RANDOM_ALGA;
+
diff --git a/lib/bind/dnssafe/amrkg.c b/lib/bind/dnssafe/amrkg.c
new file mode 100644 (file)
index 0000000..d5a19fb
--- /dev/null
@@ -0,0 +1,83 @@
+/* Copyright (C) RSA Data Security, Inc. created 1994, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "algae.h"
+#include "rsakeygn.h"
+#include "balgmeth.h"
+#include "amgen.h"
+#include "port_after.h"
+
+#define THE_GEN_PARAMS ((A_RSA_KEY_GEN_PARAMS *)params)
+
+extern struct B_AlgorithmInfoType AIT_RSAKeyGen;
+extern struct B_KeyInfoType KIT_PKCS_RSAPrivate;
+
+static int RSAKeyGenQuery PROTO_LIST
+  ((unsigned int *, unsigned int *, unsigned int *, struct B_KeyInfoType **,
+    POINTER));
+static int RSAKeyGenInit PROTO_LIST
+  ((POINTER, POINTER, POINTER, A_SURRENDER_CTX *));
+static int RSAKeyGen PROTO_LIST
+  ((POINTER, POINTER *, unsigned char *, A_SURRENDER_CTX *));
+
+static A_GENERATE_ALGA A_RSA_KEY_GEN =
+  {RSAKeyGenQuery, RSAKeyGenInit, RSAKeyGen};
+
+B_ALGORITHM_METHOD AM_RSA_KEY_GEN =
+  {&AIT_RSAKeyGen, 0, (struct B_KeyInfoType *)NULL_PTR,
+   (POINTER)&A_RSA_KEY_GEN};
+
+static int RSAKeyGenQuery
+  (contextLen, secondContextLen, randomBlockLen, resultInfoType, params)
+unsigned int *contextLen;
+unsigned int *secondContextLen;
+unsigned int *randomBlockLen;
+struct B_KeyInfoType **resultInfoType;
+POINTER params;
+{
+  if ((THE_GEN_PARAMS->modulusBits > MAX_RSA_MODULUS_BITS) ||
+      (THE_GEN_PARAMS->modulusBits < MIN_RSA_MODULUS_BITS))
+    /* Can't support a keypair of this size. */
+    return (AE_MODULUS_LEN);
+  
+  *contextLen = sizeof (A_RSA_KEY_GEN_CTX);
+  *secondContextLen = 0;
+  *randomBlockLen =
+     A_RSA_KEY_GEN_RANDOM_BLOCK_LEN (THE_GEN_PARAMS->modulusBits);
+  *resultInfoType = &KIT_PKCS_RSAPrivate;
+
+  return (0);
+}
+
+static int RSAKeyGenInit (context, secondContext, params, surrenderContext)
+POINTER context;
+POINTER secondContext;
+POINTER params;
+A_SURRENDER_CTX *surrenderContext;
+{
+UNUSED_ARG (secondContext)
+UNUSED_ARG (surrenderContext)
+
+  return (A_RSAKeyGenInit
+          ((A_RSA_KEY_GEN_CTX *)context, (A_RSA_KEY_GEN_PARAMS *)params));
+}
+
+static int RSAKeyGen (context, result, randomBlock, surrenderContext)
+POINTER context;
+POINTER *result;
+unsigned char *randomBlock;
+A_SURRENDER_CTX *surrenderContext;
+{
+  return (A_RSAKeyGen
+          ((A_RSA_KEY_GEN_CTX *)context, (A_PKCS_RSA_PRIVATE_KEY **)result,
+           randomBlock, surrenderContext));
+}
+
diff --git a/lib/bind/dnssafe/amrsae.c b/lib/bind/dnssafe/amrsae.c
new file mode 100644 (file)
index 0000000..f4d0670
--- /dev/null
@@ -0,0 +1,117 @@
+/* Copyright (C) RSA Data Security, Inc. created 1994, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "algae.h"
+#include "bsafe2.h"
+#include "balgmeth.h"
+#include "rsa.h"
+#include "amencdec.h"
+#include "port_after.h"
+
+static int RSAQuery PROTO_LIST ((unsigned int *, POINTER, POINTER));
+static int RSAInit PROTO_LIST ((POINTER, POINTER, POINTER, A_SURRENDER_CTX *));
+static int RSAUpdate PROTO_LIST
+  ((POINTER, unsigned char *, unsigned int *, unsigned int,
+    const unsigned char *, unsigned int, A_SURRENDER_CTX *));
+static int RSAFinal PROTO_LIST
+  ((POINTER, unsigned char *, unsigned int *, unsigned int,
+    A_SURRENDER_CTX *));
+static int RSAGetMaxOutputLen PROTO_LIST
+  ((POINTER, unsigned int *, unsigned int));
+static int RSAGetBlockLen PROTO_LIST ((POINTER, unsigned int *));
+
+extern struct B_AlgorithmInfoType AIT_RSAPublic;
+extern struct B_KeyInfoType KIT_RSAPublic;
+
+static A_ENCRYPT_DECRYPT_ALGA A_RSA_CRYPT = {
+  RSAQuery, RSAInit, RSAUpdate, RSAFinal, RSAGetMaxOutputLen, RSAGetBlockLen
+};
+
+B_ALGORITHM_METHOD AM_RSA_DECRYPT =
+  {&AIT_RSAPublic, 0, &KIT_RSAPublic, (POINTER)&A_RSA_CRYPT};
+B_ALGORITHM_METHOD AM_RSA_ENCRYPT =
+  {&AIT_RSAPublic, 1, &KIT_RSAPublic, (POINTER)&A_RSA_CRYPT};
+
+static int RSAQuery (contextLen, key, params)
+unsigned int *contextLen;
+POINTER key;
+POINTER params;
+{
+UNUSED_ARG (params)
+
+  if (A_IntegerBits
+      (((A_RSA_KEY *)key)->modulus.data, ((A_RSA_KEY *)key)->modulus.len)
+      > MAX_RSA_MODULUS_BITS)
+    /* Key size is too big to handle. */
+    return (AE_MODULUS_LEN);
+
+  *contextLen = sizeof (A_RSA_CTX);
+  return (0);
+}
+
+static int RSAInit (context, key, params, surrenderContext)
+POINTER context;
+POINTER key;
+POINTER params;
+A_SURRENDER_CTX *surrenderContext;
+{
+UNUSED_ARG (params)
+UNUSED_ARG (surrenderContext)
+
+  return (A_RSAInit ((A_RSA_CTX *)context, (A_RSA_KEY *)key));
+}
+
+static int RSAUpdate
+  (context, output, outputLen, maxOutputLen, input, inputLen, surrenderContext)
+POINTER context;
+unsigned char *output;
+unsigned int *outputLen;
+unsigned int maxOutputLen;
+const unsigned char *input;
+unsigned int inputLen;
+A_SURRENDER_CTX *surrenderContext;
+{
+  return (A_RSAUpdate
+          ((A_RSA_CTX *)context, output, outputLen, maxOutputLen, input,
+           inputLen, surrenderContext));
+}
+
+static int RSAFinal
+  (context, output, outputLen, maxOutputLen, surrenderContext)
+POINTER context;
+unsigned char *output;
+unsigned int *outputLen;
+unsigned int maxOutputLen;
+A_SURRENDER_CTX * surrenderContext;
+{
+UNUSED_ARG (output)
+UNUSED_ARG (maxOutputLen)
+UNUSED_ARG (surrenderContext)
+
+  *outputLen = 0;
+  return (A_RSAFinal ((A_RSA_CTX *)context));
+}
+
+static int RSAGetMaxOutputLen (context, outputLen, inputLen)
+POINTER context;
+unsigned int *outputLen;
+unsigned int inputLen;
+{
+  *outputLen = A_RSA_MAX_OUTPUT_LEN ((A_RSA_CTX *)context, inputLen);
+  return (0);
+}
+
+static int RSAGetBlockLen (context, blockLen)
+POINTER context;
+unsigned int *blockLen;
+{
+  *blockLen = A_RSA_BLOCK_LEN ((A_RSA_CTX *)context);
+  return(0);
+}
diff --git a/lib/bind/dnssafe/atypes.h b/lib/bind/dnssafe/atypes.h
new file mode 100644 (file)
index 0000000..e1af4ea
--- /dev/null
@@ -0,0 +1,60 @@
+/* Copyright (C) RSA Data Security, Inc. created 1992, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _ATYPES_H_
+#define _ATYPES_H_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _ITEM_
+#define _ITEM_ 1
+typedef struct {
+  unsigned char *data;
+  unsigned int len;
+} ITEM;
+#endif
+
+typedef struct {
+  int (T_CALL *Surrender) PROTO_LIST ((POINTER));
+  POINTER handle;
+  POINTER reserved;
+} A_SURRENDER_CTX;
+
+typedef struct {
+  ITEM modulus;
+  ITEM publicExponent;
+  ITEM privateExponent;
+  ITEM prime[2];                                            /* prime factors */
+  ITEM primeExponent[2];                      /* exponents for prime factors */
+  ITEM coefficient;                                       /* CRT coefficient */
+} A_PKCS_RSA_PRIVATE_KEY;
+
+typedef struct {
+  ITEM modulus;
+  ITEM prime[2];                                            /* prime factors */
+  ITEM primeExponent[2];                      /* exponents for prime factors */
+  ITEM coefficient;                                       /* CRT coefficient */
+} A_RSA_CRT_KEY;
+
+typedef struct {
+  ITEM modulus;                                                   /* modulus */
+  ITEM exponent;                                                 /* exponent */
+} A_RSA_KEY;
+
+typedef struct {
+  unsigned int modulusBits;
+  ITEM publicExponent;
+} A_RSA_KEY_GEN_PARAMS;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/bind/dnssafe/balg.c b/lib/bind/dnssafe/balg.c
new file mode 100644 (file)
index 0000000..48af15a
--- /dev/null
@@ -0,0 +1,117 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "balg.h"
+#include "btypechk.h"
+#include "ainfotyp.h"
+#include "port_after.h"
+
+void B_AlgorithmConstructor (algorithm)
+B_Algorithm *algorithm;
+{
+  /* Construct immediate base class. */
+  B_InfoCacheConstructor (&algorithm->infoCache);
+
+  T_memset ((POINTER)&algorithm->z, 0, sizeof (algorithm->z));
+}
+
+void B_AlgorithmDestructor (algorithm)
+B_Algorithm *algorithm;
+{
+  if (algorithm->z.handler != (B_TypeCheck *)NULL_PTR) {
+    B_TYPE_CHECK_Destructor (algorithm->z.handler);
+    T_free ((POINTER)algorithm->z.handler);
+  }
+
+  /* Destroy base class */
+  B_INFO_CACHE_Destructor (&algorithm->infoCache);
+}
+
+int B_AlgorithmCheckType (algorithm, Destructor)
+B_Algorithm *algorithm;
+B_TYPE_CHECK_DESTRUCTOR Destructor;
+{
+  if (algorithm->z.handler == (B_TypeCheck *)NULL_PTR)
+    return (BE_ALGORITHM_NOT_SET);
+
+  if (algorithm->z.handler->_Destructor != Destructor)
+    return (BE_ALG_OPERATION_UNKNOWN);
+
+  return (0);
+}
+
+int B_AlgorithmCheckTypeAndInitFlag (algorithm, Destructor)
+B_Algorithm *algorithm;
+B_TYPE_CHECK_DESTRUCTOR Destructor;
+{
+  int status;
+
+  /* Check the type first. */
+  if ((status = B_AlgorithmCheckType (algorithm, Destructor)) != 0)
+    return (status);
+
+  if (!algorithm->z.initFlag)
+    return (BE_ALGORITHM_NOT_INITIALIZED);
+
+  return (0);
+}
+
+int B_AlgorithmSetInfo (algorithm, algorithmInfoType, info)
+B_Algorithm *algorithm;
+B_AlgorithmInfoType *algorithmInfoType;
+POINTER info;
+{
+  int status;
+  
+  if (algorithm->infoCache.z.infoCount > 0)
+    return (BE_ALGORITHM_ALREADY_SET);
+
+  /* This will cache the encoding. */
+  if ((status = (*algorithmInfoType->vTable->AddInfo)
+       (algorithmInfoType, algorithm, info)) != 0)
+    return (status);
+
+  /* Allocate the algorithm handler.  NewHandler returns NULL_PTR for error.
+   */
+  if ((algorithm->z.handler = (*algorithmInfoType->vTable->NewHandler)
+       (algorithmInfoType, algorithm)) == (B_TypeCheck *)NULL_PTR)
+    return (BE_ALLOC);
+
+  return (0);
+}
+
+int B_AlgorithmGetInfo (algorithm, info, algorithmInfoType)
+B_Algorithm *algorithm;
+POINTER *info;
+B_AlgorithmInfoType *algorithmInfoType;
+{
+  int status;
+  
+  if (algorithm->infoCache.z.infoCount == 0)
+    return (BE_ALGORITHM_NOT_SET);
+
+  /* First check if the encoding is already in the encoding cache.
+   */
+  if (B_InfoCacheFindInfo
+      (&algorithm->infoCache, info, (POINTER)algorithmInfoType) == 0)
+    return (0);
+  
+  /* Info is not in the cache, go ahead and encode.
+   */
+  if ((status = (*algorithmInfoType->vTable->MakeInfo)
+       (algorithmInfoType, info, algorithm)) != 0)
+    return (status);
+
+  return (B_InfoCacheAddInfo
+          (&algorithm->infoCache, (POINTER)algorithmInfoType, *info));
+}
+
diff --git a/lib/bind/dnssafe/balg.h b/lib/bind/dnssafe/balg.h
new file mode 100644 (file)
index 0000000..517a69c
--- /dev/null
@@ -0,0 +1,116 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _BALG_H_
+#define _BALG_H_ 1
+
+#include "binfocsh.h"
+#include "btypechk.h"
+
+typedef struct {
+  B_InfoCache infoCache;                                        /* inherited */
+
+  struct {
+    B_TypeCheck *handler;
+    int initFlag;
+    /* POINTER reserved; */
+  } z;
+} B_Algorithm;
+
+void B_AlgorithmConstructor PROTO_LIST ((B_Algorithm *));
+void B_AlgorithmDestructor PROTO_LIST ((B_Algorithm *));
+
+int B_AlgorithmCheckType PROTO_LIST ((B_Algorithm *, B_TYPE_CHECK_DESTRUCTOR));
+int B_AlgorithmCheckTypeAndInitFlag PROTO_LIST
+  ((B_Algorithm *, B_TYPE_CHECK_DESTRUCTOR));
+
+struct B_AlgorithmInfoType;
+int B_AlgorithmSetInfo PROTO_LIST
+  ((B_Algorithm *, struct B_AlgorithmInfoType *, POINTER));
+int B_AlgorithmGetInfo PROTO_LIST
+  ((B_Algorithm *, POINTER *, struct B_AlgorithmInfoType *));
+
+int B_AlgorithmRandomInit PROTO_LIST
+  ((B_Algorithm *, B_ALGORITHM_CHOOSER, A_SURRENDER_CTX *));
+int B_AlgorithmRandomUpdate PROTO_LIST
+  ((B_Algorithm *, unsigned char *, unsigned int, A_SURRENDER_CTX *));
+int B_AlgorithmGenerateRandomBytes PROTO_LIST
+  ((B_Algorithm *, unsigned char *, unsigned int, A_SURRENDER_CTX *));
+
+int B_AlgorithmDigestInit PROTO_LIST
+  ((B_Algorithm *, B_Key *, B_ALGORITHM_CHOOSER, A_SURRENDER_CTX *));
+int B_AlgorithmDigestUpdate PROTO_LIST
+  ((B_Algorithm *, const unsigned char *, unsigned int, A_SURRENDER_CTX *));
+int B_AlgorithmDigestFinal PROTO_LIST
+  ((B_Algorithm *, unsigned char *, unsigned int *, unsigned int,
+    A_SURRENDER_CTX *));
+
+int B_AlgorithmEncryptInit PROTO_LIST
+  ((B_Algorithm *, B_Key *, B_ALGORITHM_CHOOSER, A_SURRENDER_CTX *));
+int B_AlgorithmDecryptInit PROTO_LIST
+  ((B_Algorithm *, B_Key *, B_ALGORITHM_CHOOSER, A_SURRENDER_CTX *));
+int B_AlgorithmEncryptUpdate PROTO_LIST
+  ((B_Algorithm *, unsigned char *, unsigned int *, unsigned int,
+    unsigned char *, unsigned int, B_Algorithm *, A_SURRENDER_CTX *));
+int B_AlgorithmDecryptUpdate PROTO_LIST
+  ((B_Algorithm *, unsigned char *, unsigned int *, unsigned int,
+    const unsigned char *, unsigned int, B_Algorithm *, A_SURRENDER_CTX *));
+int B_AlgorithmEncryptFinal PROTO_LIST
+  ((B_Algorithm *, unsigned char *, unsigned int *, unsigned int,
+    B_Algorithm *, A_SURRENDER_CTX *));
+int B_AlgorithmDecryptFinal PROTO_LIST
+  ((B_Algorithm *, unsigned char *, unsigned int *, unsigned int,
+    B_Algorithm *, A_SURRENDER_CTX *));
+
+int B_AlgorithmEncodeInit PROTO_LIST ((B_Algorithm *));
+int B_AlgorithmDecodeInit PROTO_LIST ((B_Algorithm *));
+int B_AlgorithmEncodeUpdate PROTO_LIST
+  ((B_Algorithm *, unsigned char *, unsigned int *, unsigned int,
+    unsigned char *, unsigned int));
+int B_AlgorithmDecodeUpdate PROTO_LIST
+  ((B_Algorithm *, unsigned char *, unsigned int *, unsigned int,
+    unsigned char *, unsigned int));
+int B_AlgorithmEncodeFinal PROTO_LIST
+  ((B_Algorithm *, unsigned char *, unsigned int *, unsigned int));
+int B_AlgorithmDecodeFinal PROTO_LIST
+  ((B_Algorithm *, unsigned char *, unsigned int *, unsigned int));
+
+int B_AlgorithmSignInit PROTO_LIST
+  ((B_Algorithm *, B_Key *, B_ALGORITHM_CHOOSER, A_SURRENDER_CTX *));
+int B_AlgorithmSignUpdate PROTO_LIST
+  ((B_Algorithm *, unsigned char *, unsigned int, A_SURRENDER_CTX *));
+int B_AlgorithmSignFinal PROTO_LIST
+  ((B_Algorithm *, unsigned char *, unsigned int *, unsigned int,
+    B_Algorithm *, A_SURRENDER_CTX *));
+
+int B_AlgorithmVerifyInit PROTO_LIST
+  ((B_Algorithm *, B_Key *, B_ALGORITHM_CHOOSER, A_SURRENDER_CTX *));
+int B_AlgorithmVerifyUpdate PROTO_LIST
+  ((B_Algorithm *, unsigned char *, unsigned int, A_SURRENDER_CTX *));
+int B_AlgorithmVerifyFinal PROTO_LIST
+  ((B_Algorithm *, unsigned char *, unsigned int, B_Algorithm *,
+    A_SURRENDER_CTX *));
+
+int B_AlgorithmKeyAgreeInit PROTO_LIST
+  ((B_Algorithm *, B_Key *, B_ALGORITHM_CHOOSER, A_SURRENDER_CTX *));
+int B_AlgorithmKeyAgreePhase1 PROTO_LIST
+  ((B_Algorithm *, unsigned char *, unsigned int *, unsigned int,
+    B_Algorithm *, A_SURRENDER_CTX *));
+int B_AlgorithmKeyAgreePhase2 PROTO_LIST
+  ((B_Algorithm *, unsigned char *, unsigned int *, unsigned int,
+    unsigned char *, unsigned int, A_SURRENDER_CTX *));
+
+int B_AlgorithmGenerateInit PROTO_LIST
+  ((B_Algorithm *, B_ALGORITHM_CHOOSER, A_SURRENDER_CTX *));
+int B_AlgorithmGenerateKeypair PROTO_LIST
+  ((B_Algorithm *, B_Key *, B_Key *, B_Algorithm *,
+    A_SURRENDER_CTX *));
+int B_AlgorithmGenerateParameters PROTO_LIST
+  ((B_Algorithm *, B_Algorithm *, B_Algorithm *, A_SURRENDER_CTX *));
+
+#endif
diff --git a/lib/bind/dnssafe/balgmeth.h b/lib/bind/dnssafe/balgmeth.h
new file mode 100644 (file)
index 0000000..c73e3ad
--- /dev/null
@@ -0,0 +1,18 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+struct B_AlgorithmInfoType;
+struct B_KeyInfoType;
+
+struct B_ALGORITHM_METHOD {
+  struct B_AlgorithmInfoType *algorithmInfoType;
+  int encryptFlag;
+  struct B_KeyInfoType *keyInfoType;
+  POINTER alga;
+};
+
diff --git a/lib/bind/dnssafe/bgclrbit.c b/lib/bind/dnssafe/bgclrbit.c
new file mode 100644 (file)
index 0000000..0516928
--- /dev/null
@@ -0,0 +1,30 @@
+/* Copyright (C) RSA Data Security, Inc. created 1986, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bigmath.h"
+#include "port_after.h"
+
+/* BigClrbit (a, v) -- clears v-th bit of a, where v is nonnegative.
+ */
+void BigClrbit (a, v)
+UINT2 *a;
+unsigned int v;
+{ 
+  a[v/16] &= ~ (1 << (v % 16)); 
+}
+
+/* BigSetbit (a, v) -- sets v-th bit of a, where v is nonnegative.
+ */
+void BigSetbit (a, v)
+UINT2 *a;
+unsigned int v;
+{ 
+  a[v/16] |= (1 << (v % 16)); 
+}
diff --git a/lib/bind/dnssafe/bgmdmpyx.c b/lib/bind/dnssafe/bgmdmpyx.c
new file mode 100644 (file)
index 0000000..53b191f
--- /dev/null
@@ -0,0 +1,28 @@
+/* Copyright (C) RSA Data Security, Inc. created 1986, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bigmath.h"
+#include "port_after.h"
+
+/* BigModMpyx (a, b, c, d, dInv, n) -- a = (b * c) mod d !! EXPRESS.
+     -- assumes a, b, c, d of length n, dInv of length n+2.
+     -- assumes dInv previously computed by BigInv.
+ */
+void BigModMpyx (a, b, c, d, dInv, n)
+UINT2 *a, *b, *c, *d, *dInv;
+unsigned int n;
+{
+  UINT2 prod[2 * MAX_RSA_MODULUS_WORDS];
+
+  BigPmpy (prod, b, c, n);
+  BigModx (a, prod, d, dInv, n);
+
+  T_memset ((POINTER)prod, 0, sizeof (prod));
+}
diff --git a/lib/bind/dnssafe/bgmdsqx.c b/lib/bind/dnssafe/bgmdsqx.c
new file mode 100644 (file)
index 0000000..95be98b
--- /dev/null
@@ -0,0 +1,26 @@
+/* Copyright (C) RSA Data Security, Inc. created 1986, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bigmath.h"
+#include "port_after.h"
+
+/* BigModSqx (a, b, d, dInv, n) -- a = (b * b) mod d !! EXPRESS.
+ */
+void BigModSqx (a, b, d, dInv, n)
+UINT2 *a, *b, *d, *dInv;
+unsigned int n;
+{
+  UINT2 prod[2 * MAX_RSA_MODULUS_WORDS];
+
+  BigPsq (prod, b, n);
+  BigModx (a, prod, d, dInv, n);
+
+  T_memset ((POINTER)prod, 0, sizeof (prod));
+}
diff --git a/lib/bind/dnssafe/bgmodexp.c b/lib/bind/dnssafe/bgmodexp.c
new file mode 100644 (file)
index 0000000..d548d68
--- /dev/null
@@ -0,0 +1,134 @@
+/* Copyright (C) RSA Data Security, Inc. created 1986, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bigmath.h"
+#include "surrendr.h"
+#include "port_after.h"
+
+/* BigModExp (a, b, c, d, n): a = b**c (mod d)
+   Assumes a, b, c, d of length n.
+   Returns 0, AE_CANCEL.
+ */
+int BigModExp (a, b, c, d, n, surrenderContext) 
+UINT2 *a, *b, *c, *d;
+unsigned int n;
+A_SURRENDER_CTX *surrenderContext;
+{
+  struct BigModExpFrame {
+    UINT2 dInv[MAX_RSA_MODULUS_WORDS + 2], result[MAX_RSA_MODULUS_WORDS], 
+      tab[16][MAX_RSA_MODULUS_WORDS];
+  } *frame = (struct BigModExpFrame *)NULL_PTR;
+#if !USE_ALLOCED_FRAME
+  struct BigModExpFrame stackFrame;
+#endif
+  int i, didAMultiply, status;
+  unsigned int cLen, w, setup[64], power, mask;
+
+  /* Initialize.
+   */
+  do {
+#if USE_ALLOCED_FRAME
+    if ((frame = (struct BigModExpFrame *)T_malloc (sizeof (*frame)))
+        == (struct BigModExpFrame *)NULL_PTR) {
+      status = AE_ALLOC;
+      break;
+    }
+#else
+    /* Just use the buffers allocated on the stack. */
+    frame = &stackFrame;
+#endif
+
+    /* precompute inverse of d to enable express mod-outs */
+    BigInv (frame->dInv, d, n);
+    if ((status = CheckSurrender (surrenderContext)) != 0)
+      break;
+    
+    /* precompute small (size 2**w) table of powers of b */
+    cLen = BigLen (c, n);
+    if (cLen < 4)
+      w = 1;
+    else if (cLen < 16)
+      w = 2;
+    else if (cLen < 64)
+      w = 3;
+    else
+      w = 4; 
+
+    /* zeroth power is one */
+    BigConst (frame->tab[0], 1, n);
+
+    /* first power is b */
+    BigCopy (frame->tab[1], b, n);
+    setup[0] = 1;
+    setup[1] = 1;
+    for (i = 2; i < 64; i++)
+      setup[i] = 0;
+
+    /* Loop over elements of exponent c in appropriate radix.
+     */
+    power = 0;
+    didAMultiply = 0;
+    mask = 1 << ((cLen) % 16);
+    for (i = cLen; i >= 0; i--) {
+      if (didAMultiply) {
+        BigModSqx (frame->result, frame->result, d, frame->dInv, n);
+        if ((status = CheckSurrender (surrenderContext)) != 0)
+          break;
+      }
+
+      power = power << 1;
+      if (setup[power] == 0) {
+        BigModSqx (frame->tab[power], frame->tab[power/2], d, frame->dInv, n);
+        if ((status = CheckSurrender (surrenderContext)) != 0)
+          break;
+        setup[power] = 1;
+      }
+      if (c[i/16] & mask)
+        power = power + 1;
+      if (mask == 1)
+        mask = 0x8000;
+      else
+        mask = (mask >> 1) & 0x7FFF;
+      if (setup[power] == 0) {
+        BigModMpyx
+          (frame->tab[power], frame->tab[power-1], b, d, frame->dInv, n);
+        if ((status = CheckSurrender (surrenderContext)) != 0)
+          break;
+        setup[power] = 1;
+      }
+      if ((i == 0) || (power >= (unsigned int)(1 << (w-1)))) {
+        if (didAMultiply) {
+          BigModMpyx
+            (frame->result, frame->result, frame->tab[power], d, frame->dInv,
+             n);
+          if ((status = CheckSurrender (surrenderContext)) != 0)
+            break;
+        }
+        else
+          BigCopy (frame->result, frame->tab[power], n);
+      
+        power = 0;
+        didAMultiply = 1;
+      }
+    }
+    if (status)
+      break;
+
+    BigCopy (a, frame->result, n);
+  } while (0);
+
+  if (frame != (struct BigModExpFrame *)NULL_PTR) {
+    T_memset ((POINTER)frame, 0, sizeof (*frame));
+#if USE_ALLOCED_FRAME
+    T_free ((POINTER)frame);
+#endif
+  }
+  return (status);
+}
diff --git a/lib/bind/dnssafe/bgpegcd.c b/lib/bind/dnssafe/bgpegcd.c
new file mode 100644 (file)
index 0000000..eedfe79
--- /dev/null
@@ -0,0 +1,80 @@
+/* Copyright (C) RSA Data Security, Inc. created 1986, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bigmath.h"
+#include "port_after.h"
+
+/* BigPegcd
+     input
+     u, v     bignums
+     k       int size of u, v regs
+     restriction u, v positive
+     output
+     u3=GCD (u, v)     (pos)
+     u1=inv (u)modv   (pos)
+     u2=inv (v)modu   (pos)
+     if GCD (u, v)!=1 then u1, u2 st
+     u3=u * u1mod (v) & u3=v * u2mod (u)
+     (see KNUTH vol 2)
+ */
+void BigPegcd (u3, u1, u2, u, v, k)
+UINT2 *u3, *u2, *u1, *u, *v;
+unsigned int k;
+{
+  UINT2 v1[2 * MAX_RSA_PRIME_WORDS], v2[2 * MAX_RSA_PRIME_WORDS], 
+    v3[2 * MAX_RSA_PRIME_WORDS], q[2 * MAX_RSA_PRIME_WORDS],
+    r[2 * MAX_RSA_PRIME_WORDS], t1[2 * MAX_RSA_PRIME_WORDS],
+    t2[2 * MAX_RSA_PRIME_WORDS], t3[2 * MAX_RSA_PRIME_WORDS];
+
+  BigConst (u1, 1, k);
+  BigConst (u2, 0, k);
+  BigCopy (u3, u, k);
+  BigConst (v1, 0, k);
+  BigConst (v2, 1, k);
+  BigCopy (v3, v, k);
+
+  /* Begin calc.
+   */
+  while (1) {
+    if (BigSign (v3, k) == 0)
+      break;
+    BigPdiv (q, r, u3, v3, k, k);
+    BigPmpyl (t1, v1, q, k);
+    BigPmpyl (t2, v2, q, k);
+    BigPmpyl (t3, v3, q, k);
+    BigSub (t1, u1, t1, k);
+    BigSub (t2, u2, t2, k);
+    BigSub (t3, u3, t3, k);
+
+    BigCopy (u1, v1, k);
+    BigCopy (u2, v2, k);
+    BigCopy (u3, v3, k);
+    BigCopy (v1, t1, k);
+    BigCopy (v2, t2, k);
+    BigCopy (v3, t3, k);
+  }
+
+  if (BigSign (u1, k) == -1)
+    /* make positive */
+    BigAdd (u1, u1, v, k);
+
+  if (BigSign (u2, k) == -1)
+    /* make positive */
+    BigAdd (u2, u2, u, k);
+
+  T_memset ((POINTER)v1, 0, sizeof (v1));
+  T_memset ((POINTER)v2, 0, sizeof (v2));
+  T_memset ((POINTER)v3, 0, sizeof (v3));
+  T_memset ((POINTER)q, 0, sizeof (q));
+  T_memset ((POINTER)r, 0, sizeof (r));
+  T_memset ((POINTER)t1, 0, sizeof (t1));
+  T_memset ((POINTER)t2, 0, sizeof (t2));
+  T_memset ((POINTER)t3, 0, sizeof (t3));
+}
diff --git a/lib/bind/dnssafe/big2exp.c b/lib/bind/dnssafe/big2exp.c
new file mode 100644 (file)
index 0000000..c0793e2
--- /dev/null
@@ -0,0 +1,27 @@
+/* Copyright (C) RSA Data Security, Inc. created 1986, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bigmath.h"
+#include "port_after.h"
+
+/* Big2Exp (a, v, n) -- a = 2**v, where v is nonnegative int.  
+   Sets a to be 2**v.
+ */
+void Big2Exp (a, v, n)
+UINT2 *a;
+unsigned v;
+unsigned int n;
+{
+  register unsigned int i;
+
+  for (i = 0; i < n; i++)
+    a[i] = 0;
+  a[v/16] = 1 << (v % 16);
+}
diff --git a/lib/bind/dnssafe/bigabs.c b/lib/bind/dnssafe/bigabs.c
new file mode 100644 (file)
index 0000000..0024cbf
--- /dev/null
@@ -0,0 +1,24 @@
+/* Copyright (C) RSA Data Security, Inc. created 1986, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bigmath.h"
+#include "port_after.h"
+
+/* BigAbs (a, b, n) -- a = ABS (b).
+ */
+void BigAbs (a, b, n)
+UINT2 *a, *b;
+unsigned int n;
+{
+  if (BigSign (b, n) >= 0)
+    BigCopy (a, b, n); 
+  else
+    BigNeg (a, b, n);
+}
diff --git a/lib/bind/dnssafe/bigacc.c b/lib/bind/dnssafe/bigacc.c
new file mode 100644 (file)
index 0000000..3f84836
--- /dev/null
@@ -0,0 +1,36 @@
+/* Copyright (C) RSA Data Security, Inc. created 1987, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bigmath.h"
+#include "port_after.h"
+
+/* Returns carry: vector a = b * vector c.
+ */
+UINT2 BigAcc (a, b, c, n)
+UINT2 *a;
+unsigned int b;
+UINT2 *c;
+unsigned int n;
+{
+  UINT4 bTemp, result = (UINT4)0;
+  register unsigned int i;
+
+  if (!b)
+    return (0);
+
+  bTemp = b;
+  for (i = 0; i < n; i++) {
+    result += bTemp * ((UINT4) c[i]);
+    result += ((UINT4) a[i]);
+    a[i] = (UINT2) result;
+    result >>= 16;
+  }
+  return ((UINT2)result);
+}
diff --git a/lib/bind/dnssafe/bigarith.c b/lib/bind/dnssafe/bigarith.c
new file mode 100644 (file)
index 0000000..04fbe7c
--- /dev/null
@@ -0,0 +1,140 @@
+/* Copyright (C) RSA Data Security, Inc. created 1987, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bigmath.h"
+#include "port_after.h"
+
+void BigZero (a, n)
+UINT2 *a;
+unsigned int n;
+{
+  register unsigned int i;
+  
+  for (i = 0; i < n; i++)
+    a[i] = 0;
+}
+
+void BigAdd (a, b, c, n)
+UINT2 *a, *b, *c;
+unsigned int n;
+{
+  UINT4 result = (UINT4)0;
+  register unsigned int i;
+
+  for (i = 0; i < n; i++) {
+    result += (UINT4) b[i];
+    result += (UINT4) c[i];
+    a[i] = (UINT2) result;
+    result >>= 16;
+  }
+}
+
+void BigSub (a, b, c, n)
+UINT2 *a, *b, *c;
+unsigned int n;
+{
+  UINT4 result = (UINT4)1;                   /* carry bit for negation of c */
+  register unsigned int i;
+
+  for (i = 0; i < n; i++) {
+    result += (UINT4) b[i];
+    result += (((UINT4) ~c[i]) & 0x0000FFFFL);
+    a[i] = (UINT2)result;
+    result >>= 16;
+  }
+}
+
+void BigNeg (a, b, n)
+UINT2 *a, *b;
+unsigned int n;
+{
+  register unsigned int i;
+  unsigned int carry = 1;
+
+  for (i = 0; i < n-1; i++) {
+    a[i] = ~b[i] + carry;
+    if (a[i])
+      carry = 0;
+  }
+  
+  a[i] = ~b[i] + carry;
+}
+
+void BigInc (a, n)
+UINT2 *a;
+unsigned int n;
+{
+  register unsigned int i;
+  unsigned int carry = 1;                                 /* carry to start */
+
+  for (i = 0; i < n-1 && carry; i++) {
+    a[i]++;
+    if (a[i])
+      carry = 0;
+  }
+  
+  if (carry)
+    a[i]++;
+}
+
+void BigDec (a, n)
+UINT2 *a;
+unsigned int n;
+{
+  register unsigned int i;
+  unsigned int borrow = 1;                               /* borrow to start */
+
+  for (i = 0; i < n-1 && borrow; i++) {
+    a[i]--;
+    if (a[i] != 0xFFFF)
+      borrow = 0;
+  }
+  
+  if (borrow)
+    a[i]--;
+}
+
+int BigSign (a, n)
+UINT2 *a;
+unsigned int n;
+{
+  register int i;
+  
+  if (a[n-1] & 0x8000)
+    return (-1);
+  for (i = n-1; i >= 0; i--)
+    if (a[i])
+      return (1);
+  return (0);
+}
+
+void BigCopy (a, b, n)
+UINT2 *a, *b;
+unsigned int n;
+{
+  register unsigned int i;
+  
+  for (i = 0; i < n; i++)
+    a[i] = b[i];
+}
+
+/* Assumes a is nonnegative.
+ */
+unsigned int BigLenw (a, n)
+UINT2 *a;
+unsigned int n;
+{
+  register int i;
+  
+  for (i = n-1; i >= 0; i--)
+    if (a[i])
+      return (i+1);
+  return (0);
+}
diff --git a/lib/bind/dnssafe/bigcmp.c b/lib/bind/dnssafe/bigcmp.c
new file mode 100644 (file)
index 0000000..514e2b9
--- /dev/null
@@ -0,0 +1,36 @@
+/* Copyright (C) RSA Data Security, Inc. created 1986, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bigmath.h"
+#include "port_after.h"
+
+/* Comparison operator.
+   BigCmp (a, b, n) -- returns sign of a-b.
+ */
+int BigCmp (a, b, n)
+UINT2 *a, *b;
+unsigned int n;
+{
+  register int i;
+  int aSign = BigSign (a, n), bSign = BigSign (b, n);
+
+  if (aSign > bSign)
+    return (1);
+  if (aSign < bSign)
+    return (-1);
+  
+  for (i = n-1; i >= 0 && a[i] == b[i]; i--);
+  
+  if (i == -1)
+    return (0);
+  if (a[i] > b[i])
+    return (1);
+  return (-1);
+}
diff --git a/lib/bind/dnssafe/bigconst.c b/lib/bind/dnssafe/bigconst.c
new file mode 100644 (file)
index 0000000..85a6870
--- /dev/null
@@ -0,0 +1,28 @@
+/* Copyright (C) RSA Data Security, Inc. created 1986, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bigmath.h"
+#include "port_after.h"
+
+/* BigConst (a, v, n) -- a = v, where v is an int.  Initialize bignum a to
+     value v.
+ */
+void BigConst (a, v, n)
+UINT2 *a;
+unsigned int v;
+unsigned int n;
+{
+  UINT2 signWord = (((UINT2)v & 0x8000) ? ~0 : 0);
+  register unsigned int i;
+
+  a[0] = (UINT2)v;
+  for (i = 1; i < n; i++)
+    a[i] = signWord;
+}
diff --git a/lib/bind/dnssafe/biginv.c b/lib/bind/dnssafe/biginv.c
new file mode 100644 (file)
index 0000000..047902e
--- /dev/null
@@ -0,0 +1,105 @@
+/* Copyright (C) RSA Data Security, Inc. created 1986, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bigmath.h"
+#include "port_after.h"
+
+static unsigned int Log2 PROTO_LIST ((unsigned int));
+
+/* BigInv (a, b, n) -- compute a as an "inverse" to b, suitable for
+     modding out integers which are < b**2.
+     -- assumes a has n+2 words, b has n words.
+     -- assumes b is a positive integer.
+ */              
+void BigInv (a, b, n)
+UINT2 *a, *b;
+unsigned int n;
+{
+  UINT2 p[2 * (MAX_RSA_MODULUS_WORDS + 2)],
+    q[2 * (MAX_RSA_MODULUS_WORDS + 3)], t1[MAX_RSA_MODULUS_WORDS + 3];
+  register int i;
+  unsigned int bl, u, uw, sw;
+
+  /* Do initializations.
+   */
+  /* 2** (bl-1) <= b < 2 ** bl */
+  bl = BigLen (b, n);
+  u = BigU (2 * bl);
+  
+  /* uw and sw are in words */
+  uw = u/16;
+  sw = (bl - 2) / 16;
+  
+  /* since a = floor ((2**u)/b),  2**(u-bl) < a <= 2**(u-bl+1) */
+
+  /* Initialize a to 1+2**(u-bl) -- we will converge from below.
+   */
+  Big2Exp (a, u - bl, n + 2);
+  BigInc (a, n + 2);
+  
+  /* Copy b to local register.
+   */
+  BigZero (t1, n + 3);
+  BigCopy (t1, b, n);
+
+  /* Convergence is quadratic, so iterate log (len (a)) times.
+   */
+  for (i = 1 + Log2 (u - bl + 1); i > 0; i--) {
+    /* use fast squaring routine to compute p = a**2
+       2**(2 * (u-bl)) < p <= 2**(2 * (u-bl+1)) */
+    BigPsq (p, a, n + 2); 
+
+    /* compute q = b * floor (p/ (2**s))
+       2**(2 * (u-bl)-s+bl-1) <= q <= 2**(2 * (u-bl+1)-s+bl
+       2**(2 * u-bl-s-1) <= q <= 2**(2 * u-bl-s+2) */
+    BigPmpy (q, t1, &p[sw], n + 3);
+
+    /* double a
+       2**(u-bl+1) < a <= 2**(u-bl+2) */
+    BigAdd (a, a, a, n + 2);
+    /* a = a - floor (q/(2**(u-s)))
+       2**(u-bl) < a <= 2**(u-bl+1) + epsilon */
+    BigSub (a, a, &q[uw-sw], n + 2);
+  }
+
+  /* now we are guaranteed that a is not too small */
+  BigInc (a, n + 2);
+
+  while (1) {
+    BigPmpy (p, a, t1, n + 2);
+    /* makes comparison to 2**u easier */
+    BigDec (p, 2 * (n + 2));
+
+    /* a is desired result */
+    if (BigLen (p, 2 * (n + 2)) <= u)
+      break;
+
+    /* a was too big, reduce and try again */
+    BigDec (a, n + 2);
+  }
+
+  T_memset ((POINTER)p, 0, sizeof (p));
+  T_memset ((POINTER)q, 0, sizeof (q));
+  T_memset ((POINTER)t1, 0, sizeof (t1));
+}
+
+/* Log2 (x) -- ceiling of log base 2 of x > 0. Auxiliary function.
+ */
+static unsigned int Log2 (x)
+unsigned int x;
+{
+  unsigned int i;
+
+  x = x - 1;
+  /* now Log2 is equal to len in bits of x */
+  for (i = 0; x > 0; i++, x >>= 1);
+
+  return (i);
+}
diff --git a/lib/bind/dnssafe/biglen.c b/lib/bind/dnssafe/biglen.c
new file mode 100644 (file)
index 0000000..8a9eacb
--- /dev/null
@@ -0,0 +1,30 @@
+/* Copyright (C) RSA Data Security, Inc. created 1986, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bigmath.h"
+#include "port_after.h"
+
+unsigned int BigLen (a, n)
+UINT2 *a;
+unsigned int n;
+{
+  UINT2 signWord = ((a[n-1] & 0x8000) ? ~0 : 0);
+  int i, j;
+  unsigned int k;
+
+  for (i = n-1; i >= 0 && a[i] == signWord; i--);
+  if (i == -1)
+    return (1);  /* len of 0 or -1 */
+
+  for (j = 16, k = 0x8000; 
+       j >= 0 && 0 == (k & (signWord ^ a[i])); 
+       j--, k >>= 1);
+  return (16 * i + j);
+}
diff --git a/lib/bind/dnssafe/bigmath.h b/lib/bind/dnssafe/bigmath.h
new file mode 100644 (file)
index 0000000..0cb5b4b
--- /dev/null
@@ -0,0 +1,71 @@
+/* Copyright (C) RSA Data Security, Inc. created 1992, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _BIGMATH_H_
+#define _BIGMATH_H_ 1
+
+#include "algae.h"
+#include "bigmaxes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void Big2Exp PROTO_LIST ((UINT2 *, unsigned int, unsigned int));
+void BigAbs PROTO_LIST ((UINT2 *, UINT2 *, unsigned int));
+UINT2 BigAcc PROTO_LIST ((UINT2 *, unsigned int, UINT2 *, unsigned int));
+void BigZero PROTO_LIST ((UINT2 *, unsigned int));
+void BigAdd PROTO_LIST ((UINT2 *, UINT2 *, UINT2 *, unsigned int));
+void BigSub PROTO_LIST ((UINT2 *, UINT2 *, UINT2 *, unsigned int));
+void BigNeg PROTO_LIST ((UINT2 *, UINT2 *, unsigned int));
+void BigInc PROTO_LIST ((UINT2 *, unsigned int));
+void BigDec PROTO_LIST ((UINT2 *, unsigned int));
+int BigSign PROTO_LIST ((UINT2 *, unsigned int));
+void BigCopy PROTO_LIST ((UINT2 *, UINT2 *, unsigned int));
+unsigned int BigLenw PROTO_LIST ((UINT2 *, unsigned int));
+void BigClrbit PROTO_LIST ((UINT2 *, unsigned int));
+void BigSetbit PROTO_LIST ((UINT2 *, unsigned int));
+int BigCmp PROTO_LIST ((UINT2 *, UINT2 *, unsigned int));
+void BigConst PROTO_LIST ((UINT2 *, unsigned int, unsigned int));
+void BigInv PROTO_LIST ((UINT2 *, UINT2 *, unsigned int));
+unsigned int BigLen PROTO_LIST ((UINT2 *, unsigned int));
+void BigModMpyx PROTO_LIST
+  ((UINT2 *, UINT2 *, UINT2 *, UINT2 *, UINT2 *, unsigned int));
+void BigModSqx PROTO_LIST
+  ((UINT2 *, UINT2 *, UINT2 *, UINT2 *, unsigned int));
+int BigModExp PROTO_LIST
+  ((UINT2 *, UINT2 *, UINT2 *, UINT2 *, unsigned int, A_SURRENDER_CTX *));
+void BigModx PROTO_LIST
+  ((UINT2 *, UINT2 *, UINT2 *, UINT2 *, unsigned int));
+void BigMpy PROTO_LIST ((UINT2 *, UINT2 *, UINT2 *, unsigned int));
+void BigPdiv PROTO_LIST
+  ((UINT2 *, UINT2 *, UINT2 *, UINT2 *, unsigned int , unsigned int));
+void BigPegcd PROTO_LIST
+  ((UINT2 *, UINT2 *, UINT2 *, UINT2 *, UINT2 *, unsigned int));
+void BigPmpy PROTO_LIST ((UINT2 *, UINT2 *, UINT2 *, unsigned int));
+void BigPmpyh PROTO_LIST
+  ((UINT2 *, UINT2 *, UINT2 *, unsigned int, unsigned int));
+void BigPmpyl PROTO_LIST ((UINT2 *, UINT2 *, UINT2 *, unsigned int));
+void BigPsq PROTO_LIST ((UINT2 *, UINT2 *, unsigned int));
+void BigQrx PROTO_LIST
+  ((UINT2 *, UINT2 *, UINT2 *, UINT2 *, UINT2 *, unsigned int));
+UINT2 BigSmod PROTO_LIST ((UINT2 *, unsigned int, unsigned int));
+int BigToCanonical PROTO_LIST
+  ((unsigned char *, unsigned int, UINT2 *, unsigned int));
+unsigned int BigU PROTO_LIST ((unsigned int));
+int BigUnexp PROTO_LIST
+  ((UINT2 *, UINT2 *, UINT2 *, UINT2 *, UINT2 *, UINT2 *, UINT2 *,
+    unsigned int, A_SURRENDER_CTX *));
+int CanonicalToBig PROTO_LIST
+  ((UINT2 *, unsigned int, const unsigned char *, unsigned int));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/bind/dnssafe/bigmaxes.h b/lib/bind/dnssafe/bigmaxes.h
new file mode 100644 (file)
index 0000000..17182cb
--- /dev/null
@@ -0,0 +1,47 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _BIGMAXES_H_
+#define _BIGMAXES_H_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MAX_RSA_MODULUS_BITS 4096
+
+#define BITS_TO_LEN(modulusBits) (((modulusBits) + 7) / 8)
+#define RSA_PRIME_BITS(modulusBits) (((modulusBits) + 1) / 2)
+#define RSA_PRIME_LEN(modulusBits) ((RSA_PRIME_BITS (modulusBits) + 7) / 8)
+#define BITS_TO_WORDS(bits) ((bits >> 4) + 1)
+#define LEN_TO_WORDS(len) ((len >> 1) + 1)
+
+/* MAX_RSA_PRIME_BITS -- length in bits of the maximum allowed RSA prime
+   MAX_RSA_MODULUS_LEN -- length in bytes of the maximum allowed RSA modulus,
+                          in canonical format (no sign bit)
+   MAX_RSA_PRIME_LEN -- length in bytes of the maximum allowed RSA prime, in
+                        canonical format (no sign bit)
+ */
+#define MAX_RSA_PRIME_BITS RSA_PRIME_BITS (MAX_RSA_MODULUS_BITS)
+#define MAX_RSA_PRIME_LEN RSA_PRIME_LEN (MAX_RSA_MODULUS_BITS)
+#define MAX_RSA_MODULUS_LEN BITS_TO_LEN (MAX_RSA_MODULUS_BITS)
+
+/* MAX_RSA_MODULUS_WORDS -- length in 16-bit words of the maximum allowed RSA
+                            modulus, in bignum format (including sign bit)
+   MAX_RSA_PRIME_WORDS -- length in 16-bit words of the maximum allowed RSA
+                          prime, in bignum format (including sign bit)
+ */
+
+#define MAX_RSA_MODULUS_WORDS BITS_TO_WORDS (MAX_RSA_MODULUS_BITS)
+#define MAX_RSA_PRIME_WORDS BITS_TO_WORDS (MAX_RSA_PRIME_BITS)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/bind/dnssafe/bigmodx.c b/lib/bind/dnssafe/bigmodx.c
new file mode 100644 (file)
index 0000000..af25041
--- /dev/null
@@ -0,0 +1,27 @@
+/* Copyright (C) RSA Data Security, Inc. created 1986, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bigmath.h"
+#include "port_after.h"
+
+/* BigModx (a, b, c, cInv, n) -- compute a as (b mod c).
+     -- assumes a and c of length n, cInv of length n + 2, b of length 2n.
+     -- assumes cInv computed with BigInv, and that b < c**2.
+ */
+void BigModx (a, b, c, cInv, n)
+UINT2 *a, *b, *c, *cInv;
+unsigned int n;
+{
+  UINT2 q[MAX_RSA_MODULUS_WORDS];
+
+  BigQrx (q, a, b, c, cInv, n);
+
+  T_memset ((POINTER)q, 0, sizeof (q));
+}
diff --git a/lib/bind/dnssafe/bigmpy.c b/lib/bind/dnssafe/bigmpy.c
new file mode 100644 (file)
index 0000000..3bea934
--- /dev/null
@@ -0,0 +1,38 @@
+/* Copyright (C) RSA Data Security, Inc. created 1986, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bigmath.h"
+#include "port_after.h"
+
+/* BigMpy (a, b, c, n) -- a = b * c
+     -- assumes b and c have n words, a has 2*n words
+     -- inputs may be positive or negative.
+ */
+void BigMpy (a, b, c, n)
+UINT2 *a, *b, *c;
+unsigned int n;
+{
+  UINT2 prod[2 * MAX_RSA_PRIME_WORDS], absb[MAX_RSA_PRIME_WORDS], 
+    absc[MAX_RSA_PRIME_WORDS];
+  int bSign = BigSign (b, n), cSign = BigSign (c, n);
+  
+  BigAbs (absb, b, n);
+  BigAbs (absc, c, n);
+  BigPmpy (prod, absb, absc, n);
+
+  if (bSign * cSign >= 0)
+    BigCopy (a, prod, 2 * n);
+  else 
+    BigNeg (a, prod, 2 * n);
+
+  T_memset ((POINTER)prod, 0, sizeof (prod));
+  T_memset ((POINTER)absb, 0, sizeof (absb));
+  T_memset ((POINTER)absc, 0, sizeof (absc));
+}
diff --git a/lib/bind/dnssafe/bigpdiv.c b/lib/bind/dnssafe/bigpdiv.c
new file mode 100644 (file)
index 0000000..92aa189
--- /dev/null
@@ -0,0 +1,161 @@
+/* Copyright (C) RSA Data Security, Inc. created 1986, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bigmath.h"
+#include "port_after.h"
+
+/* BigPdiv          POSITIVE DIVIDE
+     uu=vv * qi+ri
+     uu in reg of ll cells
+     vv in reg of kk cells
+     qi assumed to be ll cells
+     ri assumed to be kk cells
+     restriction uu>=0, vv>0
+       
+     input  uu in reg of ll cells
+     input  vv in reg of kk cells
+     output qi assumed to be ll cells
+     output ri assumed to be kk cells
+     restriction uu>=0, vv>0
+     uu=vv * qi+ri
+ */
+#define UJN (u[(j+n)/2] & mk[(j+n)%2])
+#define VN (v[n/2] & mk[n%2])
+#define UT (u[t/2] & mk[t%2])
+void BigPdiv (qi, ri, uu, vv, ll, kk)
+UINT2 *qi, *ri, *uu, *vv;
+unsigned int ll, kk;
+{
+  UINT2 u[2 * MAX_RSA_PRIME_WORDS + 2], us[2 * MAX_RSA_PRIME_WORDS + 2], 
+    v[2 * MAX_RSA_PRIME_WORDS + 2], vs[2 * MAX_RSA_PRIME_WORDS + 2],
+    q[2 * MAX_RSA_PRIME_WORDS + 2], r[2 * MAX_RSA_PRIME_WORDS + 2],
+    t1[2 * MAX_RSA_PRIME_WORDS + 2], t2[2 * MAX_RSA_PRIME_WORDS + 2],
+    t3[2 * MAX_RSA_PRIME_WORDS + 2], mk[2];
+  int j, l, n, m, t, x;
+  unsigned int a, b, c, d, e, vh, qq;
+
+  if (ll >= kk)
+    l = ll + 2;
+  else
+    l = kk + 2;
+  
+  mk[0] = 0x00FF;
+  mk[1] = 0xFF00;
+  b = 0x0100;
+
+  BigConst (u, 0, l);
+  BigConst (v, 0, l);
+  BigCopy (u, uu, ll);
+  BigCopy (us, u, l);
+  BigCopy (v, vv, kk);
+  BigCopy (vs, v, l);
+
+  /* zero q */
+  BigConst (q, 0, l);
+
+  /* Calculate len of v=n.
+   */
+  for (n = (2 * l) - 1; n >= 0; n--) {
+    if (VN == 0)
+      continue;
+    break;
+  }
+
+  /* Normalize.
+   */
+  a = VN;
+  if (n % 2 == 1)
+    a = a >> 8;
+  d = b / (a+1);
+  BigConst (t1, d, l);
+  BigPmpyl (t2, t1, v, l);
+  BigCopy (v, t2, l);
+  
+  /* vh=high order digit of normalized v */
+  vh = VN;
+  if (n % 2 == 1)
+    vh = vh >> 8;
+  BigPmpyl (t2, t1, u, l);
+  BigCopy (u, t2, l);
+
+  /* Calculate len of u=t.
+   */
+  for (t = (2 * l)-1; t >= 0; t--) {
+    if (UT == 0)
+      continue;
+    break;
+  }
+  
+  /* calc t = n + m */
+  m = t - n;
+
+  /* Divide u by v.
+   */
+  for (j = m + 1 + n; j > n; j--) {
+    if (j % 2 == 1)
+      c = u[j / 2];
+    else {
+      a = u[j/2];
+      a = a << 8;
+      e = u[(j - 1) / 2];
+      e = e >> 8;
+      c = a + e;
+    }
+    a = c >> 8;
+    if (vh == a)
+      qq = b - 1;
+    else
+      qq = c / vh;
+
+    BigConst (t1, qq, l);
+    BigPmpyl (t2, v, t1, l);
+    Big2Exp (t3, (j - 1 - n) * 8, l);
+    BigPmpyl (t1, t3, t2, l);
+    BigSub (t2, u, t1, l);
+
+    /* Adjust q.
+     */
+    for (x = 0; ; qq --, x ++) {
+      if (BigSign (t2, l) != -1)
+        break;
+      BigPmpyl (t1, t3, v, l);
+      BigAdd (t2, t2, t1, l);
+    }
+
+    BigCopy (u, t2, l);
+    BigConst (t3, qq, l);
+    Big2Exp (t2, 8, l);
+    BigPmpyl (t1, q, t2, l);
+    BigAdd (q, t3, t1, l);
+  }
+  
+  /* Check result.
+   */
+
+  BigPmpyl (t1, vs, q, l);
+  /* t2 has remainder */
+  BigSub (t2, us, t1, l);
+
+  BigSub (t3, vs, t2, l);
+
+  /* transfer results to input registers  */
+  BigCopy (qi, q, ll);
+  BigCopy (ri, t2, kk);
+  
+  T_memset ((POINTER)u, 0, sizeof (u));
+  T_memset ((POINTER)us, 0, sizeof (us));
+  T_memset ((POINTER)v, 0, sizeof (v));
+  T_memset ((POINTER)vs, 0, sizeof (vs));
+  T_memset ((POINTER)q, 0, sizeof (q));
+  T_memset ((POINTER)r, 0, sizeof (r));
+  T_memset ((POINTER)t1, 0, sizeof (t1));
+  T_memset ((POINTER)t2, 0, sizeof (t2));
+  T_memset ((POINTER)t3, 0, sizeof (t3));
+}
diff --git a/lib/bind/dnssafe/bigpmpy.c b/lib/bind/dnssafe/bigpmpy.c
new file mode 100644 (file)
index 0000000..ff5b441
--- /dev/null
@@ -0,0 +1,27 @@
+/* Copyright (C) RSA Data Security, Inc. created 1987, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bigmath.h"
+#include "port_after.h"
+
+/* a = b * c.
+ */
+void BigPmpy (a, b, c, n)
+UINT2 *a, *b, *c;
+unsigned int n;
+{
+  register unsigned int i;
+  unsigned int cLen;
+  
+  BigZero (a, 2*n);
+  cLen = BigLenw (c, n);
+  for (i = 0; i < n; i++)
+    a[cLen+i] = BigAcc (&a[i], (unsigned int)b[i], c, cLen);
+}
diff --git a/lib/bind/dnssafe/bigpmpyh.c b/lib/bind/dnssafe/bigpmpyh.c
new file mode 100644 (file)
index 0000000..94fcc25
--- /dev/null
@@ -0,0 +1,32 @@
+/* Copyright (C) RSA Data Security, Inc. created 1987, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bigmath.h"
+#include "port_after.h"
+
+/* Returns high order t bytes of result.
+ */
+void BigPmpyh (a, b, c, t, n)
+UINT2 *a, *b, *c;
+unsigned int t, n;
+{
+  register unsigned int i;
+  unsigned int iStart, cLen, j;
+
+  BigZero (a, 2*n);
+  cLen = BigLenw (c, n);
+  iStart = (t >= n-1) ? t - (n-1) : 0;
+
+  for (i = iStart; i < n; i++) {
+    j = (t >= i) ? t - i : 0;
+    a[cLen+i] = BigAcc
+      (&a[i+j], (unsigned int)b[i], &c[j], (cLen >= j) ? cLen-j : 0);
+  }
+}
diff --git a/lib/bind/dnssafe/bigpmpyl.c b/lib/bind/dnssafe/bigpmpyl.c
new file mode 100644 (file)
index 0000000..dffd70d
--- /dev/null
@@ -0,0 +1,32 @@
+/* Copyright (C) RSA Data Security, Inc. created 1987, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bigmath.h"
+#include "port_after.h"
+
+/* Single precision multiply, a is same len as b and c.
+   Returns low order n bytes of result.
+ */
+void BigPmpyl (a, b, c, n)
+UINT2 *a, *b, *c;
+unsigned int  n;
+{
+  register unsigned int i;
+  unsigned int cLen;
+
+  BigZero (a, n);
+  cLen = BigLenw (c, n);
+  for (i = 0; i < n; i++) {
+    if (cLen < n-i)
+      a[cLen+i] = BigAcc (&a[i], (unsigned int)b[i], c, cLen);
+    else
+      BigAcc (&a[i], (unsigned int)b[i], c, n-i);
+  }
+}
diff --git a/lib/bind/dnssafe/bigpsq.c b/lib/bind/dnssafe/bigpsq.c
new file mode 100644 (file)
index 0000000..97f0366
--- /dev/null
@@ -0,0 +1,44 @@
+/* Copyright (C) RSA Data Security, Inc. created 1987, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bigmath.h"
+#include "port_after.h"
+
+/* Similar to BigPmpy (a, b, b, n) but faster.
+ */
+void BigPsq (a, b, n)
+UINT2 *a, *b;
+unsigned int n;
+{
+  UINT4 result = (UINT4)0;
+  register unsigned int i;
+  unsigned int bLen;
+
+  BigZero (a, 2*n);
+  bLen = BigLenw (b, n);
+  if (!bLen)
+    return;
+
+  for (i = 0; i < bLen-1; i++)
+    a[bLen+i] = BigAcc (&a[2*i+1], (unsigned int)b[i], &b[i+1], bLen-i-1);
+  BigAdd (a, a, a, 2*n);
+
+  /* add in trace b[i] * b[i] */
+  for (i = 0; i < bLen; i++) {
+    result += ((UINT4)b[i]) * ((UINT4)b[i]);
+    result += (UINT4)a[2*i];
+    a[2*i] = (UINT2)result;
+    result >>= 16;
+    result += (UINT4)a[2*i+1];
+    a[2*i+1] = (UINT2)result;
+    result >>= 16;
+  }
+  a[2*i] = (UINT2)result;
+}
diff --git a/lib/bind/dnssafe/bigqrx.c b/lib/bind/dnssafe/bigqrx.c
new file mode 100644 (file)
index 0000000..2e27ee2
--- /dev/null
@@ -0,0 +1,87 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bigmath.h"
+#include "port_after.h"
+
+
+/* BigQrx (q, r, b, c, cInv, n) -- compute quotient and remainder fast.
+     -- computes q and r s.t. b = q * c + r with 0 <= r < c.
+     -- assumes b and c are positive integers.
+     -- assumes q, r, c have n words, cInv has n+2 words, b has 2*n words.
+     -- assumes cInv previously computed with BigInv.
+ */
+void BigQrx (q, r, b, c, cInv, n)
+UINT2 *q, *r, *b, *c, *cInv;
+unsigned int n;
+{
+  UINT2 qc[2 * (MAX_RSA_MODULUS_WORDS + 2)],  /* current product of q and c */
+    qsc[2 * (MAX_RSA_MODULUS_WORDS + 2)], /* temporary q scaled by 2**(u-s) */
+    t1[2 * MAX_RSA_MODULUS_WORDS + 2];
+  int uwsw3;
+  register unsigned int i;
+  unsigned int u, uw, cl, sw;
+
+  /* 2**(cl-1) <= c < 2**cl
+     2**(u-cl) <= cInv <= 2**(u-cl+1) */
+  cl = BigLen (c, n);
+                 
+  /* u is in bits, uw is in words */
+  u = BigU (2 * cl);
+  uw = u/16;
+  
+  /* sw is in words, s is is bits */
+  sw = (cl - 2) / 16;
+  
+  uwsw3 = uw - sw - 3;
+  
+  if (uwsw3 < 0)
+    uwsw3 = 0;
+
+  /* Copy b to local register.
+   */
+  BigZero (t1, 2 * n + 2);
+  BigCopy (t1, b, 2 * n);
+
+  /* Compute qsc = cInv * floor (b/ (2**s)).
+     qsc an approximation to (b/c) * (2**(u-s))
+       2**((u-cl)+ (bl-1-s)) <= qsc 2**((u-cl+1)+ (bl-s))
+       2**(u-cl+bl-s-1) <= qsc <= 2 ** (u-cl+bl-s+1)
+     (Actually, we only compute a "high-order" approximation
+       to qsc, by using BigPmpyh.)
+   */
+  BigPmpyh (qsc, cInv, &t1[sw], uwsw3, n + 2);
+
+  /* Divide by 2**(u-s) to get initial estimate for quotient q
+       2**(bl-cl-1) <= q <= 2**(bl-cl+1) (unless q = 0).
+   */
+  for (i = 0; i < n; i++)
+    q[i] = qsc[i+ (uw - sw)];
+
+  /* compute qc = low-order part of q * c
+       2 ** (bl - 2) <= qc <= 2 ** (bl + 1) */
+  BigPmpyl (qc, q, c, n);
+
+  /* subtract qc from b to get initial estimate for remainder r */
+  BigSub (r, b, qc, n);
+
+  /* Adjust to be exactly right by repeated subtraction.
+   */
+  while (BigCmp (r, c, n) >= 0) {
+    BigSub (r, r, c, n);
+    BigInc (q, n);
+  }
+  
+  T_memset ((POINTER)qc, 0, sizeof (qc));
+  T_memset ((POINTER)qsc, 0, sizeof (qsc));
+  T_memset ((POINTER)t1, 0, sizeof (t1));
+}
+
+
diff --git a/lib/bind/dnssafe/bigsmod.c b/lib/bind/dnssafe/bigsmod.c
new file mode 100644 (file)
index 0000000..7e54ff9
--- /dev/null
@@ -0,0 +1,30 @@
+/* Copyright (C) RSA Data Security, Inc. created 1987, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bigmath.h"
+#include "port_after.h"
+
+UINT2 BigSmod (a, v, n)
+UINT2 *a;
+unsigned int v;
+unsigned int n;
+{
+  UINT4 r = (UINT4)0;
+  register int i;
+  unsigned int scale;
+
+  scale = (unsigned int)((UINT4)65536 % (UINT4)v);
+
+  for (i = n-1; i >= 0; i--) {
+    r = (r*scale) + (UINT4)a[i];
+    r = r % (UINT4)v;
+  }
+  return ((UINT2)r);
+}
diff --git a/lib/bind/dnssafe/bigtocan.c b/lib/bind/dnssafe/bigtocan.c
new file mode 100644 (file)
index 0000000..2ab03a7
--- /dev/null
@@ -0,0 +1,62 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "algae.h"
+#include "bigmath.h"
+#include "port_after.h"
+
+
+/* BigToCanonical () copies a word vector to a byte vector while REVERSING the
+     order of significance.  The word vector is input LSWord first and the
+     byte vector is written out MSByte first. It also removes a leading zero
+     sign bit. (The byte vector must represent a nonnegative number.)
+   Returns 0, AE_DATA.
+ */
+int BigToCanonical (bytePointer, numBytes, wordPointer, wordCount)
+unsigned char *bytePointer;
+unsigned int numBytes;
+UINT2 *wordPointer;
+unsigned int wordCount;
+{
+  unsigned int copyCount;
+  
+  if (BigSign (wordPointer, wordCount) < 0 ||
+      (BigLen (wordPointer, wordCount) + 7) / 8 > numBytes)
+    return (AE_DATA);
+
+  /* start at end of byte vector */
+  bytePointer += numBytes-1;
+  
+  /* copy as much as possible */
+  copyCount = (wordCount < numBytes / 2) ? wordCount : numBytes / 2;
+  wordCount -= copyCount;
+  numBytes -= 2 * copyCount;
+  while (copyCount--) {
+    /* Copy two bytes.*/
+    *bytePointer-- = (unsigned char)*wordPointer;
+    *bytePointer-- = (unsigned char)(*wordPointer >> 8);
+    wordPointer++;
+  }
+  
+  if (wordCount && numBytes & 1) {
+    /* The number of output bytes was odd. Copy one last byte */
+    *bytePointer-- = (unsigned char)*wordPointer++;
+    wordCount--;
+    numBytes--;
+  }
+  
+  /* zero fill remainder of byte vector */
+  while (numBytes--)
+    *bytePointer-- = 0;
+  
+  return (0);
+}
+
+
diff --git a/lib/bind/dnssafe/bigu.c b/lib/bind/dnssafe/bigu.c
new file mode 100644 (file)
index 0000000..9c51e26
--- /dev/null
@@ -0,0 +1,23 @@
+/* Copyright (C) RSA Data Security, Inc. created 1986, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bigmath.h"
+#include "port_after.h"
+
+/* BigU (t) -- returns length u where floor (2**u/b) is used as scaled version
+     of (1/b) when modding out modulo b, and where (positive) integers to be
+     reduced are < 2**t; i.e. they are at most t bits in length.
+   Result is (t+1) rounded up if necessary to next multiple of 16.
+*/
+unsigned int BigU (t)
+unsigned int t;
+{
+  return (16 * (((t+1) + 15)/16)); 
+}
diff --git a/lib/bind/dnssafe/bigunexp.c b/lib/bind/dnssafe/bigunexp.c
new file mode 100644 (file)
index 0000000..9db9834
--- /dev/null
@@ -0,0 +1,100 @@
+/* Copyright (C) RSA Data Security, Inc. created 1986, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bigmath.h"
+#include "surrendr.h"
+#include "port_after.h"
+
+/* BigUnexp - decrypt ciphertext c into message m using Chinese remainder.
+   Assumes m, c of length 2*pSize, pp, qq, dp, dq and cr of length pSize.
+   Returns 0, AE_CANCEL.
+ */
+int BigUnexp (m, c, pp, qq, dp, dq, cr, pSize, surrenderContext)
+UINT2 *m;                        /* output message       size 2*pSize words */
+UINT2 *c;                              /* input `ciphertext'   size 2*pSize */
+UINT2 *pp;                             /* first prime          size pSize   */
+UINT2 *qq;                             /* second prime;        size pSize   */
+UINT2 *dp;                     /* decryption exponent mod p    size pSize   */
+UINT2 *dq;                     /* decryption exponent mod q    size pSize   */
+UINT2 *cr;              /* CRT coef (inverse of q mod p) cr has len pSize   */
+unsigned int pSize;                                 /* length of p in words */
+A_SURRENDER_CTX *surrenderContext;
+{
+  struct BigUnexpFrame {
+    UINT2 t1[2 * MAX_RSA_PRIME_WORDS], t2[2 * MAX_RSA_PRIME_WORDS], 
+      t3[2 * MAX_RSA_PRIME_WORDS], u1[2 * MAX_RSA_PRIME_WORDS],
+      u2[2 * MAX_RSA_PRIME_WORDS], u3[2 * MAX_RSA_PRIME_WORDS];
+  } *frame = (struct BigUnexpFrame *)NULL_PTR;
+#if !USE_ALLOCED_FRAME
+  struct BigUnexpFrame stackFrame;
+#endif
+  int status;
+
+  do {
+#if USE_ALLOCED_FRAME
+    if ((frame = (struct BigUnexpFrame *)T_malloc (sizeof (*frame)))
+        == (struct BigUnexpFrame *)NULL_PTR) {
+      status = AE_ALLOC;
+      break;
+    }
+#else
+    /* Just use the buffers allocated on the stack. */
+    frame = &stackFrame;
+#endif
+    
+    BigConst (frame->t1, 0, 2 * pSize);
+    BigConst (frame->t2, 0, 2 * pSize);
+  
+    /* u2=c mod p */
+    BigPdiv (frame->u1, frame->u2, c, pp, 2 * pSize, pSize);
+    if ((status = CheckSurrender (surrenderContext)) != 0)
+      break;
+
+    /* t1=c**dp modP */
+    if ((status = BigModExp
+         (frame->t1, frame->u2, dp, pp, pSize, surrenderContext)) != 0)
+      break;
+
+    /* u3=CmodQ */
+    BigPdiv (frame->u2, frame->u3, c, qq, 2 * pSize, pSize);
+    if ((status = CheckSurrender (surrenderContext)) != 0)
+      break;
+
+    /* t2=c**DQmodQ */
+    if ((status = BigModExp
+         (frame->t2, frame->u3, dq, qq, pSize, surrenderContext)) != 0)
+      break;
+
+    /* CRT.
+     */
+    BigSub (frame->u1, frame->t1, frame->t2, pSize);
+
+    while (-1 == BigSign (frame->u1, pSize))
+      BigAdd (frame->u1, frame->u1, pp, pSize);
+
+    BigMpy (frame->u2, frame->u1, cr, pSize);
+    if ((status = CheckSurrender (surrenderContext)) != 0)
+      break;
+    BigPdiv (frame->u3, frame->u1, frame->u2, pp, 2 * pSize, pSize);
+    if ((status = CheckSurrender (surrenderContext)) != 0)
+      break;
+    BigMpy (m, frame->u1, qq, pSize);
+
+    BigAdd (m, m, frame->t2, 2 * pSize);
+  } while (0);
+  
+  if (frame != (struct BigUnexpFrame *)NULL_PTR) {
+    T_memset ((POINTER)frame, 0, sizeof (*frame));
+#if USE_ALLOCED_FRAME
+    T_free ((POINTER)frame);
+#endif
+  }
+  return (status);
+}
diff --git a/lib/bind/dnssafe/binfocsh.c b/lib/bind/dnssafe/binfocsh.c
new file mode 100644 (file)
index 0000000..bde32ea
--- /dev/null
@@ -0,0 +1,65 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "binfocsh.h"
+#include "port_after.h"
+
+void B_InfoCacheConstructor (infoCache)
+B_InfoCache *infoCache;
+{
+  /* Construct immediate base class. */
+  B_MemoryPoolConstructor (&infoCache->memoryPool);
+
+  T_memset ((POINTER)&infoCache->z, 0, sizeof (infoCache->z));
+}
+
+/* Returns 0, BE_ALLOC.
+ */
+int B_InfoCacheAddInfo (infoCache, infoType, info)
+B_InfoCache *infoCache;
+POINTER infoType;
+POINTER info;
+{
+  int status;
+  
+  if ((status = B_MemoryPoolRealloc
+       (&infoCache->memoryPool, (POINTER *)&infoCache->z.infos,
+        (infoCache->z.infoCount + 1) * sizeof (infoCache->z.infos[0]))) != 0)
+    return (status);
+    
+  infoCache->z.infos[infoCache->z.infoCount].infoType = infoType;
+  infoCache->z.infos[infoCache->z.infoCount].info = info;
+  infoCache->z.infoCount++;        
+  
+  return (0);
+}
+
+/* Set info to the entry in the cache for the given infoType.
+   Returns 0, or BE_NOT_SUPPORTED if infoType is not in the cache.
+ */
+int B_InfoCacheFindInfo (infoCache, info, infoType)
+B_InfoCache *infoCache;
+POINTER *info;
+POINTER infoType;
+{
+  unsigned int i;
+  
+  for (i = 0; i < infoCache->z.infoCount; ++i) {
+    if (infoCache->z.infos[i].infoType == infoType) {
+      /* The info has already been constructed. */
+      *info = infoCache->z.infos[i].info;
+      return (0);
+    }
+  }
+  
+  return (BE_NOT_SUPPORTED);
+}
+
diff --git a/lib/bind/dnssafe/binfocsh.h b/lib/bind/dnssafe/binfocsh.h
new file mode 100644 (file)
index 0000000..3277876
--- /dev/null
@@ -0,0 +1,33 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _BINFOCSH_H_
+#define _BINFOCSH_H_ 1
+
+#include "bmempool.h"
+
+typedef struct B_InfoCache {
+  B_MemoryPool memoryPool;                                      /* inherited */
+  struct {
+    unsigned int infoCount;
+    struct {
+      POINTER infoType;
+      POINTER info;
+    } *infos;
+    /* POINTER reserved; */
+  } z;           /* z gives the members that are zeroized by the constructor */
+} B_InfoCache;
+
+void B_InfoCacheConstructor PROTO_LIST ((B_InfoCache *));
+#define B_INFO_CACHE_Destructor(infoCache) \
+  B_MemoryPoolDestructor (&(infoCache)->memoryPool)
+
+int B_InfoCacheAddInfo PROTO_LIST ((B_InfoCache *, POINTER, POINTER));
+int B_InfoCacheFindInfo PROTO_LIST ((B_InfoCache *, POINTER *, POINTER));
+
+#endif
diff --git a/lib/bind/dnssafe/bkey.c b/lib/bind/dnssafe/bkey.c
new file mode 100644 (file)
index 0000000..a4e348d
--- /dev/null
@@ -0,0 +1,103 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "kinfotyp.h"
+#include "kiitem.h"
+#include "port_after.h"
+
+int B_KeySetInfo (key, keyInfoType, info)
+B_Key *key;
+B_KeyInfoType *keyInfoType;
+POINTER info;
+{
+  if (key == (B_Key *)NULL_PTR)
+    return (BE_KEY_OBJ);
+
+  if (key->infoCache.z.infoCount > 0)
+    return (BE_KEY_ALREADY_SET);
+
+  /* This will cache the encoding. */
+  return ((*keyInfoType->AddInfo) (key, info));
+}
+
+int B_KeyGetInfo (key, info, keyInfoType)
+B_Key *key;
+POINTER *info;
+B_KeyInfoType *keyInfoType;
+{
+  int status;
+  
+  if (key == (B_Key *)NULL_PTR)
+    return (BE_KEY_OBJ);
+
+  if (key->infoCache.z.infoCount == 0)
+    return (BE_KEY_NOT_SET);
+
+  /* First check if the encoding is already in the encoding cache.
+   */
+  if (B_InfoCacheFindInfo (&key->infoCache, info, (POINTER)keyInfoType) == 0)
+    return (0);
+  
+  /* Info is not in the cache, go ahead and encode.
+   */
+  if ((status = (*keyInfoType->MakeInfo) (info, key)) != 0)
+    return (status);
+
+  return (B_InfoCacheAddInfo (&key->infoCache, (POINTER)keyInfoType, *info));
+}
+
+/* Create an ITEM out of the data and len and cache it as KITItem.
+   The data is already alloced in the info cache.
+   Returns 0, BE_ALLOC.
+ */
+int B_KeyAddItemInfo (key, data, len)
+B_Key *key;
+unsigned char *data;
+unsigned int len;
+{
+  ITEM *newInfo;
+  int status;
+  
+  if ((status = B_MemoryPoolAlloc
+       (&key->infoCache.memoryPool, (POINTER *)&newInfo, sizeof (*newInfo)))
+      != 0)
+    return (status);
+  
+  newInfo->data = data;
+  newInfo->len = len;
+  
+  return (B_InfoCacheAddInfo
+          (&key->infoCache, (POINTER)&KITItem, (POINTER)newInfo));
+}
+
+/* Return the number of bits in the canonical, positive integer.
+   B_IntegerBits (0) = 0.
+ */
+unsigned int B_IntegerBits (integer, integerLen)
+unsigned char *integer;
+unsigned int integerLen;
+{
+  unsigned char mask, byte;
+  unsigned int bytes, bits;
+  
+  for (bytes = 0; bytes < integerLen && integer[bytes] == 0; bytes++);
+  if (bytes == integerLen)
+    return (0);
+  
+  /* Get byte to test and increment byte count for final calculation */
+  byte = integer[bytes++];
+  
+  /* Get number of bits in most significant byte */
+  for (bits = 8, mask = 0x80; (byte & mask) == 0; bits--, mask >>= 1);
+  return (8 * (integerLen - bytes) + bits);
+}
+
diff --git a/lib/bind/dnssafe/bkey.h b/lib/bind/dnssafe/bkey.h
new file mode 100644 (file)
index 0000000..bfcaca7
--- /dev/null
@@ -0,0 +1,32 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _BKEY_H_
+#define _BKEY_H_ 1
+
+#include "binfocsh.h"
+
+typedef struct {
+  B_InfoCache infoCache;                                        /* inherited */
+
+  /* For now we don't need to worry about a reserved field.
+  struct {
+    POINTER reserved;  
+  } z;
+   */
+} B_Key;
+
+#define B_KEY_Constructor(key) (B_InfoCacheConstructor (&(key)->infoCache))
+#define B_KEY_Destructor(key) (B_INFO_CACHE_Destructor (&(key)->infoCache))
+
+struct B_KeyInfoType;
+int B_KeySetInfo PROTO_LIST ((B_Key *, struct B_KeyInfoType *, POINTER));
+int B_KeyGetInfo PROTO_LIST ((B_Key *, POINTER *, struct B_KeyInfoType *));
+int B_KeyAddItemInfo PROTO_LIST ((B_Key *, unsigned char *, unsigned int));
+
+#endif
diff --git a/lib/bind/dnssafe/bmempool.c b/lib/bind/dnssafe/bmempool.c
new file mode 100644 (file)
index 0000000..b353f39
--- /dev/null
@@ -0,0 +1,273 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bmempool.h"
+#include "port_after.h"
+
+#define ALLOCED_LIST_SLACK 10
+
+void B_MemoryPoolConstructor (memoryPool)
+B_MemoryPool *memoryPool;
+{
+  T_memset ((POINTER)&memoryPool->z, 0, sizeof (memoryPool->z));
+} 
+
+void B_MemoryPoolDestructor (memoryPool)
+B_MemoryPool *memoryPool;
+{
+  B_MemoryPoolReset (memoryPool);
+  T_free ((POINTER)memoryPool->z.allocedList);
+}
+
+/* For each item on the alloced list, call the DeleteFuncion if
+     there is one, otherwise zerioze and free.
+   Leave the list itself allocated with all NULL entries.
+ */
+void B_MemoryPoolReset (memoryPool)
+B_MemoryPool *memoryPool;
+{
+  B_ALLOCED_DATA *allocedData;
+  unsigned int i;
+
+  for (i = memoryPool->z.allocedCount,
+       allocedData = memoryPool->z.allocedList;
+       i-- > 0;
+       ++allocedData) {
+    /* Only process this entry if the data is not NULL_PTR.
+     */
+    if (allocedData->object != NULL_PTR) {
+      if (allocedData->DeleteFunction != NULL)
+        /* There is a destroy function, so call. */
+        (*allocedData->DeleteFunction) (allocedData->object);
+      else {
+        T_memset (allocedData->object, 0, allocedData->size);
+        T_free (allocedData->object);
+      }
+      allocedData->object = NULL_PTR;
+    }
+  }
+
+  memoryPool->z.allocedCount = 0;
+  /* Note that maxAllocedCount still indicates the size of the alloced list. */
+}
+
+/* On any error return, NULL_PTR is returned for the data.
+   Returns 0 if successful, or BE_ALLOC if cannot alloc the memory.
+ */
+int B_MemoryPoolAlloc (memoryPool, data, size)
+B_MemoryPool *memoryPool;
+POINTER *data;
+unsigned int size;
+{
+  if ((*data = T_malloc (size)) == NULL_PTR)
+    return (BE_ALLOC);
+  return (B_MemoryPoolAdoptData (memoryPool, data, size));
+}
+
+/* Use alloc to allocate the newData of length size and T_memcpy data into it.
+   On any error return, NULL_PTR is returned for the newData.
+   Returns 0 if successful or BE_ALLOC if cannot alloc the memory.
+ */
+int B_MemoryPoolAllocAndCopy (memoryPool, newData, data, size)
+B_MemoryPool *memoryPool;
+POINTER *newData;
+POINTER data;
+unsigned int size;
+{
+  int status;
+  
+  if ((status = B_MemoryPoolAlloc (memoryPool, newData, size)) != 0)
+    return (status);
+  
+  T_memcpy (*newData, data, size);
+  return (0);
+}
+
+/* Put the given data on the memory pool's alloced list.
+   The size of the alloced data buffer must be passed in so that it can
+     be zeroized when the object is reset (Pass in a size of zero if
+     the buffer does not need to be zeroized.)
+   The data is passed by reference, so that if there is an error,
+     the data is zeroized and freed, and the pointer to the data is set
+     to NULL_PTR.
+   This routine should be used with caution - it is meant be called
+     immediately after an alloc.
+   No check is made as to whether the data is already on the memory pool's 
+     alloced list (which would be a problem since it will get freed twice).
+   Returns 0 if successful or BE_ALLOC if cannot expand the alloced list.
+ */       
+int B_MemoryPoolAdoptData (memoryPool, data, size)
+B_MemoryPool *memoryPool;
+POINTER *data;
+unsigned int size;
+{
+  int status;
+  
+  if ((status = B_MemoryPoolAdoptHelper(memoryPool, *data, size, NULL)) != 0) {
+    T_memset (*data, 0, size);
+    T_free (*data);
+    *data = NULL_PTR;
+    return (status);
+  }
+
+  return (0);
+}
+
+/* Put the given object on the memory pool's alloced list.
+   The size of the alloced object must be passed in so that it can
+     be zeroized when the object is reset (Pass in a size of zero if
+     the buffer does not need to be zeroized, especially if it
+     is an object and not a data buffer.)
+   The object is not passed by reference.  If there is an error,
+     the calling routine should clean up the object, such as zeroizing
+     and freeing.
+   No check is made as to whether the object is already on the memory pool's 
+     alloced list (which would be a problem since it will get freed twice).
+   Returns 0 if successful or BE_ALLOC if cannot expand the alloced list.
+ */       
+int B_MemoryPoolAdoptHelper (memoryPool, object, size, DeleteFunction)
+B_MemoryPool *memoryPool;
+POINTER object;
+unsigned int size;
+B_MEMORY_POOL_DELETE_FUNCTION DeleteFunction;
+{
+  POINTER newList;
+  unsigned int newMaxCount;
+
+  if (memoryPool->z.allocedCount + 1 > memoryPool->z.maxAllocedCount) {
+    /* Make extra room on the alloced list.
+     */
+    newMaxCount = memoryPool->z.allocedCount + ALLOCED_LIST_SLACK;
+    if ((newList = T_malloc (newMaxCount * sizeof (B_ALLOCED_DATA)))
+        == NULL_PTR)
+      /* alloc errorm so caller should clean up the object it passed. */
+      return (BE_ALLOC);
+    
+    /* move in new list and free old list */
+    T_memcpy
+      (newList, (POINTER)memoryPool->z.allocedList,
+       memoryPool->z.allocedCount * sizeof (B_ALLOCED_DATA));
+    T_free ((POINTER)memoryPool->z.allocedList);
+    memoryPool->z.allocedList = (B_ALLOCED_DATA *)newList;
+    memoryPool->z.maxAllocedCount = newMaxCount;
+  }
+  
+  /* Put object on alloced list and increment count.
+   */
+  memoryPool->z.allocedList[memoryPool->z.allocedCount].object = object;
+  memoryPool->z.allocedList[memoryPool->z.allocedCount].size = size;
+  memoryPool->z.allocedList[memoryPool->z.allocedCount++].DeleteFunction =
+    DeleteFunction;
+  return (0);
+}
+
+/* 'data' points to the pointer to realloc and also is used to
+     return the realloced memory.
+   If data points to NULL_PTR, behaves like B_MemoryPoolAlloc.
+   Find 'data' on the allocedList and realloc it to the given size,
+     replacing the entry on the alloced list with the new memory.
+   If it is not on the allocedList, the adopt the reallocated memory.
+   If the buffer must be moved during the realloc, the old buffer is not
+     zeroized (unless T_realloc does the zeroizing).
+   This assumes that the (POINTER *)data is not (POINTER *)NULL_PTR.
+   This assumes there is no DesroyFunction for this entry.  That is,
+     you should not try to resize an object.
+   On any error return, NULL_PTR is returned for the data.
+   Returns 0 if successful or BE_ALLOC if cannot alloc the memory.
+ */
+int B_MemoryPoolRealloc (memoryPool, data, size)
+B_MemoryPool *memoryPool;
+POINTER *data;
+unsigned int size;
+{
+  B_ALLOCED_DATA *allocedData;
+
+  allocedData = B_MemoryPoolFindAllocedObject (memoryPool, *data);
+
+  if ((*data = T_realloc (*data, size)) == NULL_PTR) {
+    if (allocedData != (B_ALLOCED_DATA *)NULL_PTR)
+      /* Could not reallocate, so nullify this entry. */
+      allocedData->object = NULL_PTR;
+
+    return (BE_ALLOC);
+  }
+  
+  /* Realloc was successful.
+   */
+  if (allocedData == (B_ALLOCED_DATA *)NULL_PTR)
+    /* The data was not in the memory pool to start with, so adopt it.
+       Note that this also happens when the data is initially NULL_PTR. */
+    return (B_MemoryPoolAdoptData (memoryPool, data, size));
+  
+  /* Replace the entry on the alloced list with the new memory.
+   */
+  allocedData->object = *data;
+  allocedData->size = size;
+  return (0);
+}
+
+/* Find the object in the alloced list, call the DeleteFunction if
+     there is one, zeroize it and free it, nullifying that alloced list entry.
+   The object to be freed is passed by pointer and is set to NULL_PTR to
+     enforce the fact that the address no longer points to valid memory.
+   This assumes that the (POINTER *)data is not (POINTER *)NULL_PTR.
+   If the address is not found on the alloced list, only set the address
+     to NULL_PTR.
+ */
+void B_MemoryPoolFree (memoryPool, object)
+B_MemoryPool *memoryPool;
+POINTER *object;
+{
+  B_ALLOCED_DATA *allocedData;
+  
+  if ((allocedData = B_MemoryPoolFindAllocedObject (memoryPool, *object))
+      != (B_ALLOCED_DATA *)NULL_PTR) {
+    if (allocedData->DeleteFunction != NULL)
+      /* There is a destroy function, so call. */
+      (*allocedData->DeleteFunction) (allocedData->object);
+    else {
+      T_memset (*object, 0, allocedData->size);
+      T_free (*object);
+    }
+
+    /* Set this entry to NULL_PTR so that reset will not process it. */
+    allocedData->object = NULL_PTR;
+  }
+  
+  *object = NULL_PTR;
+}
+
+/* Return a pointer to the alloced object entry in the memoryPool.
+   Return (ALLOCED_DATA *)NULL_PTR if object is NULL_PTR or object is not
+     in the memoryPool.
+ */
+B_ALLOCED_DATA *B_MemoryPoolFindAllocedObject (memoryPool, object)
+B_MemoryPool *memoryPool;
+POINTER object;
+{
+  B_ALLOCED_DATA *allocedData;
+  unsigned int i;
+  
+  if (object == NULL_PTR)
+    return ((B_ALLOCED_DATA *)NULL_PTR);
+  
+  for (i = memoryPool->z.allocedCount,
+       allocedData = memoryPool->z.allocedList;
+       i-- > 0;
+       ++allocedData) {
+    if (allocedData->object == object)
+      return (allocedData);
+  }
+
+  /* data not found. */
+  return ((B_ALLOCED_DATA *)NULL_PTR);
+}
+
diff --git a/lib/bind/dnssafe/bmempool.h b/lib/bind/dnssafe/bmempool.h
new file mode 100644 (file)
index 0000000..b5216dd
--- /dev/null
@@ -0,0 +1,53 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _BMEMPOOL_H_
+#define _BMEMPOOL_H_ 1
+
+typedef void (*B_MEMORY_POOL_DELETE_FUNCTION) PROTO_LIST ((POINTER));
+
+typedef struct {
+  POINTER object;
+  unsigned int size;
+  B_MEMORY_POOL_DELETE_FUNCTION DeleteFunction;
+} B_ALLOCED_DATA;
+
+typedef struct {
+  struct {
+    unsigned int allocedCount;
+    unsigned int maxAllocedCount;      /* Size of the actuall allocated list */
+    B_ALLOCED_DATA *allocedList;
+    /* POINTER reserved; */
+  } z;           /* z gives the members that are zeroized by the constructor */
+} B_MemoryPool;
+
+void B_MemoryPoolConstructor PROTO_LIST ((B_MemoryPool *));
+void B_MemoryPoolDestructor PROTO_LIST ((B_MemoryPool *));
+
+void B_MemoryPoolReset PROTO_LIST ((B_MemoryPool *));
+int B_MemoryPoolAlloc PROTO_LIST ((B_MemoryPool *, POINTER *, unsigned int));
+int B_MemoryPoolAllocAndCopy PROTO_LIST
+  ((B_MemoryPool *, POINTER *, POINTER, unsigned int));
+int B_MemoryPoolAdoptData PROTO_LIST
+  ((B_MemoryPool *, POINTER *, unsigned int));
+int B_MemoryPoolAdoptObject PROTO_LIST
+  ((B_MemoryPool *, POINTER *, B_MEMORY_POOL_DELETE_FUNCTION));
+int B_MemoryPoolRealloc PROTO_LIST ((B_MemoryPool *, POINTER *, unsigned int));
+int B_MemoryPoolSafeRealloc PROTO_LIST
+  ((B_MemoryPool *, POINTER *, unsigned int));
+void B_MemoryPoolFree PROTO_LIST ((B_MemoryPool *, POINTER *));
+void B_MemoryPoolResetExceptObject PROTO_LIST ((B_MemoryPool *, POINTER));
+
+/* These are "private member functions ".
+ */
+B_ALLOCED_DATA *B_MemoryPoolFindAllocedObject PROTO_LIST
+  ((B_MemoryPool *, POINTER));
+int B_MemoryPoolAdoptHelper PROTO_LIST
+  ((B_MemoryPool *, POINTER, unsigned int, B_MEMORY_POOL_DELETE_FUNCTION));
+
+#endif
diff --git a/lib/bind/dnssafe/bsafe2.h b/lib/bind/dnssafe/bsafe2.h
new file mode 100644 (file)
index 0000000..6dfbbf3
--- /dev/null
@@ -0,0 +1,194 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _BSAFE_H_
+#define _BSAFE_H_ 1
+
+#ifndef T_CALL
+#define T_CALL
+#endif
+
+#include "atypes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define BE_ALGORITHM_ALREADY_SET 0x0200
+#define BE_ALGORITHM_INFO 0x0201
+#define BE_ALGORITHM_NOT_INITIALIZED 0x0202
+#define BE_ALGORITHM_NOT_SET 0x0203
+#define BE_ALGORITHM_OBJ 0x0204
+#define BE_ALG_OPERATION_UNKNOWN 0x0205
+#define BE_ALLOC 0x0206
+#define BE_CANCEL 0x0207
+#define BE_DATA 0x0208
+#define BE_EXPONENT_EVEN 0x0209
+#define BE_EXPONENT_LEN 0x020a
+#define BE_HARDWARE 0x020b
+#define BE_INPUT_DATA 0x020c
+#define BE_INPUT_LEN 0x020d
+#define BE_KEY_ALREADY_SET 0x020e
+#define BE_KEY_INFO 0x020f
+#define BE_KEY_LEN 0x0210
+#define BE_KEY_NOT_SET 0x0211
+#define BE_KEY_OBJ 0x0212
+#define BE_KEY_OPERATION_UNKNOWN 0x0213
+#define BE_MEMORY_OBJ 0x0214
+#define BE_MODULUS_LEN 0x0215
+#define BE_NOT_INITIALIZED 0x0216
+#define BE_NOT_SUPPORTED 0x0217
+#define BE_OUTPUT_LEN 0x0218
+#define BE_OVER_32K 0x0219
+#define BE_RANDOM_NOT_INITIALIZED 0x021a
+#define BE_RANDOM_OBJ 0x021b
+#define BE_SIGNATURE 0x021c
+#define BE_WRONG_ALGORITHM_INFO 0x021d
+#define BE_WRONG_KEY_INFO 0x021e
+#define BE_INPUT_COUNT 0x021f
+#define BE_OUTPUT_COUNT 0x0220
+#define BE_METHOD_NOT_IN_CHOOSER 0x221
+
+typedef POINTER B_KEY_OBJ;
+typedef POINTER B_ALGORITHM_OBJ;
+
+typedef int (T_CALL *B_INFO_TYPE) PROTO_LIST ((POINTER *));
+
+typedef struct B_ALGORITHM_METHOD B_ALGORITHM_METHOD;
+typedef B_ALGORITHM_METHOD **B_ALGORITHM_CHOOSER;
+
+/* Routines supplied by the implementor.
+ */
+void T_CALL T_memset PROTO_LIST ((POINTER, int, unsigned int));
+void T_CALL T_memcpy PROTO_LIST ((POINTER, CPOINTER, unsigned int));
+void T_CALL T_memmove PROTO_LIST ((POINTER, POINTER, unsigned int));
+int T_CALL T_memcmp PROTO_LIST ((CPOINTER, CPOINTER, unsigned int));
+POINTER T_CALL T_malloc PROTO_LIST ((unsigned int));
+POINTER T_CALL T_realloc PROTO_LIST ((POINTER, unsigned int));
+void T_CALL T_free PROTO_LIST ((POINTER));
+
+/* The key object.
+ */
+int T_CALL B_CreateKeyObject PROTO_LIST ((B_KEY_OBJ *));
+void T_CALL B_DestroyKeyObject PROTO_LIST ((B_KEY_OBJ *));
+int T_CALL B_SetKeyInfo PROTO_LIST ((B_KEY_OBJ, B_INFO_TYPE, POINTER));
+int T_CALL B_GetKeyInfo PROTO_LIST ((POINTER *, B_KEY_OBJ, B_INFO_TYPE));
+
+/* The algorithm object.
+ */
+int T_CALL B_CreateAlgorithmObject PROTO_LIST ((B_ALGORITHM_OBJ *));
+void T_CALL B_DestroyAlgorithmObject PROTO_LIST ((B_ALGORITHM_OBJ *));
+int T_CALL B_SetAlgorithmInfo PROTO_LIST
+  ((B_ALGORITHM_OBJ, B_INFO_TYPE, POINTER));
+int T_CALL B_GetAlgorithmInfo PROTO_LIST
+  ((POINTER *, B_ALGORITHM_OBJ, B_INFO_TYPE));
+
+unsigned int B_IntegerBits PROTO_LIST ((unsigned char *, unsigned int));
+
+/* Algorithm operations.
+ */
+int T_CALL B_RandomInit PROTO_LIST
+  ((B_ALGORITHM_OBJ, B_ALGORITHM_CHOOSER, A_SURRENDER_CTX *));
+int T_CALL B_RandomUpdate PROTO_LIST
+  ((B_ALGORITHM_OBJ, unsigned char *, unsigned int, A_SURRENDER_CTX *));
+int T_CALL B_GenerateRandomBytes PROTO_LIST
+  ((B_ALGORITHM_OBJ, unsigned char *, unsigned int, A_SURRENDER_CTX *));
+
+int T_CALL B_DigestInit PROTO_LIST
+  ((B_ALGORITHM_OBJ, B_KEY_OBJ, B_ALGORITHM_CHOOSER, A_SURRENDER_CTX *));
+int T_CALL B_DigestUpdate PROTO_LIST
+  ((B_ALGORITHM_OBJ, const unsigned char *, unsigned int, A_SURRENDER_CTX *));
+int T_CALL B_DigestFinal PROTO_LIST
+  ((B_ALGORITHM_OBJ, unsigned char *, unsigned int *, unsigned int,
+    A_SURRENDER_CTX *));
+
+int T_CALL B_EncryptInit PROTO_LIST
+  ((B_ALGORITHM_OBJ, B_KEY_OBJ, B_ALGORITHM_CHOOSER, A_SURRENDER_CTX *));
+int T_CALL B_EncryptUpdate PROTO_LIST
+  ((B_ALGORITHM_OBJ, unsigned char *, unsigned int *, unsigned int,
+    unsigned char *, unsigned int, B_ALGORITHM_OBJ, A_SURRENDER_CTX *));
+int T_CALL B_EncryptFinal PROTO_LIST
+  ((B_ALGORITHM_OBJ, unsigned char *, unsigned int *, unsigned int,
+    B_ALGORITHM_OBJ, A_SURRENDER_CTX *));
+
+int T_CALL B_DecryptInit PROTO_LIST
+  ((B_ALGORITHM_OBJ, B_KEY_OBJ, B_ALGORITHM_CHOOSER, A_SURRENDER_CTX *));
+int T_CALL B_DecryptUpdate PROTO_LIST
+  ((B_ALGORITHM_OBJ, unsigned char *, unsigned int *, unsigned int,
+    const unsigned char *, unsigned int, B_ALGORITHM_OBJ, A_SURRENDER_CTX *));
+int T_CALL B_DecryptFinal PROTO_LIST
+  ((B_ALGORITHM_OBJ, unsigned char *, unsigned int *, unsigned int,
+    B_ALGORITHM_OBJ, A_SURRENDER_CTX *));
+
+
+
+int T_CALL B_GenerateInit PROTO_LIST
+  ((B_ALGORITHM_OBJ, B_ALGORITHM_CHOOSER, A_SURRENDER_CTX *));
+int T_CALL B_GenerateKeypair PROTO_LIST
+  ((B_ALGORITHM_OBJ, B_KEY_OBJ, B_KEY_OBJ, B_ALGORITHM_OBJ,
+    A_SURRENDER_CTX *));
+int T_CALL B_GenerateParameters PROTO_LIST
+  ((B_ALGORITHM_OBJ, B_ALGORITHM_OBJ, B_ALGORITHM_OBJ, A_SURRENDER_CTX *));
+
+
+/* Information for password-based encryption (PBE) algorithms.
+ */
+typedef struct {
+  unsigned char *salt;                                        /* salt value */
+  unsigned int iterationCount;                           /* iteration count */
+} B_PBE_PARAMS;
+
+/* Information for MAC algorithm.
+ */
+typedef struct {
+  unsigned int macLen;                               /* length of MAC value */
+} B_MAC_PARAMS;
+
+
+/* Information for BSAFE 1.x compatible encryption algorithms.
+ */
+
+
+typedef struct {
+  unsigned int threshold;                                 /* share threshold */
+} B_SECRET_SHARING_PARAMS;
+
+/* Key Info Types.
+ */
+int T_CALL KI_8Byte PROTO_LIST ((POINTER *));
+int T_CALL KI_Item PROTO_LIST ((POINTER *));
+int T_CALL KI_PKCS_RSAPrivate PROTO_LIST ((POINTER *));
+int T_CALL KI_RSAPublic PROTO_LIST ((POINTER *));
+int T_CALL KI_RSA_CRT PROTO_LIST ((POINTER *));
+
+/* Algorithm Info Types.
+ */
+int T_CALL AI_MD5 PROTO_LIST ((POINTER *));
+int T_CALL AI_MD5Random PROTO_LIST ((POINTER *));
+int T_CALL AI_PKCS_RSAPrivate PROTO_LIST ((POINTER *));
+int T_CALL AI_PKCS_RSAPublic PROTO_LIST ((POINTER *));
+int T_CALL AI_RSAKeyGen PROTO_LIST ((POINTER *));
+int T_CALL AI_RSAPrivate PROTO_LIST ((POINTER *));
+int T_CALL AI_RSAPublic PROTO_LIST ((POINTER *));
+
+
+/* Algorithm methods for use int the algorithm chooser.
+ */
+extern B_ALGORITHM_METHOD T_CALL AM_MD5;
+extern B_ALGORITHM_METHOD T_CALL AM_MD5_RANDOM;
+extern B_ALGORITHM_METHOD T_CALL AM_RSA_CRT_DECRYPT;
+extern B_ALGORITHM_METHOD T_CALL AM_RSA_CRT_ENCRYPT;
+extern B_ALGORITHM_METHOD T_CALL AM_RSA_DECRYPT;
+extern B_ALGORITHM_METHOD T_CALL AM_RSA_ENCRYPT;
+extern B_ALGORITHM_METHOD T_CALL AM_RSA_KEY_GEN;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/bind/dnssafe/btypechk.h b/lib/bind/dnssafe/btypechk.h
new file mode 100644 (file)
index 0000000..93f5a97
--- /dev/null
@@ -0,0 +1,25 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _BTYPECHK_H_
+#define _BTYPECHK_H_ 1
+
+struct B_TypeCheck;
+
+typedef void (*B_TYPE_CHECK_DESTRUCTOR) PROTO_LIST ((struct B_TypeCheck *));
+
+typedef struct B_TypeCheck {
+  B_TYPE_CHECK_DESTRUCTOR _Destructor;
+} B_TypeCheck;
+
+#define B_TYPE_CHECK_Constructor(typeCheck, Destructor)\
+  (typeCheck)->_Destructor = (Destructor)
+#define B_TYPE_CHECK_Destructor(typeCheck)\
+  (*(typeCheck)->_Destructor) (typeCheck)
+
+#endif
diff --git a/lib/bind/dnssafe/cantobig.c b/lib/bind/dnssafe/cantobig.c
new file mode 100644 (file)
index 0000000..674b51e
--- /dev/null
@@ -0,0 +1,59 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "algae.h"
+#include "bigmath.h"
+#include "port_after.h"
+
+/* CanonicalToBig () copies a byte vector into a word vector while REVERSING
+     the order of significance.  The byte vector is input MSByte first while
+     the word vector is written out LSWord first. It also adds a leading zero
+     sign bit if necessary.
+   Returns 0, AE_DATA.
+ */
+int CanonicalToBig (wordPointer, wordCount, bytePointer, numBytes)
+UINT2 *wordPointer;
+unsigned int wordCount;
+const unsigned char *bytePointer;
+unsigned int numBytes;
+{
+  unsigned int copyCount;
+  
+  if (A_IntegerBits (bytePointer, numBytes) / 16 + 1 > wordCount)
+    return (AE_DATA);
+
+  /* start at end of byte vector */
+  bytePointer += numBytes-1;
+  
+  /* copy as much as possible */
+  copyCount = (wordCount < numBytes / 2) ? wordCount : numBytes / 2;
+  wordCount -= copyCount;
+  numBytes -= 2 * copyCount;
+  while (copyCount--) {
+    /* Copy two bytes.*/
+    *wordPointer++ = (UINT2)*bytePointer + (*(bytePointer - 1) << 8);
+    bytePointer -= 2;
+  }
+  
+  if (wordCount && numBytes & 1) {
+    /* If the number of input bytes was odd.  Copy one last byte.*/
+    *wordPointer++ = (UINT2)*bytePointer--;
+    wordCount--;
+    numBytes--;
+  }
+  
+  /* zero fill remainder of word vector */
+  while (wordCount--)
+    *wordPointer++ = 0;
+  
+  return (0);
+}
+
+
diff --git a/lib/bind/dnssafe/crt2.c b/lib/bind/dnssafe/crt2.c
new file mode 100644 (file)
index 0000000..b1307ac
--- /dev/null
@@ -0,0 +1,230 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "algae.h"
+#include "crt2.h"
+#include "bigmath.h"
+#include "port_after.h"
+
+/* RSA encryption/decryption with Chinese Remainder Theorem.
+ */
+
+#define GENERATE_BREAK(type) { \
+    status = type; \
+    break; \
+  }
+
+static int RSA_CRT2 PROTO_LIST
+  ((A_RSA_CRT2_CTX *, unsigned char *, unsigned int *, unsigned int,
+    const unsigned char *, A_SURRENDER_CTX *));
+
+int A_RSA_CRT2Init (context, key)
+A_RSA_CRT2_CTX *context;
+A_RSA_CRT_KEY *key;
+{
+  if (A_IntegerBits (key->modulus.data, key->modulus.len)
+      > MAX_RSA_MODULUS_BITS)
+    /* Key len is too big to handle. */
+    return (AE_MODULUS_LEN);
+
+  /* Set the block update blockLen to be big enough to hold the modulus.
+   */
+  context->blockLen =
+    BITS_TO_LEN (A_IntegerBits (key->modulus.data, key->modulus.len));
+
+  context->inputLen = 0;
+
+  /* convert first prime to bignum format */
+  if (CanonicalToBig
+      (context->primeP, MAX_RSA_PRIME_WORDS, key->prime[0].data,
+       key->prime[0].len))
+    return (AE_KEY_INFO);
+    
+  /* compute significant length of first prime */
+  context->primeWords = BITS_TO_WORDS
+    (BigLen (context->primeP, MAX_RSA_PRIME_WORDS));
+    
+  /* convert other private key parameters to bignum format */
+  if (CanonicalToBig
+      (context->primeQ, context->primeWords, key->prime[1].data,
+       key->prime[1].len) ||
+      CanonicalToBig
+      (context->exponentP, context->primeWords,
+       key->primeExponent[0].data, key->primeExponent[0].len) ||
+      CanonicalToBig
+      (context->exponentQ, context->primeWords,
+       key->primeExponent[1].data, key->primeExponent[1].len) ||
+      CanonicalToBig
+      (context->coefficient, context->primeWords,
+       key->coefficient.data, key->coefficient.len))
+    return (AE_KEY_INFO);
+
+  /* convert modulus to bignum format */
+  if (CanonicalToBig
+      (context->modulus, 2 * context->primeWords,
+       key->modulus.data, key->modulus.len))
+    return (AE_KEY_INFO);
+
+  return (0);
+}
+
+int A_RSA_CRT2Update
+  (context, partOut, partOutLen, maxPartOutLen, partIn, partInLen,
+   surrenderContext)
+A_RSA_CRT2_CTX *context;
+unsigned char *partOut;
+unsigned int *partOutLen;
+unsigned int maxPartOutLen;
+const unsigned char *partIn;
+unsigned int partInLen;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+  unsigned int partialLen, localPartOutLen;
+
+  /* Initialize partOutLen to zero. */
+  *partOutLen = 0;
+
+  if (context->inputLen + partInLen < context->blockLen) {
+    /* Not enough to encrypt - just accumulate.
+     */
+    T_memcpy
+      ((POINTER)(context->input + context->inputLen), (CPOINTER)partIn,
+       partInLen);
+    context->inputLen += partInLen;
+    return (0);
+  }
+  
+  if (context->inputLen > 0) {
+    /* Need to accumulate the rest of the block bytes into the input and
+         encrypt from there (otherwise it's OK to encrypt straight from
+         the partIn).
+     */
+    partialLen = context->blockLen - context->inputLen;
+    T_memcpy
+      ((POINTER)(context->input + context->inputLen), (CPOINTER)partIn,
+       partialLen);
+    partIn += partialLen;
+    partInLen -= partialLen;
+    
+    if ((status = RSA_CRT2
+         (context, partOut, &localPartOutLen, maxPartOutLen, context->input,
+          surrenderContext)) != 0)
+      return (status);
+    (*partOutLen) += localPartOutLen;
+    partOut += localPartOutLen;
+    maxPartOutLen -= localPartOutLen;
+  }
+
+  /* Encrypt as many blocks of input as provided.
+   */
+  while (partInLen >= context->blockLen) {
+    if ((status = RSA_CRT2
+         (context, partOut, &localPartOutLen, maxPartOutLen, partIn,
+          surrenderContext)) != 0)
+      return (status);
+    
+    partIn += context->blockLen;
+    partInLen -= context->blockLen;
+    (*partOutLen) += localPartOutLen;
+    partOut += localPartOutLen;
+    maxPartOutLen -= localPartOutLen;
+  }
+  
+  /* Copy remaining input bytes to the context's input buffer.
+   */
+  T_memcpy
+    ((POINTER)context->input, partIn, partInLen);
+  context->inputLen = partInLen;
+  return (0);
+}
+
+int A_RSA_CRT2Final (context)
+A_RSA_CRT2_CTX *context;
+{
+  if (context->inputLen != 0)
+    return (AE_INPUT_LEN);
+  
+  /* Restart context to accumulate a new block.
+   */
+  context->inputLen = 0;
+  return (0);
+}
+
+/* Assume input length is context->blockLen.
+ */
+static int RSA_CRT2
+  (context, output, outputLen, maxOutputLen, input, surrenderContext)
+A_RSA_CRT2_CTX *context;
+unsigned char *output;
+unsigned int *outputLen;
+unsigned int maxOutputLen;
+const unsigned char *input;
+A_SURRENDER_CTX *surrenderContext;
+{
+  struct ModExpCRTFrame {
+    UINT2 bigInBuf[2 * MAX_RSA_PRIME_WORDS],
+      bigOutBuf[2 * MAX_RSA_PRIME_WORDS];
+  } *frame = (struct ModExpCRTFrame *)NULL_PTR;
+#if !USE_ALLOCED_FRAME
+  struct ModExpCRTFrame stackFrame;
+#endif
+  int status;
+
+  status = 0;
+  do {
+    if ((*outputLen = context->blockLen) > maxOutputLen)
+      return (AE_OUTPUT_LEN);
+    
+#if USE_ALLOCED_FRAME
+    if ((frame = (struct ModExpCRTFrame *)T_malloc (sizeof (*frame)))
+        == (struct ModExpCRTFrame *)NULL_PTR) {
+      status = AE_ALLOC;
+      break;
+    }
+#else
+    /* Just use the buffers allocated on the stack. */
+    frame = &stackFrame;
+#endif
+
+    /* Convert input to bignum representation.
+       This won't return AE_DATA since input length was checked at Update.
+     */
+    CanonicalToBig
+      (frame->bigInBuf, 2 * context->primeWords, input, context->blockLen);
+
+    /* Check for overflow. */
+    if (BigCmp
+        (frame->bigInBuf, context->modulus, 2 * context->primeWords) >= 0)
+      GENERATE_BREAK (AE_INPUT_DATA);
+    
+    /* Chinese remainder exponentiation. */
+    if ((status = BigUnexp
+         (frame->bigOutBuf, frame->bigInBuf, context->primeP, context->primeQ,
+          context->exponentP, context->exponentQ, context->coefficient,
+          context->primeWords, surrenderContext)) != 0)
+      break;
+
+    /* Convert output to canonical representation.
+       This won't return AE_DATA since outputLen was set above.
+     */
+    BigToCanonical
+      (output, *outputLen, frame->bigOutBuf, 2 * context->primeWords);
+  } while (0);
+  
+  if (frame != (struct ModExpCRTFrame *)NULL_PTR) {
+    T_memset ((POINTER)frame, 0, sizeof (*frame));
+#if USE_ALLOCED_FRAME
+    T_free ((POINTER)frame);
+#endif
+  }
+  return (status);
+}
+
diff --git a/lib/bind/dnssafe/crt2.h b/lib/bind/dnssafe/crt2.h
new file mode 100644 (file)
index 0000000..c51b4a8
--- /dev/null
@@ -0,0 +1,50 @@
+/* Copyright (C) RSA Data Security, Inc. created 1994, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _RSA_H_
+#define _RSA_H_ 1
+
+#include "bigmaxes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Note, these are only valid after a call to A_RSA_CRT2Init.
+ */
+#define A_RSA_CRT2_BLOCK_LEN(context) ((context)->blockLen)
+#define A_RSA_CRT2_MAX_OUTPUT_LEN(context, inputLen)\
+  (inputLen) + (((inputLen) % (context)->blockLen) ?\
+                (context)->blockLen - ((inputLen) % (context)->blockLen) : 0)
+
+typedef struct {
+  unsigned int blockLen;           /* total size of the block to be computed */
+  unsigned char input[MAX_RSA_MODULUS_LEN];
+  unsigned int inputLen;
+  unsigned int primeWords;
+  UINT2 modulus[2 * MAX_RSA_PRIME_WORDS];
+  UINT2 primeP[MAX_RSA_PRIME_WORDS];
+  UINT2 primeQ[MAX_RSA_PRIME_WORDS];
+  UINT2 exponentP[MAX_RSA_PRIME_WORDS];
+  UINT2 exponentQ[MAX_RSA_PRIME_WORDS];
+  UINT2 coefficient[MAX_RSA_PRIME_WORDS];
+} A_RSA_CRT2_CTX;
+
+int A_RSA_CRT2Init PROTO_LIST ((A_RSA_CRT2_CTX *, A_RSA_CRT_KEY *));
+int A_RSA_CRT2Update PROTO_LIST
+  ((A_RSA_CRT2_CTX *, unsigned char *, unsigned int *, unsigned int,
+    const unsigned char *, unsigned int, A_SURRENDER_CTX *));
+int A_RSA_CRT2Final PROTO_LIST ((A_RSA_CRT2_CTX *));
+void A_RSA_CRT2GetMaxOutputLen PROTO_LIST
+  ((A_RSA_CRT2_CTX *, unsigned int *, unsigned int));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/bind/dnssafe/digest.c b/lib/bind/dnssafe/digest.c
new file mode 100644 (file)
index 0000000..0995b5d
--- /dev/null
@@ -0,0 +1,69 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "balg.h"
+#include "keyobj.h"
+#include "algobj.h"
+#include "port_after.h"
+
+int B_DigestInit
+  (algorithmObject, keyObject, algorithmChooser, surrenderContext)
+B_ALGORITHM_OBJ algorithmObject;
+B_KEY_OBJ keyObject;
+B_ALGORITHM_CHOOSER algorithmChooser;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+
+  if ((status = AlgorithmWrapCheck (THE_ALG_WRAP)) != 0)
+    return (status);
+  if ((status = KeyWrapCheck ((KeyWrap *)keyObject)) != 0)
+    return (status);
+
+  return (B_AlgorithmDigestInit
+          (&THE_ALG_WRAP->algorithm, &((KeyWrap *)keyObject)->key,
+           algorithmChooser, surrenderContext));
+}
+
+int B_DigestUpdate (algorithmObject, partIn, partInLen, surrenderContext)
+B_ALGORITHM_OBJ algorithmObject;
+const unsigned char *partIn;
+unsigned int partInLen;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+
+  if ((status = AlgorithmWrapCheck (THE_ALG_WRAP)) != 0)
+    return (status);
+
+  return (B_AlgorithmDigestUpdate
+          (&THE_ALG_WRAP->algorithm, partIn, partInLen, surrenderContext));
+}
+
+int B_DigestFinal
+  (algorithmObject, digest, digestLen, maxDigestLen, surrenderContext)
+B_ALGORITHM_OBJ algorithmObject;
+unsigned char *digest;
+unsigned int *digestLen;
+unsigned int maxDigestLen;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+
+  if ((status = AlgorithmWrapCheck (THE_ALG_WRAP)) != 0)
+    return (status);
+
+  return (B_AlgorithmDigestFinal
+          (&THE_ALG_WRAP->algorithm, digest, digestLen, maxDigestLen,
+           surrenderContext));
+}
+
diff --git a/lib/bind/dnssafe/digrand.c b/lib/bind/dnssafe/digrand.c
new file mode 100644 (file)
index 0000000..2abf028
--- /dev/null
@@ -0,0 +1,90 @@
+/* Copyright (C) RSA Data Security, Inc. created 1992, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "algae.h"
+#include "digrand.h"
+#include "port_after.h"
+
+/* Calling routine must initialize the digest algorithm and set
+     digestRandom->vTable.
+   digestLen is the length of the output of the digest algorithm (i.e. 16).
+   state must point to an unsigned char * array of 3 * digestLen.
+ */
+void A_DigestRandomInit (digestRandom, digestLen, state)
+A_DigestRandom *digestRandom;
+unsigned int digestLen;
+unsigned char *state;
+{
+  digestRandom->_state = state;
+  digestRandom->_output = state + digestLen;
+  digestRandom->_digest = digestRandom->_output + digestLen;
+
+  digestRandom->_outputAvailable = 0;
+  digestRandom->_digestLen = digestLen;
+
+  T_memset ((POINTER)digestRandom->_state, 0, digestLen);
+}
+
+void A_DigestRandomUpdate (digestRandom, input, inputLen)
+A_DigestRandom *digestRandom;
+unsigned char *input;
+unsigned int inputLen;
+{
+  unsigned int i, j, x;
+  
+  (*digestRandom->vTable->DigestUpdate) (digestRandom, input, inputLen);
+  (*digestRandom->vTable->DigestFinal) (digestRandom, digestRandom->_digest);
+
+  /* add digest to state */
+  x = 0;
+  for (i = 0; i < digestRandom->_digestLen; i++) {
+    j = digestRandom->_digestLen-1-i;
+    x += digestRandom->_state[j] + digestRandom->_digest[j];
+    digestRandom->_state[j] = (unsigned char)x;
+    x >>= 8;
+  }
+}
+
+void A_DigestRandomGenerateBytes (digestRandom, output, outputLen)
+A_DigestRandom *digestRandom;
+unsigned char *output;
+unsigned int outputLen;
+{
+  unsigned int available, i;
+  
+  available = digestRandom->_outputAvailable;
+
+  while (outputLen > available) {
+    T_memcpy
+      ((POINTER)output,
+       (POINTER)&digestRandom->_output[digestRandom->_digestLen-available],
+       available);
+    output += available;
+    outputLen -= available;
+
+    /* generate new output */
+    (*digestRandom->vTable->DigestUpdate)
+       (digestRandom, digestRandom->_state, digestRandom->_digestLen);
+    (*digestRandom->vTable->DigestFinal) (digestRandom, digestRandom->_output);
+    available = digestRandom->_digestLen;
+
+    /* increment state */
+    for (i = 0; i < digestRandom->_digestLen; i++)
+      if (digestRandom->_state[digestRandom->_digestLen-1-i]++)
+        break;
+  }
+
+  T_memcpy 
+    ((POINTER)output,
+     (POINTER)&digestRandom->_output[digestRandom->_digestLen-available],
+     outputLen);
+  digestRandom->_outputAvailable = available - outputLen;
+}
+
diff --git a/lib/bind/dnssafe/digrand.h b/lib/bind/dnssafe/digrand.h
new file mode 100644 (file)
index 0000000..6753c9c
--- /dev/null
@@ -0,0 +1,53 @@
+/* Copyright (C) RSA Data Security, Inc. created 1992, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _DIGRAND_H_
+#define _DIGRAND_H_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Use the THIS_DIGEST_RANDOM macro to define the type of object in the
+     virtual function prototype.  It defaults to the most base class, but
+     derived modules may define the macro to a more derived class before
+     including this header file.
+ */
+#ifndef THIS_DIGEST_RANDOM
+#define THIS_DIGEST_RANDOM struct A_DigestRandom
+#endif
+
+struct A_DigestRandom;
+
+typedef struct {
+  void (*DigestUpdate) PROTO_LIST
+    ((THIS_DIGEST_RANDOM *, unsigned char *, unsigned int));
+  void (*DigestFinal) PROTO_LIST ((THIS_DIGEST_RANDOM *, unsigned char *));
+} A_DigestRandomVTable;
+
+typedef struct A_DigestRandom {
+  unsigned char *_state;                                  /* input to digest */
+  unsigned char *_output;                        /* current output of digest */
+  unsigned int _outputAvailable;
+  unsigned char *_digest;
+  unsigned int _digestLen;
+  A_DigestRandomVTable *vTable;
+} A_DigestRandom;
+
+void A_DigestRandomInit PROTO_LIST
+  ((A_DigestRandom *, unsigned int, unsigned char *));
+void A_DigestRandomUpdate PROTO_LIST
+  ((A_DigestRandom *, unsigned char *, unsigned int));
+void A_DigestRandomGenerateBytes PROTO_LIST
+  ((A_DigestRandom *, unsigned char *, unsigned int));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/bind/dnssafe/encrypt.c b/lib/bind/dnssafe/encrypt.c
new file mode 100644 (file)
index 0000000..37b02bd
--- /dev/null
@@ -0,0 +1,149 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "balg.h"
+#include "keyobj.h"
+#include "algobj.h"
+#include "port_after.h"
+
+int B_EncryptInit
+  (algorithmObject, keyObject, algorithmChooser, surrenderContext)
+B_ALGORITHM_OBJ algorithmObject;
+B_KEY_OBJ keyObject;
+B_ALGORITHM_CHOOSER algorithmChooser;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+
+  if ((status = AlgorithmWrapCheck (THE_ALG_WRAP)) != 0)
+    return (status);
+  if ((status = KeyWrapCheck ((KeyWrap *)keyObject)) != 0)
+    return (status);
+
+  return (B_AlgorithmEncryptInit
+          (&THE_ALG_WRAP->algorithm, &((KeyWrap *)keyObject)->key,
+           algorithmChooser, surrenderContext));
+}
+
+int B_EncryptUpdate
+  (algorithmObject, partOut, partOutLen, maxPartOutLen, partIn, partInLen,
+   randomAlgorithm, surrenderContext)
+B_ALGORITHM_OBJ algorithmObject;
+unsigned char *partOut;
+unsigned int *partOutLen;
+unsigned int maxPartOutLen;
+unsigned char *partIn;
+unsigned int partInLen;
+B_ALGORITHM_OBJ randomAlgorithm;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+
+  if ((status = AlgorithmWrapCheck (THE_ALG_WRAP)) != 0)
+    return (status);
+  if ((status = RandomAlgorithmCheck (randomAlgorithm)) != 0)
+    return (status);
+
+  return (B_AlgorithmEncryptUpdate
+          (&THE_ALG_WRAP->algorithm, partOut, partOutLen, maxPartOutLen,
+           partIn, partInLen,
+           &((AlgorithmWrap *)randomAlgorithm)->algorithm, surrenderContext));
+}
+
+int B_EncryptFinal
+  (algorithmObject, partOut, partOutLen, maxPartOutLen, randomAlgorithm,
+   surrenderContext)
+B_ALGORITHM_OBJ algorithmObject;
+unsigned char *partOut;
+unsigned int *partOutLen;
+unsigned int maxPartOutLen;
+B_ALGORITHM_OBJ randomAlgorithm;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+
+  if ((status = AlgorithmWrapCheck (THE_ALG_WRAP)) != 0)
+    return (status);
+  if ((status = RandomAlgorithmCheck (randomAlgorithm)) != 0)
+    return (status);
+
+  return (B_AlgorithmEncryptFinal
+          (&THE_ALG_WRAP->algorithm, partOut, partOutLen, maxPartOutLen,
+           &((AlgorithmWrap *)randomAlgorithm)->algorithm, surrenderContext));
+}
+
+int B_DecryptInit
+  (algorithmObject, keyObject, algorithmChooser, surrenderContext)
+B_ALGORITHM_OBJ algorithmObject;
+B_KEY_OBJ keyObject;
+B_ALGORITHM_CHOOSER algorithmChooser;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+
+  if ((status = AlgorithmWrapCheck (THE_ALG_WRAP)) != 0)
+    return (status);
+  if ((status = KeyWrapCheck ((KeyWrap *)keyObject)) != 0)
+    return (status);
+
+  return (B_AlgorithmDecryptInit
+          (&THE_ALG_WRAP->algorithm, &((KeyWrap *)keyObject)->key,
+           algorithmChooser, surrenderContext));
+}
+
+int B_DecryptUpdate
+  (algorithmObject, partOut, partOutLen, maxPartOutLen, partIn, partInLen,
+   randomAlgorithm, surrenderContext)
+B_ALGORITHM_OBJ algorithmObject;
+unsigned char *partOut;
+unsigned int *partOutLen;
+unsigned int maxPartOutLen;
+const unsigned char *partIn;
+unsigned int partInLen;
+B_ALGORITHM_OBJ randomAlgorithm;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+
+  if ((status = AlgorithmWrapCheck (THE_ALG_WRAP)) != 0)
+    return (status);
+  if ((status = RandomAlgorithmCheck (randomAlgorithm)) != 0)
+    return (status);
+
+  return (B_AlgorithmDecryptUpdate
+          (&THE_ALG_WRAP->algorithm, partOut, partOutLen, maxPartOutLen,
+           partIn, partInLen,
+           &((AlgorithmWrap *)randomAlgorithm)->algorithm, surrenderContext));
+}
+
+int B_DecryptFinal
+  (algorithmObject, partOut, partOutLen, maxPartOutLen, randomAlgorithm,
+   surrenderContext)
+B_ALGORITHM_OBJ algorithmObject;
+unsigned char *partOut;
+unsigned int *partOutLen;
+unsigned int maxPartOutLen;
+B_ALGORITHM_OBJ randomAlgorithm;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+
+  if ((status = AlgorithmWrapCheck (THE_ALG_WRAP)) != 0)
+    return (status);
+  if ((status = RandomAlgorithmCheck (randomAlgorithm)) != 0)
+    return (status);
+
+  return (B_AlgorithmDecryptFinal
+          (&THE_ALG_WRAP->algorithm, partOut, partOutLen, maxPartOutLen,
+           &((AlgorithmWrap *)randomAlgorithm)->algorithm, surrenderContext));
+}
+
diff --git a/lib/bind/dnssafe/generate.c b/lib/bind/dnssafe/generate.c
new file mode 100644 (file)
index 0000000..9ffbe79
--- /dev/null
@@ -0,0 +1,80 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "balg.h"
+#include "ainfotyp.h"
+#include "keyobj.h"
+#include "algobj.h"
+#include "port_after.h"
+
+int B_GenerateInit (algorithmObject, algorithmChooser, surrenderContext)
+B_ALGORITHM_OBJ algorithmObject;
+B_ALGORITHM_CHOOSER algorithmChooser;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+
+  if ((status = AlgorithmWrapCheck (THE_ALG_WRAP)) != 0)
+    return (status);
+
+  return (B_AlgorithmGenerateInit
+          (&THE_ALG_WRAP->algorithm, algorithmChooser, surrenderContext));
+}
+
+int B_GenerateKeypair
+  (algorithmObject, publicKey, privateKey, randomAlgorithm, surrenderContext)
+B_ALGORITHM_OBJ algorithmObject;
+B_KEY_OBJ publicKey;
+B_KEY_OBJ privateKey;
+B_ALGORITHM_OBJ randomAlgorithm;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+
+  if ((status = AlgorithmWrapCheck (THE_ALG_WRAP)) != 0)
+    return (status);
+  if ((status = KeyWrapCheck ((KeyWrap *)publicKey)) != 0)
+    return (status);
+  if ((status = KeyWrapCheck ((KeyWrap *)privateKey)) != 0)
+    return (status);
+  if ((status = RandomAlgorithmCheck (randomAlgorithm)) != 0)
+    return (status);
+
+  return (B_AlgorithmGenerateKeypair
+          (&THE_ALG_WRAP->algorithm, &((KeyWrap *)publicKey)->key,
+           &((KeyWrap *)privateKey)->key,
+           &((AlgorithmWrap *)randomAlgorithm)->algorithm, surrenderContext));
+}
+
+int B_GenerateParameters
+  (algorithmObject, resultAlgorithmObject, randomAlgorithm, surrenderContext)
+B_ALGORITHM_OBJ algorithmObject;
+B_ALGORITHM_OBJ resultAlgorithmObject;
+B_ALGORITHM_OBJ randomAlgorithm;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+
+  if ((status = AlgorithmWrapCheck (THE_ALG_WRAP)) != 0)
+    return (status);
+  if ((status = AlgorithmWrapCheck ((AlgorithmWrap *)resultAlgorithmObject))
+      != 0)
+    return (status);
+  if ((status = RandomAlgorithmCheck (randomAlgorithm)) != 0)
+    return (status);
+
+  return (B_AlgorithmGenerateParameters
+          (&THE_ALG_WRAP->algorithm,
+           &((AlgorithmWrap *)resultAlgorithmObject)->algorithm,
+           &((AlgorithmWrap *)randomAlgorithm)->algorithm, surrenderContext));
+}
+
diff --git a/lib/bind/dnssafe/global.h b/lib/bind/dnssafe/global.h
new file mode 100644 (file)
index 0000000..8cd6723
--- /dev/null
@@ -0,0 +1,63 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _GLOBAL_H_
+#define _GLOBAL_H_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* PROTOTYPES should be set to one if and only if the compiler supports
+     function argument prototyping.
+   The following makes PROTOTYPES default to 1 if it has not already been
+     defined as 0 with C compiler flags.
+ */
+#ifndef PROTOTYPES
+#define PROTOTYPES 1
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+#if (!defined(BSD)) || (BSD < 199306)
+# include <sys/bitypes.h>
+#endif
+
+/* POINTER defines a generic pointer type */
+typedef unsigned char *POINTER;
+typedef const unsigned char *CPOINTER;
+
+/* UINT2 defines a two byte word */
+typedef u_int16_t UINT2;
+
+/* UINT4 defines a four byte word */
+typedef u_int32_t UINT4;
+
+#ifndef NULL_PTR
+#define NULL_PTR ((POINTER)0)
+#endif
+
+#ifndef UNUSED_ARG
+#define UNUSED_ARG(x) x = *(&x);
+#endif
+
+/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
+   If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
+     returns an empty list.  
+ */
+#if PROTOTYPES
+#define PROTO_LIST(list) list
+#else
+#define PROTO_LIST(list) ()
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* end _GLOBAL_H_ */
diff --git a/lib/bind/dnssafe/intbits.c b/lib/bind/dnssafe/intbits.c
new file mode 100644 (file)
index 0000000..7b35c6a
--- /dev/null
@@ -0,0 +1,34 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "algae.h"
+#include "port_after.h"
+
+/* Return the number of bits in the canonical, positive integer.
+   IntgerBits (0) = 0.
+ */
+unsigned int A_IntegerBits (integer, integerLen)
+const unsigned char *integer;
+unsigned int integerLen;
+{
+  unsigned char mask, byte;
+  unsigned int bytes, bits;
+  
+  for (bytes = 0; bytes < integerLen && integer[bytes] == 0; bytes++);
+  if (bytes == integerLen)
+    return (0);
+  
+  /* Get byte to test and increment byte count for final calculation */
+  byte = integer[bytes++];
+  
+  /* Get number of bits in most significant byte */
+  for (bits = 8, mask = 0x80; (byte & mask) == 0; bits--, mask >>= 1);
+  return (8 * (integerLen - bytes) + bits);
+}
diff --git a/lib/bind/dnssafe/intitem.c b/lib/bind/dnssafe/intitem.c
new file mode 100644 (file)
index 0000000..272681c
--- /dev/null
@@ -0,0 +1,56 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bmempool.h"
+#include "intitem.h"
+#include "port_after.h"
+
+/* Copy itemCount ITEMs from source to destination, allocating new
+     memory in the memoryPool.
+   Each ITEM is a canonical integer, and is stripped of leading zeros.
+   Use the list of staticItems as a template.  Each of the staticItems
+     points to the ITEM within the staticStruct, which is a structure
+     of the same format as destination and source.
+   Returns 0, BE_ALLOC.
+ */
+int AllocAndCopyIntegerItems
+  (destination, source, staticStruct, staticItems, itemCount, memoryPool)
+POINTER destination;
+POINTER source;
+POINTER staticStruct;
+ITEM **staticItems;
+unsigned int itemCount;
+B_MemoryPool *memoryPool;
+{
+  ITEM sourceItem, *destinationItem;
+  int status;
+  unsigned int i, offset;
+  
+  for (i = 0; i < itemCount; i++) {
+    offset = (unsigned int)((char *)staticItems[i] - (char *)staticStruct);
+    sourceItem = *(ITEM *)((char *)source + offset);
+    destinationItem = (ITEM *)((char *)destination + offset);
+
+    while (sourceItem.len > 0 && *sourceItem.data == 0) {
+      sourceItem.len--;
+      sourceItem.data++;
+    }
+    
+    if ((status = B_MemoryPoolAllocAndCopy
+         (memoryPool, (POINTER *)&destinationItem->data,
+          (POINTER)sourceItem.data, destinationItem->len = sourceItem.len))
+        != 0)
+      return (status);
+  }
+  
+  return (0);
+}
+
diff --git a/lib/bind/dnssafe/intitem.h b/lib/bind/dnssafe/intitem.h
new file mode 100644 (file)
index 0000000..05cb2fc
--- /dev/null
@@ -0,0 +1,11 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+int AllocAndCopyIntegerItems PROTO_LIST
+  ((POINTER, POINTER, POINTER, ITEM **, unsigned int, B_MemoryPool *));
+
diff --git a/lib/bind/dnssafe/keyobj.c b/lib/bind/dnssafe/keyobj.c
new file mode 100644 (file)
index 0000000..7ba2d5b
--- /dev/null
@@ -0,0 +1,115 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "kinfotyp.h"
+#include "keyobj.h"
+#include "port_after.h"
+
+#define THE_KEY_WRAP ((KeyWrap *)keyObject)
+
+static char KEY_TYPE_TAG = 0;
+
+int B_CreateKeyObject (keyObject)
+B_KEY_OBJ *keyObject;
+{
+  KeyWrap *keyWrap;
+
+  if ((*keyObject = T_malloc (sizeof (*keyWrap))) == NULL_PTR)
+    return (BE_ALLOC);
+
+  keyWrap = (KeyWrap *)*keyObject;
+
+  /* First construct base class */
+  B_KEY_Constructor (&keyWrap->key);
+  
+  keyWrap->typeTag = &KEY_TYPE_TAG;
+  keyWrap->selfCheck = keyWrap;
+  return (0);
+}
+
+void B_DestroyKeyObject (keyObject)
+B_KEY_OBJ *keyObject;
+{
+  KeyWrap *keyWrap = (KeyWrap *)*keyObject;
+
+  /* Need to explicitly check for NULL_PTR since KeyWrapCheck does not.
+   */
+  if (*keyObject == NULL_PTR)
+    return;
+  
+  if (KeyWrapCheck (keyWrap) == 0) {
+    /* zeroize self check to invalidate memory. */
+    keyWrap->selfCheck = (KeyWrap *)NULL_PTR;
+
+    /* Call base class descructor */
+    B_KEY_Destructor (&keyWrap->key);
+
+    T_free ((POINTER)keyWrap);
+  }
+
+  *keyObject = NULL_PTR;
+}
+
+int B_SetKeyInfo (keyObject, infoType, info)
+B_KEY_OBJ keyObject;
+B_INFO_TYPE infoType;
+POINTER info;
+{
+  B_KeyInfoType *keyInfoType;
+  int status;
+  
+  if ((status = KeyWrapCheck (THE_KEY_WRAP)) != 0)
+    return (status);
+
+  /* Get the KeyInfoType from the B_INFO_TYPE, which returns
+       zero for an AlgorithmInfoType, non-zero for KeyInfoType
+   */
+  if ((*infoType) ((POINTER *)&keyInfoType) == 0)
+    return (BE_ALG_OPERATION_UNKNOWN);
+  
+  return (B_KeySetInfo (&THE_KEY_WRAP->key, keyInfoType, info));
+}
+
+int B_GetKeyInfo (info, keyObject, infoType)
+POINTER *info;
+B_KEY_OBJ keyObject;
+B_INFO_TYPE infoType;
+{
+  B_KeyInfoType *keyInfoType;
+  int status;
+  
+  if ((status = KeyWrapCheck (THE_KEY_WRAP)) != 0)
+    return (status);
+
+  /* Get the KeyInfoType from the B_INFO_TYPE, which returns
+       zero for an AlgorithmInfoType, non-zero for KeyInfoType
+   */
+  if ((*infoType) ((POINTER *)&keyInfoType) == 0)
+    return (BE_ALG_OPERATION_UNKNOWN);
+  
+  return (B_KeyGetInfo (&THE_KEY_WRAP->key, info, keyInfoType));
+}
+
+/* Return 0 if this is a valid KeyWrap object, else BE_KEY_OBJ.
+   If keyWrap is NULL_PTR, return 0 and expect the lower routines
+     to check for NULL.
+ */
+int KeyWrapCheck (keyWrap)
+KeyWrap *keyWrap;
+{
+  if (keyWrap == (KeyWrap *)NULL_PTR)
+    return (0);
+
+  return ((keyWrap->selfCheck == keyWrap && keyWrap->typeTag == &KEY_TYPE_TAG)
+          ? 0 : BE_KEY_OBJ);
+}
+
diff --git a/lib/bind/dnssafe/keyobj.h b/lib/bind/dnssafe/keyobj.h
new file mode 100644 (file)
index 0000000..b7f582f
--- /dev/null
@@ -0,0 +1,16 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+typedef struct KeyWrap {
+  B_Key key;
+  char *typeTag;
+  struct KeyWrap *selfCheck;
+} KeyWrap;
+
+int KeyWrapCheck PROTO_LIST ((KeyWrap *));
+
diff --git a/lib/bind/dnssafe/ki8byte.c b/lib/bind/dnssafe/ki8byte.c
new file mode 100644 (file)
index 0000000..6c43a9c
--- /dev/null
@@ -0,0 +1,72 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "kinfotyp.h"
+#include "kiitem.h"
+#include "ki8byte.h"
+#include "port_after.h"
+
+int KIT_8ByteAddInfo PROTO_LIST ((B_Key *, POINTER));
+int KIT_8ByteMakeInfo PROTO_LIST ((POINTER *, B_Key *));
+
+B_KeyInfoType KIT_8Byte = {KIT_8ByteAddInfo, KIT_8ByteMakeInfo};
+
+int KI_8Byte (keyInfoType)
+POINTER *keyInfoType;
+{
+  *keyInfoType = (POINTER)&KIT_8Byte;
+
+  /* Return 1 to indicate a KeyInfoType, not an AlgorithmInfoType */
+  return (1);
+}
+
+/* info points to 8 byte key.
+   Cache as a KITItem and a KIT_8Byte.
+ */
+int KIT_8ByteAddInfo (key, info)
+B_Key *key;
+POINTER info;
+{
+  POINTER newData;
+  int status;
+  
+  /* Copy the 8 byte key. */
+  if ((status = B_MemoryPoolAllocAndCopy
+       (&key->infoCache.memoryPool, &newData, info, 8)) != 0)
+    return (status);
+
+  /* Cache as a KITItem as well as KIT_8Byte.
+   */
+  if ((status = B_KeyAddItemInfo (key, (unsigned char *)newData, 8)) != 0)
+    return (status);
+  return (B_InfoCacheAddInfo (&key->infoCache, (POINTER)&KIT_8Byte, newData));
+}
+
+int KIT_8ByteMakeInfo (info, key)
+POINTER *info;
+B_Key *key;
+{
+  ITEM *item;
+  int status;
+  
+  /* Try to make one from a KI_Item.  Since KI_Item doesn't
+       call KI_8Byte, this should not cause an endless loop.
+   */
+  if ((status = B_KeyGetInfo (key, (POINTER *)&item, &KITItem)) != 0)
+    return (status);
+  if (item->len != 8)
+    return (BE_WRONG_KEY_INFO);
+
+  *(unsigned char **)info = item->data;
+  return (0);
+}
+
diff --git a/lib/bind/dnssafe/ki8byte.h b/lib/bind/dnssafe/ki8byte.h
new file mode 100644 (file)
index 0000000..1c78bb1
--- /dev/null
@@ -0,0 +1,9 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+extern B_KeyInfoType KIT_8Byte;
diff --git a/lib/bind/dnssafe/kifulprv.c b/lib/bind/dnssafe/kifulprv.c
new file mode 100644 (file)
index 0000000..ef1f299
--- /dev/null
@@ -0,0 +1,153 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "kinfotyp.h"
+#include "kifulprv.h"
+#include "port_after.h"
+
+typedef struct {
+  ITEM modulus;                                                  /* modulus */
+  ITEM publicExponent;                       /* exponent for the public key */
+  ITEM privateExponent;                     /* exponent for the private key */
+  ITEM prime[2];                                           /* prime factors */
+  ITEM primeExponent[2];                     /* exponents for prime factors */
+  ITEM coefficient;                                      /* CRT coefficient */
+} FULL_PRIVATE_KEY;
+
+static int KITFullPrivateKeyAddInfo PROTO_LIST ((B_Key *, POINTER));
+
+static B_KeyInfoType KITFullPrivate =
+  {KITFullPrivateKeyAddInfo, B_KeyInfoTypeMakeError};
+
+/* Create a FULL_PRIVATE_KEY value and only copy inthe entries
+     that are not (ITEM *)NULL_PTR.
+   primes and primeExponents point to a 2 entry ITEM array.
+ */
+int CacheFullPrivateKey
+  (key, modulus, publicExponent, privateExponent, primes,
+   primeExponents, coefficient)
+B_Key *key;
+ITEM *modulus;
+ITEM *publicExponent;
+ITEM *privateExponent;
+ITEM *primes;
+ITEM *primeExponents;
+ITEM *coefficient;
+{
+  FULL_PRIVATE_KEY *fullKey;
+  int status;
+
+  /* Allocate memory for FULL_PRIVATE_KEY value.
+   */
+  if ((status = B_MemoryPoolAlloc
+       (&key->infoCache.memoryPool, (POINTER *)&fullKey,
+        sizeof (FULL_PRIVATE_KEY))) != 0)
+    return (status);
+  
+  /* Pre-zeroize and only copy in values that are not NULL.
+   */
+  T_memset ((POINTER)fullKey, 0, sizeof (*fullKey));
+  if (modulus != (ITEM *)NULL_PTR)
+    fullKey->modulus = *modulus;
+  if (publicExponent != (ITEM *)NULL_PTR)
+    fullKey->publicExponent = *publicExponent;
+  if (privateExponent != (ITEM *)NULL_PTR)
+    fullKey->privateExponent = *privateExponent;
+  if (primes != (ITEM *)NULL_PTR) {
+    fullKey->prime[0] = primes[0];
+    fullKey->prime[1] = primes[1];
+  }
+  if (primeExponents != (ITEM *)NULL_PTR) {
+    fullKey->primeExponent[0] = primeExponents[0];
+    fullKey->primeExponent[1] = primeExponents[1];
+  }
+  if (coefficient != (ITEM *)NULL_PTR)
+    fullKey->coefficient = *coefficient;
+  
+  return (B_InfoCacheAddInfo
+          (&key->infoCache, (POINTER)&KITFullPrivate, (POINTER)fullKey));
+}
+
+/* Select the key object's full private key and set all of the supplied
+     fields which are not (ITEM *)NULL_PTR.
+   primes and primeExponents point to a 2 entry ITEM array.
+   If one of the fields is not (ITEM *)NULL_PTR, but the full key's
+     field is null, return BE_WRONG_KEY_INFO.
+ */
+int GetFullPrivateKeyInfo
+  (modulus, publicExponent, privateExponent, primes, primeExponents,
+   coefficient, key)
+ITEM *modulus;
+ITEM *publicExponent;
+ITEM *privateExponent;
+ITEM *primes;
+ITEM *primeExponents;
+ITEM *coefficient;
+B_Key *key;
+{
+  FULL_PRIVATE_KEY *fullKey;
+  int status;
+  
+  if ((status = B_KeyGetInfo
+       (key, (POINTER *)&fullKey, &KITFullPrivate)) != 0)
+    return (status);
+
+  if (modulus != (ITEM *)NULL_PTR) {
+    if (fullKey->modulus.data == (unsigned char *)NULL_PTR)
+      return (BE_WRONG_KEY_INFO);
+    *modulus = fullKey->modulus;
+  }
+  if (publicExponent != (ITEM *)NULL_PTR) {
+    if (fullKey->publicExponent.data == (unsigned char *)NULL_PTR)
+      return (BE_WRONG_KEY_INFO);
+    *publicExponent = fullKey->publicExponent;
+  }
+  if (privateExponent != (ITEM *)NULL_PTR) {
+    if (fullKey->privateExponent.data == (unsigned char *)NULL_PTR)
+      return (BE_WRONG_KEY_INFO);
+    *privateExponent = fullKey->privateExponent;
+  }
+  if (primes != (ITEM *)NULL_PTR) {
+    if (fullKey->prime[0].data == (unsigned char *)NULL_PTR ||
+        fullKey->prime[1].data == (unsigned char *)NULL_PTR)
+      return (BE_WRONG_KEY_INFO);
+    primes[0] = fullKey->prime[0];
+    primes[1] = fullKey->prime[1];
+  }
+  if (primeExponents != (ITEM *)NULL_PTR) {
+    if (fullKey->primeExponent[0].data == (unsigned char *)NULL_PTR ||
+        fullKey->primeExponent[1].data == (unsigned char *)NULL_PTR)
+      return (BE_WRONG_KEY_INFO);
+    primeExponents[0] = fullKey->primeExponent[0];
+    primeExponents[1] = fullKey->primeExponent[1];
+  }
+  if (coefficient != (ITEM *)NULL_PTR) {
+    if (fullKey->coefficient.data == (unsigned char *)NULL_PTR)
+      return (BE_WRONG_KEY_INFO);
+    *coefficient = fullKey->coefficient;
+  }
+  
+  return (0);
+}
+
+/* This is not intended to be called from B_SetKeyInfo.
+   Get returns BE_WRONG_KEY_INFO.
+ */
+static int KITFullPrivateKeyAddInfo (key, info)
+B_Key *key;
+POINTER info;
+{
+UNUSED_ARG (key)
+UNUSED_ARG (info)
+  return (BE_ALG_OPERATION_UNKNOWN);
+}
+
diff --git a/lib/bind/dnssafe/kifulprv.h b/lib/bind/dnssafe/kifulprv.h
new file mode 100644 (file)
index 0000000..8e469ce
--- /dev/null
@@ -0,0 +1,12 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+int CacheFullPrivateKey PROTO_LIST
+  ((B_Key *, ITEM *, ITEM *, ITEM *, ITEM *, ITEM *, ITEM *));
+int GetFullPrivateKeyInfo PROTO_LIST
+  ((ITEM *, ITEM *, ITEM *, ITEM *, ITEM *, ITEM *, B_Key *));
diff --git a/lib/bind/dnssafe/kiitem.c b/lib/bind/dnssafe/kiitem.c
new file mode 100644 (file)
index 0000000..846f6dc
--- /dev/null
@@ -0,0 +1,46 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "kinfotyp.h"
+#include "kiitem.h"
+#include "port_after.h"
+
+int KITItemAddInfo PROTO_LIST ((B_Key *, POINTER));
+
+B_KeyInfoType KITItem = {KITItemAddInfo, B_KeyInfoTypeMakeError};
+
+int KI_Item (keyInfoType)
+POINTER *keyInfoType;
+{
+  *keyInfoType = (POINTER)&KITItem;
+
+  /* Return 1 to indicate a KeyInfoType, not an AlgorithmInfoType */
+  return (1);
+}
+
+/* info is an ITEM.  The ITEM's data is copied into the object.
+ */
+int KITItemAddInfo (key, info)
+B_Key *key;
+POINTER info;
+{
+  unsigned char *newData;
+  int status;
+  
+  if ((status = B_MemoryPoolAllocAndCopy
+       (&key->infoCache.memoryPool, (POINTER *)&newData,
+        (POINTER)((ITEM *)info)->data, ((ITEM *)info)->len)) != 0)
+    return (status);
+    
+  return (B_KeyAddItemInfo (key, newData, ((ITEM *)info)->len));
+}
+
diff --git a/lib/bind/dnssafe/kiitem.h b/lib/bind/dnssafe/kiitem.h
new file mode 100644 (file)
index 0000000..ab80cee
--- /dev/null
@@ -0,0 +1,9 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+extern B_KeyInfoType KITItem;
diff --git a/lib/bind/dnssafe/kinfotyp.c b/lib/bind/dnssafe/kinfotyp.c
new file mode 100644 (file)
index 0000000..a374c91
--- /dev/null
@@ -0,0 +1,28 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "kinfotyp.h"
+#include "port_after.h"
+
+/* This is the default routine which key info types can point MakeInfo to.
+ */
+int B_KeyInfoTypeMakeError (info, key)
+POINTER *info;
+B_Key *key;
+{
+UNUSED_ARG (info)
+UNUSED_ARG (key)
+
+  /* Should already have been found in the cache. */
+  return (BE_WRONG_KEY_INFO);
+}
+
diff --git a/lib/bind/dnssafe/kinfotyp.h b/lib/bind/dnssafe/kinfotyp.h
new file mode 100644 (file)
index 0000000..3f6ce7c
--- /dev/null
@@ -0,0 +1,57 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+typedef int (*KIT_ADD_INFO) PROTO_LIST ((B_Key *, POINTER));
+typedef int (*KIT_MAKE_INFO) PROTO_LIST ((POINTER *, B_Key *));
+
+/* The definition in C++ is:
+ class B_KeyInfoType {
+ public:
+   B_KeyInfoType (KIT_ADD_INFO AddInfo) {
+     _AddInfo = AddInfo;
+     _MakeInfo = KeyInfoType::makeError;}
+   B_KeyInfoType (KIT_ADD_INFO AddInfo, KIT_MAKE_INFO MakeInfo) {
+     _AddInfo = AddInfo;
+     _MakeInfo = MakeInfo;}
+
+   int addInfo (B_Key *key, POINTER info) {return (*_AddInfo) (key, info);}
+   int makeInfo (POINTER *info, B_Key *key) {return (*_MakeInfo) (info, key);}
+
+   static int makeError (POINTER *info, B_Key *key);
+
+ private:
+   KIT_ADD_INFO _AddInfo;
+   KIT_MAKE_INFO _MakeInfo;
+ };
+
+   Note that a derived class simply calls one of the B_KeyInfoType constructors
+     which set the addInfo or both the addInfo and makeInfo callbacks.
+   There is no need for an extra level involving virtual functions because
+     each key class only has one instance, making a V table a waste of space.
+   An example of a derived class is:
+
+ class KITItem : public B_KeyInfoType {
+ public:
+   // Set addInfo and leave makeInfo as B_KeyInfoType::makeError
+   KITItem () : B_KeyInfoType (KITItem::addInfo) {};
+
+   static int addInfo (B_Key *key, POINTER info);
+ };
+
+
+   There is one global instance which is used by B_Key::setInfo, etc.:
+   
+ KITItem KITItem;
+ */
+
+typedef struct B_KeyInfoType {
+  KIT_ADD_INFO AddInfo;
+  KIT_MAKE_INFO MakeInfo;
+} B_KeyInfoType;
+
+int B_KeyInfoTypeMakeError PROTO_LIST ((POINTER *, B_Key *));
diff --git a/lib/bind/dnssafe/kipkcrpr.c b/lib/bind/dnssafe/kipkcrpr.c
new file mode 100644 (file)
index 0000000..10177fe
--- /dev/null
@@ -0,0 +1,102 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "kinfotyp.h"
+#include "intitem.h"
+#include "kifulprv.h"
+#include "kipkcrpr.h"
+#include "port_after.h"
+
+B_KeyInfoType KIT_PKCS_RSAPrivate =
+  {KIT_PKCS_RSAPrivateAddInfo, KIT_PKCS_RSAPrivateMakeInfo};
+
+static A_PKCS_RSA_PRIVATE_KEY STATIC_PKCS_RSA_PRIVATE_KEY;
+static ITEM *PKCS_RSA_PRIVATE_KEY_ITEMS[] = {
+  &STATIC_PKCS_RSA_PRIVATE_KEY.modulus,
+  &STATIC_PKCS_RSA_PRIVATE_KEY.publicExponent,
+  &STATIC_PKCS_RSA_PRIVATE_KEY.privateExponent,
+  &STATIC_PKCS_RSA_PRIVATE_KEY.prime[0],
+  &STATIC_PKCS_RSA_PRIVATE_KEY.prime[1],
+  &STATIC_PKCS_RSA_PRIVATE_KEY.primeExponent[0],
+  &STATIC_PKCS_RSA_PRIVATE_KEY.primeExponent[1],
+  &STATIC_PKCS_RSA_PRIVATE_KEY.coefficient
+};
+
+int KI_PKCS_RSAPrivate (keyInfoType)
+POINTER *keyInfoType;
+{
+  *keyInfoType = (POINTER)&KIT_PKCS_RSAPrivate;
+
+  /* Return 1 to indicate a KeyInfoType, not an AlgorithmInfoType */
+  return (1);
+}
+
+int KIT_PKCS_RSAPrivateAddInfo (key, info)
+B_Key *key;
+POINTER info;
+{
+  A_PKCS_RSA_PRIVATE_KEY *newValue;
+  int status;
+  
+  /* Allocate memory for A_PKCS_RSA_PRIVATE_KEY struct and copy integers
+       from supplied value.
+   */
+  if ((status = B_MemoryPoolAlloc
+       (&key->infoCache.memoryPool, (POINTER *)&newValue,
+        sizeof (A_PKCS_RSA_PRIVATE_KEY))) != 0)
+    return (status);
+  if ((status = AllocAndCopyIntegerItems
+       ((POINTER)newValue, info, (POINTER)&STATIC_PKCS_RSA_PRIVATE_KEY,
+        PKCS_RSA_PRIVATE_KEY_ITEMS, sizeof (PKCS_RSA_PRIVATE_KEY_ITEMS) / 
+        sizeof (PKCS_RSA_PRIVATE_KEY_ITEMS[0]), &key->infoCache.memoryPool))
+      != 0)
+    return (status);
+    
+  /* Cache the full private key info.
+   */
+  if ((status = CacheFullPrivateKey
+       (key, &newValue->modulus, &newValue->publicExponent,
+        &newValue->privateExponent, newValue->prime, newValue->primeExponent,
+        &newValue->coefficient)) != 0)
+    return (status);
+  return (B_InfoCacheAddInfo
+          (&key->infoCache, (POINTER)&KIT_PKCS_RSAPrivate, (POINTER)newValue));
+}
+
+int KIT_PKCS_RSAPrivateMakeInfo (info, key)
+POINTER *info;
+B_Key *key;
+{
+  A_PKCS_RSA_PRIVATE_KEY keyValue;
+  int status;
+
+  /* If not already found in the cache, try to get values from
+     a full private key info.
+   */
+  if ((status = GetFullPrivateKeyInfo
+       (&keyValue.modulus, &keyValue.publicExponent,
+        &keyValue.privateExponent, keyValue.prime, keyValue.primeExponent,
+        &keyValue.coefficient, key)) != 0)
+    return (status);
+
+  /* Got all the needed fields, so allocate memory for a new
+     A_PKCS_RSA_PRIVATE_KEY struct and copy the key value.
+   */
+  if ((status = B_MemoryPoolAlloc
+       (&key->infoCache.memoryPool, info, sizeof (A_PKCS_RSA_PRIVATE_KEY)))
+      != 0)
+    return (status);
+    
+  **(A_PKCS_RSA_PRIVATE_KEY **)info = keyValue;
+  return (0);
+}
+
diff --git a/lib/bind/dnssafe/kipkcrpr.h b/lib/bind/dnssafe/kipkcrpr.h
new file mode 100644 (file)
index 0000000..9bcfc02
--- /dev/null
@@ -0,0 +1,13 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+extern B_KeyInfoType KIT_PKCS_RSAPrivate;
+
+int KIT_PKCS_RSAPrivateAddInfo PROTO_LIST ((B_Key *, POINTER));
+int KIT_PKCS_RSAPrivateMakeInfo PROTO_LIST ((POINTER *, B_Key *));
+
diff --git a/lib/bind/dnssafe/kirsacrt.c b/lib/bind/dnssafe/kirsacrt.c
new file mode 100644 (file)
index 0000000..ad086d7
--- /dev/null
@@ -0,0 +1,103 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "kinfotyp.h"
+#include "intitem.h"
+#include "kifulprv.h"
+#include "port_after.h"
+
+#define NULL_UCHAR_PTR ((unsigned char *)NULL_PTR)
+
+int KIT_RSA_CRTAddInfo PROTO_LIST ((B_Key *, POINTER));
+int KIT_RSA_CRTMakeInfo PROTO_LIST ((POINTER *, B_Key *));
+
+B_KeyInfoType KIT_RSA_CRT = {KIT_RSA_CRTAddInfo, KIT_RSA_CRTMakeInfo};
+
+static A_RSA_CRT_KEY STATIC_RSA_CRT_KEY;
+static ITEM *RSA_CRT_KEY_ITEMS[] = {
+  &STATIC_RSA_CRT_KEY.modulus, &STATIC_RSA_CRT_KEY.prime[0],
+  &STATIC_RSA_CRT_KEY.prime[1],
+  &STATIC_RSA_CRT_KEY.primeExponent[0],
+  &STATIC_RSA_CRT_KEY.primeExponent[1],
+  &STATIC_RSA_CRT_KEY.coefficient
+};
+
+/* args points to A_RSA_CRT_KEY.
+ */
+int KI_RSA_CRT (keyInfoType)
+POINTER *keyInfoType;
+{
+  *keyInfoType = (POINTER)&KIT_RSA_CRT;
+
+  /* Return 1 to indicate a KeyInfoType, not an AlgorithmInfoType */
+  return (1);
+}
+
+int KIT_RSA_CRTAddInfo (key, info)
+B_Key *key;
+POINTER info;
+{
+  A_RSA_CRT_KEY *newValue;
+  int status;
+  
+  /* Allocate memory for A_RSA_CRT_KEY struct and copy integers
+       from supplied value.
+     */
+  if ((status = B_MemoryPoolAlloc
+       (&key->infoCache.memoryPool, (POINTER *)&newValue,
+        sizeof (A_RSA_CRT_KEY))) != 0)
+    return (status);
+  if ((status = AllocAndCopyIntegerItems
+       ((POINTER)newValue, info, (POINTER)&STATIC_RSA_CRT_KEY,
+        RSA_CRT_KEY_ITEMS,
+        sizeof (RSA_CRT_KEY_ITEMS) / sizeof (RSA_CRT_KEY_ITEMS[0]),
+        &key->infoCache.memoryPool)) != 0)
+    return (status);
+
+  /* Cache the full private key info, setting unused fields to NULL.
+   */
+  if ((status = CacheFullPrivateKey
+       (key, &newValue->modulus, (ITEM *)NULL_PTR, (ITEM *)NULL_PTR,
+        newValue->prime, newValue->primeExponent, &newValue->coefficient))
+      != 0)
+    return (status);
+  return (B_InfoCacheAddInfo
+          (&key->infoCache, (POINTER)&KIT_RSA_CRT, (POINTER)newValue));
+}
+
+int KIT_RSA_CRTMakeInfo (info, key)
+POINTER *info;
+B_Key *key;
+{
+  A_RSA_CRT_KEY keyValue;
+  int status;
+
+  /* If not already found in the cache, try to get values from
+       a full private key info, setting unneeded entries to NULL.
+   */
+  if ((status = GetFullPrivateKeyInfo
+       (&keyValue.modulus, (ITEM *)NULL_PTR, (ITEM *)NULL_PTR,
+        keyValue.prime, keyValue.primeExponent, &keyValue.coefficient,
+        key)) != 0)
+    return (status);
+
+  /* Got all the needed fields, so allocate memory for a new
+       A_RSA_CRT_KEY struct and copy the key value.
+   */
+  if ((status = B_MemoryPoolAlloc
+       (&key->infoCache.memoryPool, info, sizeof (A_RSA_CRT_KEY))) != 0)
+    return (status);
+    
+  **(A_RSA_CRT_KEY **)info = keyValue;
+  return (0);
+}
+
diff --git a/lib/bind/dnssafe/kirsapub.c b/lib/bind/dnssafe/kirsapub.c
new file mode 100644 (file)
index 0000000..bb55c31
--- /dev/null
@@ -0,0 +1,82 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "kinfotyp.h"
+#include "intitem.h"
+#include "kifulprv.h"
+#include "kirsapub.h"
+#include "port_after.h"
+
+B_KeyInfoType KIT_RSAPublic =
+  {KIT_RSAPublicAddInfo, KIT_RSAPublicMakeInfo};
+
+static A_RSA_KEY STATIC_RSA_KEY;
+static ITEM *RSA_KEY_ITEMS[] =
+  {&STATIC_RSA_KEY.modulus, &STATIC_RSA_KEY.exponent};
+
+int KI_RSAPublic (keyInfoType)
+POINTER *keyInfoType;
+{
+  *keyInfoType = (POINTER)&KIT_RSAPublic;
+
+  /* Return 1 to indicate a KeyInfoType, not an AlgorithmInfoType */
+  return (1);
+}
+
+int KIT_RSAPublicAddInfo (key, info)
+B_Key *key;
+POINTER info;
+{
+  POINTER newValue;
+  int status;
+  
+  /* Allocate memory for A_RSA_KEY struct and copy integers
+       from supplied value.
+     */
+  if ((status = B_MemoryPoolAlloc
+       (&key->infoCache.memoryPool, &newValue, sizeof (A_RSA_KEY))) != 0)
+    return (status);
+  if ((status = AllocAndCopyIntegerItems
+       (newValue, info, (POINTER)&STATIC_RSA_KEY, RSA_KEY_ITEMS,
+        sizeof (RSA_KEY_ITEMS) / sizeof (RSA_KEY_ITEMS[0]),
+        &key->infoCache.memoryPool)) != 0)
+    return (status);
+    
+  return (B_InfoCacheAddInfo
+          (&key->infoCache, (POINTER)&KIT_RSAPublic, newValue));
+}
+
+int KIT_RSAPublicMakeInfo (info, key)
+POINTER *info;
+B_Key *key;
+{
+  A_RSA_KEY keyValue;
+  int status;
+  
+  /* If not already found in the cache, try to get values from
+       a full private key info, setting unneeded entries to NULL.
+   */
+  if ((status = GetFullPrivateKeyInfo
+       (&keyValue.modulus, &keyValue.exponent, (ITEM *)NULL_PTR,
+        (ITEM *)NULL_PTR, (ITEM *)NULL_PTR, (ITEM *)NULL_PTR, key)) != 0)
+    return (status);
+
+  /* Got all the needed fields, so allocate memory for a new
+       A_RSA_KEY struct and copy the key value.
+   */
+  if ((status = B_MemoryPoolAlloc
+       (&key->infoCache.memoryPool, info, sizeof (A_RSA_KEY))) != 0)
+    return (status);
+    
+  **(A_RSA_KEY **)info = keyValue;
+  return (0);
+}
diff --git a/lib/bind/dnssafe/kirsapub.h b/lib/bind/dnssafe/kirsapub.h
new file mode 100644 (file)
index 0000000..485fd79
--- /dev/null
@@ -0,0 +1,13 @@
+/* Copyright (C) RSA Data Security, Inc. created 1993, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+extern B_KeyInfoType KIT_RSAPublic;
+
+int KIT_RSAPublicAddInfo PROTO_LIST ((B_Key *, POINTER));
+int KIT_RSAPublicMakeInfo PROTO_LIST ((POINTER *, B_Key *));
+
diff --git a/lib/bind/dnssafe/md5.c b/lib/bind/dnssafe/md5.c
new file mode 100644 (file)
index 0000000..ed45242
--- /dev/null
@@ -0,0 +1,283 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "algae.h"
+#include "md5.h"
+#include "port_after.h"
+
+/* Constants for MD5Transform routine.
+ */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+static void MD5Transform PROTO_LIST ((UINT4 [4], const unsigned char [64]));
+static void Encode PROTO_LIST ((unsigned char *, UINT4 *, unsigned int));
+static void Decode PROTO_LIST ((UINT4 *, const unsigned char *, unsigned int));
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+   Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+    (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+    (a) = ROTATE_LEFT ((a), (s)); \
+    (a) += (b); \
+  }
+#define GG(a, b, c, d, x, s, ac) { \
+    (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+    (a) = ROTATE_LEFT ((a), (s)); \
+    (a) += (b); \
+  }
+#define HH(a, b, c, d, x, s, ac) { \
+    (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+    (a) = ROTATE_LEFT ((a), (s)); \
+    (a) += (b); \
+  }
+#define II(a, b, c, d, x, s, ac) { \
+    (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+    (a) = ROTATE_LEFT ((a), (s)); \
+    (a) += (b); \
+  }
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context.
+ */
+void A_MD5Init (context)
+A_MD5_CTX *context;
+{
+  context->count[0] = context->count[1] = 0;
+
+  /* Load magic initialization constants.
+   */
+  context->state[0] = 0x67452301;
+  context->state[1] = 0xefcdab89;
+  context->state[2] = 0x98badcfe;
+  context->state[3] = 0x10325476;
+}
+
+/* MD5 block update operation. Continues an MD5 message-digest
+     operation, processing another message block, and updating the
+     context.
+ */
+void A_MD5Update (context, input, inputLen)
+A_MD5_CTX *context;
+const unsigned char *input;                         /* input block */
+unsigned int inputLen;                              /* length of input block */
+{
+  unsigned int i, index, partLen;
+
+  /* Compute number of bytes mod 64 */
+  index = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+  /* Update number of bits */
+  if ((context->count[0] += ((UINT4)inputLen << 3)) < ((UINT4)inputLen << 3))
+    context->count[1]++;
+  context->count[1] += ((UINT4)inputLen >> 29);
+
+  partLen = 64 - index;
+
+  /* Transform as many times as possible.
+   */
+  if (inputLen >= partLen) {
+    T_memcpy ((POINTER)&context->buffer[index], (CPOINTER)input, partLen);
+    MD5Transform (context->state, context->buffer);
+  
+    for (i = partLen; i + 63 < inputLen; i += 64)
+      MD5Transform (context->state, &input[i]);
+    
+    index = 0;
+  }
+  else
+    i = 0;
+  
+  /* Buffer remaining input */
+  T_memcpy ((POINTER)&context->buffer[index], (CPOINTER)&input[i], inputLen-i);
+}
+
+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
+     the message digest and zeroizing the context.
+   Assume digest buffer is at least A_MD5_DIGEST_LEN.
+ */
+void A_MD5Final (context, digest)
+A_MD5_CTX *context;
+unsigned char *digest;
+{
+  unsigned char bits[8], pad[64];
+  unsigned int index, padLen;
+
+  /* Save number of bits */
+  Encode (bits, context->count, 8);
+
+  /* Pad out to 56 mod 64.
+   */
+  index = (unsigned int)((context->count[0] >> 3) & 0x3f);
+  padLen = (index < 56) ? (56 - index) : (120 - index);
+  T_memset ((POINTER)pad, 0, padLen);
+  pad[0] = 0x80;
+  A_MD5Update (context, pad, padLen);
+
+  /* Append length (before padding) */
+  A_MD5Update (context, bits, 8);
+
+  /* Store state in digest */
+  Encode (digest, context->state, 16);
+
+  /* Restart the context. */
+  A_MD5Init (context);
+}
+
+/* MD5 basic transformation. Transforms state based on block.
+ */
+static void MD5Transform (state, block)
+UINT4 state[4];
+const unsigned char block[64];
+{
+  UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+  Decode (x, block, 64);
+
+  /* Round 1 */
+  FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+  FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+  FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+  FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+  FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+  FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+  FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+  FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+  FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+  FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+  FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+  FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+  FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+  FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+  FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+  FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+  /* Round 2 */
+  GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+  GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+  GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+  GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+  GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+  GG (d, a, b, c, x[10], S22,  0x2441453); /* 22 */
+  GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+  GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+  GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+  GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+  GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+  GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+  GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+  GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+  GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+  GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+  /* Round 3 */
+  HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+  HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+  HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+  HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+  HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+  HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+  HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+  HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+  HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+  HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+  HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+  HH (b, c, d, a, x[ 6], S34,  0x4881d05); /* 44 */
+  HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+  HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+  HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+  HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+  /* Round 4 */
+  II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+  II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+  II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+  II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+  II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+  II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+  II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+  II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+  II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+  II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+  II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+  II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+  II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+  II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+  II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+  II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+  state[0] += a;
+  state[1] += b;
+  state[2] += c;
+  state[3] += d;
+  
+  /* Zeroize sensitive information.
+   */
+  T_memset ((POINTER)x, 0, sizeof (x));
+}
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is
+     a multiple of 4.
+ */
+static void Encode (output, input, len)
+unsigned char *output;
+UINT4 *input;
+unsigned int len;
+{
+  unsigned int i, j;
+
+  for (i = 0, j = 0; j < len; i++, j += 4) {
+    output[j] = (unsigned char)(input[i] & 0xff);
+    output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+    output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+    output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+  }
+}
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
+     a multiple of 4.
+ */
+static void Decode (output, input, len)
+UINT4 *output;
+const unsigned char *input;
+unsigned int len;
+{
+  unsigned int i, j;
+
+  for (i = 0, j = 0; j < len; i++, j += 4)
+    output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
+      (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
+
diff --git a/lib/bind/dnssafe/md5.h b/lib/bind/dnssafe/md5.h
new file mode 100644 (file)
index 0000000..ebfaed7
--- /dev/null
@@ -0,0 +1,32 @@
+/* Copyright (C) RSA Data Security, Inc. created 1994, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _MD5_H_
+#define _MD5_H_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define A_MD5_DIGEST_LEN 16
+
+typedef struct {
+  UINT4 state[4];                                            /* state (ABCD) */
+  UINT4 count[2];                 /* number of bits, modulo 2^64 (lsb first) */
+  unsigned char buffer[64];                                  /* input buffer */
+} A_MD5_CTX;
+
+void A_MD5Init PROTO_LIST ((A_MD5_CTX *));
+void A_MD5Update PROTO_LIST ((A_MD5_CTX *, const unsigned char *, unsigned int));
+void A_MD5Final PROTO_LIST ((A_MD5_CTX *, unsigned char *));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/bind/dnssafe/md5rand.c b/lib/bind/dnssafe/md5rand.c
new file mode 100644 (file)
index 0000000..ca39311
--- /dev/null
@@ -0,0 +1,71 @@
+/* Copyright (C) RSA Data Security, Inc. created 1994, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+/* Define this so that the type of the 'this' pointer in the
+     virtual functions will be correct for this derived class.
+ */
+struct A_MD5_RANDOM_CTX;
+#define THIS_DIGEST_RANDOM struct A_MD5_RANDOM_CTX
+
+#include "port_before.h"
+#include "global.h"
+#include "algae.h"
+#include "md5rand.h"
+#include "port_after.h"
+
+static void A_MD5RandomDigestUpdate PROTO_LIST
+  ((A_MD5_RANDOM_CTX *, unsigned char *, unsigned int));
+static void A_MD5RandomDigestFinal PROTO_LIST
+  ((A_MD5_RANDOM_CTX *, unsigned char *));
+
+static A_DigestRandomVTable V_TABLE =
+  {A_MD5RandomDigestUpdate, A_MD5RandomDigestFinal};
+
+void A_MD5RandomInit (context)
+A_MD5_RANDOM_CTX *context;
+{
+  /* Initialize "base class" */
+  A_DigestRandomInit
+    (&context->digestRandom, A_MD5_DIGEST_LEN, context->state);
+
+  /* Initialize digest algorithm and set vTable.
+   */
+  A_MD5Init (&context->md5Context);
+  context->digestRandom.vTable = &V_TABLE;
+}
+
+void A_MD5RandomUpdate (context, input, inputLen)
+A_MD5_RANDOM_CTX *context;
+unsigned char *input;
+unsigned int inputLen;
+{
+  A_DigestRandomUpdate (&context->digestRandom, input, inputLen);
+}
+
+void A_MD5RandomGenerateBytes (context, output, outputLen)
+A_MD5_RANDOM_CTX *context;
+unsigned char *output;
+unsigned int outputLen;
+{
+  A_DigestRandomGenerateBytes (&context->digestRandom, output, outputLen);
+}
+
+static void A_MD5RandomDigestUpdate (context, input, inputLen)
+A_MD5_RANDOM_CTX *context;
+unsigned char *input;
+unsigned int inputLen;
+{
+  A_MD5Update (&context->md5Context, input, inputLen);
+}
+
+static void A_MD5RandomDigestFinal (context, digest)
+A_MD5_RANDOM_CTX *context;
+unsigned char *digest;
+{
+  A_MD5Final (&context->md5Context, digest);
+}
diff --git a/lib/bind/dnssafe/md5rand.h b/lib/bind/dnssafe/md5rand.h
new file mode 100644 (file)
index 0000000..f197410
--- /dev/null
@@ -0,0 +1,36 @@
+/* Copyright (C) RSA Data Security, Inc. created 1994, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _MD5RAND_H_
+#define _MD5RAND_H_ 1
+
+#include "digrand.h"
+#include "md5.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct A_MD5_RANDOM_CTX {
+  A_DigestRandom digestRandom;                               /* "base class" */
+  
+  unsigned char state[3 * A_MD5_DIGEST_LEN];
+  A_MD5_CTX md5Context;
+} A_MD5_RANDOM_CTX;
+
+void A_MD5RandomInit PROTO_LIST ((A_MD5_RANDOM_CTX *));
+void A_MD5RandomUpdate PROTO_LIST
+  ((A_MD5_RANDOM_CTX *, unsigned char *, unsigned int));
+void A_MD5RandomGenerateBytes PROTO_LIST
+  ((A_MD5_RANDOM_CTX *, unsigned char *, unsigned int));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/bind/dnssafe/prime.c b/lib/bind/dnssafe/prime.c
new file mode 100644 (file)
index 0000000..14bab25
--- /dev/null
@@ -0,0 +1,166 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "algae.h"
+#include "bigmath.h"
+#include "prime.h"
+#include "port_after.h"
+
+static unsigned char SMALL_PRIME[]= {3, 5, 7, 11, 13, 17, 19, 23, 29, 31};
+
+/* Prime finding routine.
+   Returns 0, AE_CANCEL, AE_NEED_RANDOM.
+ */
+int PrimeFind
+  (prime, primeSizeBits, primeWords, ee, modulusWords, randomBlock,
+   surrenderContext)
+UINT2 *prime;
+unsigned int primeSizeBits;
+unsigned int primeWords;
+UINT2 *ee;
+unsigned int modulusWords;
+unsigned char *randomBlock;
+A_SURRENDER_CTX *surrenderContext;
+{
+  UINT2 t1[MAX_RSA_MODULUS_WORDS], u1[MAX_RSA_MODULUS_WORDS],
+    u2[MAX_RSA_MODULUS_WORDS], u3[MAX_RSA_MODULUS_WORDS],
+    u4[MAX_RSA_MODULUS_WORDS];
+  char sieve[1000];
+  int status = 0;
+  unsigned int i, r, s, testResult;
+  
+  do {
+    /* Create a starting point for the prime from the random block */
+    for (i = 0; i < primeWords; i++) {
+      prime[i] = (UINT2)((UINT2)randomBlock[0] << 8) + randomBlock[1];
+      randomBlock += 2;
+    }
+
+    /* set high order two bits */
+    BigSetbit (prime, primeSizeBits-2);
+    BigSetbit (prime, primeSizeBits-1);   
+    for (i = primeSizeBits; i < (unsigned int)(16 * primeWords); i++) 
+      BigClrbit (prime, i);
+
+    /* force p to be even */
+    BigClrbit (prime, 0);
+  
+    /* clear sieve and mark even positions */
+    for (i = 0; i < 1000; i += 2) {
+      sieve[i] = 1;
+      sieve[i+1] = 0;
+    }
+
+    /* sieve by all odd numbers (don't bother with primality checking) */
+    for (s = 3; s < 9000; s += 2) {
+      /* increase likelihood that s is prime */
+      for (i = 0; i < 5; i++)
+        if (s > SMALL_PRIME[i] && !(s % SMALL_PRIME[i]))
+          continue;
+
+      /* sieve based on s */
+      r = BigSmod (prime, s, primeWords);
+
+      /* returns prime modulo s */
+      if (r == 0)
+        r = s;
+
+      for (i = s - r; i < 1000; i += s)
+        sieve[i] = 1;
+    }
+  
+    /* t1 = 1 */
+    BigConst (t1, 1, modulusWords);
+
+    /* now check for primality of values with unmarked sieve */
+    testResult = 0;
+    for (i = 0; i < 1000; i++, BigInc (prime, primeWords)) {
+      if (sieve[i])
+        continue;
+
+      /* copy prime into big variable */
+      BigZero (u4, modulusWords);
+      BigCopy (u4, prime, primeWords);
+
+      /* set u4 = p - 1 */
+      BigDec (u4, modulusWords);
+      BigPegcd (u1, u2, u3, ee, u4, modulusWords);
+
+      /* Now u1 = gcd (E, t1).
+         Test (E, t1)==1 */
+      if (BigCmp (t1, u1, modulusWords))
+        continue;
+
+      /* check for pseudo primality */
+      if ((status = PseudoPrime
+           (&testResult, prime, primeWords, surrenderContext)) != 0)
+        break;
+      if (testResult)
+        /* testResult is set and will cause a break out of while (1) loop */
+        break;
+    }
+    if (status)
+      break;
+    
+    if (!testResult)
+      /* Couldn't find a prime with the supplied random block, so ask
+           caller to generate another random block and try again. */
+      status = AE_NEED_RANDOM;
+  } while (0);
+
+  T_memset ((POINTER)u1, 0, sizeof (u1));
+  T_memset ((POINTER)u2, 0, sizeof (u2));
+  T_memset ((POINTER)u3, 0, sizeof (u3));
+  T_memset ((POINTER)u4, 0, sizeof (u4));
+  return (status);
+}
+
+/* Pseudo-primality test.
+      If pseudo prime, *testResult = 1, else *testResult = 0.
+   Returns 0, AE_CANCEL.
+ */
+int PseudoPrime (testResult, prime, primeWords, surrenderContext) 
+unsigned int *testResult;
+UINT2 *prime;
+unsigned int primeWords;
+A_SURRENDER_CTX *surrenderContext;
+{
+  UINT2 base[MAX_RSA_MODULUS_WORDS], remainder[MAX_RSA_MODULUS_WORDS];
+  int status;
+  unsigned int i;
+
+  /* Default testResult to false. */
+  *testResult = 0;
+  
+  /* Prepare for setting base vector to the small prime. */
+  T_memset ((POINTER)base, 0, sizeof (base));
+  
+  for (i = 0; i < 4; i++) {
+    /* check to see if target is multiple of SMALL_PRIME */
+    if (BigSmod (prime, (unsigned int)SMALL_PRIME[i], primeWords) == 0)
+      /* fail... */
+      return (0);
+
+    /* Fermat test.  Compute remainder = base ^ prime mod prime
+         and compare the base to the remainder.
+     */
+    base[0] = (UINT2)SMALL_PRIME[i];
+    if ((status = BigModExp
+         (remainder, base, prime, prime, primeWords, surrenderContext)) != 0)
+      return (status);
+    if (BigCmp (remainder, base, primeWords) != 0)
+      /* fail... */
+      return (0);
+  }
+
+  *testResult = 1;
+  return (0);
+}
+
diff --git a/lib/bind/dnssafe/prime.h b/lib/bind/dnssafe/prime.h
new file mode 100644 (file)
index 0000000..e922f36
--- /dev/null
@@ -0,0 +1,26 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _PRIME_H_
+#define _PRIME_H_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int PrimeFind PROTO_LIST
+  ((UINT2 *, unsigned int, unsigned int, UINT2 *, unsigned int,
+    unsigned char *, A_SURRENDER_CTX *));
+int PseudoPrime PROTO_LIST
+  ((unsigned int *, UINT2 *, unsigned int, A_SURRENDER_CTX *));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/bind/dnssafe/random.c b/lib/bind/dnssafe/random.c
new file mode 100644 (file)
index 0000000..1ddb188
--- /dev/null
@@ -0,0 +1,60 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "bsafe2.h"
+#include "bkey.h"
+#include "balg.h"
+#include "ainfotyp.h"
+#include "algobj.h"
+#include "port_after.h"
+
+int B_RandomInit
+  (algorithmObject, algorithmChooser, surrenderContext)
+B_ALGORITHM_OBJ algorithmObject;
+B_ALGORITHM_CHOOSER algorithmChooser;
+A_SURRENDER_CTX *surrenderContext;
+{
+  if (AlgorithmWrapCheck (THE_ALG_WRAP) != 0)
+    /* Assume error is B_ALGORITHM_OBJ */
+    return (BE_RANDOM_OBJ);
+
+  return (B_AlgorithmRandomInit
+          (&THE_ALG_WRAP->algorithm, algorithmChooser, surrenderContext));
+}
+
+int B_RandomUpdate (algorithmObject, input, inputLen, surrenderContext)
+B_ALGORITHM_OBJ algorithmObject;
+unsigned char *input;
+unsigned int inputLen;
+A_SURRENDER_CTX *surrenderContext;
+{
+  if (AlgorithmWrapCheck (THE_ALG_WRAP) != 0)
+    /* Assume error is B_ALGORITHM_OBJ */
+    return (BE_RANDOM_OBJ);
+
+  return (B_AlgorithmRandomUpdate
+          (&THE_ALG_WRAP->algorithm, input, inputLen, surrenderContext));
+}
+
+int B_GenerateRandomBytes
+  (algorithmObject, output, outputLen, surrenderContext)
+B_ALGORITHM_OBJ algorithmObject;
+unsigned char *output;
+unsigned int outputLen;
+A_SURRENDER_CTX *surrenderContext;
+{
+  if (AlgorithmWrapCheck (THE_ALG_WRAP) != 0)
+    /* Assume error is B_ALGORITHM_OBJ */
+    return (BE_RANDOM_OBJ);
+
+  return (B_AlgorithmGenerateRandomBytes
+          (&THE_ALG_WRAP->algorithm, output, outputLen, surrenderContext));
+}
+
diff --git a/lib/bind/dnssafe/rsa.c b/lib/bind/dnssafe/rsa.c
new file mode 100644 (file)
index 0000000..64bc5e6
--- /dev/null
@@ -0,0 +1,211 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "algae.h"
+#include "rsa.h"
+#include "bigmath.h"
+#include "port_after.h"
+
+/* RSA encryption/decryption with full exponent.
+ */
+
+#define GENERATE_BREAK(type) { \
+    status = type; \
+    break; \
+  }
+
+static int RSA PROTO_LIST
+  ((A_RSA_CTX *, unsigned char *, unsigned int *, unsigned int,
+    const unsigned char *, A_SURRENDER_CTX *));
+
+/* Returns 0, AE_MODULUS_LEN, AE_KEY_INFO.
+ */
+int A_RSAInit (context, key)
+A_RSA_CTX *context;
+A_RSA_KEY *key;
+{
+  if (A_IntegerBits (key->modulus.data, key->modulus.len)
+      > MAX_RSA_MODULUS_BITS)
+    /* Key size is too big to handle. */
+    return (AE_MODULUS_LEN);
+
+  /* Set the block update blockLen to be big enough to hold the modulus. */
+  context->blockLen =
+    (A_IntegerBits (key->modulus.data, key->modulus.len) + 7) / 8;
+
+  context->inputLen = 0;
+
+  /* convert modulus to bignum representation */
+  if (CanonicalToBig
+      (context->modulus, MAX_RSA_MODULUS_WORDS, key->modulus.data,
+       key->modulus.len))
+    return (AE_KEY_INFO);
+
+  /* compute significant length of modulus */
+  context->modulusWords = BigLen
+    (context->modulus, MAX_RSA_MODULUS_WORDS) / 16 + 1;
+
+  /* convert exponent to bignum representation */
+  if (CanonicalToBig
+      (context->exponent, context->modulusWords,
+       key->exponent.data, key->exponent.len))
+    return (AE_KEY_INFO);
+
+  return (0);
+}
+
+int A_RSAUpdate
+  (context, partOut, partOutLen, maxPartOutLen, partIn, partInLen,
+   surrenderContext)
+A_RSA_CTX *context;
+unsigned char *partOut;
+unsigned int *partOutLen;
+unsigned int maxPartOutLen;
+const unsigned char *partIn;
+unsigned int partInLen;
+A_SURRENDER_CTX *surrenderContext;
+{
+  int status;
+  unsigned int partialLen, localPartOutLen;
+
+  /* Initialize partOutLen to zero. */
+  *partOutLen = 0;
+
+  if (context->inputLen + partInLen < context->blockLen) {
+    /* Not enough to encrypt - just accumulate.
+     */
+    T_memcpy
+      ((POINTER)(context->input + context->inputLen), (CPOINTER)partIn,
+       partInLen);
+    context->inputLen += partInLen;
+    return (0);
+  }
+  
+  if (context->inputLen > 0) {
+    /* Need to accumulate the rest of the block bytes into the input and
+         encrypt from there (otherwise it's OK to encrypt straight from
+         the partIn).
+     */
+    partialLen = context->blockLen - context->inputLen;
+    T_memcpy
+      ((POINTER)(context->input + context->inputLen), (CPOINTER)partIn,
+       partialLen);
+    partIn += partialLen;
+    partInLen -= partialLen;
+    
+    if ((status = RSA
+         (context, partOut, &localPartOutLen, maxPartOutLen, context->input,
+          surrenderContext)) != 0)
+      return (status);
+    (*partOutLen) += localPartOutLen;
+    partOut += localPartOutLen;
+    maxPartOutLen -= localPartOutLen;
+  }
+
+  /* Encrypt as many blocks of input as provided.
+   */
+  while (partInLen >= context->blockLen) {
+    if ((status = RSA
+         (context, partOut, &localPartOutLen, maxPartOutLen, partIn,
+          surrenderContext)) != 0)
+      return (status);
+    
+    partIn += context->blockLen;
+    partInLen -= context->blockLen;
+    (*partOutLen) += localPartOutLen;
+    partOut += localPartOutLen;
+    maxPartOutLen -= localPartOutLen;
+  }
+  
+  /* Copy remaining input bytes to the context's input buffer.
+   */
+  T_memcpy
+    ((POINTER)context->input, partIn, context->inputLen = partInLen);
+  return (0);
+}
+
+int A_RSAFinal (context)
+A_RSA_CTX *context;
+{
+  if (context->inputLen != 0)
+    return (AE_INPUT_LEN);
+  
+  /* Restart context to accumulate a new block. */
+  context->inputLen = 0;
+  return (0);
+}
+
+/* Assume input length is context->blockLen.
+ */
+static int RSA
+  (context, output, outputLen, maxOutputLen, input, surrenderContext)
+A_RSA_CTX *context;
+unsigned char *output;
+unsigned int *outputLen;
+unsigned int maxOutputLen;
+const unsigned char *input;
+A_SURRENDER_CTX *surrenderContext;
+{
+  struct ModExpFrame {
+    UINT2 bigInBuf[MAX_RSA_MODULUS_WORDS], bigOutBuf[MAX_RSA_MODULUS_WORDS];
+  } *frame = (struct ModExpFrame *)NULL_PTR;
+#if !USE_ALLOCED_FRAME
+  struct ModExpFrame stackFrame;
+#endif
+  int status;
+
+  status = 0;
+  do {
+    if ((*outputLen = context->blockLen) > maxOutputLen)
+      return (AE_OUTPUT_LEN);
+    
+#if USE_ALLOCED_FRAME
+    if ((frame = (struct ModExpFrame *)T_malloc (sizeof (*frame)))
+        == (struct ModExpFrame *)NULL_PTR) {
+      status = AE_ALLOC;
+      break;
+    }
+#else
+    /* Just use the buffers allocated on the stack. */
+    frame = &stackFrame;
+#endif
+
+    /* Convert input to bignum representation.
+       This won't return AE_DATA since input length was checked at Update.
+     */
+    CanonicalToBig
+      (frame->bigInBuf, context->modulusWords, input, context->blockLen);
+  
+    /* Check for overflow. */
+    if (BigCmp (frame->bigInBuf, context->modulus, context->modulusWords) >= 0)
+      GENERATE_BREAK (AE_INPUT_DATA);
+    
+    /* Exponentiate. */
+    if ((status = BigModExp
+         (frame->bigOutBuf, frame->bigInBuf, context->exponent,
+          context->modulus, context->modulusWords, surrenderContext)) != 0)
+      break;
+
+    /* Convert output to canonical representation.
+       This won't return AE_DATA since outputLen was set above.
+     */
+    BigToCanonical
+      (output, *outputLen, frame->bigOutBuf, context->modulusWords);
+  } while (0);
+  
+  if (frame != (struct ModExpFrame *)NULL_PTR) {
+    T_memset ((POINTER)frame, 0, sizeof (*frame));
+#if USE_ALLOCED_FRAME
+    T_free ((POINTER)frame);
+#endif
+  }
+
+  return (status);
+}
diff --git a/lib/bind/dnssafe/rsa.h b/lib/bind/dnssafe/rsa.h
new file mode 100644 (file)
index 0000000..153263f
--- /dev/null
@@ -0,0 +1,44 @@
+/* Copyright (C) RSA Data Security, Inc. created 1994, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _RSA_H_
+#define _RSA_H_ 1
+
+#include "bigmaxes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Note, these are only valid after a call to A_RSAInit.
+ */
+#define A_RSA_BLOCK_LEN(context) ((context)->blockLen)
+#define A_RSA_MAX_OUTPUT_LEN(context, inputLen)\
+  (inputLen) + (((inputLen) % (context)->blockLen) ?\
+                (context)->blockLen - ((inputLen) % (context)->blockLen) : 0)
+
+typedef struct {
+  unsigned int blockLen;          /* total size for the block to be computed */
+  unsigned char input[MAX_RSA_MODULUS_LEN];
+  unsigned int inputLen;
+  unsigned int modulusWords;
+  UINT2 modulus[MAX_RSA_MODULUS_WORDS];
+  UINT2 exponent[MAX_RSA_MODULUS_WORDS];
+} A_RSA_CTX;
+
+int A_RSAInit PROTO_LIST ((A_RSA_CTX *, A_RSA_KEY *));
+int A_RSAUpdate PROTO_LIST
+  ((A_RSA_CTX *, unsigned char *, unsigned int *, unsigned int,
+    const unsigned char *, unsigned int, A_SURRENDER_CTX *));
+int A_RSAFinal PROTO_LIST ((A_RSA_CTX *));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/bind/dnssafe/rsakeygn.c b/lib/bind/dnssafe/rsakeygn.c
new file mode 100644 (file)
index 0000000..bad9e8c
--- /dev/null
@@ -0,0 +1,244 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "algae.h"
+#include "bigmath.h"
+#include "surrendr.h"
+#include "prime.h"
+#include "rsakeygn.h"
+#include "port_after.h"
+
+#define GENERATE_BREAK(type) { \
+    status = type; \
+    break; \
+  }
+
+static int RSAParameters PROTO_LIST
+  ((UINT2 *, UINT2 *, UINT2 *, UINT2 *, UINT2 *, UINT2 *, UINT2 *, UINT2 *,
+    unsigned int, unsigned int, A_SURRENDER_CTX *));
+static void SetRSAKeyGenResult PROTO_LIST
+  ((A_PKCS_RSA_PRIVATE_KEY *, A_RSA_KEY_GEN_CTX *, UINT2 *, UINT2 *));
+
+int A_RSAKeyGenInit (context, params)
+A_RSA_KEY_GEN_CTX *context;
+A_RSA_KEY_GEN_PARAMS *params;
+{
+  context->modulusBits = params->modulusBits;
+  
+  /* Prezeroize big public exponent vector. */
+  T_memset
+    ((POINTER)context->bigPublicExponent, 0,
+     sizeof (context->bigPublicExponent));
+    
+  /* Copy public exponent into big vector */
+  if (CanonicalToBig
+      (context->bigPublicExponent, MAX_RSA_MODULUS_WORDS,
+       params->publicExponent.data, params->publicExponent.len) != 0)
+    /* could not copy exponent into MAX_RSA_MODULUS_WORDS */
+    return (AE_EXPONENT_LEN);
+
+  /* Check that public exponent is in bounds and odd.
+   */
+  if (BigLen (context->bigPublicExponent, MAX_RSA_MODULUS_WORDS) >=
+      context->modulusBits)
+    return (AE_EXPONENT_LEN);
+  if (!(context->bigPublicExponent[0] & 1))
+    return (AE_EXPONENT_EVEN);
+
+  return (0);
+}
+
+/* This generates an RSA keypair of size modulusBits with the fixed
+     publicExponent, pointing result to the resulting integers.  The
+     resulting integer data is in the context, so that the values must be
+     copied before the context is zeroized.
+   All integers are unsigned canonical bytes arrays with the most significant
+     byte first.
+   The randomBlock is of length randomBlockLen returned by RSAKeyGenQuery.
+   This assumes that the modulusBits size was checked by RSAKeyGenQuery.
+ */
+int A_RSAKeyGen (context, result, randomBlock, surrenderContext)
+A_RSA_KEY_GEN_CTX  *context;
+A_PKCS_RSA_PRIVATE_KEY **result;
+unsigned char *randomBlock;
+A_SURRENDER_CTX *surrenderContext;
+{
+  UINT2 *bigPrimeP, *bigPrimeQ;
+  int status;
+  unsigned int modulusWords, primeSizeBits, primeWords;
+
+  /* Prezeroize all big word vectors. */
+  T_memset ((POINTER)context->bigModulus, 0, sizeof (context->bigModulus));
+  T_memset
+    ((POINTER)context->bigPrivateExponent, 0,
+     sizeof (context->bigPrivateExponent));
+  T_memset ((POINTER)context->bigPrime1, 0, sizeof (context->bigPrime1));
+  T_memset ((POINTER)context->bigPrime2, 0, sizeof (context->bigPrime2));
+  T_memset ((POINTER)context->bigExponentP, 0, sizeof (context->bigExponentP));
+  T_memset ((POINTER)context->bigExponentQ, 0, sizeof (context->bigExponentQ));
+  T_memset
+    ((POINTER)context->bigCoefficient, 0, sizeof (context->bigCoefficient));
+
+  /* prime size is half modulus size */
+  modulusWords = BITS_TO_WORDS (context->modulusBits);
+  primeSizeBits = RSA_PRIME_BITS (context->modulusBits);
+  primeWords = BITS_TO_WORDS (RSA_PRIME_BITS (context->modulusBits));
+    
+  /* Fish for bigPrime1 and bigPrime2 that are compatible with supplied
+       publicExponent.
+     The randomBlock holds random bytes for two primes.
+   */
+  if ((status = PrimeFind
+       (context->bigPrime1, primeSizeBits, primeWords,
+        context->bigPublicExponent, modulusWords, randomBlock,
+        surrenderContext)) != 0)
+    return (status);
+  if ((status = PrimeFind
+       (context->bigPrime2, context->modulusBits - primeSizeBits,
+        primeWords, context->bigPublicExponent, modulusWords,
+        randomBlock + (2 * primeWords), surrenderContext)) != 0)
+    return (status);
+
+  /* Set bigPrimeP to the larger of bigPrime1 and bigPrime2 and set
+       bigPrimeQ to the smaller.
+   */
+  if (BigCmp (context->bigPrime1, context->bigPrime2, primeWords) == 1) {
+    bigPrimeP = context->bigPrime1;
+    bigPrimeQ = context->bigPrime2;
+  }
+  else {
+    bigPrimeP = context->bigPrime2;
+    bigPrimeQ = context->bigPrime1;
+  }
+
+  /* Calculate the rest of the key components */
+  if ((status = RSAParameters 
+       (context->bigModulus, context->bigCoefficient,
+        context->bigExponentP, context->bigExponentQ,
+        context->bigPrivateExponent, context->bigPublicExponent,
+        bigPrimeP, bigPrimeQ, primeWords, modulusWords, surrenderContext)) != 0)
+    return (status);
+    
+  /* Copy key components into canonical buffers which are at the
+       end of the context. */
+  *result = &context->result;
+  SetRSAKeyGenResult (*result, context, bigPrimeP, bigPrimeQ);
+  
+  return (0);
+}
+
+/* Assumes ee, pp, qq are given, calculates other parameters.
+   Returns 0, AE_CANCEL.
+ */
+static int RSAParameters 
+  (nn, cr, dp, dq, dd, ee, pp, qq, primeWords, modulusWords, surrenderContext)
+UINT2 *nn, *cr, *dp, *dq, *dd, *ee, *pp, *qq;
+unsigned int primeWords, modulusWords;
+A_SURRENDER_CTX *surrenderContext;
+{
+  UINT2 t1[2 * MAX_RSA_PRIME_WORDS], t2[MAX_RSA_PRIME_WORDS],
+    t3[MAX_RSA_MODULUS_WORDS], u1[MAX_RSA_MODULUS_WORDS],
+    u3[MAX_RSA_MODULUS_WORDS], pm1[MAX_RSA_PRIME_WORDS], 
+    qm1[MAX_RSA_PRIME_WORDS];
+  int status;
+  
+  do {
+    /* N=P*Q */
+    BigMpy (t1, pp, qq, primeWords);
+    if ((status = CheckSurrender (surrenderContext)) != 0)
+      break;
+    BigCopy (nn, t1, modulusWords);
+  
+    /*  qm1=q-1 & pm1=p-1 */
+    BigConst (t1, 1, primeWords);
+    BigSub (qm1, qq, t1, primeWords);
+    BigSub (pm1, pp, t1, primeWords);
+    
+    /* t3=1 */
+    BigConst (t3, 1, modulusWords);
+  
+    /*t1=phi (N) */
+    BigMpy (t1, pm1, qm1, primeWords);
+    if ((status = CheckSurrender (surrenderContext)) != 0)
+      break;
+
+    /* compute decryption exponent */
+    BigPegcd (u1, dd, u3, ee, t1, modulusWords);
+    if ((status = CheckSurrender (surrenderContext)) != 0)
+      break;
+
+    /* calc DP=inv (E)[mod (P-1)] & DQ=inv (e)[mod (Q-1)] */
+    BigPdiv (t1, dp, dd, pm1, modulusWords, primeWords);
+    if ((status = CheckSurrender (surrenderContext)) != 0)
+      break;
+    BigPdiv (t1, dq, dd, qm1, modulusWords, primeWords);
+    if ((status = CheckSurrender (surrenderContext)) != 0)
+      break;
+  
+    /* calc CR = (inv (Q)[modP]) */
+    BigPegcd (t1, t2, cr, pp, qq, primeWords);
+  } while (0);
+  
+  T_memset ((POINTER)t1, 0, sizeof (t1));
+  T_memset ((POINTER)t2, 0, sizeof (t2));
+  T_memset ((POINTER)t3, 0, sizeof (t3));
+  T_memset ((POINTER)u1, 0, sizeof (u1));
+  T_memset ((POINTER)u3, 0, sizeof (u3));
+  T_memset ((POINTER)pm1, 0, sizeof (pm1));
+  T_memset ((POINTER)qm1, 0, sizeof (qm1));
+  return (status);
+}
+
+static void SetRSAKeyGenResult (result, context, bigPrimeP, bigPrimeQ)
+A_PKCS_RSA_PRIVATE_KEY *result;
+A_RSA_KEY_GEN_CTX *context;
+UINT2 *bigPrimeP;
+UINT2 *bigPrimeQ;
+{
+  unsigned int primeLen, modulusLen;
+
+  modulusLen = result->modulus.len = result->publicExponent.len =
+    result->privateExponent.len = BITS_TO_LEN (context->modulusBits);
+  primeLen = result->prime[0].len = result->prime[1].len = 
+    result->primeExponent[0].len = result->primeExponent[1].len =
+    result->coefficient.len = RSA_PRIME_LEN (context->modulusBits);
+  
+  result->modulus.data = context->resultBuffer;
+  result->publicExponent.data = result->modulus.data + modulusLen;
+  result->privateExponent.data = result->publicExponent.data + modulusLen;
+  result->prime[0].data = result->privateExponent.data + modulusLen;
+  result->prime[1].data = result->prime[0].data + primeLen;
+  result->primeExponent[0].data = result->prime[1].data + primeLen;
+  result->primeExponent[1].data = result->primeExponent[0].data + primeLen;
+  result->coefficient.data = result->primeExponent[1].data + primeLen;
+
+  BigToCanonical
+    (result->modulus.data, modulusLen, context->bigModulus,
+     MAX_RSA_MODULUS_WORDS);
+  BigToCanonical
+    (result->publicExponent.data, modulusLen,
+     context->bigPublicExponent, MAX_RSA_MODULUS_WORDS);
+  BigToCanonical
+    (result->privateExponent.data, modulusLen,
+     context->bigPrivateExponent, MAX_RSA_MODULUS_WORDS);
+  BigToCanonical 
+    (result->prime[0].data, primeLen, bigPrimeP, MAX_RSA_PRIME_WORDS);
+  BigToCanonical 
+    (result->prime[1].data, primeLen, bigPrimeQ, MAX_RSA_PRIME_WORDS);
+  BigToCanonical 
+    (result->primeExponent[0].data, primeLen, context->bigExponentP,
+     MAX_RSA_PRIME_WORDS);
+  BigToCanonical
+    (result->primeExponent[1].data, primeLen, context->bigExponentQ,
+     MAX_RSA_PRIME_WORDS);
+  BigToCanonical
+    (result->coefficient.data, primeLen, context->bigCoefficient,
+     MAX_RSA_PRIME_WORDS);
+}
diff --git a/lib/bind/dnssafe/rsakeygn.h b/lib/bind/dnssafe/rsakeygn.h
new file mode 100644 (file)
index 0000000..ba40b86
--- /dev/null
@@ -0,0 +1,54 @@
+/* Copyright (C) RSA Data Security, Inc. created 1994, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _RSAKEYGN_H_
+#define _RSAKEYGN_H_ 1
+
+#include "bigmaxes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MIN_RSA_MODULUS_BITS 256
+
+/* Need randomBlock to hold bytes for two UINT2 prime number arrays each,
+     of length primeWords = BITS_TO_WORDS (RSA_PRIME_BITS (modulusBits)). */
+#define A_RSA_KEY_GEN_RANDOM_BLOCK_LEN(modulusBits) \
+  (4 * BITS_TO_WORDS (RSA_PRIME_BITS (modulusBits)))
+
+/* Note that the scratch area for the output integers is allocated
+     in the context after the RSA_KEY_GEN_CTX.
+ */
+typedef struct {
+  unsigned int modulusBits;
+  UINT2 bigModulus[MAX_RSA_MODULUS_WORDS];
+  UINT2 bigPublicExponent[MAX_RSA_MODULUS_WORDS];
+  UINT2 bigPrivateExponent[MAX_RSA_MODULUS_WORDS];
+  UINT2 bigPrime1[MAX_RSA_PRIME_WORDS];
+  UINT2 bigPrime2[MAX_RSA_PRIME_WORDS];
+  UINT2 bigExponentP[MAX_RSA_PRIME_WORDS];
+  UINT2 bigExponentQ[MAX_RSA_PRIME_WORDS];
+  UINT2 bigCoefficient[MAX_RSA_PRIME_WORDS];
+  A_PKCS_RSA_PRIVATE_KEY result;
+  unsigned char resultBuffer
+    [3 * BITS_TO_LEN (MAX_RSA_MODULUS_BITS) +
+     5 * RSA_PRIME_LEN (MAX_RSA_MODULUS_BITS)];
+} A_RSA_KEY_GEN_CTX;
+
+int A_RSAKeyGenInit PROTO_LIST ((A_RSA_KEY_GEN_CTX *, A_RSA_KEY_GEN_PARAMS *));
+int A_RSAKeyGen PROTO_LIST
+  ((A_RSA_KEY_GEN_CTX  *, A_PKCS_RSA_PRIVATE_KEY **, unsigned char *,
+    A_SURRENDER_CTX *));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/lib/bind/dnssafe/seccbcd.c b/lib/bind/dnssafe/seccbcd.c
new file mode 100644 (file)
index 0000000..bff839d
--- /dev/null
@@ -0,0 +1,148 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "algae.h"
+#include "secrcbc.h"
+#include "port_after.h"
+
+static void SecretCBCDecryptBlock PROTO_LIST
+  ((POINTER, unsigned char *, SECRET_CRYPT, unsigned char *,
+    unsigned char *));
+
+/* On first call, it is assumed that *remainderLen is zero.
+   This assumes remainder buffer is at least 16 bytes is size.
+   Returns AE_OUTPUT_LEN, 0.
+ */
+int SecretCBCDecryptUpdate
+  (context, xorBlock, remainder, remainderLen, SecretDecrypt, output,
+   outputLen, maxOutputLen, input, inputLen)
+POINTER context;
+unsigned char *xorBlock;
+unsigned char *remainder;
+unsigned int *remainderLen;
+SECRET_CRYPT SecretDecrypt;
+unsigned char *output;
+unsigned int *outputLen;
+unsigned int maxOutputLen;
+unsigned char *input;
+unsigned int inputLen;
+{
+  unsigned int partialLen;
+
+  if (*remainderLen + inputLen <= 16) {
+    /* Not enough to decrypt, just accumulate into remainder.
+     */
+    *outputLen = 0;
+    T_memcpy ((POINTER)remainder + *remainderLen, (POINTER)input, inputLen);
+    *remainderLen += inputLen;
+    return (0);
+  }
+
+  /* Fill up the rest of the remainder with bytes from input.
+   */
+  T_memcpy
+    ((POINTER)remainder + *remainderLen, (POINTER)input,
+     partialLen = 16 - *remainderLen);
+  input += partialLen;
+  inputLen -= partialLen;    
+
+  /* remainder is full and inputLen is at least 1.  Compute outputLen
+       as the size needed to keep remainder as full as possible.
+   */
+  if ((*outputLen = 8 * ((inputLen + 7) / 8)) > maxOutputLen)
+    return (AE_OUTPUT_LEN);
+
+  SecretCBCDecryptBlock
+    (context, xorBlock, SecretDecrypt, output, remainder);
+  output += 8;
+  
+  if (inputLen <= 8) {
+    /* Shift remaining input bytes into remainder */
+    T_memmove ((POINTER)remainder, (POINTER)(remainder + 8), 8);
+    T_memcpy ((POINTER)(remainder + 8), (POINTER)input, inputLen);
+    *remainderLen = 8 + inputLen;
+    return (0);
+  }
+
+  /* Decrypt the rest of the remainder.
+   */
+  SecretCBCDecryptBlock
+    (context, xorBlock, SecretDecrypt, output, remainder + 8);
+  output += 8;
+
+  /* Now decrypt the bulk of the input.
+   */
+  while (inputLen > 16) {
+    SecretCBCDecryptBlock (context, xorBlock, SecretDecrypt, output, input);
+    output += 8;
+    input += 8;
+    inputLen -= 8;
+  }
+
+  /* inputLen is now <= 16, so copy input to remainder.
+   */
+  T_memcpy ((POINTER)remainder, (POINTER)input, inputLen);
+  *remainderLen = inputLen;
+  return (0);
+}
+
+/* The caller must restart the context (setting remainderLen to zero).
+   Returns AE_INPUT_LEN, AE_OUTPUT_LEN, 0.
+ */
+int SecretCBCDecryptFinal
+  (context, xorBlock, remainder, remainderLen, SecretDecrypt, output,
+   outputLen, maxOutputLen)
+POINTER context;
+unsigned char *xorBlock;
+unsigned char *remainder;
+unsigned int remainderLen;
+SECRET_CRYPT SecretDecrypt;
+unsigned char *output;
+unsigned int *outputLen;
+unsigned int maxOutputLen;
+{
+  if ((*outputLen = remainderLen) == 0)
+    /* There was never any data. */
+    return (0);
+  
+  if (remainderLen != 8 && remainderLen != 16)
+    return (AE_INPUT_LEN);
+
+  if (*outputLen > maxOutputLen)
+    return (AE_OUTPUT_LEN);
+
+  SecretCBCDecryptBlock
+    (context, xorBlock, SecretDecrypt, output, remainder);
+  output += 8;
+  if (remainderLen == 16)
+    SecretCBCDecryptBlock
+      (context, xorBlock, SecretDecrypt, output, remainder + 8);
+  return (0);
+}
+
+static void SecretCBCDecryptBlock (context, xorBlock, SecretDecrypt, out, in)
+POINTER context;
+unsigned char *xorBlock;
+SECRET_CRYPT SecretDecrypt;
+unsigned char *out;
+unsigned char *in;
+{
+  unsigned char tempBuffer[8];
+  unsigned int i;
+  
+  /* Save input to be copied to the xor block. */
+  T_memcpy ((POINTER)tempBuffer, (POINTER)in, 8);
+  (*SecretDecrypt) (context, out, in);
+  for (i = 0; i < 8; i++)
+    out[i] ^= xorBlock[i];  
+  T_memcpy ((POINTER)xorBlock, (POINTER)tempBuffer, 8);
+  
+  T_memset ((POINTER)tempBuffer, 0, sizeof (tempBuffer));
+}
diff --git a/lib/bind/dnssafe/seccbce.c b/lib/bind/dnssafe/seccbce.c
new file mode 100644 (file)
index 0000000..3a9a291
--- /dev/null
@@ -0,0 +1,99 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "algae.h"
+#include "secrcbc.h"
+#include "port_after.h"
+
+/* On first call, it is assumed that *remainderLen is zero.
+   Returns AE_OUTPUT_LEN, 0.
+ */
+int SecretCBCEncryptUpdate
+  (context, xorBlock, remainder, remainderLen, SecretEncrypt, output,
+   outputLen, maxOutputLen, input, inputLen)
+POINTER context;
+unsigned char *xorBlock;
+unsigned char *remainder;
+unsigned int *remainderLen;
+SECRET_CRYPT SecretEncrypt;
+unsigned char *output;
+unsigned int *outputLen;
+unsigned int maxOutputLen;
+unsigned char *input;
+unsigned int inputLen;
+{
+  unsigned int partialLen, totalLen, i;
+
+  totalLen = *remainderLen + inputLen;
+
+  /* Output length will be all available 8-byte blocks.
+   */
+  if ((*outputLen = 8 * (totalLen / 8)) > maxOutputLen)
+    return (AE_OUTPUT_LEN);
+  
+  if (totalLen < 8) {
+    /* Not enough to encrypt, just accumulate into remainder.
+     */
+    T_memcpy
+      ((POINTER)remainder + *remainderLen, (POINTER)input, inputLen);
+    *remainderLen = totalLen;
+    
+    return (0);
+  }
+  
+  /* Accumulate enough bytes from input into remainder to encrypt the
+       remainder.
+   */
+  T_memcpy
+    ((POINTER)remainder + *remainderLen, (POINTER)input,
+     partialLen = 8 - *remainderLen);
+    
+  for (i = 0; i < 8; i++)
+    output[i] = remainder[i] ^ xorBlock[i];
+  /* Encrypt in place */
+  (*SecretEncrypt) (context, output, output);
+  
+  T_memcpy ((POINTER)xorBlock, (POINTER)output, 8);
+  input += partialLen;
+  inputLen -= partialLen;
+  output += 8;
+
+  /* Now encrypt the bulk of the input.
+   */
+  while (inputLen >= 8) {
+    for (i = 0; i < 8; i++)
+      output[i] = *(input++) ^ xorBlock[i];
+    /* Encrypt in place */
+    (*SecretEncrypt) (context, output, output);
+    T_memcpy ((POINTER)xorBlock, (POINTER)output, 8);
+    output += 8;
+    inputLen -= 8;
+  }
+
+  /* inputLen is now < 8, so copy input to remainder.
+   */
+  T_memcpy ((POINTER)remainder, (POINTER)input, inputLen);
+  *remainderLen = inputLen;
+   
+  return (0);
+}
+
+/* This just ensures that *remainderLen is zero.
+   The caller must restart the context (setting remainderLen to zero).
+   Returns AE_INPUT_LEN, 0.
+ */
+int SecretCBCEncryptFinal (remainderLen)
+unsigned int remainderLen;
+{
+  if (remainderLen != 0)
+    return (AE_INPUT_LEN);
+  
+  return (0);
+}
diff --git a/lib/bind/dnssafe/secrcbc.h b/lib/bind/dnssafe/secrcbc.h
new file mode 100644 (file)
index 0000000..122f83f
--- /dev/null
@@ -0,0 +1,36 @@
+/* Copyright (C) RSA Data Security, Inc. created 1990, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _SECRCBC_H_
+#define _SECRCBC_H_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void (*SECRET_CRYPT) PROTO_LIST
+  ((POINTER, unsigned char *, unsigned char *));
+
+int SecretCBCEncryptUpdate PROTO_LIST
+  ((POINTER, unsigned char *, unsigned char *, unsigned int *, SECRET_CRYPT,
+    unsigned char *, unsigned int *, unsigned int, unsigned char *,
+    unsigned int));
+int SecretCBCEncryptFinal PROTO_LIST ((unsigned int));
+int SecretCBCDecryptUpdate PROTO_LIST
+  ((POINTER, unsigned char *, unsigned char *, unsigned int *, SECRET_CRYPT,
+    unsigned char *, unsigned int *, unsigned int, unsigned char *,
+    unsigned int));
+int SecretCBCDecryptFinal PROTO_LIST
+  ((POINTER, unsigned char *, unsigned char *, unsigned int, SECRET_CRYPT,
+    unsigned char *, unsigned int *, unsigned int));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/bind/dnssafe/surrendr.c b/lib/bind/dnssafe/surrendr.c
new file mode 100644 (file)
index 0000000..05a81a5
--- /dev/null
@@ -0,0 +1,26 @@
+/* Copyright (C) RSA Data Security, Inc. created 1992, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#include "port_before.h"
+#include "global.h"
+#include "algae.h"
+#include "surrendr.h"
+#include "port_after.h"
+
+/* Returns 0, AE_CANCEL.
+ */
+int CheckSurrender (surrenderContext)
+A_SURRENDER_CTX *surrenderContext;
+{
+  if (surrenderContext == (A_SURRENDER_CTX *)NULL_PTR)
+    return (0);
+
+  if ((*surrenderContext->Surrender) (surrenderContext->handle))
+    return (AE_CANCEL);
+  return (0);
+}
diff --git a/lib/bind/dnssafe/surrendr.h b/lib/bind/dnssafe/surrendr.h
new file mode 100644 (file)
index 0000000..dc92904
--- /dev/null
@@ -0,0 +1,22 @@
+/* Copyright (C) RSA Data Security, Inc. created 1992, 1996.  This is an
+   unpublished work protected as such under copyright law.  This work
+   contains proprietary, confidential, and trade secret information of
+   RSA Data Security, Inc.  Use, disclosure or reproduction without the
+   express written authorization of RSA Data Security, Inc. is
+   prohibited.
+ */
+
+#ifndef _SURRENDR_H_
+#define _SURRENDR_H_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int CheckSurrender PROTO_LIST ((A_SURRENDER_CTX *));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/bind/dst/Makefile.in b/lib/bind/dst/Makefile.in
new file mode 100644 (file)
index 0000000..66b7b89
--- /dev/null
@@ -0,0 +1,16 @@
+OBJS=  bsafe_link.@O@ cylink_link.@O@ dst_api.@O@ eay_dss_link.@O@ \
+       hmac_link.@O@ md5_dgst.@O@ prandom.@O@ rsaref_link.@O@ support.@O@
+
+SRCS=  bsafe_link.c cylink_link.c dst_api.c eay_dss_link.c \
+       hmac_link.c md5_dgst.c prandom.c rsaref_link.c support.c
+
+TARGETS= ${OBJS}
+
+CRYPTINCL=      -I../cylink -I../dnssafe
+CRYPTFLAGS=     -DCYLINK_DSS -DHMAC_MD5 -DUSE_MD5 -DDNSSAFE
+
+CINCLUDES= -I.. -I../include ${CRYPTINCL}
+CWARNINGS= -Werror
+CDEFINES= ${CRYPTFLAGS}
+
+@BIND9_MAKE_RULES@
diff --git a/lib/bind/dst/bsafe_link.c b/lib/bind/dst/bsafe_link.c
new file mode 100644 (file)
index 0000000..b8d30b7
--- /dev/null
@@ -0,0 +1,1129 @@
+#if defined(BSAFE) || defined(DNSSAFE)
+static const char rcsid[] = "$Header: /u0/home/explorer/proj/ISC/git-conversion/cvsroot/bind9/lib/bind/dst/Attic/bsafe_link.c,v 1.1 2001/03/29 06:31:31 marka 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.
+ */
+/* 
+ * This file contains two components 
+ * 1. Interface to the BSAFE library to allow compilation of Bind 
+ *    with TIS/DNSSEC when BSAFE is not available 
+ *    all calls to BSAFE are contained inside this file.
+ * 2. The glue to connvert RSA KEYS to and from external formats
+ */
+#include "port_before.h"
+
+#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 <arpa/nameser.h>
+#include "dst_internal.h"
+
+#  ifdef __STDC__
+#    define PROTOTYPES 1
+#  else
+#    define PROTOTYPES 0
+#  endif
+
+#  ifdef BSAFE
+#    include <aglobal.h>
+#    include <bsafe.h>
+#  else
+#    include <global.h>
+#    include <bsafe2.h>
+#    include <bigmaxes.h>
+#  endif
+
+#include "port_after.h"
+
+typedef struct bsafekey {
+       char *rk_signer;
+       B_KEY_OBJ rk_Private_Key;
+       B_KEY_OBJ rk_Public_Key;
+} RSA_Key;
+
+#ifndef MAX_RSA_MODULUS_BITS
+#define MAX_RSA_MODULUS_BITS 4096
+#define MAX_RSA_MODULUS_LEN (MAX_RSA_MODULUS_BITS/8)
+#define MAX_RSA_PRIME_LEN (MAX_RSA_MODULUS_LEN/2)
+#endif
+
+#define NULL_SURRENDER (A_SURRENDER_CTX *)NULL_PTR
+#define NULL_RANDOM (B_ALGORITHM_OBJ)NULL_PTR
+
+B_ALGORITHM_METHOD *CHOOSER[] =
+{
+       &AM_MD5,
+       &AM_MD5_RANDOM,
+       &AM_RSA_KEY_GEN,
+       &AM_RSA_ENCRYPT,
+       &AM_RSA_DECRYPT,
+       &AM_RSA_CRT_ENCRYPT,
+       &AM_RSA_CRT_DECRYPT,
+       (B_ALGORITHM_METHOD *) NULL_PTR
+};
+
+static u_char pkcs1[] =
+{
+       0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86,
+       0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00,
+       0x04, 0x10
+};
+
+static int dst_bsafe_md5digest(const int mode, B_ALGORITHM_OBJ *digest_obj,
+                              const u_char *data, const int len,
+                              u_char *digest, const int digest_len);
+
+static int dst_bsafe_key_size(RSA_Key *r_key);
+
+static int dst_bsafe_sign(const int mode, DST_KEY *dkey, void **context,
+                         const u_char *data, const int len,
+                         u_char *signature, const int sig_len);
+static int dst_bsafe_verify(const int mode, DST_KEY *dkey, void **context,
+                           const u_char *data, const int len,
+                           const u_char *signature, const int sig_len);
+static int dst_bsafe_to_dns_key(const DST_KEY *in_key, u_char *out_str,
+                               const int out_len);
+static int dst_bsafe_from_dns_key(DST_KEY *s_key, const u_char *key,
+                                 const int len);
+static int dst_bsafe_key_to_file_format(const DST_KEY *key, char *buff,
+                                       const int buff_len);
+static int dst_bsafe_key_from_file_format(DST_KEY *d_key,
+                                         const char *buff,
+                                         const int buff_len);
+static int dst_bsafe_generate_keypair(DST_KEY *key, int exp);
+static int dst_bsafe_compare_keys(const DST_KEY *key1, const DST_KEY *key2);
+static void *dst_bsafe_free_key_structure(void *key);
+
+/*
+ * dst_bsafe_init()  Function to answer set up function pointers for 
+ *        BSAFE/DNSSAFE related functions 
+ */
+int
+dst_bsafe_init(void)
+{
+       if (dst_t_func[KEY_RSA] != NULL)
+               return (1);
+       dst_t_func[KEY_RSA] = malloc(sizeof(struct dst_func));
+       if (dst_t_func[KEY_RSA] == NULL)
+               return (0);
+       memset(dst_t_func[KEY_RSA], 0, sizeof(struct dst_func));
+       dst_t_func[KEY_RSA]->sign = dst_bsafe_sign;
+       dst_t_func[KEY_RSA]->verify = dst_bsafe_verify;
+       dst_t_func[KEY_RSA]->compare = dst_bsafe_compare_keys;
+       dst_t_func[KEY_RSA]->generate = dst_bsafe_generate_keypair;
+       dst_t_func[KEY_RSA]->destroy = dst_bsafe_free_key_structure;
+       dst_t_func[KEY_RSA]->from_dns_key = dst_bsafe_from_dns_key;
+       dst_t_func[KEY_RSA]->to_dns_key = dst_bsafe_to_dns_key;
+       dst_t_func[KEY_RSA]->from_file_fmt = dst_bsafe_key_from_file_format;
+       dst_t_func[KEY_RSA]->to_file_fmt = dst_bsafe_key_to_file_format;
+       return (1);
+}
+
+/*
+ * dst_bsafe_sign
+ *     Call BSAFE 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.
+ *     dkey      structure holds context for a sign done in multiple calls.
+ *     context   the context to use for this computation
+ *     data    data to be signed.
+ *     len      length in bytes of data.
+ *     priv_key    key to use for signing.
+ *     signature   location to store signature.
+ *     sig_len     size in bytes of signature field.
+ * 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_bsafe_sign(const int mode, DST_KEY *dkey, void **context,
+              const u_char *data, const int len, 
+              u_char *signature, const int sig_len)
+{
+       u_int sign_len = 0;
+       int status = 0;
+       B_ALGORITHM_OBJ *md5_ctx = NULL;
+       int w_bytes = 0;
+       u_int u_bytes = 0;
+       u_char work_area[NS_MD5RSA_MAX_SIZE];
+
+       if (mode & SIG_MODE_INIT) { 
+               md5_ctx = (B_ALGORITHM_OBJ *) malloc(sizeof(B_ALGORITHM_OBJ));
+               if ((status = B_CreateAlgorithmObject(md5_ctx)))
+                       return (-1);
+               if ((status = B_SetAlgorithmInfo(*md5_ctx, AI_MD5, NULL)))
+                       return (-1);
+       }
+       else if (context) 
+               md5_ctx = (B_ALGORITHM_OBJ *) *context;
+       if (md5_ctx == NULL) 
+               return (-1);
+
+       w_bytes = dst_bsafe_md5digest(mode, md5_ctx, 
+                                     data, len,work_area, sizeof(work_area));
+        if (w_bytes < 0 || (mode & SIG_MODE_FINAL)) {
+               B_DestroyAlgorithmObject(md5_ctx);
+               SAFE_FREE(md5_ctx);
+               if (w_bytes < 0)
+                       return (w_bytes);
+       }
+
+       if (mode & SIG_MODE_FINAL) {
+               RSA_Key *key;
+               int ret = 0;
+               B_ALGORITHM_OBJ rsaEncryptor = (B_ALGORITHM_OBJ) NULL_PTR;
+               
+               if (dkey == NULL || dkey->dk_KEY_struct == NULL)
+                       return (-1);
+               key = (RSA_Key *) dkey->dk_KEY_struct;
+               if (key == NULL || key->rk_Private_Key == NULL)
+                       return (-1);
+
+               if ((status = B_CreateAlgorithmObject(&rsaEncryptor)))
+                       return (SIGN_FINAL_FAILURE);
+               if ((status = B_SetAlgorithmInfo(rsaEncryptor,
+                                                AI_PKCS_RSAPrivate,
+                                                NULL_PTR)))
+
+                       ret = SIGN_FINAL_FAILURE;
+               if (ret == 0 && 
+                   (status = B_EncryptInit(rsaEncryptor,
+                                           key->rk_Private_Key,
+                                           CHOOSER, NULL_SURRENDER)))
+                       ret = SIGN_FINAL_FAILURE;
+               if (ret == 0 &&
+                   (status = B_EncryptUpdate(rsaEncryptor, signature,
+                                             &u_bytes, sig_len, pkcs1,
+                                             sizeof(pkcs1), NULL_PTR,
+                                             NULL_SURRENDER)))
+                       ret = SIGN_FINAL_FAILURE;
+               if (ret == 0 &&
+                   (status = B_EncryptUpdate(rsaEncryptor, signature,
+                                             &u_bytes, sig_len, work_area,
+                                             w_bytes, NULL_PTR,
+                                             NULL_SURRENDER)))
+                       ret = SIGN_FINAL_FAILURE;
+
+               if (ret == 0 &&
+                   (status = B_EncryptFinal(rsaEncryptor, signature + u_bytes,
+                                            &sign_len, sig_len - u_bytes,
+                                            NULL_PTR, NULL_SURRENDER)))
+                       ret = SIGN_FINAL_FAILURE;
+               B_DestroyAlgorithmObject(&rsaEncryptor);
+               if (ret != 0) 
+                       return (ret);
+
+       }
+       else {
+               if (context == NULL) 
+                       return (-1);
+               *context = (void *) md5_ctx;
+       }
+       return (sign_len);
+}
+
+
+/*
+ * Dst_bsafe_verify 
+ *     Calls BSAFE 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      structure holds context for a verify done in multiple calls.
+ *     context   the context to use for this computation
+ *     data    data signed.
+ *     len      length in bytes of data.
+ *     pub_key     key to use for verify.
+ *     signature   signature.
+ *     sig_len     length in bytes of signature.
+ * returns 
+ *     0  Success 
+ *    <0  Failure
+ */
+
+static int
+dst_bsafe_verify(const int mode, DST_KEY *dkey, void **context,
+                const u_char *data, const int len,
+                const u_char *signature, const int sig_len)
+{
+       B_ALGORITHM_OBJ *md5_ctx = NULL;
+       u_char digest[DST_HASH_SIZE];
+       u_char work_area[DST_HASH_SIZE + sizeof(pkcs1)];
+       int status = 0, w_bytes = 0;
+       u_int u_bytes = 0;
+
+       if (mode & SIG_MODE_INIT) { 
+               md5_ctx = (B_ALGORITHM_OBJ *) malloc(sizeof(B_ALGORITHM_OBJ));
+               if ((status = B_CreateAlgorithmObject(md5_ctx)))
+                       return (-1);
+               if ((status = B_SetAlgorithmInfo(*md5_ctx, AI_MD5, NULL)))
+                       return (-1);
+       }
+       else if (context) 
+               md5_ctx = (B_ALGORITHM_OBJ *) *context;
+       if (md5_ctx == NULL) 
+               return (-1);
+
+       w_bytes = dst_bsafe_md5digest(mode, md5_ctx, data, len, 
+                                     digest, sizeof(digest));
+
+       if (w_bytes < 0 || (mode & SIG_MODE_FINAL)) {
+               B_DestroyAlgorithmObject(md5_ctx);
+               SAFE_FREE(md5_ctx);
+               if (w_bytes < 0)
+                       return (-1);
+       }
+
+       if (mode & SIG_MODE_FINAL) {
+               RSA_Key *key;
+               int ret = 0;
+               B_ALGORITHM_OBJ rsaEncryptor = (B_ALGORITHM_OBJ) NULL_PTR;
+
+               if (dkey == NULL || dkey->dk_KEY_struct == NULL)
+                       return (-1);
+               key = (RSA_Key *) dkey->dk_KEY_struct;
+               if (key->rk_Public_Key == NULL)
+                       return (-2);
+               if (rsaEncryptor == NULL_PTR) {
+                       if ((status = B_CreateAlgorithmObject(&rsaEncryptor)))
+                               ret = SIGN_FINAL_FAILURE;
+                       if (ret == 0 &&
+                           (status = B_SetAlgorithmInfo(rsaEncryptor,
+                                                        AI_PKCS_RSAPublic,
+                                                        NULL_PTR)))
+                               ret = VERIFY_FINAL_FAILURE;
+               }
+               if (ret == 0 &&
+                   (status = B_DecryptInit(rsaEncryptor, key->rk_Public_Key,
+                                           CHOOSER, NULL_SURRENDER)))
+                       ret = VERIFY_FINAL_FAILURE;
+
+               if (ret == 0 && 
+                   (status = B_DecryptUpdate(rsaEncryptor, work_area,
+                                             &u_bytes, 0,
+                                             (const u_char *) signature,
+                                             sig_len,
+                                             NULL_PTR, NULL_SURRENDER)))
+                       ret = VERIFY_FINAL_FAILURE;
+
+               if (ret == 0 && 
+                   (status = B_DecryptFinal(rsaEncryptor, work_area + u_bytes,
+                                            &u_bytes,
+                                            sizeof(work_area) - u_bytes,
+                                            NULL_PTR, NULL_SURRENDER)))
+                       ret = VERIFY_FINAL_FAILURE;
+               B_DestroyAlgorithmObject(&rsaEncryptor);
+               /* skip PKCS#1 header in output from Decrypt function */
+               if (ret)
+                       return (ret);
+               ret = memcmp(digest, &work_area[sizeof(pkcs1)], w_bytes);
+               if (ret == 0)
+                       return(0);
+               else
+                       return(VERIFY_FINAL_FAILURE);
+       }
+       else {
+               if (context == NULL) 
+                       return (-1);
+               *context = (void *) md5_ctx;
+       }
+       return (0);
+}
+
+
+/*
+ * dst_bsafe_to_dns_key
+ *     Converts key from RSA to DNS distribution format
+ *     This function gets in a pointer to the public key and a work area
+ *     to write the key into.
+ * Parameters
+ *     public    KEY structure 
+ *     out_str   buffer to write encoded key into 
+ *     out_len   size of out_str
+ * Return
+ *     N >= 0 length of encoded key 
+ *     n < 0  error 
+ */
+
+static int
+dst_bsafe_to_dns_key(const DST_KEY *in_key, u_char *out_str,
+                    const int out_len)
+{
+       B_KEY_OBJ public;
+       A_RSA_KEY *pub = NULL;
+       u_char *op = out_str;
+       int n = 0;
+
+       if (in_key == NULL || in_key->dk_KEY_struct == NULL ||
+           out_len <= 0 || out_str == NULL)
+               return (-1);
+       public = (B_KEY_OBJ)((RSA_Key *) in_key->dk_KEY_struct)->rk_Public_Key;
+
+       n = B_GetKeyInfo((POINTER *) &pub, public, KI_RSAPublic);
+       if (n != 0)
+               return (-1);
+
+       if (pub->exponent.len < 256) {  /* key exponent is <= 2040 bits */
+               if ((unsigned int)out_len < pub->exponent.len + 1)
+                       return (-1);
+               *op++ = (u_int8_t) pub->exponent.len;
+       } else {                       /*  key exponent is > 2040 bits */
+               u_int16_t e = (u_int16_t) pub->exponent.len;
+               if ((unsigned int)out_len < pub->exponent.len + 3)
+                       return (-1);
+               *op++ = 0;          /* 3 byte length field */
+               dst_s_put_int16(op, e);
+               op += sizeof(e);
+               n = 2;
+       }
+       n++;
+       memcpy(op, pub->exponent.data, pub->exponent.len);
+       op += pub->exponent.len;
+       n += pub->exponent.len;
+
+       if ((unsigned int)(out_len - n) >= pub->modulus.len) {
+               /*copy exponent */
+               memcpy(op, pub->modulus.data, pub->modulus.len);
+               n += pub->modulus.len;
+       }
+       else 
+               n = -1;
+       return (n);
+}
+
+
+/*
+ * dst_bsafe_from_dns_key
+ *     Converts from a DNS KEY RR format to an RSA KEY. 
+ * Parameters
+ *     len    Length in bytes of DNS key
+ *     key    DNS key
+ *     name   Key name
+ *     s_key  DST structure that will point to the RSA key this routine
+ *             will build.
+ * Return
+ *     0   The input key, s_key or name was null.
+ *     1   Success
+ */
+static int
+dst_bsafe_from_dns_key(DST_KEY *s_key, const u_char *key, const int len)
+{
+       int bytes;
+       const u_char *key_ptr;
+       RSA_Key *r_key;
+       A_RSA_KEY *public;
+
+       if (s_key == NULL || len < 0 || key == NULL)
+               return (0);
+
+       r_key = (RSA_Key *) s_key->dk_KEY_struct;
+       if (r_key != NULL)      /* do not reuse */
+               s_key->dk_func->destroy(r_key);
+
+       if (len == 0)
+               return (1);
+
+       if ((r_key = (RSA_Key *) malloc(sizeof(RSA_Key))) == NULL) {
+               EREPORT(("dst_bsafe_from_dns_key(): Memory allocation error 1"));
+               return (0);
+       }
+       memset(r_key, 0, sizeof(RSA_Key));
+       s_key->dk_KEY_struct = (void *) r_key;
+       r_key->rk_signer = strdup(s_key->dk_key_name);
+
+       if (B_CreateKeyObject(&r_key->rk_Public_Key) != 0) {
+               EREPORT(("dst_bsafe_from_dns_key(): Memory allocation error 3"));
+               s_key->dk_func->destroy(r_key);
+               return (0);
+       }
+       key_ptr = key;
+       bytes = (int) *key_ptr++;       /* length of exponent in bytes */
+       if (bytes == 0)  {             /* special case for long exponents */
+               bytes = (int) dst_s_get_int16(key_ptr);
+               key_ptr += sizeof(u_int16_t);
+       }
+       if (bytes > MAX_RSA_MODULUS_LEN) { 
+               dst_bsafe_free_key_structure(r_key);
+               return (-1);
+       }
+       if ((public = (A_RSA_KEY *) malloc(sizeof(A_RSA_KEY))) == NULL)
+               return (0);
+       memset(public, 0, sizeof(*public));
+       public->exponent.len = bytes;
+       if ((public->exponent.data = (u_char *) malloc(bytes)) == NULL)
+               return (0);
+       memcpy(public->exponent.data, key_ptr, bytes);
+
+       key_ptr += bytes;       /* beginning of modulus */
+       bytes = len - bytes - 1;        /* length of modulus */
+
+       if (bytes > MAX_RSA_MODULUS_LEN) { 
+               dst_bsafe_free_key_structure(r_key);
+               return (-1);
+       }
+       public->modulus.len = bytes;
+       if ((public->modulus.data = (u_char *) malloc(bytes)) == NULL)
+               return (0);
+       memcpy(public->modulus.data, key_ptr, bytes);
+
+       B_SetKeyInfo(r_key->rk_Public_Key, KI_RSAPublic, (POINTER) public);
+
+       s_key->dk_id = (u_int16_t)
+               dst_s_get_int16(&public->modulus.data[public->modulus.len - 3]);
+       s_key->dk_key_size = dst_bsafe_key_size(r_key);
+       SAFE_FREE(public->modulus.data);
+       SAFE_FREE(public->exponent.data);
+       SAFE_FREE(public);      
+       return (1);
+}
+
+
+/*
+ *  dst_bsafe_key_to_file_format
+ *     Encodes an RSA Key into the portable file format.
+ *  Parameters 
+ *     rkey      RSA KEY structure 
+ *     buff      output buffer
+ *     buff_len  size of output buffer 
+ *  Return
+ *     0  Failure - null input rkey
+ *     -1  Failure - not enough space in output area
+ *     N  Success - Length of data returned in buff
+ */
+
+static int
+dst_bsafe_key_to_file_format(const DST_KEY *key, char *buff,
+                            const int buff_len)
+{
+       char *bp;
+       int len, b_len;
+       B_KEY_OBJ rkey;
+       A_PKCS_RSA_PRIVATE_KEY *private = NULL;
+
+       if (key == NULL || key->dk_KEY_struct == NULL)  /* no output */
+               return (0);
+       if (buff == NULL || buff_len <= (int) strlen(key_file_fmt_str))
+               return (-1);    /* no OR not enough space in output area */
+
+       rkey = (B_KEY_OBJ)((RSA_Key *) key->dk_KEY_struct)->rk_Private_Key;
+
+       B_GetKeyInfo((POINTER *) &private, rkey, KI_PKCS_RSAPrivate);
+
+           memset(buff, 0, buff_len);  /* just in case */
+       /* write file header */
+       sprintf(buff, key_file_fmt_str, KEY_FILE_FORMAT, KEY_RSA, "RSA");
+
+       bp = strchr(buff, '\0');
+       b_len = buff_len - (bp - buff);
+       if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Modulus: ",
+                                              private->modulus.data,
+                                              private->modulus.len)) <= 0)
+               return (-1);
+
+       bp += len;
+       b_len -= len;
+       if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "PublicExponent: ",
+                                              private->publicExponent.data,
+                                        private->publicExponent.len)) <= 0)
+               return (-2);
+
+       bp += len;
+       b_len -= len;
+       if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "PrivateExponent: ",
+                                              private->privateExponent.data,
+                                       private->privateExponent.len)) <= 0)
+               return (-3);
+       bp += len;
+       b_len -= len;
+
+       if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Prime1: ",
+                                              private->prime[0].data,
+                                              private->prime[0].len)) < 0)
+               return (-4);
+       bp += len;
+       b_len -= len;
+
+       if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Prime2: ",
+                                              private->prime[1].data,
+                                              private->prime[1].len)) < 0)
+               return (-5);
+       bp += len;
+       b_len -= len;
+
+       if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Exponent1: ",
+                                            private->primeExponent[0].data,
+                                       private->primeExponent[0].len)) < 0)
+               return (-6);
+       bp += len;
+       b_len -= len;
+
+       if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Exponent2: ",
+                                            private->primeExponent[1].data,
+                                       private->primeExponent[1].len)) < 0)
+               return (-7);
+       bp += len;
+       b_len -= len;
+
+       if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Coefficient: ",
+                                              private->coefficient.data,
+                                            private->coefficient.len)) < 0)
+               return (-8);
+       bp += len;
+       b_len -= len;
+       return (buff_len - b_len);
+}
+
+
+/*
+ * dst_bsafe_key_from_file_format
+ *     Converts contents of a private key file into a private RSA key. 
+ * Parameters 
+ *     RSA_Key    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_bsafe_key_from_file_format(DST_KEY *d_key, const char *buff,
+                              const int buff_len)
+{
+       int status;
+       char s[RAW_KEY_SIZE];
+       int len, s_len = sizeof(s);
+       int tag = -1;
+       const char *p = buff;
+       RSA_Key *b_key;
+       A_RSA_KEY *public;
+       A_PKCS_RSA_PRIVATE_KEY *private;
+
+       if (d_key == NULL || buff == NULL || buff_len <= 0)
+               return (-1);
+
+       b_key = (RSA_Key *) malloc(sizeof(RSA_Key));
+       public = (A_RSA_KEY *) malloc(sizeof(A_RSA_KEY));
+       private = (A_PKCS_RSA_PRIVATE_KEY *)
+               malloc(sizeof(A_PKCS_RSA_PRIVATE_KEY));
+       if (b_key == NULL || private == NULL || public == NULL) {
+               SAFE_FREE(b_key);
+               SAFE_FREE(public);
+               SAFE_FREE(private);
+               return (-2);
+       }
+       memset(b_key, 0, sizeof(*b_key));
+       memset(public, 0, sizeof(A_RSA_KEY));
+       memset(private, 0, sizeof(A_PKCS_RSA_PRIVATE_KEY));
+       d_key->dk_KEY_struct = (void *) b_key;
+       if (!dst_s_verify_str(&p, "Modulus: "))
+               return (-3);
+       memset(s, 0, s_len);
+       if ((len = dst_s_conv_bignum_b64_to_u8(&p, (u_char *)s, s_len)) == 0)
+               return (-4);
+
+       private->modulus.len = len;
+       if ((private->modulus.data = malloc(len)) == NULL)
+               return (-5);
+       memcpy(private->modulus.data, s + s_len - len, len);
+
+       while (*(++p) && p < (const char *) &buff[buff_len]) {
+               if (dst_s_verify_str(&p, "PublicExponent: ")) {
+                       if (!(len = dst_s_conv_bignum_b64_to_u8(&p, (u_char *)s, s_len)))
+                               return (-5);
+                       private->publicExponent.len = len;
+                       if ((private->publicExponent.data = malloc(len))
+                           == NULL)
+                               return (-6);
+                       memcpy(private->publicExponent.data,
+                              s + s_len - len, len);
+               } else if (dst_s_verify_str(&p, "PrivateExponent: ")) {
+                       if (!(len = dst_s_conv_bignum_b64_to_u8(&p, (u_char *)s, s_len)))
+                               return (-6);
+                       private->privateExponent.len = len;
+                       if ((private->privateExponent.data = malloc(len))
+                           == NULL)
+                               return (-7);
+                       memcpy(private->privateExponent.data, s + s_len - len,
+                              len);
+               } else if (dst_s_verify_str(&p, "Prime1: ")) {
+                       if (!(len = dst_s_conv_bignum_b64_to_u8(&p, (u_char *)s,
+                                                       MAX_RSA_PRIME_LEN)))
+                               return (-7);
+                       private->prime[0].len = len;
+                       if ((private->prime[0].data = malloc(len)) == NULL)
+                               return (-8);
+                       memcpy(private->prime[0].data,
+                              s + MAX_RSA_PRIME_LEN - len, len);
+               } else if (dst_s_verify_str(&p, "Prime2: ")) {
+                       if (!(len = dst_s_conv_bignum_b64_to_u8(&p, (u_char *)s,
+                                                       MAX_RSA_PRIME_LEN)))
+                               return (-8);
+                       private->prime[1].len = len;
+                       if ((private->prime[1].data = malloc(len)) == NULL)
+                               return (-9);
+                       memcpy(private->prime[1].data,
+                              s + MAX_RSA_PRIME_LEN - len, len);
+               } else if (dst_s_verify_str(&p, "Exponent1: ")) {
+                       if (!(len = dst_s_conv_bignum_b64_to_u8(&p, (u_char *)s,
+                                                       MAX_RSA_PRIME_LEN)))
+                               return (-9);
+                       private->primeExponent[0].len = len;
+                       if ((private->primeExponent[0].data = malloc(len))
+                           == NULL)
+                               return (-10);
+                       memcpy(private->primeExponent[0].data,
+                              s + MAX_RSA_PRIME_LEN - len, len);
+               } else if (dst_s_verify_str(&p, "Exponent2: ")) {
+                       if (!(len = dst_s_conv_bignum_b64_to_u8(&p, (u_char *)s,
+                                                       MAX_RSA_PRIME_LEN)))
+                               return (-10);
+                       private->primeExponent[1].len = len;
+                       if ((private->primeExponent[1].data = malloc(len))
+                           == NULL)
+                               return (-11);
+                       memcpy(private->primeExponent[1].data,
+                              s + MAX_RSA_PRIME_LEN - len, len);
+               } else if (dst_s_verify_str(&p, "Coefficient: ")) {
+                       if (!(len = dst_s_conv_bignum_b64_to_u8(&p, (u_char *)s,
+                                                       MAX_RSA_PRIME_LEN)))
+                               return (-11);
+                       private->coefficient.len = len;
+                       if ((private->coefficient.data = malloc(len)) == NULL)
+                               return (-12);
+                       memcpy(private->coefficient.data,
+                              s + MAX_RSA_PRIME_LEN - len, len);
+               } else {
+                       EREPORT(("Decode_RSAKey(): Bad keyword %s\n", p));
+                       return (-12);
+               }
+       }                       /* while p */
+
+       public->modulus.len = private->modulus.len;
+       if ((public->modulus.data = (u_char *) malloc(public->modulus.len)) ==
+           NULL)
+               return (-13);
+       memcpy(public->modulus.data, private->modulus.data,
+              private->modulus.len);
+
+       public->exponent.len = private->publicExponent.len;
+       if ((public->exponent.data = (u_char *) malloc(public->exponent.len))
+           == NULL)
+               return (-14);
+       memcpy(public->exponent.data, private->publicExponent.data,
+              private->publicExponent.len);
+
+       status = B_CreateKeyObject(&(b_key->rk_Public_Key));
+       if (status)
+               return (-1);
+       status = B_SetKeyInfo(b_key->rk_Public_Key, KI_RSAPublic,
+                             (POINTER) public);
+       if (status)
+               return (-1);
+
+       status = B_CreateKeyObject(&b_key->rk_Private_Key);
+       if (status)
+               return (-1);
+       status = B_SetKeyInfo(b_key->rk_Private_Key, KI_PKCS_RSAPrivate,
+                             (POINTER) private);
+       if (status)
+               return (-1);
+
+       tag = (int)(u_int16_t)
+               dst_s_get_int16(&public->modulus.data[public->modulus.len - 3]);
+       d_key->dk_key_size = dst_bsafe_key_size(b_key);
+
+       SAFE_FREE(private->modulus.data);
+       SAFE_FREE(private->publicExponent.data);
+       SAFE_FREE(private->privateExponent.data);
+       SAFE_FREE(private->prime[0].data);
+       SAFE_FREE(private->prime[1].data);
+       SAFE_FREE(private->primeExponent[0].data);
+       SAFE_FREE(private->primeExponent[1].data);
+       SAFE_FREE(private->coefficient.data);
+       SAFE_FREE(private);     /* is this the right thing to do ??? XXXX */
+       SAFE_FREE(public->modulus.data);
+       SAFE_FREE(public->exponent.data);
+       SAFE_FREE(public);
+       return (tag);
+}
+
+
+/*
+ * dst_bsafe_free_key_structure
+ *     Frees all dynamicly allocated structures in RSA_Key.
+ */
+
+static void *
+dst_bsafe_free_key_structure(void *key)
+{
+       RSA_Key *r_key = (RSA_Key *) key;
+       if (r_key != NULL) {
+               if (r_key->rk_Private_Key)
+                       B_DestroyKeyObject(&r_key->rk_Private_Key);
+               if (r_key->rk_Public_Key)
+                       B_DestroyKeyObject(&r_key->rk_Public_Key);
+               SAFE_FREE2(r_key->rk_signer, strlen(r_key->rk_signer));
+               SAFE_FREE(r_key);
+       }
+       return (NULL);
+}
+
+
+/*
+ *  dst_bsafe_generate_keypair
+ *     Generates unique keys that are hard to predict.
+ *  Parameters
+ *     key    generic Key structure
+ *     exp    the public exponent
+ *  Return 
+ *     0 Failure 
+ *     1 Success
+ */
+
+static int
+dst_bsafe_generate_keypair(DST_KEY *key, int exp)
+{
+       int i, status;
+       B_KEY_OBJ private;
+       B_KEY_OBJ public;
+       B_ALGORITHM_OBJ keypairGenerator;
+       B_ALGORITHM_OBJ randomAlgorithm;
+       A_RSA_KEY_GEN_PARAMS keygenParams;
+       char exponent[4];
+       int exponent_len;
+       RSA_Key *rsa;
+       POINTER randomSeed = NULL_PTR;
+       int randomSeedLen;
+       A_RSA_KEY *pk_access = NULL;
+
+       if (key == NULL || key->dk_alg != KEY_RSA)
+               return (0);
+
+       if ((rsa = (RSA_Key *) malloc(sizeof(RSA_Key))) == NULL) {
+               EREPORT(("dst_bsafe_generate_keypair: Memory allocation error 3"));
+               return (0);
+       }
+       memset(rsa, 0, sizeof(*rsa));
+
+       if ((status = B_CreateAlgorithmObject(&keypairGenerator)) != 0)
+               return (0);
+
+       keygenParams.modulusBits = key->dk_key_size;
+
+       /* exp = 0 or 1 are special (mean 3 or F4) */
+       if (exp == 0)
+               exp = 3;
+       else if (exp == 1)
+               exp = 65537;
+
+       /* Now encode the exponent and its length */
+       if (exp < 256) {
+               exponent_len = 1;
+               exponent[0] = exp;
+       } else if (exp < (1 << 16)) {
+               exponent_len = 2;
+               exponent[0] = exp >> 8;
+               exponent[1] = exp;
+       } else if (exp < (1 << 24)) {
+               exponent_len = 3;
+               exponent[0] = exp >> 16;
+               exponent[1] = exp >> 8;
+               exponent[2] = exp;
+       } else {
+               exponent_len = 4;
+               exponent[0] = exp >> 24;
+               exponent[1] = exp >> 16;
+               exponent[2] = exp >> 8;
+               exponent[3] = exp;
+       }
+
+       if ((keygenParams.publicExponent.data = (u_char *) malloc(exponent_len))
+           == NULL)
+               return (0);
+       memcpy(keygenParams.publicExponent.data, exponent, exponent_len);
+       keygenParams.publicExponent.len = exponent_len;
+       if ((status = B_SetAlgorithmInfo
+            (keypairGenerator, AI_RSAKeyGen, (POINTER) &keygenParams)) != 0)
+               return (0);
+
+       if ((status = B_GenerateInit(keypairGenerator, CHOOSER,
+                                    NULL_SURRENDER)) != 0)
+               return (0);
+
+       if ((status = B_CreateKeyObject(&public)) != 0)
+               return (0);
+
+       if ((status = B_CreateKeyObject(&private)) != 0)
+               return (0);
+
+       if ((status = B_CreateAlgorithmObject(&randomAlgorithm)) != 0)
+               return (0);
+
+       if ((status = B_SetAlgorithmInfo(randomAlgorithm, AI_MD5Random,
+                                        NULL_PTR))
+           != 0)
+               return (0);
+
+       if ((status = B_RandomInit(randomAlgorithm, CHOOSER,
+                                  NULL_SURRENDER)) != 0)
+               return (0);
+
+       randomSeedLen = 256;
+       if ((randomSeed = malloc(randomSeedLen)) == NULL)
+               return (0);
+       if ((status = (randomSeed == NULL_PTR)) != 0)
+               return (0);
+
+       /* gets random seed from /dev/random if present, generates random
+        * values if it is not present. 
+        * first fill the buffer with semi random data 
+        * then fill as much as possible with good random data 
+        */
+       i = dst_random(DST_RAND_SEMI, randomSeedLen, randomSeed);
+       i += dst_random(DST_RAND_KEY,  randomSeedLen, randomSeed);
+
+       if (i <= randomSeedLen) {
+               SAFE_FREE(rsa);
+               return(0);
+       }
+       if ((status = B_RandomUpdate(randomAlgorithm, randomSeed, 
+                                    randomSeedLen, NULL_SURRENDER)) != 0) {
+               SAFE_FREE(rsa);
+               return (0);
+       }
+       SAFE_FREE2(randomSeed, randomSeedLen);
+       if ((status = B_GenerateKeypair(keypairGenerator, public, private,
+                                       randomAlgorithm, NULL_SURRENDER))
+           != 0) {
+               SAFE_FREE(rsa);
+               return (0);
+       }
+       rsa->rk_signer = strdup(key->dk_key_name);
+       rsa->rk_Private_Key = private;
+       rsa->rk_Public_Key = public;
+       key->dk_KEY_struct = (void *) rsa;
+
+       /* fill in the footprint on generate key */
+       B_GetKeyInfo((POINTER *) &pk_access, public, KI_RSAPublic);
+       key->dk_id = (u_int16_t)
+               dst_s_get_int16(&pk_access->modulus.data[pk_access->modulus.len - 3]);
+       return (1);
+}
+
+
+/************************************************************************** 
+ *  dst_bsafe_compare_keys
+ *     Compare two keys for equality.
+ *  Return
+ *     0         The keys are equal
+ *     NON-ZERO   The keys are not equal
+ */
+
+static int
+dst_s_bsafe_itemcmp(ITEM i1, ITEM i2)
+{
+       if (i1.len != i2.len || memcmp (i1.data, i2.data, i1.len))
+               return (1);
+       else
+               return (0);
+}
+
+static int
+dst_bsafe_compare_keys(const DST_KEY *key1, const DST_KEY *key2)
+{
+       int status, s1 = 0, s2 = 0;
+       RSA_Key *rkey1 = (RSA_Key *) key1->dk_KEY_struct;
+       RSA_Key *rkey2 = (RSA_Key *) key2->dk_KEY_struct;
+       A_RSA_KEY *public1 = NULL, *public2 = NULL;
+       A_PKCS_RSA_PRIVATE_KEY *p1 = NULL, *p2 = NULL;
+
+       if (rkey1 == NULL && rkey2 == NULL) 
+               return(0);
+       else if (rkey1 == NULL) 
+               return (1);
+       else if (rkey2 == NULL)
+               return (2);
+
+       if (rkey1->rk_Public_Key) 
+               B_GetKeyInfo((POINTER *) &public1, rkey1->rk_Public_Key, 
+                            KI_RSAPublic);
+       if (rkey2->rk_Public_Key) 
+               B_GetKeyInfo((POINTER *) &public2, rkey2->rk_Public_Key, 
+                            KI_RSAPublic);
+       if (public1 == NULL && public2 == NULL)
+               return (0);
+       else if (public1 == NULL || public2 == NULL)
+               return (1);
+
+       status = dst_s_bsafe_itemcmp(public1->modulus, public2->modulus) ||
+                dst_s_bsafe_itemcmp(public1->exponent, public2->exponent);
+
+       if (status) 
+               return (status);
+
+       if (rkey1->rk_Private_Key == NULL || rkey2->rk_Private_Key == NULL)
+               /* if neither or only one is private key consider identical */
+               return (status);  
+       if (rkey1->rk_Private_Key)
+               s1 = B_GetKeyInfo((POINTER *) &p1, rkey1->rk_Private_Key,
+                                 KI_PKCS_RSAPrivate);
+       if (rkey2->rk_Private_Key)
+               s2 = B_GetKeyInfo((POINTER *) &p2, rkey2->rk_Private_Key,
+                                 KI_PKCS_RSAPrivate);
+       if (p1 == NULL || p2 == NULL) 
+               return (0);
+
+       status = dst_s_bsafe_itemcmp(p1->modulus, p2->modulus) ||
+               dst_s_bsafe_itemcmp (p1->publicExponent, 
+                                    p2->publicExponent) ||
+               dst_s_bsafe_itemcmp (p1->privateExponent, 
+                                    p2->privateExponent) ||
+               dst_s_bsafe_itemcmp (p1->prime[0], p2->prime[0]) ||
+               dst_s_bsafe_itemcmp (p1->prime[1], p2->prime[1]) ||
+               dst_s_bsafe_itemcmp (p1->primeExponent[0], 
+                                    p2->primeExponent[0])||
+               dst_s_bsafe_itemcmp (p1->primeExponent[1], 
+                                    p2->primeExponent[1])||
+               dst_s_bsafe_itemcmp (p1->coefficient, p2->coefficient);
+       return (status);
+}
+
+
+/* 
+ * dst_bsafe_key_size() 
+ * Function to calculate how the size of the key in bits
+ */
+static int
+dst_bsafe_key_size(RSA_Key *r_key)
+{
+       int size;
+       A_PKCS_RSA_PRIVATE_KEY *private = NULL;
+
+       if (r_key == NULL)
+               return (-1);
+       if (r_key->rk_Private_Key)
+               B_GetKeyInfo((POINTER *) &private, r_key->rk_Private_Key,
+                            KI_PKCS_RSAPrivate);
+       else if (r_key->rk_Public_Key)
+               B_GetKeyInfo((POINTER *) &private, r_key->rk_Public_Key,
+                            KI_RSAPublic);
+       size = dst_s_calculate_bits(private->modulus.data,
+                                   private->modulus.len * 8);
+       return (size);
+}
+
+/* 
+ * dst_bsafe_md5digest(): function to digest data using MD5 digest function 
+ * if needed 
+ */
+static int
+dst_bsafe_md5digest(const int mode, B_ALGORITHM_OBJ *digest_obj,
+                   const u_char *data, const int len,
+                   u_char *digest, const int digest_len)
+{
+       int status = 0;
+       u_int work_size = 0;
+
+       if (digest_obj == NULL || *digest_obj == NULL) {
+               printf("NO digest obj\n");
+               exit(-33);
+       }
+
+       if ((mode & SIG_MODE_INIT) &&
+           (status = B_DigestInit(*digest_obj, (B_KEY_OBJ) NULL,
+                                  CHOOSER, NULL_SURRENDER)))
+               return (SIGN_INIT_FAILURE);
+
+       if ((mode & SIG_MODE_UPDATE) && data && (len > 0) &&
+           (status = B_DigestUpdate(*digest_obj, data, len, NULL_SURRENDER)))
+               return (SIGN_UPDATE_FAILURE);
+
+       if (mode & SIG_MODE_FINAL) {
+               if (digest == NULL ||
+                   (status = B_DigestFinal(*digest_obj, digest, &work_size,
+                                           digest_len, NULL_SURRENDER)))
+                       return (SIGN_FINAL_FAILURE);
+               return (work_size);
+       }
+       return (0);
+}
+
+/* 
+ * just use the standard memory functions for bsafe 
+ */
+void
+T_free(POINTER block)
+{
+       free(block);
+}
+
+POINTER
+T_malloc(unsigned int len)
+{
+       return (malloc(len));
+}
+
+int
+T_memcmp(CPOINTER firstBlock, CPOINTER secondBlock, unsigned int len)
+{
+       return (memcmp(firstBlock, secondBlock, len));
+}
+
+void
+T_memcpy(POINTER output, CPOINTER input, unsigned int len)
+{
+       memcpy(output, input, len);
+}
+
+void
+T_memmove(POINTER output, POINTER input, unsigned int len)
+{
+       memmove(output, input, len);
+}
+
+void
+T_memset(POINTER output, int value, unsigned int len)
+{
+       memset(output, value, len);
+}
+
+POINTER
+T_realloc(POINTER block, unsigned int len)
+{
+       return (realloc(block, len));
+}
+
+#else  /* BSAFE NOT available */
+int
+dst_bsafe_init()
+{
+       return (0);
+}
+#endif /* BSAFE */
diff --git a/lib/bind/dst/cylink_link.c b/lib/bind/dst/cylink_link.c
new file mode 100644 (file)
index 0000000..27d657e
--- /dev/null
@@ -0,0 +1,678 @@
+#ifdef CYLINK_DSS
+static const char rcsid[] = "$Header: /u0/home/explorer/proj/ISC/git-conversion/cvsroot/bind9/lib/bind/dst/Attic/cylink_link.c,v 1.1 2001/03/29 06:31:31 marka 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.
+ */
+/* 
+ * This file contains two components 
+ * 1. Interface to the CYLINK library to allow compilation of Bind 
+ *    with TIS/DNSSEC when CYLINK is not available 
+ *    all calls to CYLINK are contained inside this file.
+ * 2. The glue to connvert DSA KEYS to and from external formats
+ */
+#include "port_before.h"
+
+#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 "dst_internal.h"
+#include <toolkit.h>
+
+#include "port_after.h"
+
+typedef struct cylinkkey {
+       char *dk_signer;
+       uchar *dk_p;
+       uchar *dk_q;
+       uchar *dk_g;
+       uchar *dk_x;
+       uchar *dk_y;
+       ushort dk_p_bytes;
+} DSA_Key;
+
+#define NULL_PRIV_KEY(k)(k == NULL || k->dk_p == NULL || k->dk_q == NULL || \
+                         k->dk_g == NULL || k->dk_x == NULL)
+#define NULL_PUB_KEY(k)(k == NULL || k->dk_p == NULL || k->dk_q == NULL || \
+                        k->dk_g == NULL || k->dk_y == NULL)
+
+static int dst_cylink_sign(const int mode, DST_KEY *dkey, void **context,
+                          const u_char *data, const int len,
+                          u_char *signature, const int sig_len);
+
+static int dst_cylink_verify(const int mode, DST_KEY *dkey, void **context,
+                            const u_char *data, const int len,
+                            const u_char *signature, const int sig_len);
+
+static int dst_cylink_to_dns_key(const DST_KEY *in_key, u_char *out_str,
+                                const int out_len);
+static int dst_cylink_from_dns_key(DST_KEY *s_key, const u_char *key,
+                                  const int len);
+static int dst_cylink_key_to_file_format(const DST_KEY *key, char *buff,
+                                        const int buff_len);
+static int dst_cylink_key_from_file_format(DST_KEY *d_key,
+                                          const char *buff,
+                                          const int buff_len);
+static void *dst_cylink_free_key_structure(void *key);
+
+static int dst_cylink_generate_keypair(DST_KEY *key, int exp);
+static int dst_cylink_compare_keys(const DST_KEY *key1, const DST_KEY *key2);
+
+static void *memcpyend(void *dest, const void *src, size_t n, size_t size);
+
+/*
+ * dst_cylink_init()  Function to answer set up function pointers for 
+ *         CYLINK related functions 
+ */
+int
+dst_cylink_init()
+{
+       if (dst_t_func[KEY_DSA] != NULL)
+               return (1);
+       dst_t_func[KEY_DSA] = malloc(sizeof(struct dst_func));
+       if (dst_t_func[KEY_DSA] == NULL)
+               return (0);
+       memset(dst_t_func[KEY_DSA], 0, sizeof(struct dst_func));
+       dst_t_func[KEY_DSA]->sign = dst_cylink_sign;
+       dst_t_func[KEY_DSA]->verify = dst_cylink_verify;
+       dst_t_func[KEY_DSA]->compare = dst_cylink_compare_keys;
+       dst_t_func[KEY_DSA]->generate = dst_cylink_generate_keypair;
+       dst_t_func[KEY_DSA]->destroy = dst_cylink_free_key_structure;
+       dst_t_func[KEY_DSA]->from_dns_key = dst_cylink_from_dns_key;
+       dst_t_func[KEY_DSA]->to_dns_key = dst_cylink_to_dns_key;
+       dst_t_func[KEY_DSA]->from_file_fmt = dst_cylink_key_from_file_format;
+       dst_t_func[KEY_DSA]->to_file_fmt = dst_cylink_key_to_file_format;
+       SetDataOrder(1);
+       return (1);
+}
+
+/*
+ * dst_cylink_sign
+ *     Call CYLINK 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.
+ *     algobj      structure holds context for a sign done in multiple calls.
+ *     context   the context to use for this computation
+ *     data    data to be signed.
+ *     len      length in bytes of data.
+ *     priv_key    key to use for signing.
+ *     signature   location to store signature.
+ *     sig_len     size in bytes of signature field.
+ * returns 
+ *     N  Success on SIG_MODE_FINAL = returns signature length in bytes
+ *         N is 41 for DNS
+ *     0  Success on SIG_MODE_INIT  and UPDATE
+ *      <0  Failure
+ */
+
+static int
+dst_cylink_sign(const int mode, DST_KEY *dkey, void **context,
+               const u_char *data, const int len, 
+               u_char *signature, const int sig_len)
+{
+       int sign_len = 0;
+       int status;
+       SHA_context *ctx = NULL;
+
+       if (mode & SIG_MODE_INIT) 
+               ctx = (SHA_context *) malloc(sizeof(SHA_context));
+       else if (context)
+               ctx = (SHA_context *) *context;
+       if (ctx == NULL)
+               return (-1);
+
+       if (mode & SIG_MODE_INIT)
+               SHAInit(ctx);
+
+       if ((mode & SIG_MODE_UPDATE) && (data && len > 0)) {
+               status = SHAUpdate(ctx, data, len);
+               if (status != SUCCESS)
+                       return (SIGN_UPDATE_FAILURE);
+       }
+       if (mode & SIG_MODE_FINAL) {
+               DSA_Key *key;
+               uchar digest[SHA_LENGTH];
+               uchar rand[SHA_LENGTH];
+               uchar r[SHA_LENGTH], s[SHA_LENGTH];
+
+               if (signature == NULL || sig_len < 2 * SHA_LENGTH)
+                       return (SIGN_FINAL_FAILURE);
+               if ((status = SHAFinal(ctx, digest)) != SUCCESS)
+                       return (SIGN_FINAL_FAILURE);
+               SAFE_FREE(ctx);
+               if (dkey == NULL || dkey->dk_KEY_struct == NULL)
+                       return (-1);
+               key = (DSA_Key *) dkey->dk_KEY_struct;
+               if (NULL_PRIV_KEY(key))
+                       return (-2);
+               dst_random(DST_RAND_STD, sizeof(rand), rand);
+               status = GenDSSSignature(key->dk_p_bytes, key->dk_p,
+                                        key->dk_q, key->dk_g, key->dk_x,
+                                        rand, r, s, digest);
+               if (status != SUCCESS)
+                       return (SIGN_FINAL_FAILURE);
+               *signature = (dkey->dk_key_size - 512)/64;
+               sign_len = 1;
+               memcpy(signature + sign_len, r, SHA_LENGTH);
+               sign_len += SHA_LENGTH;
+               memcpy(signature + sign_len, s, SHA_LENGTH);
+               sign_len += SHA_LENGTH;
+       }
+       else {
+               if (context == NULL) 
+                       return (-1);
+               *context = (void *) ctx;
+       }
+       return (sign_len);
+}
+
+
+/*
+ * Dst_cylink_verify 
+ *     Calls CYLINK 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      structure holds context for a verify done in multiple calls.
+ *     context   algorithm specific context for the current context processing
+ *     data    data signed.
+ *     len      length in bytes of data.
+ *     pub_key     key to use for verify.
+ *     signature   signature.
+ *     sig_len     length in bytes of signature.
+ * returns 
+ *     0  Success 
+ *    <0  Failure
+ */
+
+static int
+dst_cylink_verify(const int mode, DST_KEY *dkey, void **context,
+                 const u_char *data, const int len,
+                 const u_char *signature, const int sig_len)
+{
+       int status;
+       SHA_context *ctx = NULL;
+
+       if (mode & SIG_MODE_INIT) 
+               ctx = (SHA_context *) malloc(sizeof(SHA_context));
+       else if (context)
+               ctx = (SHA_context *) *context;
+       if (ctx == NULL)
+               return (-1);
+
+       if (mode & SIG_MODE_INIT)
+               SHAInit(ctx);
+
+       if ((mode & SIG_MODE_UPDATE) && (data && len > 0)) {
+               status = SHAUpdate(ctx, data, len);
+               if (status != SUCCESS)
+                       return (VERIFY_UPDATE_FAILURE);
+       }
+       if (mode & SIG_MODE_FINAL) {
+               DSA_Key *key;
+               uchar digest[SHA_LENGTH];
+               uchar r[SHA_LENGTH], s[SHA_LENGTH];
+
+               if (dkey == NULL || dkey->dk_KEY_struct == NULL)
+                       return (-1);
+               key = (DSA_Key *) dkey->dk_KEY_struct;
+               if (NULL_PUB_KEY(key))
+                       return (-2);
+               if (signature == NULL || sig_len != (2 * SHA_LENGTH +1))
+                       return (SIGN_FINAL_FAILURE);
+               status = SHAFinal(ctx, digest);
+               SAFE_FREE(ctx);
+               if (status != SUCCESS)
+                       return (SIGN_FINAL_FAILURE);
+               if (((int)*signature) != ((key->dk_p_bytes -64)/8))
+                       return(VERIFY_FINAL_FAILURE);
+
+               memcpy(r, signature +1, SHA_LENGTH);
+               memcpy(s, signature + SHA_LENGTH +1, SHA_LENGTH);
+               status = VerDSSSignature(key->dk_p_bytes, key->dk_p,
+                                        key->dk_q, key->dk_g, key->dk_y,
+                                        r, s, digest);
+               if (status != SUCCESS)
+                       return (VERIFY_FINAL_FAILURE);
+       }
+       else {
+               if (context == NULL) 
+                       return (-1);
+               *context = (void *) ctx;
+       }
+       return (0);
+}
+
+
+/*
+ * dst_cylink_to_dns_key
+ *     Converts key from DSA to DNS distribution format
+ *     This function gets in a pointer to the public key and a work area
+ *     to write the key into.
+ * Parameters
+ *     public    KEY structure 
+ *     out_str   buffer to write encoded key into 
+ *     out_len   size of out_str
+ * Return
+ *     N >= 0 length of encoded key 
+ *     n < 0  error 
+ */
+
+static int
+dst_cylink_to_dns_key(const DST_KEY *in_key, u_char *out_str,
+                     const int out_len)
+{
+       u_char *op = out_str;
+       int t;
+       DSA_Key *key;
+
+       if (in_key == NULL || in_key->dk_KEY_struct == NULL ||
+           out_len <= 0 || out_str == NULL)
+               return (-1);
+       key = (DSA_Key *) in_key->dk_KEY_struct;
+
+       t = (key->dk_p_bytes - 64) / 8;
+
+       *op++ = t;
+       memcpy(op, key->dk_q, SHA_LENGTH);
+       op += SHA_LENGTH;
+       memcpy(op, key->dk_p, key->dk_p_bytes);
+       op += key->dk_p_bytes;
+       memcpy(op, key->dk_g, key->dk_p_bytes);
+       op += key->dk_p_bytes;
+       memcpy(op, key->dk_y, key->dk_p_bytes);
+       op += key->dk_p_bytes;
+
+       return (op - out_str);
+}
+
+
+/*
+ * dst_cylink_from_dns_key
+ *     Converts from a DNS KEY RR format to an RSA KEY. 
+ * Parameters
+ *     len    Length in bytes of DNS key
+ *     key    DNS key
+ *     name   Key name
+ *     s_key  DST structure that will point to the RSA key this routine
+ *             will build.
+ * Return
+ *     0   The input key, s_key or name was null.
+ *     1   Success
+ */
+static int
+dst_cylink_from_dns_key(DST_KEY *s_key, const u_char *key, const int len)
+{
+       int t;
+       const u_char *key_ptr = key;
+       DSA_Key *d_key;
+
+       if (s_key == NULL || len < 0 || key == NULL)
+               return (0);
+
+       if (len == 0)  /* process null key */
+               return (1);
+
+       if (key_ptr == NULL)  
+               return (0);
+       t = (int) *key_ptr++;   /* length of exponent in bytes */
+
+       if ((3 * (t * 8 + 64) + SHA_LENGTH + 1) != len)
+               return (0);
+
+       if ((d_key = (DSA_Key *) malloc(sizeof(DSA_Key))) == NULL) {
+               EREPORT(("dst_cylink_from_dns_key(): Memory allocation error 1"));
+               return (0);
+       }
+       memset(d_key, 0, sizeof(DSA_Key));
+       s_key->dk_KEY_struct = (void *) d_key;
+       d_key->dk_signer = strdup(s_key->dk_key_name);
+       d_key->dk_p_bytes = 64 + 8 * t;
+
+       if ((d_key->dk_q = (uchar *) malloc(SHA_LENGTH)) == NULL)
+               return (0);
+       memcpy(d_key->dk_q, key_ptr, SHA_LENGTH);
+       key_ptr += SHA_LENGTH;
+
+       if ((d_key->dk_p = (uchar *) malloc(d_key->dk_p_bytes)) == NULL)
+               return (0);
+       memcpy(d_key->dk_p, key_ptr, d_key->dk_p_bytes);
+       key_ptr += d_key->dk_p_bytes;
+
+       if ((d_key->dk_g = (uchar *) malloc(d_key->dk_p_bytes)) == NULL)
+               return (0);
+       memcpy(d_key->dk_g, key_ptr, d_key->dk_p_bytes);
+       key_ptr += d_key->dk_p_bytes;
+
+       if ((d_key->dk_y = (uchar *) malloc(d_key->dk_p_bytes)) == NULL)
+               return (0);
+       memcpy(d_key->dk_y, key_ptr, d_key->dk_p_bytes);
+       key_ptr += d_key->dk_p_bytes;
+
+       s_key->dk_id = dst_s_id_calc(key, len); 
+       s_key->dk_key_size = d_key->dk_p_bytes * 8;
+       return (1);
+}
+
+
+/************************************************************************** 
+ *  dst_cylink_key_to_file_format
+ *     Encodes an DSA Key into the portable file format.
+ *  Parameters 
+ *     key      DSA KEY structure 
+ *     buff      output buffer
+ *     buff_len  size of output buffer 
+ *  Return
+ *     0  Failure - null input rkey
+ *     -1  Failure - not enough space in output area
+ *     N  Success - Length of data returned in buff
+ */
+
+static int
+dst_cylink_key_to_file_format(const DST_KEY *key, char *buff,
+                             const int buff_len)
+{
+       char *bp;
+       int len, b_len;
+       DSA_Key *dkey;
+       u_char num[256]; /* More than long enough for DSA keys */
+
+       if (key == NULL || key->dk_KEY_struct == NULL)  /* no output */
+               return (0);
+       if (buff == NULL || buff_len <= (int) strlen(key_file_fmt_str))
+               return (-1);    /* no OR not enough space in output area */
+
+       dkey = (DSA_Key *) key->dk_KEY_struct;
+
+           memset(buff, 0, buff_len);  /* just in case */
+       /* write file header */
+       sprintf(buff, key_file_fmt_str, KEY_FILE_FORMAT, KEY_DSA, "DSA");
+
+       bp = (char *) strchr(buff, '\0');
+       b_len = buff_len - (bp - buff);
+       memcpy(num, dkey->dk_p, dkey->dk_p_bytes);
+       if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Prime(p): ",
+                                              num, dkey->dk_p_bytes)) <= 0)
+               return (-1);
+
+       bp = (char *) strchr(buff, '\0');
+       b_len = buff_len - (bp - buff);
+       memcpy(num, dkey->dk_q, dkey->dk_p_bytes);
+       if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Subprime(q): ",
+                                              num, SHA_LENGTH)) <= 0)
+               return (-2);
+
+       bp = (char *) strchr(buff, '\0');
+       b_len = buff_len - (bp - buff);
+       memcpy(num, dkey->dk_g, dkey->dk_p_bytes);
+       if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Base(g): ",
+                                              num, dkey->dk_p_bytes)) <= 0)
+               return (-3);
+
+       bp = (char *) strchr(buff, '\0');
+       b_len = buff_len - (bp - buff);
+       memcpy(num, dkey->dk_x, dkey->dk_p_bytes);
+       if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Private_value(x): ",
+                                              num, SHA_LENGTH)) <= 0)
+               return (-4);
+
+       bp = (char *) strchr(buff, '\0');
+       b_len = buff_len - (bp - buff);
+       memcpy(num, dkey->dk_y, dkey->dk_p_bytes);
+       if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Public_value(y): ",
+                                              num, dkey->dk_p_bytes)) <= 0)
+               return (-4);
+
+       bp += len;
+       b_len -= len;
+       return (buff_len - b_len);
+}
+
+
+/************************************************************************** 
+ * dst_cylink_key_from_file_format
+ *     Converts contents of a private key file into a private DSA key. 
+ * Parameters 
+ *     DSA_Key    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_cylink_key_from_file_format(DST_KEY *d_key, const char *buff,
+                               const int buff_len)
+{
+       u_char s[DSS_LENGTH_MAX];
+       u_char dns[1024];
+       int len, s_len = sizeof(s);
+       int foot = -1, dnslen;
+       const char *p = buff;
+       DSA_Key *dsa_key;
+
+       if (d_key == NULL || buff == NULL || buff_len <= 0)
+               return (-1);
+
+       dsa_key = (DSA_Key *) malloc(sizeof(DSA_Key));
+       if (dsa_key == NULL) {
+               return (-2);
+       }
+       memset(dsa_key, 0, sizeof(*dsa_key));
+       d_key->dk_KEY_struct = (void *) dsa_key;
+
+       if (!dst_s_verify_str(&p, "Prime(p): "))
+               return (-3);
+       memset(s, 0, s_len);
+       if ((len = dst_s_conv_bignum_b64_to_u8(&p, s, s_len)) == 0)
+               return (-4);
+       dsa_key->dk_p_bytes = len;
+       if ((dsa_key->dk_p = malloc(len)) == NULL)
+               return (-5);
+       memcpy(dsa_key->dk_p, s + s_len - len, len);
+
+       while (*++p && p < (const char *) &buff[buff_len]) {
+               if (dst_s_verify_str(&p, "Subprime(q): ")) {
+                       if (!(len = dst_s_conv_bignum_b64_to_u8(&p, s, s_len)))
+                               return (-6);
+                       if ((dsa_key->dk_q = malloc(SHA_LENGTH)) == NULL)
+                               return (-7);
+                       memcpyend(dsa_key->dk_q, s + s_len - len, len,
+                                 SHA_LENGTH);
+               } else if (dst_s_verify_str(&p, "Base(g): ")) {
+                       if (!(len = dst_s_conv_bignum_b64_to_u8(&p, s, s_len)))
+                               return (-8);
+                       if ((dsa_key->dk_g = malloc(dsa_key->dk_p_bytes))
+                           == NULL)
+                               return (-9);
+                       memcpyend(dsa_key->dk_g, s + s_len - len, len,
+                                 dsa_key->dk_p_bytes);
+               } else if (dst_s_verify_str(&p, "Private_value(x): ")) {
+                       if (!(len = dst_s_conv_bignum_b64_to_u8(&p, s, s_len)))
+                               return (-10);
+                       if ((dsa_key->dk_x = malloc(SHA_LENGTH)) == NULL)
+                               return (-11);
+                       memcpyend(dsa_key->dk_x, s + s_len - len, len,
+                                 SHA_LENGTH);
+               } else if (dst_s_verify_str(&p, "Public_value(y): ")) {
+                       if (!(len = dst_s_conv_bignum_b64_to_u8(&p, s, s_len)))
+                               return (-10);
+                       if ((dsa_key->dk_y = malloc(dsa_key->dk_p_bytes))
+                           == NULL)
+                               return (-11);
+                       memcpyend(dsa_key->dk_y, s + s_len - len, len,
+                                 dsa_key->dk_p_bytes);
+               } else {
+                       EREPORT(("Decode_DSAKey(): Bad keyword %s\n", p));
+                       return (-12);
+               }
+       }                       /* while p */
+
+       d_key->dk_key_size = dsa_key->dk_p_bytes * 8;
+       dnslen = d_key->dk_func->to_dns_key(d_key, dns, sizeof(dns));
+       foot = dst_s_id_calc(dns, dnslen);
+
+       return (foot);
+}
+
+
+/************************************************************************** 
+ * dst_cylink_free_key_structure
+ *     Frees all dynamicly allocated structures in DSA_Key.
+ */
+
+static void *
+dst_cylink_free_key_structure(void *key)
+{
+       DSA_Key *d_key = (DSA_Key *) key;
+       if (d_key != NULL) {
+               SAFE_FREE(d_key->dk_signer);
+               SAFE_FREE(d_key->dk_p);
+               SAFE_FREE(d_key->dk_q);
+               SAFE_FREE(d_key->dk_g);
+               SAFE_FREE(d_key->dk_x);
+               SAFE_FREE(d_key->dk_y);
+               SAFE_FREE(d_key);
+       }
+       return (NULL);
+}
+
+
+/************************************************************************** 
+ *  dst_cylink_generate_keypair
+ *     Generates unique keys that are hard to predict.
+ *  Parameters
+ *     key    generic Key structure
+ *     exp    the public exponent
+ *  Return 
+ *     0 Failure 
+ *     1 Success
+ */
+
+static int
+dst_cylink_generate_keypair(DST_KEY *key, int nothing)
+{
+       int status, dnslen, n;
+       DSA_Key *dsa;
+       u_char rand[SHA_LENGTH];
+       u_char dns[1024];
+
+       UNUSED(nothing);
+
+       if (key == NULL || key->dk_alg != KEY_DSA)
+               return (0);
+
+       if ((dsa = (DSA_Key *) malloc(sizeof(DSA_Key))) == NULL) {
+               EREPORT(("dst_cylink_generate_keypair: Memory allocation error 3"));
+               return (0);
+       }
+       memset(dsa, 0, sizeof(*dsa));
+
+       dsa->dk_p_bytes = key->dk_key_size / 8;
+       dsa->dk_p = (uchar *) malloc(dsa->dk_p_bytes);
+       dsa->dk_q = (uchar *) malloc(SHA_LENGTH);
+       dsa->dk_g = (uchar *) malloc(dsa->dk_p_bytes);
+       dsa->dk_x = (uchar *) malloc(SHA_LENGTH);
+       dsa->dk_y = (uchar *) malloc(dsa->dk_p_bytes);
+       if (!dsa->dk_p || !dsa->dk_q || !dsa->dk_g || !dsa->dk_x || !dsa->dk_y) {
+               EREPORT(("dst_cylink_generate_keypair: Memory allocation error 4"));
+               return (0);
+       }
+       n = dst_random(DST_RAND_KEY, sizeof(rand), rand);
+       if (n != sizeof(rand))
+               return (0);
+       status = GenDSSParameters(dsa->dk_p_bytes, dsa->dk_p, dsa->dk_q,
+                                 dsa->dk_g, rand, NULL);
+       if (status != SUCCESS)
+               return (0);
+
+       status = GenDSSKey(dsa->dk_p_bytes, dsa->dk_p, dsa->dk_q, dsa->dk_g,
+                          dsa->dk_x, dsa->dk_y, rand);
+       if (status != SUCCESS)
+               return (0);
+       memset(rand, 0, sizeof(rand));
+       key->dk_KEY_struct = (void *) dsa;
+       dnslen = key->dk_func->to_dns_key(key, dns, sizeof(dns));
+       key->dk_id = dst_s_id_calc(dns, dnslen);
+       return (1);
+}
+
+
+/*
+ *  dst_cylink_compare_keys
+ *     Compare two keys for equality.
+ *  Return
+ *     0         The keys are equal
+ *     NON-ZERO   The keys are not equal
+ */
+
+static int
+dst_cylink_compare_keys(const DST_KEY *key1, const DST_KEY *key2)
+{
+       int status;
+       DSA_Key *dkey1 = (DSA_Key *) key1->dk_KEY_struct;
+       DSA_Key *dkey2 = (DSA_Key *) key2->dk_KEY_struct;
+
+       if (dkey1 == NULL && dkey2 == NULL)
+               return (0);
+       else if (dkey1 == NULL) 
+               return (2);
+       else if (dkey2 == NULL)
+               return(1);
+
+       if (dkey1->dk_p_bytes != dkey2->dk_p_bytes)
+               return (201);
+       status = memcmp(dkey1->dk_p, dkey2->dk_p, dkey1->dk_p_bytes) ||
+               memcmp(dkey1->dk_q, dkey2->dk_q, SHA_LENGTH) ||
+               memcmp(dkey1->dk_g, dkey2->dk_g, dkey1->dk_p_bytes) ||
+               memcmp(dkey1->dk_y, dkey2->dk_y, dkey1->dk_p_bytes);
+       if (status)
+               return (status);
+       if (dkey1->dk_x || dkey2->dk_x) {
+               if (dkey1->dk_x == NULL || dkey2->dk_x == NULL)
+                       return (202);
+               return (memcmp(dkey1->dk_x, dkey2->dk_x, dkey1->dk_p_bytes));
+       } else
+               return (0);
+}
+
+static void *
+memcpyend(void *dest, const void *src, size_t n, size_t size) {
+       if (n < size)
+               memset(dest, 0, size - n);
+       memcpy((char *)dest + size - n, src, n);
+       return dest;
+}
+
+#else 
+int
+dst_cylink_init() 
+{
+       return (0);
+}
+#endif /* CYLINK */
diff --git a/lib/bind/dst/dst_api.c b/lib/bind/dst/dst_api.c
new file mode 100644 (file)
index 0000000..954f8c5
--- /dev/null
@@ -0,0 +1,1069 @@
+#ifndef LINT
+static const char rcsid[] = "$Header: /u0/home/explorer/proj/ISC/git-conversion/cvsroot/bind9/lib/bind/dst/Attic/dst_api.c,v 1.1 2001/03/29 06:31:31 marka 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 "port_before.h"
+#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 <arpa/nameser.h>
+#include <resolv.h>
+
+#include "dst_internal.h"
+#include "port_after.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 u_int16_t in_id, int in_alg);
+static int dst_s_read_private_key_file(char *name, DST_KEY *pk_key,
+                                      u_int16_t 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 int 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;
+       int 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 *tmp;
+                       tmp = (char *) malloc(len + 2);
+                       memcpy(tmp, s, len + 1);
+                       if (tmp[strlen(tmp) - 1] != '/') {
+                               tmp[strlen(tmp) + 1] = 0;
+                               tmp[strlen(tmp)] = '/';
+                       }
+                       dst_path = tmp;
+               }
+       }
+       memset(dst_t_func, 0, sizeof(dst_t_func));
+       /* first one is selected */
+       dst_bsafe_init();
+       dst_rsaref_init(); 
+       dst_hmac_md5_init();
+       dst_eay_dss_init();
+       dst_cylink_init();
+}
+
+/*
+ *  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 int 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 int len,
+             u_char *signature, const int 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 int len,
+               const u_char *signature, const int 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 u_int16_t 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];
+       int 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 u_int16_t in_id, int in_alg)
+{
+       int flags, proto, alg, len, 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, 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], len - 6, enc_key, sizeof(enc_key));
+       else
+               b64_ntop(&out_key[4], 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 int 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 int 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);
+       dst_s_put_int16(out_storage, val);
+       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);
+               dst_s_put_int16(&out_storage[loc], val);
+               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 int flags,              /* dns flags */
+                 const int protocol,           /* dns protocol */
+                 const u_char *key_buf,        /* key in dns wire fmt */
+                 const int 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, int 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->to_dns_key != 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, u_int16_t 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, &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, cnt);
+       return (1);
+
+ fail:
+       memset(in_buff, 0, 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 int 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, int 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, 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/lib/bind/dst/dst_internal.h b/lib/bind/dst/dst_internal.h
new file mode 100644 (file)
index 0000000..0825109
--- /dev/null
@@ -0,0 +1,168 @@
+#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>
+#if (!defined(BSD)) || (BSD < 199306)
+# include <sys/bitypes.h>
+#else
+# include <sys/types.h>
+#endif
+
+#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 */
+       u_int32_t dk_flags;     /* and the flags of the public key */
+       u_int16_t 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/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)           (void)0
+#endif
+
+/* use our own special macro to FRRE memory */
+
+#ifndef SAFE_FREE
+#define SAFE_FREE(a) \
+do{if(a != NULL){memset(a,0, sizeof(*a)); free(a); a=NULL;}} while (0)
+#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 int len,
+                    u_int8_t *signature, const int sig_len);
+       int (*verify)(const int mode, DST_KEY *key, void **context,
+                      const u_int8_t *data, const int len,
+                      const u_int8_t *signature, const int 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 int out_len);
+       int (*from_dns_key)(DST_KEY *key, const u_int8_t *str,
+                            const int str_len);
+       int (*to_file_fmt)(const DST_KEY *key, char *out,
+                           const int out_len);
+       int (*from_file_fmt)(DST_KEY *key, const char *out,
+                             const int 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
+
+int dst_bsafe_init(void);
+
+int dst_rsaref_init(void);
+
+int dst_hmac_md5_init(void);
+
+int dst_cylink_init(void);
+
+int dst_eay_dss_init(void);
+
+/* support functions */
+/* base64 to bignum conversion routines */
+int       dst_s_conv_bignum_u8_to_b64( char *out_buf, const int out_len, 
+                                      const char *header,
+                                      const u_int8_t *bin_data,
+                                      const int bin_len);
+int       dst_s_conv_bignum_b64_to_u8( const char **buf, u_int8_t *loc,
+                                      const int 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, 
+                                u_int16_t id, int alg, const char *suffix, 
+                                size_t filename_length);
+
+FILE      *dst_s_fopen (const char *filename, const char *mode, int perm);
+
+/* from file prandom.c */
+int       dst_s_random( u_int8_t *output, int size);
+int       dst_s_semi_random( u_int8_t *output, int 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
+void
+dst_s_dump(const int mode, const u_char *data, const int size,
+            const char *msg);
+
+
+
+#endif /* DST_INTERNAL_H */
diff --git a/lib/bind/dst/eay_dss_link.c b/lib/bind/dst/eay_dss_link.c
new file mode 100644 (file)
index 0000000..c4d024c
--- /dev/null
@@ -0,0 +1,638 @@
+#ifdef EAY_DSS
+static const char rcsid[] = "$Header: /u0/home/explorer/proj/ISC/git-conversion/cvsroot/bind9/lib/bind/dst/Attic/eay_dss_link.c,v 1.1 2001/03/29 06:31:31 marka 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.
+ */
+/* 
+ * This file contains two components 
+ * 1. Interface to the EAY libcrypto library to allow compilation of Bind 
+ *    with TIS/DNSSEC when EAY libcrypto is not available 
+ *    all calls to libcrypto are contained inside this file.
+ * 2. The glue to connvert DSA KEYS to and from external formats
+ */
+#include "port_before.h"
+
+#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 "dst_internal.h"
+
+#include "crypto.h"
+#include "bn.h"
+#include "dsa.h"
+#include "sha.h"
+
+#include "port_after.h"
+
+
+static int dst_eay_dss_sign(const int mode, DST_KEY *dkey, void **context,
+                           const u_char *data, const int len,
+                           u_char *signature, const int sig_len);
+
+static int dst_eay_dss_verify(const int mode, DST_KEY *dkey, void **context,
+                             const u_char *data, const int len,
+                             const u_char *signature, const int sig_len);
+
+static int dst_eay_dss_to_dns_key(const DST_KEY *in_key, u_char *out_str,
+                                 const int out_len);
+static int dst_eay_dss_from_dns_key(DST_KEY *s_key, const u_char *key,
+                                   const int len);
+static int dst_eay_dss_key_to_file_format(const DST_KEY *key, u_char *buff,
+                                         const int buff_len);
+static int dst_eay_dss_key_from_file_format(DST_KEY *d_key,
+                                           const u_char *buff,
+                                           const int buff_len);
+static void *dst_eay_dss_free_key_structure(void *key);
+
+static int dst_eay_dss_generate_keypair(DST_KEY *key, int exp);
+static int dst_eay_dss_compare_keys(const DST_KEY *key1, const DST_KEY *key2);
+
+/*
+ * dst_eay_dss_init()  Function to answer set up function pointers for 
+ *         EAY DSS related functions 
+ */
+int
+dst_eay_dss_init(void)
+{
+       if (dst_t_func[KEY_DSA] != NULL)
+               return (1);
+       dst_t_func[KEY_DSA] = malloc(sizeof(struct dst_func));
+       if (dst_t_func[KEY_DSA] == NULL)
+               return (0);
+       memset(dst_t_func[KEY_DSA], 0, sizeof(struct dst_func));
+       dst_t_func[KEY_DSA]->sign = dst_eay_dss_sign;
+       dst_t_func[KEY_DSA]->verify = dst_eay_dss_verify;
+       dst_t_func[KEY_DSA]->compare = dst_eay_dss_compare_keys;
+       dst_t_func[KEY_DSA]->generate = dst_eay_dss_generate_keypair;
+       dst_t_func[KEY_DSA]->destroy = dst_eay_dss_free_key_structure;
+       dst_t_func[KEY_DSA]->from_dns_key = dst_eay_dss_from_dns_key;
+       dst_t_func[KEY_DSA]->to_dns_key = dst_eay_dss_to_dns_key;
+       dst_t_func[KEY_DSA]->from_file_fmt = dst_eay_dss_key_from_file_format;
+       dst_t_func[KEY_DSA]->to_file_fmt = dst_eay_dss_key_to_file_format;
+       return (1);
+}
+
+/*
+ * dst_eay_dss_sign
+ *     Call EAY DSS 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.
+ *     algobj      structure holds context for a sign done in multiple calls.
+ *     context   the context to use for this computation
+ *     data    data to be signed.
+ *     len      length in bytes of data.
+ *     priv_key    key to use for signing.
+ *     signature   location to store signature.
+ *     sig_len     size in bytes of signature field.
+ * returns 
+ *     N  Success on SIG_MODE_FINAL = returns signature length in bytes
+ *         N is 41 for DNS
+ *     0  Success on SIG_MODE_INIT  and UPDATE
+ *      <0  Failure
+ */
+
+static int
+dst_eay_dss_sign(const int mode, DST_KEY *dkey, void **context,
+                const u_char *data, const int len, 
+                u_char *signature, const int sig_len)
+{
+       int sign_len = 0;
+       int status;
+       SHA_CTX *ctx = NULL;
+
+       if (mode & SIG_MODE_INIT) 
+               ctx = (SHA_CTX *) malloc(sizeof(SHA_CTX));
+       else if (context)
+               ctx = (SHA_CTX *) *context;
+       if (ctx == NULL)
+               return (-1);
+
+       if (mode & SIG_MODE_INIT)
+               SHA1_Init(ctx);
+
+       if ((mode & SIG_MODE_UPDATE) && (data && len > 0)) {
+               SHA1_Update(ctx, (u_char *) data, len);
+       }
+       if (mode & SIG_MODE_FINAL) {
+               DSA *key;
+               u_char digest[SHA_DIGEST_LENGTH];
+               u_char rand[SHA_DIGEST_LENGTH];
+               u_char r[SHA_DIGEST_LENGTH], s[SHA_DIGEST_LENGTH];
+
+               if (dkey == NULL || dkey->dk_KEY_struct == NULL)
+                       return (-1);
+               key = dkey->dk_KEY_struct;
+               if (key == NULL)
+                       return(-2);
+               SHA1_Final(digest, ctx);
+               status = DSA_sign(0, digest, SHA_DIGEST_LENGTH,
+                                 signature, &sign_len, key);
+               if (status != 0)
+                       return (SIGN_FINAL_FAILURE);
+
+               *signature = (dkey->dk_key_size - 512)/64;
+               sign_len = 1;
+               memcpy(signature + sign_len, r, SHA_DIGEST_LENGTH);
+               sign_len += SHA_DIGEST_LENGTH;
+               memcpy(signature + sign_len, s, SHA_DIGEST_LENGTH);
+               sign_len += SHA_DIGEST_LENGTH;
+       }
+       else {
+               if (context == NULL) 
+                       return (-1);
+               *context = (void *) ctx;
+       }
+       return (sign_len);
+}
+
+
+/*
+ * dst_eay_dss_verify 
+ *     Calls EAY DSS 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      structure holds context for a verify done in multiple calls.
+ *     context   algorithm specific context for the current context processing
+ *     data    data signed.
+ *     len      length in bytes of data.
+ *     pub_key     key to use for verify.
+ *     signature   signature.
+ *     sig_len     length in bytes of signature.
+ * returns 
+ *     0  Success 
+ *    <0  Failure
+ */
+
+static int
+dst_eay_dss_verify(const int mode, DST_KEY *dkey, void **context,
+                  const u_char *data, const int len,
+                  const u_char *signature, const int sig_len)
+{
+       int status;
+       SHA_CTX *ctx = NULL;
+
+       if (mode & SIG_MODE_INIT) 
+               ctx = (SHA_CTX *) malloc(sizeof(SHA_CTX));
+       else if (context)
+               ctx = (SHA_CTX *) *context;
+       if (ctx == NULL)
+               return (-1);
+
+       if (mode & SIG_MODE_INIT)
+               SHA1_Init(ctx);
+
+       if ((mode & SIG_MODE_UPDATE) && (data && len > 0)) {
+               SHA1_Update(ctx, (u_char *) data, len);
+       }
+       if (mode & SIG_MODE_FINAL) {
+               DSA *key;
+               u_char digest[SHA_DIGEST_LENGTH];
+               u_char r[SHA_DIGEST_LENGTH], s[SHA_DIGEST_LENGTH];
+
+               if (dkey == NULL || dkey->dk_KEY_struct == NULL)
+                       return (-1);
+               key = (DSA *) dkey->dk_KEY_struct;
+               if (key = NULL)
+                       return (-2);
+               if (signature == NULL || sig_len != (2 * SHA_DIGEST_LENGTH +1))
+                       return (SIGN_FINAL_FAILURE);
+               SHA1_Final(digest, ctx);
+               SAFE_FREE(ctx);
+               if (status != 0)
+                       return (SIGN_FINAL_FAILURE);
+               if (((int)*signature) != ((BN_num_bytes(key->p) -64)/8))
+                       return(VERIFY_FINAL_FAILURE);
+
+               memcpy(r, signature +1, SHA_DIGEST_LENGTH);
+               memcpy(s, signature + SHA_DIGEST_LENGTH +1, SHA_DIGEST_LENGTH);
+               status = DSA_verify(0, digest, SHA_DIGEST_LENGTH,
+                                   (u_char *)signature, sig_len, key);
+               if (status != 0)
+                       return (VERIFY_FINAL_FAILURE);
+       }
+       else {
+               if (context == NULL) 
+                       return (-1);
+               *context = (void *) ctx;
+       }
+       return (0);
+}
+
+
+/*
+ * dst_eay_dss_to_dns_key
+ *     Converts key from DSA to DNS distribution format
+ *     This function gets in a pointer to the public key and a work area
+ *     to write the key into.
+ * Parameters
+ *     public    KEY structure 
+ *     out_str   buffer to write encoded key into 
+ *     out_len   size of out_str
+ * Return
+ *     N >= 0 length of encoded key 
+ *     n < 0  error 
+ */
+
+static int
+dst_eay_dss_to_dns_key(const DST_KEY *in_key, u_char *out_str,
+                      const int out_len)
+{
+       u_char *op = out_str;
+       int t;
+       DSA *key;
+
+       if (in_key == NULL || in_key->dk_KEY_struct == NULL ||
+           out_len <= 0 || out_str == NULL)
+               return (-1);
+       key = (DSA *) in_key->dk_KEY_struct;
+
+       t = (BN_num_bytes(key->p) - 64) / 8;
+
+       *op++ = t;
+       BN_bn2bin(key->q, op);
+       op += BN_num_bytes(key->q);
+       BN_bn2bin(key->p, op);
+       op += BN_num_bytes(key->p);
+       BN_bn2bin(key->g, op);
+       op += BN_num_bytes(key->g);
+       BN_bn2bin(key->pub_key, op);
+       op += BN_num_bytes(key->pub_key);
+
+       return (op - out_str);
+}
+
+
+/*
+ * dst_eay_dss_from_dns_key
+ *     Converts from a DNS KEY RR format to an RSA KEY. 
+ * Parameters
+ *     len    Length in bytes of DNS key
+ *     key    DNS key
+ *     name   Key name
+ *     s_key  DST structure that will point to the RSA key this routine
+ *             will build.
+ * Return
+ *     0   The input key, s_key or name was null.
+ *     1   Success
+ */
+static int
+dst_eay_dss_from_dns_key(DST_KEY *s_key, const u_char *key, const int len)
+{
+       int t;
+       u_char *key_ptr = (u_char *)key;
+       DSA *d_key;
+       int p_bytes;
+
+       if (s_key == NULL || len < 0 || key == NULL)
+               return (0);
+
+       if (len == 0)  /* process null key */
+               return (1);
+
+       if (key_ptr == NULL)  
+               return (0);
+       t = (int) *key_ptr++;   /* length of exponent in bytes */
+       p_bytes = 64 + 8 * t;
+
+       if ((3 * (t * 8 + 64) + SHA_DIGEST_LENGTH + 1) != len)
+               return (0);
+
+       if ((d_key = (DSA *) malloc(sizeof(DSA))) == NULL) {
+               EREPORT(("dst_eay_dss_from_dns_key(): Memory allocation error 1"));
+               return (0);
+       }
+       memset(d_key, 0, sizeof(DSA));
+       s_key->dk_KEY_struct = (void *) d_key;
+
+       d_key->q = BN_bin2bn(key_ptr, SHA_DIGEST_LENGTH, NULL);
+       key_ptr += SHA_DIGEST_LENGTH;
+
+       d_key->p = BN_bin2bn(key_ptr, p_bytes, NULL);
+       key_ptr += p_bytes;
+
+       d_key->g = BN_bin2bn(key_ptr, p_bytes, NULL);
+       key_ptr += p_bytes;
+
+       d_key->pub_key = BN_bin2bn(key_ptr, p_bytes, NULL);
+       key_ptr += p_bytes;
+
+       s_key->dk_id = dst_s_id_calc(key, len); 
+       s_key->dk_key_size = p_bytes * 8;
+       return (1);
+}
+
+
+/************************************************************************** 
+ *  dst_eay_dss_key_to_file_format
+ *     Encodes an DSA Key into the portable file format.
+ *  Parameters 
+ *     key      DSA KEY structure 
+ *     buff      output buffer
+ *     buff_len  size of output buffer 
+ *  Return
+ *     0  Failure - null input rkey
+ *     -1  Failure - not enough space in output area
+ *     N  Success - Length of data returned in buff
+ */
+
+static int
+dst_eay_dss_key_to_file_format(const DST_KEY *key, u_char *buff,
+                              const int buff_len)
+{
+       u_char *bp;
+       int len, b_len;
+       DSA *dkey;
+       char num[256]; /* More than long enough for DSA keys */
+
+       if (key == NULL || key->dk_KEY_struct == NULL)  /* no output */
+               return (0);
+       if (buff == NULL || buff_len <= (int) strlen(key_file_fmt_str))
+               return (-1);    /* no OR not enough space in output area */
+
+       dkey = (DSA *) key->dk_KEY_struct;
+
+       memset(buff, 0, buff_len);      /* just in case */
+       /* write file header */
+       sprintf(buff, key_file_fmt_str, KEY_FILE_FORMAT, KEY_DSA, "DSA");
+
+       bp = (char *) strchr(buff, '\0');
+       b_len = buff_len - (bp - buff);
+       memcpy(num, dkey->p, BN_num_bytes(dkey->p));
+       if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Prime(p): ", num,
+                                              BN_num_bytes(dkey->p))) <= 0)
+               return (-1);
+
+       bp = (char *) strchr(buff, '\0');
+       b_len = buff_len - (bp - buff);
+       memcpy(num, dkey->q, BN_num_bytes(dkey->q));
+       if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Subprime(q): ", num,
+                                              BN_num_bytes(dkey->q))) <= 0)
+               return (-2);
+
+       bp = (char *) strchr(buff, '\0');
+       b_len = buff_len - (bp - buff);
+       memcpy(num, dkey->g, BN_num_bytes(dkey->g));
+       if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Base(g): ", num,
+                                              BN_num_bytes(dkey->g))) <= 0)
+               return (-3);
+
+       bp = (char *) strchr(buff, '\0');
+       b_len = buff_len - (bp - buff);
+       memcpy(num, dkey->priv_key, BN_num_bytes(dkey->priv_key));
+       if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Private_value(x): ",
+                                              num,
+                                              BN_num_bytes(dkey->priv_key)))
+           <= 0)
+               return (-4);
+
+       bp = (char *) strchr(buff, '\0');
+       b_len = buff_len - (bp - buff);
+       memcpy(num, dkey->pub_key, BN_num_bytes(dkey->pub_key));
+       if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Public_value(y): ",
+                                              num,
+                                              BN_num_bytes(dkey->pub_key)))
+           <= 0)
+               return (-5);
+
+       bp += len;
+       b_len -= len;
+       return (buff_len - b_len);
+}
+
+
+/************************************************************************** 
+ * dst_eay_dss_key_from_file_format
+ *     Converts contents of a private key file into a private DSA key. 
+ * Parameters 
+ *     d_key    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_eay_dss_key_from_file_format(DST_KEY *d_key, const u_char *buff,
+                               const int buff_len)
+{
+       char s[128];
+       char dns[1024];
+       int len, s_len = sizeof(s);
+       int foot = -1, dnslen;
+       const char *p = buff;
+       DSA *dsa_key;
+
+       if (d_key == NULL || buff == NULL || buff_len <= 0)
+               return (-1);
+
+       dsa_key = (DSA *) malloc(sizeof(DSA));
+       if (dsa_key == NULL) {
+               return (-2);
+       }
+       memset(dsa_key, 0, sizeof(*dsa_key));
+       d_key->dk_KEY_struct = (void *) dsa_key;
+
+       if (!dst_s_verify_str(&p, "Prime(p): "))
+               return (-3);
+       memset(s, 0, s_len);
+       if ((len = dst_s_conv_bignum_b64_to_u8(&p, s, s_len)) == 0)
+               return (-4);
+       dsa_key->p = BN_bin2bn (s, len, NULL);
+       if (dsa_key->p == NULL)
+               return(-5);
+
+       while (*++p && p < (const char *) &buff[buff_len]) {
+               if (dst_s_verify_str(&p, "Subprime(q): ")) {
+                       if (!(len = dst_s_conv_bignum_b64_to_u8(&p, s, s_len)))
+                               return (-6);
+                       dsa_key->q = BN_bin2bn (s, len, NULL);
+                       if (dsa_key->q == NULL)
+                               return (-7);    
+               } else if (dst_s_verify_str(&p, "Base(g): ")) {
+                       if (!(len = dst_s_conv_bignum_b64_to_u8(&p, s, s_len)))
+                               return (-8);
+                       dsa_key->g = BN_bin2bn (s, len, NULL);
+                       if (dsa_key->g == NULL)
+                               return (-9);    
+               } else if (dst_s_verify_str(&p, "Private_value(x): ")) {
+                       if (!(len = dst_s_conv_bignum_b64_to_u8(&p, s, s_len)))
+                               return (-10);
+                       dsa_key->priv_key = BN_bin2bn (s, len, NULL);
+                       if (dsa_key->priv_key == NULL)
+                               return (-11);   
+               } else if (dst_s_verify_str(&p, "Public_value(y): ")) {
+                       if (!(len = dst_s_conv_bignum_b64_to_u8(&p, s, s_len)))
+                               return (-12);
+                       dsa_key->pub_key = BN_bin2bn (s, len, NULL);
+                       if (dsa_key->pub_key == NULL)
+                               return (-13);   
+               } else {
+                       EREPORT(("Decode_DSAKey(): Bad keyword %s\n", p));
+                       return (-14);
+               }
+       }                       /* while p */
+
+       d_key->dk_key_size = BN_num_bytes(dsa_key->p);
+       dnslen = d_key->dk_func->to_dns_key(d_key, dns, sizeof(dns));
+       foot = dst_s_id_calc(dns, dnslen);
+
+       return (foot);
+}
+
+
+/************************************************************************** 
+ * dst_eay_dss_free_key_structure
+ *     Frees all dynamicly allocated structures in DSA.
+ */
+
+static void *
+dst_eay_dss_free_key_structure(void *key)
+{
+       DSA *d_key = (DSA *) key;
+       if (d_key != NULL) {
+               BN_free(d_key->p);
+               BN_free(d_key->q);
+               BN_free(d_key->g);
+               if (d_key->pub_key)
+                       BN_free(d_key->pub_key);
+               if (d_key->priv_key)
+                       BN_free(d_key->priv_key);
+               SAFE_FREE(d_key);
+       }
+       return (NULL);
+}
+
+
+/************************************************************************** 
+ *  dst_eay_dss_generate_keypair
+ *     Generates unique keys that are hard to predict.
+ *  Parameters
+ *     key    generic Key structure
+ *     exp    the public exponent
+ *  Return 
+ *     0 Failure 
+ *     1 Success
+ */
+
+static int
+dst_eay_dss_generate_keypair(DST_KEY *key, int nothing)
+{
+       int status, dnslen, n;
+       DSA *dsa;
+       u_char rand[SHA_DIGEST_LENGTH];
+       char dns[1024];
+
+       if (key == NULL || key->dk_alg != KEY_DSA)
+               return (0);
+
+       if ((dsa = (DSA *) malloc(sizeof(DSA))) == NULL) {
+               EREPORT(("dst_eay_dss_generate_keypair: Memory allocation error 3"));
+               return (0);
+       }
+       memset(dsa, 0, sizeof(*dsa));
+
+       n = dst_random(DST_RAND_KEY, sizeof(rand), rand);
+       if (n != sizeof(rand))
+               return (0);
+       dsa = DSA_generate_parameters(key->dk_key_size, rand, 20, NULL, NULL,
+                                     NULL, NULL);
+
+       if (!dsa) {
+               EREPORT(("dst_eay_dss_generate_keypair: Generate Parameters failed"));
+               return (0);
+       }
+       if (DSA_generate_key(dsa) == 0) {
+               EREPORT(("dst_eay_dss_generate_keypair: Generate Key failed"));
+               return(0);
+       }
+       key->dk_KEY_struct = (void *) dsa;
+       dnslen = key->dk_func->to_dns_key(key, dns, sizeof(dns));
+       key->dk_id = dst_s_id_calc(dns, dnslen);
+       return (1);
+}
+
+
+/*
+ *  dst_eay_dss_compare_keys
+ *     Compare two keys for equality.
+ *  Return
+ *     0         The keys are equal
+ *     NON-ZERO   The keys are not equal
+ */
+
+static int
+dst_eay_dss_compare_keys(const DST_KEY *key1, const DST_KEY *key2)
+{
+       int status;
+       DSA *dkey1 = (DSA *) key1->dk_KEY_struct;
+       DSA *dkey2 = (DSA *) key2->dk_KEY_struct;
+
+       if (dkey1 == NULL && dkey2 == NULL)
+               return (0);
+       else if (dkey1 == NULL) 
+               return (2);
+       else if (dkey2 == NULL)
+               return(1);
+
+       status = BN_cmp(dkey1->p, dkey2->p) ||
+                BN_cmp(dkey1->q, dkey2->q) ||
+                BN_cmp(dkey1->g, dkey2->g) ||
+                BN_cmp(dkey1->pub_key, dkey2->pub_key);
+       
+       if (status)
+               return (status);
+
+       if (dkey1->priv_key || dkey2->priv_key) {
+               if (dkey1->priv_key == NULL || dkey2->priv_key == NULL)
+                       return (202);
+               return (BN_cmp(dkey1->priv_key, dkey2->priv_key));
+       } else
+               return (0);
+}
+#else 
+#include "port_before.h"
+
+#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 "dst_internal.h"
+#include "port_after.h"
+int
+dst_eay_dss_init(void) 
+{
+       return (0);
+}
+#endif /* EAY_DSS */
diff --git a/lib/bind/dst/hmac_link.c b/lib/bind/dst/hmac_link.c
new file mode 100644 (file)
index 0000000..dee97e6
--- /dev/null
@@ -0,0 +1,495 @@
+#ifdef HMAC_MD5
+#ifndef LINT
+static const char rcsid[] = "$Header: /u0/home/explorer/proj/ISC/git-conversion/cvsroot/bind9/lib/bind/dst/Attic/hmac_link.c,v 1.1 2001/03/29 06:31:31 marka 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 "port_before.h"
+
+#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 <arpa/nameser.h>
+#include <resolv.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
+
+#include "port_after.h"
+
+
+#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 int len, 
+                 u_char *signature, const int 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, 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 int len,
+               const u_char *signature, const int 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, 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 int keylen)
+{
+       int i;
+       HMAC_Key *hkey = NULL;
+       MD5_CTX ctx;
+       int 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, 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 int buff_len)
+{
+       char *bp;
+       int len, b_len, i, 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 int 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;
+       int key_len, len;
+
+       if (dkey == NULL)
+               return (-2);
+       if (buff == NULL || buff_len < 0)
+               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 int 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 i, n, size;
+
+       i = nothing;
+
+       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);
+       
+       i = size > 64 ? 64 : size;
+       buff = malloc(i+8);
+
+       n = dst_random(DST_RAND_SEMI, i, buff);
+       n += dst_random(DST_RAND_KEY, i, buff);
+       if (n <= i) {   /* failed getting anything */
+               SAFE_FREE2(buff, i);
+               return (-1);
+       }
+       n = dst_buffer_to_hmac_md5(key, buff, i);
+       SAFE_FREE2(buff, i);
+       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/lib/bind/dst/md5.h b/lib/bind/dst/md5.h
new file mode 100644 (file)
index 0000000..c886d17
--- /dev/null
@@ -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/lib/bind/dst/md5_dgst.c b/lib/bind/dst/md5_dgst.c
new file mode 100644 (file)
index 0000000..9bb0228
--- /dev/null
@@ -0,0 +1,368 @@
+/* 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>
+#ifdef USE_MD5 /* Added by ogud@tis.com 1998/1/26 */
+#include "md5_locl.h"
+
+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;
+register const 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/lib/bind/dst/md5_locl.h b/lib/bind/dst/md5_locl.h
new file mode 100644 (file)
index 0000000..b2f0028
--- /dev/null
@@ -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/lib/bind/dst/prandom.c b/lib/bind/dst/prandom.c
new file mode 100644 (file)
index 0000000..0c13c0c
--- /dev/null
@@ -0,0 +1,855 @@
+#ifndef LINT
+static const char rcsid[] = "$Header: /u0/home/explorer/proj/ISC/git-conversion/cvsroot/bind9/lib/bind/dst/Attic/prandom.c,v 1.1 2001/03/29 06:31:33 marka 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 "port_before.h"
+
+#include <assert.h>
+#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 "dst_internal.h"
+#include "prand_conf.h"
+
+#include "port_after.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 {
+       int 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, int 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,
+                  int size);
+static int my_digest(dst_work *tmp, const u_char *input, int size);
+static prand_hash *get_hmac_key(int step, int block);
+
+static int 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, int 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, dir_len, tb_i = 0, out = 0;
+
+       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 < (time_t)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))) {
+               int 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, n))
+                       break;
+               /* this adds some randomness to the output */
+               cnt += do_time(work);
+       }
+       while ((n = fread(buffer, sizeof(char), sizeof(buffer), pipe)) > 0)
+               (void)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 < (time_t)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, 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, 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, int size)
+{
+       const u_char *tmp = input;
+       u_char *save = NULL, *tp;
+       int i, cnt = size, n, needed, avail, dig, 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;
+               tmp = tp = save = malloc(tmp_size);
+               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 (tmp_size > 0) 
+                               SAFE_FREE2(save, tmp_size);
+                       return (1);
+               }
+       }
+       if (tmp_size > 0)
+               SAFE_FREE2(save, 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, int 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, 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 int
+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, int size)
+{
+       int n = 0, s, i;
+       static u_char old_unused[DST_HASH_SIZE * DST_NUM_HASHES];
+       static int 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) {
+               int 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, int 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, hb_size = 0;
+       static DST_KEY *my_key = NULL;
+       prand_hash *hash;
+       int out = 0, i, 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));
+#ifdef REPORT_ERRORS
+               if (i != hb_size)
+                       EREPORT(("HMAC SIGNATURE FAILURE %d\n", i));
+#endif
+               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/lib/bind/dst/rsaref_link.c b/lib/bind/dst/rsaref_link.c
new file mode 100644 (file)
index 0000000..a552104
--- /dev/null
@@ -0,0 +1,767 @@
+#ifdef RSAREF
+static const char rcsid[] = "$Header: /u0/home/explorer/proj/ISC/git-conversion/cvsroot/bind9/lib/bind/dst/Attic/rsaref_link.c,v 1.1 2001/03/29 06:31:33 marka 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.
+ */
+
+/*
+ * This file contains two components
+ * 1. Interface to the rsaref library to allow compilation when RSAREF is
+ *    not available all calls to RSAREF are contained inside this file.
+ * 2. The glue to connvert RSA{REF} KEYS to and from external formats
+ */
+#include "port_before.h"
+
+#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 "dst_internal.h"
+
+# ifdef __STDC__
+#   define PROTOTYPES 1
+# else
+#   define PROTOTYPES 0
+# endif
+
+# include <global.h>
+# include <rsaref.h>
+
+#include "port_after.h"
+
+
+typedef struct rsakey {
+       char *rk_signer;
+       R_RSA_PRIVATE_KEY *rk_Private_Key;
+       R_RSA_PUBLIC_KEY *rk_Public_Key;
+} RSA_Key;
+
+
+static int dst_rsaref_sign(const int mode, DST_KEY *key, void **context,
+                          const u_char *data, const int len,
+                          u_char *signature, const int sig_len);
+static int dst_rsaref_verify(const int mode, DST_KEY *key, void **context,
+                            const u_char *data, const int len,
+                            const u_char *signature, const int sig_len);
+
+static int dst_rsaref_to_dns_key(const DST_KEY *public, u_char *out_str,
+                                const int out_len);
+static int dst_rsaref_from_dns_key(DST_KEY *s_key, const u_char *key,
+                                  const int len);
+
+static int dst_rsaref_key_to_file_format(const DST_KEY *dkey,
+                                        u_char *buff,
+                                        const int buff_len);
+static int dst_rsaref_key_from_file_format(DST_KEY *dkey,
+                                          const u_char *buff,
+                                          const int buff_len);
+
+static int dst_rsaref_compare_keys(const DST_KEY *rkey1,
+                                  const DST_KEY *rkey2);
+static void *dst_rsaref_free_key_structure(void *d_key);
+
+static int dst_rsaref_generate_keypair(DST_KEY *key, const int exp);
+
+static void dst_rsaref_init_random_struct(R_RANDOM_STRUCT * randomstruct);
+
+/*
+ * dst_rsaref_init()  Function to answer set up function pointers for RSAREF
+ *          related functions 
+ */
+int
+dst_rsaref_init()
+{
+       if (dst_t_func[KEY_RSA] != NULL)
+               return (1);
+       dst_t_func[KEY_RSA] = malloc(sizeof(struct dst_func));
+       if (dst_t_func[KEY_RSA] == NULL)
+               return (0);
+       memset(dst_t_func[KEY_RSA], 0, sizeof(struct dst_func));
+       dst_t_func[KEY_RSA]->sign = dst_rsaref_sign;
+       dst_t_func[KEY_RSA]->verify = dst_rsaref_verify;
+       dst_t_func[KEY_RSA]->compare = dst_rsaref_compare_keys;
+       dst_t_func[KEY_RSA]->generate = dst_rsaref_generate_keypair;
+       dst_t_func[KEY_RSA]->destroy = dst_rsaref_free_key_structure;
+       dst_t_func[KEY_RSA]->to_dns_key = dst_rsaref_to_dns_key;
+       dst_t_func[KEY_RSA]->from_dns_key = dst_rsaref_from_dns_key;
+       dst_t_func[KEY_RSA]->to_file_fmt = dst_rsaref_key_to_file_format;
+       dst_t_func[KEY_RSA]->from_file_fmt = dst_rsaref_key_from_file_format;
+       return (1);
+}
+
+/*
+ * dst_rsa_sign
+ *     Call RSAREF 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.
+ *     key        pointer to a RSA key structure that points to public key
+ *                and context to use.
+ *     data       data to be signed.
+ *     len        length in bytes of data.
+ *     signature   location to store signature.
+ *     sig_len    size of the signature storage area
+ * 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_rsaref_sign(const int mode, DST_KEY *dkey, void **context,
+               const u_char *data, const int len,
+               u_char *signature, const int sig_len)
+{
+       int sign_len = 0;
+       R_SIGNATURE_CTX *ctx = NULL;
+
+       if (mode & SIG_MODE_INIT)
+               ctx = malloc(sizeof(*ctx));
+       else if (context) 
+               ctx = (R_SIGNATURE_CTX *) *context;
+       if (ctx == NULL) 
+               return (-1);
+
+       if ((mode & SIG_MODE_INIT) && R_SignInit(ctx, DA_MD5))
+               return (SIGN_INIT_FAILURE);
+
+       /* equivalent of SIG_MODE_UPDATE */
+       if ((mode & SIG_MODE_UPDATE) && (data && len > 0) &&
+           R_SignUpdate(ctx, (u_char *) data, len))
+               return (SIGN_UPDATE_FAILURE);
+
+       if (mode & SIG_MODE_FINAL) {
+               RSA_Key *key = (RSA_Key *) dkey->dk_KEY_struct;
+               if (signature == NULL ||
+                   sig_len < (int)(key->rk_Public_Key->bits + 7) / 8)
+                       return (SIGN_FINAL_FAILURE);
+               if(key == NULL || key->rk_Private_Key == NULL)
+                       return (-1);
+               if (R_SignFinal(ctx, signature, &sign_len,
+                               key->rk_Private_Key))
+                       return (SIGN_FINAL_FAILURE);
+               SAFE_FREE(ctx);
+       }
+       else {
+               if (context == NULL) 
+                       return (-1);
+               *context = (void *) ctx;
+       }
+       return (sign_len);
+}
+
+
+/*
+ * dst_rsaref_verify()
+ *     Calls RSAREF 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.
+ *     key        pointer to a RSA key structure that points to public key
+ *                and context to use.
+ *     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_rsaref_verify(const int mode, DST_KEY *dkey, void **context,
+                 const u_char *data,   const int len, 
+                 const u_char *signature, const int sig_len)
+{
+       R_SIGNATURE_CTX *ctx = NULL;
+
+       if (mode & SIG_MODE_INIT)
+               ctx = malloc(sizeof(*ctx));
+       else if (context) 
+               ctx = (R_SIGNATURE_CTX *) *context;
+       if (ctx == NULL) 
+               return (-1);
+
+       if ((mode & SIG_MODE_INIT) && R_VerifyInit(ctx, DA_MD5))
+               return (VERIFY_INIT_FAILURE);
+
+       if ((mode & SIG_MODE_UPDATE) && (data && len > 0) &&
+           R_VerifyUpdate(ctx, (u_char *) data, len))
+               return (VERIFY_UPDATE_FAILURE);
+
+       if ((mode & SIG_MODE_FINAL)) {
+               RSA_Key *key = (RSA_Key *) dkey->dk_KEY_struct;
+
+               if (key == NULL || key->rk_Public_Key == NULL)
+                       return (-1);
+               if (signature == NULL || sig_len <= 0)
+                       return (VERIFY_FINAL_FAILURE);
+               if (R_VerifyFinal(ctx, (u_char *) signature, sig_len, 
+                                 key->rk_Public_Key))
+                       return (VERIFY_FINAL_FAILURE);
+       }
+       else {
+               if (context == NULL) 
+                       return (-1);
+               *context = (void *) ctx;
+       }
+
+       return (0);
+}
+
+
+/*
+ * dst_rsaref_to_dns_key
+ *     Converts key in RSAREF to DNS distribution format
+ *     This function gets in a pointer to the public key and a work area
+ *     to write the key into.
+ * Parameters
+ *     public   KEY structure
+ *     out_str  buffer to write encoded key into
+ *     out_len  size of out_str
+ * Return
+ *     N >= 0 length of encoded key
+ *     n < 0  error
+ */
+
+static int
+dst_rsaref_to_dns_key(const DST_KEY *in_key, u_char *out_str,
+                     const int out_len)
+{
+       int n, loc;
+       R_RSA_PUBLIC_KEY *public;
+       u_char *op = (u_char *) out_str;
+
+       if (in_key == NULL || in_key->dk_KEY_struct == NULL ||
+           out_len <= 0 || out_str == NULL)
+               return (-1);
+       public = (R_RSA_PUBLIC_KEY *)
+               ((RSA_Key *) in_key->dk_KEY_struct)->rk_Public_Key;
+       if (public == NULL)
+               return (-1);
+
+       memset(op, 0, out_len);
+
+       /* find first non zero */
+       for (n = 0; public->exponent[n] == 0x0; n++) ;  
+
+       n = (MAX_RSA_MODULUS_LEN - n);  /* find lenght of exponent */
+       *op++ = (u_int8_t) n;
+
+       if (n > (out_len - (op-out_str)))
+               return (-1);
+       memcpy(op, &public->exponent[MAX_RSA_MODULUS_LEN - n], n);
+       op += n;
+       n++;                    /* include the lenght field in this count */
+
+       /* find first non zero */
+       for (loc = 0; public->modulus[loc] == 0x0; loc++) ;
+
+       /*copy exponent */
+       if ((MAX_RSA_MODULUS_LEN - loc) > (out_len - (op-out_str)))
+               return (-1);
+       memcpy(op, &public->modulus[loc], MAX_RSA_MODULUS_LEN - loc);
+       n += (MAX_RSA_MODULUS_LEN - loc);
+       return (n);
+}
+
+
+/*
+ * dst_rsaref_from_dns_key
+ *     Converts from a DNS KEY RR format to an RSA KEY.
+ * Parameters
+ *     len    Length in bytes of DNS key
+ *     key    DNS key
+ *     name   Key name
+ *     s_key  DST structure that will point to the RSA key this routine
+ *               will build.
+ * Return
+ *    -1   The input key has fields that are larger than this package supports
+ *     0   The input key, s_key or name was null.
+ *     1   Success
+ */
+static int
+dst_rsaref_from_dns_key(DST_KEY *s_key, const u_char *key, const int len)
+{
+       int bytes;
+       u_char *key_ptr;
+       RSA_Key *r_key;
+
+       if (key == NULL || s_key == NULL || len < 0)
+               return (0);
+
+       if (s_key->dk_KEY_struct) {     /* do not reuse */
+               dst_rsaref_free_key_structure(s_key->dk_KEY_struct);
+               s_key->dk_KEY_struct = NULL;
+       }
+       if (len == 0)           /* null key no conversion needed */
+               return (1);
+
+       if ((r_key = (RSA_Key *) malloc(sizeof(RSA_Key))) == NULL) {
+               EREPORT(("dst_rsaref_from_dns_key(): Memory allocation error 1\n"));
+               return (0);
+       }
+       memset(r_key, 0, sizeof(RSA_Key));
+       s_key->dk_KEY_struct = (void *) r_key;
+       r_key->rk_signer = strdup(s_key->dk_key_name);
+       r_key->rk_Public_Key = (R_RSA_PUBLIC_KEY *)
+               malloc(sizeof(R_RSA_PUBLIC_KEY));
+       if (r_key->rk_Public_Key == NULL) {
+               EREPORT(("dst_rsaref_from_dns_key(): Memory allocation error 3\n"));
+               return (0);
+       }
+       memset(r_key->rk_Public_Key, 0, sizeof(R_RSA_PUBLIC_KEY));
+       key_ptr = (u_char *) key;
+       bytes = (int) *key_ptr++;       /* length of exponent in bytes */
+       if (bytes == 0) {               /* special case for long exponents */
+               bytes = (int) dst_s_get_int16(key_ptr);
+               key_ptr += sizeof(u_int16_t);
+       }
+       if (bytes > MAX_RSA_MODULUS_LEN) { 
+               dst_rsaref_free_key_structure(r_key);
+               return (-1);
+       }
+       memcpy(&r_key->rk_Public_Key->exponent[MAX_RSA_MODULUS_LEN - bytes],
+              key_ptr, bytes);
+
+       key_ptr += bytes;       /* beginning of modulus */
+       bytes = len - bytes - 1;        /* length of modulus */
+       if (bytes > MAX_RSA_MODULUS_LEN) { 
+               dst_rsaref_free_key_structure(r_key);
+               return (-1);
+       }
+       memcpy(&r_key->rk_Public_Key->modulus[MAX_RSA_MODULUS_LEN - bytes],
+              key_ptr, bytes);
+       r_key->rk_Public_Key->bits = bytes * 8;
+       s_key->dk_id = (u_int16_t) dst_s_get_int16((u_char *)
+                  &r_key->rk_Public_Key->modulus[MAX_RSA_MODULUS_LEN - 3]);
+       s_key->dk_key_size = r_key->rk_Public_Key->bits;
+
+       return (1);
+}
+
+
+/*
+ *  dst_rsaref_key_to_file_format
+ *     Encodes an RSA Key into the portable file format.
+ *  Parameters
+ *     rkey      RSA KEY structure
+ *     buff      output buffer
+ *     buff_len  size of output buffer
+ *  Return
+ *     0  Failure - null input rkey
+ *     -1  Failure - not enough space in output area
+ *     N  Success - Length of data returned in buff
+ */
+
+static int
+dst_rsaref_key_to_file_format(const DST_KEY *in_key, u_char *buff,
+                             const int buff_len)
+{
+       u_char *bp;
+       int len, b_len;
+       R_RSA_PRIVATE_KEY *rkey;
+
+       if (in_key == NULL || in_key->dk_KEY_struct == NULL)
+               return (-1);
+       rkey = (R_RSA_PRIVATE_KEY *)
+               ((RSA_Key *) in_key->dk_KEY_struct)->rk_Private_Key;
+       if (rkey == NULL)       /* no output */
+               return (0);
+       if (buff == NULL || buff_len <= (int) strlen(key_file_fmt_str))
+               return (-1);    /* no OR not enough space in output area */
+
+           memset(buff, 0, buff_len);  /* just in case */
+       /* write file header */
+       sprintf(buff, key_file_fmt_str, KEY_FILE_FORMAT, KEY_RSA, "RSA");
+
+       bp = (char *) strchr(buff, '\0');
+       b_len = buff_len - (bp - buff);
+       if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Modulus: ",
+                                              rkey->modulus,
+                                              MAX_RSA_MODULUS_LEN)) <= 0)
+               return (-1);
+
+       bp += len;
+       b_len -= len;
+       if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "PublicExponent: ",
+                                              rkey->publicExponent,
+                                              MAX_RSA_MODULUS_LEN)) <= 0)
+               return (-2);
+       bp += len;
+       b_len -= len;
+       if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "PrivateExponent: ",
+                                              rkey->exponent,
+                                              MAX_RSA_MODULUS_LEN)) <= 0)
+               return (-3);
+       bp += len;
+       b_len -= len;
+       if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Prime1: ",
+                                              rkey->prime[0],
+                                              MAX_RSA_PRIME_LEN)) < 0)
+               return (-4);
+       bp += len;
+       b_len -= len;
+       if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Prime2: ",
+                                              rkey->prime[1],
+                                              MAX_RSA_PRIME_LEN)) < 0)
+               return (-5);
+       bp += len;
+       b_len -= len;
+       if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Exponent1: ",
+                                              rkey->primeExponent[0],
+                                              MAX_RSA_PRIME_LEN)) < 0)
+               return (-6);
+       bp += len;
+       b_len -= len;
+       if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Exponent2: ",
+                                              rkey->primeExponent[1],
+                                              MAX_RSA_PRIME_LEN)) < 0)
+               return (-7);
+       bp += len;
+       b_len -= len;
+       if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Coefficient: ",
+                                              rkey->coefficient,
+                                              MAX_RSA_PRIME_LEN)) < 0)
+               return (-8);
+       bp += len;
+       b_len -= len;
+       return (buff_len - b_len);
+}
+
+
+/*
+ * dst_rsaref_key_from_file_format
+ *     Converts contents of a private key file into a private RSA key.
+ * Parameters
+ *     r_key     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_rsaref_key_from_file_format(DST_KEY *d_key, const u_char *buff,
+                               const int buff_len)
+{
+       const char *p = (char *) buff;
+       R_RSA_PRIVATE_KEY key;
+       int foot = -1;
+       RSA_Key *r_key;
+
+       if (d_key == NULL || buff == NULL || buff_len < 0)
+               return (-1);
+
+       memset(&key, 0, sizeof(key));
+
+       if (!dst_s_verify_str(&p, "Modulus: "))
+               return (-3);
+
+       if (!dst_s_conv_bignum_b64_to_u8(&p, key.modulus, MAX_RSA_MODULUS_LEN))
+               return (-4);
+
+       key.bits = dst_s_calculate_bits(key.modulus, MAX_RSA_MODULUS_BITS);
+
+       while (*++p && p < (char *) &buff[buff_len]) {
+               if (dst_s_verify_str(&p, "PublicExponent: ")) {
+                       if (!dst_s_conv_bignum_b64_to_u8(&p,
+                                                        key.publicExponent,
+                                                      MAX_RSA_MODULUS_LEN))
+                               return (-5);
+               } else if (dst_s_verify_str(&p, "PrivateExponent: ")) {
+                       if (!dst_s_conv_bignum_b64_to_u8(&p, key.exponent,
+                                                      MAX_RSA_MODULUS_LEN))
+                               return (-6);
+               } else if (dst_s_verify_str(&p, "Prime1: ")) {
+                       if (!dst_s_conv_bignum_b64_to_u8(&p, key.prime[0],
+                                                        MAX_RSA_PRIME_LEN))
+                               return (-7);
+               } else if (dst_s_verify_str(&p, "Prime2: ")) {
+                       if (!dst_s_conv_bignum_b64_to_u8(&p, key.prime[1],
+                                                        MAX_RSA_PRIME_LEN))
+                               return (-8);
+               } else if (dst_s_verify_str(&p, "Exponent1: ")) {
+                       if (!dst_s_conv_bignum_b64_to_u8(&p,
+                                                      key.primeExponent[0],
+                                                        MAX_RSA_PRIME_LEN))
+                               return (-9);
+               } else if (dst_s_verify_str(&p, "Exponent2: ")) {
+                       if (!dst_s_conv_bignum_b64_to_u8(&p,
+                                                      key.primeExponent[1],
+                                                        MAX_RSA_PRIME_LEN))
+                               return (-10);
+               } else if (dst_s_verify_str(&p, "Coefficient: ")) {
+                       if (!dst_s_conv_bignum_b64_to_u8(&p, key.coefficient,
+                                                        MAX_RSA_PRIME_LEN))
+                               return (-11);
+               } else {
+                       EREPORT(("dst_rsaref_key_from_file_format: Bad keyword %s\n", p));
+                       return (-12);
+               }
+       }                       /* while p */
+
+       r_key = (RSA_Key *) malloc(sizeof(RSA_Key));
+       if (r_key == NULL) {
+               return (-2);
+       }
+       memset(r_key, 0, sizeof(*r_key));
+
+       r_key->rk_Private_Key =
+               (R_RSA_PRIVATE_KEY *) malloc(sizeof(R_RSA_PRIVATE_KEY));
+       if (r_key->rk_Private_Key == NULL) {
+               EREPORT(("dst_rsaref_key_from_file_format: Memory allocation error\n"));
+               return (-13);
+       }
+       r_key->rk_Public_Key = (R_RSA_PUBLIC_KEY *) r_key->rk_Private_Key;
+       memcpy(r_key->rk_Private_Key, &key, sizeof(R_RSA_PRIVATE_KEY));
+
+       r_key->rk_signer = strdup(d_key->dk_key_name);
+       d_key->dk_KEY_struct = (void *) r_key;
+       d_key->dk_key_size = r_key->rk_Private_Key->bits;
+       d_key->dk_id = (u_int16_t) dst_s_get_int16((u_char *)
+                  &r_key->rk_Public_Key->modulus[MAX_RSA_MODULUS_LEN - 3]);
+       foot = (int) d_key->dk_id;
+       return (foot);
+}
+
+
+
+/*
+ *  dst_rsaref_compare_keys
+ *     Compare two keys for equality.
+ *  Return
+ *     0          The keys are equal
+ *     NON-ZERO   The keys are not equal
+ */
+
+static int
+dst_rsaref_compare_keys(const DST_KEY *dkey1, const DST_KEY *dkey2)
+{
+       RSA_Key *rkey1 = (RSA_Key *) dkey1->dk_KEY_struct;
+       RSA_Key *rkey2 = (RSA_Key *) dkey2->dk_KEY_struct;
+       
+       if (rkey1 == NULL && rkey2 == NULL)
+               return (0); /* same */
+       else if (rkey1 == NULL)
+               return (1);
+       else if (rkey2 == NULL)
+               return (2);
+       return (memcmp(rkey1->rk_Public_Key, rkey2->rk_Public_Key,
+                      sizeof(R_RSA_PUBLIC_KEY)));
+}
+
+/*
+ *  dst_rsaref_generate_keypair
+ *     Generates unique keys that are hard to predict.
+ *  Parameters
+ *     key    generic Key structure
+ *     exp    the public exponent
+ *  Return
+ *     0 Failure
+ *     1 Success
+ */
+
+static int
+dst_rsaref_generate_keypair(DST_KEY *key, const int exp)
+{
+       R_RSA_PUBLIC_KEY *public;
+       R_RSA_PRIVATE_KEY *private;
+       R_RSA_PROTO_KEY proto;
+       R_RANDOM_STRUCT randomStruct;
+       RSA_Key *rsa;
+       int status;
+
+       if (key == NULL || key->dk_alg != KEY_RSA)
+               return (0);
+       if (key->dk_key_size < MIN_RSA_MODULUS_BITS ||
+           key->dk_key_size > MAX_RSA_MODULUS_BITS) {
+               EREPORT(("dst_rsaref_generate_keypair: Invalid key size\n"));
+               return (0);     /* these are the limits on key size in RSAREF */
+       }
+       /* allocate space */
+       if ((public = (R_RSA_PUBLIC_KEY *) malloc(sizeof(R_RSA_PUBLIC_KEY)))
+           == NULL) {
+               EREPORT(("dst_rsaref_generate_keypair: Memory allocation error 1\n"));
+               return (0);
+       }
+       if ((private = (R_RSA_PRIVATE_KEY *) malloc(sizeof(R_RSA_PRIVATE_KEY)))
+           == NULL) {
+               EREPORT(("dst_rsaref_generate_keypair: Memory allocation error 2\n"));
+               return (0);
+       }
+       if ((rsa = (RSA_Key *) malloc(sizeof(RSA_Key))) == NULL) {
+               EREPORT(("dst_rsaref_generate_keypair: Memory allocation error 3\n"));
+               return (0);
+       }
+       memset(public, 0, sizeof(*public));
+       memset(private, 0, sizeof(*private));
+
+       proto.bits = key->dk_key_size;
+       proto.useFermat4 = exp ? 0x1 : 0x0;     /* 1 for f4=65537, 0 for f0=3 */
+       EREPORT(("\ndst_rsaref_generate_keypair: Generating KEY for %s Please wait\n",
+                key->dk_key_name));
+
+       /* set up random seed */
+       dst_rsaref_init_random_struct(&randomStruct);
+
+       /* generate keys */
+       status = R_GeneratePEMKeys(public, private, &proto, &randomStruct);
+       if (status) {
+               EREPORT(("dst_rsaref_generate_keypair: No Key Pair generated %d\n",
+                        status));
+               SAFE_FREE(public);
+               SAFE_FREE(private);
+               SAFE_FREE(rsa);
+               return (0);
+       }
+       memset(rsa, 0, sizeof(*rsa));
+       rsa->rk_signer = key->dk_key_name;
+       rsa->rk_Private_Key = private;
+       rsa->rk_Public_Key = public;
+       key->dk_KEY_struct = (void *) rsa;
+
+       key->dk_id = (u_int16_t) dst_s_get_int16((u_char *)
+                    &rsa->rk_Public_Key->modulus[MAX_RSA_MODULUS_LEN - 3]);
+       return (1);
+}
+
+
+/*
+ * dst_rsaref_free_key_structure
+ *     Frees all dynamicly allocated structures in r_key
+ */
+
+static void *
+dst_rsaref_free_key_structure(void *v_key)
+{
+       RSA_Key *r_key = (RSA_Key *) v_key;
+
+       if (r_key != NULL) {
+               if ((void *) r_key->rk_Private_Key == (void *) r_key->rk_Public_Key)
+                       r_key->rk_Public_Key = NULL;
+               SAFE_FREE(r_key->rk_Private_Key);
+               SAFE_FREE(r_key->rk_Public_Key);
+               SAFE_FREE(r_key->rk_signer);
+               SAFE_FREE(r_key);
+       }
+       return (NULL);
+}
+
+
+/*
+ * dst_rsaref_init_random_struct
+ *     A random seed value is used in key generation.
+ *     This routine gets a bunch of system values to randomize the
+ *     randomstruct.  A number of system calls are used to get somewhat
+ *     unpredicable values, then a special function dst_s_prandom() is called
+ *     that will do some magic depending on the system used.
+ *     If this function is executed on reasonably busy machine then the values
+ *     that prandom uses are hard to
+ *      1. Predict
+ *      2. Regenerate
+ *      3. Hard to spy on as nothing is stored to disk and data is consumed
+ *         as fast as it is generated.
+ */
+
+static void
+dst_rsaref_init_random_struct(R_RANDOM_STRUCT * randomstruct)
+{
+       unsigned bytesNeeded;
+       struct timeval tv;
+       u_char *array;
+       int n;
+
+       R_RandomInit(randomstruct);
+
+       /* The runtime of the script is unpredictable within some range
+        * thus I'm getting the time of day again as this is an hard to guess
+        * value and the number of characters of the output from the script is
+        * hard to guess.
+        * This must be the FIRST CALL
+        */
+       gettimeofday(&tv, 0);
+       R_RandomUpdate(randomstruct, (u_char *) &tv,
+                      sizeof(struct timeval));
+
+       /*
+        * first find out how many bytes I need
+        */
+       R_GetRandomBytesNeeded(&bytesNeeded, randomstruct);
+
+       /*
+        * get a storage area for it  addjust the area for the possible
+        * side effects of digest functions writing out in blocks
+        */
+       array = (u_char *) malloc(bytesNeeded);
+
+       /* extract the random data from /dev/random if present, generate
+        *   it if not present 
+        * first fill the buffer with semi random data 
+        *  then fill as much as possible with good random data 
+        */
+       n = dst_random(DST_RAND_SEMI, bytesNeeded, array);
+       n += dst_random(DST_RAND_KEY, bytesNeeded, array);
+       if (n <= bytesNeeded) {
+               SAFE_FREE(array);
+               return(0);
+       }
+
+       /* supply the random data (even if it is larger than requested) */
+       R_RandomUpdate(randomstruct, array, bytesNeeded);
+
+       SAFE_FREE(array);
+
+       R_GetRandomBytesNeeded(&bytesNeeded, randomstruct);
+       if (bytesNeeded) {
+               EREPORT(("InitRandomStruct() didn't initialize enough randomness\n"));
+               exit(33);
+       }
+}
+
+
+#else 
+#include "port_before.h"
+
+#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 "dst_internal.h"
+#include "port_after.h"
+int /* rsaref is not available */
+dst_rsaref_init()
+{
+       return (0);
+}
+#endif /* RSAREF */
diff --git a/lib/bind/dst/support.c b/lib/bind/dst/support.c
new file mode 100644 (file)
index 0000000..d4db777
--- /dev/null
@@ -0,0 +1,463 @@
+static const char rcsid[] = "$Header: /u0/home/explorer/proj/ISC/git-conversion/cvsroot/bind9/lib/bind/dst/Attic/support.c,v 1.1 2001/03/29 06:31:33 marka 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 "port_before.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <memory.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include "dst_internal.h"
+
+#include "port_after.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 int out_len,
+                           const char *header, const u_char *bin_data,
+                           const int bin_len)
+{
+       const u_char *bp = bin_data;
+       char *op = out_buf;
+       int lenh = 0, len64 = 0;
+       int local_in_len = bin_len;
+       int local_out_len = out_len;
+
+       if (bin_data == NULL || bin_len <= 0)   /* 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)
+{
+       int 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 int loclen)
+{
+       int 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 int keysize)
+{
+       u_int32_t ac;
+       const u_char *kp = key;
+       int size = keysize;
+
+       if (!key || (keysize <= 0))
+               return (-1);
+       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 int rdata_len)
+{
+       int 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, u_int16_t id,
+                    int alg, const char *suffix, size_t filename_length)
+{
+       u_int32_t 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, int perm)
+{
+       FILE *fp;
+       char pathname[PATH_MAX];
+       size_t 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);
+}
+
+void
+dst_s_dump(const int mode, const u_char *data, const int size, 
+           const char *msg)
+{
+       UNUSED(data);
+
+       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
+       }
+}
diff --git a/lib/bind/include/Makefile.in b/lib/bind/include/Makefile.in
new file mode 100644 (file)
index 0000000..f3a030a
--- /dev/null
@@ -0,0 +1,2 @@
+all:
+@BIND9_MAKE_RULES@
diff --git a/lib/bind/include/arpa/inet.h b/lib/bind/include/arpa/inet.h
new file mode 100644 (file)
index 0000000..1a238aa
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * ++Copyright++ 1983, 1993
+ * -
+ * Copyright (c) 1983, 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.
+ * -
+ * --Copyright--
+ */
+
+/*
+ *     @(#)inet.h      8.1 (Berkeley) 6/2/93
+ *     $Id: inet.h,v 1.1 2001/03/29 06:31:34 marka Exp $
+ */
+
+#ifndef _INET_H_
+#define        _INET_H_
+
+/* External definitions for functions in inet(3) */
+
+#include <sys/param.h>
+#if (!defined(BSD)) || (BSD < 199306)
+# include <sys/bitypes.h>
+#else
+# include <sys/types.h>
+#endif
+#include <sys/cdefs.h>
+
+#define        inet_addr               __inet_addr
+#define        inet_aton               __inet_aton
+#define        inet_lnaof              __inet_lnaof
+#define        inet_makeaddr           __inet_makeaddr
+#define        inet_neta               __inet_neta
+#define        inet_netof              __inet_netof
+#define        inet_network            __inet_network
+#define        inet_net_ntop           __inet_net_ntop
+#define        inet_net_pton           __inet_net_pton
+#define        inet_cidr_ntop          __inet_cidr_ntop
+#define        inet_cidr_pton          __inet_cidr_pton
+#define        inet_ntoa               __inet_ntoa
+#define        inet_pton               __inet_pton
+#define        inet_ntop               __inet_ntop
+#define        inet_nsap_addr          __inet_nsap_addr
+#define        inet_nsap_ntoa          __inet_nsap_ntoa
+
+__BEGIN_DECLS
+unsigned long   inet_addr __P((const char *));
+int             inet_aton __P((const char *, struct in_addr *));
+unsigned long   inet_lnaof __P((struct in_addr));
+struct in_addr  inet_makeaddr __P((u_long , u_long));
+char *          inet_neta __P((u_long, char *, size_t));
+unsigned long   inet_netof __P((struct in_addr));
+unsigned long   inet_network __P((const char *));
+char           *inet_net_ntop __P((int, const void *, int, char *, size_t));
+int             inet_net_pton __P((int, const char *, void *, size_t));
+char           *inet_cidr_ntop __P((int, const void *, int, char *, size_t));
+int             inet_cidr_pton __P((int, const char *, void *, int *));
+/*const*/ char *inet_ntoa __P((struct in_addr));
+int             inet_pton __P((int, const char *, void *));
+const char     *inet_ntop __P((int, const void *, char *, size_t));
+u_int           inet_nsap_addr __P((const char *, u_char *, int));
+char           *inet_nsap_ntoa __P((int, const u_char *, char *));
+__END_DECLS
+
+#endif /* !_INET_H_ */
diff --git a/lib/bind/include/arpa/nameser.h b/lib/bind/include/arpa/nameser.h
new file mode 100644 (file)
index 0000000..9934a28
--- /dev/null
@@ -0,0 +1,559 @@
+/*
+ * Copyright (c) 1983, 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.
+ */
+
+/*
+ * 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.
+ */
+
+/*
+ *     $Id: nameser.h,v 1.1 2001/03/29 06:31:35 marka Exp $
+ */
+
+#ifndef _ARPA_NAMESER_H_
+#define _ARPA_NAMESER_H_
+
+#define BIND_4_COMPAT
+
+#include <sys/param.h>
+#if (!defined(BSD)) || (BSD < 199306)
+# include <sys/bitypes.h>
+#else
+# include <sys/types.h>
+#endif
+#include <sys/cdefs.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_char    *_msg, *_eom;
+       u_int16_t       _id, _flags, _counts[ns_s_max];
+       const u_char    *_sections[ns_s_max];
+       ns_sect         _sect;
+       int             _rrnum;
+       const u_char    *_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_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_char *  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;
+        int 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];
+       int 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_tkey = 249,        /* Transaction key */
+       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 const u_char *t_cp = (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 const u_char *t_cp = (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_char *t_cp = (u_char *)(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_char *t_cp = (u_char *)(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)
+
+/*
+ * ANSI C identifier hiding for bind's lib/nameser.
+ */
+#define        ns_msg_getflag          __ns_msg_getflag
+#define ns_get16               __ns_get16
+#define ns_get32               __ns_get32
+#define ns_put16               __ns_put16
+#define ns_put32               __ns_put32
+#define ns_initparse           __ns_initparse
+#define ns_skiprr              __ns_skiprr
+#define ns_parserr             __ns_parserr
+#define        ns_sprintrr             __ns_sprintrr
+#define        ns_sprintrrf            __ns_sprintrrf
+#define        ns_format_ttl           __ns_format_ttl
+#define        ns_parse_ttl            __ns_parse_ttl
+#define ns_datetosecs          __ns_datetosecs
+#define        ns_name_ntol            __ns_name_ntol
+#define        ns_name_ntop            __ns_name_ntop
+#define        ns_name_pton            __ns_name_pton
+#define        ns_name_unpack          __ns_name_unpack
+#define        ns_name_pack            __ns_name_pack
+#define        ns_name_compress        __ns_name_compress
+#define        ns_name_uncompress      __ns_name_uncompress
+#define        ns_name_skip            __ns_name_skip
+#define        ns_name_rollback        __ns_name_rollback
+#define        ns_sign                 __ns_sign
+#define        ns_sign_tcp             __ns_sign_tcp
+#define        ns_sign_tcp_init        __ns_sign_tcp_init
+#define ns_find_tsig           __ns_find_tsig
+#define        ns_verify               __ns_verify
+#define        ns_verify_tcp           __ns_verify_tcp
+#define        ns_verify_tcp_init      __ns_verify_tcp_init
+#define        ns_samedomain           __ns_samedomain
+#define        ns_subdomain            __ns_subdomain
+#define        ns_makecanon            __ns_makecanon
+#define        ns_samename             __ns_samename
+
+__BEGIN_DECLS
+int            ns_msg_getflag __P((ns_msg, int));
+u_int          ns_get16 __P((const u_char *));
+u_long         ns_get32 __P((const u_char *));
+void           ns_put16 __P((u_int, u_char *));
+void           ns_put32 __P((u_long, u_char *));
+int            ns_initparse __P((const u_char *, int, ns_msg *));
+int            ns_skiprr __P((const u_char *, const u_char *, ns_sect, int));
+int            ns_parserr __P((ns_msg *, ns_sect, int, ns_rr *));
+int            ns_sprintrr __P((const ns_msg *, const ns_rr *,
+                                const char *, const char *, char *, size_t));
+int            ns_sprintrrf __P((const u_char *, size_t, const char *,
+                                 ns_class, ns_type, u_long, const u_char *,
+                                 size_t, const char *, const char *,
+                                 char *, size_t));
+int            ns_format_ttl __P((u_long, char *, size_t));
+int            ns_parse_ttl __P((const char *, u_long *));
+u_int32_t      ns_datetosecs __P((const char *cp, int *errp));
+int            ns_name_ntol __P((const u_char *, u_char *, size_t));
+int            ns_name_ntop __P((const u_char *, char *, size_t));
+int            ns_name_pton __P((const char *, u_char *, size_t));
+int            ns_name_unpack __P((const u_char *, const u_char *,
+                                   const u_char *, u_char *, size_t));
+int            ns_name_pack __P((const u_char *, u_char *, int,
+                                 const u_char **, const u_char **));
+int            ns_name_uncompress __P((const u_char *, const u_char *,
+                                       const u_char *, char *, size_t));
+int            ns_name_compress __P((const char *, u_char *, size_t,
+                                     const u_char **, const u_char **));
+int            ns_name_skip __P((const u_char **, const u_char *));
+void           ns_name_rollback __P((const u_char *, const u_char **,
+                                     const u_char **));
+int            ns_sign __P((u_char *, int *, int, int, void *,
+                            const u_char *, int, u_char *, int *, time_t));
+int            ns_sign_tcp __P((u_char *, int *, int, int,
+                                ns_tcp_tsig_state *, int));
+int            ns_sign_tcp_init __P((void *, const u_char *, int,
+                                       ns_tcp_tsig_state *));
+u_char         *ns_find_tsig __P((u_char *, u_char *));
+int            ns_verify __P((u_char *, int *, void *,
+                              const u_char *, int, u_char *, int *,
+                              time_t *, int));
+int            ns_verify_tcp __P((u_char *, int *, ns_tcp_tsig_state *, int));
+int            ns_verify_tcp_init __P((void *, const u_char *, int,
+                                       ns_tcp_tsig_state *));
+int            ns_samedomain __P((const char *, const char *));
+int            ns_subdomain __P((const char *, const char *));
+int            ns_makecanon __P((const char *, char *, size_t));
+int            ns_samename __P((const char *, const char *));
+__END_DECLS
+
+#ifdef BIND_4_COMPAT
+#include <arpa/nameser_compat.h>
+#endif
+
+#endif /* !_ARPA_NAMESER_H_ */
diff --git a/lib/bind/include/arpa/nameser_compat.h b/lib/bind/include/arpa/nameser_compat.h
new file mode 100644 (file)
index 0000000..335d75b
--- /dev/null
@@ -0,0 +1,230 @@
+/* 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.1 2001/03/29 06:31:35 marka Exp $
+ */
+
+#ifndef _ARPA_NAMESER_COMPAT_
+#define        _ARPA_NAMESER_COMPAT_
+
+#define        __BIND          19950621        /* (DEAD) interface version stamp. */
+
+#ifndef BYTE_ORDER
+#if (BSD >= 199103)
+# include <machine/endian.h>
+#else
+#ifdef linux
+# include <endian.h>
+#else
+#define        LITTLE_ENDIAN   1234    /* least-significant byte first (vax, pc) */
+#define        BIG_ENDIAN      4321    /* most-significant byte first (IBM, net) */
+#define        PDP_ENDIAN      3412    /* LSB first in word, MSW first in long (pdp)*/
+
+#if defined(vax) || defined(ns32000) || defined(sun386) || defined(i386) || \
+    defined(MIPSEL) || defined(_MIPSEL) || defined(BIT_ZERO_ON_RIGHT) || \
+    defined(__alpha__) || defined(__alpha) || \
+    (defined(__Lynx__) && defined(__x86__))
+#define BYTE_ORDER     LITTLE_ENDIAN
+#endif
+
+#if defined(sel) || defined(pyr) || defined(mc68000) || defined(sparc) || \
+    defined(is68k) || defined(tahoe) || defined(ibm032) || defined(ibm370) || \
+    defined(MIPSEB) || defined(_MIPSEB) || defined(_IBMR2) || defined(DGUX) ||\
+    defined(apollo) || defined(__convex__) || defined(_CRAY) || \
+    defined(__hppa) || defined(__hp9000) || \
+    defined(__hp9000s300) || defined(__hp9000s700) || \
+    defined (BIT_ZERO_ON_LEFT) || defined(m68k) || \
+    (defined(__Lynx__) && \
+     (defined(__68k__) || defined(__sparc__) || defined(__powerpc__)))
+#define BYTE_ORDER     BIG_ENDIAN
+#endif
+#endif /* linux */
+#endif /* BSD */
+#endif /* BYTE_ORDER */
+
+#if !defined(BYTE_ORDER) || \
+    (BYTE_ORDER != BIG_ENDIAN && BYTE_ORDER != LITTLE_ENDIAN && \
+    BYTE_ORDER != PDP_ENDIAN)
+       /* you must determine what the correct bit order is for
+        * your compiler - the next line is an intentional error
+        * which will force your compiles to bomb until you fix
+        * the above macros.
+        */
+  error "Undefined or invalid BYTE_ORDER";
+#endif
+
+/*
+ * 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_A6           ns_t_a6
+#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/lib/bind/include/fd_setsize.h b/lib/bind/include/fd_setsize.h
new file mode 100644 (file)
index 0000000..235b1ad
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef _FD_SETSIZE_H
+#define _FD_SETSIZE_H
+
+/*
+ * If you need a bigger FD_SETSIZE, this is NOT the place to set it.
+ * This file is a fallback for BIND ports which don't specify their own.
+ */
+
+#endif /* _FD_SETSIZE_H */
diff --git a/lib/bind/include/hesiod.h b/lib/bind/include/hesiod.h
new file mode 100644 (file)
index 0000000..b49f5e3
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file is primarily maintained by <tytso@mit.edu> and <ghudson@mit.edu>.
+ */
+
+/*
+ * $Id: hesiod.h,v 1.1 2001/03/29 06:31:33 marka Exp $
+ */
+
+#ifndef _HESIOD_H_INCLUDED
+#define _HESIOD_H_INCLUDED
+
+int            hesiod_init __P((void **context));
+void           hesiod_end __P((void *context));
+char *         hesiod_to_bind __P((void *context, const char *name,
+                                   const char *type));
+char **                hesiod_resolve __P((void *context, const char *name,
+                                   const char *type));
+void           hesiod_free_list __P((void *context, char **list));
+struct __res_state * __hesiod_res_get __P((void *context));
+void           __hesiod_res_set __P((void *context, struct __res_state *,
+                                     void (*)(void *)));
+
+#endif /*_HESIOD_H_INCLUDED*/
diff --git a/lib/bind/include/irp.h b/lib/bind/include/irp.h
new file mode 100644 (file)
index 0000000..e56cfbc
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+/*
+ * $Id: irp.h,v 1.1 2001/03/29 06:31:34 marka Exp $
+ */
+
+#ifndef _IRP_H_INCLUDED
+#define _IRP_H_INCLUDED
+
+#define IRPD_TIMEOUT 30                        /* seconds */
+#define IRPD_MAXSESS 50                        /* number of simultaneous sessions. */
+#define IRPD_PORT 6660                 /* 10 times the number of the beast. */
+#define IRPD_PATH "/var/run/irpd"      /* af_unix socket path */
+
+/* If sets the environment variable IRPDSERVER to an IP address
+   (e.g. "192.5.5.1"), then that's the host the client expects irpd to be
+   running on. */
+#define IRPD_HOST_ENV "IRPDSERVER"
+
+/* Protocol response codes.  */
+#define IRPD_WELCOME_CODE 200
+#define IRPD_NOT_WELCOME_CODE 500
+
+#define IRPD_GETHOST_ERROR 510
+#define IRPD_GETHOST_NONE 210
+#define IRPD_GETHOST_OK 211
+#define IRPD_GETHOST_SETOK 212
+
+#define IRPD_GETNET_ERROR 520
+#define IRPD_GETNET_NONE 220
+#define IRPD_GETNET_OK 221
+#define IRPD_GETNET_SETOK 222
+
+#define IRPD_GETUSER_ERROR 530
+#define IRPD_GETUSER_NONE 230
+#define IRPD_GETUSER_OK 231
+#define IRPD_GETUSER_SETOK 232
+
+#define IRPD_GETGROUP_ERROR 540
+#define IRPD_GETGROUP_NONE 240
+#define IRPD_GETGROUP_OK 241
+#define IRPD_GETGROUP_SETOK 242
+
+#define IRPD_GETSERVICE_ERROR 550
+#define IRPD_GETSERVICE_NONE 250
+#define IRPD_GETSERVICE_OK 251
+#define IRPD_GETSERVICE_SETOK 252
+
+#define IRPD_GETPROTO_ERROR 560
+#define IRPD_GETPROTO_NONE 260
+#define IRPD_GETPROTO_OK 261
+#define IRPD_GETPROTO_SETOK 262
+
+#define IRPD_GETNETGR_ERROR 570
+#define IRPD_GETNETGR_NONE 270
+#define IRPD_GETNETGR_OK 271
+#define IRPD_GETNETGR_NOMORE 272
+#define IRPD_GETNETGR_MATCHES 273
+#define IRPD_GETNETGR_NOMATCH 274
+#define IRPD_GETNETGR_SETOK 275
+#define IRPD_GETNETGR_SETERR 276
+
+#define        irs_irp_read_body __irs_irp_read_body
+#define irs_irp_read_response __irs_irp_read_response
+#define irs_irp_disconnect __irs_irp_disconnect
+#define irs_irp_connect __irs_irp_connect
+#define irs_irp_connection_setup __irs_irp_connection_setup
+#define irs_irp_send_command __irs_irp_send_command
+
+struct irp_p;
+
+char   *irs_irp_read_body(struct irp_p *pvt, size_t *size);
+int    irs_irp_read_response(struct irp_p *pvt, char *text, size_t len);
+void   irs_irp_disconnect(struct irp_p *pvt);
+int    irs_irp_connect(struct irp_p *pvt);
+int    irs_irp_is_connected(struct irp_p *pvt);
+int    irs_irp_connection_setup(struct irp_p *cxndata, int *warned);
+int    irs_irp_send_command(struct irp_p *pvt, const char *fmt, ...);
+int    irs_irp_get_full_response(struct irp_p *pvt, int *code, char *text,
+                                 size_t textlen, char **body,
+                                 size_t *bodylen);
+int    irs_irp_read_line(struct irp_p *pvt, char *buffer, int len);
+
+#endif
diff --git a/lib/bind/include/irs.h b/lib/bind/include/irs.h
new file mode 100644 (file)
index 0000000..8680469
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+ * 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.
+ */
+
+/*
+ * $Id: irs.h,v 1.1 2001/03/29 06:31:34 marka Exp $
+ */
+
+#ifndef _IRS_H_INCLUDED
+#define _IRS_H_INCLUDED
+
+#include <sys/types.h>
+
+#include <arpa/nameser.h>
+
+#include <grp.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <pwd.h>
+#include <netgroup.h>
+
+/*
+ * This is the group map class.
+ */
+struct irs_gr {
+       void *          private;
+       void            (*close) __P((struct irs_gr *));
+       struct group *  (*next) __P((struct irs_gr *));
+       struct group *  (*byname) __P((struct irs_gr *, const char *));
+       struct group *  (*bygid) __P((struct irs_gr *, gid_t));
+       int             (*list) __P((struct irs_gr *, const char *,
+                                    gid_t, gid_t *, int *));
+       void            (*rewind) __P((struct irs_gr *));
+       void            (*minimize) __P((struct irs_gr *));
+       struct __res_state * (*res_get) __P((struct irs_gr *));
+       void            (*res_set) __P((struct irs_gr *, res_state,
+                                       void (*)(void *)));
+};
+
+/*
+ * This is the password map class.
+ */
+struct irs_pw {
+       void *          private;
+       void            (*close) __P((struct irs_pw *));
+       struct passwd * (*next) __P((struct irs_pw *));
+       struct passwd * (*byname) __P((struct irs_pw *, const char *));
+       struct passwd * (*byuid) __P((struct irs_pw *, uid_t));
+       void            (*rewind) __P((struct irs_pw *));
+       void            (*minimize) __P((struct irs_pw *));
+       struct __res_state * (*res_get) __P((struct irs_pw *));
+       void            (*res_set) __P((struct irs_pw *, res_state,
+                                       void (*)(void *)));
+};
+
+/*
+ * This is the service map class.
+ */
+struct irs_sv {
+       void *          private;
+       void            (*close) __P((struct irs_sv *));
+       struct servent *(*byname) __P((struct irs_sv *,
+                                      const char *, const char *));
+       struct servent *(*byport) __P((struct irs_sv *, int, const char *));
+       struct servent *(*next) __P((struct irs_sv *));
+       void            (*rewind) __P((struct irs_sv *));
+       void            (*minimize) __P((struct irs_sv *));
+       struct __res_state * (*res_get) __P((struct irs_sv *));
+       void            (*res_set) __P((struct irs_sv *, res_state,
+                                       void (*)(void *)));
+};
+
+/*
+ * This is the protocols map class.
+ */
+struct irs_pr {
+       void *          private;
+       void            (*close) __P((struct irs_pr *));
+       struct protoent *(*byname) __P((struct irs_pr *, const char *));
+       struct protoent *(*bynumber) __P((struct irs_pr *, int));
+       struct protoent *(*next) __P((struct irs_pr *));
+       void            (*rewind) __P((struct irs_pr *));
+       void            (*minimize) __P((struct irs_pr *));
+       struct __res_state * (*res_get) __P((struct irs_pr *));
+       void            (*res_set) __P((struct irs_pr *, res_state,
+                                       void (*)(void *)));
+};
+
+/*
+ * This is the hosts map class.
+ */
+struct irs_ho {
+       void *          private;
+       void            (*close) __P((struct irs_ho *));
+       struct hostent *(*byname) __P((struct irs_ho *, const char *));
+       struct hostent *(*byname2) __P((struct irs_ho *, const char *, int));
+       struct hostent *(*byaddr) __P((struct irs_ho *,
+                                      const void *, int, int));
+       struct hostent *(*next) __P((struct irs_ho *));
+       void            (*rewind) __P((struct irs_ho *));
+       void            (*minimize) __P((struct irs_ho *));
+       struct __res_state * (*res_get) __P((struct irs_ho *));
+       void            (*res_set) __P((struct irs_ho *, res_state,
+                                       void (*)(void *)));
+       struct addrinfo *(*addrinfo) __P((struct irs_ho *, const char *,
+                                         const struct addrinfo *));
+};
+
+/*
+ * This is the networks map class.
+ */
+struct irs_nw {
+       void *          private;
+       void            (*close) __P((struct irs_nw *));
+       struct nwent *  (*byname) __P((struct irs_nw *, const char *, int));
+       struct nwent *  (*byaddr) __P((struct irs_nw *, void *, int, int));
+       struct nwent *  (*next) __P((struct irs_nw *));
+       void            (*rewind) __P((struct irs_nw *));
+       void            (*minimize) __P((struct irs_nw *));
+       struct __res_state * (*res_get) __P((struct irs_nw *));
+       void            (*res_set) __P((struct irs_nw *, res_state,
+                                       void (*)(void *)));
+};
+
+/*
+ * This is the netgroups map class.
+ */
+struct irs_ng {
+       void *          private;
+       void            (*close) __P((struct irs_ng *));
+       int             (*next) __P((struct irs_ng *, const char **,
+                                    const char **, const char **));
+       int             (*test) __P((struct irs_ng *, const char *,
+                                    const char *, const char *,
+                                    const char *));
+       void            (*rewind) __P((struct irs_ng *, const char *));
+       void            (*minimize) __P((struct irs_ng *));
+};
+
+/*
+ * This is the generic map class, which copies the front of all others.
+ */
+struct irs_map {
+       void *          private;
+       void            (*close) __P((void *));
+};
+
+/*
+ * This is the accessor class.  It contains pointers to all of the
+ * initializers for the map classes for a particular accessor.
+ */
+struct irs_acc {
+       void *          private;
+       void            (*close) __P((struct irs_acc *));
+       struct irs_gr * (*gr_map) __P((struct irs_acc *));
+       struct irs_pw * (*pw_map) __P((struct irs_acc *));
+       struct irs_sv * (*sv_map) __P((struct irs_acc *));
+       struct irs_pr * (*pr_map) __P((struct irs_acc *));
+       struct irs_ho * (*ho_map) __P((struct irs_acc *));
+       struct irs_nw * (*nw_map) __P((struct irs_acc *));
+       struct irs_ng * (*ng_map) __P((struct irs_acc *));
+       struct __res_state * (*res_get) __P((struct irs_acc *));
+       void            (*res_set) __P((struct irs_acc *, res_state,
+                                       void (*)(void *)));
+};
+
+/*
+ * This is because the official definition of "struct netent" has no
+ * concept of CIDR even though it allows variant address families (on
+ * output but not input).  The compatibility stubs convert the structs
+ * below into "struct netent"'s.
+ */
+struct nwent {
+       char            *n_name;        /* official name of net */
+       char            **n_aliases;    /* alias list */
+       int             n_addrtype;     /* net address type */
+       void            *n_addr;        /* network address */
+       int             n_length;       /* address length, in bits */
+};
+
+/*
+ * Hide external function names from POSIX.
+ */
+#define        irs_gen_acc     __irs_gen_acc
+#define        irs_lcl_acc     __irs_lcl_acc
+#define        irs_dns_acc     __irs_dns_acc
+#define        irs_nis_acc     __irs_nis_acc
+#define        irs_irp_acc     __irs_irp_acc
+
+/*
+ * Externs.
+ */
+extern struct irs_acc *        irs_gen_acc __P((const char *options, 
+                                        const char *conf_file));
+extern struct irs_acc *        irs_lcl_acc __P((const char *options));
+extern struct irs_acc *        irs_dns_acc __P((const char *options));
+extern struct irs_acc *        irs_nis_acc __P((const char *options));
+extern struct irs_acc *        irs_irp_acc __P((const char *options));
+
+extern void            irs_destroy(void);
+
+/*
+ * These forward declarations are for the semi-private functions in
+ * the get*.c files. Each of these funcs implements the real get*
+ * functionality and the standard versions are just wrappers that
+ * call these. Apart from the wrappers, only irpd is expected to
+ * call these directly, hence these decls are put here and not in
+ * the /usr/include replacements.
+ */
+
+struct net_data;                       /* forward */
+
+/*
+ * net_data_create gets a singleton net_data object.  net_data_init
+ * creates as many net_data objects as times it is called.  Clients using
+ * the default interface will use net_data_create by default.  Servers will
+ * probably want net_data_init (one call per client)
+ */
+struct net_data *net_data_create(const char *conf_file);
+struct net_data *net_data_init(const char *conf_file);
+void           net_data_destroy(void *p);
+       
+extern struct group    *getgrent_p __P((struct net_data *net_data));
+extern struct group    *getgrnam_p __P((const char *name,
+                                       struct net_data *net_data));
+extern struct group    *getgrgid_p __P((gid_t gid,
+                                       struct net_data *net_data));
+extern int             setgroupent_p __P((int stayopen,
+                                          struct net_data *net_data));
+extern void            endgrent_p __P((struct net_data *net_data));
+extern int             getgrouplist_p __P((const char *name,
+                                           gid_t basegid,
+                                           gid_t *groups,
+                                           int *ngroups,
+                                           struct net_data *net_data));
+
+#ifdef SETGRENT_VOID
+extern void            setgrent_p __P((struct net_data *net_data));
+#else
+extern int             setgrent_p __P((struct net_data *net_data));
+#endif
+
+extern struct hostent  *gethostbyname_p __P((const char *name,
+                                             struct net_data *net_data));
+extern struct hostent  *gethostbyname2_p __P((const char *name, int af,
+                                              struct net_data *net_data));
+extern struct hostent  *gethostbyaddr_p __P((const char *addr, int len,
+                                             int af,
+                                             struct net_data *net_data));
+extern struct hostent  *gethostent_p __P((struct net_data *net_data));
+extern void            sethostent_p __P((int stayopen,
+                                         struct net_data *net_data));
+extern void            endhostent_p __P((struct net_data *net_data));
+extern struct hostent  *getipnodebyname_p __P((const char *name, int af,
+                                              int flags, int *errp,
+                                              struct net_data *net_data));
+extern struct hostent  *getipnodebyaddr_p __P((const void *addr, size_t len,
+                                             int af, int *errp,
+                                             struct net_data *net_data));
+
+extern struct netent   *getnetent_p __P((struct net_data *net_data));
+extern struct netent   *getnetbyname_p __P((const char *name,
+                                            struct net_data *net_data));
+extern struct netent   *getnetbyaddr_p __P((unsigned long net, int type,
+                                            struct net_data *net_data));
+extern void            setnetent_p __P((int stayopen,
+                                        struct net_data *net_data));
+extern void            endnetent_p __P((struct net_data *net_data));
+
+extern void            setnetgrent_p __P((const char *netgroup,
+                                          struct net_data *net_data));
+extern void            endnetgrent_p __P((struct net_data *net_data));
+extern int             innetgr_p __P((const char *netgroup,
+                                      const char *host,
+                                      const char *user,
+                                      const char *domain,
+                                      struct net_data *net_data));
+extern int             getnetgrent_p __P((const char **host, const char **user,
+                                          const char **domain,
+                                          struct net_data *net_data));
+
+extern struct protoent  *getprotoent_p __P((struct net_data *net_data));
+extern struct protoent  *getprotobyname_p __P((const char *name,
+                                              struct net_data *net_data));
+extern struct protoent *getprotobynumber_p __P((int proto,
+                                                struct net_data *net_data));
+extern void            setprotoent_p __P((int stayopen,
+                                          struct net_data *net_data));
+extern void            endprotoent_p __P((struct net_data *net_data));
+
+
+extern struct passwd   *getpwent_p __P((struct net_data *net_data));
+extern struct passwd   *getpwnam_p __P((const char *name,
+                                        struct net_data *net_data));
+extern struct passwd   *getpwuid_p __P((uid_t uid,
+                                        struct net_data *net_data));
+extern int             setpassent_p __P((int stayopen,
+                                         struct net_data *net_data));
+extern void            endpwent_p __P((struct net_data *net_data));
+
+#ifdef SETPWENT_VOID
+extern void            setpwent_p __P((struct net_data *net_data));
+#else
+extern int             setpwent_p __P((struct net_data *net_data));
+#endif
+
+extern struct servent  *getservent_p __P((struct net_data *net_data));
+extern struct servent  *getservbyname_p __P((const char *name,
+                                             const char *proto,
+                                             struct net_data *net_data));
+extern struct servent  *getservbyport_p __P((int port, const char *proto,
+                                             struct net_data *net_data));
+extern void            setservent_p __P((int stayopen,
+                                         struct net_data *net_data));
+extern void            endservent_p __P((struct net_data *net_data));
+
+#endif /*_IRS_H_INCLUDED*/
diff --git a/lib/bind/include/isc/assertions.h b/lib/bind/include/isc/assertions.h
new file mode 100644 (file)
index 0000000..bc436a5
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 1997-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.
+ */
+
+/*
+ * $Id: assertions.h,v 1.1 2001/03/29 06:31:35 marka Exp $
+ */
+
+#ifndef ASSERTIONS_H
+#define ASSERTIONS_H           1
+
+typedef enum {
+       assert_require, assert_ensure, assert_insist, assert_invariant
+} assertion_type;
+
+typedef void (*assertion_failure_callback)(const char *, int, assertion_type,
+                                          const char *, int);
+
+extern assertion_failure_callback __assertion_failed;
+void set_assertion_failure_callback(assertion_failure_callback f);
+const char *assertion_type_to_text(assertion_type type);
+
+#ifdef CHECK_ALL
+#define CHECK_REQUIRE          1
+#define CHECK_ENSURE           1
+#define CHECK_INSIST           1
+#define CHECK_INVARIANT                1
+#endif
+
+#ifdef CHECK_NONE
+#define CHECK_REQUIRE          0
+#define CHECK_ENSURE           0
+#define CHECK_INSIST           0
+#define CHECK_INVARIANT                0
+#endif
+
+#ifndef CHECK_REQUIRE
+#define CHECK_REQUIRE          1
+#endif
+
+#ifndef CHECK_ENSURE
+#define CHECK_ENSURE           1
+#endif
+
+#ifndef CHECK_INSIST
+#define CHECK_INSIST           1
+#endif
+
+#ifndef CHECK_INVARIANT
+#define CHECK_INVARIANT                1
+#endif
+
+#if CHECK_REQUIRE != 0
+#define REQUIRE(cond) \
+       ((void) ((cond) || \
+                ((__assertion_failed)(__FILE__, __LINE__, assert_require, \
+                                      #cond, 0), 0)))
+#define REQUIRE_ERR(cond) \
+       ((void) ((cond) || \
+                ((__assertion_failed)(__FILE__, __LINE__, assert_require, \
+                                      #cond, 1), 0)))
+#else
+#define REQUIRE(cond)          ((void) (cond))
+#define REQUIRE_ERR(cond)      ((void) (cond))
+#endif /* CHECK_REQUIRE */
+
+#if CHECK_ENSURE != 0
+#define ENSURE(cond) \
+       ((void) ((cond) || \
+                ((__assertion_failed)(__FILE__, __LINE__, assert_ensure, \
+                                      #cond, 0), 0)))
+#define ENSURE_ERR(cond) \
+       ((void) ((cond) || \
+                ((__assertion_failed)(__FILE__, __LINE__, assert_ensure, \
+                                      #cond, 1), 0)))
+#else
+#define ENSURE(cond)           ((void) (cond))
+#define ENSURE_ERR(cond)       ((void) (cond))
+#endif /* CHECK_ENSURE */
+
+#if CHECK_INSIST != 0
+#define INSIST(cond) \
+       ((void) ((cond) || \
+                ((__assertion_failed)(__FILE__, __LINE__, assert_insist, \
+                                      #cond, 0), 0)))
+#define INSIST_ERR(cond) \
+       ((void) ((cond) || \
+                ((__assertion_failed)(__FILE__, __LINE__, assert_insist, \
+                                      #cond, 1), 0)))
+#else
+#define INSIST(cond)           ((void) (cond))
+#define INSIST_ERR(cond)       ((void) (cond))
+#endif /* CHECK_INSIST */
+
+#if CHECK_INVARIANT != 0
+#define INVARIANT(cond) \
+       ((void) ((cond) || \
+                ((__assertion_failed)(__FILE__, __LINE__, assert_invariant, \
+                                      #cond, 0), 0)))
+#define INVARIANT_ERR(cond) \
+       ((void) ((cond) || \
+                ((__assertion_failed)(__FILE__, __LINE__, assert_invariant, \
+                                      #cond, 1), 0)))
+#else
+#define INVARIANT(cond)                ((void) (cond))
+#define INVARIANT_ERR(cond)    ((void) (cond))
+#endif /* CHECK_INVARIANT */
+
+#endif /* ASSERTIONS_H */
diff --git a/lib/bind/include/isc/ctl.h b/lib/bind/include/isc/ctl.h
new file mode 100644 (file)
index 0000000..4fe786a
--- /dev/null
@@ -0,0 +1,104 @@
+#ifndef ISC_CTL_H
+#define ISC_CTL_H
+
+/*
+ * Copyright (c) 1998,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.
+ */
+
+/*
+ * $Id: ctl.h,v 1.1 2001/03/29 06:31:35 marka Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <isc/eventlib.h>
+
+/* Macros. */
+
+#define        CTL_MORE        0x0001  /* More will be / should be sent. */
+#define        CTL_EXIT        0x0002  /* Close connection after this. */
+#define        CTL_DATA        0x0004  /* Go into / this is DATA mode. */
+
+/* Types. */
+
+struct ctl_cctx;
+struct ctl_sctx;
+struct ctl_sess;
+struct ctl_verb;
+
+enum ctl_severity { ctl_debug, ctl_warning, ctl_error };
+
+typedef void (*ctl_logfunc)(enum ctl_severity, const char *fmt, ...);
+
+typedef void (*ctl_verbfunc)(struct ctl_sctx *, struct ctl_sess *,
+                            const struct ctl_verb *, const char *rest,
+                            u_int respflags, const void *respctx, void *uctx);
+
+typedef void (*ctl_srvrdone)(struct ctl_sctx *, struct ctl_sess *, void *);
+
+typedef void (*ctl_clntdone)(struct ctl_cctx *, void *, const char *, u_int);
+
+struct ctl_verb {
+       const char *    name;
+       ctl_verbfunc    func;
+       const char *    help;
+};
+
+/* General symbols. */
+
+#define        ctl_logger      __ctl_logger
+
+void                   ctl_logger(enum ctl_severity, const char *, ...);
+
+/* Client symbols. */
+
+#define        ctl_client      __ctl_client
+#define        ctl_endclient   __ctl_endclient
+#define        ctl_command     __ctl_command
+
+struct ctl_cctx *      ctl_client(evContext, const struct sockaddr *, size_t,
+                                  const struct sockaddr *, size_t,
+                                  ctl_clntdone, void *,
+                                  u_int, ctl_logfunc);
+void                   ctl_endclient(struct ctl_cctx *);
+int                    ctl_command(struct ctl_cctx *, const char *, size_t,
+                                   ctl_clntdone, void *);
+
+/* Server symbols. */
+
+#define        ctl_server      __ctl_server
+#define        ctl_endserver   __ctl_endserver
+#define        ctl_response    __ctl_response
+#define        ctl_sendhelp    __ctl_sendhelp
+#define ctl_getcsctx   __ctl_getcsctx
+#define ctl_setcsctx   __ctl_setcsctx
+
+struct ctl_sctx *      ctl_server(evContext, const struct sockaddr *, size_t,
+                                  const struct ctl_verb *,
+                                  u_int, u_int,
+                                  u_int, int, int,
+                                  ctl_logfunc, void *);
+void                   ctl_endserver(struct ctl_sctx *);
+void                   ctl_response(struct ctl_sess *, u_int,
+                                    const char *, u_int, const void *,
+                                    ctl_srvrdone, void *,
+                                    const char *, size_t);
+void                   ctl_sendhelp(struct ctl_sess *, u_int);
+void *                 ctl_getcsctx(struct ctl_sess *);
+void *                 ctl_setcsctx(struct ctl_sess *, void *);
+
+#endif /*ISC_CTL_H*/
diff --git a/lib/bind/include/isc/dst.h b/lib/bind/include/isc/dst.h
new file mode 100644 (file)
index 0000000..9e68a10
--- /dev/null
@@ -0,0 +1,141 @@
+#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 */
+       u_int32_t dk_flags;     /* and the flags of the public key */
+       u_int16_t 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 int len,         /* length of input data */
+                 u_char *signature,     /* buffer to write signature to */
+                 const int 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 int len,       /* length of input data */
+                   const u_char *signature,/* buffer containing signature */
+                   const int sig_len);  /* length of signature */
+
+
+DST_KEY *dst_read_key(const char *in_name,   /* name of key */
+                     const u_int16_t 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 int len);      /* size of input buffer*/
+
+
+int      dst_key_to_dnskey(const DST_KEY *key, /* key to translate */
+                          u_char *out_storage, /* output buffer */
+                          const int 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 int flags,       /* dns flags */
+                          const int protocol,    /* dns protocol */
+                          const u_char *key_buf, /* key in dns wire fmt */
+                          const int key_len);    /* size of key */
+
+
+int     dst_key_to_buffer(DST_KEY *key, u_char *out_buff, int buf_len);
+
+DST_KEY *dst_generate_key(const char *name,    /* name of new key */
+                         const int alg,       /* key algorithm to generate */
+                         const int bits,      /* size of new key */
+                         const int exp,       /* alg dependent parameter*/
+                         const int flags,     /* key DNS flags */
+                         const int protocol); /* key DNS protocol */
+
+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, int 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 int rdata_len);
+u_int16_t dst_s_id_calc(const u_char *key_data, const int 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/lib/bind/include/isc/eventlib.h b/lib/bind/include/isc/eventlib.h
new file mode 100644 (file)
index 0000000..4a3dc4b
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * 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.
+ */
+
+/* eventlib.h - exported interfaces for eventlib
+ * vix 09sep95 [initial]
+ *
+ * $Id: eventlib.h,v 1.1 2001/03/29 06:31:36 marka Exp $
+ */
+
+#ifndef _EVENTLIB_H
+#define _EVENTLIB_H
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <stdio.h>
+
+#ifndef __P
+# define __EVENTLIB_P_DEFINED
+# ifdef __STDC__
+#  define __P(x) x
+# else
+#  define __P(x) ()
+# endif
+#endif
+
+/* In the absence of branded types... */
+typedef struct { void *opaque; } evConnID;
+typedef struct { void *opaque; } evFileID;
+typedef struct { void *opaque; } evStreamID;
+typedef struct { void *opaque; } evTimerID;
+typedef struct { void *opaque; } evWaitID;
+typedef struct { void *opaque; } evContext;
+typedef struct { void *opaque; } evEvent;
+
+#define        evInitID(id) ((id)->opaque = NULL)
+#define        evTestID(id) ((id).opaque != NULL)
+
+typedef void (*evConnFunc)__P((evContext ctx, void *uap, int fd,
+                              const void *la, int lalen,
+                              const void *ra, int ralen));
+typedef void (*evFileFunc)__P((evContext ctx, void *uap, int fd, int evmask));
+typedef        void (*evStreamFunc)__P((evContext ctx, void *uap, int fd, int bytes));
+typedef void (*evTimerFunc)__P((evContext ctx, void *uap,
+                               struct timespec due, struct timespec inter));
+typedef        void (*evWaitFunc)__P((evContext ctx, void *uap, const void *tag));
+
+typedef        struct { unsigned char mask[256/8]; } evByteMask;
+#define        EV_BYTEMASK_BYTE(b) ((b) / 8)
+#define        EV_BYTEMASK_MASK(b) (1 << ((b) % 8))
+#define        EV_BYTEMASK_SET(bm, b) \
+       ((bm).mask[EV_BYTEMASK_BYTE(b)] |= EV_BYTEMASK_MASK(b))
+#define        EV_BYTEMASK_CLR(bm, b) \
+       ((bm).mask[EV_BYTEMASK_BYTE(b)] &= ~EV_BYTEMASK_MASK(b))
+#define        EV_BYTEMASK_TST(bm, b) \
+       ((bm).mask[EV_BYTEMASK_BYTE(b)] & EV_BYTEMASK_MASK(b))
+
+#define        EV_POLL         1
+#define        EV_WAIT         2
+#define        EV_NULL         4
+
+#define        EV_READ         1
+#define        EV_WRITE        2
+#define        EV_EXCEPT       4
+
+/* eventlib.c */
+#define evCreate       __evCreate
+#define evSetDebug     __evSetDebug
+#define evDestroy      __evDestroy
+#define evGetNext      __evGetNext
+#define evDispatch     __evDispatch
+#define evDrop         __evDrop
+#define evMainLoop     __evMainLoop
+#define evHighestFD    __evHighestFD
+
+int  evCreate __P((evContext *ctx));
+void evSetDebug __P((evContext ctx, int lev, FILE *out));
+int  evDestroy __P((evContext ctx));
+int  evGetNext __P((evContext ctx, evEvent *ev, int options));
+int  evDispatch __P((evContext ctx, evEvent ev));
+void evDrop __P((evContext ctx, evEvent ev));
+int  evMainLoop __P((evContext ctx));
+int  evHighestFD __P((evContext ctx));
+
+/* ev_connects.c */
+#define evListen       __evListen
+#define evConnect      __evConnect
+#define evCancelConn   __evCancelConn
+#define evHold         __evHold
+#define evUnhold       __evUnhold
+#define evTryAccept    __evTryAccept
+
+int evListen __P((evContext ctx, int fd, int maxconn,
+                 evConnFunc func, void *uap, evConnID *id));
+int evConnect __P((evContext ctx, int fd, const void *ra, int ralen,
+                  evConnFunc func, void *uap, evConnID *id));
+int evCancelConn __P((evContext ctx, evConnID id));
+int evHold __P((evContext, evConnID));
+int evUnhold __P((evContext, evConnID));
+int evTryAccept __P((evContext, evConnID, int *));
+
+/* ev_files.c */
+#define evSelectFD     __evSelectFD
+#define evDeselectFD   __evDeselectFD
+
+int evSelectFD __P((evContext ctx, int fd, int eventmask,
+                   evFileFunc func, void *uap, evFileID *id));
+int evDeselectFD __P((evContext ctx, evFileID id));
+
+/* ev_streams.c */
+#define evConsIovec    __evConsIovec
+#define evWrite                __evWrite
+#define evRead         __evRead
+#define evTimeRW       __evTimeRW
+#define evUntimeRW     __evUntimeRW
+#define        evCancelRW      __evCancelRW
+
+struct iovec evConsIovec __P((void *buf, size_t cnt));
+int evWrite __P((evContext ctx, int fd, const struct iovec *iov, int cnt,
+                evStreamFunc func, void *uap, evStreamID *id));
+int evRead __P((evContext ctx, int fd, const struct iovec *iov, int cnt,
+               evStreamFunc func, void *uap, evStreamID *id));
+int evTimeRW __P((evContext ctx, evStreamID id, evTimerID timer));
+int evUntimeRW __P((evContext ctx, evStreamID id));
+int evCancelRW __P((evContext ctx, evStreamID id));
+
+/* ev_timers.c */
+#define evConsTime     __evConsTime
+#define evAddTime      __evAddTime
+#define evSubTime      __evSubTime
+#define evCmpTime      __evCmpTime
+#define        evTimeSpec      __evTimeSpec
+#define        evTimeVal       __evTimeVal
+
+#define evNowTime              __evNowTime
+#define evLastEventTime                __evLastEventTime
+#define evSetTimer             __evSetTimer
+#define evClearTimer           __evClearTimer
+#define evResetTimer           __evResetTimer
+#define evSetIdleTimer         __evSetIdleTimer
+#define evClearIdleTimer       __evClearIdleTimer
+#define evResetIdleTimer       __evResetIdleTimer
+#define evTouchIdleTimer       __evTouchIdleTimer
+
+struct timespec evConsTime __P((time_t sec, long nsec));
+struct timespec evAddTime __P((struct timespec add1, struct timespec add2));
+struct timespec evSubTime __P((struct timespec minu, struct timespec subtra));
+struct timespec evNowTime __P((void));
+struct timespec evLastEventTime __P((evContext));
+struct timespec evTimeSpec __P((struct timeval));
+struct timeval evTimeVal __P((struct timespec));
+int evCmpTime __P((struct timespec a, struct timespec b));
+int evSetTimer __P((evContext ctx, evTimerFunc func, void *uap,
+                   struct timespec due, struct timespec inter,
+                   evTimerID *id));
+int evClearTimer __P((evContext ctx, evTimerID id));
+int evResetTimer __P((evContext, evTimerID, evTimerFunc, void *,
+                     struct timespec, struct timespec));
+int evSetIdleTimer __P((evContext, evTimerFunc, void *, struct timespec,
+                       evTimerID *));
+int evClearIdleTimer __P((evContext, evTimerID));
+int evResetIdleTimer __P((evContext, evTimerID, evTimerFunc, void *,
+                         struct timespec));
+int evTouchIdleTimer __P((evContext, evTimerID));
+
+/* ev_waits.c */
+#define evWaitFor      __evWaitFor
+#define evDo           __evDo
+#define evUnwait       __evUnwait
+#define evDefer                __evDefer
+
+int evWaitFor __P((evContext ctx, const void *tag, evWaitFunc func, void *uap,
+                  evWaitID *id));
+int evDo __P((evContext ctx, const void *tag));
+int evUnwait __P((evContext ctx, evWaitID id));
+int evDefer __P((evContext, evWaitFunc, void *));
+
+#ifdef __EVENTLIB_P_DEFINED
+# undef __P
+#endif
+
+#endif /*_EVENTLIB_H*/
diff --git a/lib/bind/include/isc/heap.h b/lib/bind/include/isc/heap.h
new file mode 100644 (file)
index 0000000..45c867c
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1997,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.
+ */
+
+typedef int (*heap_higher_priority_func)(void *, void *);
+typedef void (*heap_index_func)(void *, int);
+typedef void (*heap_for_each_func)(void *, void *);
+
+typedef struct heap_context {
+       int array_size;
+       int array_size_increment;
+       int heap_size;
+       void **heap;
+       heap_higher_priority_func higher_priority;
+       heap_index_func index;
+} *heap_context;
+
+#define heap_new       __heap_new
+#define heap_free      __heap_free
+#define heap_insert    __heap_insert
+#define heap_delete    __heap_delete
+#define heap_increased __heap_increased
+#define heap_decreased __heap_decreased
+#define heap_element   __heap_element
+#define heap_for_each  __heap_for_each
+
+heap_context   heap_new(heap_higher_priority_func, heap_index_func, int);
+int            heap_free(heap_context);
+int            heap_insert(heap_context, void *);
+int            heap_delete(heap_context, int);
+int            heap_increased(heap_context, int);
+int            heap_decreased(heap_context, int);
+void *         heap_element(heap_context, int);
+int            heap_for_each(heap_context, heap_for_each_func, void *);
diff --git a/lib/bind/include/isc/irpmarshall.h b/lib/bind/include/isc/irpmarshall.h
new file mode 100644 (file)
index 0000000..d851eca
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * 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.
+ */
+
+/*
+ * $Id: irpmarshall.h,v 1.1 2001/03/29 06:31:36 marka Exp $
+ */
+
+#ifndef _IRPMARSHALL_H_INCLUDED
+#define _IRPMARSHALL_H_INCLUDED
+
+/* Hide function names */
+#define irp_marshall_gr __irp_marshall_gr
+#define irp_marshall_ho __irp_marshall_ho
+#define irp_marshall_ne __irp_marshall_ne
+#define irp_marshall_ng __irp_marshall_ng
+#define irp_marshall_nw __irp_marshall_nw
+#define irp_marshall_pr __irp_marshall_pr
+#define irp_marshall_pw __irp_marshall_pw
+#define irp_marshall_sv __irp_marshall_sv
+#define irp_unmarshall_gr __irp_unmarshall_gr
+#define irp_unmarshall_ho __irp_unmarshall_ho
+#define irp_unmarshall_ne __irp_unmarshall_ne
+#define irp_unmarshall_ng __irp_unmarshall_ng
+#define irp_unmarshall_nw __irp_unmarshall_nw
+#define irp_unmarshall_pr __irp_unmarshall_pr
+#define irp_unmarshall_pw __irp_unmarshall_pw
+#define irp_unmarshall_sv __irp_unmarshall_sv
+
+#define MAXPADDRSIZE (sizeof "255.255.255.255" + 1)
+#define ADDR_T_STR(x) (x == AF_INET ? "AF_INET" :\
+                      (x == AF_INET6 ? "AF_INET6" : "UNKNOWN"))
+
+/* See comment below on usage */
+int irp_marshall_pw(const struct passwd *pw, char **buffer, size_t *len);
+int irp_unmarshall_pw(struct passwd *pw, char *buffer);
+int irp_marshall_gr(const struct group *gr, char **buffer, size_t *len);
+int irp_unmarshall_gr(struct group *gr, char *buffer);
+int irp_marshall_sv(const struct servent *sv, char **buffer, size_t *len);
+int irp_unmarshall_sv(struct servent *sv, char *buffer);
+int irp_marshall_pr(struct protoent *pr, char **buffer, size_t *len);
+int irp_unmarshall_pr(struct protoent *pr, char *buffer);
+int irp_marshall_ho(struct hostent *ho, char **buffer, size_t *len);
+int irp_unmarshall_ho(struct hostent *ho, char *buffer);
+int irp_marshall_ng(const char *host, const char *user, const char *domain,
+                   char **buffer, size_t *len);
+int irp_unmarshall_ng(const char **host, const char **user,
+                     const char **domain, char *buffer);
+int irp_marshall_nw(struct nwent *ne, char **buffer, size_t *len);
+int irp_unmarshall_nw(struct nwent *ne, char *buffer);
+int irp_marshall_ne(struct netent *ne, char **buffer, size_t *len);
+int irp_unmarshall_ne(struct netent *ne, char *buffer);
+
+/*
+ * Functions to marshall and unmarshall various system data structures. We
+ * use a printable ascii format that is as close to various system config
+ * files as reasonable (e.g. /etc/passwd format).
+ *
+ * We are not forgiving with unmarhsalling misformatted buffers. In
+ * particular whitespace in fields is not ignored. So a formatted password
+ * entry "brister  :1364:100:...." will yield a username of "brister   "
+ *
+ * We potentially do a lot of mallocs to fill fields that are of type
+ * (char **) like a hostent h_addr field. Building (for example) the
+ * h_addr field and its associated addresses all in one buffer is
+ * certainly possible, but not done here.
+ *
+ * The following description is true for all the marshalling functions:
+ *
+ */
+
+/* int irp_marshall_XX(struct yyyy *XX, char **buffer, size_t *len);
+ *
+ * The argument XX (of type struct passwd for example) is marshalled in the
+ * buffer pointed at by *BUFFER, which is of length *LEN. Returns 0
+ * on success and -1 on failure. Failure will occur if *LEN is
+ * smaller than needed.
+ *
+ * If BUFFER is NULL, then *LEN is set to the size of the buffer
+ * needed to marshall the data and no marshalling is actually done.
+ *
+ * If *BUFFER is NULL, then a buffer large enough will be allocated
+ * with memget() and the size allocated will be stored in *LEN. An extra 2
+ * bytes will be allocated for the client to append CRLF if wanted. The
+ * value of *LEN will include these two bytes.
+ *
+ * All the marshalling functions produce a buffer with the fields
+ * separated by colons (except for the hostent marshalling, which uses '@'
+ * to separate fields). Fields that have multiple subfields (like the
+ * gr_mem field in struct group) have their subparts separated by
+ * commas.
+ */
+
+/*
+ * int irp_unmarshall_XX(struct YYYYY *XX, char *buffer);
+ *
+ * The unmashalling functions break apart the buffer and store the
+ * values in the struct pointed to by XX. All pointer values inside
+ * XX are allocated with malloc. All arrays of pointers have a NULL
+ * as the last element.
+ */
+
+#endif
diff --git a/lib/bind/include/isc/list.h b/lib/bind/include/isc/list.h
new file mode 100644 (file)
index 0000000..21dd565
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 1997,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 LIST_H
+#define LIST_H 1
+#include <isc/assertions.h>
+
+#define LIST(type) struct { type *head, *tail; }
+#define INIT_LIST(list) \
+       do { (list).head = NULL; (list).tail = NULL; } while (0)
+
+#define LINK(type) struct { type *prev, *next; }
+#define INIT_LINK(elt, link) \
+       do { \
+               (elt)->link.prev = (void *)(-1); \
+               (elt)->link.next = (void *)(-1); \
+       } while (0)
+#define LINKED(elt, link) ((void *)((elt)->link.prev) != (void *)(-1))
+
+#define HEAD(list) ((list).head)
+#define TAIL(list) ((list).tail)
+#define EMPTY(list) ((list).head == NULL)
+
+#define PREPEND(list, elt, link) \
+       do { \
+               INSIST(!LINKED(elt, link));\
+               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 APPEND(list, elt, link) \
+       do { \
+               INSIST(!LINKED(elt, link));\
+               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 UNLINK(list, elt, link) \
+       do { \
+               INSIST(LINKED(elt, link));\
+               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; \
+               INIT_LINK(elt, link); \
+       } while (0)
+
+#define PREV(elt, link) ((elt)->link.prev)
+#define NEXT(elt, link) ((elt)->link.next)
+
+#define INSERT_BEFORE(list, before, elt, link) \
+       do { \
+               INSIST(!LINKED(elt, link));\
+               if ((before)->link.prev == NULL) \
+                       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 INSERT_AFTER(list, after, elt, link) \
+       do { \
+               INSIST(!LINKED(elt, link));\
+               if ((after)->link.next == NULL) \
+                       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 ENQUEUE(list, elt, link) APPEND(list, elt, link)
+#define DEQUEUE(list, elt, link) UNLINK(list, elt, link)
+
+#endif /* LIST_H */
diff --git a/lib/bind/include/isc/logging.h b/lib/bind/include/isc/logging.h
new file mode 100644 (file)
index 0000000..3d3d313
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * 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 LOGGING_H
+#define LOGGING_H
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+#define log_critical           (-5)
+#define log_error              (-4)
+#define log_warning            (-3)
+#define log_notice             (-2)
+#define log_info               (-1)
+#define log_debug(level)       (level)
+
+typedef enum { log_syslog, log_file, log_null } log_channel_type;
+
+#define LOG_MAX_VERSIONS 99
+
+#define LOG_CLOSE_STREAM               0x0001
+#define LOG_TIMESTAMP                  0x0002
+#define LOG_TRUNCATE                   0x0004
+#define LOG_USE_CONTEXT_LEVEL          0x0008
+#define LOG_PRINT_LEVEL                        0x0010
+#define LOG_REQUIRE_DEBUG              0x0020
+#define LOG_CHANNEL_BROKEN             0x0040
+#define LOG_PRINT_CATEGORY             0x0080
+#define LOG_CHANNEL_OFF                        0x0100
+
+typedef struct log_context *log_context;
+typedef struct log_channel *log_channel;
+
+#define LOG_OPTION_DEBUG               0x01
+#define LOG_OPTION_LEVEL               0x02
+
+#define log_open_stream                __log_open_stream
+#define log_close_stream       __log_close_stream
+#define log_get_stream         __log_get_stream
+#define log_get_filename       __log_get_filename
+#define log_check_channel      __log_check_channel
+#define log_check              __log_check
+#define log_vwrite             __log_vwrite
+#define log_write              __log_write
+#define log_new_context                __log_new_context
+#define log_free_context       __log_free_context
+#define log_add_channel                __log_add_channel
+#define log_remove_channel     __log_remove_channel
+#define log_option             __log_option
+#define log_category_is_active __log_category_is_active
+#define log_new_syslog_channel __log_new_syslog_channel
+#define log_new_file_channel   __log_new_file_channel
+#define log_set_file_owner     __log_set_file_owner
+#define log_new_null_channel   __log_new_null_channel
+#define log_inc_references     __log_inc_references
+#define log_dec_references     __log_dec_references
+#define log_get_channel_type   __log_get_channel_type
+#define log_free_channel       __log_free_channel
+
+FILE *                 log_open_stream(log_channel);
+int                    log_close_stream(log_channel);
+FILE *                 log_get_stream(log_channel);
+char *                 log_get_filename(log_channel);
+int                    log_check_channel(log_context, int, log_channel);
+int                    log_check(log_context, int, int);
+void                   log_vwrite(log_context, int, int, const char *, 
+                                  va_list args);
+void                   log_write(log_context, int, int, const char *, ...);
+int                    log_new_context(int, char **, log_context *);
+void                   log_free_context(log_context);
+int                    log_add_channel(log_context, int, log_channel);
+int                    log_remove_channel(log_context, int, log_channel);
+int                    log_option(log_context, int, int);
+int                    log_category_is_active(log_context, int);
+log_channel            log_new_syslog_channel(unsigned int, int, int);
+log_channel            log_new_file_channel(unsigned int, int, char *,
+                                            FILE *, unsigned int,
+                                            unsigned long);
+int                    log_set_file_owner(log_channel, uid_t, gid_t);
+log_channel            log_new_null_channel(void);
+int                    log_inc_references(log_channel);
+int                    log_dec_references(log_channel);
+log_channel_type       log_get_channel_type(log_channel);
+int                    log_free_channel(log_channel);
+
+#endif /* !LOGGING_H */
diff --git a/lib/bind/include/isc/memcluster.h b/lib/bind/include/isc/memcluster.h
new file mode 100644 (file)
index 0000000..b6f4191
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1997,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 MEMCLUSTER_H
+#define MEMCLUSTER_H
+
+#include <stdio.h>
+
+#define meminit                __meminit
+#ifdef MEMCLUSTER_DEBUG
+#define memget(s)      __memget_debug(s, __FILE__, __LINE__)
+#define memput(p, s)   __memput_debug(p, s, __FILE__, __LINE__)
+#else /*MEMCLUSTER_DEBUG*/
+#ifdef MEMCLUSTER_RECORD
+#define memget(s)      __memget_record(s, __FILE__, __LINE__)
+#define memput(p, s)   __memput_record(p, s, __FILE__, __LINE__)
+#else /*MEMCLUSTER_RECORD*/
+#define memget         __memget
+#define memput         __memput
+#endif /*MEMCLUSTER_RECORD*/
+#endif /*MEMCLUSTER_DEBUG*/
+#define memstats       __memstats
+
+int    meminit(size_t, size_t);
+void * __memget(size_t);
+void   __memput(void *, size_t);
+void * __memget_debug(size_t, const char *, int);
+void   __memput_debug(void *, size_t, const char *, int);
+void * __memget_record(size_t, const char *, int);
+void   __memput_record(void *, size_t, const char *, int);
+void   memstats(FILE *);
+
+#endif /* MEMCLUSTER_H */
diff --git a/lib/bind/include/isc/misc.h b/lib/bind/include/isc/misc.h
new file mode 100644 (file)
index 0000000..5799316
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+/*
+ * $Id: misc.h,v 1.1 2001/03/29 06:31:36 marka Exp $
+ */
+
+#ifndef _ISC_MISC_H
+#define _ISC_MISC_H
+
+#define        bitncmp         __bitncmp
+/*#define isc_movefile __isc_movefile */
+
+extern int             bitncmp(const void *l, const void *r, int n);
+extern int             isc_movefile(const char *, const char *);
+
+#endif /*_ISC_MISC_H*/
diff --git a/lib/bind/include/isc/tree.h b/lib/bind/include/isc/tree.h
new file mode 100644 (file)
index 0000000..f383489
--- /dev/null
@@ -0,0 +1,48 @@
+/* tree.h - declare structures used by tree library
+ *
+ * vix 22jan93 [revisited; uses RCS, ANSI, POSIX; has bug fixes]
+ * vix 27jun86 [broken out of tree.c]
+ *
+ * $Id: tree.h,v 1.1 2001/03/29 06:31:37 marka Exp $
+ */
+
+
+#ifndef        _TREE_H_INCLUDED
+#define        _TREE_H_INCLUDED
+
+
+#ifndef __P
+# if defined(__STDC__) || defined(__GNUC__)
+#  define __P(x) x
+# else
+#  define __P(x) ()
+# endif
+#endif
+
+/*
+ * tree_t is our package-specific anonymous pointer.
+ */
+#if defined(__STDC__) || defined(__GNUC__)
+typedef        void *tree_t;
+#else
+typedef        char *tree_t;
+#endif
+
+
+typedef        struct tree_s {
+               tree_t          data;
+               struct tree_s   *left, *right;
+               short           bal;
+       }
+       tree;
+
+
+void   tree_init       __P((tree **));
+tree_t tree_srch       __P((tree **, int (*)(), tree_t));
+tree_t tree_add        __P((tree **, int (*)(), tree_t, void (*)()));
+int    tree_delete     __P((tree **, int (*)(), tree_t, void (*)()));
+int    tree_trav       __P((tree **, int (*)()));
+void   tree_mung       __P((tree **, void (*)()));
+
+
+#endif /* _TREE_H_INCLUDED */
diff --git a/lib/bind/include/netdb.h b/lib/bind/include/netdb.h
new file mode 100644 (file)
index 0000000..cd7d9a9
--- /dev/null
@@ -0,0 +1,485 @@
+/*
+ * ++Copyright++ 1980, 1983, 1988, 1993
+ * -
+ * Copyright (c) 1980, 1983, 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) 1995, 1996, 1997, and 1998 WIDE Project.
+ * 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 WIDE Project and
+ *    its contributors.
+ * 4. Neither the name of the project 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 PROJECT 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 PROJECT 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.
+ * -
+ * --Copyright--
+ */
+
+/*
+ *      @(#)netdb.h    8.1 (Berkeley) 6/2/93
+ *     $Id: netdb.h,v 1.1 2001/03/29 06:31:34 marka Exp $
+ */
+
+#ifndef _NETDB_H_
+#define _NETDB_H_
+
+#include <sys/param.h>
+#if (!defined(BSD)) || (BSD < 199306)
+# include <sys/bitypes.h>
+#endif
+#include <sys/cdefs.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <stdio.h>
+
+#ifndef _PATH_HEQUIV
+#define _PATH_HEQUIV   "/etc/hosts.equiv"
+#endif
+#ifndef _PATH_HOSTS
+#define        _PATH_HOSTS     "/etc/hosts"
+#endif
+#ifndef _PATH_NETWORKS
+#define        _PATH_NETWORKS  "/etc/networks"
+#endif
+#ifndef _PATH_PROTOCOLS
+#define        _PATH_PROTOCOLS "/etc/protocols"
+#endif
+#ifndef _PATH_SERVICES
+#define        _PATH_SERVICES  "/etc/services"
+#endif
+
+#ifdef _REENTRANT
+__BEGIN_DECLS
+extern int * __h_errno __P((void));
+__END_DECLS
+#define        h_errno (*__h_errno())
+#else
+extern int h_errno;
+#endif
+
+/*
+ * Structures returned by network data base library.  All addresses are
+ * supplied in host order, and returned in network order (suitable for
+ * use in system calls).
+ */
+struct hostent {
+       char    *h_name;        /* official name of host */
+       char    **h_aliases;    /* alias list */
+       int     h_addrtype;     /* host address type */
+       int     h_length;       /* length of address */
+       char    **h_addr_list;  /* list of addresses from name server */
+#define        h_addr  h_addr_list[0]  /* address, for backward compatiblity */
+};
+
+/*
+ * Assumption here is that a network number
+ * fits in an unsigned long -- probably a poor one.
+ */
+struct netent {
+       char            *n_name;        /* official name of net */
+       char            **n_aliases;    /* alias list */
+       int             n_addrtype;     /* net address type */
+       unsigned long   n_net;          /* network # */
+};
+
+struct servent {
+       char    *s_name;        /* official service name */
+       char    **s_aliases;    /* alias list */
+       int     s_port;         /* port # */
+       char    *s_proto;       /* protocol to use */
+};
+
+struct protoent {
+       char    *p_name;        /* official protocol name */
+       char    **p_aliases;    /* alias list */
+       int     p_proto;        /* protocol # */
+};
+
+struct addrinfo {
+       int             ai_flags;       /* AI_PASSIVE, AI_CANONNAME */
+       int             ai_family;      /* PF_xxx */
+       int             ai_socktype;    /* SOCK_xxx */
+       int             ai_protocol;    /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
+       size_t          ai_addrlen;     /* length of ai_addr */
+       char            *ai_canonname;  /* canonical name for hostname */
+       struct sockaddr *ai_addr;       /* binary address */
+       struct addrinfo *ai_next;       /* next structure in linked list */
+};
+
+/*
+ * Error return codes from gethostbyname() and gethostbyaddr()
+ * (left in extern int h_errno).
+ */
+
+#define        NETDB_INTERNAL  -1      /* see errno */
+#define        NETDB_SUCCESS   0       /* no problem */
+#define        HOST_NOT_FOUND  1 /* Authoritative Answer Host not found */
+#define        TRY_AGAIN       2 /* Non-Authoritive Host not found, or SERVERFAIL */
+#define        NO_RECOVERY     3 /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */
+#define        NO_DATA         4 /* Valid name, no data record of requested type */
+#define        NO_ADDRESS      NO_DATA         /* no address, look for MX record */
+
+/*
+ * Error return codes from getaddrinfo()
+ */
+
+#define        EAI_ADDRFAMILY   1      /* address family for hostname not supported */
+#define        EAI_AGAIN        2      /* temporary failure in name resolution */
+#define        EAI_BADFLAGS     3      /* invalid value for ai_flags */
+#define        EAI_FAIL         4      /* non-recoverable failure in name resolution */
+#define        EAI_FAMILY       5      /* ai_family not supported */
+#define        EAI_MEMORY       6      /* memory allocation failure */
+#define        EAI_NODATA       7      /* no address associated with hostname */
+#define        EAI_NONAME       8      /* hostname nor servname provided, or not known */
+#define        EAI_SERVICE      9      /* servname not supported for ai_socktype */
+#define        EAI_SOCKTYPE    10      /* ai_socktype not supported */
+#define        EAI_SYSTEM      11      /* system error returned in errno */
+#define EAI_BADHINTS   12
+#define EAI_PROTOCOL   13
+#define EAI_MAX                14
+
+/*
+ * Flag values for getaddrinfo()
+ */
+#define        AI_PASSIVE      0x00000001
+#define        AI_CANONNAME    0x00000002
+#define AI_NUMERICHOST 0x00000004
+#define        AI_MASK         0x00000007
+
+/*
+ * Flag values for getipnodebyname()
+ */
+#define AI_V4MAPPED    0x00000008
+#define AI_ALL         0x00000010
+#define AI_ADDRCONFIG  0x00000020
+#define AI_DEFAULT     (AI_V4MAPPED|AI_ADDRCONFIG)
+
+/*
+ * Constants for getnameinfo()
+ */
+#define        NI_MAXHOST      1025
+#define        NI_MAXSERV      32
+
+/*
+ * Flag values for getnameinfo()
+ */
+#define        NI_NOFQDN       0x00000001
+#define        NI_NUMERICHOST  0x00000002
+#define        NI_NAMEREQD     0x00000004
+#define        NI_NUMERICSERV  0x00000008
+#define        NI_DGRAM        0x00000010
+#define        NI_WITHSCOPEID  0x00000020
+#define NI_NUMERICSCOPE        0x00000040
+
+/*
+ * Scope delimit character
+ */
+#define SCOPE_DELIMITER        '%'
+
+
+#ifdef _REENTRANT
+#if defined (__hpux) || defined(__osf__)
+#define        _MAXALIASES     35
+#define        _MAXLINELEN     1024
+#define        _MAXADDRS       35
+#define        _HOSTBUFSIZE    (BUFSIZ + 1)
+
+struct hostent_data {
+       struct in_addr  host_addr;
+       char            *h_addr_ptrs[_MAXADDRS + 1];
+       char            hostaddr[_MAXADDRS];
+       char            hostbuf[_HOSTBUFSIZE];
+       char            *host_aliases[_MAXALIASES];
+       char            *host_addrs[2];
+       FILE            *hostf;
+#ifdef __osf__
+       int             svc_gethostflag;
+       int             svc_gethostbind;
+#endif
+#ifdef __hpux
+       short           _nsw_src;
+       short           _flags;
+       char            *current;
+       int             currentlen;
+#endif
+};
+
+struct  netent_data {
+       FILE    *net_fp;
+#ifdef __osf__
+       char    line[_MAXLINELEN];
+#endif
+#ifdef __hpux
+       char    line[_MAXLINELEN+1];
+#endif
+       char    *net_aliases[_MAXALIASES];
+#ifdef __osf__
+       int     _net_stayopen;
+       int     svc_getnetflag;
+#endif
+#ifdef __hpux
+       short   _nsw_src;
+       short   _flags;
+       char    *current;
+       int     currentlen;
+#endif
+};
+
+struct protoent_data {
+       FILE    *proto_fp;
+#ifdef __osf__
+       char    line[1024];
+#endif
+#ifdef __hpux
+       char    line[_MAXLINELEN+1];
+#endif
+       char    *proto_aliases[_MAXALIASES];
+#ifdef __osf__
+       int     _proto_stayopen;
+       int     svc_getprotoflag;
+#endif
+#ifdef __hpux
+       short   _nsw_src;
+       short   _flags;
+       char    *current;
+       int     currentlen;
+#endif
+};
+
+struct servent_data {
+       FILE    *serv_fp;
+#ifdef __osf__
+       char    line[_MAXLINELEN];
+#endif
+#ifdef __hpux
+       char    line[_MAXLINELEN+1];
+#endif
+       char    *serv_aliases[_MAXALIASES];
+#ifdef __osf__
+       int     _serv_stayopen;
+       int     svc_getservflag;
+#endif
+#ifdef __hpux
+       short   _nsw_src;
+       short   _flags;
+       char    *current;
+       int     currentlen;
+#endif
+};
+#endif
+#endif
+__BEGIN_DECLS
+void           endhostent __P((void));
+void           endnetent __P((void));
+void           endprotoent __P((void));
+void           endservent __P((void));
+void           freehostent __P((struct hostent *));
+struct hostent *gethostbyaddr __P((const char *, int, int));
+struct hostent *gethostbyname __P((const char *));
+struct hostent *gethostbyname2 __P((const char *, int));
+struct hostent *gethostent __P((void));
+struct hostent *getipnodebyaddr __P((const void *, size_t, int, int *));
+struct hostent *getipnodebyname __P((const char *, int, int, int *));
+struct netent  *getnetbyaddr __P((unsigned long, int));
+struct netent  *getnetbyname __P((const char *));
+struct netent  *getnetent __P((void));
+struct protoent        *getprotobyname __P((const char *));
+struct protoent        *getprotobynumber __P((int));
+struct protoent        *getprotoent __P((void));
+struct servent *getservbyname __P((const char *, const char *));
+struct servent *getservbyport __P((int, const char *));
+struct servent *getservent __P((void));
+void           herror __P((const char *));
+const char     *hstrerror __P((int));
+void           sethostent __P((int));
+/* void                sethostfile __P((const char *)); */
+void           setnetent __P((int));
+void           setprotoent __P((int));
+void           setservent __P((int));
+int            getaddrinfo __P((const char *, const char *,
+                                const struct addrinfo *, struct addrinfo **));
+int            getnameinfo __P((const struct sockaddr *, size_t, char *,
+                                size_t, char *, size_t, int));
+void           freeaddrinfo __P((struct addrinfo *));
+const char     *gai_strerror __P((int));
+struct hostent  *getipnodebyname __P((const char *, int, int, int *));
+struct hostent *getipnodebyaddr __P((const void *, size_t, int, int *));
+void           freehostent __P((struct hostent *));
+
+
+#ifdef _REENTRANT
+#if defined(__hpux) || defined(__osf__)
+int            gethostbyaddr_r __P((const char *, int, int, struct hostent *,
+                                       struct hostent_data *));
+int            gethostbyname_r __P((const char *, struct hostent *, 
+                                       struct hostent_data *));
+int            gethostent_r __P((struct hostent *, struct hostent_data *));
+int            sethostent_r __P((int, struct hostent_data *));
+#if defined(__hpux)
+int            endhostent_r __P((struct hostent_data *));
+#else
+void           endhostent_r __P((struct hostent_data *));
+#endif
+
+#ifdef __hpux
+int            getnetbyaddr_r __P((int, int,
+                               struct netent *, struct netent_data *));
+#else
+int            getnetbyaddr_r __P((long, int,
+                               struct netent *, struct netent_data *));
+#endif
+int            getnetbyname_r __P((const char *,
+                               struct netent *, struct netent_data *));
+int            getnetent_r __P((struct netent *, struct netent_data *));
+int            setnetent_r __P((int, struct netent_data *));
+#ifdef __hpux
+int            endnetent_r __P((struct netent_data *buffer));
+#else
+void           endnetent_r __P((struct netent_data *buffer));
+#endif
+
+int            getprotobyname_r __P((const char *,
+                               struct protoent *, struct protoent_data *));
+int            getprotobynumber_r __P((int,
+                               struct protoent *, struct protoent_data *));
+int            getprotoent_r __P((struct protoent *, struct protoent_data *));
+int            setprotoent_r __P((int, struct protoent_data *));
+#ifdef __hpux
+int            endprotoent_r __P((struct protoent_data *));
+#else
+void           endprotoent_r __P((struct protoent_data *));
+#endif
+
+int            getservbyname_r __P((const char *, const char *,
+                               struct servent *, struct servent_data *));
+int            getservbyport_r __P((int, const char *,
+                               struct servent *, struct servent_data *));
+int            getservent_r __P((struct servent *, struct servent_data *));
+int            setservent_r __P((int, struct servent_data *));
+#ifdef __hpux
+int            endservent_r __P((struct servent_data *));
+#else
+void           endservent_r __P((struct servent_data *));
+#endif
+#else
+ /* defined(sun) || defined(bsdi) */
+struct hostent *gethostbyaddr_r __P((const char *, int, int, struct hostent *,
+                                       char *, int, int *));
+struct hostent *gethostbyname_r __P((const char *, struct hostent *,
+                                       char *, int, int *));
+struct hostent *gethostent_r __P((struct hostent *, char *, int, int *));
+void           sethostent_r __P((int));
+void           endhostent_r __P((void));
+
+struct netent  *getnetbyname_r __P((const char *, struct netent *,
+                                       char *, int));
+struct netent  *getnetbyaddr_r __P((long, int, struct netent *,
+                                       char *, int));
+struct netent  *getnetent_r __P((struct netent *, char *, int));
+void           setnetent_r __P((int));
+void           endnetent_r __P((void));
+
+struct protoent        *getprotobyname_r __P((const char *,
+                               struct protoent *, char *, int));
+struct protoent        *getprotobynumber_r __P((int,
+                               struct protoent *, char *, int));
+struct protoent        *getprotoent_r __P((struct protoent *, char *, int));
+void           setprotoent_r __P((int));
+void           endprotoent_r __P((void));
+
+struct servent *getservbyname_r __P((const char *name, const char *,
+                                       struct servent *, char *, int));
+struct servent *getservbyport_r __P((int port, const char *,
+                                       struct servent *, char *, int));
+struct servent *getservent_r __P((struct servent *, char *, int));
+void           setservent_r __P((int));
+void           endservent_r __P((void));
+
+#endif
+#endif
+__END_DECLS
+
+/* This is nec'y to make this include file properly replace the sun version. */
+#ifdef sun
+#ifdef __GNU_LIBRARY__
+#include <rpc/netdb.h>
+#else
+struct rpcent {
+       char    *r_name;        /* name of server for this rpc program */
+       char    **r_aliases;    /* alias list */
+       int     r_number;       /* rpc program number */
+};
+struct rpcent  *getrpcbyname(), *getrpcbynumber(), *getrpcent();
+#endif /* __GNU_LIBRARY__ */
+#endif /* sun */
+
+#endif /* !_NETDB_H_ */
diff --git a/lib/bind/include/netgroup.h b/lib/bind/include/netgroup.h
new file mode 100644 (file)
index 0000000..30efb94
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef netgroup_h
+#define netgroup_h
+
+int getnetgrent(const char **machinep, const char **userp,
+               const char **domainp);
+
+int getnetgrent_r(char **machinep, char **userp, char **domainp,
+                 char *buffer, int buflen);
+
+void setnetgrent(const char *netgroup);
+
+void endnetgrent(void);
+
+int innetgr(const char *netgroup, const char *machine,
+           const char *user, const char *domain);
+
+#endif
diff --git a/lib/bind/include/res_update.h b/lib/bind/include/res_update.h
new file mode 100644 (file)
index 0000000..946ad13
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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.1 2001/03/29 06:31:34 marka Exp $
+ */
+
+#ifndef __RES_UPDATE_H
+#define __RES_UPDATE_H
+
+#include <sys/types.h>
+#include <arpa/nameser.h>
+#include <isc/list.h>
+#include <resolv.h>
+
+/*
+ * This RR-like structure is particular to UPDATE.
+ */
+struct ns_updrec {
+       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 */
+       u_char *        r_data;         /* rdata fields as text string */
+       u_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 */
+       u_int           r_zone;         /* zone number on server */
+};
+typedef struct ns_updrec ns_updrec;
+typedef        LIST(ns_updrec) ns_updque;
+
+#define res_mkupdate           __res_mkupdate
+#define res_update             __res_update
+#define res_mkupdrec           __res_mkupdrec
+#define res_freeupdrec         __res_freeupdrec
+#define res_nmkupdate          __res_nmkupdate
+#define res_nupdate            __res_nupdate
+
+int            res_mkupdate __P((ns_updrec *, u_char *, int));
+int            res_update __P((ns_updrec *));
+ns_updrec *    res_mkupdrec __P((int, const char *, u_int, u_int, u_long));
+void           res_freeupdrec __P((ns_updrec *));
+int            res_nmkupdate __P((res_state, ns_updrec *, u_char *, int));
+int            res_nupdate __P((res_state, ns_updrec *, ns_tsig_key *));
+
+#endif /*__RES_UPDATE_H*/
diff --git a/lib/bind/include/resolv.h b/lib/bind/include/resolv.h
new file mode 100644 (file)
index 0000000..f166717
--- /dev/null
@@ -0,0 +1,447 @@
+/*
+ * 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.1 2001/03/29 06:31:34 marka Exp $
+ */
+
+#ifndef _RESOLV_H_
+#define        _RESOLV_H_
+
+#include <sys/param.h>
+#if (!defined(BSD)) || (BSD < 199306)
+# include <sys/bitypes.h>
+#else
+# include <sys/types.h>
+#endif
+#include <sys/cdefs.h>
+#include <sys/socket.h>
+#include <stdio.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 (__RES > 19931104)".  Do not
+ * compare for equality; rather, use it to determine whether your resolver
+ * is new enough to contain a certain feature.
+ */
+
+#define        __RES   19991006
+
+/*
+ * 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)__P((struct sockaddr * const *ns,
+                                             const u_char **query,
+                                             int *querylen,
+                                             u_char *ans,
+                                             int anssiz,
+                                             int *resplen));
+
+typedef res_sendhookact (*res_send_rhook)__P((const struct sockaddr *ns,
+                                             const u_char *query,
+                                             int querylen,
+                                             u_char *ans,
+                                             int anssiz,
+                                             int *resplen));
+
+struct res_sym {
+       int             number;    /* Identifying number, like T_MX */
+       const char *    name;      /* Its symbolic name, like "MX" */
+       const 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. */
+#define        RES_MAXTIME             65535   /* Infinity, in milliseconds. */
+
+union __res_sockaddr_union {
+       struct sockaddr_in      sin;
+#if 1 /*def INET6*/
+       struct sockaddr_in6     sin6;
+#endif
+       int64_t                 __align;        /* 64bit alignment */
+       char                    __space[128];   /* max size */
+};
+
+struct __res_state_ext {
+       union __res_sockaddr_union nsaddrs[MAXNS];
+       struct sort_list {
+               int     af;
+               union {
+                       struct in_addr  ina;
+                       struct in6_addr in6a;
+               } addr, mask;
+       } sort_list[MAXRESOLVSORT];
+};
+
+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     _vcsock;                /* PRIVATE: for res_send VC i/o */
+       u_int   _flags;                 /* PRIVATE: see below */
+       union {
+               char    pad[52];        /* On an i386 this means 512b total. */
+               struct {
+                       u_int16_t               nscount;
+                       u_int16_t               nstimes[MAXNS]; /* ms. */
+                       int                     nssocks[MAXNS];
+                       struct __res_state_ext *ext;    /* extention for IPv6 */
+               } _ext;
+       } _u;
+};
+
+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 */
+#define        RES_F_EDNS0ERR  0x00000004      /* EDNS0 caused errors */
+
+/* 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_BLAST       0x00020000      /* blast all recursive servers */
+/* KAME extensions: use higher bit to avoid conflict with ISC use */
+#define RES_USE_EDNS0  0x40000000      /* use EDNS0 if configured */
+#define RES_USE_A6     0x20000000      /* use A6 */
+#define RES_USE_DNAME  0x10000000      /* use DNAME */
+
+#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      */
+
+/* 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
+
+#ifndef __BIND_NOSTATIC
+#define fp_nquery              __fp_nquery
+#define fp_query               __fp_query
+#define hostalias              __hostalias
+#define p_query                        __p_query
+#define res_close              __res_close
+#define res_init               __res_init
+#define res_isourserver                __res_isourserver
+#define res_mkquery            __res_mkquery
+#define res_query              __res_query
+#define res_querydomain                __res_querydomain
+#define res_search             __res_search
+#define res_send               __res_send
+#define res_sendsigned         __res_sendsigned
+
+__BEGIN_DECLS
+void           fp_nquery __P((const u_char *, int, FILE *));
+void           fp_query __P((const u_char *, FILE *));
+const char *   hostalias __P((const char *));
+void           p_query __P((const u_char *));
+void           res_close __P((void));
+int            res_init __P((void));
+int            res_isourserver __P((const struct sockaddr_in *));
+int            res_mkquery __P((int, const char *, int, int, const u_char *,
+                                int, const u_char *, u_char *, int));
+int            res_query __P((const char *, int, int, u_char *, int));
+int            res_querydomain __P((const char *, const char *, int, int,
+                                    u_char *, int));
+int            res_search __P((const char *, int, int, u_char *, int));
+int            res_send __P((const u_char *, int, u_char *, int));
+int            res_sendsigned __P((const u_char *, int, ns_tsig_key *,
+                                   u_char *, int));
+__END_DECLS
+#endif
+
+#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 */
+
+#define b64_ntop               __b64_ntop
+#define b64_pton               __b64_pton
+#define dn_comp                        __dn_comp
+#define dn_count_labels                __dn_count_labels
+#define dn_expand              __dn_expand
+#define dn_skipname            __dn_skipname
+#define fp_resstat             __fp_resstat
+#define loc_aton               __loc_aton
+#define loc_ntoa               __loc_ntoa
+#define p_cdname               __p_cdname
+#define p_cdnname              __p_cdnname
+#define p_class                        __p_class
+#define p_fqname               __p_fqname
+#define p_fqnname              __p_fqnname
+#define p_option               __p_option
+#define p_secstodate           __p_secstodate
+#define p_section              __p_section
+#define p_time                 __p_time
+#define p_type                 __p_type
+#define p_rcode                        __p_rcode
+#define putlong                        __putlong
+#define putshort               __putshort
+#define res_dnok               __res_dnok
+#define res_findzonecut                __res_findzonecut
+#define res_hnok               __res_hnok
+#define res_hostalias          __res_hostalias
+#define res_mailok             __res_mailok
+#define res_nameinquery                __res_nameinquery
+#define res_nclose             __res_nclose
+#define res_ninit              __res_ninit
+#define res_nmkquery           __res_nmkquery
+#define res_pquery             __res_pquery
+#define res_nquery             __res_nquery
+#define res_nquerydomain       __res_nquerydomain
+#define res_nsearch            __res_nsearch
+#define res_nsend              __res_nsend
+#define res_nsendsigned                __res_nsendsigned
+#define res_nisourserver       __res_nisourserver
+#define res_ownok              __res_ownok
+#define res_queriesmatch       __res_queriesmatch
+#define res_randomid           __res_randomid
+#define sym_ntop               __sym_ntop
+#define sym_ntos               __sym_ntos
+#define sym_ston               __sym_ston
+#define res_nopt               __res_nopt
+__BEGIN_DECLS
+int            res_hnok __P((const char *));
+int            res_ownok __P((const char *));
+int            res_mailok __P((const char *));
+int            res_dnok __P((const char *));
+int            sym_ston __P((const struct res_sym *, const char *, int *));
+const char *   sym_ntos __P((const struct res_sym *, int, int *));
+const char *   sym_ntop __P((const struct res_sym *, int, int *));
+int            b64_ntop __P((u_char const *, size_t, char *, size_t));
+int            b64_pton __P((char const *, u_char *, size_t));
+int            loc_aton __P((const char *ascii, u_char *binary));
+const char *   loc_ntoa __P((const u_char *binary, char *ascii));
+int            dn_skipname __P((const u_char *, const u_char *));
+void           putlong __P((u_int32_t, u_char *));
+void           putshort __P((u_int16_t, u_char *));
+#ifndef __ultrix__
+u_int16_t      _getshort __P((const u_char *src));
+u_int32_t      _getlong __P((const u_char *src));
+#endif
+const char *   p_class __P((int));
+const char *   p_time __P((u_int32_t));
+const char *   p_type __P((int));
+const char *   p_rcode __P((int));
+const u_char * p_cdnname __P((const u_char *, const u_char *, int, FILE *));
+const u_char * p_cdname __P((const u_char *, const u_char *, FILE *));
+const u_char * p_fqnname __P((const u_char *cp, const u_char *msg,
+                              int, char *, int));
+const u_char * p_fqname __P((const u_char *, const u_char *, FILE *));
+const char *   p_option __P((u_long option));
+char *         p_secstodate __P((u_long));
+int            dn_count_labels __P((const char *));
+int            dn_comp __P((const char *, u_char *, int,
+                            u_char **, u_char **));
+int            dn_expand __P((const u_char *, const u_char *, const u_char *,
+                              char *, int));
+u_int          res_randomid __P((void));
+int            res_nameinquery __P((const char *, int, int,
+                                    const u_char *, const u_char *));
+int            res_queriesmatch __P((const u_char *, const u_char *,
+                                     const u_char *, const u_char *));
+const char *   p_section __P((int section, int opcode));
+/* Things involving a resolver context. */
+int            res_ninit __P((res_state));
+int            res_nisourserver __P((const res_state,
+                                     const struct sockaddr_in *));
+void           fp_resstat __P((const res_state, FILE *));
+void           res_pquery __P((const res_state, const u_char *, int, FILE *));
+const char *   res_hostalias __P((const res_state, const char *,
+                                  char *, size_t));
+int            res_nquery __P((res_state,
+                               const char *, int, int, u_char *, int));
+int            res_nsearch __P((res_state, const char *, int,
+                                int, u_char *, int));
+int            res_nquerydomain __P((res_state,
+                                     const char *, const char *, int, int,
+                                     u_char *, int));
+int            res_nmkquery __P((res_state,
+                                 int, const char *, int, int, const u_char *,
+                                 int, const u_char *, u_char *, int));
+int            res_nsend __P((res_state, const u_char *, int, u_char *, int));
+int            res_nsendsigned __P((res_state, const u_char *, int,
+                                    ns_tsig_key *, u_char *, int));
+int            res_findzonecut __P((res_state, const char *, ns_class, int,
+                                    char *, size_t, struct in_addr *, int));
+void           res_nclose __P((res_state));
+int            res_nopt __P((res_state, int, u_char *, int, int));
+void           res_send_setqhook __P((res_send_qhook hook));
+void           res_send_setrhook __P((res_send_rhook hook));
+int            __res_vinit __P((res_state, int));
+void           res_destroyservicelist __P((void));
+const char *   res_servicename __P((u_int16_t port, const char *proto));
+const char *   res_protocolname __P((int num));
+void           res_destroyprotolist __P((void));
+void           res_buildprotolist __P((void));
+__END_DECLS
+
+#endif /* !_RESOLV_H_ */
diff --git a/lib/bind/inet/Makefile.in b/lib/bind/inet/Makefile.in
new file mode 100644 (file)
index 0000000..34cee17
--- /dev/null
@@ -0,0 +1,16 @@
+OBJS=  inet_addr.@O@ inet_cidr_ntop.@O@ inet_cidr_pton.@O@ inet_data.@O@ \
+       inet_lnaof.@O@ inet_makeaddr.@O@ inet_net_ntop.@O@ inet_net_pton.@O@ \
+       inet_neta.@O@ inet_netof.@O@ inet_network.@O@ inet_ntoa.@O@ \
+       inet_ntop.@O@ inet_pton.@O@ nsap_addr.@O@
+
+SRCS=  inet_addr.c inet_cidr_ntop.c inet_cidr_pton.c inet_data.c \
+       inet_lnaof.c inet_makeaddr.c inet_net_ntop.c inet_net_pton.c \
+       inet_neta.c inet_netof.c inet_network.c inet_ntoa.c \
+       inet_ntop.c inet_pton.c nsap_addr.c
+
+TARGETS= ${OBJS}
+
+CINCLUDES= -I.. -I../include
+CWARNINGS= -Werror
+
+@BIND9_MAKE_RULES@
diff --git a/lib/bind/inet/inet_addr.c b/lib/bind/inet/inet_addr.c
new file mode 100644 (file)
index 0000000..c978a87
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * 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.
+ */
+
+/*
+ * 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[] = "@(#)inet_addr.c  8.1 (Berkeley) 6/17/93";
+static const char rcsid[] = "$Id: inet_addr.c,v 1.1 2001/03/29 06:31:37 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+
+#include "port_after.h"
+
+/*
+ * Ascii internet address interpretation routine.
+ * The value returned is in network order.
+ */
+u_long
+inet_addr(const char *cp) {
+       struct in_addr val;
+
+       if (inet_aton(cp, &val))
+               return (val.s_addr);
+       return (INADDR_NONE);
+}
+
+/* 
+ * 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(const char *cp, struct in_addr *addr) {
+       u_long val;
+       int base, n;
+       char c;
+       u_int8_t parts[4];
+       u_int8_t *pp = parts;
+       int digit;
+
+       c = *cp;
+       for (;;) {
+               /*
+                * Collect number up to ``.''.
+                * Values are specified as for C:
+                * 0x=hex, 0=octal, isdigit=decimal.
+                */
+               if (!isdigit(c))
+                       return (0);
+               val = 0; base = 10; digit = 0;
+               if (c == '0') {
+                       c = *++cp;
+                       if (c == 'x' || c == 'X')
+                               base = 16, c = *++cp;
+                       else {
+                               base = 8;
+                               digit = 1 ;
+                       }
+               }
+               for (;;) {
+                       if (isascii(c) && isdigit(c)) {
+                               if (base == 8 && (c == '8' || c == '9'))
+                                       return (0);
+                               val = (val * base) + (c - '0');
+                               c = *++cp;
+                               digit = 1;
+                       } else if (base == 16 && isascii(c) && isxdigit(c)) {
+                               val = (val << 4) |
+                                       (c + 10 - (islower(c) ? 'a' : 'A'));
+                               c = *++cp;
+                               digit = 1;
+                       } else
+                               break;
+               }
+               if (c == '.') {
+                       /*
+                        * 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;
+                       c = *++cp;
+               } else
+                       break;
+       }
+       /*
+        * Check for trailing characters.
+        */
+       if (c != '\0' && (!isascii(c) || !isspace(c)))
+               return (0);
+       /*
+        * Did we get a valid digit?
+        */
+       if (!digit)
+               return (0);
+       /*
+        * Concoct the address according to
+        * the number of parts specified.
+        */
+       n = pp - parts + 1;
+       switch (n) {
+       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 != NULL)
+               addr->s_addr = htonl(val);
+       return (1);
+}
diff --git a/lib/bind/inet/inet_cidr_ntop.c b/lib/bind/inet/inet_cidr_ntop.c
new file mode 100644 (file)
index 0000000..35d9f7e
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 1998,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 rcsid[] = "$Id: inet_cidr_ntop.c,v 1.1 2001/03/29 06:31:37 marka Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+static char *  inet_cidr_ntop_ipv4 __P((const u_char *src, int bits,
+                                        char *dst, size_t size));
+
+/*
+ * char *
+ * inet_cidr_ntop(af, src, bits, dst, size)
+ *     convert network address from network to presentation format.
+ *     "src"'s size is determined from its "af".
+ * return:
+ *     pointer to dst, or NULL if an error occurred (check errno).
+ * note:
+ *     192.5.5.1/28 has a nonzero host part, which means it isn't a network
+ *     as called for by inet_net_ntop() but it can be a host address with
+ *     an included netmask.
+ * author:
+ *     Paul Vixie (ISC), October 1998
+ */
+char *
+inet_cidr_ntop(int af, const void *src, int bits, char *dst, size_t size) {
+       switch (af) {
+       case AF_INET:
+               return (inet_cidr_ntop_ipv4(src, bits, dst, size));
+       default:
+               errno = EAFNOSUPPORT;
+               return (NULL);
+       }
+}
+
+/*
+ * static char *
+ * inet_cidr_ntop_ipv4(src, bits, dst, size)
+ *     convert IPv4 network address from network to presentation format.
+ *     "src"'s size is determined from its "af".
+ * return:
+ *     pointer to dst, or NULL if an error occurred (check errno).
+ * note:
+ *     network byte order assumed.  this means 192.5.5.240/28 has
+ *     0b11110000 in its fourth octet.
+ * author:
+ *     Paul Vixie (ISC), October 1998
+ */
+static char *
+inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size) {
+       char *odst = dst;
+       char *t;
+       size_t len = 4;
+       size_t b, tb;
+
+       if ((bits < -1) || (bits > 32)) {
+               errno = EINVAL;
+               return (NULL);
+       }
+
+       /* Find number of significant bytes in address. */
+       if (bits == -1)
+               len = 3;
+       else
+               for (len = 0,b = 1 ; b < 4; b++)
+                       if (*(src + b))
+                               len = b;
+
+       /* Format whole octets plus nonzero trailing octets. */
+       tb = (bits <= 0) ? 1 : (bits - 1);
+       for (b = 0; b <= (tb / 8) || (b <= len); b++) {
+               if (size < sizeof "255.")
+                       goto emsgsize;
+               t = dst;
+               dst += SPRINTF((dst, "%u", *src++));
+               if (b + 1 <= (tb / 8) || (b + 1 <= len)) {
+                       *dst++ = '.';
+                       *dst = '\0';
+               }
+               size -= (size_t)(dst - t);
+       }
+
+       if (bits != -1) {
+               /* Format CIDR /width. */
+               if (size < sizeof "/32")
+                       goto emsgsize;
+               dst += SPRINTF((dst, "/%u", bits));
+       }
+
+       return (odst);
+
+ emsgsize:
+       errno = EMSGSIZE;
+       return (NULL);
+}
diff --git a/lib/bind/inet/inet_cidr_pton.c b/lib/bind/inet/inet_cidr_pton.c
new file mode 100644 (file)
index 0000000..67e222b
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 1998,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 rcsid[] = "$Id: inet_cidr_pton.c,v 1.1 2001/03/29 06:31:37 marka Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <isc/assertions.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+static int     inet_cidr_pton_ipv4 __P((const char *src, u_char *dst,
+                                        int *bits));
+
+/*
+ * int
+ * inet_cidr_pton(af, src, dst, *bits)
+ *     convert network address from presentation to network format.
+ *     accepts inet_pton()'s input for this "af" plus trailing "/CIDR".
+ *     "dst" is assumed large enough for its "af".  "bits" is set to the
+ *     /CIDR prefix length, which can have defaults (like /32 for IPv4).
+ * return:
+ *     -1 if an error occurred (inspect errno; ENOENT means bad format).
+ *     0 if successful conversion occurred.
+ * note:
+ *     192.5.5.1/28 has a nonzero host part, which means it isn't a network
+ *     as called for by inet_net_pton() but it can be a host address with
+ *     an included netmask.
+ * author:
+ *     Paul Vixie (ISC), October 1998
+ */
+int
+inet_cidr_pton(int af, const char *src, void *dst, int *bits) {
+       switch (af) {
+       case AF_INET:
+               return (inet_cidr_pton_ipv4(src, dst, bits));
+       default:
+               errno = EAFNOSUPPORT;
+               return (-1);
+       }
+}
+
+static int
+inet_cidr_pton_ipv4(const char *src, u_char *dst, int *pbits) {
+       static const char digits[] = "0123456789";
+       const u_char *odst = dst;
+       int n, ch, tmp, bits;
+       size_t size = 4;
+
+       /* Get the mantissa. */
+       while (ch = *src++, (isascii(ch) && isdigit(ch))) {
+               tmp = 0;
+               do {
+                       n = strchr(digits, ch) - digits;
+                       INSIST(n >= 0 && n <= 9);
+                       tmp *= 10;
+                       tmp += n;
+                       if (tmp > 255)
+                               goto enoent;
+               } while ((ch = *src++) != '\0' && isascii(ch) && isdigit(ch));
+               if (size-- == 0)
+                       goto emsgsize;
+               *dst++ = (u_char) tmp;
+               if (ch == '\0' || ch == '/')
+                       break;
+               if (ch != '.')
+                       goto enoent;
+       }
+
+       /* Get the prefix length if any. */
+       bits = -1;
+       if (ch == '/' && isascii(src[0]) && isdigit(src[0]) && dst > odst) {
+               /* CIDR width specifier.  Nothing can follow it. */
+               ch = *src++;    /* Skip over the /. */
+               bits = 0;
+               do {
+                       n = strchr(digits, ch) - digits;
+                       INSIST(n >= 0 && n <= 9);
+                       bits *= 10;
+                       bits += n;
+               } while ((ch = *src++) != '\0' && isascii(ch) && isdigit(ch));
+               if (ch != '\0')
+                       goto enoent;
+               if (bits > 32)
+                       goto emsgsize;
+       }
+
+       /* Firey death and destruction unless we prefetched EOS. */
+       if (ch != '\0')
+               goto enoent;
+
+       /* Prefix length can default to /32 only if all four octets spec'd. */
+       if (bits == -1) {
+               if (dst - odst == 4)
+                       bits = 32;
+               else
+                       goto enoent;
+       }
+
+       /* If nothing was written to the destination, we found no address. */
+       if (dst == odst)
+               goto enoent;
+
+       /* If prefix length overspecifies mantissa, life is bad. */
+       if ((bits / 8) > (dst - odst))
+               goto enoent;
+
+       /* Extend address to four octets. */
+       while (size-- > 0)
+               *dst++ = 0;
+
+       *pbits = bits;
+       return (0);
+
+ enoent:
+       errno = ENOENT;
+       return (-1);
+
+ emsgsize:
+       errno = EMSGSIZE;
+       return (-1);
+}
diff --git a/lib/bind/inet/inet_data.c b/lib/bind/inet/inet_data.c
new file mode 100644 (file)
index 0000000..197ee67
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char rcsid[] = "$Id: inet_data.c,v 1.1 2001/03/29 06:31:37 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+
+#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 <arpa/nameser.h>
+
+#include <ctype.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "port_after.h"
+
+#ifndef IN6ADDR_ANY_INIT
+#define        IN6ADDR_ANY_INIT        {{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}
+#endif
+#ifndef IN6ADDR_LOOPBACK_INIT
+#define        IN6ADDR_LOOPBACK_INIT   {{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}}
+#endif
+
+
+#ifndef HAS_INET6_STRUCTS
+const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
+const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
+#endif
diff --git a/lib/bind/inet/inet_lnaof.c b/lib/bind/inet/inet_lnaof.c
new file mode 100644 (file)
index 0000000..97b80cf
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 1983, 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)
+static const char sccsid[] = "@(#)inet_lnaof.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "port_after.h"
+
+/*
+ * Return the local network address portion of an
+ * internet address; handles class a/b/c network
+ * number formats.
+ */
+u_long
+inet_lnaof(in)
+       struct in_addr in;
+{
+       register u_long i = ntohl(in.s_addr);
+
+       if (IN_CLASSA(i))
+               return ((i)&IN_CLASSA_HOST);
+       else if (IN_CLASSB(i))
+               return ((i)&IN_CLASSB_HOST);
+       else
+               return ((i)&IN_CLASSC_HOST);
+}
diff --git a/lib/bind/inet/inet_makeaddr.c b/lib/bind/inet/inet_makeaddr.c
new file mode 100644 (file)
index 0000000..49ea023
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 1983, 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)
+static const char sccsid[] = "@(#)inet_makeaddr.c      8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "port_after.h"
+
+/*
+ * Formulate an Internet address from network + host.  Used in
+ * building addresses stored in the ifnet structure.
+ */
+struct in_addr
+inet_makeaddr(net, host)
+       u_long net, host;
+{
+       u_long addr;
+
+       if (net < 128)
+               addr = (net << IN_CLASSA_NSHIFT) | (host & IN_CLASSA_HOST);
+       else if (net < 65536)
+               addr = (net << IN_CLASSB_NSHIFT) | (host & IN_CLASSB_HOST);
+       else if (net < 16777216L)
+               addr = (net << IN_CLASSC_NSHIFT) | (host & IN_CLASSC_HOST);
+       else
+               addr = net | host;
+       addr = htonl(addr);
+       return (*(struct in_addr *)&addr);
+}
diff --git a/lib/bind/inet/inet_net_ntop.c b/lib/bind/inet/inet_net_ntop.c
new file mode 100644 (file)
index 0000000..ee6de06
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * 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 rcsid[] = "$Id: inet_net_ntop.c,v 1.1 2001/03/29 06:31:38 marka Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+static char *  inet_net_ntop_ipv4 __P((const u_char *src, int bits,
+                                       char *dst, size_t size));
+
+/*
+ * char *
+ * inet_net_ntop(af, src, bits, dst, size)
+ *     convert network number from network to presentation format.
+ *     generates CIDR style result always.
+ * return:
+ *     pointer to dst, or NULL if an error occurred (check errno).
+ * author:
+ *     Paul Vixie (ISC), July 1996
+ */
+char *
+inet_net_ntop(af, src, bits, dst, size)
+       int af;
+       const void *src;
+       int bits;
+       char *dst;
+       size_t size;
+{
+       switch (af) {
+       case AF_INET:
+               return (inet_net_ntop_ipv4(src, bits, dst, size));
+       default:
+               errno = EAFNOSUPPORT;
+               return (NULL);
+       }
+}
+
+/*
+ * static char *
+ * inet_net_ntop_ipv4(src, bits, dst, size)
+ *     convert IPv4 network number from network to presentation format.
+ *     generates CIDR style result always.
+ * return:
+ *     pointer to dst, or NULL if an error occurred (check errno).
+ * note:
+ *     network byte order assumed.  this means 192.5.5.240/28 has
+ *     0b11110000 in its fourth octet.
+ * author:
+ *     Paul Vixie (ISC), July 1996
+ */
+static char *
+inet_net_ntop_ipv4(src, bits, dst, size)
+       const u_char *src;
+       int bits;
+       char *dst;
+       size_t size;
+{
+       char *odst = dst;
+       char *t;
+       u_int m;
+       int b;
+
+       if (bits < 0 || bits > 32) {
+               errno = EINVAL;
+               return (NULL);
+       }
+       if (bits == 0) {
+               if (size < sizeof "0")
+                       goto emsgsize;
+               *dst++ = '0';
+               size--;
+               *dst = '\0';
+       }
+
+       /* Format whole octets. */
+       for (b = bits / 8; b > 0; b--) {
+               if (size <= sizeof "255.")
+                       goto emsgsize;
+               t = dst;
+               dst += SPRINTF((dst, "%u", *src++));
+               if (b > 1) {
+                       *dst++ = '.';
+                       *dst = '\0';
+               }
+               size -= (size_t)(dst - t);
+       }
+
+       /* Format partial octet. */
+       b = bits % 8;
+       if (b > 0) {
+               if (size <= sizeof ".255")
+                       goto emsgsize;
+               t = dst;
+               if (dst != odst)
+                       *dst++ = '.';
+               m = ((1 << b) - 1) << (8 - b);
+               dst += SPRINTF((dst, "%u", *src & m));
+               size -= (size_t)(dst - t);
+       }
+
+       /* Format CIDR /width. */
+       if (size <= sizeof "/32")
+               goto emsgsize;
+       dst += SPRINTF((dst, "/%u", bits));
+       return (odst);
+
+ emsgsize:
+       errno = EMSGSIZE;
+       return (NULL);
+}
diff --git a/lib/bind/inet/inet_net_pton.c b/lib/bind/inet/inet_net_pton.c
new file mode 100644 (file)
index 0000000..523af34
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * 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 rcsid[] = "$Id: inet_net_pton.c,v 1.1 2001/03/29 06:31:38 marka Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <isc/assertions.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+static int     inet_net_pton_ipv4 __P((const char *src, u_char *dst,
+                                       size_t size));
+
+/*
+ * static int
+ * inet_net_pton(af, src, dst, size)
+ *     convert network number from presentation to network format.
+ *     accepts hex octets, hex strings, decimal octets, and /CIDR.
+ *     "size" is in bytes and describes "dst".
+ * return:
+ *     number of bits, either imputed classfully or specified with /CIDR,
+ *     or -1 if some failure occurred (check errno).  ENOENT means it was
+ *     not a valid network specification.
+ * author:
+ *     Paul Vixie (ISC), June 1996
+ */
+int
+inet_net_pton(af, src, dst, size)
+       int af;
+       const char *src;
+       void *dst;
+       size_t size;
+{
+       switch (af) {
+       case AF_INET:
+               return (inet_net_pton_ipv4(src, dst, size));
+       default:
+               errno = EAFNOSUPPORT;
+               return (-1);
+       }
+}
+
+/*
+ * static int
+ * inet_net_pton_ipv4(src, dst, size)
+ *     convert IPv4 network number from presentation to network format.
+ *     accepts hex octets, hex strings, decimal octets, and /CIDR.
+ *     "size" is in bytes and describes "dst".
+ * return:
+ *     number of bits, either imputed classfully or specified with /CIDR,
+ *     or -1 if some failure occurred (check errno).  ENOENT means it was
+ *     not an IPv4 network specification.
+ * note:
+ *     network byte order assumed.  this means 192.5.5.240/28 has
+ *     0b11110000 in its fourth octet.
+ * author:
+ *     Paul Vixie (ISC), June 1996
+ */
+static int
+inet_net_pton_ipv4(src, dst, size)
+       const char *src;
+       u_char *dst;
+       size_t size;
+{
+       static const char
+               xdigits[] = "0123456789abcdef",
+               digits[] = "0123456789";
+       int n, ch, tmp = 0, dirty, bits;
+       const u_char *odst = dst;
+
+       ch = *src++;
+       if (ch == '0' && (src[0] == 'x' || src[0] == 'X')
+           && isascii(src[1]) && isxdigit(src[1])) {
+               /* Hexadecimal: Eat nybble string. */
+               if (size <= 0)
+                       goto emsgsize;
+               dirty = 0;
+               src++;  /* skip x or X. */
+               while ((ch = *src++) != '\0' && isascii(ch) && isxdigit(ch)) {
+                       if (isupper(ch))
+                               ch = tolower(ch);
+                       n = strchr(xdigits, ch) - xdigits;
+                       INSIST(n >= 0 && n <= 15);
+                       if (dirty == 0)
+                               tmp = n;
+                       else
+                               tmp = (tmp << 4) | n;
+                       if (++dirty == 2) {
+                               if (size-- <= 0)
+                                       goto emsgsize;
+                               *dst++ = (u_char) tmp;
+                               dirty = 0;
+                       }
+               }
+               if (dirty) {  /* Odd trailing nybble? */
+                       if (size-- <= 0)
+                               goto emsgsize;
+                       *dst++ = (u_char) (tmp << 4);
+               }
+       } else if (isascii(ch) && isdigit(ch)) {
+               /* Decimal: eat dotted digit string. */
+               for (;;) {
+                       tmp = 0;
+                       do {
+                               n = strchr(digits, ch) - digits;
+                               INSIST(n >= 0 && n <= 9);
+                               tmp *= 10;
+                               tmp += n;
+                               if (tmp > 255)
+                                       goto enoent;
+                       } while ((ch = *src++) != '\0' &&
+                                isascii(ch) && isdigit(ch));
+                       if (size-- <= 0)
+                               goto emsgsize;
+                       *dst++ = (u_char) tmp;
+                       if (ch == '\0' || ch == '/')
+                               break;
+                       if (ch != '.')
+                               goto enoent;
+                       ch = *src++;
+                       if (!isascii(ch) || !isdigit(ch))
+                               goto enoent;
+               }
+       } else
+               goto enoent;
+
+       bits = -1;
+       if (ch == '/' && isascii(src[0]) && isdigit(src[0]) && dst > odst) {
+               /* CIDR width specifier.  Nothing can follow it. */
+               ch = *src++;    /* Skip over the /. */
+               bits = 0;
+               do {
+                       n = strchr(digits, ch) - digits;
+                       INSIST(n >= 0 && n <= 9);
+                       bits *= 10;
+                       bits += n;
+               } while ((ch = *src++) != '\0' && isascii(ch) && isdigit(ch));
+               if (ch != '\0')
+                       goto enoent;
+               if (bits > 32)
+                       goto emsgsize;
+       }
+
+       /* Firey death and destruction unless we prefetched EOS. */
+       if (ch != '\0')
+               goto enoent;
+
+       /* If nothing was written to the destination, we found no address. */
+       if (dst == odst)
+               goto enoent;
+       /* If no CIDR spec was given, infer width from net class. */
+       if (bits == -1) {
+               if (*odst >= 240)       /* Class E */
+                       bits = 32;
+               else if (*odst >= 224)  /* Class D */
+                       bits = 4;
+               else if (*odst >= 192)  /* Class C */
+                       bits = 24;
+               else if (*odst >= 128)  /* Class B */
+                       bits = 16;
+               else                    /* Class A */
+                       bits = 8;
+               /* If imputed mask is narrower than specified octets, widen. */
+               if (bits >= 8 && bits < ((dst - odst) * 8))
+                       bits = (dst - odst) * 8;
+       }
+       /* Extend network to cover the actual mask. */
+       while (bits > ((dst - odst) * 8)) {
+               if (size-- <= 0)
+                       goto emsgsize;
+               *dst++ = '\0';
+       }
+       return (bits);
+
+ enoent:
+       errno = ENOENT;
+       return (-1);
+
+ emsgsize:
+       errno = EMSGSIZE;
+       return (-1);
+}
diff --git a/lib/bind/inet/inet_neta.c b/lib/bind/inet/inet_neta.c
new file mode 100644 (file)
index 0000000..0f6124a
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * 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 rcsid[] = "$Id: inet_neta.c,v 1.1 2001/03/29 06:31:38 marka Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+/*
+ * char *
+ * inet_neta(src, dst, size)
+ *     format a u_long network number into presentation format.
+ * return:
+ *     pointer to dst, or NULL if an error occurred (check errno).
+ * note:
+ *     format of ``src'' is as for inet_network().
+ * author:
+ *     Paul Vixie (ISC), July 1996
+ */
+char *
+inet_neta(src, dst, size)
+       u_long src;
+       char *dst;
+       size_t size;
+{
+       char *odst = dst;
+       char *tp;
+
+       while (src & 0xffffffff) {
+               u_char b = (src & 0xff000000) >> 24;
+
+               src <<= 8;
+               if (b) {
+                       if (size < sizeof "255.")
+                               goto emsgsize;
+                       tp = dst;
+                       dst += SPRINTF((dst, "%u", b));
+                       if (src != 0L) {
+                               *dst++ = '.';
+                               *dst = '\0';
+                       }
+                       size -= (size_t)(dst - tp);
+               }
+       }
+       if (dst == odst) {
+               if (size < sizeof "0.0.0.0")
+                       goto emsgsize;
+               strcpy(dst, "0.0.0.0");
+       }
+       return (odst);
+
+ emsgsize:
+       errno = EMSGSIZE;
+       return (NULL);
+}
diff --git a/lib/bind/inet/inet_netof.c b/lib/bind/inet/inet_netof.c
new file mode 100644 (file)
index 0000000..e887530
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 1983, 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)
+static const char sccsid[] = "@(#)inet_netof.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "port_after.h"
+
+/*
+ * Return the network number from an internet
+ * address; handles class a/b/c network #'s.
+ */
+u_long
+inet_netof(in)
+       struct in_addr in;
+{
+       register u_long i = ntohl(in.s_addr);
+
+       if (IN_CLASSA(i))
+               return (((i)&IN_CLASSA_NET) >> IN_CLASSA_NSHIFT);
+       else if (IN_CLASSB(i))
+               return (((i)&IN_CLASSB_NET) >> IN_CLASSB_NSHIFT);
+       else
+               return (((i)&IN_CLASSC_NET) >> IN_CLASSC_NSHIFT);
+}
diff --git a/lib/bind/inet/inet_network.c b/lib/bind/inet/inet_network.c
new file mode 100644 (file)
index 0000000..d26369c
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 1983, 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)
+static const char sccsid[] = "@(#)inet_network.c       8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+
+#include "port_after.h"
+
+/*
+ * Internet network address interpretation routine.
+ * The library routines call this routine to interpret
+ * network numbers.
+ */
+u_long
+inet_network(cp)
+       register const char *cp;
+{
+       register u_long val, base, n, i;
+       register char c;
+       u_long parts[4], *pp = parts;
+       int digit;
+
+again:
+       val = 0; base = 10; digit = 0;
+       if (*cp == '0')
+               digit = 1, base = 8, cp++;
+       if (*cp == 'x' || *cp == 'X')
+               base = 16, cp++;
+       while ((c = *cp) != 0) {
+               if (isdigit(c)) {
+                       if (base == 8 && (c == '8' || c == '9'))
+                               return (INADDR_NONE);
+                       val = (val * base) + (c - '0');
+                       cp++;
+                       digit = 1;
+                       continue;
+               }
+               if (base == 16 && isxdigit(c)) {
+                       val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A'));
+                       cp++;
+                       digit = 1;
+                       continue;
+               }
+               break;
+       }
+       if (!digit)
+               return (INADDR_NONE);
+       if (*cp == '.') {
+               if (pp >= parts + 4 || val > 0xff)
+                       return (INADDR_NONE);
+               *pp++ = val, cp++;
+               goto again;
+       }
+       if (*cp && !isspace(*cp))
+               return (INADDR_NONE);
+       *pp++ = val;
+       n = pp - parts;
+       if (n > 4)
+               return (INADDR_NONE);
+       for (val = 0, i = 0; i < n; i++) {
+               val <<= 8;
+               val |= parts[i] & 0xff;
+       }
+       return (val);
+}
diff --git a/lib/bind/inet/inet_ntoa.c b/lib/bind/inet/inet_ntoa.c
new file mode 100644 (file)
index 0000000..7fad4b8
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 1983, 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)
+static const char sccsid[] = "@(#)inet_ntoa.c  8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: inet_ntoa.c,v 1.1 2001/03/29 06:31:38 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include "port_after.h"
+
+/*
+ * Convert network-format internet address
+ * to base 256 d.d.d.d representation.
+ */
+/*const*/ char *
+inet_ntoa(struct in_addr in) {
+       static char ret[18];
+
+       strcpy(ret, "[inet_ntoa error]");
+       (void) inet_ntop(AF_INET, &in, ret, sizeof ret);
+       return (ret);
+}
diff --git a/lib/bind/inet/inet_ntop.c b/lib/bind/inet/inet_ntop.c
new file mode 100644 (file)
index 0000000..27d558e
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * 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 rcsid[] = "$Id: inet_ntop.c,v 1.1 2001/03/29 06:31:39 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+/*
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+static const char *inet_ntop4 __P((const u_char *src, char *dst, size_t size));
+static const char *inet_ntop6 __P((const u_char *src, char *dst, size_t size));
+
+/* char *
+ * inet_ntop(af, src, dst, size)
+ *     convert a network format address to presentation format.
+ * return:
+ *     pointer to presentation format address (`dst'), or NULL (see errno).
+ * author:
+ *     Paul Vixie, 1996.
+ */
+const char *
+inet_ntop(af, src, dst, size)
+       int af;
+       const void *src;
+       char *dst;
+       size_t size;
+{
+       switch (af) {
+       case AF_INET:
+               return (inet_ntop4(src, dst, size));
+       case AF_INET6:
+               return (inet_ntop6(src, dst, size));
+       default:
+               errno = EAFNOSUPPORT;
+               return (NULL);
+       }
+       /* NOTREACHED */
+}
+
+/* const char *
+ * inet_ntop4(src, dst, size)
+ *     format an IPv4 address
+ * return:
+ *     `dst' (as a const)
+ * notes:
+ *     (1) uses no statics
+ *     (2) takes a u_char* not an in_addr as input
+ * author:
+ *     Paul Vixie, 1996.
+ */
+static const char *
+inet_ntop4(src, dst, size)
+       const u_char *src;
+       char *dst;
+       size_t size;
+{
+       static const char fmt[] = "%u.%u.%u.%u";
+       char tmp[sizeof "255.255.255.255"];
+
+       if (SPRINTF((tmp, fmt, src[0], src[1], src[2], src[3])) >= size) {
+               errno = ENOSPC;
+               return (NULL);
+       }
+       strcpy(dst, tmp);
+       return (dst);
+}
+
+/* const char *
+ * inet_ntop6(src, dst, size)
+ *     convert IPv6 binary address into presentation (printable) format
+ * author:
+ *     Paul Vixie, 1996.
+ */
+static const char *
+inet_ntop6(src, dst, size)
+       const u_char *src;
+       char *dst;
+       size_t size;
+{
+       /*
+        * Note that int32_t and int16_t need only be "at least" large enough
+        * to contain a value of the specified size.  On some systems, like
+        * Crays, there is no such thing as an integer variable with 16 bits.
+        * Keep this in mind if you think this function should have been coded
+        * to use pointer overlays.  All the world's not a VAX.
+        */
+       char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
+       struct { int base, len; } best, cur;
+       u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
+       int i;
+
+       /*
+        * Preprocess:
+        *      Copy the input (bytewise) array into a wordwise array.
+        *      Find the longest run of 0x00's in src[] for :: shorthanding.
+        */
+       memset(words, '\0', sizeof words);
+       for (i = 0; i < NS_IN6ADDRSZ; i++)
+               words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
+       best.base = -1;
+       cur.base = -1;
+       for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
+               if (words[i] == 0) {
+                       if (cur.base == -1)
+                               cur.base = i, cur.len = 1;
+                       else
+                               cur.len++;
+               } else {
+                       if (cur.base != -1) {
+                               if (best.base == -1 || cur.len > best.len)
+                                       best = cur;
+                               cur.base = -1;
+                       }
+               }
+       }
+       if (cur.base != -1) {
+               if (best.base == -1 || cur.len > best.len)
+                       best = cur;
+       }
+       if (best.base != -1 && best.len < 2)
+               best.base = -1;
+
+       /*
+        * Format the result.
+        */
+       tp = tmp;
+       for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
+               /* Are we inside the best run of 0x00's? */
+               if (best.base != -1 && i >= best.base &&
+                   i < (best.base + best.len)) {
+                       if (i == best.base)
+                               *tp++ = ':';
+                       continue;
+               }
+               /* Are we following an initial run of 0x00s or any real hex? */
+               if (i != 0)
+                       *tp++ = ':';
+               /* Is this address an encapsulated IPv4? */
+               if (i == 6 && best.base == 0 &&
+                   (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
+                       if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)))
+                               return (NULL);
+                       tp += strlen(tp);
+                       break;
+               }
+               tp += SPRINTF((tp, "%x", words[i]));
+       }
+       /* Was it a trailing run of 0x00's? */
+       if (best.base != -1 && (best.base + best.len) == 
+           (NS_IN6ADDRSZ / NS_INT16SZ))
+               *tp++ = ':';
+       *tp++ = '\0';
+
+       /*
+        * Check for overflow, copy, and we're done.
+        */
+       if ((size_t)(tp - tmp) > size) {
+               errno = ENOSPC;
+               return (NULL);
+       }
+       strcpy(dst, tmp);
+       return (dst);
+}
diff --git a/lib/bind/inet/inet_pton.c b/lib/bind/inet/inet_pton.c
new file mode 100644 (file)
index 0000000..6939843
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * 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 rcsid[] = "$Id: inet_pton.c,v 1.1 2001/03/29 06:31:41 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <string.h>
+#include <errno.h>
+#include "port_after.h"
+
+/*
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+static int     inet_pton4 __P((const char *src, u_char *dst));
+static int     inet_pton6 __P((const char *src, u_char *dst));
+
+/* int
+ * inet_pton(af, src, dst)
+ *     convert from presentation format (which usually means ASCII printable)
+ *     to network format (which is usually some kind of binary format).
+ * return:
+ *     1 if the address was valid for the specified address family
+ *     0 if the address wasn't valid (`dst' is untouched in this case)
+ *     -1 if some other error occurred (`dst' is untouched in this case, too)
+ * author:
+ *     Paul Vixie, 1996.
+ */
+int
+inet_pton(af, src, dst)
+       int af;
+       const char *src;
+       void *dst;
+{
+       switch (af) {
+       case AF_INET:
+               return (inet_pton4(src, dst));
+       case AF_INET6:
+               return (inet_pton6(src, dst));
+       default:
+               errno = EAFNOSUPPORT;
+               return (-1);
+       }
+       /* NOTREACHED */
+}
+
+/* int
+ * inet_pton4(src, dst)
+ *     like inet_aton() but without all the hexadecimal and shorthand.
+ * return:
+ *     1 if `src' is a valid dotted quad, else 0.
+ * notice:
+ *     does not touch `dst' unless it's returning 1.
+ * author:
+ *     Paul Vixie, 1996.
+ */
+static int
+inet_pton4(src, dst)
+       const char *src;
+       u_char *dst;
+{
+       static const char digits[] = "0123456789";
+       int saw_digit, octets, ch;
+       u_char tmp[NS_INADDRSZ], *tp;
+
+       saw_digit = 0;
+       octets = 0;
+       *(tp = tmp) = 0;
+       while ((ch = *src++) != '\0') {
+               const char *pch;
+
+               if ((pch = strchr(digits, ch)) != NULL) {
+                       u_int new = *tp * 10 + (pch - digits);
+
+                       if (new > 255)
+                               return (0);
+                       *tp = new;
+                       if (! saw_digit) {
+                               if (++octets > 4)
+                                       return (0);
+                               saw_digit = 1;
+                       }
+               } else if (ch == '.' && saw_digit) {
+                       if (octets == 4)
+                               return (0);
+                       *++tp = 0;
+                       saw_digit = 0;
+               } else
+                       return (0);
+       }
+       if (octets < 4)
+               return (0);
+       memcpy(dst, tmp, NS_INADDRSZ);
+       return (1);
+}
+
+/* int
+ * inet_pton6(src, dst)
+ *     convert presentation level address to network order binary form.
+ * return:
+ *     1 if `src' is a valid [RFC1884 2.2] address, else 0.
+ * notice:
+ *     (1) does not touch `dst' unless it's returning 1.
+ *     (2) :: in a full address is silently ignored.
+ * credit:
+ *     inspired by Mark Andrews.
+ * author:
+ *     Paul Vixie, 1996.
+ */
+static int
+inet_pton6(src, dst)
+       const char *src;
+       u_char *dst;
+{
+       static const char xdigits_l[] = "0123456789abcdef",
+                         xdigits_u[] = "0123456789ABCDEF";
+       u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
+       const char *xdigits, *curtok;
+       int ch, saw_xdigit;
+       u_int val;
+
+       memset((tp = tmp), '\0', NS_IN6ADDRSZ);
+       endp = tp + NS_IN6ADDRSZ;
+       colonp = NULL;
+       /* Leading :: requires some special handling. */
+       if (*src == ':')
+               if (*++src != ':')
+                       return (0);
+       curtok = src;
+       saw_xdigit = 0;
+       val = 0;
+       while ((ch = *src++) != '\0') {
+               const char *pch;
+
+               if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
+                       pch = strchr((xdigits = xdigits_u), ch);
+               if (pch != NULL) {
+                       val <<= 4;
+                       val |= (pch - xdigits);
+                       if (val > 0xffff)
+                               return (0);
+                       saw_xdigit = 1;
+                       continue;
+               }
+               if (ch == ':') {
+                       curtok = src;
+                       if (!saw_xdigit) {
+                               if (colonp)
+                                       return (0);
+                               colonp = tp;
+                               continue;
+                       } else if (*src == '\0') {
+                               return (0);
+                       }
+                       if (tp + NS_INT16SZ > endp)
+                               return (0);
+                       *tp++ = (u_char) (val >> 8) & 0xff;
+                       *tp++ = (u_char) val & 0xff;
+                       saw_xdigit = 0;
+                       val = 0;
+                       continue;
+               }
+               if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
+                   inet_pton4(curtok, tp) > 0) {
+                       tp += NS_INADDRSZ;
+                       saw_xdigit = 0;
+                       break;  /* '\0' was seen by inet_pton4(). */
+               }
+               return (0);
+       }
+       if (saw_xdigit) {
+               if (tp + NS_INT16SZ > endp)
+                       return (0);
+               *tp++ = (u_char) (val >> 8) & 0xff;
+               *tp++ = (u_char) val & 0xff;
+       }
+       if (colonp != NULL) {
+               /*
+                * Since some memmove()'s erroneously fail to handle
+                * overlapping regions, we'll do the shift by hand.
+                */
+               const int n = tp - colonp;
+               int i;
+
+               if (tp == endp)
+                       return (0);
+               for (i = 1; i <= n; i++) {
+                       endp[- i] = colonp[n - i];
+                       colonp[n - i] = 0;
+               }
+               tp = endp;
+       }
+       if (tp != endp)
+               return (0);
+       memcpy(dst, tmp, NS_IN6ADDRSZ);
+       return (1);
+}
diff --git a/lib/bind/inet/nsap_addr.c b/lib/bind/inet/nsap_addr.c
new file mode 100644 (file)
index 0000000..f6a6d67
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * 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 DISCLAI!
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANT!
+ * 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 TH!
+ * SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: nsap_addr.c,v 1.1 2001/03/29 06:31:41 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <resolv.h>
+
+#include "port_after.h"
+
+static char
+xtob(int c) {
+       return (c - (((c >= '0') && (c <= '9')) ? '0' : '7'));
+}
+
+u_int
+inet_nsap_addr(const char *ascii, u_char *binary, int maxlen) {
+       u_char c, nib;
+       u_int len = 0;
+
+       while ((c = *ascii++) != '\0' && len < (u_int)maxlen) {
+               if (c == '.' || c == '+' || c == '/')
+                       continue;
+               if (!isascii(c))
+                       return (0);
+               if (islower(c))
+                       c = toupper(c);
+               if (isxdigit(c)) {
+                       nib = xtob(c);
+                       c = *ascii++;
+                       if (c != '\0') {
+                               c = toupper(c);
+                               if (isxdigit(c)) {
+                                       *binary++ = (nib << 4) | xtob(c);
+                                       len++;
+                               } else
+                                       return (0);
+                       }
+                       else
+                               return (0);
+               }
+               else
+                       return (0);
+       }
+       return (len);
+}
+
+char *
+inet_nsap_ntoa(int binlen, const u_char *binary, char *ascii) {
+       int nib;
+       int i;
+       static char tmpbuf[255*3];
+       char *start;
+
+       if (ascii)
+               start = ascii;
+       else {
+               ascii = tmpbuf;
+               start = tmpbuf;
+       }
+
+       if (binlen > 255)
+               binlen = 255;
+
+       for (i = 0; i < binlen; i++) {
+               nib = *binary >> 4;
+               *ascii++ = nib + (nib < 10 ? '0' : '7');
+               nib = *binary++ & 0x0f;
+               *ascii++ = nib + (nib < 10 ? '0' : '7');
+               if (((i % 2) == 0 && (i + 1) < binlen))
+                       *ascii++ = '.';
+       }
+       *ascii = '\0';
+       return (start);
+}
diff --git a/lib/bind/irs/Makefile.in b/lib/bind/irs/Makefile.in
new file mode 100644 (file)
index 0000000..69bd9c6
--- /dev/null
@@ -0,0 +1,49 @@
+WANT_IRS_THREADS_OBJS= gethostent_r.@O@ getnetgrent_r.@O@ \
+       getprotoent_r.@O@ getservent_r.@O@
+
+WANT_IRS_NISGR_OBJ= nis_gr.@O@ 
+WANT_IRS_GR_OBJS= dns_gr.@O@ irp_gr.@O@ lcl_gr.@O@ gen_gr.@O@ getgrent.@O@ \
+       @WANT_IRS_NISGR_OBJS@ @WANT_IRS_THREADSGR_OBJS@
+
+WANT_IRS_THREADSPW_OBJS=getpwent_r.@O@
+WANT_IRS_NISPW_OBJS= nis_pw.@O@
+WANT_IRS_PW_OBJS= dns_pw.@O@ irp_pw.@O@ lcl_pw.@O@ gen_pw.@O@ getpwent.@O@ \
+       @WANT_IRS_NISPW_OBJS@ @WANT_IRS_THREADSPW_OBJS@
+
+WANT_IRS_NIS_OBJS= \
+       nis_ho.@O@ nis_ng.@O@ nis_nw.@O@ nis_pr.@O@ nis_sv.@O@
+
+OBJS=  @WANT_IRS_GR_OBJS@ @WANT_IRS_NIS_OBJS@ @WANT_IRS_THREADS_OBJS@ \
+       dns.@O@ dns_ho.@O@ dns_nw.@O@ dns_pr.@O@ \
+       dns_sv.@O@ gai_strerror.@O@ gen.@O@ gen_ho.@O@ \
+       gen_ng.@O@ gen_nw.@O@ gen_pr.@O@ gen_sv.@O@ \
+       getaddrinfo.@O@ gethostent.@O@ \
+       getnameinfo.@O@ getnetent.@O@ getnetent_r.@O@ \
+       getnetgrent.@O@ getprotoent.@O@ getservent.@O@ \
+       hesiod.@O@ irp.@O@ irp_ho.@O@ irp_ng.@O@ irp_nw.@O@ \
+       irp_pr.@O@ irp_sv.@O@ irpmarshall.@O@ irs_data.@O@ \
+       lcl.@O@ lcl_ho.@O@ lcl_ng.@O@ lcl_nw.@O@ lcl_pr.@O@ \
+       lcl_sv.@O@ nis.@O@ nul_ng.@O@ util.@O@
+
+SRCS=  dns.c dns_gr.c dns_ho.c dns_nw.c dns_pr.c dns_pw.c \
+       dns_sv.c gai_strerror.c gen.c gen_gr.c gen_ho.c \
+       gen_ng.c gen_nw.c gen_pr.c gen_pw.c gen_sv.c \
+       getaddrinfo.c getgrent.c gethostent.c \
+       getnameinfo.c getnetent.c getnetent_r.c \
+       getnetgrent.c getprotoent.c getpwent.c getservent.c \
+       hesiod.c irp.c irp_gr.c irp_ho.c irp_ng.c irp_nw.c \
+       irp_pr.c irp_pw.c irp_sv.c irpmarshall.c irs_data.c \
+       lcl.c lcl_gr.c lcl_ho.c lcl_ng.c lcl_nw.c lcl_pr.c \
+       lcl_pw.c lcl_sv.c nis.c nis_gr.c nis_ho.c nis_ng.c \
+       nis_nw.c nis_pr.c nis_pw.c nis_sv.c nul_ng.c \
+       util.c getgrent_r.c gethostent_r.c getnetgrent_r.c getprotoent_r.c \
+       getpwent_r.c getservent_r.c
+
+WANT_IRS_THREADSGR_OBJS=getgrent_r.@O@
+
+TARGETS= ${OBJS}
+
+CINCLUDES= -I.. -I../include
+CWARNINGS= -Werror
+
+@BIND9_MAKE_RULES@
diff --git a/lib/bind/irs/dns.c b/lib/bind/irs/dns.c
new file mode 100644 (file)
index 0000000..1077623
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * 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 rcsid[] = "$Id: dns.c,v 1.1 2001/03/29 06:31:42 marka Exp $";
+#endif
+
+/*
+ * dns.c --- this is the top-level accessor function for the dns
+ */
+
+#include "port_before.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <resolv.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "hesiod.h"
+#include "dns_p.h"
+
+/* forward */
+
+static void            dns_close(struct irs_acc *);
+static struct __res_state *    dns_res_get(struct irs_acc *);
+static void            dns_res_set(struct irs_acc *, struct __res_state *,
+                               void (*)(void *));
+
+/* public */
+
+struct irs_acc *
+irs_dns_acc(const char *options) {
+       struct irs_acc *acc;
+       struct dns_p *dns;
+
+       UNUSED(options);
+
+       if (!(acc = memget(sizeof *acc))) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(acc, 0x5e, sizeof *acc);
+       if (!(dns = memget(sizeof *dns))) {
+               errno = ENOMEM;
+               memput(acc, sizeof *acc);
+               return (NULL);
+       }
+       memset(dns, 0x5e, sizeof *dns);
+       dns->res = NULL;
+       dns->free_res = NULL;
+       if (hesiod_init(&dns->hes_ctx) < 0) {
+               /*
+                * We allow the dns accessor class to initialize
+                * despite hesiod failing to initialize correctly,
+                * since dns host queries don't depend on hesiod.
+                */
+               dns->hes_ctx = NULL;
+       }
+       acc->private = dns;
+#ifdef WANT_IRS_GR
+       acc->gr_map = irs_dns_gr;
+#else
+       acc->gr_map = NULL;
+#endif
+#ifdef WANT_IRS_PW
+       acc->pw_map = irs_dns_pw;
+#else
+       acc->pw_map = NULL;
+#endif
+       acc->sv_map = irs_dns_sv;
+       acc->pr_map = irs_dns_pr;
+       acc->ho_map = irs_dns_ho;
+       acc->nw_map = irs_dns_nw;
+       acc->ng_map = irs_nul_ng;
+       acc->res_get = dns_res_get;
+       acc->res_set = dns_res_set;
+       acc->close = dns_close;
+       return (acc);
+}
+
+/* methods */
+static struct __res_state *
+dns_res_get(struct irs_acc *this) {
+       struct dns_p *dns = (struct dns_p *)this->private;
+
+       if (dns->res == NULL) {
+               struct __res_state *res;
+               res = (struct __res_state *)malloc(sizeof *res);
+               if (res == NULL)
+                       return (NULL);
+               memset(dns->res, 0, sizeof *dns->res);
+               dns_res_set(this, res, free);
+       }
+
+       if ((dns->res->options & RES_INIT) == 0 &&
+           res_ninit(dns->res) < 0)
+               return (NULL);
+
+       return (dns->res);
+}
+
+static void
+dns_res_set(struct irs_acc *this, struct __res_state *res,
+           void (*free_res)(void *)) {
+       struct dns_p *dns = (struct dns_p *)this->private;
+
+       if (dns->res && dns->free_res) {
+               res_nclose(dns->res);
+               (*dns->free_res)(dns->res);
+       }
+       dns->res = res;
+       dns->free_res = free_res;
+}
+
+static void
+dns_close(struct irs_acc *this) {
+       struct dns_p *dns;
+
+       dns = (struct dns_p *)this->private;
+       if (dns->res && dns->free_res)
+               (*dns->free_res)(dns->res);
+       if (dns->hes_ctx)
+               hesiod_end(dns->hes_ctx);
+       memput(dns, sizeof *dns);
+       memput(this, sizeof *this);
+}
+
diff --git a/lib/bind/irs/dns_gr.c b/lib/bind/irs/dns_gr.c
new file mode 100644 (file)
index 0000000..a47ba1e
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+ * 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 rcsid[] = "$Id: dns_gr.c,v 1.1 2001/03/29 06:31:42 marka Exp $";
+#endif
+
+/*
+ * dns_gr.c --- this file contains the functions for accessing
+ *     group information from Hesiod.
+ */
+
+#include "port_before.h"
+
+#ifndef WANT_IRS_GR
+static int __bind_irs_gr_unneeded;
+#else
+
+#include <sys/param.h>
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <netinet/in.h> 
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <isc/memcluster.h>
+
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "hesiod.h"
+#include "dns_p.h"
+
+/* Types. */
+
+struct pvt {
+       /*
+        * This is our private accessor data.  It has a shared hesiod context.
+        */
+       struct dns_p *  dns;
+       /*
+        * Need space to store the entries read from the group file.
+        * The members list also needs space per member, and the
+        * strings making up the user names must be allocated
+        * somewhere.  Rather than doing lots of small allocations,
+        * we keep one buffer and resize it as needed.
+        */
+       struct group    group;
+       size_t          nmemb;          /* Malloc'd max index of gr_mem[]. */
+       char *          membuf;
+       size_t          membufsize;
+};
+
+/* Forward. */
+
+static struct group *  gr_next(struct irs_gr *);
+static struct group *  gr_byname(struct irs_gr *, const char *);
+static struct group *  gr_bygid(struct irs_gr *, gid_t);
+static void            gr_rewind(struct irs_gr *);
+static void            gr_close(struct irs_gr *);
+static int             gr_list(struct irs_gr *, const char *,
+                               gid_t, gid_t *, int *);
+static void            gr_minimize(struct irs_gr *);
+static struct __res_state * gr_res_get(struct irs_gr *);
+static void            gr_res_set(struct irs_gr *,
+                                  struct __res_state *,
+                                  void (*)(void *));
+
+static struct group *  get_hes_group(struct irs_gr *this,
+                                     const char *name,
+                                     const char *type);
+
+/* Public. */
+
+struct irs_gr *
+irs_dns_gr(struct irs_acc *this) {
+       struct dns_p *dns = (struct dns_p *)this->private;
+       struct irs_gr *gr;
+       struct pvt *pvt;
+
+       if (!dns || !dns->hes_ctx) {
+               errno = ENODEV;
+               return (NULL);
+       }
+       if (!(pvt = memget(sizeof *pvt))) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pvt, 0, sizeof *pvt);
+       pvt->dns = dns;
+       if (!(gr = memget(sizeof *gr))) {
+               memput(pvt, sizeof *pvt);
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(gr, 0x5e, sizeof *gr);
+       gr->private = pvt;
+       gr->next = gr_next;
+       gr->byname = gr_byname;
+       gr->bygid = gr_bygid;
+       gr->rewind = gr_rewind;
+       gr->close = gr_close;
+       gr->list = gr_list;
+       gr->minimize = gr_minimize;
+       gr->res_get = gr_res_get;
+       gr->res_set = gr_res_set;
+       return (gr);
+}
+
+/* methods */
+
+static void
+gr_close(struct irs_gr *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (pvt->group.gr_mem)
+               free(pvt->group.gr_mem);
+       if (pvt->membuf)
+               free(pvt->membuf);
+       memput(pvt, sizeof *pvt);
+       memput(this, sizeof *this);
+}
+
+static struct group *
+gr_next(struct irs_gr *this) {
+
+       UNUSED(this);
+
+       return (NULL);
+}
+
+static struct group *
+gr_byname(struct irs_gr *this, const char *name) {
+       return (get_hes_group(this, name, "group"));
+}
+
+static struct group *
+gr_bygid(struct irs_gr *this, gid_t gid) {
+       char name[32];
+
+       sprintf(name, "%ld", (long)gid);
+       return (get_hes_group(this, name, "gid"));
+}
+
+static void
+gr_rewind(struct irs_gr *this) {
+
+       UNUSED(this);
+
+       /* NOOP */
+}
+
+static int
+gr_list(struct irs_gr *this, const char *name,
+       gid_t basegid, gid_t *groups, int *ngroups)
+{
+       UNUSED(this);
+       UNUSED(name);
+       UNUSED(basegid);
+       UNUSED(groups);
+
+       *ngroups = 0;
+       /* There's some way to do this in Hesiod. */
+       return (-1);
+}
+
+static void
+gr_minimize(struct irs_gr *this) {
+
+       UNUSED(this);
+       /* NOOP */
+}
+
+/* Private. */
+
+static struct group *
+get_hes_group(struct irs_gr *this, const char *name, const char *type) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       char **hes_list, *cp, **new;
+       size_t num_members = 0;
+       u_long t;
+
+       hes_list = hesiod_resolve(pvt->dns->hes_ctx, name, type);
+       if (!hes_list)
+               return (NULL);
+
+       /*
+        * Copy the returned hesiod string into storage space.
+        */
+       if (pvt->membuf)
+               free(pvt->membuf);
+       pvt->membuf = strdup(*hes_list);
+       hesiod_free_list(pvt->dns->hes_ctx, hes_list);
+
+       cp = pvt->membuf;
+       pvt->group.gr_name = cp;
+       if (!(cp = strchr(cp, ':')))
+               goto cleanup;
+       *cp++ = '\0';
+       
+       pvt->group.gr_passwd = cp;
+       if (!(cp = strchr(cp, ':')))
+               goto cleanup;
+       *cp++ = '\0';
+
+       errno = -1;
+       t = strtoul(cp, NULL, 10);
+       if (errno == ERANGE)
+               goto cleanup;
+       pvt->group.gr_gid = (gid_t) t;
+       if (!(cp = strchr(cp, ':')))
+               goto cleanup;
+       cp++;
+
+       /*
+        * Parse the members out.
+        */
+       while (*cp) {
+               if (num_members+1 >= pvt->nmemb || pvt->group.gr_mem == NULL) {
+                       pvt->nmemb += 10;
+                       new = realloc(pvt->group.gr_mem,
+                                     pvt->nmemb * sizeof(char *));
+                       if (new == NULL)
+                               goto cleanup;
+                       pvt->group.gr_mem = new;
+               }
+               pvt->group.gr_mem[num_members++] = cp;
+               if (!(cp = strchr(cp, ',')))
+                       break;
+               *cp++ = '\0';
+       }
+       if (!pvt->group.gr_mem) {
+               pvt->group.gr_mem = malloc(sizeof(char*));
+               if (!pvt->group.gr_mem)
+                       goto cleanup;
+       }
+       pvt->group.gr_mem[num_members] = NULL;
+       
+       return (&pvt->group);
+       
+ cleanup:      
+       if (pvt->group.gr_mem) {
+               free(pvt->group.gr_mem);
+               pvt->group.gr_mem = NULL;
+       }
+       if (pvt->membuf) {
+               free(pvt->membuf);
+               pvt->membuf = NULL;
+       }
+       return (NULL);
+}
+
+static struct __res_state *
+gr_res_get(struct irs_gr *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct dns_p *dns = pvt->dns;
+
+       return (__hesiod_res_get(dns->hes_ctx));
+}
+
+static void
+gr_res_set(struct irs_gr *this, struct __res_state * res,
+          void (*free_res)(void *)) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct dns_p *dns = pvt->dns;
+
+       __hesiod_res_set(dns->hes_ctx, res, free_res);
+}
+
+#endif /* WANT_IRS_GR */
diff --git a/lib/bind/irs/dns_ho.c b/lib/bind/irs/dns_ho.c
new file mode 100644 (file)
index 0000000..fedbc0e
--- /dev/null
@@ -0,0 +1,1606 @@
+/*
+ * Copyright (c) 1985, 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) 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.
+ */
+
+/* from gethostnamadr.c        8.1 (Berkeley) 6/4/93 */
+/* BIND Id: gethnamaddr.c,v 8.15 1996/05/22 04:56:30 vixie Exp $ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: dns_ho.c,v 1.1 2001/03/29 06:31:42 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* Imports. */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "dns_p.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) sprintf x
+#endif
+
+/* Definitions. */
+
+#define        MAXALIASES      35
+#define        MAXADDRS        35
+
+#if PACKETSZ > 1024
+#define        MAXPACKET       PACKETSZ
+#else
+#define        MAXPACKET       1024
+#endif
+
+#define BOUNDS_CHECK(ptr, count) \
+       if ((ptr) + (count) > eom) { \
+               had_error++; \
+               continue; \
+       } else (void)0
+
+typedef union {
+       HEADER hdr;
+       u_char buf[MAXPACKET];
+} querybuf;
+
+struct dns_res_target {
+       struct dns_res_target *next;
+       querybuf qbuf;          /* query buffer */
+       u_char *answer;         /* buffer to put answer */
+       int anslen;             /* size of answer buffer */
+       int qclass, qtype;      /* class and type of query */
+       int action;             /* condition whether query is really issued */
+       char qname[MAXDNAME +1]; /* domain name */
+#if 0
+       int n;                  /* result length */
+#endif
+};
+enum {RESTGT_DOALWAYS, RESTGT_AFTERFAILURE, RESTGT_IGNORE};
+enum {RESQRY_SUCCESS, RESQRY_FAIL};
+
+struct pvt {
+       struct hostent  host;
+       char *          h_addr_ptrs[MAXADDRS + 1];
+       char *          host_aliases[MAXALIASES];
+       char            hostbuf[8*1024];
+       u_char          host_addr[16];  /* IPv4 or IPv6 */
+       struct __res_state  *res;
+       void            (*free_res)(void *);
+};
+
+typedef union {
+       int32_t al;
+       char ac;
+} align;
+
+static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
+static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
+/* Note: the IPv6 loopback address is in the "tunnel" space */
+static const u_char v6local[] = { 0,0, 0,1 }; /* last 4 bytes of IPv6 addr */
+
+/* Forwards. */
+
+static void            ho_close(struct irs_ho *this);
+static struct hostent *        ho_byname(struct irs_ho *this, const char *name);
+static struct hostent *        ho_byname2(struct irs_ho *this, const char *name,
+                                  int af);
+static struct hostent *        ho_byaddr(struct irs_ho *this, const void *addr,
+                                 int len, int af);
+static struct hostent *        ho_next(struct irs_ho *this);
+static void            ho_rewind(struct irs_ho *this);
+static void            ho_minimize(struct irs_ho *this);
+static struct __res_state * ho_res_get(struct irs_ho *this);
+static void            ho_res_set(struct irs_ho *this,
+                                  struct __res_state *res,
+                                  void (*free_res)(void *));
+static struct addrinfo * ho_addrinfo(struct irs_ho *this, const char *name,
+                                    const struct addrinfo *pai);
+
+static void            map_v4v6_hostent(struct hostent *hp, char **bp,
+                                        int *len);
+static void            addrsort(res_state, char **, int);
+static struct hostent *        gethostans(struct irs_ho *this,
+                                  const u_char *ansbuf, int anslen,
+                                  const char *qname, int qtype,
+                                  int af, int size,
+                                  struct addrinfo **ret_aip,
+                                  const struct addrinfo *pai);
+static int add_hostent(struct pvt *pvt, char *bp, char **hap,
+                      struct addrinfo *ai);
+static const u_char * ar_head(const u_char *, int, const u_char *,
+                             const u_char *, struct pvt *,
+                             int (*)(const char *));
+static struct addrinfo * a6_expand(const u_char *, const u_char *, int,
+                                  const u_char *, const u_char *,
+                                  const struct in6_addr *, int,
+                                  const struct addrinfo *,
+                                  struct pvt *, int (*)(const char *), int *);
+static const char *dname_subst(const char *, const char *, const char *);
+static int             init(struct irs_ho *this);
+
+/* Exports. */
+
+struct irs_ho *
+irs_dns_ho(struct irs_acc *this) {
+       struct irs_ho *ho;
+       struct pvt *pvt;
+
+       UNUSED(this);
+
+       if (!(pvt = memget(sizeof *pvt))) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pvt, 0, sizeof *pvt);
+
+       if (!(ho = memget(sizeof *ho))) {
+               memput(pvt, sizeof *pvt);
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(ho, 0x5e, sizeof *ho);
+       ho->private = pvt;
+       ho->close = ho_close;
+       ho->byname = ho_byname;
+       ho->byname2 = ho_byname2;
+       ho->byaddr = ho_byaddr;
+       ho->next = ho_next;
+       ho->rewind = ho_rewind;
+       ho->minimize = ho_minimize;
+       ho->res_get = ho_res_get;
+       ho->res_set = ho_res_set;
+       ho->addrinfo = ho_addrinfo;
+       return (ho);
+}
+
+/* Methods. */
+
+static void
+ho_close(struct irs_ho *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       ho_minimize(this);
+       if (pvt->res && pvt->free_res)
+               (*pvt->free_res)(pvt->res);
+       if (pvt)
+               memput(pvt, sizeof *pvt);
+       memput(this, sizeof *this);
+}
+
+static struct hostent *
+ho_byname(struct irs_ho *this, const char *name) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct hostent *hp;
+
+       if (init(this) == -1)
+               return (NULL);
+
+       if (pvt->res->options & RES_USE_INET6) {
+               hp = ho_byname2(this, name, AF_INET6);
+               if (hp)
+                       return (hp);
+       }
+       return (ho_byname2(this, name, AF_INET));
+}
+
+static struct hostent *
+ho_byname2(struct irs_ho *this, const char *name, int af)
+{
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct hostent *hp = NULL;
+       int n, size;
+       char tmp[NS_MAXDNAME];
+       const char *cp;
+       struct addrinfo ai;
+       struct dns_res_target q, q2, *p;
+       int querystate = RESQRY_FAIL;
+
+       if (init(this) == -1)
+               return (NULL);
+
+       memset(&q, 0, sizeof(q2));
+       memset(&q2, 0, sizeof(q2));
+
+       switch (af) {
+       case AF_INET:
+               size = INADDRSZ;
+               q.qclass = C_IN;
+               q.qtype = T_A;
+               q.answer = q.qbuf.buf;
+               q.anslen = sizeof(q.qbuf);
+               q.action = RESTGT_DOALWAYS;
+               break;
+       case AF_INET6:
+               size = IN6ADDRSZ;
+               q.qclass = C_IN;
+               q.qtype = ns_t_a6;
+               q.answer = q.qbuf.buf;
+               q.anslen = sizeof(q.qbuf);
+               q.next = &q2;
+#ifdef RES_USE_A6
+               if ((pvt->res->options & RES_USE_A6) == 0)
+                       q.action = RESTGT_IGNORE;
+               else
+#endif
+                       q.action = RESTGT_DOALWAYS;
+               q2.qclass = C_IN;
+               q2.qtype = T_AAAA;
+               q2.answer = q2.qbuf.buf;
+               q2.anslen = sizeof(q2.qbuf);
+               q2.action = RESTGT_AFTERFAILURE;
+               break;
+       default:
+               RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+               errno = EAFNOSUPPORT;
+               return (NULL);
+       }
+
+       /*
+        * if there aren't any dots, it could be a user-level alias.
+        * this is also done in res_nquery() since we are not the only
+        * function that looks up host names.
+        */
+       if (!strchr(name, '.') && (cp = res_hostalias(pvt->res, name,
+                                                     tmp, sizeof tmp)))
+               name = cp;
+
+       for (p = &q; p; p = p->next) {
+               switch(p->action) {
+               case RESTGT_DOALWAYS:
+                       break;
+               case RESTGT_AFTERFAILURE:
+                       if (querystate == RESQRY_SUCCESS)
+                               continue;
+                       break;
+               case RESTGT_IGNORE:
+                       continue;
+               }
+
+               if ((n = res_nsearch(pvt->res, name, p->qclass, p->qtype,
+                                    p->answer, p->anslen)) < 0) {
+                       querystate = RESQRY_FAIL;
+                       continue;
+               }
+
+               memset(&ai, 0, sizeof(ai));
+               ai.ai_family = af;
+               if ((hp = gethostans(this, p->answer, n, name, p->qtype,
+                                    af, size, NULL,
+                                    (const struct addrinfo *)&ai)) != NULL)
+                       return(hp); /* no more loop is necessary */
+
+               querystate = RESQRY_FAIL;
+               continue;
+       }
+
+       return(hp);             /* should be NULL */
+}
+
+static struct hostent *
+ho_byaddr(struct irs_ho *this, const void *addr, int len, int af)
+{
+       struct pvt *pvt = (struct pvt *)this->private;
+       const u_char *uaddr = addr;
+       char *qp;
+       struct hostent *hp;
+       struct addrinfo ai;
+       struct dns_res_target q, q2, *p;
+       int n, size;
+       int querystate = RESQRY_FAIL;
+       
+       if (init(this) == -1)
+               return (NULL);
+
+       memset(&q, 0, sizeof(q2));
+       memset(&q2, 0, sizeof(q2));
+
+       if (af == AF_INET6 && len == IN6ADDRSZ &&
+           (!memcmp(uaddr, mapped, sizeof mapped) ||
+           (!memcmp(uaddr, tunnelled, sizeof tunnelled) &&
+            memcmp(&uaddr[sizeof tunnelled], v6local, sizeof(v6local))))) {
+               /* Unmap. */
+               addr = (const char *)addr + sizeof mapped;
+               uaddr += sizeof mapped;
+               af = AF_INET;
+               len = INADDRSZ;
+       }
+       switch (af) {
+       case AF_INET:
+               size = INADDRSZ;
+               q.qclass = C_IN;
+               q.qtype = T_PTR;
+               q.answer = q.qbuf.buf;
+               q.anslen = sizeof(q.qbuf);
+               q.action = RESTGT_DOALWAYS;
+               break;
+       case AF_INET6:
+               size = IN6ADDRSZ;
+               q.qclass = C_IN;
+               q.qtype = T_PTR;
+               q.answer = q.qbuf.buf;
+               q.anslen = sizeof(q.qbuf);
+               q.next = &q2;
+#ifdef RES_USE_DNAME
+               if ((pvt->res->options & RES_USE_DNAME) == 0)
+                       q.action = RESTGT_IGNORE;
+               else
+#endif
+                       q.action = RESTGT_DOALWAYS;
+               q2.qclass = C_IN;
+               q2.qtype = T_PTR;
+               q2.answer = q2.qbuf.buf;
+               q2.anslen = sizeof(q2.qbuf);
+               q2.action = RESTGT_AFTERFAILURE;
+               break;
+       default:
+               errno = EAFNOSUPPORT;
+               RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+               return (NULL);
+       }
+       if (size > len) {
+               errno = EINVAL;
+               RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+               return (NULL);
+       }
+       switch (af) {
+       case AF_INET:
+               qp = q.qname;
+               (void) sprintf(qp, "%u.%u.%u.%u.in-addr.arpa",
+                              (uaddr[3] & 0xff),
+                              (uaddr[2] & 0xff),
+                              (uaddr[1] & 0xff),
+                              (uaddr[0] & 0xff));
+               break;
+       case AF_INET6:
+               if (q.action != RESTGT_IGNORE) {
+                       qp = q.qname;
+                       qp += SPRINTF((qp, "\\[x"));
+                       for (n = 0; n < IN6ADDRSZ; n++)
+                               qp += SPRINTF((qp, "%02x", uaddr[n]));
+                       strcpy(qp, "/128].ip6.arpa");
+               }
+               qp = q2.qname;
+               for (n = IN6ADDRSZ - 1; n >= 0; n--) {
+                       qp += SPRINTF((qp, "%x.%x.",
+                                      uaddr[n] & 0xf,
+                                      (uaddr[n] >> 4) & 0xf));
+               }
+               strcpy(qp, "ip6.int");
+               break;
+       default:
+               abort();
+       }
+
+       for (p = &q; p; p = p->next) {
+               switch(p->action) {
+               case RESTGT_DOALWAYS:
+                       break;
+               case RESTGT_AFTERFAILURE:
+                       if (querystate == RESQRY_SUCCESS)
+                               continue;
+                       break;
+               case RESTGT_IGNORE:
+                       continue;
+               }
+
+               if ((n = res_nsearch(pvt->res, p->qname, p->qclass, p->qtype,
+                                    p->answer, p->anslen)) < 0) {
+                       querystate = RESQRY_FAIL;
+                       continue;
+               }
+
+               if ((n = res_nquery(pvt->res, p->qname, C_IN, T_PTR, p->answer,
+                                   p->anslen)) < 0) {
+                       querystate = RESQRY_FAIL;
+                       continue;
+               }
+
+               memset(&ai, 0, sizeof(ai));
+               ai.ai_family = af;
+               hp = gethostans(this, p->answer, n, p->qname, T_PTR, af, size,
+                               NULL, (const struct addrinfo *)&ai);
+               if (!hp) {
+                       querystate = RESQRY_FAIL;
+                       continue;
+               }
+                       
+               memcpy(pvt->host_addr, addr, len);
+               pvt->h_addr_ptrs[0] = (char *)pvt->host_addr;
+               pvt->h_addr_ptrs[1] = NULL;
+               if (af == AF_INET && (pvt->res->options & RES_USE_INET6)) {
+                       map_v4v6_address((char*)pvt->host_addr,
+                                        (char*)pvt->host_addr);
+                       pvt->host.h_addrtype = AF_INET6;
+                       pvt->host.h_length = IN6ADDRSZ;
+               }
+
+               RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS);
+               return (hp);    /* no more loop is necessary. */
+       }
+
+       return(NULL);           /* H_ERRNO was set by subroutines */
+}
+
+static struct hostent *
+ho_next(struct irs_ho *this) {
+
+       UNUSED(this);
+
+       return (NULL);
+}
+
+static void
+ho_rewind(struct irs_ho *this) {
+
+       UNUSED(this);
+
+       /* NOOP */
+}
+
+static void
+ho_minimize(struct irs_ho *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (pvt->res)
+               res_nclose(pvt->res);
+}
+
+static struct __res_state *
+ho_res_get(struct irs_ho *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (!pvt->res) {
+               struct __res_state *res;
+               res = (struct __res_state *)malloc(sizeof *res);
+               if (!res) {
+                       errno = ENOMEM;
+                       return (NULL);
+               }
+               memset(res, 0, sizeof *res);
+               ho_res_set(this, res, free);
+       }
+
+       return (pvt->res);
+}
+
+/* XXX */
+extern struct addrinfo *addr2addrinfo __P((const struct addrinfo *,
+                                          const char *));
+
+static struct addrinfo *
+ho_addrinfo(struct irs_ho *this, const char *name, const struct addrinfo *pai)
+{
+       struct pvt *pvt = (struct pvt *)this->private;
+       int n;
+       char tmp[NS_MAXDNAME];
+       const char *cp;
+       struct dns_res_target q, q2, q3, *p;
+       struct addrinfo sentinel, *cur;
+       int querystate = RESQRY_FAIL;
+
+       if (init(this) == -1)
+               return (NULL);
+
+       memset(&q, 0, sizeof(q2));
+       memset(&q2, 0, sizeof(q2));
+       memset(&q3, 0, sizeof(q3));
+       memset(&sentinel, 0, sizeof(sentinel));
+       cur = &sentinel;
+
+       switch (pai->ai_family) {
+       case AF_UNSPEC:
+               /* prefer IPv6 */
+               q.qclass = C_IN;
+               q.qtype = ns_t_a6;
+               q.answer = q.qbuf.buf;
+               q.anslen = sizeof(q.qbuf);
+               q.next = &q2;
+#ifdef RES_USE_A6
+               if ((pvt->res->options & RES_USE_A6) == 0)
+                       q.action = RESTGT_IGNORE;
+               else
+#endif
+                       q.action = RESTGT_DOALWAYS;
+               q2.qclass = C_IN;
+               q2.qtype = T_AAAA;
+               q2.answer = q2.qbuf.buf;
+               q2.anslen = sizeof(q2.qbuf);
+               q2.next = &q3;
+               /* try AAAA only when A6 query fails */
+               q2.action = RESTGT_AFTERFAILURE;
+               q3.qclass = C_IN;
+               q3.qtype = T_A;
+               q3.answer = q3.qbuf.buf;
+               q3.anslen = sizeof(q3.qbuf);
+               q3.action = RESTGT_DOALWAYS;
+               break;
+       case AF_INET:
+               q.qclass = C_IN;
+               q.qtype = T_A;
+               q.answer = q.qbuf.buf;
+               q.anslen = sizeof(q.qbuf);
+               q.action = RESTGT_DOALWAYS;
+               break;
+       case AF_INET6:
+               q.qclass = C_IN;
+               q.qtype = ns_t_a6;
+               q.answer = q.qbuf.buf;
+               q.anslen = sizeof(q.qbuf);
+               q.next = &q2;
+#ifdef RES_USE_A6
+               if ((pvt->res->options & RES_USE_A6) == 0)
+                       q.action = RESTGT_IGNORE;
+               else
+#endif
+                       q.action = RESTGT_DOALWAYS;
+               q2.qclass = C_IN;
+               q2.qtype = T_AAAA;
+               q2.answer = q2.qbuf.buf;
+               q2.anslen = sizeof(q2.qbuf);
+               q2.action = RESTGT_AFTERFAILURE;
+               break;
+       default:
+               RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); /* better error? */
+               return(NULL);
+       }
+
+       /*
+        * if there aren't any dots, it could be a user-level alias.
+        * this is also done in res_nquery() since we are not the only
+        * function that looks up host names.
+        */
+       if (!strchr(name, '.') && (cp = res_hostalias(pvt->res, name,
+                                                     tmp, sizeof tmp)))
+               name = cp;
+
+       for (p = &q; p; p = p->next) {
+               struct addrinfo *ai;
+
+               switch(p->action) {
+               case RESTGT_DOALWAYS:
+                       break;
+               case RESTGT_AFTERFAILURE:
+                       if (querystate == RESQRY_SUCCESS)
+                               continue;
+                       break;
+               case RESTGT_IGNORE:
+                       continue;
+               }
+
+               if ((n = res_nsearch(pvt->res, name, p->qclass, p->qtype,
+                                    p->answer, p->anslen)) < 0) {
+                       querystate = RESQRY_FAIL;
+                       continue;
+               }
+               (void)gethostans(this, p->answer, n, name, p->qtype,
+                                pai->ai_family, /* XXX: meaningless */
+                                0, &ai, pai);
+               if (ai) {
+                       querystate = RESQRY_SUCCESS;
+                       cur->ai_next = ai;
+                       while (cur && cur->ai_next)
+                               cur = cur->ai_next;
+               }
+               else
+                       querystate = RESQRY_FAIL;
+       }
+
+       return(sentinel.ai_next);
+}
+
+static const u_char *
+ar_head(cp, count, msg, eom, pvt, name_ok)
+       const u_char *cp, *msg, *eom;
+       int count;
+       struct pvt *pvt;
+       int (*name_ok)(const char *);
+{
+       int n;
+       u_char buf[1024];       /* XXX */
+
+       while (count-- > 0 && cp < eom) {
+               n = dn_expand(msg, eom, cp, buf, sizeof(buf));
+               if (n < 0 || !maybe_ok(pvt->res, buf, name_ok))
+                       goto end;
+               cp += n;                        /* name */
+               if (cp + 3 * INT16SZ + INT32SZ >= eom)
+                       goto end;
+               cp += INT16SZ;                  /* type */
+               cp += INT16SZ + INT32SZ;        /* class, TTL */
+               n = ns_get16(cp);
+               cp += n + INT16SZ;              /* len */
+       }
+       return(cp);
+
+  end:
+       return(eom);            /* XXX */
+}
+
+/* XXX: too many arguments */
+static struct addrinfo *
+a6_expand(const u_char *ansbuf, const u_char *a6p,
+         int a6len, const u_char *arp, const u_char *eom,
+         const struct in6_addr *in6, int plen, const struct addrinfo *pai,
+         struct pvt *pvt, int (*name_ok)(const char *), int *errorp)
+{
+       struct in6_addr a;
+       int n, pbyte, plen1, pbyte1, error = 0;
+       const u_char *cp;
+       struct addrinfo sentinel, *cur;
+       u_char pname[1024], buf[1024]; /* XXX */
+
+       *errorp = NETDB_SUCCESS;
+       memset(&sentinel, 0, sizeof(sentinel));
+       cur = &sentinel;
+
+       /*
+        * Validate A6 parameters.
+        */
+       if (a6len == 0) { /* an A6 record must contain at least 1 byte. */
+               error = NO_RECOVERY;
+               goto bad;
+       }
+       /* prefix length check. */
+       if ((plen1 = *a6p) > 128) {
+               error = NO_RECOVERY;
+               goto bad;
+       }
+       if (plen1 > plen) {
+               /*
+                * New length must not be greater than old one.
+                * Ignore the record as specified in RFC 2874
+                * Section 3.1.2.
+                */
+               return(NULL); /* just ignore. */
+       }
+       /* boundary check for new plen and prefix addr */
+       pbyte1 = (plen1 & ~7) / 8;
+       if ((int)sizeof(struct in6_addr) - pbyte1 > a6len - 1) {
+               error = NO_RECOVERY;
+               goto bad;
+       }
+
+       /*
+        * merge the new prefix portion.
+        * <--- plen(bits) --->
+        * <--- pbyte ---><-b->
+        * 000000000000000pppppxxxxxxxxxxx(= in6, 0: unknown, x: known, p: pad)
+        *           PP++++++++(+ should be merged. P: padding, must be 0)
+        * <-- plen1-->
+        * <-pbyte1->
+        *           ^a6p+1
+        * The result should be:
+        * 0000000000PP++++++++xxxxxxxxxxx(= a)
+        */
+       pbyte = (plen & ~7) / 8;
+       a = *in6;
+       if (pbyte > pbyte1) {
+               /* N.B. the case of "pbyte1 == 128" is implicitly excluded. */
+               int b = plen % 8; /* = the length of "pp..." above */
+               u_char c_hi, c_lo;
+
+               memcpy(&a.s6_addr[pbyte1], a6p + 1, pbyte - pbyte1);
+               if (b > 0) {
+                       c_hi = a6p[pbyte - pbyte1 + 1];
+                       c_lo = in6->s6_addr[pbyte];
+                       a.s6_addr[pbyte] =
+                               (c_hi & (0xff << (8 - b))) |
+                               ((0x00ff >> b) & c_lo);
+               }
+       }
+
+#if 0                          /* for debug */
+       if ((pvt->res->options & RES_DEBUG) != 0) {
+               u_char ntopbuf[INET6_ADDRSTRLEN];
+
+               inet_ntop(AF_INET6, &a, ntopbuf, sizeof(ntopbuf));
+               printf("a6_expand: %s\\%d\n", ntopbuf, plen1);
+       }
+#endif
+
+       if (plen1 == 0) {
+               /* Here is the end of A6 chain. make addrinfo, then return. */
+               return(addr2addrinfo(pai, (const char *)&a));
+       }
+
+       /*
+        * Expand the new prefix name. Since the prefix name must not be
+        * compressed (RFC 2874 Section 3.1.1), we could use ns_name_ntop()
+        * here if it had a stricter boundary check.
+        */
+       cp = a6p + 1 + (sizeof(*in6) - pbyte1);
+       n = dn_expand(ansbuf, eom, cp, pname, sizeof(pname));
+       if (n < 0 || !maybe_ok(pvt->res, pname, name_ok)) {
+               error = NO_RECOVERY;
+               goto bad;
+       }
+       if (cp + n != a6p + a6len) { /* length mismatch */
+               error = NO_RECOVERY;
+               goto bad;
+       }
+
+       /*
+        * we need (more) additional section records, but no one is
+        * available, which possibly means a malformed answer.
+        */
+       if (arp == NULL) {
+               error = NO_RECOVERY; /* we can't resolve the chain. */
+               goto bad;
+       }
+
+       /*
+        * Loop thru the rest of the buffer, searching for the next A6 record
+        * that has the same owner name as the prefix name. If found, then
+        * recursively call this function to expand the whole A6 chain.
+        */
+       plen = plen1;
+       for (cp = arp; cp != NULL && cp < eom; cp += n) {
+               int class, type;
+
+               n = dn_expand(ansbuf, eom, cp, buf, sizeof(buf));
+               if (n < 0 || !maybe_ok(pvt->res, buf, name_ok)) {
+                       error = NO_RECOVERY;
+                       goto bad;
+               }
+               cp += n;                        /* name */
+               if (cp + 3 * INT16SZ + INT32SZ > eom) {
+                       error = NO_RECOVERY;
+                       goto bad;
+               }
+               type = ns_get16(cp);
+               cp += INT16SZ;                  /* type */
+               class = ns_get16(cp);
+               cp += INT16SZ + INT32SZ;        /* class, TTL */
+               n = ns_get16(cp);
+               cp += INT16SZ;                  /* len */
+               if (cp + n > eom) {
+                       error = NO_RECOVERY;
+                       goto bad;
+               }
+               if (class != C_IN || type != ns_t_a6) {
+                       /* we are only interested in A6 records. skip others */
+                       continue;
+               }
+
+               if (ns_samename(buf, pname) != 1) {
+                       continue;
+               }
+
+               /* Proceed to the next record in the chain. */
+               cur->ai_next = a6_expand(ansbuf, cp, n, cp + n, eom,
+                                        (const struct in6_addr *)&a,
+                                        plen, pai, pvt, name_ok, &error);
+               if (error != NETDB_SUCCESS)
+                       goto bad;
+               while (cur && cur->ai_next)
+                       cur = cur->ai_next;
+       }
+
+       return(sentinel.ai_next);
+
+  bad:
+       *errorp = error;
+       if (sentinel.ai_next)
+               freeaddrinfo(sentinel.ai_next);
+       return(NULL);
+}
+
+static const char *
+dname_subst(const char *qname0, const char *owner0, const char *target) {
+       char owner[MAXDNAME];
+       static char qname[MAXDNAME];
+       const char blabelhead[] = "\\[x"; /* we can assume hex strings */
+       int qlen, olen;
+       int bufsiz = sizeof(qname);
+
+       /* make local copies, which are canonicalized. */
+       if (ns_makecanon(qname0, qname, sizeof(qname)) < 0 ||
+           ns_makecanon(owner0, owner, sizeof(owner)) < 0)
+               return(NULL);
+       qlen = strlen(qname);
+       olen = strlen(owner);
+       /* from now on, do not refer to qname0 nor owner0. */
+
+       /*
+        * check if QNAME is a subdomain of OWNER.
+        * XXX: currently, we only handle the following two cases:
+        *      (A) none of the labels are bitlabels, or
+        *      (B) both of the head labels are bitlabels (and the following
+        *          labels are NOT bitlabels).
+        * If we pass the check, then subtract the remaining part from QNAME.
+        * ex. (A) qname=www.foo.com,owner=foo.com => new qname=www.
+        *     (B) qname=\[x3ffe0501/32].foo.com,owner=\[x3ffe/16].foo.com
+        *                                  => new qname=\[x0501/16].
+        */
+       if (ns_samedomain(qname, owner)) { /* check (A) */
+               /* at this point, qlen must not be smaller than olen */
+               qname[qlen - olen] = 0;
+               bufsiz -= (qlen - olen);
+       } else {                /* check (B) */
+               char *parent0, *parent1;
+               /* the following 3 have enough size to store 1 bitlabel */
+               u_char qlabel[64], olabel[64], newlabel[64];
+               int qlabellen, olabellen;
+
+               if (strncmp(qname, blabelhead, 3) != 0 ||
+                   strncmp(owner, blabelhead, 3) != 0)
+                       return(NULL);
+               /*
+                * Both two begin with bitlabels. The succeeding parts
+                * must exact match.
+                */
+               if ((parent0 = strchr(qname, '.')) == NULL ||
+                   (parent1 = strchr(owner, '.')) == NULL)
+                       return(NULL);
+
+               /* ns_samename allows names to begin with '.' */
+               if (ns_samename(parent0, parent1) != 1)
+                       return(NULL);
+
+               /* cut the upper domain parts off. */
+               *(parent0 + 1) = 0;
+               *(parent1 + 1) = 0;
+               /* convert the textual form into binary one. */
+               if (ns_name_pton(qname, qlabel, sizeof(qlabel)) < 0 ||
+                   ns_name_pton(owner, olabel, sizeof(olabel)) < 0)
+                       return(NULL);
+               if ((qlabellen = *(qlabel + 1)) == 0)
+                       qlabellen = 256;
+               if ((olabellen = *(olabel + 1)) == 0)
+                       olabellen = 256;
+               if (olabellen > qlabellen)
+                       return(NULL); /* owner does not contain qname. */
+               else {
+                       int qplen = (qlabellen + 7) / 8;
+                       int oplen = (olabellen + 7) / 8;
+                       int sft = olabellen % 8;
+                       int nllen, n;
+                       u_char *qp, *op, *np;
+
+                       /* skip ELT and Count. */
+                       qp = qlabel + 2;
+                       op = olabel + 2;
+
+                       /* check if olabel is a "subdomain" of qlabel. */
+                       if (memcmp(qp, op, oplen - 1) != 0)
+                               return(NULL);
+                       if (sft > 0) {
+                               /* compare trailing bits (between 1 and 7) */
+                               if ((qp[qplen - 1] & (0xff << sft)) !=
+                                   op[qplen - 1])
+                                       return(NULL);
+                       }
+
+                       /* OK, get remaining bits from qlabel. */
+                       np = newlabel;
+                       if (olabellen == qlabellen) {
+                               /*
+                                * Two names (including bitlabels) are exactly
+                                * same. Discard the whole names.
+                                * XXX: ns_samename() above should exclude
+                                * this case...
+                                */
+                               qname[0] = 0;
+                               goto maketarget;
+                       }
+                       *np++ = 0x41; /* XXX hardcoding */
+                       *np++ = nllen = (qlabellen - olabellen);
+                       if (sft == 0) {
+                               /*
+                                * No alignment issue. can just use memcpy.
+                                * Note that the "else" part below contains
+                                * this case. We separate the two cases just
+                                * for efficiency.
+                                * We assume that ns_name_pton above ensures
+                                * QP does not contain trailing garbages.
+                                */
+                               memcpy(np, qp + oplen, qplen - oplen);
+                               np += qplen - oplen;
+                               *np = 0;
+                       } else {
+                               /*
+                                * copy the lower (8-SFT) bits of QP to the
+                                * upper (8-SFT) bits of NP, then copy the
+                                * upper SFT bits of QP+1 to the lower SFT bits
+                                * of NP, and so on...
+                                * if QP is       xxxyyyyy zzzwww..., then
+                                *    NP would be yyyyyzzz ...
+                                * Again, we assume QP does not contain
+                                * trailing garbages.
+                                */
+                               qp += (oplen - 1);
+                               while (nllen > 0) {
+                                       *np = (*qp << sft) & 0xff;
+                                       if ((nllen -= (8 - sft)) <= 0)
+                                               break; /* done */
+                                       qp++;
+                                       *np |= ((*qp >> sft) & 0xff);
+                                       np++;
+                                       nllen -= sft;
+                               }
+                               *++np = 0;
+                       }
+
+                       /*
+                        * make a new bitlabel with the remaining bits.
+                        * Note that there's no buffer boundary issue, since
+                        * qlabel, olabel, and newlabel all have the same size.
+                        * ns_name_ntop() must not return 0, since we have
+                        * a non-empty bitlabel.
+                        */
+                       if ((n = ns_name_ntop(newlabel, qname, sizeof(qname)))
+                            <= 0)
+                               return(NULL);
+                       bufsiz -= n;
+                       if (qname[n - 1] != '.') { /* XXX no trailing dot */
+                               qname[n - 1] = '.';
+                               qname[n] = 0;
+                               bufsiz--;
+                       }
+
+               }
+       }
+
+  maketarget:
+       /*
+        * Finally, append the remaining part (maybe empty) to the new target.
+        */
+       if (bufsiz < (int)strlen(target)) /* bufsiz takes care of the \0. */
+               return(NULL);
+       strcat(qname, target);
+
+       return((const char *)qname);
+}
+
+static void
+ho_res_set(struct irs_ho *this, struct __res_state *res,
+               void (*free_res)(void *)) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (pvt->res && pvt->free_res) {
+               res_nclose(pvt->res);
+               (*pvt->free_res)(pvt->res);
+       }
+
+       pvt->res = res;
+       pvt->free_res = free_res;
+}
+
+/* Private. */
+
+static struct hostent *
+gethostans(struct irs_ho *this,
+          const u_char *ansbuf, int anslen, const char *qname, int qtype,
+          int af, int size,    /* meaningless for addrinfo cases */
+          struct addrinfo **ret_aip, const struct addrinfo *pai)
+{
+       struct pvt *pvt = (struct pvt *)this->private;
+       int type, class, buflen, ancount, qdcount, n, haveanswer, had_error;
+       int error = NETDB_SUCCESS, arcount;
+       int (*name_ok)(const char *);
+       const HEADER *hp;
+       const u_char *eom;
+       const u_char *cp;
+       const char *tname;
+       const char *hname;
+       char *bp, **ap, **hap;
+       char tbuf[MAXDNAME+1];
+       struct addrinfo sentinel, *cur, ai;
+       const u_char *arp = NULL;
+
+       if (pai == NULL) abort();
+       if (ret_aip != NULL)
+               *ret_aip = NULL;
+       memset(&sentinel, 0, sizeof(sentinel));
+       cur = &sentinel;
+
+       tname = qname;
+       eom = ansbuf + anslen;
+       switch (qtype) {
+       case ns_t_a6:
+       case T_A:
+       case T_AAAA:
+       case T_ANY:     /* use T_ANY only for T_A/T_AAAA lookup */
+               name_ok = res_hnok;
+               break;
+       case T_PTR:
+               name_ok = res_dnok;
+               break;
+       default:
+               abort();
+       }
+
+       pvt->host.h_addrtype = af;
+       pvt->host.h_length = size;
+       hname = pvt->host.h_name = NULL;
+
+       /*
+        * Find first satisfactory answer.
+        */
+       if (ansbuf + HFIXEDSZ > eom) {
+               RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+               return (NULL);
+       }
+       hp = (const HEADER *)ansbuf;
+       ancount = ntohs(hp->ancount);
+       qdcount = ntohs(hp->qdcount);
+       arcount = ntohs(hp->arcount);
+       bp = pvt->hostbuf;
+       buflen = sizeof pvt->hostbuf;
+       cp = ansbuf + HFIXEDSZ;
+       if (qdcount != 1) {
+               RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+               return (NULL);
+       }
+       n = dn_expand(ansbuf, eom, cp, bp, buflen);
+       if (n < 0 || !maybe_ok(pvt->res, bp, name_ok)) {
+               RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+               return (NULL);
+       }
+       cp += n + QFIXEDSZ;
+       if (cp > eom) {
+               RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+               return (NULL);
+       }
+       if (qtype == T_A || qtype == T_AAAA ||
+           qtype == ns_t_a6 || qtype == T_ANY) {
+               /* res_nsend() has already verified that the query name is the
+                * same as the one we sent; this just gets the expanded name
+                * (i.e., with the succeeding search-domain tacked on).
+                */
+               n = strlen(bp) + 1;             /* for the \0 */
+               if (n > MAXHOSTNAMELEN) {
+                       RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+                       return (NULL);
+               }
+               pvt->host.h_name = bp;
+               hname = bp;
+               bp += n;
+               buflen -= n;
+               /* The qname can be abbreviated, but hname is now absolute. */
+               qname = pvt->host.h_name;
+       }
+       ap = pvt->host_aliases;
+       *ap = NULL;
+       pvt->host.h_aliases = pvt->host_aliases;
+       hap = pvt->h_addr_ptrs;
+       *hap = NULL;
+       pvt->host.h_addr_list = pvt->h_addr_ptrs;
+       haveanswer = 0;
+       had_error = 0;
+       while (ancount-- > 0 && cp < eom && !had_error) {
+               n = dn_expand(ansbuf, eom, cp, bp, buflen);
+               if (n < 0 || !maybe_ok(pvt->res, bp, name_ok)) {
+                       had_error++;
+                       continue;
+               }
+               cp += n;                        /* name */
+               BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
+               type = ns_get16(cp);
+               cp += INT16SZ;                  /* type */
+               class = ns_get16(cp);
+               cp += INT16SZ + INT32SZ;        /* class, TTL */
+               n = ns_get16(cp);
+               cp += INT16SZ;                  /* len */
+               BOUNDS_CHECK(cp, n);
+               if (class != C_IN) {
+                       cp += n;
+                       continue;
+               }
+               if ((qtype == T_A || qtype == T_AAAA || qtype == ns_t_a6 ||
+                    qtype == T_ANY) && type == T_CNAME) {
+                       if (ap >= &pvt->host_aliases[MAXALIASES-1])
+                               continue;
+                       n = dn_expand(ansbuf, eom, cp, tbuf, sizeof tbuf);
+                       if (n < 0 || !maybe_ok(pvt->res, tbuf, name_ok)) {
+                               had_error++;
+                               continue;
+                       }
+                       cp += n;
+                       /* Store alias. */
+                       *ap++ = bp;
+                       n = strlen(bp) + 1;     /* for the \0 */
+                       bp += n;
+                       buflen -= n;
+                       /* Get canonical name. */
+                       n = strlen(tbuf) + 1;   /* for the \0 */
+                       if (n > buflen || n > MAXHOSTNAMELEN) {
+                               had_error++;
+                               continue;
+                       }
+                       strcpy(bp, tbuf);
+                       pvt->host.h_name = bp;
+                       hname = bp;
+                       bp += n;
+                       buflen -= n;
+                       continue;
+               }
+               if (type == ns_t_dname) {
+                       const char *t0, *t;
+
+                       /*
+                        * just replace the query target; do not update the
+                        * aliase list. (Or should we?)
+                        */
+                       t0 = (qtype == T_PTR) ? tname : hname;
+
+                       n = dn_expand(ansbuf, eom, cp, tbuf, sizeof(tbuf));
+                       if (n < 0 || !maybe_dnok(pvt->res, tbuf)) {
+                               had_error++;
+                               continue;
+                       }
+#ifdef RES_USE_DNAME
+                       if ((pvt ->res->options & RES_USE_DNAME) == 0) {
+                               cp += n;
+                               continue;
+                       }
+#endif
+                       if ((t = dname_subst(t0, bp, tbuf)) == NULL) {
+                               cp += n;
+                               continue;
+                       }
+#if 0                          /* for debug */
+                       if ((pvt->res->options & RES_DEBUG) != 0) {
+                               printf("DNAME owner=%s, target=%s, next=%s\n",
+                                      bp, tbuf, t);
+                       }
+#endif
+                       cp += n;
+
+                       n = strlen(t) + 1; /* for the \0 */
+                       if (n > buflen) {
+                               had_error++;
+                               continue;
+                       }
+                       strcpy(bp, t);
+                       if (qtype == T_PTR)
+                               tname = bp;
+                       else
+                               hname = bp;
+                       bp += n;
+                       buflen -= n;
+
+                       continue;
+               }
+               if (qtype == T_PTR && type == T_CNAME) {
+                       n = dn_expand(ansbuf, eom, cp, tbuf, sizeof tbuf);
+                       if (n < 0 || !maybe_dnok(pvt->res, tbuf)) {
+                               had_error++;
+                               continue;
+                       }
+                       cp += n;
+#ifdef RES_USE_DNAME
+                       if ((pvt->res->options & RES_USE_DNAME) != 0)
+#endif
+                       {
+                               /*
+                                * We may be able to check this regardless
+                                * of the USE_DNAME bit, but we add the check
+                                * for now since the DNAME support is
+                                * experimental.
+                                */
+                               if (ns_samename(tname, bp) != 1)
+                                       continue;
+                       }
+                       /* Get canonical name. */
+                       n = strlen(tbuf) + 1;   /* for the \0 */
+                       if (n > buflen) {
+                               had_error++;
+                               continue;
+                       }
+                       strcpy(bp, tbuf);
+                       tname = bp;
+                       bp += n;
+                       buflen -= n;
+                       continue;
+               }
+               if (qtype == T_ANY) {
+                       if (!(type == T_A || type == T_AAAA ||
+                             type == ns_t_a6)) {
+                               cp += n;
+                               continue;
+                       }
+               } else if (type != qtype) {
+                       cp += n;
+                       continue;
+               }
+               switch (type) {
+               case T_PTR:
+                       if (ret_aip != NULL) {
+                               /* addrinfo never needs T_PTR */
+                               cp += n;
+                               continue;
+                       }
+                       if (ns_samename(tname, bp) != 1) {
+                               cp += n;
+                               continue;
+                       }
+                       n = dn_expand(ansbuf, eom, cp, bp, buflen);
+                       if (n < 0 || !maybe_hnok(pvt->res, bp) ||
+                           n >= MAXHOSTNAMELEN) {
+                               had_error++;
+                               break;
+                       }
+                       cp += n;
+                       if (!haveanswer) {
+                               pvt->host.h_name = bp;
+                               hname = bp;
+                       }
+                       else if (ap < &pvt->host_aliases[MAXALIASES-1])
+                               *ap++ = bp;
+                       else
+                               n = -1;
+                       if (n != -1) {
+                               n = strlen(bp) + 1;     /* for the \0 */
+                               bp += n;
+                               buflen -= n;
+                       }
+                       break;
+               case ns_t_a6: {
+                       struct in6_addr in6;
+                       struct addrinfo ai;
+
+#ifdef RES_USE_A6
+                       if ((pvt->res->options & RES_USE_A6) == 0) {
+                               cp += n;
+                               continue;
+                       }
+#endif
+
+                       if (ns_samename(hname, bp) != 1) {
+                               cp += n;
+                               continue;
+                       }
+
+                       /*
+                        * search for the top of the additional section.
+                        * once found, keep it for the case where we have
+                        * more than one A6 record.
+                        * XXX: however, we may not need this part.
+                        */
+                       if (arp == NULL && arcount > 0) {
+                               int nscount = ntohs(hp->nscount);
+
+                               arp = ar_head(cp + n, nscount + ancount - 1,
+                                             ansbuf, eom, pvt, name_ok);
+                       }
+
+                       /* recursively collect the whole A6 chain */
+                       ai = *pai; /* XXX: we can't override constant pai */
+                       ai.ai_family = AF_INET6;
+                       memset(&in6, 0, sizeof(in6)); /* just for safety */
+                       cur->ai_next = a6_expand(ansbuf, cp, n, arp, eom,
+                                                &in6, 128,
+                                                (const struct addrinfo *)&ai,
+                                                pvt, name_ok, &error);
+                       if (error != NETDB_SUCCESS) {
+#ifdef DEBUG
+                               /* in this case, cur->ai_next must be NULL. */
+                               if (cur->ai_next != NULL)
+                                       abort();
+#endif
+                               had_error++;
+                               continue;
+                       }
+
+                       /*
+                        * We don't bother even if cur->ai_next is NULL unless
+                        * the expansion failed by a fatal error. The list
+                        * can be NULL if the given A6 is incomplete, but we
+                        * may have another complete A6 chain in this answer.
+                        * See the last paragraph of RFC 2874 Section 3.1.4. 
+                        */
+                       if (cur->ai_next == NULL) {
+                               cp += n;
+                               continue; /* no error, no answer */
+                       }
+                       goto convertinfo;
+               } /* FALLTHROUGH */
+               case T_A:
+               case T_AAAA:
+                       if (ns_samename(hname, bp) != 1) {
+                               cp += n;
+                               continue;
+                       }
+                       if (type == T_A && n != INADDRSZ) {
+                               cp += n;
+                               continue;
+                       }
+                       if (type == T_AAAA && n != IN6ADDRSZ) {
+                               cp += n;
+                               continue;
+                       }
+
+                       /* make addrinfo. don't overwrite constant PAI */
+                       ai = *pai;
+                       ai.ai_family = (type == T_AAAA) ? AF_INET6 : AF_INET;
+                       cur->ai_next = addr2addrinfo((const struct addrinfo *)&ai, cp);
+                       if (cur->ai_next == NULL)
+                               had_error++;
+
+                 convertinfo:  /* convert addrinfo into hostent form */
+                       if (!haveanswer) {
+                               int nn;
+
+                               nn = strlen(bp) + 1;    /* for the \0 */
+                               if (nn >= MAXHOSTNAMELEN) {
+                                       cp += n;
+                                       had_error++;
+                                       continue;
+                               }
+                               pvt->host.h_name = bp;
+                               hname = bp;
+                               bp += nn;
+                               buflen -= nn;
+                       }
+                       /* Ensure alignment. */
+                       bp += sizeof(align) - ((u_long)bp % sizeof(align));
+                       /* Avoid overflows. */
+                       if (bp + n >= &pvt->hostbuf[sizeof pvt->hostbuf]) {
+                               had_error++;
+                               continue;
+                       }
+                       if (ret_aip) { /* need addrinfo. keep it. */
+                               while (cur && cur->ai_next)
+                                       cur = cur->ai_next;
+                       } else if (cur->ai_next) { /* need hostent */
+                               struct addrinfo *aip = cur->ai_next;
+
+                               for (aip = cur->ai_next; aip;
+                                    aip = aip->ai_next) {
+                                       int m;
+
+                                       m = add_hostent(pvt, bp, hap, aip);
+                                       if (m < 0) {
+                                               had_error++;
+                                               break;
+                                       }
+                                       if (hap < &pvt->h_addr_ptrs[MAXADDRS-1])
+                                               hap++;
+
+                                       bp += m;
+                               }
+
+                               freeaddrinfo(cur->ai_next);
+                               cur->ai_next = NULL;
+                       }
+                       cp += n;
+                       break;
+               default:
+                       abort();
+               }
+               if (!had_error)
+                       haveanswer++;
+       }
+       if (haveanswer) {
+               if (ret_aip == NULL) {
+                       *ap = NULL;
+                       *hap = NULL;
+
+                       if (pvt->res->nsort && haveanswer > 1 && qtype == T_A)
+                               addrsort(pvt->res, pvt->h_addr_ptrs,
+                                        haveanswer);
+                       if (pvt->host.h_name == NULL) {
+                               n = strlen(qname) + 1;  /* for the \0 */
+                               if (n > buflen || n >= MAXHOSTNAMELEN)
+                                       goto no_recovery;
+                               strcpy(bp, qname);
+                               pvt->host.h_name = bp;
+                               bp += n;
+                               buflen -= n;
+                       }
+                       if (pvt->res->options & RES_USE_INET6)
+                               map_v4v6_hostent(&pvt->host, &bp, &buflen);
+                       RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS);
+                       return (&pvt->host);
+               } else {
+                       if ((pai->ai_flags & AI_CANONNAME) != 0) {
+                               if (pvt->host.h_name == NULL) {
+                                       sentinel.ai_next->ai_canonname =
+                                               strdup(qname);
+                               }
+                               else {
+                                       sentinel.ai_next->ai_canonname =
+                                               strdup(pvt->host.h_name);
+                               }
+                       }
+                       *ret_aip = sentinel.ai_next;
+                       return(NULL);
+               }
+       }
+ no_recovery:
+       if (sentinel.ai_next) {
+               /* this should be impossible, but check it for safety */
+               freeaddrinfo(sentinel.ai_next);
+       }
+       if (error == NETDB_SUCCESS)
+               RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+       else
+               RES_SET_H_ERRNO(pvt->res, error);
+       return(NULL);
+}
+
+static int
+add_hostent(struct pvt *pvt, char *bp, char **hap, struct addrinfo *ai)
+{
+       int addrlen;
+       char *addrp;
+
+       switch(ai->ai_addr->sa_family) {
+       case AF_INET6:
+               addrlen = IN6ADDRSZ;
+               addrp = (char *)&((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr;
+               break;
+       case AF_INET:
+               addrlen = INADDRSZ;
+               addrp = (char *)&((struct sockaddr_in *)ai->ai_addr)->sin_addr;
+               break;
+       default:
+               return(-1);     /* abort? */
+       }
+
+       bp += sizeof(align) - ((u_long)bp % sizeof(align));
+       if (bp + addrlen >= &pvt->hostbuf[sizeof pvt->hostbuf])
+               return(-1);
+       if (hap >= &pvt->h_addr_ptrs[MAXADDRS-1])
+               return(addrlen); /* fail, but not treat it as an error. */
+#if 0
+       /* Suppress duplicates. */
+       for (tap = (const char **)pvt->h_addr_ptrs;
+            *tap != NULL;
+            tap++)
+               if (memcmp(*tap, cp, n) == 0)
+                       break;
+       if (*tap != NULL) {
+               cp += n;
+               continue;
+       }
+#endif
+
+       memcpy(*hap = bp, addrp, addrlen);
+       return(addrlen);
+}
+
+static void
+map_v4v6_hostent(struct hostent *hp, char **bpp, int *lenp) {
+       char **ap;
+
+       if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ)
+               return;
+       hp->h_addrtype = AF_INET6;
+       hp->h_length = IN6ADDRSZ;
+       for (ap = hp->h_addr_list; *ap; ap++) {
+               int i = sizeof(align) - ((u_long)*bpp % sizeof(align));
+
+               if (*lenp < (i + IN6ADDRSZ)) {
+                       /* Out of memory.  Truncate address list here. */
+                       *ap = NULL;
+                       return;
+               }
+               *bpp += i;
+               *lenp -= i;
+               map_v4v6_address(*ap, *bpp);
+               *ap = *bpp;
+               *bpp += IN6ADDRSZ;
+               *lenp -= IN6ADDRSZ;
+       }
+}
+
+static void
+addrsort(res_state statp, char **ap, int num) {
+       int i, j, needsort = 0, aval[MAXADDRS];
+       char **p;
+
+       p = ap;
+       for (i = 0; i < num; i++, p++) {
+               for (j = 0 ; (unsigned)j < statp->nsort; j++)
+                       if (statp->sort_list[j].addr.s_addr == 
+                           (((struct in_addr *)(*p))->s_addr &
+                            statp->sort_list[j].mask))
+                               break;
+               aval[i] = j;
+               if (needsort == 0 && i > 0 && j < aval[i-1])
+                       needsort = i;
+       }
+       if (!needsort)
+               return;
+
+       while (needsort < num) {
+               for (j = needsort - 1; j >= 0; j--) {
+                       if (aval[j] > aval[j+1]) {
+                               char *hp;
+
+                               i = aval[j];
+                               aval[j] = aval[j+1];
+                               aval[j+1] = i;
+
+                               hp = ap[j];
+                               ap[j] = ap[j+1];
+                               ap[j+1] = hp;
+
+                       } else
+                               break;
+               }
+               needsort++;
+       }
+}
+
+static int
+init(struct irs_ho *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       
+       if (!pvt->res && !ho_res_get(this))
+               return (-1);
+       if (((pvt->res->options & RES_INIT) == 0) &&
+           res_ninit(pvt->res) == -1)
+               return (-1);
+       return (0);
+}
diff --git a/lib/bind/irs/dns_nw.c b/lib/bind/irs/dns_nw.c
new file mode 100644 (file)
index 0000000..41984f7
--- /dev/null
@@ -0,0 +1,566 @@
+/*
+ * 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 rcsid[] = "$Id: dns_nw.c,v 1.1 2001/03/29 06:31:42 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* Imports. */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "dns_p.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) sprintf x
+#endif
+
+/* Definitions. */
+
+#define        MAXALIASES      35
+
+#if PACKETSZ > 1024
+#define        MAXPACKET       PACKETSZ
+#else
+#define        MAXPACKET       1024
+#endif
+
+struct pvt {
+       struct nwent    net;
+       char *          ali[MAXALIASES];
+       char            buf[BUFSIZ+1];
+       struct __res_state * res;
+       void            (*free_res)(void *);
+};
+
+typedef union {
+       long    al;
+       char    ac;
+} align;
+
+enum by_what { by_addr, by_name };
+
+/* Forwards. */
+
+static void            nw_close(struct irs_nw *);
+static struct nwent *  nw_byname(struct irs_nw *, const char *, int);
+static struct nwent *  nw_byaddr(struct irs_nw *, void *, int, int);
+static struct nwent *  nw_next(struct irs_nw *);
+static void            nw_rewind(struct irs_nw *);
+static void            nw_minimize(struct irs_nw *);
+static struct __res_state * nw_res_get(struct irs_nw *this);
+static void            nw_res_set(struct irs_nw *this,
+                                  struct __res_state *res,
+                                  void (*free_res)(void *));
+
+static struct nwent *  get1101byaddr(struct irs_nw *, u_char *, int);
+static struct nwent *  get1101byname(struct irs_nw *, const char *);
+static struct nwent *  get1101answer(struct irs_nw *,
+                                     u_char *ansbuf, int anslen,
+                                     enum by_what by_what,
+                                     int af, const char *name,
+                                     const u_char *addr, int addrlen);
+static struct nwent *  get1101mask(struct irs_nw *this, struct nwent *);
+static int             make1101inaddr(const u_char *, int, char *, int);
+static void            normalize_name(char *name);
+static int             init(struct irs_nw *this);
+
+/* Exports. */
+
+struct irs_nw *
+irs_dns_nw(struct irs_acc *this) {
+       struct irs_nw *nw;
+       struct pvt *pvt;
+
+       UNUSED(this);
+
+       if (!(pvt = memget(sizeof *pvt))) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pvt, 0, sizeof *pvt);
+       if (!(nw = memget(sizeof *nw))) {
+               memput(pvt, sizeof *pvt);
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(nw, 0x5e, sizeof *nw);
+       nw->private = pvt;
+       nw->close = nw_close;
+       nw->byname = nw_byname;
+       nw->byaddr = nw_byaddr;
+       nw->next = nw_next;
+       nw->rewind = nw_rewind;
+       nw->minimize = nw_minimize;
+       nw->res_get = nw_res_get;
+       nw->res_set = nw_res_set;
+       return (nw);
+}
+
+/* Methods. */
+
+static void
+nw_close(struct irs_nw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       nw_minimize(this);
+
+       if (pvt->res && pvt->free_res)
+               (*pvt->free_res)(pvt->res);
+
+       memput(pvt, sizeof *pvt);
+       memput(this, sizeof *this);
+}
+
+static struct nwent *
+nw_byname(struct irs_nw *this, const char *name, int af) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (init(this) == -1)
+               return (NULL);
+
+       switch (af) {
+       case AF_INET:
+               return (get1101byname(this, name));
+       default:
+               (void)NULL;
+       }
+       RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+       errno = EAFNOSUPPORT;
+       return (NULL);
+}
+
+static struct nwent *
+nw_byaddr(struct irs_nw *this, void *net, int len, int af) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (init(this) == -1)
+               return (NULL);
+
+       switch (af) {
+       case AF_INET:
+               return (get1101byaddr(this, net, len));
+       default:
+               (void)NULL;
+       }
+       RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+       errno = EAFNOSUPPORT;
+       return (NULL);
+}
+
+static struct nwent *
+nw_next(struct irs_nw *this) {
+
+       UNUSED(this);
+
+       return (NULL);
+}
+
+static void
+nw_rewind(struct irs_nw *this) {
+       UNUSED(this);
+       /* NOOP */
+}
+
+static void
+nw_minimize(struct irs_nw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (pvt->res)
+               res_nclose(pvt->res);
+}
+
+static struct __res_state *
+nw_res_get(struct irs_nw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (!pvt->res) {
+               struct __res_state *res;
+               res = (struct __res_state *)malloc(sizeof *res);
+               if (!res) {
+                       errno = ENOMEM;
+                       return (NULL);
+               }
+               memset(res, 0, sizeof *res);
+               nw_res_set(this, res, free);
+       }
+
+       return (pvt->res);
+}
+
+static void
+nw_res_set(struct irs_nw *this, struct __res_state *res,
+               void (*free_res)(void *)) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (pvt->res && pvt->free_res) {
+               res_nclose(pvt->res);
+               (*pvt->free_res)(pvt->res);
+       }
+
+       pvt->res = res;
+       pvt->free_res = free_res;
+}
+
+/* Private. */
+
+static struct nwent *
+get1101byname(struct irs_nw *this, const char *name) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       u_char ansbuf[MAXPACKET];
+       int anslen;
+
+       anslen = res_nsearch(pvt->res, name, C_IN, T_PTR,
+                            ansbuf, sizeof ansbuf);
+       if (anslen < 0)
+               return (NULL);
+       return (get1101mask(this, get1101answer(this, ansbuf, anslen, by_name,
+                                               AF_INET, name, NULL, 0)));
+}
+
+static struct nwent *
+get1101byaddr(struct irs_nw *this, u_char *net, int len) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       char qbuf[sizeof "255.255.255.255.in-addr.arpa"];
+       u_char ansbuf[MAXPACKET];
+       int anslen;
+
+       if (len < 1 || len > 32) {
+               errno = EINVAL;
+               RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+               return (NULL);
+       }
+       if (make1101inaddr(net, len, qbuf, sizeof qbuf) < 0)
+               return (NULL);
+       anslen = res_nquery(pvt->res, qbuf, C_IN, T_PTR,
+                           ansbuf, sizeof ansbuf);
+       if (anslen < 0)
+               return (NULL);
+       return (get1101mask(this, get1101answer(this, ansbuf, anslen, by_addr,
+                                               AF_INET, NULL, net, len)));
+}
+
+static struct nwent *
+get1101answer(struct irs_nw *this,
+             u_char *ansbuf, int anslen, enum by_what by_what,
+             int af, const char *name, const u_char *addr, int addrlen)
+{
+       struct pvt *pvt = (struct pvt *)this->private;
+       int type, class, buflen, ancount, qdcount, haveanswer;
+       char *bp, **ap;
+       u_char *cp, *eom;
+       HEADER *hp;
+
+       /* Initialize, and parse header. */
+       eom = ansbuf + anslen;
+       if (ansbuf + HFIXEDSZ > eom) {
+               RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+               return (NULL);
+       }
+       hp = (HEADER *)ansbuf;
+       cp = ansbuf + HFIXEDSZ;
+       qdcount = ntohs(hp->qdcount);
+       while (qdcount-- > 0) {
+               int n = dn_skipname(cp, eom);
+               cp += n + QFIXEDSZ;
+               if (n < 0 || cp > eom) {
+                       RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+                       return (NULL);
+               }
+       }
+       ancount = ntohs(hp->ancount);
+       if (!ancount) {
+               if (hp->aa)
+                       RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
+               else
+                       RES_SET_H_ERRNO(pvt->res, TRY_AGAIN);
+               return (NULL);
+       }
+
+       /* Prepare a return structure. */
+       bp = pvt->buf;
+       buflen = sizeof pvt->buf;
+       pvt->net.n_name = NULL;
+       pvt->net.n_aliases = pvt->ali;
+       pvt->net.n_addrtype = af;
+       pvt->net.n_addr = NULL;
+       pvt->net.n_length = addrlen;
+
+       /* Save input key if given. */
+       switch (by_what) {
+       case by_name:
+               if (name != NULL) {
+                       int n = strlen(name) + 1;
+
+                       if (n > buflen) {
+                               RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+                               return (NULL);
+                       }
+                       pvt->net.n_name = strcpy(bp, name);
+                       bp += n;
+                       buflen -= n;
+               }
+               break;
+       case by_addr:
+               if (addr != NULL && addrlen != 0) {
+                       int n = addrlen / 8 + ((addrlen % 8) != 0);
+
+                       if (INADDRSZ > buflen) {
+                               RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+                               return (NULL);
+                       }
+                       memset(bp, 0, INADDRSZ);
+                       memcpy(bp, addr, n);
+                       pvt->net.n_addr = bp;
+                       bp += INADDRSZ;
+                       buflen -= INADDRSZ;
+               }
+               break;
+       default:
+               abort();
+       }
+
+       /* Parse the answer, collect aliases. */
+       ap = pvt->ali;
+       haveanswer = 0;
+       while (--ancount >= 0 && cp < eom) {
+               int n = dn_expand(ansbuf, eom, cp, bp, buflen);
+
+               cp += n;                /* Owner */
+               if (n < 0 || !maybe_dnok(pvt->res, bp) ||
+                   cp + 3 * INT16SZ + INT32SZ > eom) {
+                       RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+                       return (NULL);
+               }
+               GETSHORT(type, cp);     /* Type */
+               GETSHORT(class, cp);    /* Class */
+               cp += INT32SZ;          /* TTL */
+               GETSHORT(n, cp);        /* RDLENGTH */
+               if (class == C_IN && type == T_PTR) {
+                       int nn;
+
+                       nn = dn_expand(ansbuf, eom, cp, bp, buflen);
+                       if (nn < 0 || !maybe_hnok(pvt->res, bp) || nn != n) {
+                               RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+                               return (NULL);
+                       }
+                       normalize_name(bp);
+                       switch (by_what) {
+                       case by_addr: {
+                               if (pvt->net.n_name == NULL)
+                                       pvt->net.n_name = bp;
+                               else if (ns_samename(pvt->net.n_name, bp) == 1)
+                                       break;
+                               else
+                                       *ap++ = bp;
+                               nn = strlen(bp) + 1;
+                               bp += nn;
+                               buflen -= nn;
+                               haveanswer++;
+                               break;
+                           }
+                       case by_name: {
+                               u_int b1, b2, b3, b4;
+
+                               if (pvt->net.n_addr != NULL ||
+                                   sscanf(bp, "%u.%u.%u.%u.in-addr.arpa",
+                                          &b1, &b2, &b3, &b4) != 4)
+                                       break;
+                               if (buflen < INADDRSZ) {
+                                       RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+                                       return (NULL);
+                               }
+                               pvt->net.n_addr = bp;
+                               *bp++ = b4;
+                               *bp++ = b3;
+                               *bp++ = b2;
+                               *bp++ = b1;
+                               buflen -= INADDRSZ;
+                               pvt->net.n_length = INADDRSZ * 8;
+                               haveanswer++;
+                           }
+                       }
+               }
+               cp += n;                /* RDATA */
+       }
+       if (!haveanswer) {
+               RES_SET_H_ERRNO(pvt->res, TRY_AGAIN);
+               return (NULL);
+       }
+       *ap = NULL;
+
+       return (&pvt->net);
+}
+
+static struct nwent *
+get1101mask(struct irs_nw *this, struct nwent *nwent) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       char qbuf[sizeof "255.255.255.255.in-addr.arpa"], owner[MAXDNAME];
+       int anslen, type, class, ancount, qdcount;
+       u_char ansbuf[MAXPACKET], *cp, *eom;
+       HEADER *hp;
+
+       if (!nwent)
+               return (NULL);
+       if (make1101inaddr(nwent->n_addr, nwent->n_length, qbuf, sizeof qbuf)
+           < 0) {
+               /* "First, do no harm." */
+               return (nwent);
+       }
+
+       /* Query for the A RR that would hold this network's mask. */
+       anslen = res_nquery(pvt->res, qbuf, C_IN, T_A, ansbuf, sizeof ansbuf);
+       if (anslen < HFIXEDSZ)
+               return (nwent);
+
+       /* Initialize, and parse header. */
+       hp = (HEADER *)ansbuf;
+       cp = ansbuf + HFIXEDSZ;
+       eom = ansbuf + anslen;
+       qdcount = ntohs(hp->qdcount);
+       while (qdcount-- > 0) {
+               int n = dn_skipname(cp, eom);
+               cp += n + QFIXEDSZ;
+               if (n < 0 || cp > eom)
+                       return (nwent);
+       }
+       ancount = ntohs(hp->ancount);
+
+       /* Parse the answer, collect aliases. */
+       while (--ancount >= 0 && cp < eom) {
+               int n = dn_expand(ansbuf, eom, cp, owner, sizeof owner);
+
+               if (n < 0 || !maybe_dnok(pvt->res, owner))
+                       break;
+               cp += n;                /* Owner */
+               if (cp + 3 * INT16SZ + INT32SZ > eom)
+                       break;
+               GETSHORT(type, cp);     /* Type */
+               GETSHORT(class, cp);    /* Class */
+               cp += INT32SZ;          /* TTL */
+               GETSHORT(n, cp);        /* RDLENGTH */
+               if (cp + n > eom)
+                       break;
+               if (n == INADDRSZ && class == C_IN && type == T_A &&
+                   ns_samename(qbuf, owner) == 1) {
+                       /* This A RR indicates the actual netmask. */
+                       int nn, mm;
+
+                       nwent->n_length = 0;
+                       for (nn = 0; nn < INADDRSZ; nn++)
+                               for (mm = 7; mm >= 0; mm--)
+                                       if (cp[nn] & (1 << mm))
+                                               nwent->n_length++;
+                                       else
+                                               break;
+               }
+               cp += n;                /* RDATA */
+       }
+       return (nwent);
+}
+
+static int
+make1101inaddr(const u_char *net, int bits, char *name, int size) {
+       int n, m;
+
+       /* Zero fill any whole bytes left out of the prefix. */
+       for (n = (32 - bits) / 8; n > 0; n--) {
+               if (size < (int)(sizeof "0."))
+                       goto emsgsize;
+               m = SPRINTF((name, "0."));
+               name += m;
+               size -= m;
+       }
+
+       /* Format the partial byte, if any, within the prefix. */
+       if ((n = bits % 8) != 0) {
+               if (size < (int)(sizeof "255."))
+                       goto emsgsize;
+               m = SPRINTF((name, "%u.",
+                            net[bits / 8] & ~((1 << (8 - n)) - 1)));
+               name += m;
+               size -= m;
+       }
+
+       /* Format the whole bytes within the prefix. */
+       for (n = bits / 8; n > 0; n--) {
+               if (size < (int)(sizeof "255."))
+                       goto emsgsize;
+               m = SPRINTF((name, "%u.", net[n - 1]));
+               name += m;
+               size -= m;
+       }
+
+       /* Add the static text. */
+       if (size < (int)(sizeof "in-addr.arpa"))
+               goto emsgsize;
+       (void) SPRINTF((name, "in-addr.arpa"));
+       return (0);
+
+ emsgsize:
+       errno = EMSGSIZE;
+       return (-1);
+}
+
+static void
+normalize_name(char *name) {
+       char *t;
+
+       /* Make lower case. */
+       for (t = name; *t; t++)
+               if (isascii(*t) && isupper(*t))
+                       *t = tolower(*t);
+
+       /* Remove trailing dots. */
+       while (t > name && t[-1] == '.')
+               *--t = '\0';
+}
+
+static int
+init(struct irs_nw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       
+       if (!pvt->res && !nw_res_get(this))
+               return (-1);
+       if (((pvt->res->options & RES_INIT) == 0) &&
+           res_ninit(pvt->res) == -1)
+               return (-1);
+       return (0);
+}
diff --git a/lib/bind/irs/dns_p.h b/lib/bind/irs/dns_p.h
new file mode 100644 (file)
index 0000000..3f9b554
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+/*
+ * $Id: dns_p.h,v 1.1 2001/03/29 06:31:42 marka Exp $
+ */
+
+#ifndef _DNS_P_H_INCLUDED
+#define        _DNS_P_H_INCLUDED
+
+#define        maybe_ok(res, nm, ok) (((res)->options & RES_NOCHECKNAME) != 0 || \
+                              (ok)(nm) != 0)
+#define maybe_hnok(res, hn) maybe_ok((res), (hn), res_hnok)
+#define maybe_dnok(res, dn) maybe_ok((res), (dn), res_dnok)
+
+/*
+ * Object state.
+ */
+struct dns_p {
+       void                    *hes_ctx;
+       struct __res_state      *res;
+       void                    (*free_res) __P((void *));
+};
+
+/*
+ * Methods.
+ */
+
+extern struct irs_gr * irs_dns_gr __P((struct irs_acc *));
+extern struct irs_pw * irs_dns_pw __P((struct irs_acc *));
+extern struct irs_sv * irs_dns_sv __P((struct irs_acc *));
+extern struct irs_pr * irs_dns_pr __P((struct irs_acc *));
+extern struct irs_ho * irs_dns_ho __P((struct irs_acc *));
+extern struct irs_nw * irs_dns_nw __P((struct irs_acc *));
+
+#endif /*_DNS_P_H_INCLUDED*/
diff --git a/lib/bind/irs/dns_pr.c b/lib/bind/irs/dns_pr.c
new file mode 100644 (file)
index 0000000..fc0c872
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * 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 rcsid[] = "$Id: dns_pr.c,v 1.1 2001/03/29 06:31:42 marka Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "hesiod.h"
+#include "dns_p.h"
+
+/* Types. */
+
+struct pvt {
+       struct dns_p *          dns;
+       struct protoent         proto;
+       char *                  prbuf;
+};
+
+/* Forward. */
+
+static void                    pr_close(struct irs_pr *);
+static struct protoent *       pr_byname(struct irs_pr *, const char *);
+static struct protoent *       pr_bynumber(struct irs_pr *, int);
+static struct protoent *       pr_next(struct irs_pr *);
+static void                    pr_rewind(struct irs_pr *);
+static void                    pr_minimize(struct irs_pr *);
+static struct __res_state *    pr_res_get(struct irs_pr *);
+static void                    pr_res_set(struct irs_pr *,
+                                          struct __res_state *,
+                                          void (*)(void *));
+
+static struct protoent *       parse_hes_list(struct irs_pr *, char **);
+
+/* Public. */
+
+struct irs_pr *
+irs_dns_pr(struct irs_acc *this) {
+       struct dns_p *dns = (struct dns_p *)this->private;
+       struct pvt *pvt;
+       struct irs_pr *pr;
+
+       if (!dns->hes_ctx) {
+               errno = ENODEV;
+               return (NULL);
+       }
+       if (!(pvt = memget(sizeof *pvt))) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pvt, 0, sizeof *pvt);
+       if (!(pr = memget(sizeof *pr))) {
+               memput(pvt, sizeof *pvt);
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pr, 0x5e, sizeof *pr);
+       pvt->dns = dns;
+       pr->private = pvt;
+       pr->byname = pr_byname;
+       pr->bynumber = pr_bynumber;
+       pr->next = pr_next;
+       pr->rewind = pr_rewind;
+       pr->close = pr_close;
+       pr->minimize = pr_minimize;
+       pr->res_get = pr_res_get;
+       pr->res_set = pr_res_set;
+       return (pr);
+}
+
+/* Methods. */
+
+static void
+pr_close(struct irs_pr *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (pvt->proto.p_aliases)
+               free(pvt->proto.p_aliases);
+       if (pvt->prbuf)
+               free(pvt->prbuf);
+
+       memput(pvt, sizeof *pvt);
+       memput(this, sizeof *this);
+}
+
+static struct protoent *
+pr_byname(struct irs_pr *this, const char *name) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct dns_p *dns = pvt->dns;
+       struct protoent *proto;
+       char **hes_list;
+
+       if (!(hes_list = hesiod_resolve(dns->hes_ctx, name, "protocol")))
+               return (NULL);
+
+       proto = parse_hes_list(this, hes_list);
+       hesiod_free_list(dns->hes_ctx, hes_list);
+       return (proto);
+}
+
+static struct protoent *
+pr_bynumber(struct irs_pr *this, int num) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct dns_p *dns = pvt->dns;
+       struct protoent *proto;
+       char numstr[16];
+       char **hes_list;
+
+       sprintf(numstr, "%d", num);
+       if (!(hes_list = hesiod_resolve(dns->hes_ctx, numstr, "protonum")))
+               return (NULL);
+       
+       proto = parse_hes_list(this, hes_list);
+       hesiod_free_list(dns->hes_ctx, hes_list);
+       return (proto);
+}
+
+static struct protoent *
+pr_next(struct irs_pr *this) {
+       UNUSED(this);
+       errno = ENODEV;
+       return (NULL);
+}
+
+static void
+pr_rewind(struct irs_pr *this) {
+       UNUSED(this);
+       /* NOOP */
+}
+
+static void
+pr_minimize(struct irs_pr *this) {
+       UNUSED(this);
+       /* NOOP */
+}
+
+static struct __res_state *
+pr_res_get(struct irs_pr *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct dns_p *dns = pvt->dns;
+
+       return (__hesiod_res_get(dns->hes_ctx));
+}
+
+static void
+pr_res_set(struct irs_pr *this, struct __res_state * res,
+          void (*free_res)(void *)) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct dns_p *dns = pvt->dns;
+
+       __hesiod_res_set(dns->hes_ctx, res, free_res);
+}
+
+/* Private. */
+
+static struct protoent *
+parse_hes_list(struct irs_pr *this, char **hes_list) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       char *p, *cp, **cpp, **new;
+       int num = 0;
+       int max = 0;
+       
+       for (cpp = hes_list; *cpp; cpp++) {
+               cp = *cpp;
+
+               /* Strip away comments, if any. */
+               if ((p = strchr(cp, '#')))
+                       *p = 0;
+
+               /* Skip blank lines. */
+               p = cp;
+               while (*p && !isspace(*p))
+                       p++;
+               if (!*p)
+                       continue;
+
+               /* OK, we've got a live one.  Let's parse it for real. */
+               if (pvt->prbuf)
+                       free(pvt->prbuf);
+               pvt->prbuf = strdup(cp);
+
+               p = pvt->prbuf;
+               pvt->proto.p_name = p;
+               while (*p && !isspace(*p))
+                       p++;
+               if (!*p)
+                       continue;
+               *p++ = '\0';
+
+               pvt->proto.p_proto = atoi(p);
+               while (*p && !isspace(*p))
+                       p++;
+               if (*p)
+                       *p++ = '\0';
+
+               while (*p) {
+                       if ((num + 1) >= max || !pvt->proto.p_aliases) {
+                               max += 10;
+                               new = realloc(pvt->proto.p_aliases,
+                                             max * sizeof(char *));
+                               if (!new) {
+                                       errno = ENOMEM;
+                                       goto cleanup;
+                               }
+                               pvt->proto.p_aliases = new;
+                       }
+                       pvt->proto.p_aliases[num++] = p;
+                       while (*p && !isspace(*p))
+                               p++;
+                       if (*p)
+                               *p++ = '\0';
+               }
+               if (!pvt->proto.p_aliases)
+                       pvt->proto.p_aliases = malloc(sizeof(char *));
+               if (!pvt->proto.p_aliases)
+                       goto cleanup;
+               pvt->proto.p_aliases[num] = NULL;
+               return (&pvt->proto);
+       }
+       
+ cleanup:
+       if (pvt->proto.p_aliases) {
+               free(pvt->proto.p_aliases);
+               pvt->proto.p_aliases = NULL;
+       }
+       if (pvt->prbuf) {
+               free(pvt->prbuf);
+               pvt->prbuf = NULL;
+       }
+       return (NULL);
+}
diff --git a/lib/bind/irs/dns_pw.c b/lib/bind/irs/dns_pw.c
new file mode 100644 (file)
index 0000000..f387848
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * 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 rcsid[] = "$Id: dns_pw.c,v 1.1 2001/03/29 06:31:42 marka Exp $";
+#endif
+
+#include "port_before.h"
+
+#ifndef WANT_IRS_PW
+static int __bind_irs_pw_unneeded;
+#else
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <isc/memcluster.h>
+
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "hesiod.h"
+#include "dns_p.h"
+
+/* Types. */
+
+struct pvt {
+       struct dns_p *  dns;
+       struct passwd   passwd;
+       char *          pwbuf;
+};
+
+/* Forward. */
+
+static void                    pw_close(struct irs_pw *);
+static struct passwd *         pw_byname(struct irs_pw *, const char *);
+static struct passwd *         pw_byuid(struct irs_pw *, uid_t);
+static struct passwd *         pw_next(struct irs_pw *);
+static void                    pw_rewind(struct irs_pw *);
+static void                    pw_minimize(struct irs_pw *);
+static struct __res_state *    pw_res_get(struct irs_pw *);
+static void                    pw_res_set(struct irs_pw *,
+                                          struct __res_state *,
+                                          void (*)(void *));
+
+static struct passwd *         getpwcommon(struct irs_pw *, const char *,
+                                           const char *);
+
+/* Public. */
+
+struct irs_pw *
+irs_dns_pw(struct irs_acc *this) {
+       struct dns_p *dns = (struct dns_p *)this->private;
+       struct irs_pw *pw;
+       struct pvt *pvt;
+
+       if (!dns || !dns->hes_ctx) {
+               errno = ENODEV;
+               return (NULL);
+       }
+       if (!(pvt = memget(sizeof *pvt))) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pvt, 0, sizeof *pvt);
+       pvt->dns = dns;
+       if (!(pw = memget(sizeof *pw))) {
+               memput(pvt, sizeof *pvt);
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pw, 0x5e, sizeof *pw);
+       pw->private = pvt;
+       pw->close = pw_close;
+       pw->byname = pw_byname;
+       pw->byuid = pw_byuid;
+       pw->next = pw_next;
+       pw->rewind = pw_rewind;
+       pw->minimize = pw_minimize;
+       pw->res_get = pw_res_get;
+       pw->res_set = pw_res_set;
+       return (pw);
+}
+
+/* Methods. */
+
+static void
+pw_close(struct irs_pw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (pvt->pwbuf)
+               free(pvt->pwbuf);
+
+       memput(pvt, sizeof *pvt);
+       memput(this, sizeof *this);
+}
+
+static struct passwd *
+pw_byname(struct irs_pw *this, const char *nam) {
+       return (getpwcommon(this, nam, "passwd"));
+}
+
+static struct passwd *
+pw_byuid(struct irs_pw *this, uid_t uid) {
+       char uidstr[16];
+
+       sprintf(uidstr, "%lu", (u_long)uid);
+       return (getpwcommon(this, uidstr, "uid"));
+}
+
+static struct passwd *
+pw_next(struct irs_pw *this) {
+       UNUSED(this);
+       errno = ENODEV;
+       return (NULL);
+}
+
+static void
+pw_rewind(struct irs_pw *this) {
+       UNUSED(this);
+       /* NOOP */
+}
+
+static void
+pw_minimize(struct irs_pw *this) {
+       UNUSED(this);
+       /* NOOP */
+}
+
+static struct __res_state *
+pw_res_get(struct irs_pw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct dns_p *dns = pvt->dns;
+
+       return (__hesiod_res_get(dns->hes_ctx));
+}
+
+static void
+pw_res_set(struct irs_pw *this, struct __res_state * res,
+          void (*free_res)(void *)) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct dns_p *dns = pvt->dns;
+
+       __hesiod_res_set(dns->hes_ctx, res, free_res);
+}
+
+/* Private. */
+
+static struct passwd *
+getpwcommon(struct irs_pw *this, const char *arg, const char *type) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       char **hes_list, *cp;
+
+       if (!(hes_list = hesiod_resolve(pvt->dns->hes_ctx, arg, type)))
+               return (NULL);
+       if (!*hes_list) {
+               hesiod_free_list(pvt->dns->hes_ctx, hes_list);
+               errno = ENOENT;
+               return (NULL);
+       }
+
+       memset(&pvt->passwd, 0, sizeof pvt->passwd);
+       if (pvt->pwbuf)
+               free(pvt->pwbuf);
+       pvt->pwbuf = strdup(*hes_list);
+       hesiod_free_list(pvt->dns->hes_ctx, hes_list);
+
+       cp = pvt->pwbuf;
+       pvt->passwd.pw_name = cp;
+       if (!(cp = strchr(cp, ':')))
+               goto cleanup;
+       *cp++ = '\0';
+
+       pvt->passwd.pw_passwd = cp;
+       if (!(cp = strchr(cp, ':')))
+               goto cleanup;
+       *cp++ = '\0';
+       
+       pvt->passwd.pw_uid = atoi(cp);
+       if (!(cp = strchr(cp, ':')))
+               goto cleanup;
+       *cp++ = '\0';
+
+       pvt->passwd.pw_gid = atoi(cp);
+       if (!(cp = strchr(cp, ':')))
+               goto cleanup;
+       *cp++ = '\0';
+
+       pvt->passwd.pw_gecos = cp;
+       if (!(cp = strchr(cp, ':')))
+               goto cleanup;
+       *cp++ = '\0';
+
+       pvt->passwd.pw_dir = cp;
+       if (!(cp = strchr(cp, ':')))
+               goto cleanup;
+       *cp++ = '\0';
+
+       pvt->passwd.pw_shell = cp;
+       return (&pvt->passwd);
+       
+ cleanup:
+       free(pvt->pwbuf);
+       pvt->pwbuf = NULL;
+       return (NULL);
+}
+
+#endif /* WANT_IRS_PW */
diff --git a/lib/bind/irs/dns_sv.c b/lib/bind/irs/dns_sv.c
new file mode 100644 (file)
index 0000000..73db164
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * 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 rcsid[] = "$Id: dns_sv.c,v 1.1 2001/03/29 06:31:43 marka Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "hesiod.h"
+#include "dns_p.h"
+
+/* Definitions */
+
+struct pvt {
+       struct dns_p *          dns;
+       struct servent          serv;
+       char *                  svbuf;
+       struct __res_state *    res;
+       void                    (*free_res)(void *);
+};
+
+/* Forward. */
+
+static void                    sv_close(struct irs_sv *);
+static struct servent *                sv_byname(struct irs_sv *,
+                                         const char *, const char *);
+static struct servent *                sv_byport(struct irs_sv *, int, const char *);
+static struct servent *                sv_next(struct irs_sv *);
+static void                    sv_rewind(struct irs_sv *);
+static void                    sv_minimize(struct irs_sv *);
+#ifdef SV_RES_SETGET
+static struct __res_state *    sv_res_get(struct irs_sv *);
+static void                    sv_res_set(struct irs_sv *,
+                                          struct __res_state *,
+                                          void (*)(void *));
+#endif
+
+static struct servent *                parse_hes_list(struct irs_sv *,
+                                              char **, const char *);
+
+/* Public */
+
+struct irs_sv *
+irs_dns_sv(struct irs_acc *this) {
+       struct dns_p *dns = (struct dns_p *)this->private;
+       struct irs_sv *sv;
+       struct pvt *pvt;
+
+       if (!dns || !dns->hes_ctx) {
+               errno = ENODEV;
+               return (NULL);
+       }
+       if (!(pvt = memget(sizeof *pvt))) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pvt, 0, sizeof *pvt);
+       pvt->dns = dns;
+       if (!(sv = memget(sizeof *sv))) {
+               memput(pvt, sizeof *pvt);
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(sv, 0x5e, sizeof *sv);
+       sv->private = pvt;
+       sv->byname = sv_byname;
+       sv->byport = sv_byport;
+       sv->next = sv_next;
+       sv->rewind = sv_rewind;
+       sv->close = sv_close;
+       sv->minimize = sv_minimize;
+#ifdef SV_RES_SETGET
+       sv->res_get = sv_res_get;
+       sv->res_set = sv_res_set;
+#else
+       sv->res_get = NULL; /* sv_res_get; */
+       sv->res_set = NULL; /* sv_res_set; */
+#endif
+       return (sv);
+}
+
+/* Methods */
+
+static void
+sv_close(struct irs_sv *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (pvt->serv.s_aliases)
+               free(pvt->serv.s_aliases);
+       if (pvt->svbuf)
+               free(pvt->svbuf);
+
+       if (pvt->res && pvt->free_res)
+               (*pvt->free_res)(pvt->res);
+       memput(pvt, sizeof *pvt);
+       memput(this, sizeof *this);
+}
+
+static struct servent *
+sv_byname(struct irs_sv *this, const char *name, const char *proto) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct dns_p *dns = pvt->dns;
+       struct servent *s;
+       char **hes_list;
+
+       if (!(hes_list = hesiod_resolve(dns->hes_ctx, name, "service")))
+               return (NULL);
+
+       s = parse_hes_list(this, hes_list, proto);
+       hesiod_free_list(dns->hes_ctx, hes_list);
+       return (s);
+}
+
+static struct servent *
+sv_byport(struct irs_sv *this, int port, const char *proto) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct dns_p *dns = pvt->dns;
+       struct servent *s;
+       char portstr[16];
+       char **hes_list;
+
+       sprintf(portstr, "%d", ntohs(port));
+       if (!(hes_list = hesiod_resolve(dns->hes_ctx, portstr, "port")))
+               return (NULL);
+       
+       s = parse_hes_list(this, hes_list, proto);
+       hesiod_free_list(dns->hes_ctx, hes_list);
+       return (s);
+}
+
+static struct servent *
+sv_next(struct irs_sv *this) {
+       UNUSED(this);
+       errno = ENODEV;
+       return (NULL);
+}
+
+static void
+sv_rewind(struct irs_sv *this) {
+       UNUSED(this);
+       /* NOOP */
+}
+
+/* Private */
+
+static struct servent *
+parse_hes_list(struct irs_sv *this, char **hes_list, const char *proto) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       char *p, *cp, **cpp, **new;
+       int proto_len;
+       int num = 0;
+       int max = 0;
+       
+       for (cpp = hes_list; *cpp; cpp++) {
+               cp = *cpp;
+
+               /* Strip away comments, if any. */
+               if ((p = strchr(cp, '#')))
+                       *p = 0;
+
+               /* Check to make sure the protocol matches. */
+               p = cp;
+               while (*p && !isspace(*p))
+                       p++;
+               if (!*p)
+                       continue;
+               if (proto) {
+                    proto_len = strlen(proto);
+                    if (strncasecmp(++p, proto, proto_len) != 0)
+                         continue;
+                    if (p[proto_len] && !isspace(p[proto_len]))
+                         continue;
+               }
+               /* OK, we've got a live one.  Let's parse it for real. */
+               if (pvt->svbuf)
+                       free(pvt->svbuf);
+               pvt->svbuf = strdup(cp);
+
+               p = pvt->svbuf;
+               pvt->serv.s_name = p;
+               while (*p && !isspace(*p))
+                       p++;
+               if (!*p)
+                       continue;
+               *p++ = '\0';
+
+               pvt->serv.s_proto = p;
+               while (*p && !isspace(*p))
+                       p++;
+               if (!*p)
+                       continue;
+               *p++ = '\0';
+
+               pvt->serv.s_port = htons((u_short) atoi(p));
+               while (*p && !isspace(*p))
+                       p++;
+               if (*p)
+                       *p++ = '\0';
+
+               while (*p) {
+                       if ((num + 1) >= max || !pvt->serv.s_aliases) {
+                               max += 10;
+                               new = realloc(pvt->serv.s_aliases,
+                                             max * sizeof(char *));
+                               if (!new) {
+                                       errno = ENOMEM;
+                                       goto cleanup;
+                               }
+                               pvt->serv.s_aliases = new;
+                       }
+                       pvt->serv.s_aliases[num++] = p;
+                       while (*p && !isspace(*p))
+                               p++;
+                       if (*p)
+                               *p++ = '\0';
+               }
+               if (!pvt->serv.s_aliases)
+                       pvt->serv.s_aliases = malloc(sizeof(char *));
+               if (!pvt->serv.s_aliases)
+                       goto cleanup;
+               pvt->serv.s_aliases[num] = NULL;
+               return (&pvt->serv);
+       }
+       
+ cleanup:
+       if (pvt->serv.s_aliases) {
+               free(pvt->serv.s_aliases);
+               pvt->serv.s_aliases = NULL;
+       }
+       if (pvt->svbuf) {
+               free(pvt->svbuf);
+               pvt->svbuf = NULL;
+       }
+       return (NULL);
+}
+
+static void
+sv_minimize(struct irs_sv *this) {
+       UNUSED(this);
+       /* NOOP */
+}
+
+#ifdef SV_RES_SETGET
+static struct __res_state *
+sv_res_get(struct irs_sv *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct dns_p *dns = pvt->dns;
+
+       return (__hesiod_res_get(dns->hes_ctx));
+}
+
+static void
+sv_res_set(struct irs_sv *this, struct __res_state * res,
+          void (*free_res)(void *)) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct dns_p *dns = pvt->dns;
+
+       __hesiod_res_set(dns->hes_ctx, res, free_res);
+}
+#endif
diff --git a/lib/bind/irs/gai_strerror.c b/lib/bind/irs/gai_strerror.c
new file mode 100644 (file)
index 0000000..55fa1f7
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+%%% copyright-cmetz-97
+This software is Copyright 1997-1998 by Craig Metz, All Rights Reserved.
+The Inner Net License Version 2 applies to this software.
+You should have received a copy of the license with this software. If
+you didn't get a copy, you may request one from <license@inner.net>.
+
+*/
+
+#include <port_before.h>
+#include <netdb.h>
+#include <errno.h>
+#include <port_after.h>
+
+const char *
+gai_strerror(int errnum) {
+       switch(errnum) {
+       case 0:
+               return "no error";
+       case EAI_BADFLAGS:
+               return "invalid value for ai_flags";
+       case EAI_NONAME:
+               return "name or service is not known";
+       case EAI_AGAIN:
+               return "temporary failure in name resolution";
+       case EAI_FAIL:
+               return "non-recoverable failure in name resolution";
+       case EAI_NODATA:
+               return "no address associated with name";
+       case EAI_FAMILY:
+               return "ai_family not supported";
+       case EAI_SOCKTYPE:
+               return "ai_socktype not supported";
+       case EAI_SERVICE:
+               return "service not supported for ai_socktype";
+       case EAI_ADDRFAMILY:
+               return "address family for name not supported";
+       case EAI_MEMORY:
+               return "memory allocation failure";
+       case EAI_SYSTEM:
+               return "system error";
+       default:
+               return "unknown error";
+       };
+}
diff --git a/lib/bind/irs/gen.c b/lib/bind/irs/gen.c
new file mode 100644 (file)
index 0000000..9a208d7
--- /dev/null
@@ -0,0 +1,427 @@
+/*
+ * 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(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: gen.c,v 1.1 2001/03/29 06:31:43 marka Exp $";
+#endif
+
+/*
+ * this is the top level dispatcher
+ *
+ * The dispatcher is implemented as an accessor class; it is an
+ * accessor class that calls other accessor classes, as controlled by a
+ * configuration file.
+ * 
+ * A big difference between this accessor class and others is that the
+ * map class initializers are NULL, and the map classes are already
+ * filled in with method functions that will do the right thing.
+ */
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <isc/assertions.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <netinet/in.h> 
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "gen_p.h"
+
+/* Definitions */
+
+struct nameval {
+       const char *    name;
+       int             val;
+};
+
+static const struct nameval acc_names[irs_nacc+1] = {
+       { "local", irs_lcl },
+       { "dns", irs_dns },
+       { "nis", irs_nis },
+       { "irp", irs_irp },
+       { NULL, irs_nacc }
+};
+
+typedef struct irs_acc *(*accinit) __P((const char *options));
+
+static const accinit accs[irs_nacc+1] = {
+       irs_lcl_acc,
+       irs_dns_acc,
+#ifdef WANT_IRS_NIS
+       irs_nis_acc,
+#else
+       NULL,
+#endif
+       irs_irp_acc,
+       NULL
+};
+
+static const struct nameval map_names[irs_nmap+1] = {
+       { "group", irs_gr },
+       { "passwd", irs_pw },
+       { "services", irs_sv },
+       { "protocols", irs_pr },
+       { "hosts", irs_ho },
+       { "networks", irs_nw },
+       { "netgroup", irs_ng },
+       { NULL, irs_nmap }
+};
+
+static const struct nameval option_names[] = {
+       { "merge", IRS_MERGE },
+       { "continue", IRS_CONTINUE },
+       { NULL, 0 }
+};
+
+/* Forward */
+
+static void            gen_close(struct irs_acc *);
+static struct __res_state * gen_res_get(struct irs_acc *);
+static void            gen_res_set(struct irs_acc *, struct __res_state *,
+                                   void (*)(void *));
+static int             find_name(const char *, const struct nameval nv[]);
+static void            init_map_rules(struct gen_p *, const char *conf_file);
+static struct irs_rule *release_rule(struct irs_rule *);
+static int             add_rule(struct gen_p *,
+                                enum irs_map_id, enum irs_acc_id,
+                                const char *);
+
+/* Public */
+
+struct irs_acc *
+irs_gen_acc(const char *options, const char *conf_file) {
+       struct irs_acc *acc;
+       struct gen_p *irs;
+               
+       if (!(acc = memget(sizeof *acc))) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(acc, 0x5e, sizeof *acc);
+       if (!(irs = memget(sizeof *irs))) {
+               errno = ENOMEM;
+               memput(acc, sizeof *acc);
+               return (NULL);
+       }
+       memset(irs, 0x5e, sizeof *irs);
+       irs->options = strdup(options);
+       irs->res = NULL;
+       irs->free_res = NULL;
+       memset(irs->accessors, 0, sizeof irs->accessors);
+       memset(irs->map_rules, 0, sizeof irs->map_rules);
+       init_map_rules(irs, conf_file);
+       acc->private = irs;
+#ifdef WANT_IRS_GR
+       acc->gr_map = irs_gen_gr;
+#else
+       acc->gr_map = NULL;
+#endif
+#ifdef WANT_IRS_PW
+       acc->pw_map = irs_gen_pw;
+#else
+       acc->pw_map = NULL;
+#endif
+       acc->sv_map = irs_gen_sv;
+       acc->pr_map = irs_gen_pr;
+       acc->ho_map = irs_gen_ho;
+       acc->nw_map = irs_gen_nw;
+       acc->ng_map = irs_gen_ng;
+       acc->res_get = gen_res_get;
+       acc->res_set = gen_res_set;
+       acc->close = gen_close;
+       return (acc);
+}
+
+/* Methods */
+
+static struct __res_state *
+gen_res_get(struct irs_acc *this) {
+       struct gen_p *irs = (struct gen_p *)this->private;
+
+       if (irs->res == NULL) {
+               struct __res_state *res;
+               res = (struct __res_state *)malloc(sizeof *res);
+               if (res == NULL)
+                       return (NULL);
+               memset(res, 0, sizeof *res);
+               gen_res_set(this, res, free);
+       }
+
+       if (((irs->res->options & RES_INIT) == 0) && res_ninit(irs->res) < 0)
+               return (NULL);
+
+       return (irs->res);
+}
+
+static void
+gen_res_set(struct irs_acc *this, struct __res_state *res,
+           void (*free_res)(void *)) {
+       struct gen_p *irs = (struct gen_p *)this->private;
+#if 0
+       struct irs_rule *rule;
+       struct irs_ho *ho;
+       struct irs_nw *nw;
+#endif
+
+       if (irs->res && irs->free_res) {
+               res_nclose(irs->res);
+               (*irs->free_res)(irs->res);
+       }
+
+       irs->res = res;
+       irs->free_res = free_res;
+
+#if 0
+       for (rule = irs->map_rules[irs_ho]; rule; rule = rule->next) {
+                ho = rule->inst->ho;
+
+                (*ho->res_set)(ho, res, NULL);
+       }
+       for (rule = irs->map_rules[irs_nw]; rule; rule = rule->next) {
+                nw = rule->inst->nw;
+
+                (*nw->res_set)(nw, res, NULL);
+       }
+#endif
+}
+
+static void
+gen_close(struct irs_acc *this) {
+       struct gen_p *irs = (struct gen_p *)this->private;
+       int n;
+       
+       /* Search rules. */
+       for (n = 0; n < irs_nmap; n++)
+               while (irs->map_rules[n] != NULL)
+                       irs->map_rules[n] = release_rule(irs->map_rules[n]);
+
+       /* Access methods. */
+       for (n = 0; n < irs_nacc; n++) {
+               /* Map objects. */
+               if (irs->accessors[n].gr != NULL)
+                       (*irs->accessors[n].gr->close)(irs->accessors[n].gr);
+               if (irs->accessors[n].pw != NULL)
+                       (*irs->accessors[n].pw->close)(irs->accessors[n].pw);
+               if (irs->accessors[n].sv != NULL)
+                       (*irs->accessors[n].sv->close)(irs->accessors[n].sv);
+               if (irs->accessors[n].pr != NULL)
+                       (*irs->accessors[n].pr->close)(irs->accessors[n].pr);
+               if (irs->accessors[n].ho != NULL)
+                       (*irs->accessors[n].ho->close)(irs->accessors[n].ho);
+               if (irs->accessors[n].nw != NULL)
+                       (*irs->accessors[n].nw->close)(irs->accessors[n].nw);
+               if (irs->accessors[n].ng != NULL)
+                       (*irs->accessors[n].ng->close)(irs->accessors[n].ng);
+               /* Enclosing accessor. */
+               if (irs->accessors[n].acc != NULL)
+                       (*irs->accessors[n].acc->close)(irs->accessors[n].acc);
+       }
+
+       /* The options string was strdup'd. */
+       free((void*)irs->options);
+
+       if (irs->res && irs->free_res)
+               (*irs->free_res)(irs->res);
+
+       /* The private data container. */
+       memput(irs, sizeof *irs);
+
+       /* The object. */
+       memput(this, sizeof *this);
+}
+
+/* Private */
+
+static int
+find_name(const char *name, const struct nameval names[]) {
+       int n;
+
+       for (n = 0; names[n].name != NULL; n++)
+               if (strcmp(name, names[n].name) == 0)
+                       return (names[n].val);
+       return (-1);
+}
+
+static struct irs_rule *
+release_rule(struct irs_rule *rule) {
+       struct irs_rule *next = rule->next;
+
+       memput(rule, sizeof *rule);
+       return (next);
+}
+
+static int
+add_rule(struct gen_p *irs,
+        enum irs_map_id map, enum irs_acc_id acc,
+        const char *options)
+{
+       struct irs_rule **rules, *last, *tmp, *new;
+       struct irs_inst *inst;
+       const char *cp;
+       int n;
+
+#ifndef WANT_IRS_GR
+       if (map == irs_gr)
+               return (-1);
+#endif
+#ifndef WANT_IRS_PW
+       if (map == irs_pw)
+               return (-1);
+#endif
+#ifndef WANT_IRS_NIS
+       if (acc == irs_nis)
+               return (-1);
+#endif
+       new = memget(sizeof *new);
+       if (new == NULL)
+               return (-1);
+       memset(new, 0x5e, sizeof *new);
+       new->next = NULL;
+
+       new->inst = &irs->accessors[acc];
+
+       new->flags = 0;
+       cp = options;
+       while (cp && *cp) {
+               char option[50], *next;
+
+               next = strchr(cp, ',');
+               if (next)
+                       n = next++ - cp;
+               else
+                       n = strlen(cp);
+               if ((size_t)n > sizeof option - 1)
+                       n = sizeof option - 1;
+               strncpy(option, cp, n);
+               option[n] = '\0';
+
+               n = find_name(option, option_names);
+               if (n >= 0)
+                       new->flags |= n;
+
+               cp = next;
+       }
+
+       rules = &irs->map_rules[map];
+       for (last = NULL, tmp = *rules;
+            tmp != NULL;
+            last = tmp, tmp = tmp->next)
+               (void)NULL;
+       if (last == NULL)
+               *rules = new;
+       else
+               last->next = new;
+
+       /* Try to instantiate map accessors for this if necessary & approp. */
+       inst = &irs->accessors[acc];
+       if (inst->acc == NULL && accs[acc] != NULL)
+               inst->acc = (*accs[acc])(irs->options);
+       if (inst->acc != NULL) {
+               if (inst->gr == NULL && inst->acc->gr_map != NULL)
+                       inst->gr = (*inst->acc->gr_map)(inst->acc);
+               if (inst->pw == NULL && inst->acc->pw_map != NULL)
+                       inst->pw = (*inst->acc->pw_map)(inst->acc);
+               if (inst->sv == NULL && inst->acc->sv_map != NULL)
+                       inst->sv = (*inst->acc->sv_map)(inst->acc);
+               if (inst->pr == NULL && inst->acc->pr_map != NULL)
+                       inst->pr = (*inst->acc->pr_map)(inst->acc);
+               if (inst->ho == NULL && inst->acc->ho_map != NULL)
+                       inst->ho = (*inst->acc->ho_map)(inst->acc);
+               if (inst->nw == NULL && inst->acc->nw_map != NULL)
+                       inst->nw = (*inst->acc->nw_map)(inst->acc);
+               if (inst->ng == NULL && inst->acc->ng_map != NULL)
+                       inst->ng = (*inst->acc->ng_map)(inst->acc);
+       }
+
+       return (0);
+}
+
+static void
+default_map_rules(struct gen_p *irs) {
+       /* Install time honoured and proved BSD style rules as default. */
+       add_rule(irs, irs_gr, irs_lcl, "");
+       add_rule(irs, irs_pw, irs_lcl, "");
+       add_rule(irs, irs_sv, irs_lcl, "");
+       add_rule(irs, irs_pr, irs_lcl, "");
+       add_rule(irs, irs_ho, irs_dns, "continue");
+       add_rule(irs, irs_ho, irs_lcl, "");
+       add_rule(irs, irs_nw, irs_dns, "continue");
+       add_rule(irs, irs_nw, irs_lcl, "");
+       add_rule(irs, irs_ng, irs_lcl, "");
+}
+
+static void
+init_map_rules(struct gen_p *irs, const char *conf_file) {
+       char line[1024], pattern[40], mapname[20], accname[20], options[100];
+       FILE *conf;
+
+       if (conf_file == NULL) 
+               conf_file = _PATH_IRS_CONF ;
+
+       /* A conf file of "" means compiled in defaults. Irpd wants this */
+       if (conf_file[0] == '\0' || (conf = fopen(conf_file, "r")) == NULL) {
+               default_map_rules(irs);
+               return;
+       }
+       (void) sprintf(pattern, "%%%ds %%%ds %%%ds\n",
+                      sizeof mapname, sizeof accname, sizeof options);
+       while (fgets(line, sizeof line, conf)) {
+               enum irs_map_id map;
+               enum irs_acc_id acc;
+               char *tmp;
+               int n;
+
+               for (tmp = line; isascii(*tmp) && isspace(*tmp); tmp++)
+                       (void)NULL;
+               if (*tmp == '#' || *tmp == '\n' || *tmp == '\0')
+                       continue;
+               n = sscanf(tmp, pattern, mapname, accname, options);
+               if (n < 2)
+                       continue;
+               if (n < 3)
+                       options[0] = '\0';
+
+               n = find_name(mapname, map_names);
+               INSIST(n < irs_nmap);
+               if (n < 0)
+                       continue;
+               map = (enum irs_map_id) n;
+
+               n = find_name(accname, acc_names);
+               INSIST(n < irs_nacc);
+               if (n < 0)
+                       continue;
+               acc = (enum irs_acc_id) n;
+
+               add_rule(irs, map, acc, options);
+       }
+       fclose(conf);
+}
diff --git a/lib/bind/irs/gen_gr.c b/lib/bind/irs/gen_gr.c
new file mode 100644 (file)
index 0000000..e752362
--- /dev/null
@@ -0,0 +1,454 @@
+/*
+ * 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(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: gen_gr.c,v 1.1 2001/03/29 06:31:43 marka Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#ifndef WANT_IRS_GR
+static int __bind_irs_gr_unneeded;
+#else
+
+#include <sys/types.h>
+
+#include <isc/assertions.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "gen_p.h"
+
+/* Definitions */
+
+struct pvt {
+       struct irs_rule *       rules;
+       struct irs_rule *       rule;
+       struct irs_gr *         gr;
+       /*
+        * Need space to store the entries read from the group file.
+        * The members list also needs space per member, and the
+        * strings making up the user names must be allocated
+        * somewhere.  Rather than doing lots of small allocations,
+        * we keep one buffer and resize it as needed.
+        */
+       struct group            group;
+       size_t                  nmemb;    /* Malloc'd max index of gr_mem[]. */
+       char *                  membuf;
+       size_t                  membufsize;
+       struct __res_state *    res;
+       void                    (*free_res)(void *);
+};
+
+/* Forward */
+
+static void            gr_close(struct irs_gr *);
+static struct group *  gr_next(struct irs_gr *);
+static struct group *  gr_byname(struct irs_gr *, const char *);
+static struct group *  gr_bygid(struct irs_gr *, gid_t);
+static void            gr_rewind(struct irs_gr *);
+static int             gr_list(struct irs_gr *, const char *,
+                               gid_t, gid_t *, int *);
+static void            gr_minimize(struct irs_gr *);
+static struct __res_state * gr_res_get(struct irs_gr *);
+static void            gr_res_set(struct irs_gr *,
+                                     struct __res_state *,
+                                     void (*)(void *));
+
+static void            grmerge(struct irs_gr *gr, const struct group *src,
+                               int preserve);
+
+static int             countvec(char **vec);
+static int             isnew(char **old, char *new);
+static int             countnew(char **old, char **new);
+static size_t          sizenew(char **old, char **new);
+static int             newgid(int, gid_t *, gid_t);
+
+/* Public */
+
+struct irs_gr *
+irs_gen_gr(struct irs_acc *this) {
+       struct gen_p *accpvt = (struct gen_p *)this->private;
+       struct irs_gr *gr;
+       struct pvt *pvt;
+
+       if (!(gr = memget(sizeof *gr))) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(gr, 0x5e, sizeof *gr);
+       if (!(pvt = memget(sizeof *pvt))) {
+               memput(gr, sizeof *gr);
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pvt, 0, sizeof *pvt);
+       pvt->rules = accpvt->map_rules[irs_gr];
+       pvt->rule = pvt->rules;
+       gr->private = pvt;
+       gr->close = gr_close;
+       gr->next = gr_next;
+       gr->byname = gr_byname;
+       gr->bygid = gr_bygid;
+       gr->rewind = gr_rewind;
+       gr->list = gr_list;
+       gr->minimize = gr_minimize;
+       gr->res_get = gr_res_get;
+       gr->res_set = gr_res_set;
+       return (gr);
+}
+
+/* Methods. */
+
+static void
+gr_close(struct irs_gr *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       memput(pvt, sizeof *pvt);
+       memput(this, sizeof *this);
+}
+
+static struct group *
+gr_next(struct irs_gr *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct group *rval;
+       struct irs_gr *gr;
+
+       while (pvt->rule) {
+               gr = pvt->rule->inst->gr;
+               rval = (*gr->next)(gr);
+               if (rval)
+                       return (rval);
+               if (!(pvt->rule->flags & IRS_CONTINUE))
+                       break;
+               pvt->rule = pvt->rule->next;
+               if (pvt->rule) {
+                       gr = pvt->rule->inst->gr;
+                       (*gr->rewind)(gr);
+               }
+       }
+       return (NULL);
+}
+
+static struct group *
+gr_byname(struct irs_gr *this, const char *name) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct irs_rule *rule;
+       struct group *tval;
+       struct irs_gr *gr;
+       int dirty;
+
+       dirty = 0;
+       for (rule = pvt->rules; rule; rule = rule->next) {
+               gr = rule->inst->gr;
+               tval = (*gr->byname)(gr, name);
+               if (tval) {
+                       grmerge(this, tval, dirty++);
+                       if (!(rule->flags & IRS_MERGE))
+                               break;
+               } else {
+                       if (!(rule->flags & IRS_CONTINUE))
+                               break;
+               }
+       }
+       if (dirty)
+               return (&pvt->group);
+       return (NULL);
+}
+
+static struct group *
+gr_bygid(struct irs_gr *this, gid_t gid) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct irs_rule *rule;
+       struct group *tval;
+       struct irs_gr *gr;
+       int dirty;
+
+       dirty = 0;
+       for (rule = pvt->rules; rule; rule = rule->next) {
+               gr = rule->inst->gr;
+               tval = (*gr->bygid)(gr, gid);
+               if (tval) {
+                       grmerge(this, tval, dirty++);
+                       if (!(rule->flags & IRS_MERGE))
+                               break;
+               } else {
+                       if (!(rule->flags & IRS_CONTINUE))
+                               break;
+               }
+       }
+       if (dirty)
+               return (&pvt->group);
+       return (NULL);
+}
+
+static void
+gr_rewind(struct irs_gr *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct irs_gr *gr;
+
+       pvt->rule = pvt->rules;
+       if (pvt->rule) {
+               gr = pvt->rule->inst->gr;
+               (*gr->rewind)(gr);
+       }
+}
+
+static int
+gr_list(struct irs_gr *this, const char *name,
+       gid_t basegid, gid_t *groups, int *ngroups)
+{
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct irs_rule *rule;
+       struct irs_gr *gr;
+       int t_ngroups, maxgroups;
+       gid_t *t_groups;
+       int n, t, rval = 0;
+
+       maxgroups = *ngroups;
+       *ngroups = 0;
+       t_groups = (gid_t *)malloc(maxgroups * sizeof(gid_t));
+       if (!t_groups) {
+               errno = ENOMEM;
+               return (-1);
+       }
+
+       for (rule = pvt->rules; rule; rule = rule->next) {
+               t_ngroups = maxgroups;
+               gr = rule->inst->gr;
+               t = (*gr->list)(gr, name, basegid, t_groups, &t_ngroups);
+               for (n = 0; n < t_ngroups; n++) {
+                       if (newgid(*ngroups, groups, t_groups[n])) {
+                               if (*ngroups == maxgroups) {
+                                       rval = -1;
+                                       goto done;
+                               }
+                               groups[(*ngroups)++] = t_groups[n];
+                       }
+               }
+               if (t == 0) {
+                       if (!(rule->flags & IRS_MERGE))
+                               break;
+               } else {
+                       if (!(rule->flags & IRS_CONTINUE))
+                               break;
+               }
+       }
+ done:
+       free(t_groups);
+       return (rval);
+}
+
+static void
+gr_minimize(struct irs_gr *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct irs_rule *rule;
+
+       for (rule = pvt->rules; rule != NULL; rule = rule->next) {
+               struct irs_gr *gr = rule->inst->gr;
+
+               (*gr->minimize)(gr);
+       }
+}
+
+static struct __res_state *
+gr_res_get(struct irs_gr *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (!pvt->res) {
+               struct __res_state *res;
+               res = (struct __res_state *)malloc(sizeof *res);
+               if (!res) {
+                       errno = ENOMEM;
+                       return (NULL);
+               }
+               memset(res, 0, sizeof *res);
+               gr_res_set(this, res, free);
+       }
+
+       return (pvt->res);
+}
+
+static void
+gr_res_set(struct irs_gr *this, struct __res_state *res,
+               void (*free_res)(void *)) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct irs_rule *rule;
+
+       if (pvt->res && pvt->free_res) {
+               res_nclose(pvt->res);
+               (*pvt->free_res)(pvt->res);
+       }
+
+       pvt->res = res;
+       pvt->free_res = free_res;
+
+       for (rule = pvt->rules; rule != NULL; rule = rule->next) {
+               struct irs_gr *gr = rule->inst->gr;
+
+               if (gr->res_set)
+                       (*gr->res_set)(gr, pvt->res, NULL);
+       }
+}
+
+/* Private. */
+
+static void
+grmerge(struct irs_gr *this, const struct group *src, int preserve) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       char *cp, **m, **p;
+       int n, ndst, nnew, memadj;
+
+       if (!preserve) {
+               pvt->group.gr_gid = src->gr_gid;
+               if (pvt->nmemb < 1) {
+                       m = malloc(sizeof *m);
+                       if (!m) {
+                               /* No harm done, no work done. */
+                               return;
+                       }
+                       pvt->group.gr_mem = m;
+                       pvt->nmemb = 1;
+               }
+               pvt->group.gr_mem[0] = NULL;
+       }
+       ndst = countvec(pvt->group.gr_mem);
+       nnew = countnew(pvt->group.gr_mem, src->gr_mem);
+
+       /*
+        * Make sure destination member array is large enough.
+        * p points to new portion.
+        */
+       n = ndst + nnew + 1;
+       if ((size_t)n > pvt->nmemb) {
+               m = realloc(pvt->group.gr_mem, n * sizeof *m);
+               if (!m) {
+                       /* No harm done, no work done. */
+                       return;
+               }
+               pvt->group.gr_mem = m;
+               pvt->nmemb = n;
+       }
+       p = pvt->group.gr_mem + ndst;
+
+       /*
+        * Enlarge destination membuf; cp points at new portion.
+        */
+       n = sizenew(pvt->group.gr_mem, src->gr_mem);
+       INSIST((nnew == 0) == (n == 0));
+       if (!preserve) {
+               n += strlen(src->gr_name) + 1;
+               n += strlen(src->gr_passwd) + 1;
+       }
+       if (n == 0) {
+               /* No work to do. */
+               return;
+       }
+       cp = realloc(pvt->membuf, pvt->membufsize + n);
+       if (!cp) {
+               /* No harm done, no work done. */
+               return;
+       }
+       memadj = cp - pvt->membuf;
+       pvt->membuf = cp;
+       cp += pvt->membufsize;
+       pvt->membufsize += n;
+
+       /*
+        * Add new elements.
+        */
+       for (m = src->gr_mem; *m; m++)
+               if (isnew(pvt->group.gr_mem, *m)) {
+                       *p++ = cp;
+                       *p = NULL;
+                       strcpy(cp, *m);
+                       cp += strlen(cp) + 1;
+               }
+       if (preserve) {
+               pvt->group.gr_name += memadj;
+               pvt->group.gr_passwd += memadj;
+       } else {
+               pvt->group.gr_name = cp;
+               strcpy(cp, src->gr_name);
+               cp += strlen(src->gr_name) + 1;
+               pvt->group.gr_passwd = cp;
+               strcpy(cp, src->gr_passwd);
+               cp += strlen(src->gr_passwd) + 1;
+       }
+       INSIST(cp >= pvt->membuf && cp <= &pvt->membuf[pvt->membufsize]);
+}
+
+static int
+countvec(char **vec) {
+       int n = 0;
+
+       while (*vec++)
+               n++;
+       return (n);
+}
+
+static int
+isnew(char **old, char *new) {
+       for (; *old; old++)
+               if (strcmp(*old, new) == 0)
+                       return (0);
+       return (1);
+}
+
+static int
+countnew(char **old, char **new) {
+       int n = 0;
+
+       for (; *new; new++)
+               n += isnew(old, *new);
+       return (n);
+}
+
+static size_t
+sizenew(char **old, char **new) {
+       size_t n = 0;
+
+       for (; *new; new++)
+               if (isnew(old, *new))
+                       n += strlen(*new) + 1;
+       return (n);
+}
+
+static int
+newgid(int ngroups, gid_t *groups, gid_t group) {
+       ngroups--, groups++;
+       for (; ngroups-- > 0; groups++)
+               if (*groups == group)
+                       return (0);
+       return (1);
+}
+
+#endif /* WANT_IRS_GR */
diff --git a/lib/bind/irs/gen_ho.c b/lib/bind/irs/gen_ho.c
new file mode 100644 (file)
index 0000000..0fec909
--- /dev/null
@@ -0,0 +1,391 @@
+/*
+ * 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 rcsid[] = "$Id: gen_ho.c,v 1.1 2001/03/29 06:31:43 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "gen_p.h"
+
+/* Definitions */
+
+struct pvt {
+       struct irs_rule *       rules;
+       struct irs_rule *       rule;
+       struct irs_ho *         ho;
+       struct __res_state *    res;
+       void                    (*free_res)(void *);
+};
+
+/* Forwards */
+
+static void            ho_close(struct irs_ho *this);
+static struct hostent *        ho_byname(struct irs_ho *this, const char *name);
+static struct hostent *        ho_byname2(struct irs_ho *this, const char *name,
+                                  int af);
+static struct hostent *        ho_byaddr(struct irs_ho *this, const void *addr,
+                                 int len, int af);
+static struct hostent *        ho_next(struct irs_ho *this);
+static void            ho_rewind(struct irs_ho *this);
+static void            ho_minimize(struct irs_ho *this);
+static struct __res_state * ho_res_get(struct irs_ho *this);
+static void            ho_res_set(struct irs_ho *this,
+                                  struct __res_state *res,
+                                  void (*free_res)(void *));
+static struct addrinfo * ho_addrinfo(struct irs_ho *this, const char *name,
+                                    const struct addrinfo *pai);
+
+static int             init(struct irs_ho *this);
+
+/* Exports */
+
+struct irs_ho *
+irs_gen_ho(struct irs_acc *this) {
+       struct gen_p *accpvt = (struct gen_p *)this->private;
+       struct irs_ho *ho;
+       struct pvt *pvt;
+
+       if (!(pvt = memget(sizeof *pvt))) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pvt, 0, sizeof *pvt);
+       if (!(ho = memget(sizeof *ho))) {
+               memput(pvt, sizeof *pvt);
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(ho, 0x5e, sizeof *ho);
+       pvt->rules = accpvt->map_rules[irs_ho];
+       pvt->rule = pvt->rules;
+       ho->private = pvt;
+       ho->close = ho_close;
+       ho->byname = ho_byname;
+       ho->byname2 = ho_byname2;
+       ho->byaddr = ho_byaddr;
+       ho->next = ho_next;
+       ho->rewind = ho_rewind;
+       ho->minimize = ho_minimize;
+       ho->res_get = ho_res_get;
+       ho->res_set = ho_res_set;
+       ho->addrinfo = ho_addrinfo;
+       return (ho);
+}
+
+/* Methods. */
+
+static void
+ho_close(struct irs_ho *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       ho_minimize(this);
+       if (pvt->res && pvt->free_res)
+               (*pvt->free_res)(pvt->res);
+       memput(pvt, sizeof *pvt);
+       memput(this, sizeof *this);
+}
+
+static struct hostent *
+ho_byname(struct irs_ho *this, const char *name) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct irs_rule *rule;
+       struct hostent *rval;
+       struct irs_ho *ho;
+       int therrno = NETDB_INTERNAL;
+       int softerror = 0;
+
+       if (init(this) == -1)
+               return (NULL);
+
+       for (rule = pvt->rules; rule; rule = rule->next) {
+               ho = rule->inst->ho;
+               RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+               errno = 0;
+               rval = (*ho->byname)(ho, name);
+               if (rval != NULL)
+                       return (rval);
+               if (softerror == 0 &&
+                   pvt->res->res_h_errno != HOST_NOT_FOUND &&
+                   pvt->res->res_h_errno != NETDB_INTERNAL) {
+                       softerror = 1;
+                       therrno = pvt->res->res_h_errno;
+               }
+               if (rule->flags & IRS_CONTINUE)
+                       continue;
+               /*
+                * The value TRY_AGAIN can mean that the service
+                * is not available, or just that this particular name
+                * cannot be resolved now.  We use the errno ECONNREFUSED
+                * to distinguish.  If a lookup sets that errno when
+                * H_ERRNO is TRY_AGAIN, we continue to try other lookup
+                * functions, otherwise we return the TRY_AGAIN error.
+                */
+               if (pvt->res->res_h_errno != TRY_AGAIN || errno != ECONNREFUSED)
+                       break;
+       }
+       if (softerror != 0 && pvt->res->res_h_errno == HOST_NOT_FOUND)
+               RES_SET_H_ERRNO(pvt->res, therrno);
+       return (NULL);
+}
+
+static struct hostent *
+ho_byname2(struct irs_ho *this, const char *name, int af) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct irs_rule *rule;
+       struct hostent *rval;
+       struct irs_ho *ho;
+       int therrno = NETDB_INTERNAL;
+       int softerror = 0;
+
+       if (init(this) == -1)
+               return (NULL);
+
+       for (rule = pvt->rules; rule; rule = rule->next) {
+               ho = rule->inst->ho;
+               RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+               errno = 0;
+               rval = (*ho->byname2)(ho, name, af);
+               if (rval != NULL)
+                       return (rval);
+               if (softerror == 0 &&
+                   pvt->res->res_h_errno != HOST_NOT_FOUND &&
+                   pvt->res->res_h_errno != NETDB_INTERNAL) {
+                       softerror = 1;
+                       therrno = pvt->res->res_h_errno;
+               }
+               if (rule->flags & IRS_CONTINUE)
+                       continue;
+               /*
+                * See the comments in ho_byname() explaining
+                * the interpretation of TRY_AGAIN and ECONNREFUSED.
+                */
+               if (pvt->res->res_h_errno != TRY_AGAIN || errno != ECONNREFUSED)
+                       break;
+       }
+       if (softerror != 0 && pvt->res->res_h_errno == HOST_NOT_FOUND)
+               RES_SET_H_ERRNO(pvt->res, therrno);
+       return (NULL);
+}
+
+static struct hostent *
+ho_byaddr(struct irs_ho *this, const void *addr, int len, int af) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct irs_rule *rule;
+       struct hostent *rval;
+       struct irs_ho *ho;
+       int therrno = NETDB_INTERNAL;
+       int softerror = 0;
+
+
+       if (init(this) == -1)
+               return (NULL);
+
+       for (rule = pvt->rules; rule; rule = rule->next) {
+               ho = rule->inst->ho;
+               RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+               errno = 0;
+               rval = (*ho->byaddr)(ho, addr, len, af);
+               if (rval != NULL)
+                       return (rval);
+               if (softerror == 0 &&
+                   pvt->res->res_h_errno != HOST_NOT_FOUND &&
+                   pvt->res->res_h_errno != NETDB_INTERNAL) {
+                       softerror = 1;
+                       therrno = pvt->res->res_h_errno;
+               }
+
+               if (rule->flags & IRS_CONTINUE)
+                       continue;
+               /*
+                * See the comments in ho_byname() explaining
+                * the interpretation of TRY_AGAIN and ECONNREFUSED.
+                */
+               if (pvt->res->res_h_errno != TRY_AGAIN || errno != ECONNREFUSED)
+                       break;
+       }
+       if (softerror != 0 && pvt->res->res_h_errno == HOST_NOT_FOUND)
+               RES_SET_H_ERRNO(pvt->res, therrno);
+       return (NULL);
+}
+
+static struct hostent *
+ho_next(struct irs_ho *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct hostent *rval;
+       struct irs_ho *ho;
+
+       while (pvt->rule) {
+               ho = pvt->rule->inst->ho;
+               rval = (*ho->next)(ho);
+               if (rval)
+                       return (rval);
+               if (!(pvt->rule->flags & IRS_CONTINUE))
+                       break;
+               pvt->rule = pvt->rule->next;
+               if (pvt->rule) {
+                       ho = pvt->rule->inst->ho;
+                       (*ho->rewind)(ho);
+               }
+       }
+       return (NULL);
+}
+
+static void
+ho_rewind(struct irs_ho *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct irs_ho *ho;
+
+       pvt->rule = pvt->rules;
+       if (pvt->rule) {
+               ho = pvt->rule->inst->ho;
+               (*ho->rewind)(ho);
+       }
+}
+
+static void
+ho_minimize(struct irs_ho *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct irs_rule *rule;
+
+       if (pvt->res)
+               res_nclose(pvt->res);
+       for (rule = pvt->rules; rule != NULL; rule = rule->next) {
+               struct irs_ho *ho = rule->inst->ho;
+
+               (*ho->minimize)(ho);
+       }
+}
+
+static struct __res_state *
+ho_res_get(struct irs_ho *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (!pvt->res) {
+               struct __res_state *res;
+               res = (struct __res_state *)malloc(sizeof *res);
+               if (!res) {
+                       errno = ENOMEM;
+                       return (NULL);
+               }
+               memset(res, 0, sizeof *res);
+               ho_res_set(this, res, free);
+       }
+
+       return (pvt->res);
+}
+
+static void
+ho_res_set(struct irs_ho *this, struct __res_state *res,
+               void (*free_res)(void *)) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct irs_rule *rule;
+
+       if (pvt->res && pvt->free_res) {
+               res_nclose(pvt->res);
+               (*pvt->free_res)(pvt->res);
+       }
+
+       pvt->res = res;
+       pvt->free_res = free_res;
+
+       for (rule = pvt->rules; rule != NULL; rule = rule->next) {
+               struct irs_ho *ho = rule->inst->ho;
+
+               (*ho->res_set)(ho, pvt->res, NULL);
+       }
+}
+
+static struct addrinfo *
+ho_addrinfo(struct irs_ho *this, const char *name, const struct addrinfo *pai)
+{
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct irs_rule *rule;
+       struct addrinfo *rval = NULL;
+       struct irs_ho *ho;
+       int therrno = NETDB_INTERNAL;
+       int softerror = 0;
+
+       if (init(this) == -1)
+               return (NULL);
+
+       for (rule = pvt->rules; rule; rule = rule->next) {
+               ho = rule->inst->ho;
+               RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+               errno = 0;
+               if (ho->addrinfo == NULL) /* for safety */
+                       continue;
+               rval = (*ho->addrinfo)(ho, name, pai);
+               if (rval != NULL)
+                       return (rval);
+               if (softerror == 0 &&
+                   pvt->res->res_h_errno != HOST_NOT_FOUND &&
+                   pvt->res->res_h_errno != NETDB_INTERNAL) {
+                       softerror = 1;
+                       therrno = pvt->res->res_h_errno;
+               }
+               if (rule->flags & IRS_CONTINUE)
+                       continue;
+               /*
+                * See the comments in ho_byname() explaining
+                * the interpretation of TRY_AGAIN and ECONNREFUSED.
+                */
+               if (pvt->res->res_h_errno != TRY_AGAIN ||
+                   errno != ECONNREFUSED)
+                       break;
+       }
+       if (softerror != 0 && pvt->res->res_h_errno == HOST_NOT_FOUND)
+               RES_SET_H_ERRNO(pvt->res, therrno);
+       if (rval)
+               freeaddrinfo(rval);
+       return (NULL);
+}
+
+static int
+init(struct irs_ho *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+        if (!pvt->res && !ho_res_get(this))
+                return (-1);
+
+        if (((pvt->res->options & RES_INIT) == 0) &&
+            (res_ninit(pvt->res) == -1))
+                return (-1);
+
+        return (0);
+}
diff --git a/lib/bind/irs/gen_ng.c b/lib/bind/irs/gen_ng.c
new file mode 100644 (file)
index 0000000..51e1fed
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * 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(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: gen_ng.c,v 1.1 2001/03/29 06:31:43 marka Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "gen_p.h"
+
+/* Types */
+
+struct pvt {
+       struct irs_rule *       rules;
+       struct irs_rule *       rule;
+       char *                  curgroup;
+};
+
+/* Forward */
+
+static void            ng_close(struct irs_ng *);
+static int             ng_next(struct irs_ng *, const char **,
+                               const char **, const char **);
+static int             ng_test(struct irs_ng *, const char *,
+                               const char *, const char *,
+                               const char *);
+static void            ng_rewind(struct irs_ng *, const char *);
+static void            ng_minimize(struct irs_ng *);
+
+/* Public */
+
+struct irs_ng *
+irs_gen_ng(struct irs_acc *this) {
+       struct gen_p *accpvt = (struct gen_p *)this->private;
+       struct irs_ng *ng;
+       struct pvt *pvt;
+       
+       if (!(ng = memget(sizeof *ng))) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(ng, 0x5e, sizeof *ng);
+       if (!(pvt = memget(sizeof *pvt))) {
+               memput(ng, sizeof *ng);
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pvt, 0, sizeof *pvt);
+       pvt->rules = accpvt->map_rules[irs_ng];
+       pvt->rule = pvt->rules;
+       ng->private = pvt;
+       ng->close = ng_close;
+       ng->next = ng_next;
+       ng->test = ng_test;
+       ng->rewind = ng_rewind;
+       ng->minimize = ng_minimize;
+       return (ng);
+}
+
+/* Methods */
+
+static void 
+ng_close(struct irs_ng *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       
+       ng_minimize(this);
+       if (pvt->curgroup)
+               free(pvt->curgroup);
+       memput(pvt, sizeof *pvt);
+       memput(this, sizeof *this);
+}
+
+static int
+ng_next(struct irs_ng *this, const char **host, const char **user,
+       const char **domain)
+{
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct irs_ng *ng;
+       
+       while (pvt->rule) {
+               ng = pvt->rule->inst->ng;
+               if ((*ng->next)(ng, host, user, domain) == 1)
+                       return (1);
+               if (!(pvt->rule->flags & IRS_CONTINUE))
+                       break;
+               pvt->rule = pvt->rule->next;
+               if (pvt->rule) {
+                       ng = pvt->rule->inst->ng;
+                       (*ng->rewind)(ng, pvt->curgroup);
+               }
+       }
+       return (0);
+}
+
+static int
+ng_test(struct irs_ng *this, const char *name,
+       const char *user, const char *host, const char *domain)
+{
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct irs_rule *rule;
+       struct irs_ng *ng;
+       int rval;
+       
+       rval = 0;
+       for (rule = pvt->rules; rule; rule = rule->next) {
+               ng = rule->inst->ng;
+               rval = (*ng->test)(ng, name, user, host, domain);
+               if (rval || !(rule->flags & IRS_CONTINUE))
+                       break;
+       }
+       return (rval);
+}
+
+static void
+ng_rewind(struct irs_ng *this, const char *group) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct irs_ng *ng;
+       
+       pvt->rule = pvt->rules;
+       if (pvt->rule) {
+               if (pvt->curgroup)
+                       free(pvt->curgroup);
+               pvt->curgroup = strdup(group);
+               ng = pvt->rule->inst->ng;
+               (*ng->rewind)(ng, pvt->curgroup);
+       }
+}
+
+static void
+ng_minimize(struct irs_ng *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct irs_rule *rule;
+
+       for (rule = pvt->rules; rule != NULL; rule = rule->next) {
+               struct irs_ng *ng = rule->inst->ng;
+
+               (*ng->minimize)(ng);
+       }
+}
diff --git a/lib/bind/irs/gen_nw.c b/lib/bind/irs/gen_nw.c
new file mode 100644 (file)
index 0000000..c436fa0
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ * 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(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: gen_nw.c,v 1.1 2001/03/29 06:31:44 marka Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <resolv.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "gen_p.h"
+
+/* Types */
+
+struct pvt {
+       struct irs_rule *       rules;
+       struct irs_rule *       rule;
+       struct __res_state *    res;
+       void                    (*free_res)(void *);
+};
+
+/* Forward */
+
+static void            nw_close(struct irs_nw*);
+static struct nwent *  nw_next(struct irs_nw *);
+static struct nwent *  nw_byname(struct irs_nw *, const char *, int);
+static struct nwent *  nw_byaddr(struct irs_nw *, void *, int, int);
+static void                    nw_rewind(struct irs_nw *);
+static void            nw_minimize(struct irs_nw *);
+static struct __res_state * nw_res_get(struct irs_nw *this);
+static void            nw_res_set(struct irs_nw *this,
+                                  struct __res_state *res,
+                                  void (*free_res)(void *));
+
+static int             init(struct irs_nw *this);
+
+/* Public */
+
+struct irs_nw *
+irs_gen_nw(struct irs_acc *this) {
+       struct gen_p *accpvt = (struct gen_p *)this->private;
+       struct irs_nw *nw;
+       struct pvt *pvt;
+
+       if (!(pvt = memget(sizeof *pvt))) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pvt, 0, sizeof *pvt);
+       if (!(nw = memget(sizeof *nw))) {
+               memput(pvt, sizeof *pvt);
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(nw, 0x5e, sizeof *nw);
+       pvt->rules = accpvt->map_rules[irs_nw];
+       pvt->rule = pvt->rules;
+       nw->private = pvt;
+       nw->close = nw_close;
+       nw->next = nw_next;
+       nw->byname = nw_byname;
+       nw->byaddr = nw_byaddr;
+       nw->rewind = nw_rewind;
+       nw->minimize = nw_minimize;
+       nw->res_get = nw_res_get;
+       nw->res_set = nw_res_set;
+       return (nw);
+}
+
+/* Methods */
+
+static void
+nw_close(struct irs_nw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       nw_minimize(this);
+
+       if (pvt->res && pvt->free_res)
+               (*pvt->free_res)(pvt->res);
+
+       memput(pvt, sizeof *pvt);
+       memput(this, sizeof *this);
+}
+
+static struct nwent *
+nw_next(struct irs_nw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct nwent *rval;
+       struct irs_nw *nw;
+
+       if (init(this) == -1)
+               return(NULL);
+
+       while (pvt->rule) {
+               nw = pvt->rule->inst->nw;
+               rval = (*nw->next)(nw);
+               if (rval)
+                       return (rval);
+               if (!(pvt->rules->flags & IRS_CONTINUE))
+                       break;
+               pvt->rule = pvt->rule->next;
+               if (pvt->rule) {
+                       nw = pvt->rule->inst->nw;
+                       (*nw->rewind)(nw);
+               }
+       }
+       return (NULL);
+}
+
+static struct nwent *
+nw_byname(struct irs_nw *this, const char *name, int type) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct irs_rule *rule;
+       struct nwent *rval;
+       struct irs_nw *nw;
+       
+       if (init(this) == -1)
+               return(NULL);
+
+       for (rule = pvt->rules; rule; rule = rule->next) {
+               nw = rule->inst->nw;
+               RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+               rval = (*nw->byname)(nw, name, type);
+               if (rval != NULL)
+                       return (rval);
+               if (pvt->res->res_h_errno != TRY_AGAIN &&
+                   !(rule->flags & IRS_CONTINUE))
+                       break;
+       }
+       return (NULL);
+}
+
+static struct nwent *
+nw_byaddr(struct irs_nw *this, void *net, int length, int type) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct irs_rule *rule;
+       struct nwent *rval;
+       struct irs_nw *nw;
+       
+       if (init(this) == -1)
+               return(NULL);
+
+       for (rule = pvt->rules; rule; rule = rule->next) {
+               nw = rule->inst->nw;
+               RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+               rval = (*nw->byaddr)(nw, net, length, type);
+               if (rval != NULL)
+                       return (rval);
+               if (pvt->res->res_h_errno != TRY_AGAIN &&
+                   !(rule->flags & IRS_CONTINUE))
+                       break;
+       }
+       return (NULL);
+}
+
+static void
+nw_rewind(struct irs_nw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct irs_nw *nw;
+
+       pvt->rule = pvt->rules;
+       if (pvt->rule) {
+               nw = pvt->rule->inst->nw;
+               (*nw->rewind)(nw);
+       }
+}
+
+static void
+nw_minimize(struct irs_nw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct irs_rule *rule;
+
+       if (pvt->res)
+               res_nclose(pvt->res);
+       for (rule = pvt->rules; rule != NULL; rule = rule->next) {
+               struct irs_nw *nw = rule->inst->nw;
+
+               (*nw->minimize)(nw);
+       }
+}
+
+static struct __res_state *
+nw_res_get(struct irs_nw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (!pvt->res) {
+               struct __res_state *res;
+               res = (struct __res_state *)malloc(sizeof *res);
+               if (!res) {
+                       errno = ENOMEM;
+                       return (NULL);
+               }
+               memset(res, 0, sizeof *res);
+               nw_res_set(this, res, free);
+       }
+
+       return (pvt->res);
+}
+
+static void
+nw_res_set(struct irs_nw *this, struct __res_state *res,
+               void (*free_res)(void *)) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct irs_rule *rule;
+
+       if (pvt->res && pvt->free_res) {
+               res_nclose(pvt->res);
+               (*pvt->free_res)(pvt->res);
+       }
+
+       pvt->res = res;
+       pvt->free_res = free_res;
+
+       for (rule = pvt->rules; rule != NULL; rule = rule->next) {
+               struct irs_nw *nw = rule->inst->nw;
+
+               (*nw->res_set)(nw, pvt->res, NULL);
+       }
+}
+
+static int
+init(struct irs_nw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       
+       if (!pvt->res && !nw_res_get(this))
+               return (-1);
+       if (((pvt->res->options & RES_INIT) == 0) &&
+           res_ninit(pvt->res) == -1)
+               return (-1);
+       return (0);
+}
diff --git a/lib/bind/irs/gen_p.h b/lib/bind/irs/gen_p.h
new file mode 100644 (file)
index 0000000..e0ad838
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+/*
+ * $Id: gen_p.h,v 1.1 2001/03/29 06:31:44 marka Exp $
+ */
+
+/* Notes:
+ *     We hope to create a complete set of thread-safe entry points someday,
+ *     which will mean a set of getXbyY() functions that take as an argument
+ *     a pointer to the map class, which will have a pointer to the private
+ *     data, which will be used preferentially to the static variables that
+ *     are necessary to support the "classic" interface.  This "classic"
+ *     interface will then be reimplemented as stubs on top of the thread
+ *     safe modules, and will keep the map class pointers as their only
+ *     static data.  HOWEVER, we are not there yet.  So while we will call
+ *     the just-barely-converted map class methods with map class pointers,
+ *     right now they probably all still use statics.  We're not fooling
+ *     anybody, and we're not trying to (yet).
+ */
+
+#ifndef _GEN_P_H_INCLUDED
+#define _GEN_P_H_INCLUDED
+
+/*
+ * These are the access methods.
+ */
+enum irs_acc_id {
+       irs_lcl,        /* Local. */
+       irs_dns,        /* DNS or Hesiod. */
+       irs_nis,        /* Sun NIS ("YP"). */
+       irs_irp,        /* IR protocol.  */
+       irs_nacc
+};
+
+/*
+ * These are the map types.
+ */
+enum irs_map_id {
+       irs_gr,         /* "group" */
+       irs_pw,         /* "passwd" */
+       irs_sv,         /* "services" */
+       irs_pr,         /* "protocols" */
+       irs_ho,         /* "hosts" */
+       irs_nw,         /* "networks" */
+       irs_ng,         /* "netgroup" */
+       irs_nmap
+};
+
+/*
+ * This is an accessor instance.
+ */
+struct irs_inst {
+       struct irs_acc *acc;
+       struct irs_gr * gr;
+       struct irs_pw * pw;
+       struct irs_sv * sv;
+       struct irs_pr * pr;
+       struct irs_ho * ho;
+       struct irs_nw * nw;
+       struct irs_ng * ng;
+};
+
+/*
+ * This is a search rule for some map type.
+ */
+struct irs_rule {
+       struct irs_rule *       next;
+       struct irs_inst *       inst;
+       int                     flags;
+};
+#define IRS_MERGE              0x0001  /* Don't stop if acc. has data? */
+#define        IRS_CONTINUE            0x0002  /* Don't stop if acc. has no data? */
+
+/*
+ * This is the private data for a search access class.
+ */
+struct gen_p {
+       char *                  options;
+       struct irs_rule *       map_rules[(int)irs_nmap];
+       struct irs_inst         accessors[(int)irs_nacc];
+       struct __res_state *    res;
+       void                    (*free_res) __P((void *));
+};
+
+/*
+ * Externs.
+ */
+
+extern struct irs_acc *        irs_gen_acc __P((const char *, const char *conf_file));
+extern struct irs_gr * irs_gen_gr __P((struct irs_acc *));
+extern struct irs_pw * irs_gen_pw __P((struct irs_acc *));
+extern struct irs_sv * irs_gen_sv __P((struct irs_acc *));
+extern struct irs_pr * irs_gen_pr __P((struct irs_acc *));
+extern struct irs_ho * irs_gen_ho __P((struct irs_acc *));
+extern struct irs_nw * irs_gen_nw __P((struct irs_acc *));
+extern struct irs_ng * irs_gen_ng __P((struct irs_acc *));
+
+#endif /*_IRS_P_H_INCLUDED*/
diff --git a/lib/bind/irs/gen_pr.c b/lib/bind/irs/gen_pr.c
new file mode 100644 (file)
index 0000000..661ff7e
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * 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(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: gen_pr.c,v 1.1 2001/03/29 06:31:44 marka Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <resolv.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "gen_p.h"
+
+/* Types */
+
+struct pvt {
+       struct irs_rule *       rules;
+       struct irs_rule *       rule;
+       struct __res_state *    res;
+       void                    (*free_res)(void *);
+};
+
+/* Forward */
+
+static void                    pr_close(struct irs_pr*);
+static struct protoent *       pr_next(struct irs_pr *);
+static struct protoent *       pr_byname(struct irs_pr *, const char *);
+static struct protoent *       pr_bynumber(struct irs_pr *, int);
+static void                    pr_rewind(struct irs_pr *);
+static void                    pr_minimize(struct irs_pr *);
+static struct __res_state *    pr_res_get(struct irs_pr *);
+static void                    pr_res_set(struct irs_pr *,
+                                          struct __res_state *,
+                                          void (*)(void *));
+
+/* Public */
+
+struct irs_pr *
+irs_gen_pr(struct irs_acc *this) {
+       struct gen_p *accpvt = (struct gen_p *)this->private;
+       struct irs_pr *pr;
+       struct pvt *pvt;
+
+       if (!(pr = memget(sizeof *pr))) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pr, 0x5e, sizeof *pr);
+       if (!(pvt = memget(sizeof *pvt))) {
+               memput(pr, sizeof *pr);
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pvt, 0, sizeof *pvt);
+       pvt->rules = accpvt->map_rules[irs_pr];
+       pvt->rule = pvt->rules;
+       pr->private = pvt;
+       pr->close = pr_close;
+       pr->next = pr_next;
+       pr->byname = pr_byname;
+       pr->bynumber = pr_bynumber;
+       pr->rewind = pr_rewind;
+       pr->minimize = pr_minimize;
+       pr->res_get = pr_res_get;
+       pr->res_set = pr_res_set;
+       return (pr);
+}
+
+/* Methods */
+
+static void
+pr_close(struct irs_pr *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       memput(pvt, sizeof *pvt);
+       memput(this, sizeof *this);
+}
+
+static struct protoent *
+pr_next(struct irs_pr *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct protoent *rval;
+       struct irs_pr *pr;
+
+       while (pvt->rule) {
+               pr = pvt->rule->inst->pr;
+               rval = (*pr->next)(pr);
+               if (rval)
+                       return (rval);
+               if (!(pvt->rules->flags & IRS_CONTINUE))
+                       break;
+               pvt->rule = pvt->rule->next;
+               if (pvt->rule) {
+                       pr = pvt->rule->inst->pr;
+                       (*pr->rewind)(pr);
+               }
+       }
+       return (NULL);
+}
+
+static struct protoent *
+pr_byname(struct irs_pr *this, const char *name) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct irs_rule *rule;
+       struct protoent *rval;
+       struct irs_pr *pr;
+       
+       rval = NULL;
+       for (rule = pvt->rules; rule; rule = rule->next) {
+               pr = rule->inst->pr;
+               rval = (*pr->byname)(pr, name);
+               if (rval || !(rule->flags & IRS_CONTINUE))
+                       break;
+       }
+       return (rval);
+}
+
+static struct protoent *
+pr_bynumber(struct irs_pr *this, int proto) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct irs_rule *rule;
+       struct protoent *rval;
+       struct irs_pr *pr;
+       
+       rval = NULL;
+       for (rule = pvt->rules; rule; rule = rule->next) {
+               pr = rule->inst->pr;
+               rval = (*pr->bynumber)(pr, proto);
+               if (rval || !(rule->flags & IRS_CONTINUE))
+                       break;
+       }
+       return (rval);
+}
+
+static void
+pr_rewind(struct irs_pr *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct irs_pr *pr;
+
+       pvt->rule = pvt->rules;
+       if (pvt->rule) {
+               pr = pvt->rule->inst->pr;
+               (*pr->rewind)(pr);
+       }
+}
+
+static void
+pr_minimize(struct irs_pr *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct irs_rule *rule;
+
+       for (rule = pvt->rules; rule != NULL; rule = rule->next) {
+               struct irs_pr *pr = rule->inst->pr;
+
+               (*pr->minimize)(pr);
+       }
+}
+
+static struct __res_state *
+pr_res_get(struct irs_pr *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (!pvt->res) {
+               struct __res_state *res;
+               res = (struct __res_state *)malloc(sizeof *res);
+               if (!res) {
+                       errno = ENOMEM;
+                       return (NULL);
+               }
+               memset(res, 0, sizeof *res);
+               pr_res_set(this, res, free);
+       }
+
+       return (pvt->res);
+}
+
+static void
+pr_res_set(struct irs_pr *this, struct __res_state *res,
+               void (*free_res)(void *)) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct irs_rule *rule;
+
+       if (pvt->res && pvt->free_res) {
+               res_nclose(pvt->res);
+               (*pvt->free_res)(pvt->res);
+       }
+
+       pvt->res = res;
+       pvt->free_res = free_res;
+
+       for (rule = pvt->rules; rule != NULL; rule = rule->next) {
+               struct irs_pr *pr = rule->inst->pr;
+
+               if (pr->res_set)
+                       (*pr->res_set)(pr, pvt->res, NULL);
+       }
+}
diff --git a/lib/bind/irs/gen_pw.c b/lib/bind/irs/gen_pw.c
new file mode 100644 (file)
index 0000000..63e9157
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * 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(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: gen_pw.c,v 1.1 2001/03/29 06:31:44 marka Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#ifndef WANT_IRS_PW
+static int __bind_irs_pw_unneeded;
+#else
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <errno.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "gen_p.h"
+
+/* Types */
+
+struct pvt {
+       struct irs_rule *       rules;
+       struct irs_rule *       rule;
+       struct __res_state *    res;
+       void                    (*free_res)(void *);
+};
+
+/* Forward */
+
+static void                    pw_close(struct irs_pw *);
+static struct passwd *         pw_next(struct irs_pw *);
+static struct passwd *         pw_byname(struct irs_pw *, const char *);
+static struct passwd *         pw_byuid(struct irs_pw *, uid_t);
+static void                    pw_rewind(struct irs_pw *);
+static void                    pw_minimize(struct irs_pw *);
+static struct __res_state *    pw_res_get(struct irs_pw *);
+static void                    pw_res_set(struct irs_pw *,
+                                          struct __res_state *,
+                                          void (*)(void *));
+
+/* Public */
+
+struct irs_pw *
+irs_gen_pw(struct irs_acc *this) {
+       struct gen_p *accpvt = (struct gen_p *)this->private;
+       struct irs_pw *pw;
+       struct pvt *pvt;
+
+       if (!(pw = memget(sizeof *pw))) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pw, 0x5e, sizeof *pw);
+       if (!(pvt = memget(sizeof *pvt))) {
+               memput(pw, sizeof *pvt);
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pvt, 0, sizeof *pvt);
+       pvt->rules = accpvt->map_rules[irs_pw];
+       pvt->rule = pvt->rules;
+       pw->private = pvt;
+       pw->close = pw_close;
+       pw->next = pw_next;
+       pw->byname = pw_byname;
+       pw->byuid = pw_byuid;
+       pw->rewind = pw_rewind;
+       pw->minimize = pw_minimize;
+       pw->res_get = pw_res_get;
+       pw->res_set = pw_res_set;
+       return (pw);
+}
+
+/* Methods */
+
+static void
+pw_close(struct irs_pw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       
+       memput(pvt, sizeof *pvt);
+       memput(this, sizeof *this);
+}
+
+static struct passwd *
+pw_next(struct irs_pw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct passwd *rval;
+       struct irs_pw *pw;
+       
+       while (pvt->rule) {
+               pw = pvt->rule->inst->pw;
+               rval = (*pw->next)(pw);
+               if (rval)
+                       return (rval);
+               if (!(pvt->rule->flags & IRS_CONTINUE))
+                       break;
+               pvt->rule = pvt->rule->next;
+               if (pvt->rule) {
+                       pw = pvt->rule->inst->pw;
+                       (*pw->rewind)(pw);
+               }
+       }
+       return (NULL);
+}
+
+static void
+pw_rewind(struct irs_pw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct irs_pw *pw;
+       
+       pvt->rule = pvt->rules;
+       if (pvt->rule) {
+               pw = pvt->rule->inst->pw;
+               (*pw->rewind)(pw);
+       }
+}
+
+static struct passwd *
+pw_byname(struct irs_pw *this, const char *name) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct irs_rule *rule;
+       struct passwd *rval;
+       struct irs_pw *pw;
+       
+       rval = NULL;
+       for (rule = pvt->rules; rule; rule = rule->next) {
+               pw = rule->inst->pw;
+               rval = (*pw->byname)(pw, name);
+               if (rval || !(rule->flags & IRS_CONTINUE))
+                       break;
+       }
+       return (rval);
+}
+
+static struct passwd *
+pw_byuid(struct irs_pw *this, uid_t uid) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct irs_rule *rule;
+       struct passwd *rval;
+       struct irs_pw *pw;
+       
+       rval = NULL;
+       for (rule = pvt->rules; rule; rule = rule->next) {
+               pw = rule->inst->pw;
+               rval = (*pw->byuid)(pw, uid);
+               if (rval || !(rule->flags & IRS_CONTINUE))
+                       break;
+       }
+       return (rval);
+}      
+
+static void
+pw_minimize(struct irs_pw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct irs_rule *rule;
+
+       for (rule = pvt->rules; rule != NULL; rule = rule->next) {
+               struct irs_pw *pw = rule->inst->pw;
+
+               (*pw->minimize)(pw);
+       }
+}
+
+static struct __res_state *
+pw_res_get(struct irs_pw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (!pvt->res) {
+               struct __res_state *res;
+               res = (struct __res_state *)malloc(sizeof *res);
+               if (!res) {
+                       errno = ENOMEM;
+                       return (NULL);
+               }
+               memset(res, 0, sizeof *res);
+               pw_res_set(this, res, free);
+       }
+
+       return (pvt->res);
+}
+
+static void
+pw_res_set(struct irs_pw *this, struct __res_state *res,
+               void (*free_res)(void *)) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct irs_rule *rule;
+
+       if (pvt->res && pvt->free_res) {
+               res_nclose(pvt->res);
+               (*pvt->free_res)(pvt->res);
+       }
+
+       pvt->res = res;
+       pvt->free_res = free_res;
+
+       for (rule = pvt->rules; rule != NULL; rule = rule->next) {
+               struct irs_pw *pw = rule->inst->pw;
+
+               if (pw->res_set)
+                       (*pw->res_set)(pw, pvt->res, NULL);
+       }
+}
+
+#endif /* WANT_IRS_PW */
diff --git a/lib/bind/irs/gen_sv.c b/lib/bind/irs/gen_sv.c
new file mode 100644 (file)
index 0000000..9062394
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * 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(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: gen_sv.c,v 1.1 2001/03/29 06:31:44 marka Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "gen_p.h"
+
+/* Types */
+
+struct pvt {
+       struct irs_rule *       rules;
+       struct irs_rule *       rule;
+       struct __res_state *    res;
+       void                    (*free_res)(void *);
+};
+
+/* Forward */
+
+static void                    sv_close(struct irs_sv*);
+static struct servent *                sv_next(struct irs_sv *);
+static struct servent *                sv_byname(struct irs_sv *, const char *,
+                                         const char *);
+static struct servent *                sv_byport(struct irs_sv *, int, const char *);
+static void                    sv_rewind(struct irs_sv *);
+static void                    sv_minimize(struct irs_sv *);
+static struct __res_state *    sv_res_get(struct irs_sv *);
+static void                    sv_res_set(struct irs_sv *,
+                                             struct __res_state *,
+                                             void (*)(void *));
+
+/* Public */
+
+struct irs_sv *
+irs_gen_sv(struct irs_acc *this) {
+       struct gen_p *accpvt = (struct gen_p *)this->private;
+       struct irs_sv *sv;
+       struct pvt *pvt;
+
+       if (!(sv = memget(sizeof *sv))) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(sv, 0x5e, sizeof *sv);
+       if (!(pvt = memget(sizeof *pvt))) {
+               memput(sv, sizeof *sv);
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pvt, 0, sizeof *pvt);
+       pvt->rules = accpvt->map_rules[irs_sv];
+       pvt->rule = pvt->rules;
+       sv->private = pvt;
+       sv->close = sv_close;
+       sv->next = sv_next;
+       sv->byname = sv_byname;
+       sv->byport = sv_byport;
+       sv->rewind = sv_rewind;
+       sv->minimize = sv_minimize;
+       sv->res_get = sv_res_get;
+       sv->res_set = sv_res_set;
+       return (sv);
+}
+
+/* Methods */
+
+static void
+sv_close(struct irs_sv *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       
+       memput(pvt, sizeof *pvt);
+       memput(this, sizeof *this);
+}
+
+static struct servent *
+sv_next(struct irs_sv *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct servent *rval;
+       struct irs_sv *sv;
+       
+       while (pvt->rule) {
+               sv = pvt->rule->inst->sv;
+               rval = (*sv->next)(sv);
+               if (rval)
+                       return (rval);
+               if (!(pvt->rule->flags & IRS_CONTINUE))
+                       break;
+               pvt->rule = pvt->rule->next;
+               if (pvt->rule) {
+                       sv = pvt->rule->inst->sv;
+                       (*sv->rewind)(sv);
+               }
+       }
+       return (NULL);
+}
+
+static struct servent *
+sv_byname(struct irs_sv *this, const char *name, const char *proto) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct irs_rule *rule;
+       struct servent *rval;
+       struct irs_sv *sv;
+       
+       rval = NULL;
+       for (rule = pvt->rules; rule; rule = rule->next) {
+               sv = rule->inst->sv;
+               rval = (*sv->byname)(sv, name, proto);
+               if (rval || !(rule->flags & IRS_CONTINUE))
+                       break;
+       }
+       return (rval);
+}
+
+static struct servent *
+sv_byport(struct irs_sv *this, int port, const char *proto) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct irs_rule *rule;
+       struct servent *rval;
+       struct irs_sv *sv;
+       
+       rval = NULL;
+       for (rule = pvt->rules; rule; rule = rule->next) {
+               sv = rule->inst->sv;
+               rval = (*sv->byport)(sv, port, proto);
+               if (rval || !(rule->flags & IRS_CONTINUE))
+                       break;
+       }
+       return (rval);
+}
+
+static void
+sv_rewind(struct irs_sv *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct irs_sv *sv;
+
+       pvt->rule = pvt->rules;
+       if (pvt->rule) {
+               sv = pvt->rule->inst->sv;
+               (*sv->rewind)(sv);
+       }
+}
+
+static void
+sv_minimize(struct irs_sv *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct irs_rule *rule;
+
+       for (rule = pvt->rules; rule != NULL; rule = rule->next) {
+               struct irs_sv *sv = rule->inst->sv;
+
+               (*sv->minimize)(sv);
+       }
+}
+
+static struct __res_state *
+sv_res_get(struct irs_sv *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (!pvt->res) {
+               struct __res_state *res;
+               res = (struct __res_state *)malloc(sizeof *res);
+               if (!res) {
+                       errno = ENOMEM;
+                       return (NULL);
+               }
+               memset(res, 0, sizeof *res);
+               sv_res_set(this, res, free);
+       }
+
+       return (pvt->res);
+}
+
+static void
+sv_res_set(struct irs_sv *this, struct __res_state *res,
+               void (*free_res)(void *)) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct irs_rule *rule;
+
+       if (pvt->res && pvt->free_res) {
+               res_nclose(pvt->res);
+               (*pvt->free_res)(pvt->res);
+       }
+
+       pvt->res = res;
+       pvt->free_res = free_res;
+
+       for (rule = pvt->rules; rule != NULL; rule = rule->next) {
+               struct irs_sv *sv = rule->inst->sv;
+
+               if (sv->res_set)
+                       (*sv->res_set)(sv, pvt->res, NULL);
+       }
+}
diff --git a/lib/bind/irs/getaddrinfo.c b/lib/bind/irs/getaddrinfo.c
new file mode 100644 (file)
index 0000000..3a904b5
--- /dev/null
@@ -0,0 +1,1254 @@
+/*     $KAME: getaddrinfo.c,v 1.14 2001/01/06 09:41:15 jinmei Exp $    */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * 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 project 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 PROJECT 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 PROJECT 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.
+ */
+
+/*
+ * Issues to be discussed:
+ * - Thread safe-ness must be checked.
+ * - Return values.  There are nonstandard return values defined and used
+ *   in the source code.  This is because RFC2553 is silent about which error
+ *   code must be returned for which situation.
+ * - IPv4 classful (shortened) form.  RFC2553 is silent about it.  XNET 5.2
+ *   says to use inet_aton() to convert IPv4 numeric to binary (allows
+ *   classful form as a result).
+ *   current code - disallow classful form for IPv4 (due to use of inet_pton).
+ * - freeaddrinfo(NULL).  RFC2553 is silent about it.  XNET 5.2 says it is
+ *   invalid.
+ *   current code - SEGV on freeaddrinfo(NULL)
+ * Note:
+ * - We use getipnodebyname() just for thread-safeness.  There's no intent
+ *   to let it do PF_UNSPEC (actually we never pass PF_UNSPEC to
+ *   getipnodebyname().
+ * - The code filters out AFs that are not supported by the kernel,
+ *   when globbing NULL hostname (to loopback, or wildcard).  Is it the right
+ *   thing to do?  What is the relationship with post-RFC2553 AI_ADDRCONFIG
+ *   in ai_flags?
+ * - (post-2553) semantics of AI_ADDRCONFIG itself is too vague.
+ *   (1) what should we do against numeric hostname (2) what should we do
+ *   against NULL hostname (3) what is AI_ADDRCONFIG itself.  AF not ready?
+ *   non-loopback address configured?  global address configured?
+ * - To avoid search order issue, we have a big amount of code duplicate
+ *   from gethnamaddr.c and some other places.  The issues that there's no
+ *   lower layer function to lookup "IPv4 or IPv6" record.  Calling
+ *   gethostbyname2 from getaddrinfo will end up in wrong search order, as
+ *   follows:
+ *     - The code makes use of following calls when asked to resolver with
+ *       ai_family  = PF_UNSPEC:
+ *             getipnodebyname(host, AF_INET6);
+ *             getipnodebyname(host, AF_INET);
+ *       This will result in the following queries if the node is configure to
+ *       prefer /etc/hosts than DNS:
+ *             lookup /etc/hosts for IPv6 address
+ *             lookup DNS for IPv6 address
+ *             lookup /etc/hosts for IPv4 address
+ *             lookup DNS for IPv4 address
+ *       which may not meet people's requirement.
+ *       The right thing to happen is to have underlying layer which does
+ *       PF_UNSPEC lookup (lookup both) and return chain of addrinfos.
+ *       This would result in a bit of code duplicate with _dns_ghbyname() and
+ *       friends.
+ */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <netdb.h>
+#include <resolv.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <stdarg.h>
+
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_data.h"
+
+/*
+ * if we enable it, we will see duplicated addrinfo entries on reply if both
+ * AAAA and A6 records are found.  disable it for default installation.
+ */
+#undef T_A6
+
+#define SUCCESS 0
+#define ANY 0
+#define YES 1
+#define NO  0
+
+static const char in_addrany[] = { 0, 0, 0, 0 };
+static const char in6_addrany[] = {
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+static const char in_loopback[] = { 127, 0, 0, 1 };
+static const char in6_loopback[] = {
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
+};
+
+static const struct afd {
+       int a_af;
+       int a_addrlen;
+       int a_socklen;
+       int a_off;
+       const char *a_addrany;
+       const char *a_loopback;
+       int a_scoped;
+} afdl [] = {
+#ifdef INET6
+       {PF_INET6, sizeof(struct in6_addr),
+        sizeof(struct sockaddr_in6),
+        offsetof(struct sockaddr_in6, sin6_addr),
+        in6_addrany, in6_loopback, 1},
+#endif
+       {PF_INET, sizeof(struct in_addr),
+        sizeof(struct sockaddr_in),
+        offsetof(struct sockaddr_in, sin_addr),
+        in_addrany, in_loopback, 0},
+       {0, 0, 0, 0, NULL, NULL, 0},
+};
+
+struct explore {
+       int e_af;
+       int e_socktype;
+       int e_protocol;
+       const char *e_protostr;
+       int e_wild;
+#define WILD_AF(ex)            ((ex)->e_wild & 0x01)
+#define WILD_SOCKTYPE(ex)      ((ex)->e_wild & 0x02)
+#define WILD_PROTOCOL(ex)      ((ex)->e_wild & 0x04)
+};
+
+static const struct explore explore[] = {
+#if 0
+       { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 },
+#endif
+#ifdef INET6
+       { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
+       { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
+       { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 },
+#endif
+       { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
+       { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
+       { PF_INET, SOCK_RAW, ANY, NULL, 0x05 },
+       { -1, 0, 0, NULL, 0 },
+};
+
+#ifdef INET6
+#define PTON_MAX       16
+#else
+#define PTON_MAX       4
+#endif
+
+#if PACKETSZ > 1024
+#define MAXPACKET      PACKETSZ
+#else
+#define MAXPACKET      1024
+#endif
+
+typedef union {
+       HEADER hdr;
+       u_char buf[MAXPACKET];
+} querybuf;
+
+static int str_isnumber __P((const char *));
+static int explore_fqdn __P((const struct addrinfo *, const char *,
+       const char *, struct addrinfo **));
+static int explore_copy __P((const struct addrinfo *, const struct addrinfo *,
+       struct addrinfo **));
+static int explore_null __P((const struct addrinfo *,
+       const char *, struct addrinfo **));
+static int explore_numeric __P((const struct addrinfo *, const char *,
+       const char *, struct addrinfo **));
+static int explore_numeric_scope __P((const struct addrinfo *, const char *,
+       const char *, struct addrinfo **));
+static int get_canonname __P((const struct addrinfo *,
+       struct addrinfo *, const char *));
+static struct addrinfo *get_ai __P((const struct addrinfo *,
+       const struct afd *, const char *));
+static struct addrinfo *copy_ai __P((const struct addrinfo *));
+static int get_portmatch __P((const struct addrinfo *, const char *));
+static int get_port __P((const struct addrinfo *, const char *, int));
+static const struct afd *find_afd __P((int));
+static int addrconfig __P((int));
+#ifdef INET6
+static int ip6_str2scopeid __P((char *, struct sockaddr_in6 *));
+#endif
+static struct net_data *init __P((void));
+
+struct addrinfo *hostent2addrinfo __P((struct hostent *,
+                                      const struct addrinfo *));
+struct addrinfo *addr2addrinfo __P((const struct addrinfo *,
+                                   const char *));
+
+#if 0
+static const char *ai_errlist[] = {
+       "Success",
+       "Address family for hostname not supported",    /* EAI_ADDRFAMILY */
+       "Temporary failure in name resolution",         /* EAI_AGAIN      */
+       "Invalid value for ai_flags",                   /* EAI_BADFLAGS   */
+       "Non-recoverable failure in name resolution",   /* EAI_FAIL       */
+       "ai_family not supported",                      /* EAI_FAMILY     */
+       "Memory allocation failure",                    /* EAI_MEMORY     */
+       "No address associated with hostname",          /* EAI_NODATA     */
+       "hostname nor servname provided, or not known", /* EAI_NONAME     */
+       "servname not supported for ai_socktype",       /* EAI_SERVICE    */
+       "ai_socktype not supported",                    /* EAI_SOCKTYPE   */
+       "System error returned in errno",               /* EAI_SYSTEM     */
+       "Invalid value for hints",                      /* EAI_BADHINTS   */
+       "Resolved protocol is unknown",                 /* EAI_PROTOCOL   */
+       "Unknown error",                                /* EAI_MAX        */
+};
+#endif
+
+/* XXX macros that make external reference is BAD. */
+
+#define GET_AI(ai, afd, addr) \
+do { \
+       /* external reference: pai, error, and label free */ \
+       (ai) = get_ai(pai, (afd), (addr)); \
+       if ((ai) == NULL) { \
+               error = EAI_MEMORY; \
+               goto free; \
+       } \
+} while (/*CONSTCOND*/0)
+
+#define GET_PORT(ai, serv) \
+do { \
+       /* external reference: error and label free */ \
+       error = get_port((ai), (serv), 0); \
+       if (error != 0) \
+               goto free; \
+} while (/*CONSTCOND*/0)
+
+#define GET_CANONNAME(ai, str) \
+do { \
+       /* external reference: pai, error and label free */ \
+       error = get_canonname(pai, (ai), (str)); \
+       if (error != 0) \
+               goto free; \
+} while (/*CONSTCOND*/0)
+
+#define ERR(err) \
+do { \
+       /* external reference: error, and label bad */ \
+       error = (err); \
+       goto bad; \
+       /*NOTREACHED*/ \
+} while (/*CONSTCOND*/0)
+
+#define MATCH_FAMILY(x, y, w) \
+       ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC)))
+#define MATCH(x, y, w) \
+       ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY)))
+
+#if 0                          /* bind8 has its own version */
+char *
+gai_strerror(ecode)
+       int ecode;
+{
+       if (ecode < 0 || ecode > EAI_MAX)
+               ecode = EAI_MAX;
+       return ai_errlist[ecode];
+}
+#endif
+
+void
+freeaddrinfo(ai)
+       struct addrinfo *ai;
+{
+       struct addrinfo *next;
+
+       do {
+               next = ai->ai_next;
+               if (ai->ai_canonname)
+                       free(ai->ai_canonname);
+               /* no need to free(ai->ai_addr) */
+               free(ai);
+               ai = next;
+       } while (ai);
+}
+
+static int
+str_isnumber(p)
+       const char *p;
+{
+       char *ep;
+
+       if (*p == '\0')
+               return NO;
+       ep = NULL;
+       (void)strtoul(p, &ep, 10);
+       if (ep && *ep == '\0')
+               return YES;
+       else
+               return NO;
+}
+
+int
+getaddrinfo(hostname, servname, hints, res)
+       const char *hostname, *servname;
+       const struct addrinfo *hints;
+       struct addrinfo **res;
+{
+       struct addrinfo sentinel;
+       struct addrinfo *cur;
+       int error = 0;
+       struct addrinfo ai, ai0, *afai;
+       struct addrinfo *pai;
+       const struct explore *ex;
+
+       memset(&sentinel, 0, sizeof(sentinel));
+       cur = &sentinel;
+       pai = &ai;
+       pai->ai_flags = 0;
+       pai->ai_family = PF_UNSPEC;
+       pai->ai_socktype = ANY;
+       pai->ai_protocol = ANY;
+       pai->ai_addrlen = 0;
+       pai->ai_canonname = NULL;
+       pai->ai_addr = NULL;
+       pai->ai_next = NULL;
+
+       if (hostname == NULL && servname == NULL)
+               return EAI_NONAME;
+       if (hints) {
+               /* error check for hints */
+               if (hints->ai_addrlen || hints->ai_canonname ||
+                   hints->ai_addr || hints->ai_next)
+                       ERR(EAI_BADHINTS); /* xxx */
+               if (hints->ai_flags & ~AI_MASK)
+                       ERR(EAI_BADFLAGS);
+               switch (hints->ai_family) {
+               case PF_UNSPEC:
+               case PF_INET:
+#ifdef INET6
+               case PF_INET6:
+#endif
+                       break;
+               default:
+                       ERR(EAI_FAMILY);
+               }
+               memcpy(pai, hints, sizeof(*pai));
+
+               /*
+                * if both socktype/protocol are specified, check if they
+                * are meaningful combination.
+                */
+               if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) {
+                       for (ex = explore; ex->e_af >= 0; ex++) {
+                               if (pai->ai_family != ex->e_af)
+                                       continue;
+                               if (ex->e_socktype == ANY)
+                                       continue;
+                               if (ex->e_protocol == ANY)
+                                       continue;
+                               if (pai->ai_socktype == ex->e_socktype &&
+                                   pai->ai_protocol != ex->e_protocol) {
+                                       ERR(EAI_BADHINTS);
+                               }
+                       }
+               }
+       }
+
+       /*
+        * post-2553: AI_ALL and AI_V4MAPPED are effective only against
+        * AF_INET6 query.  They needs to be ignored if specified in other
+        * occassions.
+        */
+       switch (pai->ai_flags & (AI_ALL | AI_V4MAPPED)) {
+       case AI_V4MAPPED:
+       case AI_ALL | AI_V4MAPPED:
+               if (pai->ai_family != AF_INET6)
+                       pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED);
+               break;
+       case AI_ALL:
+#if 1
+               /* illegal */
+               ERR(EAI_BADFLAGS);
+#else
+               pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED);
+#endif
+               break;
+       }
+
+       /*
+        * check for special cases.  (1) numeric servname is disallowed if
+        * socktype/protocol are left unspecified. (2) servname is disallowed
+        * for raw and other inet{,6} sockets.
+        */
+       if (MATCH_FAMILY(pai->ai_family, PF_INET, 1)
+#ifdef PF_INET6
+        || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
+#endif
+           ) {
+               ai0 = *pai;     /* backup *pai */
+
+               if (pai->ai_family == PF_UNSPEC) {
+#ifdef PF_INET6
+                       pai->ai_family = PF_INET6;
+#else
+                       pai->ai_family = PF_INET;
+#endif
+               }
+               error = get_portmatch(pai, servname);
+               if (error)
+                       ERR(error);
+
+               *pai = ai0;
+       }
+
+       ai0 = *pai;
+
+       /* NULL hostname, or numeric hostname */
+       for (ex = explore; ex->e_af >= 0; ex++) {
+               *pai = ai0;
+
+               if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
+                       continue;
+               if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))
+                       continue;
+               if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))
+                       continue;
+
+               if (pai->ai_family == PF_UNSPEC)
+                       pai->ai_family = ex->e_af;
+               if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
+                       pai->ai_socktype = ex->e_socktype;
+               if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
+                       pai->ai_protocol = ex->e_protocol;
+
+               /*
+                * if the servname does not match socktype/protocol, ignore it.
+                */
+               if (get_portmatch(pai, servname) != 0)
+                       continue;
+
+               if (hostname == NULL) {
+                       /*
+                        * filter out AFs that are not supported by the kernel
+                        * XXX errno?
+                        */
+                       if (!addrconfig(pai->ai_family))
+                               continue;
+                       error = explore_null(pai, servname, &cur->ai_next);
+               } else
+                       error = explore_numeric_scope(pai, hostname, servname,
+                           &cur->ai_next);
+
+               if (error)
+                       goto free;
+
+               while (cur && cur->ai_next)
+                       cur = cur->ai_next;
+       }
+
+       /*
+        * XXX
+        * If numreic representation of AF1 can be interpreted as FQDN
+        * representation of AF2, we need to think again about the code below.
+        */
+       if (sentinel.ai_next)
+               goto good;
+
+       if (pai->ai_flags & AI_NUMERICHOST)
+               ERR(EAI_NODATA);
+       if (hostname == NULL)
+               ERR(EAI_NODATA);
+
+       /*
+        * hostname as alphabetical name.
+        * We'll make sure that
+        * - if returning addrinfo list is empty, return non-zero error
+        *   value (already known one or EAI_NODATA).
+        * - otherwise, 
+        *   + if we haven't had any errors, return 0 (i.e. success).
+        *   + if we've had an error, free the list and return the error.
+        * without any assumption on the behavior of explore_fqdn().
+        */
+
+       /* first, try to query DNS for all possible address families. */
+       *pai = ai0;
+       error = explore_fqdn(pai, hostname, servname, &afai);
+       if (error) {
+               if (afai != NULL)
+                       freeaddrinfo(afai);
+               goto free;
+       }
+       if (afai == NULL) {
+               error = EAI_NODATA; /* we've had no errors. */
+               goto free;
+       }
+
+       /*
+        * we would like to prefer AF_INET6 than AF_INET, so we'll make an
+        * outer loop by AFs.
+        */
+       for (ex = explore; ex->e_af >= 0; ex++) {
+               *pai = ai0;
+
+               if (pai->ai_family == PF_UNSPEC)
+                       pai->ai_family = ex->e_af;
+
+               if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
+                       continue;
+               if (!MATCH(pai->ai_socktype, ex->e_socktype,
+                          WILD_SOCKTYPE(ex))) {
+                       continue;
+               }
+               if (!MATCH(pai->ai_protocol, ex->e_protocol,
+                          WILD_PROTOCOL(ex))) {
+                       continue;
+               }
+
+#ifdef AI_ADDRCONFIG
+               /*
+                * If AI_ADDRCONFIG is specified, check if we are
+                * expected to return the address family or not.
+                */
+               if ((pai->ai_flags & AI_ADDRCONFIG) != 0 &&
+                   !addrconfig(pai->ai_family))
+                       continue;
+#endif
+
+               if (pai->ai_family == PF_UNSPEC)
+                       pai->ai_family = ex->e_af;
+               if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
+                       pai->ai_socktype = ex->e_socktype;
+               if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
+                       pai->ai_protocol = ex->e_protocol;
+
+               /*
+                * if the servname does not match socktype/protocol, ignore it.
+                */
+               if (get_portmatch(pai, servname) != 0)
+                       continue;
+
+               if ((error = explore_copy(pai, afai, &cur->ai_next)) != 0) {
+                       freeaddrinfo(afai);
+                       goto free;
+               }
+
+               while (cur && cur->ai_next)
+                       cur = cur->ai_next;
+       }
+
+       freeaddrinfo(afai);     /* afai must not be NULL at this point. */
+
+       /* we must not have got any errors. */
+       if (error != 0) /* just for diagnosis */
+               abort();
+
+       if (sentinel.ai_next) {
+good:
+               *res = sentinel.ai_next;
+               return(SUCCESS);
+       } else {
+               /*
+                * All the process succeeded, but we've had an empty list. 
+                * This can happen if the given hints do not match our
+                * candidates.
+                */
+               error = EAI_NODATA;
+       }
+
+free:
+bad:
+       if (sentinel.ai_next)
+               freeaddrinfo(sentinel.ai_next);
+       *res = NULL;
+       return(error);
+}
+
+/*
+ * FQDN hostname, DNS lookup
+ */
+static int
+explore_fqdn(pai, hostname, servname, res)
+       const struct addrinfo *pai;
+       const char *hostname;
+       const char *servname;
+       struct addrinfo **res;
+{
+       struct addrinfo *result;
+       struct addrinfo *cur;
+       struct net_data *net_data = init();
+       struct irs_ho *ho;
+       int error = 0;
+       char tmp[NS_MAXDNAME];
+       const char *cp;
+
+       result = NULL;
+
+       /*
+        * if the servname does not match socktype/protocol, ignore it.
+        */
+       if (get_portmatch(pai, servname) != 0)
+               return(0);
+
+       if (!net_data || !(ho = net_data->ho))
+               return(0);
+#if 0                          /* XXX (notyet) */
+       if (net_data->ho_stayopen && net_data->ho_last &&
+           net_data->ho_last->h_addrtype == af) {
+               if (ns_samename(name, net_data->ho_last->h_name) == 1)
+                       return (net_data->ho_last);
+               for (hap = net_data->ho_last->h_aliases; hap && *hap; hap++)
+                       if (ns_samename(name, *hap) == 1)
+                               return (net_data->ho_last);
+       }
+#endif
+       if (!strchr(hostname, '.') &&
+           (cp = res_hostalias(net_data->res, hostname,
+                               tmp, sizeof(tmp))))
+               hostname = cp;
+       result = (*ho->addrinfo)(ho, hostname, pai);
+       if (!net_data->ho_stayopen) {
+               (*ho->minimize)(ho);
+       }
+       if (result == NULL) {
+               int *e = __h_errno();
+
+               switch(*e) {
+               case NETDB_INTERNAL:
+                       error = EAI_SYSTEM;
+                       break;
+               case TRY_AGAIN:
+                       error = EAI_AGAIN;
+                       break;
+               case NO_RECOVERY:
+                       error = EAI_FAIL;
+                       break;
+               case HOST_NOT_FOUND:
+               case NO_DATA:
+                       error = EAI_NODATA;
+                       break;
+               default:
+               case NETDB_SUCCESS: /* should be impossible... */
+                       error = EAI_NODATA;
+                       break;
+               }
+               goto free;
+       }
+
+       for (cur = result; cur; cur = cur->ai_next) {
+               GET_PORT(cur, servname); /* XXX: redundant lookups... */
+               /* canonname should already be filled. */
+       }
+
+       *res = result;
+
+       return(0);
+
+free:
+       if (result)
+               freeaddrinfo(result);
+       return error;
+}
+
+static int
+explore_copy(pai, src0, res)
+       const struct addrinfo *pai;     /* seed */
+       const struct addrinfo *src0;    /* source */
+       struct addrinfo **res;
+{
+       int error;
+       struct addrinfo sentinel, *cur;
+       const struct addrinfo *src;
+
+       error = 0;
+       sentinel.ai_next = NULL;
+       cur = &sentinel;
+
+       for (src = src0; src != NULL; src = src->ai_next) {
+               if (src->ai_family != pai->ai_family)
+                       continue;
+
+               cur->ai_next = copy_ai(src);
+               if (!cur->ai_next) {
+                       error = EAI_MEMORY;
+                       goto fail;
+               }
+
+               cur->ai_next->ai_socktype = pai->ai_socktype;
+               cur->ai_next->ai_protocol = pai->ai_protocol;
+               cur = cur->ai_next;
+       }
+
+       *res = sentinel.ai_next;
+       return 0;
+
+fail:
+       freeaddrinfo(sentinel.ai_next);
+       return error;
+}
+
+/*
+ * hostname == NULL.
+ * passive socket -> anyaddr (0.0.0.0 or ::)
+ * non-passive socket -> localhost (127.0.0.1 or ::1)
+ */
+static int
+explore_null(pai, servname, res)
+       const struct addrinfo *pai;
+       const char *servname;
+       struct addrinfo **res;
+{
+       const struct afd *afd;
+       struct addrinfo *cur;
+       struct addrinfo sentinel;
+       int error;
+
+       *res = NULL;
+       sentinel.ai_next = NULL;
+       cur = &sentinel;
+
+       afd = find_afd(pai->ai_family);
+       if (afd == NULL)
+               return 0;
+
+       if (pai->ai_flags & AI_PASSIVE) {
+               GET_AI(cur->ai_next, afd, afd->a_addrany);
+               /* xxx meaningless?
+                * GET_CANONNAME(cur->ai_next, "anyaddr");
+                */
+               GET_PORT(cur->ai_next, servname);
+       } else {
+               GET_AI(cur->ai_next, afd, afd->a_loopback);
+               /* xxx meaningless?
+                * GET_CANONNAME(cur->ai_next, "localhost");
+                */
+               GET_PORT(cur->ai_next, servname);
+       }
+       cur = cur->ai_next;
+
+       *res = sentinel.ai_next;
+       return 0;
+
+free:
+       if (sentinel.ai_next)
+               freeaddrinfo(sentinel.ai_next);
+       return error;
+}
+
+/*
+ * numeric hostname
+ */
+static int
+explore_numeric(pai, hostname, servname, res)
+       const struct addrinfo *pai;
+       const char *hostname;
+       const char *servname;
+       struct addrinfo **res;
+{
+       const struct afd *afd;
+       struct addrinfo *cur;
+       struct addrinfo sentinel;
+       int error;
+       char pton[PTON_MAX];
+
+       *res = NULL;
+       sentinel.ai_next = NULL;
+       cur = &sentinel;
+
+       afd = find_afd(pai->ai_family);
+       if (afd == NULL)
+               return 0;
+
+       switch (afd->a_af) {
+#if 0 /*X/Open spec*/
+       case AF_INET:
+               if (inet_aton(hostname, (struct in_addr *)pton) == 1) {
+                       if (pai->ai_family == afd->a_af ||
+                           pai->ai_family == PF_UNSPEC /*?*/) {
+                               GET_AI(cur->ai_next, afd, pton);
+                               GET_PORT(cur->ai_next, servname);
+                               while (cur && cur->ai_next)
+                                       cur = cur->ai_next;
+                       } else
+                               ERR(EAI_FAMILY);        /*xxx*/
+               }
+               break;
+#endif
+       default:
+               if (inet_pton(afd->a_af, hostname, pton) == 1) {
+                       if (pai->ai_family == afd->a_af ||
+                           pai->ai_family == PF_UNSPEC /*?*/) {
+                               GET_AI(cur->ai_next, afd, pton);
+                               GET_PORT(cur->ai_next, servname);
+                               while (cur && cur->ai_next)
+                                       cur = cur->ai_next;
+                       } else
+                               ERR(EAI_FAMILY);        /*xxx*/
+               }
+               break;
+       }
+
+       *res = sentinel.ai_next;
+       return 0;
+
+free:
+bad:
+       if (sentinel.ai_next)
+               freeaddrinfo(sentinel.ai_next);
+       return error;
+}
+
+/*
+ * numeric hostname with scope
+ */
+static int
+explore_numeric_scope(pai, hostname, servname, res)
+       const struct addrinfo *pai;
+       const char *hostname;
+       const char *servname;
+       struct addrinfo **res;
+{
+#if !defined(SCOPE_DELIMITER) || !defined(INET6)
+       return explore_numeric(pai, hostname, servname, res);
+#else
+       const struct afd *afd;
+       struct addrinfo *cur;
+       int error;
+       char *cp, *hostname2 = NULL, *scope, *addr;
+       struct sockaddr_in6 *sin6;
+
+       afd = find_afd(pai->ai_family);
+       if (afd == NULL)
+               return 0;
+
+       if (!afd->a_scoped)
+               return explore_numeric(pai, hostname, servname, res);
+
+       cp = strchr(hostname, SCOPE_DELIMITER);
+       if (cp == NULL)
+               return explore_numeric(pai, hostname, servname, res);
+
+#if 0
+       /*
+        * Handle special case of <scope id><delimiter><scoped_address>
+        */
+       hostname2 = strdup(hostname);
+       if (hostname2 == NULL)
+               return EAI_MEMORY;
+       /* terminate at the delimiter */
+       hostname2[cp - hostname] = '\0';
+       scope = hostname2;
+       addr = cp + 1;
+#else
+       /*
+        * Handle special case of <scoped_address><delimiter><scope id>
+        */
+       hostname2 = strdup(hostname);
+       if (hostname2 == NULL)
+               return EAI_MEMORY;
+       /* terminate at the delimiter */
+       hostname2[cp - hostname] = '\0';
+       addr = hostname2;
+       scope = cp + 1;
+#endif
+
+       error = explore_numeric(pai, addr, servname, res);
+       if (error == 0) {
+               int scopeid;
+
+               for (cur = *res; cur; cur = cur->ai_next) {
+                       if (cur->ai_family != AF_INET6)
+                               continue;
+                       sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr;
+                       if ((scopeid = ip6_str2scopeid(scope, sin6)) == -1) {
+                               free(hostname2);
+                               return(EAI_NODATA); /* XXX: is return OK? */
+                       }
+                       sin6->sin6_scope_id = scopeid;
+               }
+       }
+
+       free(hostname2);
+
+       return error;
+#endif
+}
+
+static int
+get_canonname(pai, ai, str)
+       const struct addrinfo *pai;
+       struct addrinfo *ai;
+       const char *str;
+{
+       if ((pai->ai_flags & AI_CANONNAME) != 0) {
+               ai->ai_canonname = (char *)malloc(strlen(str) + 1);
+               if (ai->ai_canonname == NULL)
+                       return EAI_MEMORY;
+               strcpy(ai->ai_canonname, str);
+       }
+       return 0;
+}
+
+static struct addrinfo *
+get_ai(pai, afd, addr)
+       const struct addrinfo *pai;
+       const struct afd *afd;
+       const char *addr;
+{
+       char *p;
+       struct addrinfo *ai;
+
+       ai = (struct addrinfo *)malloc(sizeof(struct addrinfo)
+               + (afd->a_socklen));
+       if (ai == NULL)
+               return NULL;
+
+       memcpy(ai, pai, sizeof(struct addrinfo));
+       ai->ai_addr = (struct sockaddr *)(void *)(ai + 1);
+       memset(ai->ai_addr, 0, (size_t)afd->a_socklen);
+       ai->ai_addr->sa_len = afd->a_socklen;
+       ai->ai_addrlen = afd->a_socklen;
+       ai->ai_addr->sa_family = ai->ai_family = afd->a_af;
+       p = (char *)(void *)(ai->ai_addr);
+       memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen);
+       return ai;
+}
+
+/* XXX need to malloc() the same way we do from other functions! */
+static struct addrinfo *
+copy_ai(pai)
+       const struct addrinfo *pai;
+{
+       struct addrinfo *ai;
+       size_t l;
+
+       l = sizeof(*ai) + pai->ai_addrlen;
+       if ((ai = (struct addrinfo *)malloc(l)) == NULL)
+               return NULL;
+       memset(ai, 0, l);
+       memcpy(ai, pai, sizeof(*ai));
+       ai->ai_addr = (struct sockaddr *)(void *)(ai + 1);
+       memcpy(ai->ai_addr, pai->ai_addr, pai->ai_addrlen);
+
+       if (pai->ai_canonname) {
+               l = strlen(pai->ai_canonname) + 1;
+               if ((ai->ai_canonname = malloc(l)) == NULL) {
+                       free(ai);
+                       return NULL;
+               }
+#ifdef HAVE_STRLCPY
+               strlcpy(ai->ai_canonname, pai->ai_canonname, l);
+#else
+               strncpy(ai->ai_canonname, pai->ai_canonname, l);
+#endif
+       } else {
+               /* just to make sure */
+               ai->ai_canonname = NULL;
+       }
+
+       ai->ai_next = NULL;
+
+       return ai;
+}
+
+static int
+get_portmatch(const struct addrinfo *ai, const char *servname) {
+
+       /* get_port does not touch first argument. when matchonly == 1. */
+       /* LINTED const cast */
+       return get_port((const struct addrinfo *)ai, servname, 1);
+}
+
+static int
+get_port(const struct addrinfo *ai, const char *servname, int matchonly) {
+       const char *proto;
+       struct servent *sp;
+       int port;
+       int allownumeric;
+
+       if (servname == NULL)
+               return 0;
+       switch (ai->ai_family) {
+       case AF_INET:
+#ifdef AF_INET6
+       case AF_INET6:
+#endif
+               break;
+       default:
+               return 0;
+       }
+
+       switch (ai->ai_socktype) {
+       case SOCK_RAW:
+               return EAI_SERVICE;
+       case SOCK_DGRAM:
+       case SOCK_STREAM:
+               allownumeric = 1;
+               break;
+       case ANY:
+               allownumeric = 0;
+               break;
+       default:
+               return EAI_SOCKTYPE;
+       }
+
+       if (str_isnumber(servname)) {
+               if (!allownumeric)
+                       return EAI_SERVICE;
+               port = htons(atoi(servname));
+               if (port < 0 || port > 65535)
+                       return EAI_SERVICE;
+       } else {
+               switch (ai->ai_socktype) {
+               case SOCK_DGRAM:
+                       proto = "udp";
+                       break;
+               case SOCK_STREAM:
+                       proto = "tcp";
+                       break;
+               default:
+                       proto = NULL;
+                       break;
+               }
+
+               if ((sp = getservbyname(servname, proto)) == NULL)
+                       return EAI_SERVICE;
+               port = sp->s_port;
+       }
+
+       if (!matchonly) {
+               switch (ai->ai_family) {
+               case AF_INET:
+                       ((struct sockaddr_in *)(void *)
+                           ai->ai_addr)->sin_port = port;
+                       break;
+#ifdef INET6
+               case AF_INET6:
+                       ((struct sockaddr_in6 *)(void *)
+                           ai->ai_addr)->sin6_port = port;
+                       break;
+#endif
+               }
+       }
+
+       return 0;
+}
+
+static const struct afd *
+find_afd(af)
+       int af;
+{
+       const struct afd *afd;
+
+       if (af == PF_UNSPEC)
+               return NULL;
+       for (afd = afdl; afd->a_af; afd++) {
+               if (afd->a_af == af)
+                       return afd;
+       }
+       return NULL;
+}
+
+/*
+ * post-2553: AI_ADDRCONFIG check.  if we use getipnodeby* as backend, backend
+ * will take care of it.
+ * the semantics of AI_ADDRCONFIG is not defined well.  we are not sure
+ * if the code is right or not.
+ */
+static int
+addrconfig(af)
+       int af;
+{
+       int s;
+
+       /* XXX errno */
+       s = socket(af, SOCK_DGRAM, 0);
+       if (s < 0) {
+               if (errno != EMFILE)
+                       return 0;
+       } else
+               close(s);
+       return 1;
+}
+
+#ifdef INET6
+/* convert a string to a scope identifier. XXX: IPv6 specific */
+static int
+ip6_str2scopeid(scope, sin6)
+       char *scope;
+       struct sockaddr_in6 *sin6;
+{
+       int scopeid;
+       struct in6_addr *a6 = &sin6->sin6_addr;
+       char *ep;
+
+       /* empty scopeid portion is invalid */
+       if (*scope == '\0')
+               return -1;
+
+       if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) {
+               /*
+                * We currently assume a one-to-one mapping between links
+                * and interfaces, so we simply use interface indices for
+                * like-local scopes.
+                */
+               scopeid = if_nametoindex(scope);
+               if (scopeid == 0)
+                       goto trynumeric;
+               return(scopeid);
+       }
+
+       /* still unclear about literal, allow numeric only - placeholder */
+       if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6))
+               goto trynumeric;
+       if (IN6_IS_ADDR_MC_ORGLOCAL(a6))
+               goto trynumeric;
+       else
+               goto trynumeric;        /* global */
+
+       /* try to convert to a numeric id as a last resort */
+trynumeric:
+       scopeid = (int)strtoul(scope, &ep, 10);
+       if (*ep == '\0')
+               return scopeid;
+       else
+               return -1;
+}
+#endif
+
+struct addrinfo *
+hostent2addrinfo(hp, pai)
+       struct hostent *hp;
+       const struct addrinfo *pai;
+{
+       int i, af, error = 0;
+       char **aplist = NULL, *ap;
+       struct addrinfo sentinel, *cur;
+       const struct afd *afd;
+
+       af = hp->h_addrtype;
+       if (pai->ai_family != AF_UNSPEC && af != pai->ai_family)
+               return(NULL);
+
+       afd = find_afd(af);
+       if (afd == NULL)
+               return(NULL);
+
+       aplist = hp->h_addr_list;
+
+       memset(&sentinel, 0, sizeof(sentinel));
+       cur = &sentinel;
+
+       for (i = 0; (ap = aplist[i]) != NULL; i++) {
+#if 0                          /* the trick seems too much */
+#ifdef INET6
+               af = hp->h_addr_list;
+               if (af == AF_INET6 &&
+                   IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
+                       af = AF_INET;
+                       ap = ap + sizeof(struct in6_addr)
+                               - sizeof(struct in_addr);
+               }
+               afd = find_afd(af);
+               if (afd == NULL)
+                       continue;
+#endif
+#endif /* 0 */
+
+               GET_AI(cur->ai_next, afd, ap);
+
+               /* GET_PORT(cur->ai_next, servname); */
+               if ((pai->ai_flags & AI_CANONNAME) != 0) {
+                       /*
+                        * RFC2553 says that ai_canonname will be set only for
+                        * the first element.  we do it for all the elements,
+                        * just for convenience.
+                        */
+                       GET_CANONNAME(cur->ai_next, hp->h_name);
+               }
+               while (cur && cur->ai_next) /* no need to loop, actually. */
+                       cur = cur->ai_next;
+               continue;
+
+       free:
+               if (cur->ai_next)
+                       freeaddrinfo(cur->ai_next);
+               cur->ai_next = NULL;
+               /* continue, without tht pointer CUR advanced. */
+       }
+
+       return(sentinel.ai_next);
+}
+
+struct addrinfo *
+addr2addrinfo(pai, cp)
+       const struct addrinfo *pai;
+       const char *cp;
+{
+       const struct afd *afd;
+
+       afd = find_afd(pai->ai_family);
+       if (afd == NULL)
+               return(NULL);
+
+       return(get_ai(pai, afd, cp));
+}
+
+static struct net_data *
+init()
+{
+       struct net_data *net_data;
+
+       if (!(net_data = net_data_init(NULL)))
+               goto error;
+       if (!net_data->ho) {
+               net_data->ho = (*net_data->irs->ho_map)(net_data->irs);
+               if (!net_data->ho || !net_data->res) {
+error:
+                       errno = EIO;
+                       if (net_data && net_data->res)
+                               RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL);
+                       return (NULL);
+               }
+
+               (*net_data->ho->res_set)(net_data->ho, net_data->res, NULL);
+       }
+
+       return (net_data);
+}
diff --git a/lib/bind/irs/getgrent.c b/lib/bind/irs/getgrent.c
new file mode 100644 (file)
index 0000000..1b10e33
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * 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(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: getgrent.c,v 1.1 2001/03/29 06:31:45 marka Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#if !defined(WANT_IRS_GR) || defined(__BIND_NOSTATIC)
+static int __bind_irs_gr_unneeded;
+#else
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <grp.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_data.h"
+
+/* Forward */
+
+static struct net_data *init(void);
+void                   endgrent(void);
+
+/* Public */
+
+struct group *
+getgrent() {
+       struct net_data *net_data = init();
+
+       return (getgrent_p(net_data));
+}
+
+struct group *
+getgrnam(const char *name) {
+       struct net_data *net_data = init();
+
+       return (getgrnam_p(name, net_data));
+}
+
+struct group *
+getgrgid(gid_t gid) {
+       struct net_data *net_data = init();
+
+       return (getgrgid_p(gid, net_data));
+}
+
+int
+setgroupent(int stayopen) {
+       struct net_data *net_data = init();
+
+       return (setgroupent_p(stayopen, net_data));
+}
+
+#ifdef SETGRENT_VOID
+void
+setgrent() {
+       struct net_data *net_data = init();
+
+       return (setgrent_p(net_data));
+}
+#else
+int
+setgrent() {
+       struct net_data *net_data = init();
+
+       return (setgrent_p(net_data));
+}
+#endif /* SETGRENT_VOID */
+
+void
+endgrent() {
+       struct net_data *net_data = init();
+
+       endgrent_p(net_data);
+}
+
+int
+getgrouplist(GETGROUPLIST_ARGS) {
+       struct net_data *net_data = init();
+
+       return (getgrouplist_p(name, basegid, groups, ngroups, net_data));
+}
+
+/* Shared private. */
+
+struct group *
+getgrent_p(struct net_data *net_data) {
+       struct irs_gr *gr;
+
+       if (!net_data || !(gr = net_data->gr))
+               return (NULL);
+       net_data->gr_last = (*gr->next)(gr);
+       return (net_data->gr_last);
+}
+
+struct group *
+getgrnam_p(const char *name, struct net_data *net_data) {
+       struct irs_gr *gr;
+
+       if (!net_data || !(gr = net_data->gr))
+               return (NULL);
+       if (net_data->gr_stayopen && net_data->gr_last &&
+           !strcmp(net_data->gr_last->gr_name, name))
+               return (net_data->gr_last);
+       net_data->gr_last = (*gr->byname)(gr, name);
+       if (!net_data->gr_stayopen)
+               endgrent();
+       return (net_data->gr_last);
+}
+
+struct group *
+getgrgid_p(gid_t gid, struct net_data *net_data) {
+       struct irs_gr *gr;
+
+       if (!net_data || !(gr = net_data->gr))
+               return (NULL);
+       if (net_data->gr_stayopen && net_data->gr_last &&
+           (gid_t)net_data->gr_last->gr_gid == gid)
+               return (net_data->gr_last);
+       net_data->gr_last = (*gr->bygid)(gr, gid);
+       if (!net_data->gr_stayopen)
+               endgrent();
+       return (net_data->gr_last);
+}
+
+int
+setgroupent_p(int stayopen, struct net_data *net_data) {
+       struct irs_gr *gr;
+
+       if (!net_data || !(gr = net_data->gr))
+               return (0);
+       (*gr->rewind)(gr);
+       net_data->gr_stayopen = (stayopen != 0);
+       if (stayopen == 0)
+               net_data_minimize(net_data);
+       return (1);
+}
+
+#ifdef SETGRENT_VOID
+void
+setgrent_p(struct net_data *net_data) {
+       (void)setgroupent_p(0, net_data);
+}
+#else
+int
+setgrent_p(struct net_data *net_data) {
+       return (setgroupent_p(0, net_data));
+}
+#endif /* SETGRENT_VOID */
+
+void
+endgrent_p(struct net_data *net_data) {
+       struct irs_gr *gr;
+
+       if ((net_data != NULL) && ((gr = net_data->gr) != NULL))
+               (*gr->minimize)(gr);
+}
+
+int
+getgrouplist_p(const char *name, gid_t basegid, gid_t *groups, int *ngroups,
+              struct net_data *net_data) {
+       struct irs_gr *gr;
+
+       if (!net_data || !(gr = net_data->gr)) {
+               *ngroups = 0;
+               return (-1);
+       }
+       return ((*gr->list)(gr, name, basegid, groups, ngroups));
+}
+
+/* Private */
+
+static struct net_data *
+init() {
+       struct net_data *net_data;
+
+       if (!(net_data = net_data_init(NULL)))
+               goto error;
+       if (!net_data->gr) {
+               net_data->gr = (*net_data->irs->gr_map)(net_data->irs);
+
+               if (!net_data->gr || !net_data->res) {
+ error: 
+                       errno = EIO;
+                       return (NULL);
+               }
+               (*net_data->gr->res_set)(net_data->gr, net_data->res,
+                                        NULL);
+       }
+       
+       return (net_data);
+}
+
+#endif /* WANT_IRS_GR */
diff --git a/lib/bind/irs/getgrent_r.c b/lib/bind/irs/getgrent_r.c
new file mode 100644 (file)
index 0000000..0db7f22
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 1998-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 rcsid[] = "$Id: getgrent_r.c,v 1.1 2001/03/29 06:31:45 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <port_before.h>
+#if !defined(_REENTRANT) || !defined(DO_PTHREADS) || !defined(WANT_IRS_PW)
+       static int getgrent_r_not_required = 0;
+#else
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <grp.h>
+#include <sys/param.h>
+#include <port_after.h>
+
+#ifdef GROUP_R_RETURN
+
+static int
+copy_group(struct group *, struct group *, char *buf, int buflen);
+
+/* POSIX 1003.1c */
+#ifdef POSIX_GETGRNAM_R
+int
+__posix_getgrnam_r(const char *name,  struct group *gptr,
+               char *buf, int buflen, struct group **result) {
+#else
+int
+getgrnam_r(const char *name,  struct group *gptr,
+               char *buf, size_t buflen, struct group **result) {
+#endif
+       struct group *ge = getgrnam(name);
+       int res;
+
+       if (ge == NULL) {
+               *result = NULL;
+               return (-1);
+       }
+
+       res = copy_group(ge, gptr, buf, buflen);
+       *result = res ? NULL : gptr;
+       return (res);
+}
+
+#ifdef POSIX_GETGRNAM_R
+struct group *
+getgrnam_r(const char *name,  struct group *gptr,
+               char *buf, int buflen) {
+       struct group *ge = getgrnam(name);
+       int res;
+
+       if (ge == NULL)
+               return (NULL);
+       res = copy_group(ge, gptr, buf, buflen);
+       return (res ? NULL : gptr);
+}
+#endif /* POSIX_GETGRNAM_R */
+
+/* POSIX 1003.1c */
+#ifdef POSIX_GETGRGID_R
+int
+__posix_getgrgid_r(const gid_t gid, struct group *gptr,
+               char *buf, int buflen, struct group **result) {
+#else /* POSIX_GETGRGID_R */
+int
+getgrgid_r(const gid_t gid, struct group *gptr,
+               char *buf, size_t buflen, struct group **result) {
+#endif /* POSIX_GETGRGID_R */
+       struct group *ge = getgrgid(gid);
+       int res;
+
+       if (ge == NULL) {
+               *result = NULL;
+               return (-1);
+       }
+
+       res = copy_group(ge, gptr, buf, buflen);
+       *result = res ? NULL : gptr;
+       return (res);
+}
+
+#ifdef POSIX_GETGRGID_R
+struct group *
+getgrgid_r(const gid_t gid, struct group *gptr,
+               char *buf, int buflen) {
+       struct group *ge = getgrgid(gid);
+       int res;
+
+       if (ge == NULL)
+               return (NULL);
+
+       res = copy_group(ge, gptr, buf, buflen);
+       return (res ? NULL : gptr);
+}
+#endif
+
+/*
+ *     These assume a single context is in operation per thread.
+ *     If this is not the case we will need to call irs directly
+ *     rather than through the base functions.
+ */
+
+GROUP_R_RETURN
+getgrent_r(struct group *gptr, GROUP_R_ARGS) {
+       struct group *ge = getgrent();
+       int res;
+
+       if (ge == NULL) {
+               return (GROUP_R_BAD);
+       }
+
+       res = copy_group(ge, gptr, buf, buflen);
+       return (res ? GROUP_R_BAD : GROUP_R_OK);
+}
+
+GROUP_R_SET_RETURN
+setgrent_r(GROUP_R_ENT_ARGS) {
+
+       setgrent();
+#ifdef GROUP_R_SET_RESULT
+       return (GROUP_R_SET_RESULT);
+#endif
+}
+
+GROUP_R_END_RETURN
+endgrent_r(GROUP_R_ENT_ARGS) {
+
+       endgrent();
+       GROUP_R_END_RESULT(GROUP_R_OK);
+}
+
+
+#if 0
+       /* XXX irs does not have a fgetgrent() */
+GROUP_R_RETURN
+fgetgrent_r(FILE *f, struct group *gptr, GROUP_R_ARGS) {
+       struct group *ge = fgetgrent(f);
+       int res;
+
+       if (ge == NULL)
+               return (GROUP_R_BAD);
+
+       res = copy_group(ge, gptr, buf, buflen);
+       return (res ? GROUP_R_BAD : GROUP_R_OK);
+}
+#endif
+
+/* Private */
+
+static int
+copy_group(struct group *ge, struct group *gptr, char *buf, int buflen) {
+       char *cp;
+       int i, n;
+       int numptr, len;
+
+       /* Find out the amount of space required to store the answer. */
+       numptr = 1; /* NULL ptr */
+       len = (char *)ALIGN(buf) - buf;
+       for (i = 0; ge->gr_mem[i]; i++, numptr++) {
+               len += strlen(ge->gr_mem[i]) + 1;
+       }
+       len += strlen(ge->gr_name) + 1;
+       len += strlen(ge->gr_passwd) + 1;
+       len += numptr * sizeof(char*);
+       
+       if (len > buflen) {
+               errno = ERANGE;
+               return (-1);
+       }
+
+       /* copy group id */
+       gptr->gr_gid = ge->gr_gid;
+
+       cp = (char *)ALIGN(buf) + numptr * sizeof(char *);
+
+       /* copy official name */
+       n = strlen(ge->gr_name) + 1;
+       strcpy(cp, ge->gr_name);
+       gptr->gr_name = cp;
+       cp += n;
+
+       /* copy member list */
+       gptr->gr_mem = (char **)ALIGN(buf);
+       for (i = 0 ; ge->gr_mem[i]; i++) {
+               n = strlen(ge->gr_mem[i]) + 1;
+               strcpy(cp, ge->gr_mem[i]);
+               gptr->gr_mem[i] = cp;
+               cp += n;
+       }
+       gptr->gr_mem[i] = NULL;
+
+       /* copy password */
+       n = strlen(ge->gr_passwd) + 1;
+       strcpy(cp, ge->gr_passwd);
+       gptr->gr_passwd = cp;
+       cp += n;
+
+       return (0);
+}
+#else /* GROUP_R_RETURN */
+       static int getgrent_r_unknown_system = 0;
+#endif /* GROUP_R_RETURN */
+#endif /* !def(_REENTRANT) || !def(DO_PTHREADS) || !def(WANT_IRS_PW) */
diff --git a/lib/bind/irs/gethostent.c b/lib/bind/irs/gethostent.c
new file mode 100644 (file)
index 0000000..a664a4b
--- /dev/null
@@ -0,0 +1,900 @@
+/*
+ * 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(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: gethostent.c,v 1.1 2001/03/29 06:31:45 marka Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#if !defined(__BIND_NOSTATIC)
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <irs.h>
+#include <isc/memcluster.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "irs_data.h"
+
+/* Definitions */
+
+struct pvt {
+       char *          aliases[1];
+       char *          addrs[2];
+       char            addr[NS_IN6ADDRSZ];
+       char            name[NS_MAXDNAME + 1];
+       struct hostent  host;
+};
+
+/* Forward */
+
+static struct net_data *init(void);
+static void            freepvt(struct net_data *);
+static struct hostent  *fakeaddr(const char *, int, struct net_data *);
+
+
+/* Public */
+
+struct hostent *
+gethostbyname(const char *name) {
+       struct net_data *net_data = init();
+
+       return (gethostbyname_p(name, net_data));
+}
+
+struct hostent *
+gethostbyname2(const char *name, int af) {
+       struct net_data *net_data = init();
+
+       return (gethostbyname2_p(name, af, net_data));
+}
+
+struct hostent *
+gethostbyaddr(const char *addr, int len, int af) {
+       struct net_data *net_data = init();
+
+       return (gethostbyaddr_p(addr, len, af, net_data));
+}
+
+struct hostent *
+gethostent() {
+       struct net_data *net_data = init();
+
+       return (gethostent_p(net_data));
+}
+
+void
+sethostent(int stayopen) {
+       struct net_data *net_data = init();
+       sethostent_p(stayopen, net_data);
+}
+
+
+void
+endhostent() {
+       struct net_data *net_data = init();
+       endhostent_p(net_data);
+}
+
+/* Shared private. */
+
+struct hostent *
+gethostbyname_p(const char *name, struct net_data *net_data) {
+       struct hostent *hp;
+
+       if (!net_data)
+               return (NULL);
+
+       if (net_data->res->options & RES_USE_INET6) {
+               hp = gethostbyname2_p(name, AF_INET6, net_data);
+               if (hp)
+                       return (hp);
+       }
+       return (gethostbyname2_p(name, AF_INET, net_data));
+}
+
+struct hostent *
+gethostbyname2_p(const char *name, int af, struct net_data *net_data) {
+       struct irs_ho *ho;
+       char tmp[NS_MAXDNAME];
+       struct hostent *hp;
+       const char *cp;
+       char **hap;
+
+       if (!net_data || !(ho = net_data->ho))
+               return (NULL);
+       if (net_data->ho_stayopen && net_data->ho_last &&
+           net_data->ho_last->h_addrtype == af) {
+               if (ns_samename(name, net_data->ho_last->h_name) == 1)
+                       return (net_data->ho_last);
+               for (hap = net_data->ho_last->h_aliases; hap && *hap; hap++)
+                       if (ns_samename(name, *hap) == 1)
+                               return (net_data->ho_last);
+       }
+       if (!strchr(name, '.') && (cp = res_hostalias(net_data->res, name,
+                                                     tmp, sizeof tmp)))
+               name = cp;
+       if ((hp = fakeaddr(name, af, net_data)) != NULL)
+               return (hp);
+       net_data->ho_last = (*ho->byname2)(ho, name, af);
+       if (!net_data->ho_stayopen)
+               endhostent();
+       return (net_data->ho_last);
+}
+
+struct hostent *
+gethostbyaddr_p(const char *addr, int len, int af, struct net_data *net_data) {
+       struct irs_ho *ho;
+       char **hap;
+
+       if (!net_data || !(ho = net_data->ho))
+               return (NULL);
+       if (net_data->ho_stayopen && net_data->ho_last &&
+           net_data->ho_last->h_length == len)
+               for (hap = net_data->ho_last->h_addr_list;
+                    hap && *hap;
+                    hap++)
+                       if (!memcmp(addr, *hap, len))
+                               return (net_data->ho_last);
+       net_data->ho_last = (*ho->byaddr)(ho, addr, len, af);
+       if (!net_data->ho_stayopen)
+               endhostent();
+       return (net_data->ho_last);
+}
+
+
+struct hostent *
+gethostent_p(struct net_data *net_data) {
+       struct irs_ho *ho;
+       struct hostent *hp;
+
+       if (!net_data || !(ho = net_data->ho))
+               return (NULL);
+       while ((hp = (*ho->next)(ho)) != NULL &&
+              hp->h_addrtype == AF_INET6 &&
+              (net_data->res->options & RES_USE_INET6) == 0)
+               continue;
+       net_data->ho_last = hp;
+       return (net_data->ho_last);
+}
+
+
+void
+sethostent_p(int stayopen, struct net_data *net_data) {
+       struct irs_ho *ho;
+
+       if (!net_data || !(ho = net_data->ho))
+               return;
+       freepvt(net_data);
+       (*ho->rewind)(ho);
+       net_data->ho_stayopen = (stayopen != 0);
+       if (stayopen == 0)
+               net_data_minimize(net_data);
+}
+
+void
+endhostent_p(struct net_data *net_data) {
+       struct irs_ho *ho;
+
+       if ((net_data != NULL) && ((ho = net_data->ho) != NULL))
+               (*ho->minimize)(ho);
+}
+
+#ifndef IN6_IS_ADDR_V4COMPAT
+static const unsigned char in6addr_compat[12] = {
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+#define IN6_IS_ADDR_V4COMPAT(x) (!memcmp((x)->s6_addr, in6addr_compat, 12) && \
+                                ((x)->s6_addr[12] != 0 || \
+                                 (x)->s6_addr[13] != 0 || \
+                                 (x)->s6_addr[14] != 0 || \
+                                  ((x)->s6_addr[15] != 0 && \
+                                   (x)->s6_addr[15] != 1)))
+#endif
+#ifndef IN6_IS_ADDR_V4MAPPED
+#define IN6_IS_ADDR_V4MAPPED(x) (!memcmp((x)->s6_addr, in6addr_mapped, 12))
+#endif
+
+static const unsigned char in6addr_mapped[12] = {
+       0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0xff, 0xff };
+
+static int scan_interfaces(int *, int *);
+static struct hostent *copyandmerge(struct hostent *, struct hostent *, int, int *);
+
+/*
+ *     Public functions
+ */
+
+/*
+ *     AI_V4MAPPED + AF_INET6
+ *     If no IPv6 address then a query for IPv4 and map returned values.
+ *
+ *     AI_ALL + AI_V4MAPPED + AF_INET6
+ *     Return IPv6 and IPv4 mapped.
+ *
+ *     AI_ADDRCONFIG
+ *     Only return IPv6 / IPv4 address if there is an interface of that
+ *     type active.
+ */
+
+struct hostent *
+getipnodebyname(const char *name, int af, int flags, int *error_num) {
+       int have_v4 = 1, have_v6 = 1;
+       struct in_addr in4;
+       struct in6_addr in6;
+       struct hostent he, *he1 = NULL, *he2 = NULL, *he3;
+       int v4 = 0, v6 = 0;
+       struct net_data *net_data = init();
+       u_long options;
+       int tmp_err;
+
+       if (net_data == NULL) {
+               *error_num = NO_RECOVERY;
+               return (NULL);
+       }
+
+       /* If we care about active interfaces then check. */
+       if ((flags & AI_ADDRCONFIG) != 0)
+               if (scan_interfaces(&have_v4, &have_v6) == -1) {
+                       *error_num = NO_RECOVERY;
+                       return (NULL);
+               }
+
+       /* Check for literal address. */
+       if ((v4 = inet_pton(AF_INET, name, &in4)) != 1)
+               v6 = inet_pton(AF_INET6, name, &in6);
+
+       /* Impossible combination? */
+        
+       if ((af == AF_INET6 && (flags & AI_V4MAPPED) == 0 && v4 == 1) ||
+           (af == AF_INET && v6 == 1) ||
+           (have_v4 == 0 && v4 == 1) ||
+           (have_v6 == 0 && v6 == 1) ||
+           (have_v4 == 0 && af == AF_INET) ||
+           (have_v6 == 0 && af == AF_INET6)) {
+               *error_num = HOST_NOT_FOUND;
+               return (NULL);
+       }
+
+       /* Literal address? */
+       if (v4 == 1 || v6 == 1) {
+               char *addr_list[2];
+               char *aliases[1];
+
+               DE_CONST(name, he.h_name);
+               he.h_addr_list = addr_list;
+               he.h_addr_list[0] = (v4 == 1) ? (char *)&in4 : (char *)&in6;
+               he.h_addr_list[1] = NULL;
+               he.h_aliases = aliases;
+               he.h_aliases[0] = NULL;
+               he.h_length = (v4 == 1) ? INADDRSZ : IN6ADDRSZ;
+               he.h_addrtype = (v4 == 1) ? AF_INET : AF_INET6;
+               return (copyandmerge(&he, NULL, af, error_num));
+       }
+
+       options = net_data->res->options;
+       net_data->res->options &= ~RES_USE_INET6;
+
+       tmp_err = NO_RECOVERY;
+       if (have_v6 && af == AF_INET6) {
+               he2 = gethostbyname2_p(name, AF_INET6, net_data);
+               if (he2 != NULL) {
+                       he1 = copyandmerge(he2, NULL, af, error_num);
+                       if (he1 == NULL)
+                               return (NULL);
+                       he2 = NULL;
+               } else {
+                       tmp_err = net_data->res->res_h_errno;
+               }
+       }
+
+       if (have_v4 &&
+           ((af == AF_INET) ||
+            (af == AF_INET6 && (flags & AI_V4MAPPED) != 0 &&
+             (he1 == NULL || (flags & AI_ALL) != 0)))) {
+               he2 = gethostbyname2_p(name, AF_INET, net_data);
+               if (he1 == NULL && he2 == NULL) {
+                       *error_num = net_data->res->res_h_errno;
+                       return (NULL);
+               } 
+       } else
+               *error_num = tmp_err;
+
+       net_data->res->options = options;
+
+       he3 = copyandmerge(he1, he2, af, error_num);
+
+       if (he1 != NULL)
+               freehostent(he1);
+       return (he3);
+}
+
+struct hostent *
+getipnodebyaddr(const void *src, size_t len, int af, int *error_num) {
+       struct hostent *he1, *he2;
+       struct net_data *net_data = init();
+
+       /* Sanity Checks. */
+       if (src == NULL) {
+               *error_num = NO_RECOVERY;
+               return (NULL);
+       }
+               
+       switch (af) {
+       case AF_INET:
+               if (len != INADDRSZ) {
+                       *error_num = NO_RECOVERY;
+                       return (NULL);
+               }
+               break;
+       case AF_INET6:
+               if (len != IN6ADDRSZ) {
+                       *error_num = NO_RECOVERY;
+                       return (NULL);
+               }
+               break;
+       default:
+               *error_num = NO_RECOVERY;
+               return (NULL);
+       }
+
+       /*
+        * Lookup IPv4 and IPv4 mapped/compatible addresses
+        */
+       if ((af == AF_INET6 &&
+            IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)src)) ||
+           (af == AF_INET6 &&
+            IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)src)) ||
+           (af == AF_INET)) {
+               const char *cp = src;
+
+               if (af == AF_INET6)
+                       cp += 12;
+               he1 = gethostbyaddr_p(cp, 4, AF_INET, net_data);
+               if (he1 == NULL) {
+                       *error_num = net_data->res->res_h_errno;
+                       return (NULL);
+               }
+               he2 = copyandmerge(he1, NULL, af, error_num);
+               if (he2 == NULL)
+                       return (NULL);
+               /*
+                * Restore original address if mapped/compatible.
+                */
+               if (af == AF_INET6)
+                       memcpy(he1->h_addr, src, len);
+               return (he2);
+       }
+
+       /*
+        * Lookup IPv6 address.
+        */
+       if (memcmp((const struct in6_addr *)src, &in6addr_any, 16) == 0) {
+               *error_num = HOST_NOT_FOUND;
+               return (NULL);
+       }
+
+       he1 = gethostbyaddr_p(src, 16, AF_INET6, net_data);
+       if (he1 == NULL) {
+               *error_num = net_data->res->res_h_errno;
+               return (NULL);
+       }
+       return (copyandmerge(he1, NULL, af, error_num));
+}
+
+void
+freehostent(struct hostent *he) {
+       char **cpp;
+       int names = 1;
+       int addresses = 1;
+
+       memput(he->h_name, strlen(he->h_name) + 1);
+
+       cpp = he->h_addr_list;
+       while (*cpp != NULL) {
+               memput(*cpp, (he->h_addrtype == AF_INET) ?
+                            INADDRSZ : IN6ADDRSZ);
+               *cpp = NULL;
+               cpp++;
+               addresses++;
+       }
+
+       cpp = he->h_aliases;
+       while (*cpp != NULL) {
+               memput(*cpp, strlen(*cpp) + 1);
+               cpp++;
+               names++;
+       }
+
+       memput(he->h_aliases, sizeof(char *) * (names));
+       memput(he->h_addr_list, sizeof(char *) * (addresses));
+       memput(he, sizeof *he);
+}
+
+/*
+ * Private
+ */
+
+/*
+ * Scan the interface table and set have_v4 and have_v6 depending
+ * upon whether there are IPv4 and IPv6 interface addresses.
+ *
+ * Returns:
+ *     0 on success
+ *     -1 on failure.
+ */
+
+static int
+scan_interfaces(int *have_v4, int *have_v6) {
+#ifndef SIOCGLIFCONF
+/* map new to old */
+#define SIOCGLIFCONF SIOCGIFCONF
+#define lifc_len ifc_len
+#define lifc_buf ifc_buf
+       struct ifconf lifc;
+#else
+#define SETFAMILYFLAGS
+       struct lifconf lifc;
+#endif
+
+#ifndef SIOCGLIFADDR
+/* map new to old */
+#define SIOCGLIFADDR SIOCGIFADDR
+#endif
+
+#ifndef SIOCGLIFFLAGS
+#define SIOCGLIFFLAGS SIOCGIFFLAGS
+#define lifr_addr ifr_addr
+#define lifr_name ifr_name
+#define lifr_flags ifr_flags
+#define ss_family sa_family
+       struct ifreq lifreq;
+#else
+       struct lifreq lifreq;
+#endif
+       struct in_addr in4;
+       struct in6_addr in6;
+       char *buf = NULL, *cp, *cplim;
+       static unsigned int bufsiz = 4095;
+       int s, cpsize, n;
+
+       /* Set to zero.  Used as loop terminators below. */
+       *have_v4 = *have_v6 = 0;
+
+       /* Get interface list from system. */
+       if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
+               goto err_ret;
+
+       /*
+        * Grow buffer until large enough to contain all interface
+        * descriptions.
+        */
+       for (;;) {
+               buf = memget(bufsiz);
+               if (buf == NULL)
+                       goto err_ret;
+#ifdef SETFAMILYFLAGS
+               lifc.lifc_family = AF_UNSPEC;
+               lifc.lifc_flags = 0;
+#endif
+               lifc.lifc_len = bufsiz;
+               lifc.lifc_buf = buf;
+#ifdef IRIX_EMUL_IOCTL_SIOCGIFCONF
+               /*
+                * This is a fix for IRIX OS in which the call to ioctl with
+                * the flag SIOCGIFCONF may not return an entry for all the
+                * interfaces like most flavors of Unix.
+                */
+               if (emul_ioctl(&lifc) >= 0)
+                       break;
+#else
+               if ((n = ioctl(s, SIOCGLIFCONF, (char *)&lifc)) != -1) {
+                       /*
+                        * Some OS's just return what will fit rather
+                        * than set EINVAL if the buffer is too small
+                        * to fit all the interfaces in.  If 
+                        * lifc.lifc_len is too near to the end of the
+                        * buffer we will grow it just in case and
+                        * retry.
+                        */
+                       if (lifc.lifc_len + 2 * sizeof(lifreq) < bufsiz)
+                               break;
+               }
+#endif
+               if ((n == -1) && errno != EINVAL)
+                       goto err_ret;
+
+               if (bufsiz > 1000000)
+                       goto err_ret;
+
+               memput(buf, bufsiz);
+               bufsiz += 4096;
+       }
+
+       /* Parse system's interface list. */
+       cplim = buf + lifc.lifc_len;    /* skip over if's with big ifr_addr's */
+       for (cp = buf;
+            (*have_v4 == 0 || *have_v6 == 0) && cp < cplim;
+            cp += cpsize) {
+               memcpy(&lifreq, cp, sizeof lifreq);
+#ifdef HAVE_SA_LEN
+#ifdef FIX_ZERO_SA_LEN
+               if (lifreq.lifr_addr.sa_len == 0)
+                       lifreq.lifr_addr.sa_len = 16;
+#endif
+#ifdef HAVE_MINIMUM_IFREQ
+               cpsize = sizeof lifreq;
+               if (lifreq.lifr_addr.sa_len > sizeof (struct sockaddr))
+                       cpsize += (int)lifreq.lifr_addr.sa_len -
+                               (int)(sizeof (struct sockaddr));
+#else
+               cpsize = sizeof lifreq.lifr_name + lifreq.lifr_addr.sa_len;
+#endif /* HAVE_MINIMUM_IFREQ */
+#elif defined SIOCGIFCONF_ADDR
+               cpsize = sizeof lifreq;
+#else
+               cpsize = sizeof lifreq.lifr_name;
+               /* XXX maybe this should be a hard error? */
+               if (ioctl(s, SIOCGLIFADDR, (char *)&lifreq) < 0)
+                       continue;
+#endif
+               switch (lifreq.lifr_addr.ss_family) {
+               case AF_INET:
+                       if (*have_v4 == 0) {
+                               memcpy(&in4,
+                                      &((struct sockaddr_in *)
+                                      &lifreq.lifr_addr)->sin_addr,
+                                      sizeof in4);
+                               if (in4.s_addr == INADDR_ANY)
+                                       break;
+                               n = ioctl(s, SIOCGLIFFLAGS, (char *)&lifreq);
+                               if (n < 0)
+                                       break;
+                               if ((lifreq.lifr_flags & IFF_UP) == 0)
+                                       break;
+                               *have_v4 = 1;
+                       } 
+                       break;
+               case AF_INET6:
+                       if (*have_v6 == 0) {
+                               memcpy(&in6,
+                                      &((struct sockaddr_in6 *)
+                                      &lifreq.lifr_addr)->sin6_addr, sizeof in6);
+                               if (memcmp(&in6, &in6addr_any, sizeof in6) == 0)
+                                       break;
+                               n = ioctl(s, SIOCGLIFFLAGS, (char *)&lifreq);
+                               if (n < 0)
+                                       break;
+                               if ((lifreq.lifr_flags & IFF_UP) == 0)
+                                       break;
+                               *have_v6 = 1;
+                       }
+                       break;
+               }
+       }
+       if (buf != NULL)
+               memput(buf, bufsiz);
+       close(s);
+       /* printf("scan interface -> 4=%d 6=%d\n", *have_v4, *have_v6); */
+       return (0);
+ err_ret:
+       if (buf != NULL)
+               memput(buf, bufsiz);
+       if (s != -1)
+               close(s);
+       /* printf("scan interface -> 4=%d 6=%d\n", *have_v4, *have_v6); */
+       return (-1);
+}
+
+static struct hostent *
+copyandmerge(struct hostent *he1, struct hostent *he2, int af, int *error_num) {
+       struct hostent *he = NULL;
+       int addresses = 1;      /* NULL terminator */
+       int names = 1;          /* NULL terminator */
+       int len = 0;
+       char **cpp, **npp;
+
+       /*
+        * Work out array sizes;
+        */
+       if (he1 != NULL) {
+               cpp = he1->h_addr_list;
+               while (*cpp != NULL) {
+                       addresses++;
+                       cpp++;
+               }
+               cpp = he1->h_aliases;
+               while (*cpp != NULL) {
+                       names++;
+                       cpp++;
+               }
+       }
+
+       if (he2 != NULL) {
+               cpp = he2->h_addr_list;
+               while (*cpp != NULL) {
+                       addresses++;
+                       cpp++;
+               }
+               if (he1 == NULL) {
+                       cpp = he2->h_aliases;
+                       while (*cpp != NULL) {
+                               names++;
+                               cpp++;
+                       }
+               }
+       }
+
+       if (addresses == 1) {
+               *error_num = NO_ADDRESS;
+               return (NULL);
+       }
+
+       he = memget(sizeof *he);
+       if (he == NULL)
+               goto no_recovery;
+
+       he->h_addr_list = memget(sizeof(char *) * (addresses));
+       if (he->h_addr_list == NULL)
+               goto cleanup0;
+       memset(he->h_addr_list, 0, sizeof(char *) * (addresses));
+
+       /* copy addresses */
+       npp = he->h_addr_list;
+       if (he1 != NULL) {
+               cpp = he1->h_addr_list;
+               while (*cpp != NULL) {
+                       *npp = memget((af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
+                       if (*npp == NULL)
+                               goto cleanup1;
+                       /* convert to mapped if required */
+                       if (af == AF_INET6 && he1->h_addrtype == AF_INET) {
+                               memcpy(*npp, in6addr_mapped,
+                                      sizeof in6addr_mapped);
+                               memcpy(*npp + sizeof in6addr_mapped, *cpp,
+                                      INADDRSZ);
+                       } else {
+                               memcpy(*npp, *cpp,
+                                      (af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
+                       }
+                       cpp++;
+                       npp++;
+               }
+       }
+
+       if (he2 != NULL) {
+               cpp = he2->h_addr_list;
+               while (*cpp != NULL) {
+                       *npp = memget((af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
+                       if (*npp == NULL)
+                               goto cleanup1;
+                       /* convert to mapped if required */
+                       if (af == AF_INET6 && he2->h_addrtype == AF_INET) {
+                               memcpy(*npp, in6addr_mapped,
+                                      sizeof in6addr_mapped);
+                               memcpy(*npp + sizeof in6addr_mapped, *cpp,
+                                      INADDRSZ);
+                       } else {
+                               memcpy(*npp, *cpp,
+                                      (af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
+                       }
+                       cpp++;
+                       npp++;
+               }
+       }
+
+       he->h_aliases = memget(sizeof(char *) * (names));
+       if (he->h_aliases == NULL)
+               goto cleanup1;
+       memset(he->h_aliases, 0, sizeof(char *) * (names));
+
+       /* copy aliases */
+       npp = he->h_aliases;
+       cpp = (he1 != NULL) ? he1->h_aliases : he2->h_aliases;
+       while (*cpp != NULL) {
+               len = strlen (*cpp) + 1;
+               *npp = memget(len);
+               if (*npp == NULL)
+                       goto cleanup2;
+               strcpy(*npp, *cpp);
+               npp++;
+               cpp++;
+       }
+
+       /* copy hostname */
+       he->h_name = memget(strlen((he1 != NULL) ?
+                           he1->h_name : he2->h_name) + 1);
+       if (he->h_name == NULL)
+               goto cleanup2;
+       strcpy(he->h_name, (he1 != NULL) ? he1->h_name : he2->h_name);
+
+       /* set address type and length */
+       he->h_addrtype = af;
+       he->h_length = (af == AF_INET) ? INADDRSZ : IN6ADDRSZ;
+       return(he);
+
+ cleanup2:
+       cpp = he->h_aliases;
+       while (*cpp != NULL) {
+               memput(*cpp, strlen(*cpp) + 1);
+               cpp++;
+       }
+       memput(he->h_aliases, sizeof(char *) * (names));
+
+ cleanup1:
+       cpp = he->h_addr_list;
+       while (*cpp != NULL) {
+               memput(*cpp, (af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
+               *cpp = NULL;
+               cpp++;
+       }
+       memput(he->h_addr_list, sizeof(char *) * (addresses));
+
+ cleanup0:
+       memput(he, sizeof *he);
+
+ no_recovery:
+       *error_num = NO_RECOVERY;
+       return (NULL);
+}
+
+static struct net_data *
+init() {
+       struct net_data *net_data;
+
+       if (!(net_data = net_data_init(NULL)))
+               goto error;
+       if (!net_data->ho) {
+               net_data->ho = (*net_data->irs->ho_map)(net_data->irs);
+               if (!net_data->ho || !net_data->res) {
+  error:
+                       errno = EIO;
+                       if (net_data && net_data->res)
+                               RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL);
+                       return (NULL);
+               }
+       
+               (*net_data->ho->res_set)(net_data->ho, net_data->res, NULL);
+       }
+       
+       return (net_data);
+}
+
+static void
+freepvt(struct net_data *net_data) {
+       if (net_data->ho_data) {
+               free(net_data->ho_data);
+               net_data->ho_data = NULL;
+       }
+}
+
+static struct hostent *
+fakeaddr(const char *name, int af, struct net_data *net_data) {
+       struct pvt *pvt;
+
+       freepvt(net_data);
+       net_data->ho_data = malloc(sizeof (struct pvt));
+       if (!net_data->ho_data) {
+               errno = ENOMEM;
+               RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL);
+               return (NULL);
+       }
+       pvt = net_data->ho_data;
+#ifndef __bsdi__
+       /*
+        * Unlike its forebear(inet_aton), our friendly inet_pton() is strict
+        * in its interpretation of its input, and it will only return "1" if
+        * the input string is a formally valid(and thus unambiguous with
+        * respect to host names) internet address specification for this AF.
+        *
+        * This means "telnet 0xdeadbeef" and "telnet 127.1" are dead now.
+        */
+       if (inet_pton(af, name, pvt->addr) != 1) {
+#else
+       /* BSDI XXX
+        * We put this back to inet_aton -- we really want the old behavior
+        * Long live 127.1...
+        */
+       if ((af != AF_INET ||
+           inet_aton(name, (struct in_addr *)pvt->addr) != 1) &&
+           inet_pton(af, name, pvt->addr) != 1) {
+#endif
+               RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND);
+               return (NULL);
+       }
+       strncpy(pvt->name, name, NS_MAXDNAME);
+       pvt->name[NS_MAXDNAME] = '\0';
+       if (af == AF_INET && (net_data->res->options & RES_USE_INET6) != 0) {
+               map_v4v6_address(pvt->addr, pvt->addr);
+               af = AF_INET6;
+       }
+       pvt->host.h_addrtype = af;
+       switch(af) {
+       case AF_INET:
+               pvt->host.h_length = NS_INADDRSZ;
+               break;
+       case AF_INET6:
+               pvt->host.h_length = NS_IN6ADDRSZ;
+               break;
+       default:
+               errno = EAFNOSUPPORT;
+               RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL);
+               return (NULL);
+       }
+       pvt->host.h_name = pvt->name;
+       pvt->host.h_aliases = pvt->aliases;
+       pvt->aliases[0] = NULL;
+       pvt->addrs[0] = (char *)pvt->addr;
+       pvt->addrs[1] = NULL;
+       pvt->host.h_addr_list = pvt->addrs;
+       RES_SET_H_ERRNO(net_data->res, NETDB_SUCCESS);
+       return (&pvt->host);
+}
+
+#ifdef grot    /* for future use in gethostbyaddr(), for "SUNSECURITY" */
+       struct hostent *rhp;
+       char **haddr;
+       u_long old_options;
+       char hname2[MAXDNAME+1];
+
+       if (af == AF_INET) {
+           /*
+            * turn off search as the name should be absolute,
+            * 'localhost' should be matched by defnames
+            */
+           strncpy(hname2, hp->h_name, MAXDNAME);
+           hname2[MAXDNAME] = '\0';
+           old_options = net_data->res->options;
+           net_data->res->options &= ~RES_DNSRCH;
+           net_data->res->options |= RES_DEFNAMES;
+           if (!(rhp = gethostbyname(hname2))) {
+               net_data->res->options = old_options;
+               RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND);
+               return (NULL);
+           }
+           net_data->res->options = old_options;
+           for (haddr = rhp->h_addr_list; *haddr; haddr++)
+               if (!memcmp(*haddr, addr, INADDRSZ))
+                       break;
+           if (!*haddr) {
+               RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND);
+               return (NULL);
+           }
+       }
+#endif /* grot */
+
+#endif /*__BIND_NOSTATIC*/
diff --git a/lib/bind/irs/gethostent_r.c b/lib/bind/irs/gethostent_r.c
new file mode 100644 (file)
index 0000000..fd174b4
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 1998-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 rcsid[] = "$Id: gethostent_r.c,v 1.1 2001/03/29 06:31:45 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <port_before.h>
+#if !defined(_REENTRANT) || !defined(DO_PTHREADS)
+       static int gethostent_r_not_required = 0;
+#else
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <sys/param.h>
+#include <port_after.h>
+
+#ifdef HOST_R_RETURN
+
+static HOST_R_RETURN 
+copy_hostent(struct hostent *, struct hostent *, HOST_R_COPY_ARGS);
+
+HOST_R_RETURN
+gethostbyname_r(const char *name,  struct hostent *hptr, HOST_R_ARGS) {
+       struct hostent *he = gethostbyname(name);
+
+       HOST_R_ERRNO;
+
+       if (he == NULL)
+               return (HOST_R_BAD);
+
+       return (copy_hostent(he, hptr, HOST_R_COPY));
+}
+
+HOST_R_RETURN
+gethostbyaddr_r(const char *addr, int len, int type,
+               struct hostent *hptr, HOST_R_ARGS) {
+       struct hostent *he = gethostbyaddr(addr, len, type);
+
+       HOST_R_ERRNO;
+
+       if (he == NULL)
+               return (HOST_R_BAD);
+
+       return (copy_hostent(he, hptr, HOST_R_COPY));
+}
+
+/*
+ *     These assume a single context is in operation per thread.
+ *     If this is not the case we will need to call irs directly
+ *     rather than through the base functions.
+ */
+
+HOST_R_RETURN
+gethostent_r(struct hostent *hptr, HOST_R_ARGS) {
+       struct hostent *he = gethostent();
+
+       HOST_R_ERRNO;
+
+       if (he == NULL)
+               return (HOST_R_BAD);
+
+       return (copy_hostent(he, hptr, HOST_R_COPY));
+}
+
+HOST_R_SET_RETURN
+#ifdef HOST_R_ENT_ARGS
+sethostent_r(int stay_open, HOST_R_ENT_ARGS)
+#else
+sethostent_r(int stay_open)
+#endif
+{
+       sethostent(stay_open);
+#ifdef HOST_R_SET_RESULT
+       return (HOST_R_SET_RESULT);
+#endif
+}
+
+HOST_R_END_RETURN
+#ifdef HOST_R_ENT_ARGS
+endhostent_r(HOST_R_ENT_ARGS)
+#else
+endhostent_r()
+#endif
+{
+       endhostent();
+       HOST_R_END_RESULT(HOST_R_OK);
+}
+
+/* Private */
+
+#ifndef HOSTENT_DATA
+static HOST_R_RETURN
+copy_hostent(struct hostent *he, struct hostent *hptr, HOST_R_COPY_ARGS) {
+       char *cp;
+       char **ptr;
+       int i, n;
+       int nptr, len;
+
+       /* Find out the amount of space required to store the answer. */
+       nptr = 2; /* NULL ptrs */
+       len = (char *)ALIGN(buf) - buf;
+       for (i = 0; he->h_addr_list[i]; i++, nptr++) {
+               len += he->h_length;
+       }
+       for (i = 0; he->h_aliases[i]; i++, nptr++) {
+               len += strlen(he->h_aliases[i]) + 1;
+       }
+       len += strlen(he->h_name) + 1;
+       len += nptr * sizeof(char*);
+       
+       if (len > buflen) {
+               errno = ERANGE;
+               return (HOST_R_BAD);
+       }
+
+       /* copy address size and type */
+       hptr->h_addrtype = he->h_addrtype;
+       n = hptr->h_length = he->h_length;
+
+       ptr = (char **)ALIGN(buf);
+       cp = (char *)ALIGN(buf) + nptr * sizeof(char *);
+
+       /* copy address list */
+       hptr->h_addr_list = ptr;
+       for (i = 0; he->h_addr_list[i]; i++ , ptr++) {
+               memcpy(cp, he->h_addr_list[i], n);
+               hptr->h_addr_list[i] = cp;
+               cp += n;
+       }
+       hptr->h_addr_list[i] = NULL;
+       ptr++;
+
+       /* copy official name */
+       n = strlen(he->h_name) + 1;
+       strcpy(cp, he->h_name);
+       hptr->h_name = cp;
+       cp += n;
+
+       /* copy aliases */
+       hptr->h_aliases = ptr;
+       for (i = 0 ; he->h_aliases[i]; i++) {
+               n = strlen(he->h_aliases[i]) + 1;
+               strcpy(cp, he->h_aliases[i]);
+               hptr->h_aliases[i] = cp;
+               cp += n;
+       }
+       hptr->h_aliases[i] = NULL;
+
+       return (HOST_R_OK);
+}
+#else /* !HOSTENT_DATA */
+static int
+copy_hostent(struct hostent *he, struct hostent *hptr, HOST_R_COPY_ARGS) {
+       char *cp, *eob;
+       int i, n;
+
+       /* copy address size and type */
+       hptr->h_addrtype = he->h_addrtype;
+       n = hptr->h_length = he->h_length;
+
+       /* copy up to first 35 addresses */
+       i = 0;
+       cp = hdptr->hostaddr;
+       eob = hdptr->hostaddr + sizeof(hdptr->hostaddr);
+       hptr->h_addr_list = hdptr->h_addr_ptrs;
+       while (he->h_addr_list[i] && i < (_MAXADDRS)) {
+               if (n < (eob - cp)) {
+                       memcpy(cp, he->h_addr_list[i], n);
+                       hptr->h_addr_list[i] = cp;
+                       cp += n;
+               } else {
+                       break;
+               }
+               i++;
+       }
+       hptr->h_addr_list[i] = NULL;
+
+       /* copy official name */
+       cp = hdptr->hostbuf;
+       eob = hdptr->hostbuf + sizeof(hdptr->hostbuf);
+       if ((n = strlen(he->h_name) + 1) < (eob - cp)) {
+               strcpy(cp, he->h_name);
+               hptr->h_name = cp;
+               cp += n;
+       } else {
+               return (-1);
+       }
+
+       /* copy aliases */
+       i = 0;
+       hptr->h_aliases = hdptr->host_aliases;
+       while (he->h_aliases[i] && i < (_MAXALIASES-1)) {
+               if ((n = strlen(he->h_aliases[i]) + 1) < (eob - cp)) {
+                       strcpy(cp, he->h_aliases[i]);
+                       hptr->h_aliases[i] = cp;
+                       cp += n;
+               } else {
+                       break;
+               }
+               i++;
+       }
+       hptr->h_aliases[i] = NULL;
+
+       return (HOST_R_OK);
+}
+#endif /* !HOSTENT_DATA */
+#else /* HOST_R_RETURN */
+       static int gethostent_r_unknown_systemm = 0;
+#endif /* HOST_R_RETURN */
+#endif /* !defined(_REENTRANT) || !defined(DO_PTHREADS) */
diff --git a/lib/bind/irs/getnameinfo.c b/lib/bind/irs/getnameinfo.c
new file mode 100644 (file)
index 0000000..44756db
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * Issues to be discussed:
+ * - Thread safe-ness must be checked
+ * - Return values.  There seems to be no standard for return value (RFC2133)
+ *   but INRIA implementation returns EAI_xxx defined for getaddrinfo().
+ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * 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 WIDE Project and
+ *    its contributors.
+ * 4. Neither the name of the project 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 PROJECT 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 PROJECT 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.
+ */
+
+#include <port_before.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <netdb.h>
+#include <resolv.h>
+#include <string.h>
+
+#include <port_after.h>
+
+#define SUCCESS 0
+#define ANY 0
+#define YES 1
+#define NO  0
+
+/*
+ * Note that a_off will be dynamically adjusted so that to be consistent
+ * with the definition of sockaddr_in{,6}.
+ * The value presented below is just a guess.
+ */
+static struct afd {
+       int a_af;
+       int a_addrlen;
+       size_t a_socklen;
+       int a_off;
+} afdl [] = {
+       /* first entry is linked last... */
+       {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in),
+               4 /*XXX*/},
+       {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6),
+               8 /*XXX*/},
+       {0, 0, 0, 0},
+};
+
+struct sockinet {
+       u_char  si_len;
+       u_char  si_family;
+       u_short si_port;
+};
+
+#define ENI_NOSOCKET   0
+#define ENI_NOSERVNAME 1
+#define ENI_NOHOSTNAME 2
+#define ENI_MEMORY     3
+#define ENI_SYSTEM     4
+#define ENI_FAMILY     5
+#define ENI_SALEN      6
+
+int
+getnameinfo(sa, salen, host, hostlen, serv, servlen, flags)
+       const struct sockaddr *sa;
+       size_t salen;
+       char *host;
+       size_t hostlen;
+       char *serv;
+       size_t servlen;
+       int flags;
+{
+       struct afd *afd;
+       struct servent *sp;
+       struct hostent *hp;
+       u_short port;
+#ifdef HAVE_SA_LEN
+       size_t len;
+#endif
+       int family, i;
+       const char *addr;
+       char *p;
+       u_char pfx;
+       static int firsttime = 1;
+       static char numserv[512];
+       static char numaddr[512];
+
+
+       /* dynamically adjust a_off */
+       if (firsttime) {
+               struct afd *p;
+               u_char *q;
+               struct sockaddr_in sin;
+               struct sockaddr_in6 sin6;
+
+               for (p = &afdl[0]; p->a_af; p++) {
+                       switch (p->a_af) {
+                       case PF_INET:
+                               q = (u_char *)&sin.sin_addr.s_addr;
+                               p->a_off = q - (u_char *)&sin;
+                               break;
+                       case PF_INET6:
+                               q = (u_char *)&sin6.sin6_addr.s6_addr;
+                               p->a_off = q - (u_char *)&sin6;
+                               break;
+                       default:
+                               break;
+                       }
+               }
+               firsttime = 0;
+       }
+
+       if (sa == NULL)
+               return ENI_NOSOCKET;
+
+#ifdef HAVE_SA_LEN
+       len = sa->sa_len;
+       if (len != salen) return ENI_SALEN;
+#endif
+       
+       family = sa->sa_family;
+       for (i = 0; afdl[i].a_af; i++)
+               if (afdl[i].a_af == family) {
+                       afd = &afdl[i];
+                       goto found;
+               }
+       return ENI_FAMILY;
+       
+ found:
+       if (salen != afd->a_socklen) return ENI_SALEN;
+       
+       port = ((const struct sockinet *)sa)->si_port; /* network byte order */
+       addr = (const char *)sa + afd->a_off;
+
+       if (serv == NULL || servlen == 0) {
+               /* what we should do? */
+       } else if (flags & NI_NUMERICSERV) {
+               snprintf(numserv, sizeof(numserv), "%d", ntohs(port));
+               if (strlen(numserv) > servlen)
+                       return ENI_MEMORY;
+               strcpy(serv, numserv);
+       } else {
+               sp = getservbyport(port, (flags & NI_DGRAM) ? "udp" : "tcp");
+               if (sp) {
+                       if (strlen(sp->s_name) + 1 > servlen)
+                               return ENI_MEMORY;
+                       strcpy(serv, sp->s_name);
+               } else
+                       return ENI_NOSERVNAME;
+       }
+
+       switch (sa->sa_family) {
+       case AF_INET:
+               if (ntohl(*(const u_long *)addr) >> IN_CLASSA_NSHIFT == 0)
+                       flags |= NI_NUMERICHOST;                        
+               break;
+       case AF_INET6:
+               pfx = *addr;
+               if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
+                       flags |= NI_NUMERICHOST;
+               break;
+       }
+       if (host == NULL || hostlen == 0) {
+               /* what should we do? */
+       } else if (flags & NI_NUMERICHOST) {
+               if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
+                   == NULL)
+                       return ENI_SYSTEM;
+               if (strlen(numaddr) + 1 > hostlen)
+                       return ENI_MEMORY;
+               strcpy(host, numaddr);
+       } else {
+               hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af);
+
+               if (hp) {
+                       if (flags & NI_NOFQDN) {
+                               p = strchr(hp->h_name, '.');
+                               if (p) *p = '\0';
+                       }
+                       if (strlen(hp->h_name) + 1 > hostlen)
+                               return ENI_MEMORY;
+                       strcpy(host, hp->h_name);
+               } else {
+                       if (flags & NI_NAMEREQD)
+                               return ENI_NOHOSTNAME;
+                       if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
+                           == NULL)
+                               return ENI_NOHOSTNAME;
+                       if (strlen(numaddr) + 1 > hostlen)
+                               return ENI_MEMORY;
+                       strcpy(host, numaddr);
+               }
+       }
+       return SUCCESS;
+}
diff --git a/lib/bind/irs/getnetent.c b/lib/bind/irs/getnetent.c
new file mode 100644 (file)
index 0000000..b71f9b2
--- /dev/null
@@ -0,0 +1,342 @@
+/*
+ * 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(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: getnetent.c,v 1.1 2001/03/29 06:31:46 marka Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#if !defined(__BIND_NOSTATIC)
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "irs_data.h"
+
+/* Definitions */
+
+struct pvt {
+       struct netent   netent;
+       char *          aliases[1];
+       char            name[MAXDNAME + 1];
+};
+
+/* Forward */
+
+static struct net_data *init(void);
+static struct netent   *nw_to_net(struct nwent *, struct net_data *);
+static void            freepvt(struct net_data *);
+static struct netent   *fakeaddr(const char *, int af, struct net_data *);
+
+/* Portability */
+
+#ifndef INADDR_NONE
+# define INADDR_NONE 0xffffffff
+#endif
+
+/* Public */
+
+struct netent *
+getnetent() {
+       struct net_data *net_data = init();
+
+       return (getnetent_p(net_data));
+}
+
+struct netent *
+getnetbyname(const char *name) {
+       struct net_data *net_data = init();
+
+       return (getnetbyname_p(name, net_data));
+}
+
+struct netent *
+getnetbyaddr(unsigned long net, int type) {
+       struct net_data *net_data = init();
+
+       return (getnetbyaddr_p(net, type, net_data));
+}
+
+void
+setnetent(int stayopen) {
+       struct net_data *net_data = init();
+
+       setnetent_p(stayopen, net_data);
+}
+
+
+void
+endnetent() {
+       struct net_data *net_data = init();
+
+       endnetent_p(net_data);
+}
+
+/* Shared private. */
+
+struct netent *
+getnetent_p(struct net_data *net_data) {
+       struct irs_nw *nw;
+
+       if (!net_data || !(nw = net_data->nw))
+               return (NULL);
+       net_data->nww_last = (*nw->next)(nw);
+       net_data->nw_last = nw_to_net(net_data->nww_last, net_data);
+       return (net_data->nw_last);
+}
+
+struct netent *
+getnetbyname_p(const char *name, struct net_data *net_data) {
+       struct irs_nw *nw;
+       struct netent *np;
+       char **nap;
+
+       if (!net_data || !(nw = net_data->nw))
+               return (NULL);
+       if (net_data->nw_stayopen && net_data->nw_last) {
+               if (!strcmp(net_data->nw_last->n_name, name))
+                       return (net_data->nw_last);
+               for (nap = net_data->nw_last->n_aliases; nap && *nap; nap++)
+                       if (!strcmp(name, *nap))
+                               return (net_data->nw_last);
+       }
+       if ((np = fakeaddr(name, AF_INET, net_data)) != NULL)
+               return (np);
+       net_data->nww_last = (*nw->byname)(nw, name, AF_INET);
+       net_data->nw_last = nw_to_net(net_data->nww_last, net_data);
+       if (!net_data->nw_stayopen)
+               endnetent();
+       return (net_data->nw_last);
+}
+
+struct netent *
+getnetbyaddr_p(unsigned long net, int type, struct net_data *net_data) {
+       struct irs_nw *nw;
+       u_char addr[4];
+       int bits;
+
+       if (!net_data || !(nw = net_data->nw))
+               return (NULL);
+       if (net_data->nw_stayopen && net_data->nw_last)
+               if (type == net_data->nw_last->n_addrtype &&
+                   net == net_data->nw_last->n_net)
+                       return (net_data->nw_last);
+
+       /* cannonize net(host order) */
+       if (net < 256) {
+               net <<= 24;
+               bits = 8;
+       } else if (net < 65536) {
+               net <<= 16;
+               bits = 16;
+       } else if (net < 16777216) {
+               net <<= 8;
+               bits = 24;
+       } else
+               bits = 32;
+
+       /* convert to net order */
+       addr[0] = (0xFF000000 & net) >> 24;
+       addr[1] = (0x00FF0000 & net) >> 16;
+       addr[2] = (0x0000FF00 & net) >> 8;
+       addr[3] = (0x000000FF & net);
+
+       /* reduce bits to as close to natural number as possible */
+       if ((bits == 32) && (addr[0] < 224) && (addr[3] == 0)) {
+               if ((addr[0] < 192) && (addr[2] == 0)) {
+                       if ((addr[0] < 128) && (addr[1] == 0))
+                               bits = 8;
+                       else
+                               bits = 16;
+               } else {
+                       bits = 24;
+               }
+       }
+
+       net_data->nww_last = (*nw->byaddr)(nw, addr, bits, AF_INET);
+       net_data->nw_last = nw_to_net(net_data->nww_last, net_data);
+       if (!net_data->nw_stayopen)
+               endnetent();
+       return (net_data->nw_last);
+}
+
+
+
+
+void
+setnetent_p(int stayopen, struct net_data *net_data) {
+       struct irs_nw *nw;
+
+       if (!net_data || !(nw = net_data->nw))
+               return;
+       freepvt(net_data);
+       (*nw->rewind)(nw);
+       net_data->nw_stayopen = (stayopen != 0);
+       if (stayopen == 0)
+               net_data_minimize(net_data);
+}
+
+void
+endnetent_p(struct net_data *net_data) {
+       struct irs_nw *nw;
+
+       if ((net_data != NULL) && ((nw  = net_data->nw) != NULL))
+               (*nw->minimize)(nw);
+}
+
+/* Private */
+
+static struct net_data *
+init() {
+       struct net_data *net_data;
+
+       if (!(net_data = net_data_init(NULL)))
+               goto error;
+       if (!net_data->nw) {
+               net_data->nw = (*net_data->irs->nw_map)(net_data->irs);
+
+               if (!net_data->nw || !net_data->res) {
+ error:                
+                       errno = EIO;
+                       return (NULL);
+               }
+               (*net_data->nw->res_set)(net_data->nw, net_data->res, NULL);
+       }
+       
+       return (net_data);
+}
+
+static void
+freepvt(struct net_data *net_data) {
+       if (net_data->nw_data) {
+               free(net_data->nw_data);
+               net_data->nw_data = NULL;
+       }
+}
+
+static struct netent *
+fakeaddr(const char *name, int af, struct net_data *net_data) {
+       struct pvt *pvt;
+       const char *cp;
+       u_long tmp;
+
+       if (af != AF_INET) {
+               /* XXX should support IPv6 some day */
+               errno = EAFNOSUPPORT;
+               RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL);
+               return (NULL);
+       }
+       if (!isascii(name[0]) || !isdigit(name[0]))
+               return (NULL);
+       for (cp = name; *cp; ++cp)
+               if (!isascii(*cp) || (!isdigit(*cp) && *cp != '.'))
+                       return (NULL);
+       if (*--cp == '.')
+               return (NULL);
+
+       /* All-numeric, no dot at the end. */
+
+       tmp = inet_network(name);
+       if (tmp == INADDR_NONE) {
+               RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND);
+               return (NULL);
+       }
+
+       /* Valid network number specified.
+        * Fake up a netent as if we'd actually
+        * done a lookup.
+        */
+       freepvt(net_data);
+       net_data->nw_data = malloc(sizeof (struct pvt));
+       if (!net_data->nw_data) {
+               errno = ENOMEM;
+               RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL);
+               return (NULL);
+       }
+       pvt = net_data->nw_data;
+
+       strncpy(pvt->name, name, MAXDNAME);
+       pvt->name[MAXDNAME] = '\0';
+       pvt->netent.n_name = pvt->name;
+       pvt->netent.n_addrtype = AF_INET;
+       pvt->netent.n_aliases = pvt->aliases;
+       pvt->aliases[0] = NULL;
+       pvt->netent.n_net = tmp;
+
+       return (&pvt->netent);
+}
+
+static struct netent *
+nw_to_net(struct nwent *nwent, struct net_data *net_data) {
+       struct pvt *pvt;
+       u_long addr = 0;
+       int i;
+       int msbyte;
+
+       if (!nwent || nwent->n_addrtype != AF_INET)
+               return (NULL);
+       freepvt(net_data);
+       net_data->nw_data = malloc(sizeof (struct pvt));
+       if (!net_data->nw_data) {
+               errno = ENOMEM;
+               RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL);
+               return (NULL);
+       }
+       pvt = net_data->nw_data;
+       pvt->netent.n_name = nwent->n_name;
+       pvt->netent.n_aliases = nwent->n_aliases;
+       pvt->netent.n_addrtype = nwent->n_addrtype;
+
+/*
+ * What this code does: Converts net addresses from network to host form.
+ *
+ * msbyte: the index of the most significant byte in the n_addr array.
+ *
+ * Shift bytes in significant order into addr. When all signicant
+ * bytes are in, zero out bits in the LSB that are not part of the network.
+ */
+       msbyte = nwent->n_length / 8 +
+               ((nwent->n_length % 8) != 0 ? 1 : 0) - 1;
+       for (i = 0; i <= msbyte; i++)
+               addr = (addr << 8) | ((unsigned char *)nwent->n_addr)[i];
+       i = (32 - nwent->n_length) % 8;
+       if (i != 0)
+               addr &= ~((1 << (i + 1)) - 1);
+       pvt->netent.n_net = addr;
+       return (&pvt->netent);
+}
+
+#endif /*__BIND_NOSTATIC*/
diff --git a/lib/bind/irs/getnetent_r.c b/lib/bind/irs/getnetent_r.c
new file mode 100644 (file)
index 0000000..43e41fa
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 1998-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 rcsid[] = "$Id: getnetent_r.c,v 1.1 2001/03/29 06:31:46 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <port_before.h>
+#if !defined(_REENTRANT) || !defined(DO_PTHREADS)
+       static int getnetent_r_not_required = 0;
+#else
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <sys/param.h>
+#include <port_after.h>
+
+#ifdef NET_R_RETURN
+
+static NET_R_RETURN 
+copy_netent(struct netent *, struct netent *, NET_R_COPY_ARGS);
+
+NET_R_RETURN
+getnetbyname_r(const char *name,  struct netent *nptr, NET_R_ARGS) {
+       struct netent *ne = getnetbyname(name);
+
+       if (ne == NULL)
+               return (NET_R_BAD);
+
+       return (copy_netent(ne, nptr, NET_R_COPY));
+}
+
+#ifndef GETNETBYADDR_ADDR_T
+#define GETNETBYADDR_ADDR_T long
+#endif
+NET_R_RETURN
+getnetbyaddr_r(GETNETBYADDR_ADDR_T addr, int type, struct netent *nptr, NET_R_ARGS) {
+       struct netent *ne = getnetbyaddr(addr, type);
+
+       if (ne == NULL)
+               return (NET_R_BAD);
+
+       return (copy_netent(ne, nptr, NET_R_COPY));
+}
+
+/*
+ *     These assume a single context is in operation per thread.
+ *     If this is not the case we will need to call irs directly
+ *     rather than through the base functions.
+ */
+
+NET_R_RETURN
+getnetent_r(struct netent *nptr, NET_R_ARGS) {
+       struct netent *ne = getnetent();
+
+       if (ne == NULL)
+               return (NET_R_BAD);
+
+       return (copy_netent(ne, nptr, NET_R_COPY));
+}
+
+NET_R_SET_RETURN
+#ifdef NET_R_ENT_ARGS
+setnetent_r(int stay_open, NET_R_ENT_ARGS)
+#else
+setnetent_r(int stay_open)
+#endif
+{
+       setnetent(stay_open);
+#ifdef NET_R_SET_RESULT
+       return (NET_R_SET_RESULT);
+#endif
+}
+
+NET_R_END_RETURN
+#ifdef NET_R_ENT_ARGS
+endnetent_r(NET_R_ENT_ARGS)
+#else
+endnetent_r()
+#endif
+{
+       endnetent();
+       NET_R_END_RESULT(NET_R_OK);
+}
+
+/* Private */
+
+#ifndef NETENT_DATA
+static NET_R_RETURN
+copy_netent(struct netent *ne, struct netent *nptr, NET_R_COPY_ARGS) {
+       char *cp;
+       int i, n;
+       int numptr, len;
+
+       /* Find out the amount of space required to store the answer. */
+       numptr = 1; /* NULL ptr */
+       len = (char *)ALIGN(buf) - buf;
+       for (i = 0; ne->n_aliases[i]; i++, numptr++) {
+               len += strlen(ne->n_aliases[i]) + 1;
+       }
+       len += strlen(ne->n_name) + 1;
+       len += numptr * sizeof(char*);
+       
+       if (len > buflen) {
+               errno = ERANGE;
+               return (NET_R_BAD);
+       }
+
+       /* copy net value and type */
+       nptr->n_addrtype = ne->n_addrtype;
+       nptr->n_net = ne->n_net;
+
+       cp = (char *)ALIGN(buf) + numptr * sizeof(char *);
+
+       /* copy official name */
+       n = strlen(ne->n_name) + 1;
+       strcpy(cp, ne->n_name);
+       nptr->n_name = cp;
+       cp += n;
+
+       /* copy aliases */
+       nptr->n_aliases = (char **)ALIGN(buf);
+       for (i = 0 ; ne->n_aliases[i]; i++) {
+               n = strlen(ne->n_aliases[i]) + 1;
+               strcpy(cp, ne->n_aliases[i]);
+               nptr->n_aliases[i] = cp;
+               cp += n;
+       }
+       nptr->n_aliases[i] = NULL;
+
+       return (NET_R_OK);
+}
+#else /* !NETENT_DATA */
+static int
+copy_netent(struct netent *ne, struct netent *nptr, NET_R_COPY_ARGS) {
+       char *cp, *eob;
+       int i, n;
+
+       /* copy net value and type */
+       nptr->n_addrtype = ne->n_addrtype;
+       nptr->n_net = ne->n_net;
+
+       /* copy official name */
+       cp = ndptr->line;
+       eob = ndptr->line + sizeof(ndptr->line);
+       if ((n = strlen(ne->n_name) + 1) < (eob - cp)) {
+               strcpy(cp, ne->n_name);
+               nptr->n_name = cp;
+               cp += n;
+       } else {
+               return (-1);
+       }
+
+       /* copy aliases */
+       i = 0;
+       nptr->n_aliases = ndptr->net_aliases;
+       while (ne->n_aliases[i] && i < (_MAXALIASES-1)) {
+               if ((n = strlen(ne->n_aliases[i]) + 1) < (eob - cp)) {
+                       strcpy(cp, ne->n_aliases[i]);
+                       nptr->n_aliases[i] = cp;
+                       cp += n;
+               } else {
+                       break;
+               }
+               i++;
+       }
+       nptr->n_aliases[i] = NULL;
+
+       return (NET_R_OK);
+}
+#endif /* !NETENT_DATA */
+#else /* NET_R_RETURN */
+       static int getnetent_r_unknown_systemm = 0;
+#endif /* NET_R_RETURN */
+#endif /* !defined(_REENTRANT) || !defined(DO_PTHREADS) */
diff --git a/lib/bind/irs/getnetgrent.c b/lib/bind/irs/getnetgrent.c
new file mode 100644 (file)
index 0000000..07f39a7
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * 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 rcsid[] = "$Id: getnetgrent.c,v 1.1 2001/03/29 06:31:46 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* Imports */
+
+#include "port_before.h"
+
+#if !defined(__BIND_NOSTATIC)
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <resolv.h>
+#include <stdio.h>
+
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_data.h"
+
+/* Forward */
+
+static struct net_data *init(void);
+
+
+/* Public */
+
+void
+setnetgrent(const char *netgroup) {
+       struct net_data *net_data = init();
+
+       setnetgrent_p(netgroup, net_data);
+}
+
+void
+endnetgrent(void) {
+       struct net_data *net_data = init();
+
+       endnetgrent_p(net_data);
+}
+
+int
+innetgr(const char *netgroup, const char *host,
+       const char *user, const char *domain) {
+       struct net_data *net_data = init();
+
+       return (innetgr_p(netgroup, host, user, domain, net_data));
+}
+
+int
+getnetgrent(const char **host, const char **user, const char **domain) {
+       struct net_data *net_data = init();
+
+       return (getnetgrent_p(host, user, domain, net_data));
+}
+
+/* Shared private. */
+
+void
+setnetgrent_p(const char *netgroup, struct net_data *net_data) {
+       struct irs_ng *ng;
+
+       if ((net_data != NULL) && ((ng = net_data->ng) != NULL))
+               (*ng->rewind)(ng, netgroup);
+}
+
+void
+endnetgrent_p(struct net_data *net_data) {
+       struct irs_ng *ng;
+
+       if (!net_data)
+               return;
+       if ((ng = net_data->ng) != NULL)
+               (*ng->close)(ng);
+       net_data->ng = NULL;
+}
+
+int
+innetgr_p(const char *netgroup, const char *host,
+         const char *user, const char *domain,
+         struct net_data *net_data) {
+       struct irs_ng *ng;
+
+       if (!net_data || !(ng = net_data->ng))
+               return (0);
+       return ((*ng->test)(ng, netgroup, host, user, domain));
+}
+
+int
+getnetgrent_p(const char **host, const char **user, const char **domain,
+             struct net_data *net_data ) {
+       struct irs_ng *ng;
+
+       if (!net_data || !(ng = net_data->ng))
+               return (0);
+       return ((*ng->next)(ng, host, user, domain));
+}
+
+/* Private */
+
+static struct net_data *
+init(void) {
+       struct net_data *net_data;
+
+       if (!(net_data = net_data_init(NULL)))
+               goto error;
+       if (!net_data->ng) {
+               net_data->ng = (*net_data->irs->ng_map)(net_data->irs);
+               if (!net_data->ng) {
+  error:
+                       errno = EIO;
+                       return (NULL);
+               }
+       }
+       
+       return (net_data);
+}
+
+#endif /*__BIND_NOSTATIC*/
diff --git a/lib/bind/irs/getnetgrent_r.c b/lib/bind/irs/getnetgrent_r.c
new file mode 100644 (file)
index 0000000..b0a25af
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 1998-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 rcsid[] = "$Id: getnetgrent_r.c,v 1.1 2001/03/29 06:31:47 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <port_before.h>
+#if !defined(_REENTRANT) || !defined(DO_PTHREADS)
+       static int getnetgrent_r_not_required = 0;
+#else
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <netgroup.h>
+#include <port_after.h>
+
+#ifdef NGR_R_RETURN
+
+static NGR_R_RETURN 
+copy_protoent(char **, char **, char **, const char *, const char *,
+             const char *, NGR_R_COPY_ARGS);
+
+NGR_R_RETURN
+innetgr_r(const char *netgroup, const char *host, const char *user,
+       const char *domain) {
+
+       return (innetgr(netgroup, host, user, domain));
+}
+
+/*
+ *     These assume a single context is in operation per thread.
+ *     If this is not the case we will need to call irs directly
+ *     rather than through the base functions.
+ */
+
+NGR_R_RETURN
+getnetgrent_r(char **machinep, char **userp, char **domainp, NGR_R_ARGS) {
+       const char *mp, *up, *dp;
+       int res = getnetgrent(&mp, &up, &dp);
+
+       if (res != 1) 
+               return (res);
+
+       return (copy_protoent(machinep, userp, domainp,
+                               mp, up, dp, NGR_R_COPY));
+}
+
+NGR_R_SET_RETURN
+#ifdef NGR_R_ENT_ARGS
+setnetgrent_r(const char *netgroup, NGR_R_ENT_ARGS)
+#else
+setnetgrent_r(const char *netgroup)
+#endif
+{
+       setnetgrent(netgroup);
+#ifdef NGR_R_SET_RESULT
+       return (NGR_R_SET_RESULT);
+#endif
+}
+
+NGR_R_END_RETURN
+#ifdef NGR_R_ENT_ARGS
+endnetgrent_r(NGR_R_ENT_ARGS)
+#else
+endnetgrent_r(void)
+#endif
+{
+       endnetgrent();
+       NGR_R_END_RESULT(NGR_R_OK);
+}
+
+/* Private */
+
+static int
+copy_protoent(char **machinep, char **userp, char **domainp,
+             const char *mp, const char *up, const char *dp,
+             NGR_R_COPY_ARGS) {
+       char *cp;
+       int n;
+       int len;
+
+       /* Find out the amount of space required to store the answer. */
+       len = 0;
+       if (mp != NULL) len += strlen(mp) + 1;
+       if (up != NULL) len += strlen(up) + 1;
+       if (dp != NULL) len += strlen(dp) + 1;
+       
+       if (len > buflen) {
+               errno = ERANGE;
+               return (NGR_R_BAD);
+       }
+
+       cp = buf;
+
+       if (mp != NULL) {
+               n = strlen(mp) + 1;
+               strcpy(cp, mp);
+               *machinep = cp;
+               cp += n;
+       } else
+               *machinep = NULL;
+
+       if (up != NULL) {
+               n = strlen(up) + 1;
+               strcpy(cp, up);
+               *userp = cp;
+               cp += n;
+       } else
+               *userp = NULL;
+
+       if (dp != NULL) {
+               n = strlen(dp) + 1;
+               strcpy(cp, dp);
+               *domainp = cp;
+               cp += n;
+       } else
+               *domainp = NULL;
+
+       return (NGR_R_OK);
+}
+#else /* NGR_R_RETURN */
+       static int getnetgrent_r_unknown_system = 0;
+#endif /* NGR_R_RETURN */
+#endif /* !defined(_REENTRANT) || !defined(DO_PTHREADS) */
diff --git a/lib/bind/irs/getprotoent.c b/lib/bind/irs/getprotoent.c
new file mode 100644 (file)
index 0000000..e154379
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * 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(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: getprotoent.c,v 1.1 2001/03/29 06:31:47 marka Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#if !defined(__BIND_NOSTATIC)
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <resolv.h>
+#include <stdio.h>
+
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_data.h"
+
+/* Forward */
+
+static struct net_data *init(void);
+
+/* Public */
+
+struct protoent *
+getprotoent() {
+       struct net_data *net_data = init();
+
+       return (getprotoent_p(net_data));
+}
+
+struct protoent *
+getprotobyname(const char *name) {
+       struct net_data *net_data = init();
+
+       return (getprotobyname_p(name, net_data));
+}
+
+struct protoent *
+getprotobynumber(int proto) {
+       struct net_data *net_data = init();
+
+       return (getprotobynumber_p(proto, net_data));
+}
+
+void
+setprotoent(int stayopen) {
+       struct net_data *net_data = init();
+
+       setprotoent_p(stayopen, net_data);
+}
+
+void
+endprotoent() {
+       struct net_data *net_data = init();
+
+       endprotoent_p(net_data);
+}
+
+/* Shared private. */
+
+struct protoent *
+getprotoent_p(struct net_data *net_data) {
+       struct irs_pr *pr;
+
+       if (!net_data || !(pr = net_data->pr))
+               return (NULL);
+       net_data->pr_last = (*pr->next)(pr);
+       return (net_data->pr_last);
+}
+
+struct protoent *
+getprotobyname_p(const char *name, struct net_data *net_data) {
+       struct irs_pr *pr;
+       char **pap;
+
+       if (!net_data || !(pr = net_data->pr))
+               return (NULL);
+       if (net_data->pr_stayopen && net_data->pr_last) {
+               if (!strcmp(net_data->pr_last->p_name, name))
+                       return (net_data->pr_last);
+               for (pap = net_data->pr_last->p_aliases; pap && *pap; pap++)
+                       if (!strcmp(name, *pap))
+                               return (net_data->pr_last);
+       }
+       net_data->pr_last = (*pr->byname)(pr, name);
+       if (!net_data->pr_stayopen)
+               endprotoent();
+       return (net_data->pr_last);
+}
+
+struct protoent *
+getprotobynumber_p(int proto, struct net_data *net_data) {
+       struct irs_pr *pr;
+
+       if (!net_data || !(pr = net_data->pr))
+               return (NULL);
+       if (net_data->pr_stayopen && net_data->pr_last)
+               if (net_data->pr_last->p_proto == proto)
+                       return (net_data->pr_last);
+       net_data->pr_last = (*pr->bynumber)(pr, proto);
+       if (!net_data->pr_stayopen)
+               endprotoent();
+       return (net_data->pr_last);
+}
+
+void
+setprotoent_p(int stayopen, struct net_data *net_data) {
+       struct irs_pr *pr;
+
+       if (!net_data || !(pr = net_data->pr))
+               return;
+       (*pr->rewind)(pr);
+       net_data->pr_stayopen = (stayopen != 0);
+       if (stayopen == 0)
+               net_data_minimize(net_data);
+}
+
+void
+endprotoent_p(struct net_data *net_data) {
+       struct irs_pr *pr;
+
+       if ((net_data != NULL) && ((pr = net_data->pr) != NULL))
+               (*pr->minimize)(pr);
+}
+
+/* Private */
+
+static struct net_data *
+init() {
+       struct net_data *net_data;
+
+       if (!(net_data = net_data_init(NULL)))
+               goto error;
+       if (!net_data->pr) {
+               net_data->pr = (*net_data->irs->pr_map)(net_data->irs);
+
+               if (!net_data->pr || !net_data->res) {
+ error:                
+                       errno = EIO;
+                       return (NULL);
+               }
+               (*net_data->pr->res_set)(net_data->pr, net_data->res, NULL);
+       }
+       
+       return (net_data);
+}
+
+#endif /*__BIND_NOSTATIC*/
diff --git a/lib/bind/irs/getprotoent_r.c b/lib/bind/irs/getprotoent_r.c
new file mode 100644 (file)
index 0000000..08876da
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 1998-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 rcsid[] = "$Id: getprotoent_r.c,v 1.1 2001/03/29 06:31:47 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <port_before.h>
+#if !defined(_REENTRANT) || !defined(DO_PTHREADS)
+       static int getprotoent_r_not_required = 0;
+#else
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <port_after.h>
+
+#ifdef PROTO_R_RETURN
+
+static PROTO_R_RETURN 
+copy_protoent(struct protoent *, struct protoent *, PROTO_R_COPY_ARGS);
+
+PROTO_R_RETURN
+getprotobyname_r(const char *name, struct protoent *pptr, PROTO_R_ARGS) {
+       struct protoent *pe = getprotobyname(name);
+
+       if (pe == NULL)
+               return (PROTO_R_BAD);
+
+       return (copy_protoent(pe, pptr, PROTO_R_COPY));
+}
+
+PROTO_R_RETURN
+getprotobynumber_r(int proto, struct protoent *pptr, PROTO_R_ARGS) {
+       struct protoent *pe = getprotobynumber(proto);
+
+       if (pe == NULL)
+               return (PROTO_R_BAD);
+
+       return (copy_protoent(pe, pptr, PROTO_R_COPY));
+}
+
+/*
+ *     These assume a single context is in operation per thread.
+ *     If this is not the case we will need to call irs directly
+ *     rather than through the base functions.
+ */
+
+PROTO_R_RETURN
+getprotoent_r(struct protoent *pptr, PROTO_R_ARGS) {
+       struct protoent *pe = getprotoent();
+
+       if (pe == NULL)
+               return (PROTO_R_BAD);
+
+       return (copy_protoent(pe, pptr, PROTO_R_COPY));
+}
+
+PROTO_R_SET_RETURN
+#ifdef PROTO_R_ENT_ARGS
+setprotoent_r(int stay_open, PROTO_R_ENT_ARGS)
+#else
+setprotoent_r(int stay_open)
+#endif
+{
+       setprotoent(stay_open);
+#ifdef PROTO_R_SET_RESULT
+       return (PROTO_R_SET_RESULT);
+#endif
+}
+
+PROTO_R_END_RETURN
+#ifdef PROTO_R_ENT_ARGS
+endprotoent_r(PROTO_R_ENT_ARGS)
+#else
+endprotoent_r()
+#endif
+{
+       endprotoent();
+       PROTO_R_END_RESULT(PROTO_R_OK);
+}
+
+/* Private */
+
+#ifndef PROTOENT_DATA
+static PROTO_R_RETURN
+copy_protoent(struct protoent *pe, struct protoent *pptr, PROTO_R_COPY_ARGS) {
+       char *cp;
+       int i, n;
+       int numptr, len;
+
+       /* Find out the amount of space required to store the answer. */
+       numptr = 1; /* NULL ptr */
+       len = (char *)ALIGN(buf) - buf;
+       for (i = 0; pe->p_aliases[i]; i++, numptr++) {
+               len += strlen(pe->p_aliases[i]) + 1;
+       }
+       len += strlen(pe->p_name) + 1;
+       len += numptr * sizeof(char*);
+       
+       if (len > buflen) {
+               errno = ERANGE;
+               return (PROTO_R_BAD);
+       }
+
+       /* copy protocol value*/
+       pptr->p_proto = pe->p_proto;
+
+       cp = (char *)ALIGN(buf) + numptr * sizeof(char *);
+
+       /* copy official name */
+       n = strlen(pe->p_name) + 1;
+       strcpy(cp, pe->p_name);
+       pptr->p_name = cp;
+       cp += n;
+
+       /* copy aliases */
+       pptr->p_aliases = (char **)ALIGN(buf);
+       for (i = 0 ; pe->p_aliases[i]; i++) {
+               n = strlen(pe->p_aliases[i]) + 1;
+               strcpy(cp, pe->p_aliases[i]);
+               pptr->p_aliases[i] = cp;
+               cp += n;
+       }
+       pptr->p_aliases[i] = NULL;
+
+       return (PROTO_R_OK);
+}
+#else /* !PROTOENT_DATA */
+static int
+copy_protoent(struct protoent *pe, struct protoent *pptr, PROTO_R_COPY_ARGS) {
+       char *cp, *eob;
+       int i, n;
+
+       /* copy protocol value */
+       pptr->p_proto = pe->p_proto;
+
+       /* copy official name */
+       cp = pdptr->line;
+       eob = pdptr->line + sizeof(pdptr->line);
+       if ((n = strlen(pe->p_name) + 1) < (eob - cp)) {
+               strcpy(cp, pe->p_name);
+               pptr->p_name = cp;
+               cp += n;
+       } else {
+               return (-1);
+       }
+
+       /* copy aliases */
+       i = 0;
+       pptr->p_aliases = pdptr->proto_aliases;
+       while (pe->p_aliases[i] && i < (_MAXALIASES-1)) {
+               if ((n = strlen(pe->p_aliases[i]) + 1) < (eob - cp)) {
+                       strcpy(cp, pe->p_aliases[i]);
+                       pptr->p_aliases[i] = cp;
+                       cp += n;
+               } else {
+                       break;
+               }
+               i++;
+       }
+       pptr->p_aliases[i] = NULL;
+
+       return (PROTO_R_OK);
+}
+#endif /* PROTOENT_DATA */
+#else /* PROTO_R_RETURN */
+       static int getprotoent_r_unknown_systemm = 0;
+#endif /* PROTO_R_RETURN */
+#endif /* !defined(_REENTRANT) || !defined(DO_PTHREADS) */
diff --git a/lib/bind/irs/getpwent.c b/lib/bind/irs/getpwent.c
new file mode 100644 (file)
index 0000000..b9cc9e3
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * 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(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: getpwent.c,v 1.1 2001/03/29 06:31:47 marka Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#if !defined(WANT_IRS_PW) || defined(__BIND_NOSTATIC)
+static int __bind_irs_pw_unneeded;
+#else
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <pwd.h>
+#include <resolv.h>
+#include <stdio.h>
+
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_data.h"
+
+/* Forward */
+
+static struct net_data * init(void);
+
+/* Public */
+
+struct passwd *
+getpwent(void) {
+       struct net_data *net_data = init();
+
+       return (getpwent_p(net_data));
+}
+
+struct passwd *
+getpwnam(const char *name) {
+       struct net_data *net_data = init();
+
+       return (getpwnam_p(name, net_data));
+}
+
+struct passwd *
+getpwuid(uid_t uid) {
+       struct net_data *net_data = init();
+
+       return (getpwuid_p(uid, net_data));
+}
+
+int
+setpassent(int stayopen) {
+       struct net_data *net_data = init();
+
+       return (setpassent_p(stayopen, net_data));
+}
+
+#ifdef SETPWENT_VOID
+void
+setpwent() {
+       struct net_data *net_data = init();
+
+       setpwent_p(net_data);
+}
+#else
+int
+setpwent() {
+       struct net_data *net_data = init();
+
+       return (setpwent_p(net_data));
+}
+#endif
+
+void
+endpwent() {
+       struct net_data *net_data = init();
+
+       endpwent_p(net_data);
+}
+
+/* Shared private. */
+
+struct passwd *
+getpwent_p(struct net_data *net_data) {
+       struct irs_pw *pw;
+
+       if (!net_data || !(pw = net_data->pw))
+               return (NULL);
+       net_data->pw_last = (*pw->next)(pw);
+       return (net_data->pw_last);
+}
+
+struct passwd *
+getpwnam_p(const char *name, struct net_data *net_data) {
+       struct irs_pw *pw;
+
+       if (!net_data || !(pw = net_data->pw))
+               return (NULL);
+       if (net_data->pw_stayopen && net_data->pw_last &&
+           !strcmp(net_data->pw_last->pw_name, name))
+               return (net_data->pw_last);
+       net_data->pw_last = (*pw->byname)(pw, name);
+       if (!net_data->pw_stayopen)
+               endpwent();
+       return (net_data->pw_last);
+}
+
+struct passwd *
+getpwuid_p(uid_t uid, struct net_data *net_data) {
+       struct irs_pw *pw;
+
+       if (!net_data || !(pw = net_data->pw))
+               return (NULL);
+       if (net_data->pw_stayopen && net_data->pw_last &&
+           net_data->pw_last->pw_uid == uid)
+               return (net_data->pw_last);
+       net_data->pw_last = (*pw->byuid)(pw, uid);
+       if (!net_data->pw_stayopen)
+               endpwent();
+       return (net_data->pw_last);
+}
+
+int
+setpassent_p(int stayopen, struct net_data *net_data) {
+       struct irs_pw *pw;
+
+       if (!net_data || !(pw = net_data->pw))
+               return (0);
+       (*pw->rewind)(pw);
+       net_data->pw_stayopen = (stayopen != 0);
+       if (stayopen == 0)
+               net_data_minimize(net_data);
+       return (1);
+}
+
+#ifdef SETPWENT_VOID
+void
+setpwent_p(struct net_data *net_data) {
+       (void) setpassent_p(0, net_data);
+}
+#else
+int
+setpwent_p(struct net_data *net_data) {
+       return (setpassent_p(0, net_data));
+}
+#endif
+
+void
+endpwent_p(struct net_data *net_data) {
+       struct irs_pw *pw;
+
+       if ((net_data != NULL) && ((pw = net_data->pw) != NULL))
+               (*pw->minimize)(pw);
+}
+
+/* Private */
+
+static struct net_data *
+init() {
+       struct net_data *net_data;
+       if (!(net_data = net_data_init(NULL)))
+               goto error;
+       if (!net_data->pw) {
+               net_data->pw = (*net_data->irs->pw_map)(net_data->irs);
+
+               if (!net_data->pw || !net_data->res) {
+ error: 
+                       errno = EIO;
+                       return (NULL);
+               }
+               (*net_data->pw->res_set)(net_data->pw, net_data->res, NULL);
+       }
+       
+       return (net_data);
+}
+
+#endif /* WANT_IRS_PW */
diff --git a/lib/bind/irs/getpwent_r.c b/lib/bind/irs/getpwent_r.c
new file mode 100644 (file)
index 0000000..ef400df
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 1998-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 rcsid[] = "$Id: getpwent_r.c,v 1.1 2001/03/29 06:31:47 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <port_before.h>
+#if !defined(_REENTRANT) || !defined(DO_PTHREADS) || !defined(WANT_IRS_PW)
+       static int getpwent_r_not_required = 0;
+#else
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <port_after.h>
+
+#ifdef PASS_R_RETURN
+
+static int 
+copy_passwd(struct passwd *, struct passwd *, char *buf, int buflen);
+
+/* POSIX 1003.1c */
+#ifdef POSIX_GETPWNAM_R
+int
+__posix_getpwnam_r(const char *login,  struct passwd *pwptr,
+               char *buf, size_t buflen, struct passwd **result) {
+#else
+int
+getpwnam_r(const char *login,  struct passwd *pwptr,
+               char *buf, size_t buflen, struct passwd **result) {
+#endif
+       struct passwd *pw = getpwnam(login);
+       int res;
+
+       if (pw == NULL) {
+               *result = NULL;
+               return (-1);
+       }
+
+       res = copy_passwd(pw, pwptr, buf, buflen);
+       *result = res ? NULL : pwptr;
+       return (res);
+}
+
+#ifdef POSIX_GETPWNAM_R
+struct passwd *
+getpwnam_r(const char *login,  struct passwd *pwptr, char *buf, int buflen) {
+       struct passwd *pw = getpwnam(login);
+       int res;
+
+       if (pw == NULL)
+               return (NULL);
+
+       res = copy_passwd(pw, pwptr, buf, buflen);
+       return (res ? NULL : pwptr);
+}
+#endif
+
+/* POSIX 1003.1c */
+#ifdef POSIX_GETPWUID_R
+int
+__posix_getpwuid_r(uid_t uid, struct passwd *pwptr,
+               char *buf, int buflen, struct passwd **result) {
+#else
+int
+getpwuid_r(uid_t uid, struct passwd *pwptr,
+               char *buf, size_t buflen, struct passwd **result) {
+#endif
+       struct passwd *pw = getpwuid(uid);
+       int res;
+
+       if (pw == NULL) {
+               *result = NULL;
+               return (-1);
+       }
+
+       res = copy_passwd(pw, pwptr, buf, buflen);
+       *result = res ? NULL : pwptr;
+       return (res);
+}
+
+#ifdef POSIX_GETPWUID_R
+struct passwd *
+getpwuid_r(uid_t uid,  struct passwd *pwptr, char *buf, int buflen) {
+       struct passwd *pw = getpwuid(uid);
+       int res;
+
+       if (pw == NULL)
+               return (NULL);
+
+       res = copy_passwd(pw, pwptr, buf, buflen);
+       return (res ? NULL : pwptr);
+}
+#endif
+
+/*
+ *     These assume a single context is in operation per thread.
+ *     If this is not the case we will need to call irs directly
+ *     rather than through the base functions.
+ */
+
+PASS_R_RETURN
+getpwent_r(struct passwd *pwptr, PASS_R_ARGS) {
+       struct passwd *pw = getpwent();
+       int res;
+
+       if (pw == NULL)
+               return (PASS_R_BAD);
+
+       res = copy_passwd(pw, pwptr, buf, buflen);
+       return (res ? PASS_R_BAD : PASS_R_OK);
+}
+
+PASS_R_SET_RETURN
+#ifdef PASS_R_ENT_ARGS
+setpassent_r(int stayopen, PASS_R_ENT_ARGS)
+#else
+setpassent_r(int stayopen)
+#endif
+{
+
+       setpassent(stayopen);
+#ifdef PASS_R_SET_RESULT
+       return (PASS_R_SET_RESULT);
+#endif
+}
+
+PASS_R_SET_RETURN
+#ifdef PASS_R_ENT_ARGS
+setpwent_r(PASS_R_ENT_ARGS)
+#else
+setpwent_r(void)
+#endif
+{
+
+       setpwent();
+#ifdef PASS_R_SET_RESULT
+       return (PASS_R_SET_RESULT);
+#endif
+}
+
+PASS_R_END_RETURN
+#ifdef PASS_R_ENT_ARGS
+endpwent_r(PASS_R_ENT_ARGS)
+#else
+endpwent_r(void)
+#endif
+{
+
+       endpwent();
+       PASS_R_END_RESULT(PASS_R_OK);
+}
+
+
+#ifdef HAS_FGETPWENT
+PASS_R_RETURN
+fgetpwent_r(FILE *f, struct passwd *pwptr, PASS_R_COPY_ARGS) {
+       struct passwd *pw = fgetpwent(f);
+       int res;
+
+       if (pw == NULL)
+               return (PASS_R_BAD);
+
+       res = copy_passwd(pw, pwptr, PASS_R_COPY);
+       return (res ? PASS_R_BAD : PASS_R_OK );
+}
+#endif
+
+/* Private */
+
+static int
+copy_passwd(struct passwd *pw, struct passwd *pwptr, char *buf, int buflen) {
+       char *cp;
+       int n;
+       int len;
+
+       /* Find out the amount of space required to store the answer. */
+       len = strlen(pw->pw_name) + 1;
+       len += strlen(pw->pw_passwd) + 1;
+#ifdef HAVE_PW_CLASS
+       len += strlen(pw->pw_class) + 1;
+#endif
+       len += strlen(pw->pw_gecos) + 1;
+       len += strlen(pw->pw_dir) + 1;
+       len += strlen(pw->pw_shell) + 1;
+       
+       if (len > buflen) {
+               errno = ERANGE;
+               return (-1);
+       }
+
+       /* copy fixed atomic values*/
+       pwptr->pw_uid = pw->pw_uid;
+       pwptr->pw_gid = pw->pw_gid;
+#ifdef HAVE_PW_CHANGE
+       pwptr->pw_change = pw->pw_change;
+#endif
+#ifdef HAVE_PW_EXPIRE
+       pwptr->pw_expire = pw->pw_expire;
+#endif
+
+       cp = buf;
+
+       /* copy official name */
+       n = strlen(pw->pw_name) + 1;
+       strcpy(cp, pw->pw_name);
+       pwptr->pw_name = cp;
+       cp += n;
+
+       /* copy password */
+       n = strlen(pw->pw_passwd) + 1;
+       strcpy(cp, pw->pw_passwd);
+       pwptr->pw_passwd = cp;
+       cp += n;
+
+#ifdef HAVE_PW_CLASS
+       /* copy class */
+       n = strlen(pw->pw_class) + 1;
+       strcpy(cp, pw->pw_class);
+       pwptr->pw_class = cp;
+       cp += n;
+#endif
+
+       /* copy gecos */
+       n = strlen(pw->pw_gecos) + 1;
+       strcpy(cp, pw->pw_gecos);
+       pwptr->pw_gecos = cp;
+       cp += n;
+
+       /* copy directory */
+       n = strlen(pw->pw_dir) + 1;
+       strcpy(cp, pw->pw_dir);
+       pwptr->pw_dir = cp;
+       cp += n;
+
+       /* copy login shell */
+       n = strlen(pw->pw_shell) + 1;
+       strcpy(cp, pw->pw_shell);
+       pwptr->pw_shell = cp;
+       cp += n;
+
+       return (0);
+}
+#else /* PASS_R_RETURN */
+       static int getpwent_r_unknown_systemm = 0;
+#endif /* PASS_R_RETURN */
+#endif /* !def(_REENTRANT) || !def(DO_PTHREADS) || !def(WANT_IRS_PW) */
diff --git a/lib/bind/irs/getservent.c b/lib/bind/irs/getservent.c
new file mode 100644 (file)
index 0000000..56cc107
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * 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(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: getservent.c,v 1.1 2001/03/29 06:31:47 marka Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#if !defined(__BIND_NOSTATIC)
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <resolv.h>
+#include <stdio.h>
+
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_data.h"
+
+/* Forward */
+
+static struct net_data *init(void);
+
+/* Public */
+
+struct servent *
+getservent(void) {
+       struct net_data *net_data = init();
+
+       return (getservent_p(net_data));
+}
+
+struct servent *
+getservbyname(const char *name, const char *proto) {
+       struct net_data *net_data = init();
+
+       return (getservbyname_p(name, proto, net_data));
+}
+
+struct servent *
+getservbyport(int port, const char *proto) {
+       struct net_data *net_data = init();
+
+       return (getservbyport_p(port, proto, net_data));
+}
+
+void
+setservent(int stayopen) {
+       struct net_data *net_data = init();
+
+       setservent_p(stayopen, net_data);
+}
+
+void
+endservent() {
+       struct net_data *net_data = init();
+
+       endservent_p(net_data);
+}
+
+/* Shared private. */
+
+struct servent *
+getservent_p(struct net_data *net_data) {
+       struct irs_sv *sv;
+
+       if (!net_data || !(sv = net_data->sv))
+               return (NULL);
+       net_data->sv_last = (*sv->next)(sv);
+       return (net_data->sv_last);
+}
+
+struct servent *
+getservbyname_p(const char *name, const char *proto,
+               struct net_data *net_data) {
+       struct irs_sv *sv;
+       char **sap;
+
+       if (!net_data || !(sv = net_data->sv))
+               return (NULL);
+       if (net_data->sv_stayopen && net_data->sv_last)
+               if (!proto || !strcmp(net_data->sv_last->s_proto, proto)) {
+                       if (!strcmp(net_data->sv_last->s_name, name))
+                               return (net_data->sv_last);
+                       for (sap = net_data->sv_last->s_aliases;
+                            sap && *sap; sap++)
+                               if (!strcmp(name, *sap))
+                                       return (net_data->sv_last);
+               }
+       net_data->sv_last = (*sv->byname)(sv, name, proto);
+       if (!net_data->sv_stayopen)
+               endservent();
+       return (net_data->sv_last);
+}
+
+struct servent *
+getservbyport_p(int port, const char *proto, struct net_data *net_data) {
+       struct irs_sv *sv;
+
+       if (!net_data || !(sv = net_data->sv))
+               return (NULL);
+       if (net_data->sv_stayopen && net_data->sv_last)
+               if (port == net_data->sv_last->s_port &&
+                   ( !proto ||
+                    !strcmp(net_data->sv_last->s_proto, proto)))
+                       return (net_data->sv_last);
+       net_data->sv_last = (*sv->byport)(sv, port, proto);
+       return (net_data->sv_last);
+}
+
+void
+setservent_p(int stayopen, struct net_data *net_data) {
+       struct irs_sv *sv;
+
+       if (!net_data || !(sv = net_data->sv))
+               return;
+       (*sv->rewind)(sv);
+       net_data->sv_stayopen = (stayopen != 0);
+       if (stayopen == 0)
+               net_data_minimize(net_data);
+}
+
+void
+endservent_p(struct net_data *net_data) {
+       struct irs_sv *sv;
+
+       if ((net_data != NULL) && ((sv = net_data->sv) != NULL))
+               (*sv->minimize)(sv);
+}
+
+/* Private */
+
+static struct net_data *
+init() {
+       struct net_data *net_data;
+
+       if (!(net_data = net_data_init(NULL)))
+               goto error;
+       if (!net_data->sv) {
+               net_data->sv = (*net_data->irs->sv_map)(net_data->irs);
+
+               if (!net_data->sv || !net_data->res) {
+ error:                
+                       errno = EIO;
+                       return (NULL);
+               }
+               (*net_data->sv->res_set)(net_data->sv, net_data->res, NULL);
+       }
+       
+       return (net_data);
+}
+
+#endif /*__BIND_NOSTATIC*/
diff --git a/lib/bind/irs/getservent_r.c b/lib/bind/irs/getservent_r.c
new file mode 100644 (file)
index 0000000..b9ecb2f
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 1998-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 rcsid[] = "$Id: getservent_r.c,v 1.1 2001/03/29 06:31:48 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <port_before.h>
+#if !defined(_REENTRANT) || !defined(DO_PTHREADS)
+       static int getservent_r_not_required = 0;
+#else
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <sys/param.h>
+#include <port_after.h>
+
+#ifdef SERV_R_RETURN
+
+static SERV_R_RETURN 
+copy_servent(struct servent *, struct servent *, SERV_R_COPY_ARGS);
+
+SERV_R_RETURN
+getservbyname_r(const char *name, const char *proto,
+               struct servent *sptr, SERV_R_ARGS) {
+       struct servent *se = getservbyname(name, proto);
+
+       if (se == NULL)
+               return (SERV_R_BAD);
+
+       return (copy_servent(se, sptr, SERV_R_COPY));
+}
+
+SERV_R_RETURN
+getservbyport_r(int port, const char *proto,
+               struct servent *sptr, SERV_R_ARGS) {
+       struct servent *se = getservbyport(port, proto);
+
+       if (se == NULL)
+               return (SERV_R_BAD);
+
+       return (copy_servent(se, sptr, SERV_R_COPY));
+}
+
+/*
+ *     These assume a single context is in operation per thread.
+ *     If this is not the case we will need to call irs directly
+ *     rather than through the base functions.
+ */
+
+SERV_R_RETURN
+getservent_r(struct servent *sptr, SERV_R_ARGS) {
+       struct servent *se = getservent();
+
+       if (se == NULL)
+               return (SERV_R_BAD);
+
+       return (copy_servent(se, sptr, SERV_R_COPY));
+}
+
+SERV_R_SET_RETURN
+#ifdef SERV_R_ENT_ARGS
+setservent_r(int stay_open, SERV_R_ENT_ARGS)
+#else
+setservent_r(int stay_open)
+#endif
+{
+
+       setservent(stay_open);
+#ifdef SERV_R_SET_RESULT
+       return (SERV_R_SET_RESULT);
+#endif
+}
+
+SERV_R_END_RETURN
+#ifdef SERV_R_ENT_ARGS
+endservent_r(SERV_R_ENT_ARGS)
+#else
+endservent_r()
+#endif
+{
+
+       endservent();
+       SERV_R_END_RESULT(SERV_R_OK);
+}
+
+/* Private */
+
+#ifndef SERVENT_DATA
+static SERV_R_RETURN
+copy_servent(struct servent *se, struct servent *sptr, SERV_R_COPY_ARGS) {
+       char *cp;
+       int i, n;
+       int numptr, len;
+
+       /* Find out the amount of space required to store the answer. */
+       numptr = 1; /* NULL ptr */
+       len = (char *)ALIGN(buf) - buf;
+       for (i = 0; se->s_aliases[i]; i++, numptr++) {
+               len += strlen(se->s_aliases[i]) + 1;
+       }
+       len += strlen(se->s_name) + 1;
+       len += strlen(se->s_proto) + 1;
+       len += numptr * sizeof(char*);
+       
+       if (len > buflen) {
+               errno = ERANGE;
+               return (SERV_R_BAD);
+       }
+
+       /* copy port value */
+       sptr->s_port = se->s_port;
+
+       cp = (char *)ALIGN(buf) + numptr * sizeof(char *);
+
+       /* copy official name */
+       n = strlen(se->s_name) + 1;
+       strcpy(cp, se->s_name);
+       sptr->s_name = cp;
+       cp += n;
+
+       /* copy aliases */
+       sptr->s_aliases = (char **)ALIGN(buf);
+       for (i = 0 ; se->s_aliases[i]; i++) {
+               n = strlen(se->s_aliases[i]) + 1;
+               strcpy(cp, se->s_aliases[i]);
+               sptr->s_aliases[i] = cp;
+               cp += n;
+       }
+       sptr->s_aliases[i] = NULL;
+
+       /* copy proto */
+       n = strlen(se->s_proto) + 1;
+       strcpy(cp, se->s_proto);
+       sptr->s_proto = cp;
+       cp += n;
+
+       return (SERV_R_OK);
+}
+#else /* !SERVENT_DATA */
+static int
+copy_servent(struct servent *se, struct servent *sptr, SERV_R_COPY_ARGS) {
+       char *cp, *eob;
+       int i, n;
+
+       /* copy port value */
+       sptr->s_port = se->s_port;
+
+       /* copy official name */
+       cp = ndptr->line;
+       eob = ndptr->line + sizeof(ndptr->line);
+       if ((n = strlen(se->s_name) + 1) < (eob - cp)) {
+               strcpy(cp, se->s_name);
+               sptr->s_name = cp;
+               cp += n;
+       } else {
+               return (-1);
+       }
+
+       /* copy aliases */
+       i = 0;
+       sptr->s_aliases = ndptr->serv_aliases;
+       while (se->s_aliases[i] && i < (_MAXALIASES-1)) {
+               if ((n = strlen(se->s_aliases[i]) + 1) < (eob - cp)) {
+                       strcpy(cp, se->s_aliases[i]);
+                       sptr->s_aliases[i] = cp;
+                       cp += n;
+               } else {
+                       break;
+               }
+               i++;
+       }
+       sptr->s_aliases[i] = NULL;
+
+       /* copy proto */
+       if ((n = strlen(se->s_proto) + 1) < (eob - cp)) {
+               strcpy(cp, se->s_proto);
+               sptr->s_proto = cp;
+               cp += n;
+       } else {
+               return (-1);
+       }
+
+       return (SERV_R_OK);
+}
+#endif /* !SERVENT_DATA */
+#else /*SERV_R_RETURN */
+       static int getservent_r_unknown_systemm = 0;
+#endif /*SERV_R_RETURN */
+#endif /* !defined(_REENTRANT) || !defined(DO_PTHREADS) */
diff --git a/lib/bind/irs/hesiod.c b/lib/bind/irs/hesiod.c
new file mode 100644 (file)
index 0000000..242e875
--- /dev/null
@@ -0,0 +1,506 @@
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: hesiod.c,v 1.1 2001/03/29 06:31:48 marka Exp $";
+#endif
+
+/*
+ * 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.
+ */
+
+/*
+ * This file is primarily maintained by <tytso@mit.edu> and <ghudson@mit.edu>.
+ */
+
+/*
+ * hesiod.c --- the core portion of the hesiod resolver.
+ *
+ * This file is derived from the hesiod library from Project Athena;
+ * It has been extensively rewritten by Theodore Ts'o to have a more
+ * thread-safe interface.
+ */
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "port_after.h"
+
+#include "pathnames.h"
+#include "hesiod.h"
+#include "hesiod_p.h"
+
+/* Forward */
+
+int            hesiod_init(void **context);
+void           hesiod_end(void *context);
+char *         hesiod_to_bind(void *context, const char *name,
+                              const char *type);
+char **                hesiod_resolve(void *context, const char *name,
+                              const char *type);
+void           hesiod_free_list(void *context, char **list);
+
+static int     parse_config_file(struct hesiod_p *ctx, const char *filename);
+static char ** get_txt_records(struct hesiod_p *ctx, int class,
+                               const char *name);
+static int     init(struct hesiod_p *ctx);
+
+/* Public */
+
+/*
+ * This function is called to initialize a hesiod_p.
+ */
+int
+hesiod_init(void **context) {
+       struct hesiod_p *ctx;
+       char *cp;
+
+       ctx = malloc(sizeof(struct hesiod_p));
+       if (ctx == 0) {
+               errno = ENOMEM;
+               return (-1);
+       }
+
+       ctx->LHS = NULL;
+       ctx->RHS = NULL;
+       ctx->res = NULL;
+
+       if (parse_config_file(ctx, _PATH_HESIOD_CONF) < 0) {
+#ifdef DEF_RHS
+               /*
+                * Use compiled in defaults.
+                */
+               ctx->LHS = malloc(strlen(DEF_LHS)+1);
+               ctx->RHS = malloc(strlen(DEF_RHS)+1);
+               if (ctx->LHS == 0 || ctx->RHS == 0) {
+                       errno = ENOMEM;
+                       goto cleanup;
+               }
+               strcpy(ctx->LHS, DEF_LHS);
+               strcpy(ctx->RHS, DEF_RHS);
+#else
+               goto cleanup;
+#endif
+       }
+       /*
+        * The default RHS can be overridden by an environment
+        * variable.
+        */
+       if ((cp = getenv("HES_DOMAIN")) != NULL) {
+               if (ctx->RHS)
+                       free(ctx->RHS);
+               ctx->RHS = malloc(strlen(cp)+2);
+               if (!ctx->RHS) {
+                       errno = ENOMEM;
+                       goto cleanup;
+               }
+               if (cp[0] == '.')
+                       strcpy(ctx->RHS, cp);
+               else {
+                       strcpy(ctx->RHS, ".");
+                       strcat(ctx->RHS, cp);
+               }
+       }
+
+       /*
+        * If there is no default hesiod realm set, we return an
+        * error.
+        */
+       if (!ctx->RHS) {
+               errno = ENOEXEC;
+               goto cleanup;
+       }
+       
+#if 0
+       if (res_ninit(ctx->res) < 0)
+               goto cleanup;
+#endif
+
+       *context = ctx;
+       return (0);
+
+ cleanup:
+       hesiod_end(ctx);
+       return (-1);
+}
+
+/*
+ * This function deallocates the hesiod_p
+ */
+void
+hesiod_end(void *context) {
+       struct hesiod_p *ctx = (struct hesiod_p *) context;
+       int save_errno = errno;
+
+       if (ctx->res)
+               res_nclose(ctx->res);
+       if (ctx->RHS)
+               free(ctx->RHS);
+       if (ctx->LHS)
+               free(ctx->LHS);
+       if (ctx->res && ctx->free_res)
+               (*ctx->free_res)(ctx->res);
+       free(ctx);
+       errno = save_errno;
+}
+
+/*
+ * This function takes a hesiod (name, type) and returns a DNS
+ * name which is to be resolved.
+ */
+char *
+hesiod_to_bind(void *context, const char *name, const char *type) {
+       struct hesiod_p *ctx = (struct hesiod_p *) context;
+       char *bindname;
+       char **rhs_list = NULL;
+       const char *RHS, *cp;
+
+       /* Decide what our RHS is, and set cp to the end of the actual name. */
+       if ((cp = strchr(name, '@')) != NULL) {
+               if (strchr(cp + 1, '.'))
+                       RHS = cp + 1;
+               else if ((rhs_list = hesiod_resolve(context, cp + 1,
+                   "rhs-extension")) != NULL)
+                       RHS = *rhs_list;
+               else {
+                       errno = ENOENT;
+                       return (NULL);
+               }
+       } else {
+               RHS = ctx->RHS;
+               cp = name + strlen(name);
+       }
+
+       /*
+        * Allocate the space we need, including up to three periods and
+        * the terminating NUL.
+        */
+       if ((bindname = malloc((cp - name) + strlen(type) + strlen(RHS) +
+           (ctx->LHS ? strlen(ctx->LHS) : 0) + 4)) == NULL) {
+               errno = ENOMEM;
+               if (rhs_list)
+                       hesiod_free_list(context, rhs_list);
+               return NULL;
+       }
+
+       /* Now put together the DNS name. */
+       memcpy(bindname, name, cp - name);
+       bindname[cp - name] = '\0';
+       strcat(bindname, ".");
+       strcat(bindname, type);
+       if (ctx->LHS) {
+               if (ctx->LHS[0] != '.')
+                       strcat(bindname, ".");
+               strcat(bindname, ctx->LHS);
+       }
+       if (RHS[0] != '.')
+               strcat(bindname, ".");
+       strcat(bindname, RHS);
+
+       if (rhs_list)
+               hesiod_free_list(context, rhs_list);
+
+       return (bindname);
+}
+
+/*
+ * This is the core function.  Given a hesiod (name, type), it
+ * returns an array of strings returned by the resolver.
+ */
+char **
+hesiod_resolve(void *context, const char *name, const char *type) {
+       struct hesiod_p *ctx = (struct hesiod_p *) context;
+       char *bindname = hesiod_to_bind(context, name, type);
+       char **retvec;
+
+       if (bindname == NULL)
+               return (NULL);
+       if (init(ctx) == -1) {
+               free(bindname);
+               return (NULL);
+       }
+
+       if ((retvec = get_txt_records(ctx, C_IN, bindname))) {
+               free(bindname);
+               return (retvec);
+       }
+       
+       if (errno != ENOENT)
+               return (NULL);
+
+       retvec = get_txt_records(ctx, C_HS, bindname);
+       free(bindname);
+       return (retvec);
+}
+
+void
+hesiod_free_list(void *context, char **list) {
+       char **p;
+
+       UNUSED(context);
+
+       for (p = list; *p; p++)
+               free(*p);
+       free(list);
+}
+
+/*
+ * This function parses the /etc/hesiod.conf file
+ */
+static int
+parse_config_file(struct hesiod_p *ctx, const char *filename) {
+       char *key, *data, *cp, **cpp;
+       char buf[MAXDNAME+7];
+       FILE *fp;
+
+       /*
+        * Clear the existing configuration variable, just in case
+        * they're set.
+        */
+       if (ctx->RHS)
+               free(ctx->RHS);
+       if (ctx->LHS)
+               free(ctx->LHS);
+       ctx->RHS = ctx->LHS = 0;
+
+       /*
+        * Now open and parse the file...
+        */
+       if (!(fp = fopen(filename, "r")))
+               return (-1);
+       
+       while (fgets(buf, sizeof(buf), fp) != NULL) {
+               cp = buf;
+               if (*cp == '#' || *cp == '\n' || *cp == '\r')
+                       continue;
+               while(*cp == ' ' || *cp == '\t')
+                       cp++;
+               key = cp;
+               while(*cp != ' ' && *cp != '\t' && *cp != '=')
+                       cp++;
+               *cp++ = '\0';
+               
+               while(*cp == ' ' || *cp == '\t' || *cp == '=')
+                       cp++;
+               data = cp;
+               while(*cp != ' ' && *cp != '\n' && *cp != '\r')
+                       cp++;
+               *cp++ = '\0';
+
+               if (strcmp(key, "lhs") == 0)
+                       cpp = &ctx->LHS;
+               else if (strcmp(key, "rhs") == 0)
+                       cpp = &ctx->RHS;
+               else
+                       continue;
+
+               *cpp = malloc(strlen(data) + 1);
+               if (!*cpp) {
+                       errno = ENOMEM;
+                       goto cleanup;
+               }
+               strcpy(*cpp, data);
+       }
+       fclose(fp);
+       return (0);
+       
+ cleanup:
+       fclose(fp);
+       if (ctx->RHS)
+               free(ctx->RHS);
+       if (ctx->LHS)
+               free(ctx->LHS);
+       ctx->RHS = ctx->LHS = 0;
+       return (-1);
+}
+
+/*
+ * Given a DNS class and a DNS name, do a lookup for TXT records, and
+ * return a list of them.
+ */
+static char **
+get_txt_records(struct hesiod_p *ctx, int class, const char *name) {
+       struct {
+               int type;               /* RR type */
+               int class;              /* RR class */
+               int dlen;               /* len of data section */
+               u_char *data;           /* pointer to data */
+       } rr;
+       HEADER *hp;
+       u_char qbuf[MAX_HESRESP], abuf[MAX_HESRESP];
+       u_char *cp, *erdata, *eom;
+       char *dst, *edst, **list;
+       int ancount, qdcount;
+       int i, j, n, skip;
+
+       /*
+        * Construct the query and send it.
+        */
+       n = res_nmkquery(ctx->res, QUERY, name, class, T_TXT, NULL, 0,
+                        NULL, qbuf, MAX_HESRESP);
+       if (n < 0) {
+               errno = EMSGSIZE;
+               return (NULL);
+       }
+       n = res_nsend(ctx->res, qbuf, n, abuf, MAX_HESRESP);
+       if (n < 0) {
+               errno = ECONNREFUSED;
+               return (NULL);
+       }
+       if (n < HFIXEDSZ) {
+               errno = EMSGSIZE;
+               return (NULL);
+       }
+
+       /*
+        * OK, parse the result.
+        */
+       hp = (HEADER *) abuf;
+       ancount = ntohs(hp->ancount);
+       qdcount = ntohs(hp->qdcount);
+       cp = abuf + sizeof(HEADER);
+       eom = abuf + n;
+
+       /* Skip query, trying to get to the answer section which follows. */
+       for (i = 0; i < qdcount; i++) {
+               skip = dn_skipname(cp, eom);
+               if (skip < 0 || cp + skip + QFIXEDSZ > eom) {
+                       errno = EMSGSIZE;
+                       return (NULL);
+               }
+               cp += skip + QFIXEDSZ;
+       }
+
+       list = malloc((ancount + 1) * sizeof(char *));
+       if (!list) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       j = 0;
+       for (i = 0; i < ancount; i++) {
+               skip = dn_skipname(cp, eom);
+               if (skip < 0) {
+                       errno = EMSGSIZE;
+                       goto cleanup;
+               }
+               cp += skip;
+               if (cp + 3 * INT16SZ + INT32SZ > eom) {
+                       errno = EMSGSIZE;
+                       goto cleanup;
+               }
+               rr.type = ns_get16(cp);
+               cp += INT16SZ;
+               rr.class = ns_get16(cp);
+               cp += INT16SZ + INT32SZ;        /* skip the ttl, too */
+               rr.dlen = ns_get16(cp);
+               cp += INT16SZ;
+               if (cp + rr.dlen > eom) {
+                       errno = EMSGSIZE;
+                       goto cleanup;
+               }
+               rr.data = cp;
+               cp += rr.dlen;
+               if (rr.class != class || rr.type != T_TXT)
+                       continue;
+               if (!(list[j] = malloc(rr.dlen)))
+                       goto cleanup;
+               dst = list[j++];
+               edst = dst + rr.dlen;
+               erdata = rr.data + rr.dlen;
+               cp = rr.data;
+               while (cp < erdata) {
+                       n = (unsigned char) *cp++;
+                       if (cp + n > eom || dst + n > edst) {
+                               errno = EMSGSIZE;
+                               goto cleanup;
+                       }
+                       memcpy(dst, cp, n);
+                       cp += n;
+                       dst += n;
+               }
+               if (cp != erdata) {
+                       errno = EMSGSIZE;
+                       goto cleanup;
+               }
+               *dst = '\0';
+       }
+       list[j] = NULL;
+       if (j == 0) {
+               errno = ENOENT;
+               goto cleanup;
+       }
+       return (list);
+
+ cleanup:
+       for (i = 0; i < j; i++)
+               free(list[i]);
+       free(list);
+       return (NULL);
+}
+
+struct __res_state *
+__hesiod_res_get(void *context) {
+       struct hesiod_p *ctx = context;
+
+       if (!ctx->res) {
+               struct __res_state *res;
+               res = (struct __res_state *)malloc(sizeof *res);
+               if (res == NULL) {
+                       errno = ENOMEM;
+                       return (NULL);
+               }
+               memset(res, 0, sizeof *res);
+               __hesiod_res_set(ctx, res, free);
+       }
+
+       return (ctx->res);
+}
+
+void
+__hesiod_res_set(void *context, struct __res_state *res,
+                void (*free_res)(void *)) {
+       struct hesiod_p *ctx = context;
+
+       if (ctx->res && ctx->free_res) {
+               res_nclose(ctx->res);
+               (*ctx->free_res)(ctx->res);
+       }
+
+       ctx->res = res;
+       ctx->free_res = free_res;
+}
+
+static int
+init(struct hesiod_p *ctx) {
+       
+       if (!ctx->res && !__hesiod_res_get(ctx))
+               return (-1);
+
+       if (((ctx->res->options & RES_INIT) == 0) &&
+           (res_ninit(ctx->res) == -1))
+               return (-1);
+
+       return (0);
+}
diff --git a/lib/bind/irs/hesiod_p.h b/lib/bind/irs/hesiod_p.h
new file mode 100644 (file)
index 0000000..180e01d
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file is primarily maintained by <tytso@mit.edu> and <ghudson@mit.edu>.
+ */
+
+/*
+ * $Id: hesiod_p.h,v 1.1 2001/03/29 06:31:48 marka Exp $
+ */
+
+/*
+ * hesiod_p.h -- private definitions for the hesiod library
+ */
+
+#ifndef _HESIOD_P_H_INCLUDED
+#define _HESIOD_P_H_INCLUDED
+
+#define DEF_RHS                ".Athena.MIT.EDU"       /* Defaults if HESIOD_CONF */
+#define DEF_LHS                ".ns"                   /*    file is not */
+                                               /*    present. */
+struct hesiod_p {
+       char *          LHS;            /* normally ".ns" */
+       char *          RHS;            /* AKA the default hesiod domain */
+       struct __res_state * res;       /* resolver context */
+       void            (*free_res)(void *);
+       void            (*res_set)(struct hesiod_p *, struct __res_state *,
+                                  void (*)(void *));
+       struct __res_state * (*res_get)(struct hesiod_p *);
+};
+
+#define MAX_HESRESP    1024
+
+#endif /*_HESIOD_P_H_INCLUDED*/
diff --git a/lib/bind/irs/irp.c b/lib/bind/irs/irp.c
new file mode 100644 (file)
index 0000000..ed985d7
--- /dev/null
@@ -0,0 +1,592 @@
+/*
+ * Copyright (c) 1996, 1998 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(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: irp.c,v 1.1 2001/03/29 06:31:48 marka Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <syslog.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#include <isc/memcluster.h>
+
+#include <irs.h>
+#include <irp.h>
+
+#include "irs_p.h"
+#include "irp_p.h"
+
+#include "port_after.h"
+
+/* Forward. */
+
+static void            irp_close(struct irs_acc *);
+
+#define LINEINCR 128
+
+#if !defined(SUN_LEN)
+#define SUN_LEN(su) \
+       (sizeof (*(su)) - sizeof ((su)->sun_path) + strlen((su)->sun_path))
+#endif
+
+
+/* Public */
+
+
+/* send errors to syslog if true. */
+int irp_log_errors = 1;
+
+/*
+ * This module handles the irp module connection to irpd.
+ *
+ * The client expects a synchronous interface to functions like
+ * getpwnam(3), so we can't use the ctl_* i/o library on this end of
+ * the wire (it's used in the server).
+ */
+
+/*
+ * irs_acc *irs_irp_acc(const char *options);
+ *
+ *     Initialize the irp module.
+ */
+struct irs_acc *
+irs_irp_acc(const char *options) {
+       struct irs_acc *acc;
+       struct irp_p *irp;
+
+       UNUSED(options);
+
+       if (!(acc = memget(sizeof *acc))) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(acc, 0x5e, sizeof *acc);
+       if (!(irp = memget(sizeof *irp))) {
+               errno = ENOMEM;
+               free(acc);
+               return (NULL);
+       }
+       irp->inlast = 0;
+       irp->incurr = 0;
+       irp->fdCxn = -1;
+       acc->private = irp;
+
+#ifdef WANT_IRS_GR
+       acc->gr_map = irs_irp_gr;
+#else
+       acc->gr_map = NULL;
+#endif
+#ifdef WANT_IRS_PW
+       acc->pw_map = irs_irp_pw;
+#else
+       acc->pw_map = NULL;
+#endif
+       acc->sv_map = irs_irp_sv;
+       acc->pr_map = irs_irp_pr;
+       acc->ho_map = irs_irp_ho;
+       acc->nw_map = irs_irp_nw;
+       acc->ng_map = irs_irp_ng;
+       acc->close = irp_close;
+       return (acc);
+}
+
+
+int
+irs_irp_connection_setup(struct irp_p *cxndata, int *warned) {
+       if (irs_irp_is_connected(cxndata)) {
+               return (0);
+       } else if (irs_irp_connect(cxndata) != 0) {
+               if (warned != NULL && !*warned) {
+                       syslog(LOG_ERR, "irpd connection failed: %m\n");
+                       (*warned)++;
+               }
+
+               return (-1);
+       }
+
+       return (0);
+}
+
+
+/*
+ * int irs_irp_connect(void);
+ *
+ *     Sets up the connection to the remote irpd server.
+ *
+ * Returns:
+ *
+ *     0 on success, -1 on failure.
+ *
+ */
+int
+irs_irp_connect(struct irp_p *pvt) {
+       int flags;
+       struct sockaddr *addr;
+       struct sockaddr_in iaddr;
+#ifndef NO_SOCKADDR_UN
+       struct sockaddr_un uaddr;
+#endif
+       long ipaddr;
+       const char *irphost;
+       int code;
+       char text[256];
+       int socklen = 0;
+
+       if (pvt->fdCxn != -1) {
+               perror("fd != 1");
+               return (-1);
+       }
+
+#ifndef NO_SOCKADDR_UN
+       memset(&uaddr, 0, sizeof uaddr);
+#endif
+       memset(&iaddr, 0, sizeof iaddr);
+
+       irphost = getenv(IRPD_HOST_ENV);
+       if (irphost == NULL) {
+               irphost = "127.0.0.1";
+       }
+
+#ifndef NO_SOCKADDR_UN
+       if (irphost[0] == '/') {
+               addr = (struct sockaddr *)&uaddr;
+               strncpy(uaddr.sun_path, irphost, sizeof uaddr.sun_path);
+               uaddr.sun_family = AF_UNIX;
+               socklen = SUN_LEN(&uaddr);
+#ifdef HAVE_SA_LEN
+               uaddr.sun_len = socklen;
+#endif
+       } else
+#endif
+       {
+               if (inet_pton(AF_INET, irphost, &ipaddr) != 1) {
+                       errno = EADDRNOTAVAIL;
+                       perror("inet_pton");
+                       return (-1);
+               }
+
+               addr = (struct sockaddr *)&iaddr;
+               socklen = sizeof iaddr;
+#ifdef HAVE_SA_LEN
+               iaddr.sin_len = socklen;
+#endif
+               iaddr.sin_family = AF_INET;
+               iaddr.sin_port = htons(IRPD_PORT);
+               iaddr.sin_addr.s_addr = ipaddr;
+       }
+
+
+       pvt->fdCxn = socket(addr->sa_family, SOCK_STREAM, PF_UNSPEC);
+       if (pvt->fdCxn < 0) {
+               perror("socket");
+               return (-1);
+       }
+
+       if (connect(pvt->fdCxn, addr, socklen) != 0) {
+               perror("connect");
+               return (-1);
+       }
+
+       flags = fcntl(pvt->fdCxn, F_GETFL, 0);
+       if (flags < 0) {
+               close(pvt->fdCxn);
+               perror("close");
+               return (-1);
+       }
+
+#if 0
+       flags |= O_NONBLOCK;
+       if (fcntl(pvt->fdCxn, F_SETFL, flags) < 0) {
+               close(pvt->fdCxn);
+               perror("fcntl");
+               return (-1);
+       }
+#endif
+
+       code = irs_irp_read_response(pvt, text, sizeof text);
+       if (code != IRPD_WELCOME_CODE) {
+               if (irp_log_errors) {
+                       syslog(LOG_WARNING, "Connection failed: %s", text);
+               }
+               irs_irp_disconnect(pvt);
+               return (-1);
+       }
+
+       return (0);
+}
+
+
+
+/*
+ * int irs_irp_is_connected(struct irp_p *pvt);
+ *
+ * Returns:
+ *
+ *     Non-zero if streams are setup to remote.
+ *
+ */
+
+int
+irs_irp_is_connected(struct irp_p *pvt) {
+       return (pvt->fdCxn >= 0);
+}
+
+
+
+/*
+ * void
+ * irs_irp_disconnect(struct irp_p *pvt);
+ *
+ *     Closes streams to remote.
+ */
+
+void
+irs_irp_disconnect(struct irp_p *pvt) {
+       if (pvt->fdCxn != -1) {
+               close(pvt->fdCxn);
+               pvt->fdCxn = -1;
+       }
+}
+
+
+
+int
+irs_irp_read_line(struct irp_p *pvt, char *buffer, int len) {
+       char *realstart = &pvt->inbuffer[0];
+       char *p, *start, *end;
+       int spare;
+       int i;
+       int buffpos = 0;
+       int left = len - 1;
+
+       while (left > 0) {
+               start = p = &pvt->inbuffer[pvt->incurr];
+               end = &pvt->inbuffer[pvt->inlast];
+
+               while (p != end && *p != '\n')
+                       p++;
+
+               if (p == end) {
+                       /* Found no newline so shift data down if necessary
+                        * and append new data to buffer
+                        */
+                       if (start > realstart) {
+                               memmove(realstart, start, end - start);
+                               pvt->inlast = end - start;
+                               start = realstart;
+                               pvt->incurr = 0;
+                               end = &pvt->inbuffer[pvt->inlast];
+                       }
+
+                       spare = sizeof (pvt->inbuffer) - pvt->inlast;
+
+                       p = end;
+                       i = read(pvt->fdCxn, end, spare);
+                       if (i < 0) {
+                               close(pvt->fdCxn);
+                               pvt->fdCxn = -1;
+                               return (buffpos > 0 ? buffpos : -1);
+                       } else if (i == 0) {
+                               return (buffpos);
+                       }
+
+                       end += i;
+                       pvt->inlast += i;
+
+                       while (p != end && *p != '\n')
+                               p++;
+               }
+
+               if (p == end) {
+                       /* full buffer and still no newline */
+                       i = sizeof pvt->inbuffer;
+               } else {
+                       /* include newline */
+                       i = p - start + 1;
+               }
+
+               if (i > left)
+                       i = left;
+               memcpy(buffer + buffpos, start, i);
+               pvt->incurr += i;
+               buffpos += i;
+               buffer[buffpos] = '\0';
+
+               if (p != end) {
+                       left = 0;
+               } else {
+                       left -= i;
+               }
+       }
+
+#if 0
+       fprintf(stderr, "read line: %s\n", buffer);
+#endif
+       return (buffpos);
+}
+
+
+
+
+
+/*
+ * int irp_read_response(struct irp_p *pvt);
+ *
+ * Returns:
+ *
+ *     The number found at the beginning of the line read from
+ *     FP. 0 on failure(0 is not a legal response code). The
+ *     rest of the line is discarded.
+ *
+ */
+
+int
+irs_irp_read_response(struct irp_p *pvt, char *text, size_t textlen) {
+       char line[1024];
+       int code;
+       char *p;
+
+       if (irs_irp_read_line(pvt, line, sizeof line) <= 0) {
+               return (0);
+       }
+
+       p = strchr(line, '\n');
+       if (p == NULL) {
+               return (0);
+       }
+
+       if (sscanf(line, "%d", &code) != 1) {
+               code = 0;
+       } else if (text != NULL && textlen > 0) {
+               p = line;
+               while (isspace(*p)) p++;
+               while (isdigit(*p)) p++;
+               while (isspace(*p)) p++;
+               strncpy(text, p, textlen - 1);
+               p[textlen - 1] = '\0';
+       }
+
+       return (code);
+}
+
+
+
+/*
+ * char *irp_read_body(struct irp_p *pvt, size_t *size);
+ *
+ *     Read in the body of a response. Terminated by a line with
+ *     just a dot on it. Lines should be terminated with a CR-LF
+ *     sequence, but we're nt piccky if the CR is missing.
+ *     No leading dot escaping is done as the protcol doesn't
+ *     use leading dots anywhere.
+ *
+ * Returns:
+ *
+ *     Pointer to null-terminated buffer allocated by memget.
+ *     *SIZE is set to the length of the buffer.
+ *
+ */
+
+char *
+irs_irp_read_body(struct irp_p *pvt, size_t *size) {
+       char line[1024];
+       u_int linelen;
+       size_t len = LINEINCR;
+       char *buffer = memget(len);
+       int idx = 0;
+
+       for (;;) {
+               if (irs_irp_read_line(pvt, line, sizeof line) <= 0 ||
+                   strchr(line, '\n') == NULL)
+                       goto death;
+
+               linelen = strlen(line);
+
+               if (line[linelen - 1] != '\n')
+                       goto death;
+
+               /* We're not strict about missing \r. Should we be??  */
+               if (linelen > 2 && line[linelen - 2] == '\r') {
+                       line[linelen - 2] = '\n';
+                       line[linelen - 1] = '\0';
+                       linelen--;
+               }
+
+               if (linelen == 2 && line[0] == '.') {
+                       *size = len;
+                       buffer[idx] = '\0';
+
+                       return (buffer);
+               }
+
+               if (linelen > (len - (idx + 1))) {
+                       char *p = memget(len + LINEINCR);
+
+                       if (p == NULL)
+                               goto death;
+                       memcpy(p, buffer, len);
+                       memput(buffer, len);
+                       buffer = p;
+                       len += LINEINCR;
+               }
+
+               memcpy(buffer + idx, line, linelen);
+               idx += linelen;
+       }
+ death:
+       memput(buffer, len);
+       return (NULL);
+}
+
+
+/*
+ * int irs_irp_get_full_response(struct irp_p *pvt, int *code,
+ *                     char **body, size_t *bodylen);
+ *
+ *     Gets the response to a command. If the response indicates
+ *     there's a body to follow(code % 10 == 1), then the
+ *     body buffer is allcoated with memget and stored in
+ *     *BODY. The length of the allocated body buffer is stored
+ *     in *BODY. The caller must give the body buffer back to
+ *     memput when done. The results code is stored in *CODE.
+ *
+ * Returns:
+ *
+ *     0 if a result was read. -1 on some sort of failure.
+ *
+ */
+
+int
+irs_irp_get_full_response(struct irp_p *pvt, int *code, char *text,
+                         size_t textlen, char **body, size_t *bodylen) {
+       int result = irs_irp_read_response(pvt, text, textlen);
+
+       *body = NULL;
+
+       if (result == 0) {
+               return (-1);
+       }
+
+       *code = result;
+
+       /* Code that matches 2xx is a good result code.
+        * Code that matches xx1 means there's a response body coming.
+        */
+       if ((result / 100) == 2 && (result % 10) == 1) {
+               *body = irs_irp_read_body(pvt, bodylen);
+               if (*body == NULL) {
+                       return (-1);
+               }
+       }
+
+       return (0);
+}
+
+
+/*
+ * int irs_irp_send_command(struct irp_p *pvt, const char *fmt, ...);
+ *
+ *     Sends command to remote connected via the PVT
+ *     struture. FMT and args after it are fprintf-like
+ *     arguments for formatting.
+ *
+ * Returns:
+ *
+ *     0 on success, -1 on failure.
+ */
+
+int
+irs_irp_send_command(struct irp_p *pvt, const char *fmt, ...) {
+       va_list ap;
+       char buffer[1024];
+       int pos = 0;
+       int i, todo;
+
+
+       if (pvt->fdCxn < 0) {
+               return (-1);
+       }
+
+       va_start(ap, fmt);
+       todo = vsprintf(buffer, fmt, ap);
+       if (todo > (int)sizeof(buffer) - 3) {
+               syslog(LOG_CRIT, "memory overrun in irs_irp_send_command()");
+               exit(1);
+       }
+       strcat(buffer, "\r\n");
+       todo = strlen(buffer);
+
+       while (todo > 0) {
+               i = write(pvt->fdCxn, buffer + pos, todo);
+#if 0
+               /* XXX brister */
+               fprintf(stderr, "Wrote: \"");
+               fwrite(buffer + pos, sizeof (char), todo, stderr);
+               fprintf(stderr, "\"\n");
+#endif
+               if (i < 0) {
+                       close(pvt->fdCxn);
+                       pvt->fdCxn = -1;
+                       return (-1);
+               }
+               todo -= i;
+       }
+       va_end(ap);
+
+       return (0);
+}
+
+
+/* Methods */
+
+
+
+/*
+ * void irp_close(struct irs_acc *this)
+ *
+ */
+
+static void
+irp_close(struct irs_acc *this) {
+       struct irp_p *irp = (struct irp_p *)this->private;
+
+       if (irp != NULL) {
+               irs_irp_disconnect(irp);
+               memput(irp, sizeof *irp);
+       }
+
+       memput(this, sizeof *this);
+}
+
+
+
diff --git a/lib/bind/irs/irp_gr.c b/lib/bind/irs/irp_gr.c
new file mode 100644 (file)
index 0000000..1e2efa1
--- /dev/null
@@ -0,0 +1,405 @@
+/*
+ * Portions Copyright(c) 1996, 1998 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 rcsid[] = "$Id: irp_gr.c,v 1.1 2001/03/29 06:31:48 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* extern */
+
+#include "port_before.h"
+
+#ifndef WANT_IRS_PW
+static int __bind_irs_gr_unneeded;
+#else
+
+#include <syslog.h>
+#include <sys/param.h>
+#include <sys/types.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <syslog.h>
+
+#include <irs.h>
+#include <irp.h>
+#include <isc/memcluster.h>
+#include <isc/irpmarshall.h>
+
+#include "irs_p.h"
+#include "lcl_p.h"
+#include "irp_p.h"
+
+#include "port_after.h"
+
+
+/* Types. */
+
+/*
+ * Module for the getnetgrent(3) family to use when connected to a
+ * remote irp daemon.
+ *
+ * See irpd.c for justification of caching done here.
+ *
+ */
+
+struct pvt {
+       struct irp_p   *girpdata;       /* global IRP data */
+       int             warned;
+       struct group    group;
+};
+
+/* Forward. */
+
+static void            gr_close(struct irs_gr *);
+static struct group *  gr_next(struct irs_gr *);
+static struct group *  gr_byname(struct irs_gr *, const char *);
+static struct group *  gr_bygid(struct irs_gr *, gid_t);
+static void            gr_rewind(struct irs_gr *);
+static void            gr_minimize(struct irs_gr *);
+
+/* Private */
+static void            free_group(struct group *gr);
+
+
+/* Public. */
+
+
+
+
+
+/*
+ * struct irs_gr * irs_irp_gr(struct irs_acc *this)
+ *
+ * Notes:
+ *
+ *     Initialize the group sub-module.
+ *
+ * Notes:
+ *
+ *     Module data.
+ *
+ */
+
+struct irs_gr *
+irs_irp_gr(struct irs_acc *this) {
+       struct irs_gr *gr;
+       struct pvt *pvt;
+
+       if (!(gr = memget(sizeof *gr))) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(gr, 0x0, sizeof *gr);
+
+       if (!(pvt = memget(sizeof *pvt))) {
+               memput(gr, sizeof *gr);
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pvt, 0x0, sizeof *pvt);
+       pvt->girpdata = this->private;
+
+       gr->private = pvt;
+       gr->close = gr_close;
+       gr->next = gr_next;
+       gr->byname = gr_byname;
+       gr->bygid = gr_bygid;
+       gr->rewind = gr_rewind;
+       gr->list = make_group_list;
+       gr->minimize = gr_minimize;
+       return (gr);
+}
+
+/* Methods. */
+
+
+
+/*
+ * void gr_close(struct irs_gr *this)
+ *
+ * Notes:
+ *
+ *     Close the sub-module.
+ *
+ */
+
+static void
+gr_close(struct irs_gr *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       gr_minimize(this);
+
+       memput(pvt, sizeof *pvt);
+       memput(this, sizeof *this);
+}
+
+
+
+
+/*
+ * struct group * gr_next(struct irs_gr *this)
+ *
+ * Notes:
+ *
+ *     Gets the next group out of the cached data and returns it.
+ *
+ */
+
+static struct group *
+gr_next(struct irs_gr *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct group *gr = &pvt->group;
+       char *body;
+       size_t bodylen;
+       int code;
+       char text[256];
+
+       if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+               return (NULL);
+       }
+
+       if (irs_irp_send_command(pvt->girpdata, "getgrent") != 0) {
+               return (NULL);
+       }
+
+       if (irs_irp_get_full_response(pvt->girpdata, &code,
+                                     text, sizeof text,
+                                     &body, &bodylen) != 0) {
+               if (irp_log_errors) {
+                       syslog(LOG_WARNING, "getgrent failed: %s", text);
+               }
+               return (NULL);
+       }
+
+       if (code == IRPD_GETGROUP_OK) {
+               free_group(gr);
+               if (irp_unmarshall_gr(gr, body) != 0) {
+                       gr = NULL;
+               }
+       } else {
+               gr = NULL;
+       }
+
+       if (body != NULL) {
+               memput(body, bodylen);
+       }
+
+       return (gr);
+}
+
+
+
+
+
+/*
+ * struct group * gr_byname(struct irs_gr *this, const char *name)
+ *
+ * Notes:
+ *
+ *     Gets a group by name from irpd and returns it.
+ *
+ */
+
+static struct group *
+gr_byname(struct irs_gr *this, const char *name) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct group *gr = &pvt->group;
+       char *body;
+       size_t bodylen;
+       int code;
+       char text[256];
+
+
+       if (gr->gr_name != NULL && strcmp(name, gr->gr_name) == 0) {
+               return (gr);
+       }
+
+       if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+               return (NULL);
+       }
+
+       if (irs_irp_send_command(pvt->girpdata, "getgrnam %s", name) != 0)
+               return (NULL);
+
+       if (irs_irp_get_full_response(pvt->girpdata, &code,
+                                     text, sizeof text,
+                                     &body, &bodylen) != 0) {
+               return (NULL);
+       }
+
+       if (code == IRPD_GETGROUP_OK) {
+               free_group(gr);
+               if (irp_unmarshall_gr(gr, body) != 0) {
+                       gr = NULL;
+               }
+       } else {
+               gr = NULL;
+       }
+
+       if (body != NULL) {
+               memput(body, bodylen);
+       }
+
+       return (gr);
+}
+
+
+
+
+
+/*
+ * struct group * gr_bygid(struct irs_gr *this, gid_t gid)
+ *
+ * Notes:
+ *
+ *     Gets a group by gid from irpd and returns it.
+ *
+ */
+
+static struct group *
+gr_bygid(struct irs_gr *this, gid_t gid) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct group *gr = &pvt->group;
+       char *body;
+       size_t bodylen;
+       int code;
+       char text[256];
+
+       if (gr->gr_name != NULL && (gid_t)gr->gr_gid == gid) {
+               return (gr);
+       }
+
+       if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+               return (NULL);
+       }
+
+       if (irs_irp_send_command(pvt->girpdata, "getgrgid %d", gid) != 0)
+               return (NULL);
+
+       if (irs_irp_get_full_response(pvt->girpdata, &code,
+                                     text, sizeof text,
+                                     &body, &bodylen) != 0) {
+               return (NULL);
+       }
+
+       if (code == IRPD_GETGROUP_OK) {
+               free_group(gr);
+               if (irp_unmarshall_gr(gr, body) != 0) {
+                       gr = NULL;
+               }
+       } else {
+               gr = NULL;
+       }
+
+       if (body != NULL) {
+               memput(body, bodylen);
+       }
+
+       return (gr);
+}
+
+
+
+
+/*
+ * void gr_rewind(struct irs_gr *this)
+ *
+ */
+
+static void
+gr_rewind(struct irs_gr *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       char text[256];
+       int code;
+
+       if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+               return;
+       }
+
+       if (irs_irp_send_command(pvt->girpdata, "setgrent") != 0) {
+               return;
+       }
+
+       code = irs_irp_read_response(pvt->girpdata, text, sizeof text);
+       if (code != IRPD_GETGROUP_SETOK) {
+               if (irp_log_errors) {
+                       syslog(LOG_WARNING, "setgrent failed: %s", text);
+               }
+       }
+
+       return;
+}
+
+
+
+
+/*
+ * void gr_minimize(struct irs_gr *this)
+ *
+ * Notes:
+ *
+ *     Frees up cached data and disconnects(if necessary) from the remote.
+ *
+ */
+
+static void
+gr_minimize(struct irs_gr *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       free_group(&pvt->group);
+       irs_irp_disconnect(pvt->girpdata);
+}
+
+/* Private. */
+
+
+
+/*
+ * static void free_group(struct group *gr);
+ *
+ *     Deallocate all the memory irp_unmarshall_gr allocated.
+ *
+ */
+
+static void
+free_group(struct group *gr) {
+       char **p;
+
+       if (gr == NULL)
+               return;
+
+       if (gr->gr_name != NULL)
+               free(gr->gr_name);
+
+       if (gr->gr_passwd != NULL)
+               free(gr->gr_passwd);
+
+       for (p = gr->gr_mem ; p != NULL && *p != NULL ; p++)
+               free(*p);
+
+       if (p != NULL)
+               free(p);
+}
+
+
+#endif /* WANT_IRS_GR */
diff --git a/lib/bind/irs/irp_ho.c b/lib/bind/irs/irp_ho.c
new file mode 100644 (file)
index 0000000..6556b8f
--- /dev/null
@@ -0,0 +1,429 @@
+/*
+ * Portions Copyright (c) 1996,1998 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 rcsid[] = "$Id: irp_ho.c,v 1.1 2001/03/29 06:31:49 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* Imports. */
+
+#include "port_before.h"
+
+#include <syslog.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+
+#include <irs.h>
+#include <irp.h>
+#include <isc/irpmarshall.h>
+#include <isc/memcluster.h>
+
+#include "irs_p.h"
+#include "dns_p.h"
+#include "irp_p.h"
+
+#include "port_after.h"
+
+/* Definitions. */
+
+#define        MAXALIASES      35
+#define        MAXADDRS        35
+#define        Max(a,b)        ((a) > (b) ? (a) : (b))
+
+
+struct pvt {
+       struct irp_p           *girpdata;
+       int                     warned;
+       struct hostent          host;
+};
+
+/* Forward. */
+
+static void            ho_close(struct irs_ho *this);
+static struct hostent *        ho_byname(struct irs_ho *this, const char *name);
+static struct hostent *        ho_byname2(struct irs_ho *this, const char *name,
+                                  int af);
+static struct hostent *        ho_byaddr(struct irs_ho *this, const void *addr,
+                                 int len, int af);
+static struct hostent *        ho_next(struct irs_ho *this);
+static void            ho_rewind(struct irs_ho *this);
+static void            ho_minimize(struct irs_ho *this);
+
+static void            free_host(struct hostent *ho);
+static struct addrinfo * ho_addrinfo(struct irs_ho *this, const char *name,
+                                    const struct addrinfo *pai);
+
+/* Public. */
+
+
+
+/*
+ * struct irs_ho * irs_irp_ho(struct irs_acc *this)
+ *
+ * Notes:
+ *
+ *     Initializes the irp_ho module.
+ *
+ */
+
+struct irs_ho *
+irs_irp_ho(struct irs_acc *this) {
+       struct irs_ho *ho;
+       struct pvt *pvt;
+
+       if (!(ho = memget(sizeof *ho))) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(ho, 0x0, sizeof *ho);
+
+       if (!(pvt = memget(sizeof *pvt))) {
+               memput(ho, sizeof *ho);
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pvt, 0, sizeof *pvt);
+       pvt->girpdata = this->private;
+
+       ho->private = pvt;
+       ho->close = ho_close;
+       ho->byname = ho_byname;
+       ho->byname2 = ho_byname2;
+       ho->byaddr = ho_byaddr;
+       ho->next = ho_next;
+       ho->rewind = ho_rewind;
+       ho->minimize = ho_minimize;
+       ho->addrinfo = ho_addrinfo;
+
+       return (ho);
+}
+
+/* Methods. */
+
+
+
+/*
+ * void ho_close(struct irs_ho *this)
+ *
+ * Notes:
+ *
+ *     Closes down the module.
+ *
+ */
+
+static void
+ho_close(struct irs_ho *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       ho_minimize(this);
+
+       free_host(&pvt->host);
+
+       memput(pvt, sizeof *pvt);
+       memput(this, sizeof *this);
+}
+
+
+
+/*
+ * struct hostent * ho_byname(struct irs_ho *this, const char *name)
+ *
+ */
+
+static struct hostent *
+ho_byname(struct irs_ho *this, const char *name) {
+       return (ho_byname2(this, name, AF_INET));
+}
+
+
+
+
+
+/*
+ * struct hostent * ho_byname2(struct irs_ho *this, const char *name, int af)
+ *
+ */
+
+static struct hostent *
+ho_byname2(struct irs_ho *this, const char *name, int af) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct hostent *ho = &pvt->host;
+       char *body = NULL;
+       size_t bodylen;
+       int code;
+       char text[256];
+
+       if (ho->h_name != NULL &&
+           strcmp(name, ho->h_name) == 0 &&
+           af == ho->h_addrtype) {
+               return (ho);
+       }
+
+       if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+               return (NULL);
+       }
+
+       if (irs_irp_send_command(pvt->girpdata, "gethostbyname2 %s %s",
+                                name, ADDR_T_STR(af)) != 0)
+               return (NULL);
+
+       if (irs_irp_get_full_response(pvt->girpdata, &code,
+                                     text, sizeof text,
+                                     &body, &bodylen) != 0) {
+               return (NULL);
+       }
+
+       if (code == IRPD_GETHOST_OK) {
+               free_host(ho);
+               if (irp_unmarshall_ho(ho, body) != 0) {
+                       ho = NULL;
+               }
+       } else {
+               ho = NULL;
+       }
+
+       if (body != NULL) {
+               memput(body, bodylen);
+       }
+
+       return (ho);
+}
+
+
+
+/*
+ * struct hostent * ho_byaddr(struct irs_ho *this, const void *addr,
+ *                        int len, int af)
+ *
+ */
+
+static struct hostent *
+ho_byaddr(struct irs_ho *this, const void *addr, int len, int af) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct hostent *ho = &pvt->host;
+       char *body = NULL;
+       size_t bodylen;
+       int code;
+       char **p;
+       char paddr[MAXPADDRSIZE];
+       char text[256];
+
+       if (ho->h_name != NULL &&
+           af == ho->h_addrtype &&
+           len == ho->h_length) {
+               for (p = ho->h_addr_list ; *p != NULL ; p++) {
+                       if (memcmp(*p, addr, len) == 0)
+                               return (ho);
+               }
+       }
+
+       if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+               return (NULL);
+       }
+
+       if (inet_ntop(af, addr, paddr, sizeof paddr) == NULL) {
+               return (NULL);
+       }
+
+       if (irs_irp_send_command(pvt->girpdata, "gethostbyaddr %s %s",
+                                paddr, ADDR_T_STR(af)) != 0) {
+               return (NULL);
+       }
+
+       if (irs_irp_get_full_response(pvt->girpdata, &code,
+                                     text, sizeof text,
+                                     &body, &bodylen) != 0) {
+               return (NULL);
+       }
+
+       if (code == IRPD_GETHOST_OK) {
+               free_host(ho);
+               if (irp_unmarshall_ho(ho, body) != 0) {
+                       ho = NULL;
+               }
+       } else {
+               ho = NULL;
+       }
+
+       if (body != NULL) {
+               memput(body, bodylen);
+       }
+
+       return (ho);
+}
+
+
+
+
+
+/*
+ * struct hostent * ho_next(struct irs_ho *this)
+ *
+ * Notes:
+ *
+ *     The implementation for gethostent(3). The first time it's
+ *     called all the data is pulled from the remote(i.e. what
+ *     the maximum number of gethostent(3) calls would return)
+ *     and that data is cached.
+ *
+ */
+
+static struct hostent *
+ho_next(struct irs_ho *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct hostent *ho = &pvt->host;
+       char *body;
+       size_t bodylen;
+       int code;
+       char text[256];
+
+       if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+               return (NULL);
+       }
+
+       if (irs_irp_send_command(pvt->girpdata, "gethostent") != 0) {
+               return (NULL);
+       }
+
+       if (irs_irp_get_full_response(pvt->girpdata, &code,
+                                     text, sizeof text,
+                                     &body, &bodylen) != 0) {
+               return (NULL);
+       }
+
+       if (code == IRPD_GETHOST_OK) {
+               free_host(ho);
+               if (irp_unmarshall_ho(ho, body) != 0) {
+                       ho = NULL;
+               }
+       } else {
+               ho = NULL;
+       }
+
+       if (body != NULL) {
+               memput(body, bodylen);
+       }
+
+       return (ho);
+}
+
+
+
+
+
+/*
+ * void ho_rewind(struct irs_ho *this)
+ *
+ */
+
+static void
+ho_rewind(struct irs_ho *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       char text[256];
+       int code;
+
+       if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+               return;
+       }
+
+       if (irs_irp_send_command(pvt->girpdata, "sethostent") != 0) {
+               return;
+       }
+
+       code = irs_irp_read_response(pvt->girpdata, text, sizeof text);
+       if (code != IRPD_GETHOST_SETOK) {
+               if (irp_log_errors) {
+                       syslog(LOG_WARNING, "sethostent failed: %s", text);
+               }
+       }
+
+       return;
+}
+
+
+
+
+/*
+ * void ho_minimize(struct irs_ho *this)
+ *
+ */
+
+static void
+ho_minimize(struct irs_ho *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       free_host(&pvt->host);
+
+       irs_irp_disconnect(pvt->girpdata);
+}
+
+
+
+
+/*
+ * void free_host(struct hostent *ho)
+ *
+ */
+
+static void
+free_host(struct hostent *ho) {
+       char **p;
+
+       if (ho == NULL) {
+               return;
+       }
+
+       if (ho->h_name != NULL)
+               free(ho->h_name);
+
+       if (ho->h_aliases != NULL) {
+               for (p = ho->h_aliases ; *p != NULL ; p++)
+                       free(*p);
+               free(ho->h_aliases);
+       }
+
+       if (ho->h_addr_list != NULL) {
+               for (p = ho->h_addr_list ; *p != NULL ; p++)
+                       free(*p);
+               free(ho->h_addr_list);
+       }
+}
+
+/* dummy */
+static struct addrinfo *
+ho_addrinfo(struct irs_ho *this, const char *name, const struct addrinfo *pai)
+{
+       UNUSED(this);
+       UNUSED(name);
+       UNUSED(pai);
+       return(NULL);
+}
diff --git a/lib/bind/irs/irp_ng.c b/lib/bind/irs/irp_ng.c
new file mode 100644 (file)
index 0000000..86192ec
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 1996, 1998 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(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: irp_ng.c,v 1.1 2001/03/29 06:31:49 marka Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <syslog.h>
+
+#include <irs.h>
+#include <irp.h>
+#include <isc/memcluster.h>
+#include <isc/irpmarshall.h>
+
+#include "irs_p.h"
+#include "irp_p.h"
+
+#include "port_after.h"
+
+/* Definitions */
+
+struct pvt {
+       struct irp_p           *girpdata;
+       int                     warned;
+};
+
+
+/* Forward */
+
+static void            ng_rewind(struct irs_ng *, const char*);
+static void            ng_close(struct irs_ng *);
+static int             ng_next(struct irs_ng *, const char **, const char **,
+                               const char **);
+static int             ng_test(struct irs_ng *, const char *,
+                               const char *, const char *,
+                               const char *);
+static void            ng_minimize(struct irs_ng *);
+
+
+/* Public */
+
+
+
+/*
+ * struct irs_ng * irs_irp_ng(struct irs_acc *this)
+ *
+ * Notes:
+ *
+ *     Intialize the irp netgroup module.
+ *
+ */
+
+struct irs_ng *
+irs_irp_ng(struct irs_acc *this) {
+       struct irs_ng *ng;
+       struct pvt *pvt;
+
+       if (!(ng = memget(sizeof *ng))) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(ng, 0x5e, sizeof *ng);
+
+       if (!(pvt = memget(sizeof *pvt))) {
+               memput(ng, sizeof *ng);
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pvt, 0, sizeof *pvt);
+       pvt->girpdata = this->private;
+
+       ng->private = pvt;
+       ng->close = ng_close;
+       ng->next = ng_next;
+       ng->test = ng_test;
+       ng->rewind = ng_rewind;
+       ng->minimize = ng_minimize;
+       return (ng);
+}
+
+/* Methods */
+
+
+
+/*
+ * void ng_close(struct irs_ng *this)
+ *
+ */
+
+static void
+ng_close(struct irs_ng *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       ng_minimize(this);
+
+       memput(pvt, sizeof *pvt);
+       memput(this, sizeof *this);
+}
+
+
+
+
+/*
+ * void ng_rewind(struct irs_ng *this, const char *group)
+ *
+ *
+ */
+
+static void
+ng_rewind(struct irs_ng *this, const char *group) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       char text[256];
+       int code;
+
+       if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+               return;
+       }
+
+       if (irs_irp_send_command(pvt->girpdata,
+                                "setnetgrent %s", group) != 0) {
+               return;
+       }
+
+       code = irs_irp_read_response(pvt->girpdata, text, sizeof text);
+       if (code != IRPD_GETNETGR_SETOK) {
+               if (irp_log_errors) {
+                       syslog(LOG_WARNING, "setnetgrent(%s) failed: %s",
+                              group, text);
+               }
+       }
+
+       return;
+}
+
+
+
+
+/*
+ * int ng_next(struct irs_ng *this, const char **host, const char **user,
+ *            const char **domain)
+ *
+ * Notes:
+ *
+ *     Get the next netgroup item from the cache.
+ *
+ */
+
+static int
+ng_next(struct irs_ng *this, const char **host, const char **user,
+        const char **domain)
+{
+       struct pvt *pvt = (struct pvt *)this->private;
+       int code;
+       char *body = NULL;
+       size_t bodylen;
+       int rval = 0;
+       char text[256];
+
+       if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+               return (0);
+       }
+
+       if (irs_irp_send_command(pvt->girpdata, "getnetgrent") != 0)
+               return (0);
+
+       if (irs_irp_get_full_response(pvt->girpdata, &code,
+                                     text, sizeof text,
+                                     &body, &bodylen) != 0) {
+               return (0);
+       }
+
+       if (code == IRPD_GETNETGR_OK) {
+               if (irp_unmarshall_ng(host, user, domain, body) == 0) {
+                       rval = 1;
+               }
+       }
+
+       if (body != NULL) {
+               memput(body, bodylen);
+       }
+
+       return (rval);
+}
+
+
+
+/*
+ * int ng_test(struct irs_ng *this, const char *name, const char *host,
+ *             const char *user, const char *domain)
+ *
+ * Notes:
+ *
+ *     Search for a match in a netgroup.
+ *
+ */
+
+static int
+ng_test(struct irs_ng *this, const char *name,
+       const char *host, const char *user, const char *domain)
+{
+       struct pvt *pvt = (struct pvt *)this->private;
+       char *body = NULL;
+       size_t bodylen = 0;
+       int code;
+       char text[256];
+       int rval = 0;
+
+       UNUSED(name);
+
+       if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+               return (0);
+       }
+
+       if (irp_marshall_ng(host, user, domain, &body, &bodylen) != 0) {
+               return (0);
+       }
+
+       if (irs_irp_send_command(pvt->girpdata, "innetgr %s", body) == 0) {
+               memput(body, bodylen);
+
+               code = irs_irp_read_response(pvt->girpdata, text, sizeof text);
+               if (code == IRPD_GETNETGR_MATCHES) {
+                       rval = 1;
+               }
+       }
+
+       return (rval);
+}
+
+
+
+
+/*
+ * void ng_minimize(struct irs_ng *this)
+ *
+ */
+
+static void
+ng_minimize(struct irs_ng *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       irs_irp_disconnect(pvt->girpdata);
+}
+
+
+
+
+/* Private */
+
diff --git a/lib/bind/irs/irp_nw.c b/lib/bind/irs/irp_nw.c
new file mode 100644 (file)
index 0000000..9255557
--- /dev/null
@@ -0,0 +1,375 @@
+/*
+ * Portions Copyright (c) 1996,1998 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 rcsid[] = "$Id: irp_nw.c,v 1.1 2001/03/29 06:31:49 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#if 0
+
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <syslog.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+
+#include <irs.h>
+#include <irp.h>
+#include <isc/irpmarshall.h>
+
+#include <isc/memcluster.h>
+#include <isc/misc.h>
+
+#include "irs_p.h"
+#include "lcl_p.h"
+#include "irp_p.h"
+
+#include "port_after.h"
+
+#define MAXALIASES 35
+#define MAXADDRSIZE 4
+
+struct pvt {
+       struct irp_p           *girpdata;
+       int                     warned;
+       struct nwent            net;
+};
+
+/* Forward */
+
+static void            nw_close(struct irs_nw *);
+static struct nwent *  nw_byname(struct irs_nw *, const char *, int);
+static struct nwent *  nw_byaddr(struct irs_nw *, void *, int, int);
+static struct nwent *  nw_next(struct irs_nw *);
+static void            nw_rewind(struct irs_nw *);
+static void            nw_minimize(struct irs_nw *);
+
+static void            free_nw(struct nwent *nw);
+
+
+/* Public */
+
+
+
+/*
+ * struct irs_nw * irs_irp_nw(struct irs_acc *this) 
+ *
+ */
+
+struct irs_nw *
+irs_irp_nw(struct irs_acc *this) {
+       struct irs_nw *nw;
+       struct pvt *pvt;
+
+       if (!(pvt = memget(sizeof *pvt))) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pvt, 0, sizeof *pvt);
+
+       if (!(nw = memget(sizeof *nw))) {
+               memput(pvt, sizeof *pvt);
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(nw, 0x0, sizeof *nw);
+       pvt->girpdata = this->private;
+
+       nw->private = pvt;
+       nw->close = nw_close;
+       nw->byname = nw_byname;
+       nw->byaddr = nw_byaddr;
+       nw->next = nw_next;
+       nw->rewind = nw_rewind;
+       nw->minimize = nw_minimize;
+       return (nw);
+}
+
+/* Methods */
+
+
+
+/*
+ * void nw_close(struct irs_nw *this) 
+ *
+ */
+
+static void
+nw_close(struct irs_nw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       nw_minimize(this);
+
+       free_nw(&pvt->net);
+
+       memput(pvt, sizeof *pvt);
+       memput(this, sizeof *this);
+}
+
+
+
+
+/*
+ * struct nwent * nw_byaddr(struct irs_nw *this, void *net, 
+ *                             int length, int type) 
+ *
+ */
+
+static struct nwent *
+nw_byaddr(struct irs_nw *this, void *net, int length, int type) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct nwent *nw = &pvt->net;
+       char *body = NULL;
+       size_t bodylen;
+       int code;
+       char paddr[24];                 /* bigenough for ip4 w/ cidr spec. */
+       char text[256];
+
+       if (inet_net_ntop(type, net, length, paddr, sizeof paddr) == NULL) {
+               return (NULL);
+       }
+
+       if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+               return (NULL);
+       }
+
+       if (irs_irp_send_command(pvt->girpdata, "getnetbyaddr %s %s",
+                                paddr, ADDR_T_STR(type)) != 0)
+               return (NULL);
+
+       if (irs_irp_get_full_response(pvt->girpdata, &code,
+                                     text, sizeof text,
+                                     &body, &bodylen) != 0) {
+               return (NULL);
+       }
+
+       if (code == IRPD_GETNET_OK) {
+               free_nw(nw);
+               if (irp_unmarshall_nw(nw, body) != 0) {
+                       nw = NULL;
+               }
+       } else {
+               nw = NULL;
+       }
+               
+       if (body != NULL) {
+               memput(body, bodylen);
+       }
+       
+       return (nw);
+}
+
+
+
+
+/*
+ * struct nwent * nw_byname(struct irs_nw *this, const char *name, int type) 
+ *
+ */
+
+static struct nwent *
+nw_byname(struct irs_nw *this, const char *name, int type) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct nwent *nw = &pvt->net;
+       char *body = NULL;
+       size_t bodylen;
+       int code;
+       char text[256];
+
+       if (nw->n_name != NULL &&
+           strcmp(name, nw->n_name) == 0 &&
+           nw->n_addrtype == type) {
+               return (nw);
+       }
+
+       if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+               return (NULL);
+       }
+
+       if (irs_irp_send_command(pvt->girpdata, "getnetbyname %s", name) != 0)
+               return (NULL);
+
+       if (irs_irp_get_full_response(pvt->girpdata, &code,
+                                     text, sizeof text,
+                                     &body, &bodylen) != 0) {
+               return (NULL);
+       }
+
+       if (code == IRPD_GETNET_OK) {
+               free_nw(nw);
+               if (irp_unmarshall_nw(nw, body) != 0) {
+                       nw = NULL;
+               }
+       } else {
+               nw = NULL;
+       }
+       
+       if (body != NULL) {
+               memput(body, bodylen);
+       }
+       
+       return (nw);
+}
+
+
+
+
+/*
+ * void nw_rewind(struct irs_nw *this) 
+ *
+ */
+
+static void
+nw_rewind(struct irs_nw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       char text[256];
+       int code;
+
+       if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+               return;
+       }
+
+       if (irs_irp_send_command(pvt->girpdata, "setnetent") != 0) {
+               return;
+       }
+
+       code = irs_irp_read_response(pvt->girpdata, text, sizeof text);
+       if (code != IRPD_GETNET_SETOK) {
+               if (irp_log_errors) {
+                       syslog(LOG_WARNING, "setnetent failed: %s", text);
+               }
+       }
+       
+       return;
+}
+
+
+
+
+
+
+/*
+ * struct nwent * nw_next(struct irs_nw *this) 
+ *
+ * Notes:
+ *     
+ *     Prepares the cache if necessary and returns the first, or 
+ *     next item from it.
+ */
+
+static struct nwent *
+nw_next(struct irs_nw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct nwent *nw = &pvt->net;
+       char *body;
+       size_t bodylen;
+       int code;
+       char text[256];
+
+       if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+               return (NULL);
+       }
+
+       if (irs_irp_send_command(pvt->girpdata, "getnetent") != 0) {
+               return (NULL);
+       }
+
+       if (irs_irp_get_full_response(pvt->girpdata, &code,
+                                     text, sizeof text,
+                                     &body, &bodylen) != 0) {
+               return (NULL);
+       }
+
+       if (code == IRPD_GETNET_OK) {
+               free_nw(nw);
+               if (irp_unmarshall_nw(nw, body) != 0) {
+                       nw = NULL;
+               }
+       } else {
+               nw = NULL;
+       }
+
+       return (nw);
+}
+
+
+
+
+
+
+/*
+ * void nw_minimize(struct irs_nw *this) 
+ *
+ */
+
+static void
+nw_minimize(struct irs_nw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       irs_irp_disconnect(pvt->girpdata);
+}
+
+
+
+
+/* private. */
+
+
+
+/*
+ * static void free_passwd(struct passwd *pw);
+ *
+ *     deallocate all the memory irp_unmarshall_pw allocated.
+ *
+ */
+
+static void
+free_nw(struct nwent *nw) {
+       char **p;
+
+       if (nw == NULL)
+               return;
+
+       if (nw->n_name != NULL)
+               free(nw->n_name);
+
+       if (nw->n_aliases != NULL) {
+               for (p = nw->n_aliases ; *p != NULL ; p++) {
+                       free(*p);
+               }
+               free(nw->n_aliases);
+       }
+
+       if (nw->n_addr != NULL)
+               free(nw->n_addr);
+}
diff --git a/lib/bind/irs/irp_p.h b/lib/bind/irs/irp_p.h
new file mode 100644 (file)
index 0000000..5fa881b
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1996 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.
+ */
+
+/*
+ * $Id: irp_p.h,v 1.1 2001/03/29 06:31:49 marka Exp $
+ */
+
+#ifndef _IRP_P_H_INCLUDED
+#define _IRP_P_H_INCLUDED
+
+#include <stdio.h>
+
+struct irp_p {
+       char inbuffer[1024];
+       int inlast; /* index of one past the last char in buffer */
+       int incurr; /* index of the next char to be read from buffer */
+
+       int fdCxn;
+};
+
+/*
+ * Externs.
+ */
+
+extern struct irs_acc *        irs_irp_acc __P((const char *));
+extern struct irs_gr * irs_irp_gr __P((struct irs_acc *));
+extern struct irs_pw * irs_irp_pw __P((struct irs_acc *));
+extern struct irs_sv * irs_irp_sv __P((struct irs_acc *));
+extern struct irs_pr * irs_irp_pr __P((struct irs_acc *));
+extern struct irs_ho * irs_irp_ho __P((struct irs_acc *));
+extern struct irs_nw * irs_irp_nw __P((struct irs_acc *));
+extern struct irs_ng * irs_irp_ng __P((struct irs_acc *));
+
+int irs_irp_connect(struct irp_p *pvt);
+int irs_irp_is_connected(struct irp_p *pvt);
+void irs_irp_disconnect(struct irp_p *pvt);
+int irs_irp_read_response(struct irp_p *pvt, char *text, size_t textlen);
+char *irs_irp_read_body(struct irp_p *pvt, size_t *size);
+int irs_irp_get_full_response(struct irp_p *pvt, int *code,
+                             char *text, size_t textlen,
+                             char **body, size_t *bodylen);
+int irs_irp_send_command(struct irp_p *pvt, const char *fmt, ...);
+
+
+extern int irp_log_errors;
+
+#endif
diff --git a/lib/bind/irs/irp_pr.c b/lib/bind/irs/irp_pr.c
new file mode 100644 (file)
index 0000000..8b9e9a9
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+ * Portions Copyright (c) 1996 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 rcsid[] = "$Id: irp_pr.c,v 1.1 2001/03/29 06:31:49 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* extern */
+
+#include "port_before.h"
+
+#include <syslog.h>
+#include <sys/types.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <syslog.h>
+
+#include <irs.h>
+#include <irp.h>
+#include <isc/memcluster.h>
+#include <isc/irpmarshall.h>
+
+#include "irs_p.h"
+#include "lcl_p.h"
+#include "irp_p.h"
+
+#include "port_after.h"
+
+
+#define MAXALIASES     35
+
+/* Types */
+
+struct pvt {
+       struct irp_p           *girpdata;
+       int                     warned;
+       struct protoent         proto;
+};
+
+/* Forward */
+
+static void                    pr_close(struct irs_pr *);
+static struct protoent *       pr_next(struct irs_pr *);
+static struct protoent *       pr_byname(struct irs_pr *, const char *);
+static struct protoent *       pr_bynumber(struct irs_pr *, int);
+static void                    pr_rewind(struct irs_pr *);
+static void                    pr_minimize(struct irs_pr *);
+
+static void                    free_proto(struct protoent *pr);
+
+/* Public */
+
+
+
+/*
+ * struct irs_pr * irs_irp_pr(struct irs_acc *this)
+ *
+ */
+
+struct irs_pr *
+irs_irp_pr(struct irs_acc *this) {
+       struct irs_pr *pr;
+       struct pvt *pvt;
+
+       if (!(pr = memget(sizeof *pr))) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pr, 0x0, sizeof *pr);
+
+       if (!(pvt = memget(sizeof *pvt))) {
+               memput(pr, sizeof *pr);
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pvt, 0, sizeof *pvt);
+       pvt->girpdata = this->private;
+
+       pr->private = pvt;
+       pr->close = pr_close;
+       pr->byname = pr_byname;
+       pr->bynumber = pr_bynumber;
+       pr->next = pr_next;
+       pr->rewind = pr_rewind;
+       pr->minimize = pr_minimize;
+       return (pr);
+}
+
+/* Methods */
+
+
+
+/*
+ * void pr_close(struct irs_pr *this)
+ *
+ */
+
+static void
+pr_close(struct irs_pr *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       pr_minimize(this);
+
+       free_proto(&pvt->proto);
+
+       memput(pvt, sizeof *pvt);
+       memput(this, sizeof *this);
+}
+
+
+
+/*
+ * struct protoent * pr_byname(struct irs_pr *this, const char *name)
+ *
+ */
+
+static struct protoent *
+pr_byname(struct irs_pr *this, const char *name) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct protoent *pr = &pvt->proto;
+       char *body = NULL;
+       size_t bodylen;
+       int code;
+       int i;
+       char text[256];
+
+       if (pr->p_name != NULL && strcmp(name, pr->p_name) == 0) {
+               return (pr);
+       }
+
+       if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+               return (NULL);
+       }
+
+       i = irs_irp_send_command(pvt->girpdata, "getprotobyname %s", name);
+       if (i != 0)
+               return (NULL);
+
+       if (irs_irp_get_full_response(pvt->girpdata, &code,
+                                     text, sizeof text,
+                                     &body, &bodylen) != 0) {
+               return (NULL);
+       }
+
+       if (code == IRPD_GETPROTO_OK) {
+               free_proto(pr);
+               if (irp_unmarshall_pr(pr, body) != 0) {
+                       pr = NULL;
+               }
+       } else {
+               pr = NULL;
+       }
+
+       if (body != NULL) {
+               memput(body, bodylen);
+       }
+
+       return (pr);
+}
+
+
+
+/*
+ * struct protoent * pr_bynumber(struct irs_pr *this, int proto)
+ *
+ */
+
+static struct protoent *
+pr_bynumber(struct irs_pr *this, int proto) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct protoent *pr = &pvt->proto;
+       char *body = NULL;
+       size_t bodylen;
+       int code;
+       int i;
+       char text[256];
+
+       if (pr->p_name != NULL && proto == pr->p_proto) {
+               return (pr);
+       }
+
+       if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+               return (NULL);
+       }
+
+       i = irs_irp_send_command(pvt->girpdata, "getprotobynumber %d", proto);
+       if (i != 0)
+               return (NULL);
+
+       if (irs_irp_get_full_response(pvt->girpdata, &code,
+                                     text, sizeof text,
+                                     &body, &bodylen) != 0) {
+               return (NULL);
+       }
+
+       if (code == IRPD_GETPROTO_OK) {
+               free_proto(pr);
+               if (irp_unmarshall_pr(pr, body) != 0) {
+                       pr = NULL;
+               }
+       } else {
+               pr = NULL;
+       }
+
+       if (body != NULL) {
+               memput(body, bodylen);
+       }
+
+       return (pr);
+}
+
+
+
+
+/*
+ * void pr_rewind(struct irs_pr *this)
+ *
+ */
+
+static void
+pr_rewind(struct irs_pr *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       char text[256];
+       int code;
+
+       if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+               return;
+       }
+
+       if (irs_irp_send_command(pvt->girpdata, "setprotoent") != 0) {
+               return;
+       }
+
+       code = irs_irp_read_response(pvt->girpdata, text, sizeof text);
+       if (code != IRPD_GETPROTO_SETOK) {
+               if (irp_log_errors) {
+                       syslog(LOG_WARNING, "setprotoent failed: %s", text);
+               }
+       }
+
+       return;
+}
+
+
+
+
+/*
+ * struct protoent * pr_next(struct irs_pr *this)
+ *
+ * Notes:
+ *
+ *     Prepares the cache if necessary and returns the next item in it.
+ *
+ */
+
+static struct protoent *
+pr_next(struct irs_pr *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct protoent *pr = &pvt->proto;
+       char *body;
+       size_t bodylen;
+       int code;
+       char text[256];
+
+       if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+               return (NULL);
+       }
+
+       if (irs_irp_send_command(pvt->girpdata, "getprotoent") != 0) {
+               return (NULL);
+       }
+
+       if (irs_irp_get_full_response(pvt->girpdata, &code,
+                                     text, sizeof text,
+                                     &body, &bodylen) != 0) {
+               return (NULL);
+       }
+
+       if (code == IRPD_GETPROTO_OK) {
+               free_proto(pr);
+               if (irp_unmarshall_pr(pr, body) != 0) {
+                       pr = NULL;
+               }
+       } else {
+               pr = NULL;
+       }
+
+       if (body != NULL) {
+               memput(body, bodylen);
+       }
+
+       return (pr);
+}
+
+
+
+
+/*
+ * void pr_minimize(struct irs_pr *this)
+ *
+ */
+
+static void
+pr_minimize(struct irs_pr *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       irs_irp_disconnect(pvt->girpdata);
+}
+
+
+
+
+
+
+/*
+ * static void free_proto(struct protoent *pw);
+ *
+ *     Deallocate all the memory irp_unmarshall_pr allocated.
+ *
+ */
+
+static void
+free_proto(struct protoent *pr) {
+       char **p;
+
+       if (pr == NULL)
+               return;
+
+       if (pr->p_name != NULL)
+               free(pr->p_name);
+
+       for (p = pr->p_aliases ; p != NULL && *p != NULL ; p++)
+               free(*p);
+}
diff --git a/lib/bind/irs/irp_pw.c b/lib/bind/irs/irp_pw.c
new file mode 100644 (file)
index 0000000..567ef24
--- /dev/null
@@ -0,0 +1,356 @@
+/*
+ * Portions Copyright (c) 1996 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 rcsid[] = "$Id: irp_pw.c,v 1.1 2001/03/29 06:31:49 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* Extern */
+
+#include "port_before.h"
+
+#ifndef WANT_IRS_PW
+static int __bind_irs_pw_unneeded;
+#else
+
+#include <syslog.h>
+#include <sys/param.h>
+
+#include <db.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <utmp.h>
+#include <unistd.h>
+
+#include <irs.h>
+#include <irp.h>
+#include <isc/memcluster.h>
+#include <isc/irpmarshall.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "irp_p.h"
+
+
+/* Types */
+
+struct pvt {
+       struct irp_p   *girpdata; /* global IRP data */
+       int             warned;
+       struct passwd   passwd;         /* password structure */
+};
+
+/* Forward */
+
+static void                    pw_close(struct irs_pw *);
+static struct passwd *         pw_next(struct irs_pw *);
+static struct passwd *         pw_byname(struct irs_pw *, const char *);
+static struct passwd *         pw_byuid(struct irs_pw *, uid_t);
+static void                    pw_rewind(struct irs_pw *);
+static void                    pw_minimize(struct irs_pw *);
+
+static void                    free_passwd(struct passwd *pw);
+
+/* Public */
+struct irs_pw *
+irs_irp_pw(struct irs_acc *this) {
+       struct irs_pw *pw;
+       struct pvt *pvt;
+
+       if (!(pw = memget(sizeof *pw))) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pw, 0, sizeof *pw);
+
+       if (!(pvt = memget(sizeof *pvt))) {
+               memput(pw, sizeof *pw);
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pvt, 0, sizeof *pvt);
+       pvt->girpdata = this->private;
+
+       pw->private = pvt;
+       pw->close = pw_close;
+       pw->next = pw_next;
+       pw->byname = pw_byname;
+       pw->byuid = pw_byuid;
+       pw->rewind = pw_rewind;
+       pw->minimize = pw_minimize;
+
+       return (pw);
+}
+
+/* Methods */
+
+
+
+/*
+ * void pw_close(struct irs_pw *this)
+ *
+ */
+
+static void
+pw_close(struct irs_pw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       pw_minimize(this);
+
+       free_passwd(&pvt->passwd);
+
+       memput(pvt, sizeof *pvt);
+       memput(this, sizeof *this);
+}
+
+
+
+
+/*
+ * struct passwd * pw_next(struct irs_pw *this)
+ *
+ */
+
+static struct passwd *
+pw_next(struct irs_pw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct passwd *pw = &pvt->passwd;
+       char *body;
+       size_t bodylen;
+       int code;
+       char text[256];
+
+       if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+               return (NULL);
+       }
+
+       if (irs_irp_send_command(pvt->girpdata, "getpwent") != 0) {
+               return (NULL);
+       }
+
+       if (irs_irp_get_full_response(pvt->girpdata, &code,
+                                     text, sizeof text,
+                                     &body, &bodylen) != 0) {
+               return (NULL);
+       }
+
+       if (code == IRPD_GETUSER_OK) {
+               free_passwd(pw);
+               if (irp_unmarshall_pw(pw, body) != 0) {
+                       pw = NULL;
+               }
+       } else {
+               pw = NULL;
+       }
+
+       if (body != NULL) {
+               memput(body, bodylen);
+       }
+
+       return (pw);
+}
+
+
+
+
+/*
+ * struct passwd * pw_byname(struct irs_pw *this, const char *name)
+ *
+ */
+
+static struct passwd *
+pw_byname(struct irs_pw *this, const char *name) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct passwd *pw = &pvt->passwd;
+       char *body = NULL;
+       char text[256];
+       size_t bodylen;
+       int code;
+
+       if (pw->pw_name != NULL && strcmp(name, pw->pw_name) == 0) {
+               return (pw);
+       }
+
+       if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+               return (NULL);
+       }
+
+       if (irs_irp_send_command(pvt->girpdata, "getpwnam %s", name) != 0) {
+               return (NULL);
+       }
+
+       if (irs_irp_get_full_response(pvt->girpdata, &code,
+                                     text, sizeof text,
+                                     &body, &bodylen) != 0) {
+               return (NULL);
+       }
+
+       if (code == IRPD_GETUSER_OK) {
+               free_passwd(pw);
+               if (irp_unmarshall_pw(pw, body) != 0) {
+                       pw = NULL;
+               }
+       } else {
+               pw = NULL;
+       }
+
+       if (body != NULL) {
+               memput(body, bodylen);
+       }
+
+       return (pw);
+}
+
+
+
+
+/*
+ * struct passwd * pw_byuid(struct irs_pw *this, uid_t uid)
+ *
+ */
+
+static struct passwd *
+pw_byuid(struct irs_pw *this, uid_t uid) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       char *body;
+       char text[256];
+       size_t bodylen;
+       int code;
+       struct passwd *pw = &pvt->passwd;
+
+       if (pw->pw_name != NULL && pw->pw_uid == uid) {
+               return (pw);
+       }
+
+       if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+               return (NULL);
+       }
+
+       if (irs_irp_send_command(pvt->girpdata, "getpwuid %d", uid) != 0) {
+               return (NULL);
+       }
+
+       if (irs_irp_get_full_response(pvt->girpdata, &code,
+                                     text, sizeof text,
+                                     &body, &bodylen) != 0) {
+               return (NULL);
+       }
+
+       if (code == IRPD_GETUSER_OK) {
+               free_passwd(pw);
+               if (irp_unmarshall_pw(pw, body) != 0) {
+                       pw = NULL;
+               }
+       } else {
+               pw = NULL;
+       }
+
+       if (body != NULL) {
+               memput(body, bodylen);
+       }
+
+       return (pw);
+}
+
+
+
+
+/*
+ * void pw_rewind(struct irs_pw *this)
+ *
+ */
+
+static void
+pw_rewind(struct irs_pw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       char text[256];
+       int code;
+
+       if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+               return;
+       }
+
+       if (irs_irp_send_command(pvt->girpdata, "setpwent") != 0) {
+               return;
+       }
+
+       code = irs_irp_read_response(pvt->girpdata, text, sizeof text);
+       if (code != IRPD_GETUSER_SETOK) {
+               if (irp_log_errors) {
+                       syslog(LOG_WARNING, "setpwent failed: %s", text);
+               }
+       }
+
+       return;
+}
+
+
+/*
+ * void pw_minimize(struct irs_pw *this)
+ *
+ */
+
+static void
+pw_minimize(struct irs_pw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       irs_irp_disconnect(pvt->girpdata);
+}
+
+
+/* Private. */
+
+
+
+/*
+ * static void free_passwd(struct passwd *pw);
+ *
+ *     Deallocate all the memory irp_unmarshall_pw allocated.
+ *
+ */
+
+static void
+free_passwd(struct passwd *pw) {
+       if (pw == NULL)
+               return;
+
+       if (pw->pw_name != NULL)
+               free(pw->pw_name);
+
+       if (pw->pw_passwd != NULL)
+               free(pw->pw_passwd);
+
+       if (pw->pw_class != NULL)
+               free(pw->pw_class);
+
+       if (pw->pw_gecos != NULL)
+               free(pw->pw_gecos);
+
+       if (pw->pw_dir != NULL)
+               free(pw->pw_dir);
+
+       if (pw->pw_shell != NULL)
+               free(pw->pw_shell);
+}
+
+#endif /* WANT_IRS_PW */
diff --git a/lib/bind/irs/irp_sv.c b/lib/bind/irs/irp_sv.c
new file mode 100644 (file)
index 0000000..4f14b87
--- /dev/null
@@ -0,0 +1,369 @@
+/*
+ * Portions Copyright (c) 1996,1998 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 rcsid[] = "$Id: irp_sv.c,v 1.1 2001/03/29 06:31:49 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* extern */
+
+#include "port_before.h"
+
+#include <syslog.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#ifdef IRS_LCL_SV_DB
+#include <db.h>
+#endif
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <syslog.h>
+
+#include <irs.h>
+#include <irp.h>
+#include <isc/irpmarshall.h>
+#include <isc/memcluster.h>
+
+#include "irs_p.h"
+#include "lcl_p.h"
+#include "irp_p.h"
+
+#include "port_after.h"
+
+/* Types */
+
+struct pvt {
+       struct irp_p           *girpdata;
+       int                     warned;
+       struct servent          service;
+};
+
+/* Forward */
+
+static void                    sv_close(struct irs_sv*);
+static struct servent *                sv_next(struct irs_sv *);
+static struct servent *                sv_byname(struct irs_sv *, const char *,
+                                         const char *);
+static struct servent *                sv_byport(struct irs_sv *, int, const char *);
+static void                    sv_rewind(struct irs_sv *);
+static void                    sv_minimize(struct irs_sv *);
+
+static void                    free_service(struct servent *sv);
+
+
+
+/* Public */
+
+
+
+/*
+ * struct irs_sv * irs_irp_sv(struct irs_acc *this)
+ *
+ */
+
+struct irs_sv *
+irs_irp_sv(struct irs_acc *this) {
+       struct irs_sv *sv;
+       struct pvt *pvt;
+
+       if ((sv = memget(sizeof *sv)) == NULL) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(sv, 0x0, sizeof *sv);
+
+       if ((pvt = memget(sizeof *pvt)) == NULL) {
+               memput(sv, sizeof *sv);
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pvt, 0, sizeof *pvt);
+       pvt->girpdata = this->private;
+
+       sv->private = pvt;
+       sv->close = sv_close;
+       sv->next = sv_next;
+       sv->byname = sv_byname;
+       sv->byport = sv_byport;
+       sv->rewind = sv_rewind;
+       sv->minimize = sv_minimize;
+
+       return (sv);
+}
+
+/* Methods */
+
+
+
+/*
+ * void sv_close(struct irs_sv *this)
+ *
+ */
+
+static void
+sv_close(struct irs_sv *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       sv_minimize(this);
+
+       free_service(&pvt->service);
+
+       memput(pvt, sizeof *pvt);
+       memput(this, sizeof *this);
+}
+
+
+
+
+/*
+ * struct servent * sv_next(struct irs_sv *this)
+ *
+ * Notes:
+ *
+ *     Fills the cache if necessary and returns the next item from it.
+ *
+ */
+
+static struct servent *
+sv_next(struct irs_sv *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct servent *sv = &pvt->service;
+       char *body;
+       size_t bodylen;
+       int code;
+       char text[256];
+
+       if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+               return (NULL);
+       }
+
+       if (irs_irp_send_command(pvt->girpdata, "getservent") != 0) {
+               return (NULL);
+       }
+
+       if (irs_irp_get_full_response(pvt->girpdata, &code,
+                                     text, sizeof text,
+                                     &body, &bodylen) != 0) {
+               return (NULL);
+       }
+
+       if (code == IRPD_GETSERVICE_OK) {
+               free_service(sv);
+               if (irp_unmarshall_sv(sv, body) != 0) {
+                       sv = NULL;
+               }
+       } else {
+               sv = NULL;
+       }
+
+       if (body != NULL) {
+               memput(body, bodylen);
+       }
+
+       return (sv);
+}
+
+
+
+
+/*
+ * struct servent * sv_byname(struct irs_sv *this, const char *name,
+ *                             const char *proto)
+ *
+ */
+
+static struct servent *
+sv_byname(struct irs_sv *this, const char *name, const char *proto) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct servent *sv = &pvt->service;
+       char *body;
+       char text[256];
+       size_t bodylen;
+       int code;
+
+       if (sv->s_name != NULL &&
+           strcmp(name, sv->s_name) == 0 &&
+           strcasecmp(proto, sv->s_proto) == 0) {
+               return (sv);
+       }
+
+       if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+               return (NULL);
+       }
+
+       if (irs_irp_send_command(pvt->girpdata, "getservbyname %s %s",
+                                name, proto) != 0)
+               return (NULL);
+
+       if (irs_irp_get_full_response(pvt->girpdata, &code,
+                                     text, sizeof text,
+                                     &body, &bodylen) != 0) {
+               return (NULL);
+       }
+
+       if (code == IRPD_GETSERVICE_OK) {
+               free_service(sv);
+               if (irp_unmarshall_sv(sv, body) != 0) {
+                       sv = NULL;
+               }
+       } else {
+               sv = NULL;
+       }
+
+       if (body != NULL) {
+               memput(body, bodylen);
+       }
+
+       return (sv);
+}
+
+
+
+
+/*
+ * struct servent * sv_byport(struct irs_sv *this, int port,
+ *                             const char *proto)
+ *
+ */
+
+static struct servent *
+sv_byport(struct irs_sv *this, int port, const char *proto) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct servent *sv = &pvt->service;
+       char *body;
+       size_t bodylen;
+       char text[256];
+       int code;
+
+       if (sv->s_name != NULL &&
+           port == sv->s_port &&
+           strcasecmp(proto, sv->s_proto) == 0) {
+               return (sv);
+       }
+
+       if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+               return (NULL);
+       }
+
+       if (irs_irp_send_command(pvt->girpdata, "getservbyport %d %s",
+                                ntohs((short)port), proto) != 0) {
+               return (NULL);
+       }
+
+       if (irs_irp_get_full_response(pvt->girpdata, &code,
+                                     text, sizeof text,
+                                     &body, &bodylen) != 0) {
+               return (NULL);
+       }
+
+       if (code == IRPD_GETSERVICE_OK) {
+               free_service(sv);
+               if (irp_unmarshall_sv(sv, body) != 0) {
+                       sv = NULL;
+               }
+       } else {
+               sv = NULL;
+       }
+
+       if (body != NULL) {
+               memput(body, bodylen);
+       }
+
+       return (sv);
+}
+
+
+
+
+
+/*
+ * void sv_rewind(struct irs_sv *this)
+ *
+ */
+
+static void
+sv_rewind(struct irs_sv *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       char text[256];
+       int code;
+
+       if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
+               return;
+       }
+
+       if (irs_irp_send_command(pvt->girpdata, "setservent") != 0) {
+               return;
+       }
+
+       code = irs_irp_read_response(pvt->girpdata, text, sizeof text);
+       if (code != IRPD_GETSERVICE_SETOK) {
+               if (irp_log_errors) {
+                       syslog(LOG_WARNING, "setservent failed: %s", text);
+               }
+       }
+
+       return;
+}
+
+
+
+
+
+/*
+ * void sv_minimize(struct irs_sv *this)
+ *
+ */
+
+static void
+sv_minimize(struct irs_sv *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       irs_irp_disconnect(pvt->girpdata);
+}
+
+
+
+
+
+
+static void
+free_service(struct servent *sv) {
+       char **p;
+
+       if (sv == NULL) {
+               return;
+       }
+
+       if (sv->s_name != NULL) {
+               free(sv->s_name);
+       }
+
+       for (p = sv->s_aliases ; p != NULL && *p != NULL ; p++) {
+               free(*p);
+       }
+
+       if (sv->s_proto != NULL) {
+               free(sv->s_proto);
+       }
+}
+
+
diff --git a/lib/bind/irs/irpmarshall.c b/lib/bind/irs/irpmarshall.c
new file mode 100644 (file)
index 0000000..d8d8ffa
--- /dev/null
@@ -0,0 +1,2344 @@
+/*
+ * Copyright(c) 1989, 1993, 1995
+ *     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 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 rcsid[] = "$Id: irpmarshall.c,v 1.1 2001/03/29 06:31:50 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#if 0
+
+Check values are in approrpriate endian order.
+
+Double check memory allocations on unmarhsalling
+
+#endif
+
+
+/* Extern */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <stdio.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <utmp.h>
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <irs.h>
+#include <isc/memcluster.h>
+#include <isc/irpmarshall.h>
+
+#include "port_after.h"
+
+
+#ifndef HAVE_STRNDUP
+static char    *strndup(const char *str, size_t len);
+#endif
+
+static char   **splitarray(const char *buffer, const char *buffend, char delim);
+static int     joinarray(char * const * argv, char *buffer, char delim);
+static char    *getfield(char **res, size_t reslen, char **buffer, char delim);
+static size_t  joinlength(char * const *argv);
+static void    free_array(char **argv, size_t entries);
+
+#define ADDR_T_STR(x) (x == AF_INET ? "AF_INET" :\
+                      (x == AF_INET6 ? "AF_INET6" : "UNKNOWN"))
+
+#define MAXPADDRSIZE (sizeof "255.255.255.255" + 1)
+
+static char COMMA = ',';
+
+static const char *COMMASTR = ",";
+static const char *COLONSTR = ":";
+
+
+
+/* See big comment at bottom of irpmarshall.h for description. */
+
+
+#ifdef WANT_IRS_PW
+/* +++++++++++++++++++++++++ struct passwd +++++++++++++++++++++++++ */
+
+
+/*
+ * int irp_marshall_pw(const struct passwd *pw, char **buffer, size_t *len)
+ *
+ * notes:
+ *
+ *     See above
+ *
+ * return:
+ *
+ *     0 on sucess, -1 on failure.
+ *
+ */
+
+int
+irp_marshall_pw(const struct passwd *pw, char **buffer, size_t *len) {
+       size_t need = 1 ;               /* for null byte */
+       char pwUid[24];
+       char pwGid[24];
+       char pwChange[24];
+       char pwExpire[24];
+       const char *pwClass;
+       const char *fieldsep = COLONSTR;
+
+       if (pw == NULL || len == NULL) {
+               errno = EINVAL;
+               return (-1);
+       }
+
+       sprintf(pwUid, "%ld", (long)pw->pw_uid);
+       sprintf(pwGid, "%ld", (long)pw->pw_gid);
+
+#ifdef HAVE_PW_CHANGE
+       sprintf(pwChange, "%ld", (long)pw->pw_change);
+#else
+       pwChange[0] = '0';
+       pwChange[1] = '\0';
+#endif
+
+#ifdef HAVE_PW_EXPIRE
+       sprintf(pwExpire, "%ld", (long)pw->pw_expire);
+#else
+       pwExpire[0] = '0';
+       pwExpire[1] = '\0';
+#endif
+
+#ifdef HAVE_PW_CLASS
+       pwClass = pw->pw_class;
+#else
+       pwClass = "";
+#endif
+
+       need += strlen(pw->pw_name)     + 1; /* one for fieldsep */
+       need += strlen(pw->pw_passwd)   + 1;
+       need += strlen(pwUid)           + 1;
+       need += strlen(pwGid)           + 1;
+       need += strlen(pwClass)         + 1;
+       need += strlen(pwChange)        + 1;
+       need += strlen(pwExpire)        + 1;
+       need += strlen(pw->pw_gecos)    + 1;
+       need += strlen(pw->pw_dir)      + 1;
+       need += strlen(pw->pw_shell)    + 1;
+
+       if (buffer == NULL) {
+               *len = need;
+               return (0);
+       }
+
+       if (*buffer != NULL && need > *len) {
+               errno = EINVAL;
+               return (-1);
+       }
+
+       if (*buffer == NULL) {
+               need += 2;              /* for CRLF */
+               *buffer = memget(need);
+               if (*buffer == NULL) {
+                       errno = ENOMEM;
+                       return (-1);
+               }
+
+               *len = need;
+       }
+
+       strcpy(*buffer, pw->pw_name);           strcat(*buffer, fieldsep);
+       strcat(*buffer, pw->pw_passwd);         strcat(*buffer, fieldsep);
+       strcat(*buffer, pwUid);                 strcat(*buffer, fieldsep);
+       strcat(*buffer, pwGid);                 strcat(*buffer, fieldsep);
+       strcat(*buffer, pwClass);               strcat(*buffer, fieldsep);
+       strcat(*buffer, pwChange);              strcat(*buffer, fieldsep);
+       strcat(*buffer, pwExpire);              strcat(*buffer, fieldsep);
+       strcat(*buffer, pw->pw_gecos);          strcat(*buffer, fieldsep);
+       strcat(*buffer, pw->pw_dir);            strcat(*buffer, fieldsep);
+       strcat(*buffer, pw->pw_shell);          strcat(*buffer, fieldsep);
+
+       return (0);
+}
+
+
+
+
+
+/*
+ * int irp_unmarshall_pw(struct passwd *pw, char *buffer)
+ *
+ * notes:
+ *
+ *     see above
+ *
+ * return:
+ *
+ *     0 on success, -1 on failure
+ *
+ */
+
+int
+irp_unmarshall_pw(struct passwd *pw, char *buffer) {
+       char *name, *pass, *class, *gecos, *dir, *shell;
+       uid_t pwuid;
+       gid_t pwgid;
+       time_t pwchange;
+       time_t pwexpire;
+       char *p;
+       long t;
+       char tmpbuf[24];
+       char *tb = &tmpbuf[0];
+       char fieldsep = ':';
+       int myerrno = EINVAL;
+
+       name = pass = class = gecos = dir = shell = NULL;
+       p = buffer;
+
+       /* pw_name field */
+       name = NULL;
+       if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0) {
+               goto error;
+       }
+
+       /* pw_passwd field */
+       pass = NULL;
+       if (getfield(&pass, 0, &p, fieldsep) == NULL) { /* field can be empty */
+               goto error;
+       }
+
+
+       /* pw_uid field */
+       tb = tmpbuf;
+       if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+           strlen(tb) == 0) {
+               goto error;
+       }
+       t = strtol(tmpbuf, &tb, 10);
+       if (*tb) {
+               goto error;     /* junk in value */
+       }
+       pwuid = (uid_t)t;
+       if ((long) pwuid != t) {        /* value must have been too big. */
+               goto error;
+       }
+
+
+
+       /* pw_gid field */
+       tb = tmpbuf;
+       if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+           strlen(tb) == 0) {
+               goto error;
+       }
+       t = strtol(tmpbuf, &tb, 10);
+       if (*tb) {
+               goto error;     /* junk in value */
+       }
+       pwgid = (gid_t)t;
+       if ((long)pwgid != t) { /* value must have been too big. */
+               goto error;
+       }
+
+
+
+       /* pw_class field */
+       class = NULL;
+       if (getfield(&class, 0, &p, fieldsep) == NULL) {
+               goto error;
+       }
+
+
+
+       /* pw_change field */
+       tb = tmpbuf;
+       if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+           strlen(tb) == 0) {
+               goto error;
+       }
+       t = strtol(tmpbuf, &tb, 10);
+       if (*tb) {
+               goto error;     /* junk in value */
+       }
+       pwchange = (time_t)t;
+       if ((long)pwchange != t) {      /* value must have been too big. */
+               goto error;
+       }
+
+
+
+       /* pw_expire field */
+       tb = tmpbuf;
+       if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+           strlen(tb) == 0) {
+               goto error;
+       }
+       t = strtol(tmpbuf, &tb, 10);
+       if (*tb) {
+               goto error;     /* junk in value */
+       }
+       pwexpire = (time_t)t;
+       if ((long) pwexpire != t) {     /* value must have been too big. */
+               goto error;
+       }
+
+
+
+       /* pw_gecos field */
+       gecos = NULL;
+       if (getfield(&gecos, 0, &p, fieldsep) == NULL) {
+               goto error;
+       }
+
+
+
+       /* pw_dir field */
+       dir = NULL;
+       if (getfield(&dir, 0, &p, fieldsep) == NULL) {
+               goto error;
+       }
+
+
+
+       /* pw_shell field */
+       shell = NULL;
+       if (getfield(&shell, 0, &p, fieldsep) == NULL) {
+               goto error;
+       }
+
+
+
+       pw->pw_name = name;
+       pw->pw_passwd = pass;
+       pw->pw_uid = pwuid;
+       pw->pw_gid = pwgid;
+       pw->pw_gecos = gecos;
+       pw->pw_dir = dir;
+       pw->pw_shell = shell;
+
+#ifdef HAVE_PW_CHANGE
+       pw->pw_change = pwchange;
+#endif
+#ifdef HAVE_PW_CLASS
+       pw->pw_class = class;
+#endif
+#ifdef HAVE_PW_EXPIRE
+       pw->pw_expire = pwexpire;
+#endif
+
+       return (0);
+
+ error:
+       errno = myerrno;
+
+       if (name != NULL) free(name);
+       if (pass != NULL) free(pass);
+       if (gecos != NULL) free(gecos);
+       if (dir != NULL) free(dir);
+       if (shell != NULL) free(shell);
+
+       return (-1);
+}
+
+/* ------------------------- struct passwd ------------------------- */
+#endif /* WANT_IRS_PW */
+
+
+
+/* +++++++++++++++++++++++++ struct group +++++++++++++++++++++++++ */
+
+
+
+/*
+ * int irp_marshall_gr(const struct group *gr, char **buffer, size_t *len)
+ *
+ * notes:
+ *
+ *     see above.
+ *
+ * return:
+ *
+ *     0 on success, -1 on failure
+ */
+
+int
+irp_marshall_gr(const struct group *gr, char **buffer, size_t *len) {
+       size_t need = 1;        /* for null byte */
+       char grGid[24];
+       const char *fieldsep = COLONSTR;
+
+       if (gr == NULL || len == NULL) {
+               errno = EINVAL;
+               return (-1);
+       }
+
+       sprintf(grGid, "%ld", (long)gr->gr_gid);
+
+       need += strlen(gr->gr_name) + 1;
+#ifndef MISSING_GR_PASSWD
+       need += strlen(gr->gr_passwd) + 1;
+#else
+       need++;
+#endif
+       need += strlen(grGid) + 1;
+       need += joinlength(gr->gr_mem) + 1;
+
+       if (buffer == NULL) {
+               *len = need;
+               return (0);
+       }
+
+       if (*buffer != NULL && need > *len) {
+               errno = EINVAL;
+               return (-1);
+       }
+
+       if (*buffer == NULL) {
+               need += 2;              /* for CRLF */
+               *buffer = memget(need);
+               if (*buffer == NULL) {
+                       errno = ENOMEM;
+                       return (-1);
+               }
+
+               *len = need;
+       }
+
+       strcpy(*buffer, gr->gr_name);           strcat(*buffer, fieldsep);
+#ifndef MISSING_GR_PASSWD
+       strcat(*buffer, gr->gr_passwd);
+#endif
+       strcat(*buffer, fieldsep);
+       strcat(*buffer, grGid);                 strcat(*buffer, fieldsep);
+       joinarray(gr->gr_mem, *buffer, COMMA) ; strcat(*buffer, fieldsep);
+
+       return (0);
+}
+
+
+
+
+/*
+ * int irp_unmarshall_gr(struct group *gr, char *buffer)
+ *
+ * notes:
+ *
+ *     see above
+ *
+ * return:
+ *
+ *     0 on success and -1 on failure.
+ *
+ */
+
+int
+irp_unmarshall_gr(struct group *gr, char *buffer) {
+       char *p, *q;
+       gid_t grgid;
+       long t;
+       char *name = NULL;
+       char *pass = NULL;
+       char **members = NULL;
+       char tmpbuf[24];
+       char *tb;
+       char fieldsep = ':';
+       int myerrno = EINVAL;
+
+       if (gr == NULL || buffer == NULL) {
+               errno = EINVAL;
+               return (-1);
+       }
+
+       p = buffer;
+
+       /* gr_name field */
+       name = NULL;
+       if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0) {
+               goto error;
+       }
+
+
+       /* gr_passwd field */
+       pass = NULL;
+       if (getfield(&pass, 0, &p, fieldsep) == NULL) {
+               goto error;
+       }
+
+
+       /* gr_gid field */
+       tb = tmpbuf;
+       if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+           strlen(tb) == 0) {
+               goto error;
+       }
+       t = strtol(tmpbuf, &tb, 10);
+       if (*tb) {
+               goto error;     /* junk in value */
+       }
+       grgid = (gid_t)t;
+       if ((long) grgid != t) {        /* value must have been too big. */
+               goto error;
+       }
+
+
+       /* gr_mem field. Member names are separated by commas */
+       q = strchr(p, fieldsep);
+       if (q == NULL) {
+               goto error;
+       }
+       members = splitarray(p, q, COMMA);
+       if (members == NULL) {
+               myerrno = errno;
+               goto error;
+       }
+       p = q + 1;
+
+
+       gr->gr_name = name;
+#ifndef MISSING_GR_PASSWD
+       gr->gr_passwd = pass;
+#endif
+       gr->gr_gid = grgid;
+       gr->gr_mem = members;
+
+       return (0);
+
+ error:
+       errno = myerrno;
+
+       if (name != NULL) free(name);
+       if (pass != NULL) free(pass);
+
+       return (-1);
+}
+
+
+/* ------------------------- struct group ------------------------- */
+
+
+
+
+/* +++++++++++++++++++++++++ struct servent +++++++++++++++++++++++++ */
+
+
+
+/*
+ * int irp_marshall_sv(const struct servent *sv, char **buffer, size_t *len)
+ *
+ * notes:
+ *
+ *     see above
+ *
+ * return:
+ *
+ *     0 on success, -1 on failure.
+ *
+ */
+
+int
+irp_marshall_sv(const struct servent *sv, char **buffer, size_t *len) {
+       size_t need = 1;        /* for null byte */
+       char svPort[24];
+       const char *fieldsep = COLONSTR;
+       short realport;
+
+       if (sv == NULL || len == NULL) {
+               errno = EINVAL;
+               return (-1);
+       }
+
+       /* the int s_port field is actually a short in network order. We
+          want host order to make the marshalled data look correct */
+       realport = ntohs((short)sv->s_port);
+       sprintf(svPort, "%d", realport);
+
+       need += strlen(sv->s_name) + 1;
+       need += joinlength(sv->s_aliases) + 1;
+       need += strlen(svPort) + 1;
+       need += strlen(sv->s_proto) + 1;
+
+       if (buffer == NULL) {
+               *len = need;
+               return (0);
+       }
+
+       if (*buffer != NULL && need > *len) {
+               errno = EINVAL;
+               return (-1);
+       }
+
+       if (*buffer == NULL) {
+               need += 2;              /* for CRLF */
+               *buffer = memget(need);
+               if (*buffer == NULL) {
+                       errno = ENOMEM;
+                       return (-1);
+               }
+
+               *len = need;
+       }
+
+       strcpy(*buffer, sv->s_name);            strcat(*buffer, fieldsep);
+       joinarray(sv->s_aliases, *buffer, COMMA); strcat(*buffer, fieldsep);
+       strcat(*buffer, svPort);                strcat(*buffer, fieldsep);
+       strcat(*buffer, sv->s_proto);           strcat(*buffer, fieldsep);
+
+       return (0);
+}
+
+
+
+
+
+/*
+ * int irp_unmarshall_sv(struct servent *sv, char *buffer)
+ *
+ * notes:
+ *
+ *     see above
+ *
+ * return:
+ *
+ *     0 on success, -1 on failure.
+ *
+ */
+
+int
+irp_unmarshall_sv(struct servent *sv, char *buffer) {
+       char *p, *q;
+       short svport;
+       long t;
+       char *name = NULL;
+       char *proto = NULL;
+       char **aliases = NULL;
+       char tmpbuf[24];
+       char *tb;
+       char fieldsep = ':';
+       int myerrno = EINVAL;
+
+       if (sv == NULL || buffer == NULL)
+               return (-1);
+
+       p = buffer;
+
+
+       /* s_name field */
+       name = NULL;
+       if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0) {
+               goto error;
+       }
+
+
+       /* s_aliases field */
+       q = strchr(p, fieldsep);
+       if (q == NULL) {
+               goto error;
+       }
+       aliases = splitarray(p, q, COMMA);
+       if (aliases == NULL) {
+               myerrno = errno;
+               goto error;
+       }
+       p = q + 1;
+
+
+       /* s_port field */
+       tb = tmpbuf;
+       if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+           strlen(tb) == 0) {
+               goto error;
+       }
+       t = strtol(tmpbuf, &tb, 10);
+       if (*tb) {
+               goto error;     /* junk in value */
+       }
+       svport = (short)t;
+       if ((long) svport != t) {       /* value must have been too big. */
+               goto error;
+       }
+       svport = htons(svport);
+
+       /* s_proto field */
+       proto = NULL;
+       if (getfield(&proto, 0, &p, fieldsep) == NULL) {
+               goto error;
+       }
+
+       sv->s_name = name;
+       sv->s_aliases = aliases;
+       sv->s_port = svport;
+       sv->s_proto = proto;
+
+       return (0);
+
+ error:
+       errno = myerrno;
+
+       if (name != NULL) free(name);
+       if (proto != NULL) free(proto);
+       free_array(aliases, 0);
+
+       return (-1);
+}
+
+
+/* ------------------------- struct servent ------------------------- */
+
+/* +++++++++++++++++++++++++ struct protoent +++++++++++++++++++++++++ */
+
+
+
+/*
+ * int irp_marshall_pr(struct protoent *pr, char **buffer, size_t *len)
+ *
+ * notes:
+ *
+ *     see above
+ *
+ * return:
+ *
+ *     0 on success and -1 on failure.
+ *
+ */
+
+int
+irp_marshall_pr(struct protoent *pr, char **buffer, size_t *len) {
+       size_t need = 1;        /* for null byte */
+       char prProto[24];
+       const char *fieldsep = COLONSTR;
+
+       if (pr == NULL || len == NULL) {
+               errno = EINVAL;
+               return (-1);
+       }
+
+       sprintf(prProto, "%d", (int)pr->p_proto);
+
+       need += strlen(pr->p_name) + 1;
+       need += joinlength(pr->p_aliases) + 1;
+       need += strlen(prProto) + 1;
+
+       if (buffer == NULL) {
+               *len = need;
+               return (0);
+       }
+
+       if (*buffer != NULL && need > *len) {
+               errno = EINVAL;
+               return (-1);
+       }
+
+       if (*buffer == NULL) {
+               need += 2;              /* for CRLF */
+               *buffer = memget(need);
+               if (*buffer == NULL) {
+                       errno = ENOMEM;
+                       return (-1);
+               }
+
+               *len = need;
+       }
+
+       strcpy(*buffer, pr->p_name);            strcat(*buffer, fieldsep);
+       joinarray(pr->p_aliases, *buffer, COMMA); strcat(*buffer, fieldsep);
+       strcat(*buffer, prProto);               strcat(*buffer, fieldsep);
+
+       return (0);
+
+}
+
+
+
+/*
+ * int irp_unmarshall_pr(struct protoent *pr, char *buffer)
+ *
+ * notes:
+ *
+ *     See above
+ *
+ * return:
+ *
+ *     0 on success, -1 on failure
+ *
+ */
+
+int irp_unmarshall_pr(struct protoent *pr, char *buffer) {
+       char *p, *q;
+       int prproto;
+       long t;
+       char *name = NULL;
+       char **aliases = NULL;
+       char tmpbuf[24];
+       char *tb;
+       char fieldsep = ':';
+       int myerrno = EINVAL;
+
+       if (pr == NULL || buffer == NULL) {
+               errno = EINVAL;
+               return (-1);
+       }
+
+       p = buffer;
+
+       /* p_name field */
+       name = NULL;
+       if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0) {
+               goto error;
+       }
+
+
+       /* p_aliases field */
+       q = strchr(p, fieldsep);
+       if (q == NULL) {
+               goto error;
+       }
+       aliases = splitarray(p, q, COMMA);
+       if (aliases == NULL) {
+               myerrno = errno;
+               goto error;
+       }
+       p = q + 1;
+
+
+       /* p_proto field */
+       tb = tmpbuf;
+       if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+           strlen(tb) == 0) {
+               goto error;
+       }
+       t = strtol(tmpbuf, &tb, 10);
+       if (*tb) {
+               goto error;     /* junk in value */
+       }
+       prproto = (int)t;
+       if ((long) prproto != t) {      /* value must have been too big. */
+               goto error;
+       }
+
+       pr->p_name = name;
+       pr->p_aliases = aliases;
+       pr->p_proto = prproto;
+
+       return (0);
+
+ error:
+       errno = myerrno;
+
+       if (name != NULL) free(name);
+       free_array(aliases, 0);
+
+       return (-1);
+}
+
+/* ------------------------- struct protoent ------------------------- */
+
+
+
+/* +++++++++++++++++++++++++ struct hostent +++++++++++++++++++++++++ */
+
+
+/*
+ * int irp_marshall_ho(struct hostent *ho, char **buffer, size_t *len)
+ *
+ * notes:
+ *
+ *     see above.
+ *
+ * return:
+ *
+ *     0 on success, -1 on failure.
+ *
+ */
+
+int
+irp_marshall_ho(struct hostent *ho, char **buffer, size_t *len) {
+       size_t need = 1;        /* for null byte */
+       char hoaddrtype[24];
+       char holength[24];
+       char **av;
+       char *p;
+       int addrlen;
+       int malloced = 0;
+       size_t remlen;
+       const char *fieldsep = "@";
+
+       if (ho == NULL || len == NULL) {
+               errno = EINVAL;
+               return (-1);
+       }
+
+       switch(ho->h_addrtype) {
+       case AF_INET:
+               strcpy(hoaddrtype, "AF_INET");
+               break;
+
+       case AF_INET6:
+               strcpy(hoaddrtype, "AF_INET6");
+               break;
+
+       default:
+               errno = EINVAL;
+               return (-1);
+       }
+
+       sprintf(holength, "%d", ho->h_length);
+
+       need += strlen(ho->h_name) + 1;
+       need += joinlength(ho->h_aliases) + 1;
+       need += strlen(hoaddrtype) + 1;
+       need += strlen(holength) + 1;
+
+       /* we determine an upper bound on the string length needed, not an
+          exact length. */
+       addrlen = (ho->h_addrtype == AF_INET ? 16 : 46) ; /* XX other AF's?? */
+       for (av = ho->h_addr_list; av != NULL && *av != NULL ; av++)
+               need += addrlen;
+
+       if (buffer == NULL) {
+               *len = need;
+               return (0);
+       }
+
+       if (*buffer != NULL && need > *len) {
+               errno = EINVAL;
+               return (-1);
+       }
+
+       if (*buffer == NULL) {
+               need += 2;              /* for CRLF */
+               *buffer = memget(need);
+               if (*buffer == NULL) {
+                       errno = ENOMEM;
+                       return (-1);
+               }
+
+               *len = need;
+               malloced = 1;
+       }
+
+       strcpy(*buffer, ho->h_name);            strcat(*buffer, fieldsep);
+       joinarray(ho->h_aliases, *buffer, COMMA); strcat(*buffer, fieldsep);
+       strcat(*buffer, hoaddrtype);            strcat(*buffer, fieldsep);
+       strcat(*buffer, holength);              strcat(*buffer, fieldsep);
+
+       p = *buffer + strlen(*buffer);
+       remlen = need - strlen(*buffer);
+       for (av = ho->h_addr_list ; av != NULL && *av != NULL ; av++) {
+               if (inet_ntop(ho->h_addrtype, *av, p, remlen) == NULL) {
+                       goto error;
+               }
+               if (*(av + 1) != NULL)
+                       strcat(p, COMMASTR);
+               remlen -= strlen(p);
+               p += strlen(p);
+       }
+       strcat(*buffer, fieldsep);
+
+       return (0);
+
+ error:
+       if (malloced) {
+               memput(*buffer, need);
+       }
+
+       return (-1);
+}
+
+
+
+/*
+ * int irp_unmarshall_ho(struct hostent *ho, char *buffer)
+ *
+ * notes:
+ *
+ *     See above.
+ *
+ * return:
+ *
+ *     0 on success, -1 on failure.
+ *
+ */
+
+int
+irp_unmarshall_ho(struct hostent *ho, char *buffer) {
+       char *p, *q, *r;
+       int hoaddrtype;
+       int holength;
+       long t;
+       char *name = NULL;
+       char **aliases = NULL;
+       char **hohaddrlist = NULL;
+       size_t hoaddrsize;
+       char tmpbuf[24];
+       char *tb;
+       char **alist;
+       int addrcount;
+       char fieldsep = '@';
+       int myerrno = EINVAL;
+
+       if (ho == NULL || buffer == NULL) {
+               errno = EINVAL;
+               return (-1);
+       }
+
+       p = buffer;
+
+       /* h_name field */
+       name = NULL;
+       if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0) {
+               goto error;
+       }
+
+
+       /* h_aliases field */
+       q = strchr(p, fieldsep);
+       if (q == NULL) {
+               goto error;
+       }
+       aliases = splitarray(p, q, COMMA);
+       if (aliases == NULL) {
+               myerrno = errno;
+               goto error;
+       }
+       p = q + 1;
+
+
+       /* h_addrtype field */
+       tb = tmpbuf;
+       if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+           strlen(tb) == 0) {
+               goto error;
+       }
+       if (strcmp(tmpbuf, "AF_INET") == 0)
+               hoaddrtype = AF_INET;
+       else if (strcmp(tmpbuf, "AF_INET6") == 0)
+               hoaddrtype = AF_INET6;
+       else
+               goto error;
+
+
+       /* h_length field */
+       tb = tmpbuf;
+       if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+           strlen(tb) == 0) {
+               goto error;
+       }
+       t = strtol(tmpbuf, &tb, 10);
+       if (*tb) {
+               goto error;     /* junk in value */
+       }
+       holength = (int)t;
+       if ((long) holength != t) {     /* value must have been too big. */
+               goto error;
+       }
+
+
+       /* h_addr_list field */
+       q = strchr(p, fieldsep);
+       if (q == NULL)
+               goto error;
+
+       /* count how many addresss are in there */
+       if (q > p + 1) {
+               for (addrcount = 1, r = p ; r != q ; r++) {
+                       if (*r == COMMA)
+                               addrcount++;
+               }
+       } else {
+               addrcount = 0;
+       }
+
+       hoaddrsize = (addrcount + 1) * sizeof (char *);
+       hohaddrlist = malloc(hoaddrsize);
+       if (hohaddrlist == NULL) {
+               myerrno = ENOMEM;
+               goto error;
+       }
+
+       memset(hohaddrlist, 0x0, hoaddrsize);
+
+       alist = hohaddrlist;
+       for (t = 0, r = p ; r != q ; p = r + 1, t++) {
+               char saved;
+               while (r != q && *r != COMMA) r++;
+               saved = *r;
+               *r = 0x0;
+
+               alist[t] = malloc(hoaddrtype == AF_INET ? 4 : 16);
+               if (alist[t] == NULL) {
+                       myerrno = ENOMEM;
+                       goto error;
+               }
+
+               if (inet_pton(hoaddrtype, p, alist[t]) == -1)
+                       goto error;
+               *r = saved;
+       }
+       alist[t] = NULL;
+
+       ho->h_name = name;
+       ho->h_aliases = aliases;
+       ho->h_addrtype = hoaddrtype;
+       ho->h_length = holength;
+       ho->h_addr_list = hohaddrlist;
+
+       return (0);
+
+ error:
+       errno = myerrno;
+
+       if (name != NULL) free(name);
+       free_array(aliases, 0);
+
+       return (-1);
+}
+
+/* ------------------------- struct hostent------------------------- */
+
+
+
+/* +++++++++++++++++++++++++ struct netgrp +++++++++++++++++++++++++ */
+
+
+/*
+ * int irp_marshall_ng(const char *host, const char *user,
+ *                    const char *domain, char *buffer, size_t *len)
+ *
+ * notes:
+ *
+ *     See note for irp_marshall_ng_start
+ *
+ * return:
+ *
+ *     0 on success, 0 on failure.
+ *
+ */
+
+int
+irp_marshall_ng(const char *host, const char *user, const char *domain,
+               char **buffer, size_t *len) {
+       size_t need = 1; /* for nul byte */
+       const char *fieldsep = ",";
+
+       if (len == NULL) {
+               errno = EINVAL;
+               return (-1);
+       }
+
+       need += 4;                     /* two parens and two commas */
+       need += (host == NULL ? 0 : strlen(host));
+       need += (user == NULL ? 0 : strlen(user));
+       need += (domain == NULL ? 0 : strlen(domain));
+
+       if (buffer == NULL) {
+               *len = need;
+               return (0);
+       } else if (*buffer != NULL && need > *len) {
+               errno = EINVAL;
+               return (-1);
+       }
+
+       if (*buffer == NULL) {
+               need += 2;              /* for CRLF */
+               *buffer = memget(need);
+               if (*buffer == NULL) {
+                       errno = ENOMEM;
+                       return (-1);
+               }
+
+               *len = need;
+       }
+
+       (*buffer)[0] = '(';
+       (*buffer)[1] = '\0';
+
+       if (host != NULL)
+               strcat(*buffer, host);
+       strcat(*buffer, fieldsep);
+
+       if (user != NULL)
+               strcat(*buffer, user);
+       strcat(*buffer, fieldsep);
+
+       if (domain != NULL)
+               strcat(*buffer, domain);
+       strcat(*buffer, ")");
+
+       return (0);
+}
+
+
+
+/* ---------- */
+
+
+/*
+ * int irp_unmarshall_ng(const char **host, const char **user,
+ *                      const char **domain, char *buffer)
+ *
+ * notes:
+ *
+ *     Unpacks the BUFFER into 3 character arrays it allocates and assigns
+ *     to *HOST, *USER and *DOMAIN. If any field of the value is empty,
+ *     then the corresponding paramater value will be set to NULL.
+ *
+ * return:
+ *
+ *     0 on success and -1 on failure.
+ */
+
+int
+irp_unmarshall_ng(const char **hostp, const char **userp, const char **domainp,
+                 char *buffer)
+{
+       char *p, *q;
+       char fieldsep = ',';
+       int myerrno = EINVAL;
+       char *host, *user, *domain;
+
+       if (userp == NULL || hostp == NULL ||
+           domainp == NULL || buffer == NULL) {
+               errno = EINVAL;
+               return (-1);
+       }
+
+       host = user = domain = NULL;
+
+       p = buffer;
+       while (isspace(*p)) {
+               p++;
+       }
+       if (*p != '(') {
+               goto error;
+       }
+
+       q = p + 1;
+       while (*q && *q != fieldsep)
+               q++;
+       if (!*q) {
+               goto error;
+       } else if (q > p + 1) {
+               host = strndup(p, q - p);
+       }
+
+       p = q + 1;
+       if (!*p) {
+               goto error;
+       } else if (*p != fieldsep) {
+               q = p + 1;
+               while (*q && *q != fieldsep)
+                       q++;
+               if (!*q) {
+                       goto error;
+               }
+               user = strndup(p, q - p);
+       } else {
+               p++;
+       }
+
+       if (!*p) {
+               goto error;
+       } else if (*p != ')') {
+               q = p + 1;
+               while (*q && *q != ')')
+                       q++;
+               if (!*q) {
+                       goto error;
+               }
+               domain = strndup(p, q - p);
+       }
+       *hostp = host;
+       *userp = user;
+       *domainp = domain;
+
+       return (0);
+
+ error:
+       errno = myerrno;
+
+       if (host != NULL) free(host);
+       if (user != NULL) free(user);
+       if (domain != NULL) free(domain);
+
+       return (-1);
+}
+
+/* ------------------------- struct netgrp ------------------------- */
+
+
+
+
+/* +++++++++++++++++++++++++ struct nwent +++++++++++++++++++++++++ */
+
+
+/*
+ * int irp_marshall_nw(struct nwent *ne, char **buffer, size_t *len)
+ *
+ * notes:
+ *
+ *     See at top.
+ *
+ * return:
+ *
+ *     0 on success and -1 on failure.
+ *
+ */
+
+int
+irp_marshall_nw(struct nwent *ne, char **buffer, size_t *len) {
+       size_t need = 1;        /* for null byte */
+       char nAddrType[24];
+       char nNet[MAXPADDRSIZE];
+       const char *fieldsep = COLONSTR;
+
+       if (ne == NULL || len == NULL) {
+               return (-1);
+       }
+
+       strcpy(nAddrType, ADDR_T_STR(ne->n_addrtype));
+
+       if (inet_net_ntop(ne->n_addrtype, ne->n_addr, ne->n_length,
+                         nNet, sizeof nNet) == NULL) {
+               return (-1);
+       }
+
+
+       need += strlen(ne->n_name) + 1;
+       need += joinlength(ne->n_aliases) + 1;
+       need += strlen(nAddrType) + 1;
+       need += strlen(nNet) + 1;
+
+       if (buffer == NULL) {
+               *len = need;
+               return (0);
+       }
+
+       if (*buffer != NULL && need > *len) {
+               errno = EINVAL;
+               return (-1);
+       }
+
+       if (*buffer == NULL) {
+               need += 2;              /* for CRLF */
+               *buffer = memget(need);
+               if (*buffer == NULL) {
+                       errno = ENOMEM;
+                       return (-1);
+               }
+
+               *len = need;
+       }
+
+       strcpy(*buffer, ne->n_name);            strcat(*buffer, fieldsep);
+       joinarray(ne->n_aliases, *buffer, COMMA) ; strcat(*buffer, fieldsep);
+       strcat(*buffer, nAddrType);             strcat(*buffer, fieldsep);
+       strcat(*buffer, nNet);                  strcat(*buffer, fieldsep);
+
+       return (0);
+}
+
+
+
+/*
+ * int irp_unmarshall_nw(struct nwent *ne, char *buffer)
+ *
+ * notes:
+ *
+ *     See note up top.
+ *
+ * return:
+ *
+ *     0 on success and -1 on failure.
+ *
+ */
+
+int
+irp_unmarshall_nw(struct nwent *ne, char *buffer) {
+       char *p, *q;
+       int naddrtype;
+       long nnet;
+       int bits;
+       char *name = NULL;
+       char **aliases = NULL;
+       char tmpbuf[24];
+       char *tb;
+       char fieldsep = ':';
+       int myerrno = EINVAL;
+
+       if (ne == NULL || buffer == NULL) {
+               goto error;
+       }
+
+       p = buffer;
+
+       /* n_name field */
+       name = NULL;
+       if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0) {
+               goto error;
+       }
+
+
+       /* n_aliases field. Aliases are separated by commas */
+       q = strchr(p, fieldsep);
+       if (q == NULL) {
+               goto error;
+       }
+       aliases = splitarray(p, q, COMMA);
+       if (aliases == NULL) {
+               myerrno = errno;
+               goto error;
+       }
+       p = q + 1;
+
+
+       /* h_addrtype field */
+       tb = tmpbuf;
+       if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+           strlen(tb) == 0) {
+               goto error;
+       }
+       if (strcmp(tmpbuf, "AF_INET") == 0)
+               naddrtype = AF_INET;
+       else if (strcmp(tmpbuf, "AF_INET6") == 0)
+               naddrtype = AF_INET6;
+       else
+               goto error;
+
+
+       /* n_net field */
+       tb = tmpbuf;
+       if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+           strlen(tb) == 0) {
+               goto error;
+       }
+       nnet = 0;
+       bits = inet_net_pton(naddrtype, tmpbuf, &nnet, sizeof nnet);
+       if (bits < 0) {
+               goto error;
+       }
+
+       /* nnet = ntohl(nnet); */ /* keep in network order for nwent */
+
+       ne->n_name = name;
+       ne->n_aliases = aliases;
+       ne->n_addrtype = naddrtype;
+       ne->n_length = bits;
+       ne->n_addr = malloc(sizeof nnet);
+       if (ne->n_addr == NULL) {
+               goto error;
+       }
+
+       memcpy(ne->n_addr, &nnet, sizeof nnet);
+
+       return (0);
+
+ error:
+       errno = myerrno;
+
+       if (name != NULL) free(name);
+       free_array(aliases, 0);
+
+       return (-1);
+}
+
+
+/* ------------------------- struct nwent ------------------------- */
+
+
+/* +++++++++++++++++++++++++ struct netent +++++++++++++++++++++++++ */
+
+
+/*
+ * int irp_marshall_ne(struct netent *ne, char **buffer, size_t *len)
+ *
+ * notes:
+ *
+ *     See at top.
+ *
+ * return:
+ *
+ *     0 on success and -1 on failure.
+ *
+ */
+
+int
+irp_marshall_ne(struct netent *ne, char **buffer, size_t *len) {
+       size_t need = 1;        /* for null byte */
+       char nAddrType[24];
+       char nNet[MAXPADDRSIZE];
+       const char *fieldsep = COLONSTR;
+       long nval;
+
+       if (ne == NULL || len == NULL) {
+               return (-1);
+       }
+
+       strcpy(nAddrType, ADDR_T_STR(ne->n_addrtype));
+
+       nval = htonl(ne->n_net);
+       if (inet_ntop(ne->n_addrtype, &nval, nNet, sizeof nNet) == NULL) {
+               return (-1);
+       }
+
+       need += strlen(ne->n_name) + 1;
+       need += joinlength(ne->n_aliases) + 1;
+       need += strlen(nAddrType) + 1;
+       need += strlen(nNet) + 1;
+
+       if (buffer == NULL) {
+               *len = need;
+               return (0);
+       }
+
+       if (*buffer != NULL && need > *len) {
+               errno = EINVAL;
+               return (-1);
+       }
+
+       if (*buffer == NULL) {
+               need += 2;              /* for CRLF */
+               *buffer = memget(need);
+               if (*buffer == NULL) {
+                       errno = ENOMEM;
+                       return (-1);
+               }
+
+               *len = need;
+       }
+
+       strcpy(*buffer, ne->n_name);            strcat(*buffer, fieldsep);
+       joinarray(ne->n_aliases, *buffer, COMMA) ; strcat(*buffer, fieldsep);
+       strcat(*buffer, nAddrType);             strcat(*buffer, fieldsep);
+       strcat(*buffer, nNet);                  strcat(*buffer, fieldsep);
+
+       return (0);
+}
+
+
+
+/*
+ * int irp_unmarshall_ne(struct netent *ne, char *buffer)
+ *
+ * notes:
+ *
+ *     See note up top.
+ *
+ * return:
+ *
+ *     0 on success and -1 on failure.
+ *
+ */
+
+int
+irp_unmarshall_ne(struct netent *ne, char *buffer) {
+       char *p, *q;
+       int naddrtype;
+       long nnet;
+       int bits;
+       char *name = NULL;
+       char **aliases = NULL;
+       char tmpbuf[24];
+       char *tb;
+       char fieldsep = ':';
+       int myerrno = EINVAL;
+
+       if (ne == NULL || buffer == NULL) {
+               goto error;
+       }
+
+       p = buffer;
+
+       /* n_name field */
+       name = NULL;
+       if (getfield(&name, 0, &p, fieldsep) == NULL || strlen(name) == 0) {
+               goto error;
+       }
+
+
+       /* n_aliases field. Aliases are separated by commas */
+       q = strchr(p, fieldsep);
+       if (q == NULL) {
+               goto error;
+       }
+       aliases = splitarray(p, q, COMMA);
+       if (aliases == NULL) {
+               myerrno = errno;
+               goto error;
+       }
+       p = q + 1;
+
+
+       /* h_addrtype field */
+       tb = tmpbuf;
+       if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+           strlen(tb) == 0) {
+               goto error;
+       }
+       if (strcmp(tmpbuf, "AF_INET") == 0)
+               naddrtype = AF_INET;
+       else if (strcmp(tmpbuf, "AF_INET6") == 0)
+               naddrtype = AF_INET6;
+       else
+               goto error;
+
+
+       /* n_net field */
+       tb = tmpbuf;
+       if (getfield(&tb, sizeof tmpbuf, &p, fieldsep) == NULL ||
+           strlen(tb) == 0) {
+               goto error;
+       }
+       bits = inet_net_pton(naddrtype, tmpbuf, &nnet, sizeof nnet);
+       if (bits < 0) {
+               goto error;
+       }
+       nnet = ntohl(nnet);
+
+       ne->n_name = name;
+       ne->n_aliases = aliases;
+       ne->n_addrtype = naddrtype;
+       ne->n_net = nnet;
+
+       return (0);
+
+ error:
+       errno = myerrno;
+
+       if (name != NULL) free(name);
+       free_array(aliases, 0);
+
+       return (-1);
+}
+
+
+/* ------------------------- struct netent ------------------------- */
+
+
+/* =========================================================================== */
+
+
+/*
+ * static char ** splitarray(const char *buffer, const char *buffend, char delim)
+ *
+ * notes:
+ *
+ *     Split a delim separated astring. Not allowed
+ *     to have two delims next to each other. BUFFER points to begining of
+ *     string, BUFFEND points to one past the end of the string
+ *     (i.e. points at where the null byte would be if null
+ *     terminated).
+ *
+ * return:
+ *
+ *     Returns a malloced array of pointers, each pointer pointing to a
+ *     malloced string. If BUFEER is an empty string, then return values is
+ *     array of 1 pointer that is NULL. Returns NULL on failure.
+ *
+ */
+
+static char **
+splitarray(const char *buffer, const char *buffend, char delim) {
+       const char *p, *q;
+       int count = 0;
+       char **arr = NULL;
+       char **aptr;
+
+       if (buffend < buffer)
+               return (NULL);
+       else if (buffend > buffer && *buffer == delim)
+               return (NULL);
+       else if (buffend > buffer && *(buffend - 1) == delim)
+               return (NULL);
+
+       /* count the number of field and make sure none are empty */
+       if (buffend > buffer + 1) {
+               for (count = 1, q = buffer ; q != buffend ; q++) {
+                       if (*q == delim) {
+                               if (q > buffer && (*(q - 1) == delim)) {
+                                       errno = EINVAL;
+                                       return (NULL);
+                               }
+                               count++;
+                       }
+               }
+       }
+
+       if (count > 0) {
+               count++ ;               /* for NULL at end */
+               aptr = arr = malloc(count * sizeof (char *));
+               if (aptr == NULL) {
+                        errno = ENOMEM;
+                        return (NULL);
+                }
+
+               memset(arr, 0x0, count * sizeof (char *));
+               for (p = buffer ; p < buffend ; p++) {
+                       for (q = p ; *q != delim && q != buffend ; q++)
+                               /* nothing */;
+                       *aptr = strndup(p, q - p);
+
+                       p = q;
+                       aptr++;
+               }
+               *aptr = NULL;
+       } else {
+               arr = malloc(sizeof (char *));
+               if (arr == NULL) {
+                       errno = ENOMEM;
+                       return (NULL);
+               }
+
+               *arr = NULL;
+       }
+
+       return (arr);
+}
+
+
+
+
+/*
+ * static size_t joinlength(char * const *argv)
+ *
+ * return:
+ *
+ *     the number of bytes in all the arrays pointed at
+ *     by argv, including their null bytes(which will usually be turned
+ *     into commas).
+ *
+ *
+ */
+
+static size_t
+joinlength(char * const *argv) {
+       int len = 0;
+
+       while (argv && *argv) {
+               len += (strlen(*argv) + 1);
+               argv++;
+       }
+
+       return (len);
+}
+
+
+
+/*
+ * int joinarray(char * const *argv, char *buffer, char delim)
+ *
+ * notes:
+ *
+ *     Copy all the ARGV strings into the end of BUFFER
+ *     separating them with DELIM.  BUFFER is assumed to have
+ *     enough space to hold everything and to be already null-terminated.
+ *
+ * return:
+ *
+ *     0 unless argv or buffer is NULL.
+ *
+ *
+ */
+
+static int
+joinarray(char * const *argv, char *buffer, char delim) {
+       char * const *p;
+       char sep[2];
+
+       if (argv == NULL || buffer == NULL) {
+               errno = EINVAL;
+               return (-1);
+       }
+
+       sep[0] = delim;
+       sep[1] = 0x0;
+
+       for (p = argv ; *p != NULL ; p++) {
+               strcat(buffer, *p);
+               if (*(p + 1) != NULL) {
+                       strcat(buffer, sep);
+               }
+       }
+
+       return (0);
+}
+
+
+/*
+ * static char * getfield(char **res, size_t reslen, char **ptr, char delim)
+ *
+ * notes:
+ *
+ *     Stores in *RES, which is a buffer of length RESLEN, a
+ *     copy of the bytes from *PTR up to and including the first
+ *     instance of DELIM. If *RES is NULL, then it will be
+ *     assigned a malloced buffer to hold the copy. *PTR is
+ *     modified to point at the found delimiter.
+ *
+ * return:
+ *
+ *     If there was no delimiter, then NULL is returned,
+ *     otherewise *RES is returned.
+ *
+ */
+
+static char *
+getfield(char **res, size_t reslen, char **ptr, char delim) {
+       char *q;
+
+       if (res == NULL || ptr == NULL || *ptr == NULL) {
+               errno = EINVAL;
+               return (NULL);
+       }
+
+       q = strchr(*ptr, delim);
+
+       if (q == NULL) {
+               errno = EINVAL;
+               return (NULL);
+       } else {
+               if (*res == NULL) {
+                       *res = strndup(*ptr, q - *ptr);
+               } else {
+                       if ((size_t)(q - *ptr + 1) > reslen) { /* to big for res */
+                               errno = EINVAL;
+                               return (NULL);
+                       } else {
+                               strncpy(*res, *ptr, q - *ptr);
+                               (*res)[q - *ptr] = 0x0;
+                       }
+               }
+               *ptr = q + 1;
+       }
+
+       return (*res);
+}
+
+
+
+
+
+#ifndef HAVE_STRNDUP
+/*
+ * static char * strndup(const char *str, size_t len)
+ *
+ * notes:
+ *
+ *     like strdup, except do len bytes instead of the whole string. Always
+ *     null-terminates.
+ *
+ * return:
+ *
+ *     The newly malloced string.
+ *
+ */
+
+static char *
+strndup(const char *str, size_t len) {
+       char *p = malloc(len + 1);
+
+       if (p == NULL)
+               return (NULL);
+       strncpy(p, str, len);
+       p[len] = 0x0;
+       return (p);
+}
+#endif
+
+#if WANT_MAIN
+
+/*
+ * static int strcmp_nws(const char *a, const char *b)
+ *
+ * notes:
+ *
+ *     do a strcmp, except uneven lengths of whitespace compare the same
+ *
+ * return:
+ *
+ */
+
+static int
+strcmp_nws(const char *a, const char *b) {
+       while (*a && *b) {
+               if (isspace(*a) && isspace(*b)) {
+                       do {
+                               a++;
+                       } while (isspace(*a));
+                       do {
+                               b++;
+                       } while (isspace(*b));
+               }
+               if (*a < *b)
+                       return (-1);
+               else if (*a > *b)
+                       return (1);
+
+               a++;
+               b++;;
+       }
+
+       if (*a == *b)
+               return (0);
+       else if (*a > *b)
+               return (1);
+       else
+               return (-1);
+}
+
+#endif
+
+
+
+
+
+/*
+ * static void free_array(char **argv, size_t entries)
+ *
+ * notes:
+ *
+ *     Free argv and each of the pointers inside it. The end of
+ *     the array is when a NULL pointer is found inside. If
+ *     entries is > 0, then NULL pointers inside the array do
+ *     not indicate the end of the array.
+ *
+ */
+
+static void
+free_array(char **argv, size_t entries) {
+       char **p = argv;
+       int useEntries = (entries > 0);
+
+       if (argv == NULL)
+               return;
+
+       while ((useEntries && entries > 0) || *p) {
+               if (*p)
+                       free(*p);
+               p++;
+               if (useEntries)
+                       entries--;
+       }
+       free(argv);
+}
+
+
+
+
+
+/* ************************************************** */
+
+#if WANT_MAIN
+
+/* takes an option to indicate what sort of marshalling(read the code) and
+   an argument. If the argument looks like a marshalled buffer(has a ':'
+   embedded) then it's unmarshalled and the remarshalled and the new string
+   is compared to the old one.
+*/
+
+int
+main(int argc, char **argv) {
+       char buffer[1024];
+       char *b = &buffer[0];
+       size_t len = sizeof buffer;
+       char option;
+
+       if (argc < 2 || argv[1][0] != '-')
+               exit(1);
+
+       option = argv[1][1];
+       argv++;
+       argc--;
+
+
+#if 0
+       {
+               char buff[10];
+               char *p = argv[1], *q = &buff[0];
+
+               while (getfield(&q, sizeof buff, &p, ':') != NULL) {
+                       printf("field: \"%s\"\n", q);
+                       p++;
+               }
+               printf("p is now \"%s\"\n", p);
+       }
+#endif
+
+#if 0
+       {
+               char **x = splitarray(argv[1], argv[1] + strlen(argv[1]),
+                                     argv[2][0]);
+               char **p;
+
+               if (x == NULL)
+                       printf("split failed\n");
+
+               for (p = x ; p != NULL && *p != NULL ; p++) {
+                       printf("\"%s\"\n", *p);
+               }
+       }
+#endif
+
+#if 1
+       switch(option) {
+       case 'n': {
+               struct nwent ne;
+               int i;
+
+               if (strchr(argv[1], ':') != NULL) {
+                       if (irp_unmarshall_nw(&ne, argv[1]) != 0) {
+                               printf("Unmarhsalling failed\n");
+                               exit(1);
+                       }
+
+                       printf("Name: \"%s\"\n", ne.n_name);
+                       printf("Aliases:");
+                       for (i = 0 ; ne.n_aliases[i] != NULL ; i++)
+                               printf("\n\t\"%s\"", ne.n_aliases[i]);
+                       printf("\nAddrtype: %s\n", ADDR_T_STR(ne.n_addrtype));
+                       inet_net_ntop(ne.n_addrtype, ne.n_addr, ne.n_length,
+                                     buffer, sizeof buffer);
+                       printf("Net: \"%s\"\n", buffer);
+                       *((long*)ne.n_addr) = htonl(*((long*)ne.n_addr));
+                       inet_net_ntop(ne.n_addrtype, ne.n_addr, ne.n_length,
+                                     buffer, sizeof buffer);
+                       printf("Corrected Net: \"%s\"\n", buffer);
+               } else {
+                       struct netent *np1 = getnetbyname(argv[1]);
+                       ne.n_name = np1->n_name;
+                       ne.n_aliases = np1->n_aliases;
+                       ne.n_addrtype = np1->n_addrtype;
+                       ne.n_addr = &np1->n_net;
+                       ne.n_length = (IN_CLASSA(np1->n_net) ?
+                                      8 :
+                                      (IN_CLASSB(np1->n_net) ?
+                                       16 :
+                                       (IN_CLASSC(np1->n_net) ?
+                                        24 : -1)));
+                       np1->n_net = htonl(np1->n_net);
+                       if (irp_marshall_nw(&ne, &b, &len) != 0) {
+                               printf("Marshalling failed\n");
+                       }
+                       printf("%s\n", b);
+               }
+               break;
+       }
+
+
+       case 'r': {
+               char **hosts, **users, **domains;
+               size_t entries;
+               int i;
+               char *buff;
+               size_t size;
+               char *ngname;
+
+               if (strchr(argv[1], '(') != NULL) {
+                       if (irp_unmarshall_ng(&ngname, &entries,
+                                             &hosts, &users, &domains,
+                                             argv[1]) != 0) {
+                               printf("unmarshall failed\n");
+                               exit(1);
+                       }
+
+#define STRVAL(x) (x == NULL ? "*" : x)
+
+                       printf("%s {\n", ngname);
+                       for (i = 0 ; i < entries ; i++)
+                               printf("\t\"%s\" : \"%s\" : \"%s\"\n",
+                                      STRVAL(hosts[i]),
+                                      STRVAL(users[i]),
+                                      STRVAL(domains[i]));
+                       printf("}\n\n\n");
+
+
+                       irp_marshall_ng_start(ngname, NULL, &size);
+                       for (i = 0 ; i < entries ; i++)
+                               irp_marshall_ng_next(hosts[i], users[i],
+                                                    domains[i], NULL, &size);
+                       irp_marshall_ng_end(NULL, &size);
+
+                       buff = malloc(size);
+
+                       irp_marshall_ng_start(ngname, buff, &size);
+                       for (i = 0 ; i < entries ; i++) {
+                               if (irp_marshall_ng_next(hosts[i], users[i],
+                                                        domains[i], buff,
+                                                        &size) != 0)
+                                       printf("next marshalling failed.\n");
+                       }
+                       irp_marshall_ng_end(buff, &size);
+
+                       if (strcmp_nws(argv[1], buff) != 0) {
+                               printf("compare failed:\n\t%s\n\t%s\n",
+                                      buffer, argv[1]);
+                       } else {
+                               printf("compare ok\n");
+                       }
+               } else {
+                       char *h, *u, *d, *buff;
+                       size_t size;
+
+                       /* run through two times. First to figure out how
+                          much of a buffer we need. Second to do the
+                          actual marshalling */
+
+                       setnetgrent(argv[1]);
+                       irp_marshall_ng_start(argv[1], NULL, &size);
+                       while (getnetgrent(&h, &u, &d) == 1)
+                               irp_marshall_ng_next(h, u, d, NULL, &size);
+                       irp_marshall_ng_end(NULL, &size);
+                       endnetgrent(argv[1]);
+
+                       buff = malloc(size);
+
+                       setnetgrent(argv[1]);
+                       if (irp_marshall_ng_start(argv[1], buff, &size) != 0)
+                               printf("Marshalling start failed\n");
+
+                       while (getnetgrent(&h, &u, &d) == 1) {
+                               if (irp_marshall_ng_next(h, u, d, buff, &size)
+                                   != 0) {
+                                       printf("Marshalling failed\n");
+                               }
+                       }
+
+                       irp_marshall_ng_end(buff, &size);
+                       endnetgrent();
+
+                       printf("success: %s\n", buff);
+               }
+               break;
+       }
+
+
+
+       case 'h': {
+               struct hostent he, *hp;
+               int i;
+
+
+               if (strchr(argv[1], '@') != NULL) {
+                       if (irp_unmarshall_ho(&he, argv[1]) != 0) {
+                               printf("unmarshall failed\n");
+                               exit(1);
+                       }
+
+                       printf("Host: \"%s\"\nAliases:", he.h_name);
+                       for (i = 0 ; he.h_aliases[i] != NULL ; i++)
+                               printf("\n\t\t\"%s\"", he.h_aliases[i]);
+                       printf("\nAddr Type: \"%s\"\n",
+                              ADDR_T_STR(he.h_addrtype));
+                       printf("Length: %d\nAddresses:", he.h_length);
+                       for (i = 0 ; he.h_addr_list[i] != 0 ; i++) {
+                               inet_ntop(he.h_addrtype, he.h_addr_list[i],
+                                         buffer, sizeof buffer);
+                               printf("\n\t\"%s\"\n", buffer);
+                       }
+                       printf("\n\n");
+
+                       irp_marshall_ho(&he, &b, &len);
+                       if (strcmp(argv[1], buffer) != 0) {
+                               printf("compare failed:\n\t\"%s\"\n\t\"%s\"\n",
+                                      buffer, argv[1]);
+                       } else {
+                               printf("compare ok\n");
+                       }
+               } else {
+                       if ((hp = gethostbyname(argv[1])) == NULL) {
+                               perror("gethostbyname");
+                               printf("\"%s\"\n", argv[1]);
+                               exit(1);
+                       }
+
+                       if (irp_marshall_ho(hp, &b, &len) != 0) {
+                               printf("irp_marshall_ho failed\n");
+                               exit(1);
+                       }
+
+                       printf("success: \"%s\"\n", buffer);
+               }
+               break;
+       }
+
+
+       case 's': {
+               struct servent *sv;
+               struct servent sv1;
+
+               if (strchr(argv[1], ':') != NULL) {
+                       sv = &sv1;
+                       memset(sv, 0xef, sizeof (struct servent));
+                       if (irp_unmarshall_sv(sv, argv[1]) != 0) {
+                               printf("unmarshall failed\n");
+
+                       }
+
+                       irp_marshall_sv(sv, &b, &len);
+                       if (strcmp(argv[1], buffer) != 0) {
+                               printf("compare failed:\n\t\"%s\"\n\t\"%s\"\n",
+                                      buffer, argv[1]);
+                       } else {
+                               printf("compare ok\n");
+                       }
+               } else {
+                       if ((sv = getservbyname(argv[1], argv[2])) == NULL) {
+                               perror("getservent");
+                               exit(1);
+                       }
+
+                       if (irp_marshall_sv(sv, &b, &len) != 0) {
+                               printf("irp_marshall_sv failed\n");
+                               exit(1);
+                       }
+
+                       printf("success: \"%s\"\n", buffer);
+               }
+               break;
+       }
+
+       case 'g': {
+               struct group *gr;
+               struct group gr1;
+
+               if (strchr(argv[1], ':') != NULL) {
+                       gr = &gr1;
+                       memset(gr, 0xef, sizeof (struct group));
+                       if (irp_unmarshall_gr(gr, argv[1]) != 0) {
+                               printf("unmarshall failed\n");
+
+                       }
+
+                       irp_marshall_gr(gr, &b, &len);
+                       if (strcmp(argv[1], buffer) != 0) {
+                               printf("compare failed:\n\t\"%s\"\n\t\"%s\"\n",
+                                      buffer, argv[1]);
+                       } else {
+                               printf("compare ok\n");
+                       }
+               } else {
+                       if ((gr = getgrnam(argv[1])) == NULL) {
+                               perror("getgrnam");
+                               exit(1);
+                       }
+
+                       if (irp_marshall_gr(gr, &b, &len) != 0) {
+                               printf("irp_marshall_gr failed\n");
+                               exit(1);
+                       }
+
+                       printf("success: \"%s\"\n", buffer);
+               }
+               break;
+       }
+
+
+       case 'p': {
+               struct passwd *pw;
+               struct passwd pw1;
+
+               if (strchr(argv[1], ':') != NULL) {
+                       pw = &pw1;
+                       memset(pw, 0xef, sizeof (*pw));
+                       if (irp_unmarshall_pw(pw, argv[1]) != 0) {
+                               printf("unmarshall failed\n");
+                               exit(1);
+                       }
+
+                       printf("User: \"%s\"\nPasswd: \"%s\"\nUid: %ld\nGid: %ld\n",
+                              pw->pw_name, pw->pw_passwd, (long)pw->pw_uid,
+                              (long)pw->pw_gid);
+                       printf("Class: \"%s\"\nChange: %ld\nGecos: \"%s\"\n",
+                              pw->pw_class, (long)pw->pw_change, pw->pw_gecos);
+                       printf("Shell: \"%s\"\nDirectory: \"%s\"\n",
+                              pw->pw_shell, pw->pw_dir);
+
+                       pw = getpwnam(pw->pw_name);
+                       irp_marshall_pw(pw, &b, &len);
+                       if (strcmp(argv[1], buffer) != 0) {
+                               printf("compare failed:\n\t\"%s\"\n\t\"%s\"\n",
+                                      buffer, argv[1]);
+                       } else {
+                               printf("compare ok\n");
+                       }
+               } else {
+                       if ((pw = getpwnam(argv[1])) == NULL) {
+                               perror("getpwnam");
+                               exit(1);
+                       }
+
+                       if (irp_marshall_pw(pw, &b, &len) != 0) {
+                               printf("irp_marshall_pw failed\n");
+                               exit(1);
+                       }
+
+                       printf("success: \"%s\"\n", buffer);
+               }
+               break;
+       }
+
+       default:
+               printf("Wrong option: %c\n", option);
+               break;
+       }
+
+#endif
+
+       return (0);
+}
+
+#endif
diff --git a/lib/bind/irs/irs_data.c b/lib/bind/irs/irs_data.c
new file mode 100644 (file)
index 0000000..16609a4
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * 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(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: irs_data.c,v 1.1 2001/03/29 06:31:50 marka Exp $";
+#endif
+
+#include "port_before.h"
+
+#ifndef __BIND_NOSTATIC
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <resolv.h>
+#include <stdio.h>
+#include <isc/memcluster.h>
+
+#ifdef DO_PTHREADS
+#include <pthread.h>
+#endif
+
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_data.h"
+#undef _res
+#undef h_errno
+
+extern struct __res_state _res;
+extern int h_errno;
+
+#ifdef DO_PTHREADS
+static pthread_key_t   key;
+static int             once = 0;
+#else
+static struct net_data *net_data;
+#endif
+
+void
+irs_destroy(void) {
+#ifndef DO_PTHREADS
+       if (net_data != NULL)
+               net_data_destroy(net_data);
+       net_data = NULL;
+#endif
+}
+
+void
+net_data_destroy(void *p) {
+       struct net_data *net_data = p;
+
+       res_nclose(net_data->res);
+       if (net_data->gr != NULL) {
+               (*net_data->gr->close)(net_data->gr);
+               net_data->gr = NULL;
+       }
+       if (net_data->pw != NULL) {
+               (*net_data->pw->close)(net_data->pw);
+               net_data->pw = NULL;
+       }
+       if (net_data->sv != NULL) {
+               (*net_data->sv->close)(net_data->sv);
+               net_data->sv = NULL;
+       }
+       if (net_data->pr != NULL) {
+               (*net_data->pr->close)(net_data->pr);
+               net_data->pr = NULL;
+       }
+       if (net_data->ho != NULL) {
+               (*net_data->ho->close)(net_data->ho);
+               net_data->ho = NULL;
+       }
+       if (net_data->nw != NULL) {
+               (*net_data->nw->close)(net_data->nw);
+               net_data->nw = NULL;
+       }
+       if (net_data->ng != NULL) {
+               (*net_data->ng->close)(net_data->ng);
+               net_data->ng = NULL;
+       }
+
+       (*net_data->irs->close)(net_data->irs);
+       memput(net_data, sizeof *net_data);
+}
+
+/* applications that need a specific config file other than
+ * _PATH_IRS_CONF should call net_data_init directly rather than letting
+ *   the various wrapper functions make the first call. - brister
+ */
+
+struct net_data *
+net_data_init(const char *conf_file) {
+#ifdef DO_PTHREADS
+       static pthread_mutex_t keylock = PTHREAD_MUTEX_INITIALIZER;
+       struct net_data *net_data;
+
+       if (!once) {
+               pthread_mutex_lock(&keylock);
+               if (!once++)
+                       pthread_key_create(&key, net_data_destroy);
+               pthread_mutex_unlock(&keylock);
+       }
+       net_data = pthread_getspecific(key);
+#endif
+
+       if (net_data == NULL) {
+               net_data = net_data_create(conf_file);
+               if (net_data == NULL)
+                       return (NULL);
+#ifdef DO_PTHREADS
+               pthread_setspecific(key, net_data);
+#endif
+       }
+
+       return (net_data);
+}
+
+struct net_data *
+net_data_create(const char *conf_file) {
+       struct net_data *net_data;
+
+       net_data = memget(sizeof (struct net_data));
+       if (net_data == NULL)
+               return (NULL);
+       memset(net_data, 0, sizeof (struct net_data));
+
+       if ((net_data->irs = irs_gen_acc("", conf_file)) == NULL)
+               return (NULL);
+#ifndef DO_PTHREADS
+       (*net_data->irs->res_set)(net_data->irs, &_res, NULL);
+#endif
+
+       net_data->res = (*net_data->irs->res_get)(net_data->irs);
+       if (net_data->res == NULL)
+               return (NULL);
+
+       if (res_ninit(net_data->res) == -1)
+               return (NULL);
+
+       return (net_data);
+}
+
+
+
+void
+net_data_minimize(struct net_data *net_data) {
+       res_nclose(net_data->res);
+}
+
+struct __res_state *
+__res_state(void) {
+       /* NULL param here means use the default config file. */
+       struct net_data *net_data = net_data_init(NULL);
+       if (net_data && net_data->res)
+               return (net_data->res);
+
+       return (&_res);
+}
+
+int *
+__h_errno(void) {
+       /* NULL param here means use the default config file. */
+       struct net_data *net_data = net_data_init(NULL);
+       if (net_data && net_data->res)
+               return (&net_data->res->res_h_errno);
+       return (&h_errno);
+}
+
+void
+__h_errno_set(struct __res_state *res, int err) {
+
+       h_errno = res->res_h_errno = err;
+}
+
+#endif /*__BIND_NOSTATIC*/
diff --git a/lib/bind/irs/irs_data.h b/lib/bind/irs/irs_data.h
new file mode 100644 (file)
index 0000000..1639555
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+/*
+ * $Id: irs_data.h,v 1.1 2001/03/29 06:31:50 marka Exp $
+ */
+
+#ifndef __BIND_NOSTATIC
+
+#define        net_data_init           __net_data_init
+
+struct net_data {
+       struct irs_acc *        irs;
+
+       struct irs_gr *         gr;
+       struct irs_pw *         pw;
+       struct irs_sv *         sv;
+       struct irs_pr *         pr;
+       struct irs_ho *         ho;
+       struct irs_nw *         nw;
+       struct irs_ng *         ng;
+
+       struct group *          gr_last;
+       struct passwd *         pw_last;
+       struct servent *        sv_last;
+       struct protoent *       pr_last;
+       struct netent *         nw_last; /* should have been ne_last */
+       struct nwent *          nww_last;
+       struct hostent *        ho_last;
+
+       unsigned int            gr_stayopen :1;
+       unsigned int            pw_stayopen :1;
+       unsigned int            sv_stayopen :1;
+       unsigned int            pr_stayopen :1;
+       unsigned int            ho_stayopen :1;
+       unsigned int            nw_stayopen :1;
+
+       void *                  nw_data;
+       void *                  ho_data;
+
+       struct __res_state *    res;    /* for gethostent.c */
+
+};
+
+extern struct net_data *       net_data_init(const char *conf_file);
+extern void                    net_data_minimize(struct net_data *);
+
+#endif /*__BIND_NOSTATIC*/
diff --git a/lib/bind/irs/irs_p.h b/lib/bind/irs/irs_p.h
new file mode 100644 (file)
index 0000000..a4ed450
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+/*
+ * $Id: irs_p.h,v 1.1 2001/03/29 06:31:50 marka Exp $
+ */
+
+#ifndef _IRS_P_H_INCLUDED
+#define _IRS_P_H_INCLUDED
+
+#include <stdio.h>
+
+#include "pathnames.h"
+
+#define IRS_SV_MAXALIASES      35
+
+struct lcl_sv {
+       FILE *          fp;
+       char            line[BUFSIZ+1];
+       struct servent  serv;
+       char *          serv_aliases[IRS_SV_MAXALIASES];
+};
+
+#define        irs_nul_ng      __irs_nul_ng
+#define        map_v4v6_address __map_v4v6_address
+#define        make_group_list __make_group_list
+#define        irs_lclsv_fnxt  __irs_lclsv_fnxt
+
+extern void            map_v4v6_address(const char *src, char *dst);
+extern int             make_group_list(struct irs_gr *, const char *,
+                                       gid_t, gid_t *, int *);
+extern struct irs_ng * irs_nul_ng(struct irs_acc *);
+extern struct servent * irs_lclsv_fnxt(struct lcl_sv *);
+
+#endif
diff --git a/lib/bind/irs/lcl.c b/lib/bind/irs/lcl.c
new file mode 100644 (file)
index 0000000..3adc4cd
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * 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(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: lcl.c,v 1.1 2001/03/29 06:31:50 marka Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <netinet/in.h> 
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <isc/memcluster.h>
+
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "lcl_p.h"
+
+/* Forward. */
+
+static void            lcl_close(struct irs_acc *);
+static struct __res_state *    lcl_res_get(struct irs_acc *);
+static void            lcl_res_set(struct irs_acc *, struct __res_state *,
+                               void (*)(void *));
+
+/* Public */
+
+struct irs_acc *
+irs_lcl_acc(const char *options) {
+       struct irs_acc *acc;
+       struct lcl_p *lcl;
+
+       UNUSED(options);
+
+       if (!(acc = memget(sizeof *acc))) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(acc, 0x5e, sizeof *acc);
+       if (!(lcl = memget(sizeof *lcl))) {
+               errno = ENOMEM;
+               free(acc);
+               return (NULL);
+       }
+       memset(lcl, 0x5e, sizeof *lcl);
+       lcl->res = NULL;
+       lcl->free_res = NULL;
+       acc->private = lcl;
+#ifdef WANT_IRS_GR
+       acc->gr_map = irs_lcl_gr;
+#else
+       acc->gr_map = NULL;
+#endif
+#ifdef WANT_IRS_PW
+       acc->pw_map = irs_lcl_pw;
+#else
+       acc->pw_map = NULL;
+#endif
+       acc->sv_map = irs_lcl_sv;
+       acc->pr_map = irs_lcl_pr;
+       acc->ho_map = irs_lcl_ho;
+       acc->nw_map = irs_lcl_nw;
+       acc->ng_map = irs_lcl_ng;
+       acc->res_get = lcl_res_get;
+       acc->res_set = lcl_res_set;
+       acc->close = lcl_close;
+       return (acc);
+}
+
+/* Methods */
+static struct __res_state *
+lcl_res_get(struct irs_acc *this) {
+       struct lcl_p *lcl = (struct lcl_p *)this->private;
+
+       if (lcl->res == NULL) {
+               struct __res_state *res;
+               res = (struct __res_state *)malloc(sizeof *res);
+               if (res == NULL)
+                       return (NULL);
+               memset(res, 0, sizeof *res);
+               lcl_res_set(this, res, free);
+       }
+
+       if ((lcl->res->options & RES_INIT) == 0 &&
+           res_ninit(lcl->res) < 0)
+               return (NULL);
+
+       return (lcl->res);
+}
+
+static void
+lcl_res_set(struct irs_acc *this, struct __res_state *res,
+               void (*free_res)(void *)) {
+       struct lcl_p *lcl = (struct lcl_p *)this->private;
+
+       if (lcl->res && lcl->free_res) {
+               res_nclose(lcl->res);
+               (*lcl->free_res)(lcl->res);
+       }
+
+       lcl->res = res;
+       lcl->free_res = free_res;
+}
+
+static void
+lcl_close(struct irs_acc *this) {
+       struct lcl_p *lcl = (struct lcl_p *)this->private;
+
+       if (lcl) {
+               if (lcl->free_res)
+                       (*lcl->free_res)(lcl->res);
+               memput(lcl, sizeof *lcl);
+       }
+       memput(this, sizeof *this);
+}
diff --git a/lib/bind/irs/lcl_gr.c b/lib/bind/irs/lcl_gr.c
new file mode 100644 (file)
index 0000000..d70fac0
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 1989, 1993, 1995
+ *     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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: lcl_gr.c,v 1.1 2001/03/29 06:31:50 marka Exp $";
+/* from getgrent.c 8.2 (Berkeley) 3/21/94"; */
+/* from BSDI Id: getgrent.c,v 2.8 1996/05/28 18:15:14 bostic Exp $     */
+#endif /* LIBC_SCCS and not lint */
+
+/* extern */
+
+#include "port_before.h"
+
+#ifndef WANT_IRS_PW
+static int __bind_irs_gr_unneeded;
+#else
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <irs.h>
+#include <isc/memcluster.h>
+
+#include "irs_p.h"
+#include "lcl_p.h"
+#include "irp_p.h"
+
+#include "port_after.h"
+
+
+/* Types. */
+
+struct pvt {
+       FILE *          fp;
+       /*
+        * Need space to store the entries read from the group file.
+        * The members list also needs space per member, and the
+        * strings making up the user names must be allocated
+        * somewhere.  Rather than doing lots of small allocations,
+        * we keep one buffer and resize it as needed.
+        */
+       struct group    group;
+       size_t          nmemb;          /* Malloc'd max index of gr_mem[]. */
+       char *          membuf;
+       size_t          membufsize;
+};
+
+/* Forward. */
+
+static void            gr_close(struct irs_gr *);
+static struct group *  gr_next(struct irs_gr *);
+static struct group *  gr_byname(struct irs_gr *, const char *);
+static struct group *  gr_bygid(struct irs_gr *, gid_t);
+static void            gr_rewind(struct irs_gr *);
+static void            gr_minimize(struct irs_gr *);
+
+static int             grstart(struct pvt *);
+static char *          grnext(struct pvt *);
+static struct group *  grscan(struct irs_gr *, int, gid_t, const char *);
+
+/* Portability. */
+
+#ifndef SEEK_SET
+# define SEEK_SET 0
+#endif
+
+/* Public. */
+
+struct irs_gr *
+irs_lcl_gr(struct irs_acc *this) {
+       struct irs_gr *gr;
+       struct pvt *pvt;
+
+       UNUSED(this);
+
+       if (!(gr = memget(sizeof *gr))) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(gr, 0x5e, sizeof *gr);
+       if (!(pvt = memget(sizeof *pvt))) {
+               memput(gr, sizeof *gr);
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pvt, 0, sizeof *pvt);
+       gr->private = pvt;
+       gr->close = gr_close;
+       gr->next = gr_next;
+       gr->byname = gr_byname;
+       gr->bygid = gr_bygid;
+       gr->rewind = gr_rewind;
+       gr->list = make_group_list;
+       gr->minimize = gr_minimize;
+       gr->res_get = NULL;
+       gr->res_set = NULL;
+       return (gr);
+}
+
+/* Methods. */
+
+static void
+gr_close(struct irs_gr *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (pvt->fp)
+               (void)fclose(pvt->fp);
+       if (pvt->group.gr_mem)
+               free(pvt->group.gr_mem);
+       if (pvt->membuf)
+               free(pvt->membuf);
+       memput(pvt, sizeof *pvt);
+       memput(this, sizeof *this);
+}
+
+static struct group *
+gr_next(struct irs_gr *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (!pvt->fp && !grstart(pvt))
+               return (NULL);
+       return (grscan(this, 0, 0, NULL));
+}
+
+static struct group *
+gr_byname(struct irs_gr *this, const char *name) {
+       if (!grstart((struct pvt *)this->private))
+               return (NULL);
+       return (grscan(this, 1, 0, name));
+}
+
+static struct group *
+gr_bygid(struct irs_gr *this, gid_t gid) {
+       if (!grstart((struct pvt *)this->private))
+               return (NULL);
+       return (grscan(this, 1, gid, NULL));
+}
+
+static void
+gr_rewind(struct irs_gr *this) {
+       (void) grstart((struct pvt *)this->private);
+}
+
+static void
+gr_minimize(struct irs_gr *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (pvt->fp != NULL) {
+               (void)fclose(pvt->fp);
+               pvt->fp = NULL;
+       }
+}
+
+/* Private. */
+
+static int
+grstart(struct pvt *pvt) {
+       if (pvt->fp) {
+               if (fseek(pvt->fp, 0L, SEEK_SET) == 0)
+                       return (1);
+               (void)fclose(pvt->fp);
+       }
+       if (!(pvt->fp = fopen(_PATH_GROUP, "r")))
+               return (0);
+       if (fcntl(fileno(pvt->fp), F_SETFD, 1) < 0) {
+               fclose(pvt->fp);
+               return (0);
+       }
+       return (1);
+}
+
+#define        INITIAL_NMEMB   30                      /* about 120 bytes */
+#define        INITIAL_BUFSIZ  (INITIAL_NMEMB * 8)     /* about 240 bytes */
+
+static char *
+grnext(struct pvt *pvt) {
+       char *w, *e;
+       int ch;
+
+       /* Make sure we have a buffer. */
+       if (pvt->membuf == NULL) {
+               pvt->membuf = malloc(INITIAL_BUFSIZ);
+               if (pvt->membuf == NULL) {
+ enomem:
+                       errno = ENOMEM;
+                       return (NULL);
+               }
+               pvt->membufsize = INITIAL_BUFSIZ;
+       }
+
+       /* Read until EOF or EOL. */
+       w = pvt->membuf;
+       e = pvt->membuf + pvt->membufsize;
+       while ((ch = fgetc(pvt->fp)) != EOF && ch != '\n') {
+               /* Make sure we have room for this character and a \0. */
+               if (w + 1 == e) {
+                       size_t o = w - pvt->membuf;
+                       size_t n = pvt->membufsize * 2;
+                       char *t = realloc(pvt->membuf, n);
+
+                       if (t == NULL)
+                               goto enomem;
+                       pvt->membuf = t;
+                       pvt->membufsize = n;
+                       w = pvt->membuf + o;
+                       e = pvt->membuf + pvt->membufsize;
+               }
+               /* Store it. */
+               *w++ = (char)ch;
+       }
+
+       /* Hitting EOF on the first character really does mean EOF. */
+       if (w == pvt->membuf && ch == EOF) {
+               errno = ENOENT;
+               return (NULL);
+       }
+
+       /* Last line of /etc/group need not end with \n; we don't care. */
+       *w = '\0';
+       return (pvt->membuf);
+}
+
+static struct group *
+grscan(struct irs_gr *this, int search, gid_t gid, const char *name) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       size_t n;
+       char *bp, **m, *p;
+
+       /* Read lines until we find one that matches our search criteria. */
+       for (;;) {
+               if ((bp = grnext(pvt)) == NULL)
+                       return (NULL);
+
+               /* Optimize the usual case of searching for a name. */
+               pvt->group.gr_name = strsep(&bp, ":");
+               if (search && name != NULL &&
+                   strcmp(pvt->group.gr_name, name) != 0)
+                       continue;
+               if (bp == NULL || *bp == '\0')
+                       goto corrupt;
+
+               /* Skip past the password field. */
+               pvt->group.gr_passwd = strsep(&bp, ":");
+               if (bp == NULL || *bp == '\0')
+                       goto corrupt;
+
+               /* Checking for a gid. */
+               if ((p = strsep(&bp, ":")) == NULL)
+                       continue;
+               /*
+                * Unlike the tests above, the test below is supposed to be
+                * testing 'p' and not 'bp', in case you think it's a typo.
+                */
+               if (p == NULL || *p == '\0') {
+ corrupt:
+                       /* warning: corrupted %s file!", _PATH_GROUP */
+                       continue;
+               }
+               pvt->group.gr_gid = atoi(p);
+               if (search && name == NULL && (gid_t)pvt->group.gr_gid != gid)
+                       continue;
+
+               /* We want this record. */
+               break;
+       }
+
+       /*
+        * Count commas to find out how many members there might be.
+        * Note that commas separate, so if there is one comma there
+        * can be two members (group:*:id:user1,user2).  Add another
+        * to account for the NULL terminator.  As above, allocate
+        * largest of INITIAL_NMEMB, or 2*n.
+        */
+       n = 1;
+       if (bp != NULL)
+               for (n = 2, p = bp; (p = strpbrk(p, ", ")) != NULL; ++n)
+                       p += strspn(p, ", ");
+       if (n > pvt->nmemb || pvt->group.gr_mem == NULL) {
+               if ((n *= 2) < INITIAL_NMEMB)
+                       n = INITIAL_NMEMB;
+               if ((m = realloc(pvt->group.gr_mem, n * sizeof *m)) == NULL)
+                       return (NULL);
+               pvt->group.gr_mem = m;
+               pvt->nmemb = n;
+       }
+
+       /* Set the name pointers. */
+       for (m = pvt->group.gr_mem; (p = strsep(&bp, ", ")) != NULL;)
+               if (p[0] != '\0')
+                       *m++ = p;
+       *m = NULL;
+
+       return (&pvt->group);
+}
+
+#endif /* WANT_IRS_GR */
diff --git a/lib/bind/irs/lcl_ho.c b/lib/bind/irs/lcl_ho.c
new file mode 100644 (file)
index 0000000..a2d13e3
--- /dev/null
@@ -0,0 +1,576 @@
+/*
+ * Copyright (c) 1985, 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) 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.
+ */
+
+/* from gethostnamadr.c        8.1 (Berkeley) 6/4/93 */
+/* BIND Id: gethnamaddr.c,v 8.15 1996/05/22 04:56:30 vixie Exp $ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: lcl_ho.c,v 1.1 2001/03/29 06:31:50 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* Imports. */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <irs.h>
+#include <isc/memcluster.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "dns_p.h"
+#include "lcl_p.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) sprintf x
+#endif
+
+/* Definitions. */
+
+#define        MAXALIASES      35
+#define        MAXADDRS        35
+#define        Max(a,b)        ((a) > (b) ? (a) : (b))
+
+#if PACKETSZ > 1024
+#define        MAXPACKET       PACKETSZ
+#else
+#define        MAXPACKET       1024
+#endif
+
+struct pvt {
+       FILE *          fp;
+       struct hostent  host;
+       char *          h_addr_ptrs[MAXADDRS + 1];
+       char *          host_aliases[MAXALIASES];
+       char            hostbuf[8*1024];
+       u_char          host_addr[16];  /* IPv4 or IPv6 */
+       struct __res_state  *res;
+       void            (*free_res)(void *);
+};
+
+typedef union {
+       int32_t al;
+       char ac;
+} align;
+
+static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
+static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
+
+/* Forward. */
+
+static void            ho_close(struct irs_ho *this);
+static struct hostent *        ho_byname(struct irs_ho *this, const char *name);
+static struct hostent *        ho_byname2(struct irs_ho *this, const char *name,
+                                  int af);
+static struct hostent *        ho_byaddr(struct irs_ho *this, const void *addr,
+                                 int len, int af);
+static struct hostent *        ho_next(struct irs_ho *this);
+static void            ho_rewind(struct irs_ho *this);
+static void            ho_minimize(struct irs_ho *this);
+static struct __res_state * ho_res_get(struct irs_ho *this);
+static void            ho_res_set(struct irs_ho *this,
+                                  struct __res_state *res,
+                                  void (*free_res)(void *));
+static struct addrinfo * ho_addrinfo(struct irs_ho *this, const char *name,
+                                    const struct addrinfo *pai);
+
+static size_t          ns_namelen(const char *);
+static int             init(struct irs_ho *this);
+
+/* Portability. */
+
+#ifndef SEEK_SET
+# define SEEK_SET 0
+#endif
+
+/* Public. */
+
+struct irs_ho *
+irs_lcl_ho(struct irs_acc *this) {
+       struct irs_ho *ho;
+       struct pvt *pvt;
+
+       UNUSED(this);
+
+       if (!(pvt = memget(sizeof *pvt))) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pvt, 0, sizeof *pvt);
+       if (!(ho = memget(sizeof *ho))) {
+               memput(pvt, sizeof *pvt);
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(ho, 0x5e, sizeof *ho);
+       ho->private = pvt;
+       ho->close = ho_close;
+       ho->byname = ho_byname;
+       ho->byname2 = ho_byname2;
+       ho->byaddr = ho_byaddr;
+       ho->next = ho_next;
+       ho->rewind = ho_rewind;
+       ho->minimize = ho_minimize;
+       ho->res_get = ho_res_get;
+       ho->res_set = ho_res_set;
+       ho->addrinfo = ho_addrinfo;
+       return (ho);
+}
+
+/* Methods. */
+
+static void
+ho_close(struct irs_ho *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       ho_minimize(this);
+       if (pvt->fp)
+               (void) fclose(pvt->fp);
+       if (pvt->res && pvt->free_res)
+               (*pvt->free_res)(pvt->res);
+       memput(pvt, sizeof *pvt);
+       memput(this, sizeof *this);
+}
+
+static struct hostent *
+ho_byname(struct irs_ho *this, const char *name) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct hostent *hp;
+
+       if (init(this) == -1)
+               return (NULL);
+
+       if (pvt->res->options & RES_USE_INET6) {
+               hp = ho_byname2(this, name, AF_INET6);
+               if (hp)
+                       return (hp);
+       }
+       return (ho_byname2(this, name, AF_INET));
+}
+
+static struct hostent *
+ho_byname2(struct irs_ho *this, const char *name, int af) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct hostent *hp;
+       char **hap;
+       size_t n;
+       
+       if (init(this) == -1)
+               return (NULL);
+
+       ho_rewind(this);
+       n = ns_namelen(name);
+       while ((hp = ho_next(this)) != NULL) {
+               size_t nn;
+
+               if (hp->h_addrtype != af)
+                       continue;
+               nn = ns_namelen(hp->h_name);
+               if (strncasecmp(hp->h_name, name, Max(n, nn)) == 0)
+                       goto found;
+               for (hap = hp->h_aliases; *hap; hap++) {
+                       nn = ns_namelen(*hap);
+                       if (strncasecmp(*hap, name, Max(n, nn)) == 0)
+                               goto found;
+               }
+       }
+ found:
+       if (!hp) {
+               RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
+               return (NULL);
+       }
+       RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS);
+       return (hp);
+}
+
+static struct hostent *
+ho_byaddr(struct irs_ho *this, const void *addr, int len, int af) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       const u_char *uaddr = addr;
+       struct hostent *hp;
+       int size;
+       
+       if (init(this) == -1)
+               return (NULL);
+
+       if (af == AF_INET6 && len == IN6ADDRSZ &&
+           (!memcmp(uaddr, mapped, sizeof mapped) ||
+            !memcmp(uaddr, tunnelled, sizeof tunnelled))) {
+               /* Unmap. */
+               addr = (const u_char *)addr + sizeof mapped;
+               uaddr += sizeof mapped;
+               af = AF_INET;
+               len = INADDRSZ;
+       }
+       switch (af) {
+       case AF_INET:
+               size = INADDRSZ;
+               break;
+       case AF_INET6:
+               size = IN6ADDRSZ;
+               break;
+       default:
+               errno = EAFNOSUPPORT;
+               RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+               return (NULL);
+       }
+       if (size > len) {
+               errno = EINVAL;
+               RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+               return (NULL);
+       }
+
+       /*
+        * Do the search.
+        */
+       ho_rewind(this);
+       while ((hp = ho_next(this)) != NULL) {
+               char **hap;
+
+               for (hap = hp->h_addr_list; *hap; hap++) {
+                       const u_char *taddr = (const u_char *)*hap;
+                       int taf = hp->h_addrtype;
+                       int tlen = hp->h_length;
+
+                       if (taf == AF_INET6 && tlen == IN6ADDRSZ &&
+                           (!memcmp(taddr, mapped, sizeof mapped) ||
+                            !memcmp(taddr, tunnelled, sizeof tunnelled))) {
+                               /* Unmap. */
+                               taddr += sizeof mapped;
+                               taf = AF_INET;
+                               tlen = INADDRSZ;
+                       }
+                       if (taf == af && tlen == len &&
+                           !memcmp(taddr, uaddr, tlen))
+                               goto found;
+               }
+       }
+ found:
+       if (!hp) {
+               RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
+               return (NULL);
+       }
+       RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS);
+       return (hp);
+}
+
+static struct hostent *
+ho_next(struct irs_ho *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       char *cp, **q, *p;
+       char *bufp, *ndbuf, *dbuf = NULL;
+       int c, af, len, bufsiz, offset;
+
+       if (init(this) == -1)
+               return (NULL);
+
+       if (!pvt->fp)
+               ho_rewind(this);
+       if (!pvt->fp) {
+               RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+               return (NULL);
+       }
+       bufp = pvt->hostbuf;
+       bufsiz = sizeof pvt->hostbuf;
+       offset = 0;
+ again:
+       if (!(p = fgets(bufp + offset, bufsiz - offset, pvt->fp))) {
+               RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
+               if (dbuf)
+                       free(dbuf);
+               return (NULL);
+       }
+       if (!strchr(p, '\n') && !feof(pvt->fp)) {
+#define GROWBUF 1024
+               /* allocate space for longer line */
+               if (dbuf == NULL) {
+                       if ((ndbuf = malloc(bufsiz + GROWBUF)) != NULL)
+                               strcpy(ndbuf, bufp);
+               } else
+                       ndbuf = realloc(dbuf, bufsiz + GROWBUF);
+               if (ndbuf) {
+                       dbuf = ndbuf;
+                       bufp = dbuf;
+                       bufsiz += GROWBUF;
+                       offset = strlen(dbuf);
+               } else {
+                       /* allocation failed; skip this long line */
+                       while ((c = getc(pvt->fp)) != EOF)
+                               if (c == '\n')
+                                       break;
+                       if (c != EOF)
+                               ungetc(c, pvt->fp);
+               }
+               goto again;
+       }
+
+       p -= offset;
+       offset = 0;
+
+       if (*p == '#')
+               goto again;
+       if ((cp = strpbrk(p, "#\n")) != NULL)
+               *cp = '\0';
+       if (!(cp = strpbrk(p, " \t")))
+               goto again;
+       *cp++ = '\0';
+       if (inet_pton(AF_INET6, p, pvt->host_addr) > 0) {
+               af = AF_INET6;
+               len = IN6ADDRSZ;
+       } else if (inet_aton(p, (struct in_addr *)pvt->host_addr) > 0) {
+               if (pvt->res->options & RES_USE_INET6) {
+                       map_v4v6_address((char*)pvt->host_addr,
+                                        (char*)pvt->host_addr);
+                       af = AF_INET6;
+                       len = IN6ADDRSZ;
+               } else {
+                       af = AF_INET;
+                       len = INADDRSZ;
+               }
+       } else {
+               goto again;
+       }
+       pvt->h_addr_ptrs[0] = (char *)pvt->host_addr;
+       pvt->h_addr_ptrs[1] = NULL;
+       pvt->host.h_addr_list = pvt->h_addr_ptrs;
+       pvt->host.h_length = len;
+       pvt->host.h_addrtype = af;
+       while (*cp == ' ' || *cp == '\t')
+               cp++;
+       pvt->host.h_name = cp;
+       q = pvt->host.h_aliases = pvt->host_aliases;
+       if ((cp = strpbrk(cp, " \t")) != NULL)
+               *cp++ = '\0';
+       while (cp && *cp) {
+               if (*cp == ' ' || *cp == '\t') {
+                       cp++;
+                       continue;
+               }
+               if (q < &pvt->host_aliases[MAXALIASES - 1])
+                       *q++ = cp;
+               if ((cp = strpbrk(cp, " \t")) != NULL)
+                       *cp++ = '\0';
+       }
+       *q = NULL;
+       if (dbuf)
+               free(dbuf);
+       RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS);
+       return (&pvt->host);
+}
+
+static void
+ho_rewind(struct irs_ho *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (pvt->fp) {
+               if (fseek(pvt->fp, 0L, SEEK_SET) == 0)
+                       return;
+               (void)fclose(pvt->fp);
+       }
+       if (!(pvt->fp = fopen(_PATH_HOSTS, "r")))
+               return;
+       if (fcntl(fileno(pvt->fp), F_SETFD, 1) < 0) {
+               (void)fclose(pvt->fp);
+               pvt->fp = NULL;
+       }
+}
+
+static void
+ho_minimize(struct irs_ho *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (pvt->fp != NULL) {
+               (void)fclose(pvt->fp);
+               pvt->fp = NULL;
+       }
+       if (pvt->res)
+               res_nclose(pvt->res);
+} 
+
+static struct __res_state *
+ho_res_get(struct irs_ho *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (!pvt->res) {
+               struct __res_state *res;
+               res = (struct __res_state *)malloc(sizeof *res);
+               if (!res) {
+                       errno = ENOMEM;
+                       return (NULL);
+               }
+               memset(res, 0, sizeof *res);
+               ho_res_set(this, res, free);
+       }
+
+       return (pvt->res);
+}
+
+static void
+ho_res_set(struct irs_ho *this, struct __res_state *res,
+               void (*free_res)(void *)) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (pvt->res && pvt->free_res) {
+               res_nclose(pvt->res);
+               (*pvt->free_res)(pvt->res);
+       }
+
+       pvt->res = res;
+       pvt->free_res = free_res;
+}
+
+struct lcl_res_target {
+       struct lcl_res_target *next;
+       int family;
+};
+
+/* XXX */
+extern struct addrinfo *hostent2addrinfo __P((struct hostent *,
+                                             const struct addrinfo *pai));
+
+static struct addrinfo *
+ho_addrinfo(struct irs_ho *this, const char *name, const struct addrinfo *pai)
+{
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct hostent *hp;
+       struct lcl_res_target q, q2, *p;
+       struct addrinfo sentinel, *cur;
+
+       memset(&q, 0, sizeof(q2));
+       memset(&q2, 0, sizeof(q2));
+       memset(&sentinel, 0, sizeof(sentinel));
+       cur = &sentinel;
+
+       switch(pai->ai_family) {
+       case AF_UNSPEC:         /* INET6 then INET4 */
+               q.family = AF_INET6;
+               q.next = &q2;
+               q2.family = AF_INET;
+               break;
+       case AF_INET6:
+               q.family = AF_INET6;
+               break;
+       case AF_INET:
+               q.family = AF_INET;
+               break;
+       default:
+               RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); /* ??? */
+               return(NULL);
+       }
+
+       for (p = &q; p; p = p->next) {
+               struct addrinfo *ai;
+
+               hp = (*this->byname2)(this, name, p->family);
+               if (hp == NULL) {
+                       /* byname2 should've set an appropriate error */
+                       continue;
+               }
+               if ((hp->h_name == NULL) || (hp->h_name[0] == 0) ||
+                   (hp->h_addr_list[0] == NULL)) {
+                       RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+                       continue;
+               }
+
+               ai = hostent2addrinfo(hp, pai);
+               if (ai) {
+                       cur->ai_next = ai;
+                       while (cur && cur->ai_next)
+                               cur = cur->ai_next;
+               }
+       }
+
+       if (sentinel.ai_next == NULL)
+               RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
+
+       return(sentinel.ai_next);
+}
+
+/* Private. */
+
+static size_t
+ns_namelen(const char *s) {
+       int i;
+
+       for (i = strlen(s); i > 0 && s[i-1] == '.'; i--)
+               (void)NULL;
+       return ((size_t) i);
+}
+
+static int
+init(struct irs_ho *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       
+       if (!pvt->res && !ho_res_get(this))
+               return (-1);
+       if (((pvt->res->options & RES_INIT) == 0) &&
+           res_ninit(pvt->res) == -1)
+               return (-1);
+       return (0);
+}
diff --git a/lib/bind/irs/lcl_ng.c b/lib/bind/irs/lcl_ng.c
new file mode 100644 (file)
index 0000000..7edc28d
--- /dev/null
@@ -0,0 +1,444 @@
+/*
+ * 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(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: lcl_ng.c,v 1.1 2001/03/29 06:31:50 marka Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <irs.h>
+#include <isc/memcluster.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "lcl_p.h"
+
+/* Definitions */
+
+#define NG_HOST         0       /* Host name */
+#define NG_USER         1       /* User name */
+#define NG_DOM          2       /* and Domain name */
+#define LINSIZ         1024    /* Length of netgroup file line */
+
+/*
+ * XXX Warning XXX
+ * This code is a hack-and-slash special.  It realy needs to be
+ * rewritten with things like strdup, and realloc in mind.
+ * More reasonable data structures would not be a bad thing.
+ */
+
+/*
+ * Static Variables and functions used by setnetgrent(), getnetgrent() and
+ * endnetgrent().
+ * There are two linked lists:
+ * - linelist is just used by setnetgrent() to parse the net group file via.
+ *   parse_netgrp()
+ * - netgrp is the list of entries for the current netgroup
+ */
+struct linelist {
+       struct linelist *l_next;        /* Chain ptr. */
+       int             l_parsed;       /* Flag for cycles */
+       char *          l_groupname;    /* Name of netgroup */
+       char *          l_line;         /* Netgroup entrie(s) to be parsed */
+};
+
+struct ng_old_struct {
+       struct ng_old_struct *ng_next;  /* Chain ptr */
+       char *          ng_str[3];      /* Field pointers, see below */
+};
+
+struct pvt {
+       FILE                    *fp;
+       struct linelist         *linehead;
+       struct ng_old_struct    *nextgrp;
+       struct {
+               struct ng_old_struct    *gr;
+               char                    *grname;
+       } grouphead;
+};
+
+/* Forward */
+
+static void            ng_rewind(struct irs_ng *, const char*);
+static void            ng_close(struct irs_ng *);
+static int             ng_next(struct irs_ng *, const char **,
+                               const char **, const char **);
+static int             ng_test(struct irs_ng *, const char *,
+                               const char *, const char *,
+                               const char *);
+static void            ng_minimize(struct irs_ng *);
+
+static int             parse_netgrp(struct irs_ng *, const char*);
+static struct linelist *read_for_group(struct irs_ng *, const char *);
+static void            freelists(struct irs_ng *);
+
+/* Public */
+
+struct irs_ng *
+irs_lcl_ng(struct irs_acc *this) {
+       struct irs_ng *ng;
+       struct pvt *pvt;
+
+       UNUSED(this);
+       
+       if (!(ng = memget(sizeof *ng))) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(ng, 0x5e, sizeof *ng);
+       if (!(pvt = memget(sizeof *pvt))) {
+               memput(ng, sizeof *ng);
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pvt, 0, sizeof *pvt);
+       ng->private = pvt;
+       ng->close = ng_close;
+       ng->next = ng_next;
+       ng->test = ng_test;
+       ng->rewind = ng_rewind;
+       ng->minimize = ng_minimize;
+       return (ng);
+}
+
+/* Methods */
+
+static void
+ng_close(struct irs_ng *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       
+       if (pvt->fp != NULL)
+               fclose(pvt->fp);
+       freelists(this);
+       memput(pvt, sizeof *pvt);
+       memput(this, sizeof *this);
+}
+       
+/*
+ * Parse the netgroup file looking for the netgroup and build the list
+ * of netgrp structures. Let parse_netgrp() and read_for_group() do
+ * most of the work.
+ */
+static void
+ng_rewind(struct irs_ng *this, const char *group) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       
+       if (pvt->fp != NULL && fseek(pvt->fp, SEEK_CUR, 0L) == -1) {
+               fclose(pvt->fp);
+               pvt->fp = NULL;
+       }
+
+       if (pvt->fp == NULL || pvt->grouphead.gr == NULL || 
+           strcmp(group, pvt->grouphead.grname)) {
+               freelists(this);
+               if (pvt->fp != NULL)
+                       fclose(pvt->fp);
+               pvt->fp = fopen(_PATH_NETGROUP, "r");
+               if (pvt->fp != NULL) {
+                       if (parse_netgrp(this, group))
+                               freelists(this);
+                       if (!(pvt->grouphead.grname = strdup(group)))
+                               freelists(this);
+                       fclose(pvt->fp);
+                       pvt->fp = NULL;
+               }
+       }
+       pvt->nextgrp = pvt->grouphead.gr;
+}
+
+/*
+ * Get the next netgroup off the list.
+ */
+static int
+ng_next(struct irs_ng *this, const char **host, const char **user,
+       const char **domain)
+{
+       struct pvt *pvt = (struct pvt *)this->private;
+       
+       if (pvt->nextgrp) {
+               *host = pvt->nextgrp->ng_str[NG_HOST];
+               *user = pvt->nextgrp->ng_str[NG_USER];
+               *domain = pvt->nextgrp->ng_str[NG_DOM];
+               pvt->nextgrp = pvt->nextgrp->ng_next;
+               return (1);
+       }
+       return (0);
+}
+
+/*
+ * Search for a match in a netgroup.
+ */
+static int
+ng_test(struct irs_ng *this, const char *name,
+       const char *host, const char *user, const char *domain)
+{
+       const char *ng_host, *ng_user, *ng_domain;
+
+       ng_rewind(this, name);
+       while (ng_next(this, &ng_host, &ng_user, &ng_domain))
+               if ((host == NULL || ng_host == NULL || 
+                    !strcmp(host, ng_host)) &&
+                   (user ==  NULL || ng_user == NULL || 
+                    !strcmp(user, ng_user)) &&
+                   (domain == NULL || ng_domain == NULL ||
+                    !strcmp(domain, ng_domain))) {
+                       freelists(this);
+                       return (1);
+               }
+       freelists(this);
+       return (0);
+}
+
+static void
+ng_minimize(struct irs_ng *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (pvt->fp != NULL) {
+               (void)fclose(pvt->fp);
+               pvt->fp = NULL;
+       }
+}
+
+/* Private */
+
+/*
+ * endnetgrent() - cleanup
+ */
+static void
+freelists(struct irs_ng *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct linelist *lp, *olp;
+       struct ng_old_struct *gp, *ogp;
+
+       lp = pvt->linehead;
+       while (lp) {
+               olp = lp;
+               lp = lp->l_next;
+               free(olp->l_groupname);
+               free(olp->l_line);
+               free((char *)olp);
+       }
+       pvt->linehead = NULL;
+       if (pvt->grouphead.grname) {
+               free(pvt->grouphead.grname);
+               pvt->grouphead.grname = NULL;
+       }
+       gp = pvt->grouphead.gr;
+       while (gp) {
+               ogp = gp;
+               gp = gp->ng_next;
+               if (ogp->ng_str[NG_HOST])
+                       free(ogp->ng_str[NG_HOST]);
+               if (ogp->ng_str[NG_USER])
+                       free(ogp->ng_str[NG_USER]);
+               if (ogp->ng_str[NG_DOM])
+                       free(ogp->ng_str[NG_DOM]);
+               free((char *)ogp);
+       }
+       pvt->grouphead.gr = NULL;
+}
+
+/*
+ * Parse the netgroup file setting up the linked lists.
+ */
+static int
+parse_netgrp(struct irs_ng *this, const char *group) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       char *spos, *epos;
+       int len, strpos;
+       char *pos, *gpos;
+       struct ng_old_struct *grp;
+       struct linelist *lp = pvt->linehead;
+
+        /*
+         * First, see if the line has already been read in.
+         */
+       while (lp) {
+               if (!strcmp(group, lp->l_groupname))
+                       break;
+               lp = lp->l_next;
+       }
+       if (lp == NULL &&
+           (lp = read_for_group(this, group)) == NULL)
+               return (1);
+       if (lp->l_parsed) {
+               /*fprintf(stderr, "Cycle in netgroup %s\n", lp->l_groupname);*/
+               return (1);
+       } else
+               lp->l_parsed = 1;
+       pos = lp->l_line;
+       while (*pos != '\0') {
+               if (*pos == '(') {
+                       if (!(grp = malloc(sizeof (struct ng_old_struct)))) {
+                               freelists(this);
+                               errno = ENOMEM;
+                               return (1);
+                       }
+                       memset(grp, 0, sizeof (struct ng_old_struct));
+                       grp->ng_next = pvt->grouphead.gr;
+                       pvt->grouphead.gr = grp;
+                       pos++;
+                       gpos = strsep(&pos, ")");
+                       for (strpos = 0; strpos < 3; strpos++) {
+                               if ((spos = strsep(&gpos, ","))) {
+                                       while (*spos == ' ' || *spos == '\t')
+                                               spos++;
+                                       if ((epos = strpbrk(spos, " \t"))) {
+                                               *epos = '\0';
+                                               len = epos - spos;
+                                       } else
+                                               len = strlen(spos);
+                                       if (len > 0) {
+                                               if(!(grp->ng_str[strpos] 
+                                                  =  (char *)
+                                                  malloc(len + 1))) {
+                                                       freelists(this);
+                                                       return (1);
+                                               }
+                                               memcpy(grp->ng_str[strpos],
+                                                      spos,
+                                                      len + 1);
+                                       }
+                               } else
+                                       goto errout;
+                       }
+               } else {
+                       spos = strsep(&pos, ", \t");
+                       if (spos != NULL && parse_netgrp(this, spos)) {
+                               freelists(this);
+                               return (1);
+                       }
+               }
+               if (pos == NULL)
+                       break;
+               while (*pos == ' ' || *pos == ',' || *pos == '\t')
+                       pos++;
+       }
+       return (0);
+ errout:
+       /*fprintf(stderr, "Bad netgroup %s at ..%s\n", lp->l_groupname,
+                 spos);*/
+       return (1);
+}
+
+/*
+ * Read the netgroup file and save lines until the line for the netgroup
+ * is found. Return 1 if eof is encountered.
+ */
+static struct linelist *
+read_for_group(struct irs_ng *this, const char *group) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       char *pos, *spos, *linep = NULL, *olinep;
+       int len, olen, cont;
+       struct linelist *lp;
+       char line[LINSIZ + 1];
+       
+       while (fgets(line, LINSIZ, pvt->fp) != NULL) {
+               pos = line;
+               if (*pos == '#')
+                       continue;
+               while (*pos == ' ' || *pos == '\t')
+                       pos++;
+               spos = pos;
+               while (*pos != ' ' && *pos != '\t' && *pos != '\n' &&
+                       *pos != '\0')
+                       pos++;
+               len = pos - spos;
+               while (*pos == ' ' || *pos == '\t')
+                       pos++;
+               if (*pos != '\n' && *pos != '\0') {
+                       if (!(lp = malloc(sizeof (*lp)))) {
+                               freelists(this);
+                               return (NULL);
+                       }
+                       lp->l_parsed = 0;
+                       if (!(lp->l_groupname = malloc(len + 1))) {
+                               free(lp);
+                               freelists(this);
+                               return (NULL);
+                       }
+                       memcpy(lp->l_groupname, spos,  len);
+                       *(lp->l_groupname + len) = '\0';
+                       len = strlen(pos);
+                       olen = 0;
+                       olinep = NULL;
+
+                       /*
+                        * Loop around handling line continuations.
+                        */
+                       do {
+                               if (*(pos + len - 1) == '\n')
+                                       len--;
+                               if (*(pos + len - 1) == '\\') {
+                                       len--;
+                                       cont = 1;
+                               } else
+                                       cont = 0;
+                               if (len > 0) {
+                                       if (!(linep = malloc(olen + len + 1))){
+                                               if (olen > 0)
+                                                       free(olinep);
+                                               free(lp->l_groupname);
+                                               free(lp);
+                                               freelists(this);
+                                               errno = ENOMEM;
+                                               return (NULL);
+                                       }
+                                       if (olen > 0) {
+                                               memcpy(linep, olinep, olen);
+                                               free(olinep);
+                                       }
+                                       memcpy(linep + olen, pos, len);
+                                       olen += len;
+                                       *(linep + olen) = '\0';
+                                       olinep = linep;
+                               }
+                               if (cont) {
+                                       if (fgets(line, LINSIZ, pvt->fp)) {
+                                               pos = line;
+                                               len = strlen(pos);
+                                       } else
+                                               cont = 0;
+                               }
+                       } while (cont);
+                       lp->l_line = linep;
+                       lp->l_next = pvt->linehead;
+                       pvt->linehead = lp;
+                       
+                       /*
+                        * If this is the one we wanted, we are done.
+                        */
+                       if (!strcmp(lp->l_groupname, group))
+                               return (lp);
+               }
+       }
+       return (NULL);
+}
diff --git a/lib/bind/irs/lcl_nw.c b/lib/bind/irs/lcl_nw.c
new file mode 100644 (file)
index 0000000..d6a9710
--- /dev/null
@@ -0,0 +1,371 @@
+/*
+ * Copyright (c) 1989, 1993, 1995
+ *     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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: lcl_nw.c,v 1.1 2001/03/29 06:31:50 marka Exp $";
+/* from getgrent.c 8.2 (Berkeley) 3/21/94"; */
+/* from BSDI Id: getgrent.c,v 2.8 1996/05/28 18:15:14 bostic Exp $     */
+#endif /* LIBC_SCCS and not lint */
+
+/* Imports */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <irs.h>
+#include <isc/memcluster.h>
+
+#include "port_after.h"
+
+#include <isc/misc.h>
+#include "irs_p.h"
+#include "lcl_p.h"
+
+#define MAXALIASES 35
+#define MAXADDRSIZE 4
+
+struct pvt {
+       FILE *          fp;
+       char            line[BUFSIZ+1];
+       struct nwent    net;
+       char *          aliases[MAXALIASES];
+       char            addr[MAXADDRSIZE];
+       struct __res_state *  res;
+       void            (*free_res)(void *);
+};
+
+/* Forward */
+
+static void            nw_close(struct irs_nw *);
+static struct nwent *  nw_byname(struct irs_nw *, const char *, int);
+static struct nwent *  nw_byaddr(struct irs_nw *, void *, int, int);
+static struct nwent *  nw_next(struct irs_nw *);
+static void            nw_rewind(struct irs_nw *);
+static void            nw_minimize(struct irs_nw *);
+static struct __res_state * nw_res_get(struct irs_nw *this);
+static void            nw_res_set(struct irs_nw *this,
+                                  struct __res_state *res,
+                                  void (*free_res)(void *));
+
+static int             init(struct irs_nw *this);
+
+/* Portability. */
+
+#ifndef SEEK_SET
+# define SEEK_SET 0
+#endif
+
+/* Public */
+
+struct irs_nw *
+irs_lcl_nw(struct irs_acc *this) {
+       struct irs_nw *nw;
+       struct pvt *pvt;
+
+       UNUSED(this);
+
+       if (!(pvt = memget(sizeof *pvt))) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pvt, 0, sizeof *pvt);
+       if (!(nw = memget(sizeof *nw))) {
+               memput(pvt, sizeof *pvt);
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(nw, 0x5e, sizeof *nw);
+       nw->private = pvt;
+       nw->close = nw_close;
+       nw->byname = nw_byname;
+       nw->byaddr = nw_byaddr;
+       nw->next = nw_next;
+       nw->rewind = nw_rewind;
+       nw->minimize = nw_minimize;
+       nw->res_get = nw_res_get;
+       nw->res_set = nw_res_set;
+       return (nw);
+}
+
+/* Methods */
+
+static void
+nw_close(struct irs_nw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       
+       nw_minimize(this);
+       if (pvt->res && pvt->free_res)
+               (*pvt->free_res)(pvt->res);
+       if (pvt->fp)
+               (void)fclose(pvt->fp);
+       memput(pvt, sizeof *pvt);
+       memput(this, sizeof *this);
+}
+
+static struct nwent *
+nw_byaddr(struct irs_nw *this, void *net, int length, int type) {
+       struct nwent *p;
+       
+       if (init(this) == -1)
+               return(NULL);
+
+       nw_rewind(this);
+       while ((p = nw_next(this)) != NULL)
+               if (p->n_addrtype == type && p->n_length == length)
+                       if (bitncmp(p->n_addr, net, length) == 0)
+                               break;
+       return (p);
+}
+
+static struct nwent *
+nw_byname(struct irs_nw *this, const char *name, int type) {
+       struct nwent *p;
+       char **ap;
+       
+       if (init(this) == -1)
+               return(NULL);
+
+       nw_rewind(this);
+       while ((p = nw_next(this)) != NULL) {
+               if (ns_samename(p->n_name, name) == 1 &&
+                   p->n_addrtype == type)
+                       break;
+               for (ap = p->n_aliases; *ap; ap++)
+                       if ((ns_samename(*ap, name) == 1) &&
+                           (p->n_addrtype == type))
+                               goto found;
+       }
+ found:
+       return (p);
+}
+
+static void
+nw_rewind(struct irs_nw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       
+       if (pvt->fp) {
+               if (fseek(pvt->fp, 0L, SEEK_SET) == 0)
+                       return;
+               (void)fclose(pvt->fp);
+       }
+       if (!(pvt->fp = fopen(_PATH_NETWORKS, "r")))
+               return;
+       if (fcntl(fileno(pvt->fp), F_SETFD, 1) < 0) {
+               (void)fclose(pvt->fp);
+               pvt->fp = NULL;
+       }
+}
+
+static struct nwent *
+nw_next(struct irs_nw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct nwent *ret = NULL;
+       char *p, *cp, **q;
+       char *bufp, *ndbuf, *dbuf = NULL;
+       int c, bufsiz, offset = 0;
+
+       if (init(this) == -1)
+               return(NULL);
+
+       if (pvt->fp == NULL)
+               nw_rewind(this);
+       if (pvt->fp == NULL) {
+               RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+               return (NULL);
+       }
+       bufp = pvt->line;
+       bufsiz = sizeof(pvt->line);
+
+ again:
+       p = fgets(bufp + offset, bufsiz - offset, pvt->fp);
+       if (p == NULL)
+               goto cleanup;
+       if (!strchr(p, '\n') && !feof(pvt->fp)) {
+#define GROWBUF 1024
+               /* allocate space for longer line */
+               if (dbuf == NULL) {
+                       if ((ndbuf = malloc(bufsiz + GROWBUF)) != NULL)
+                               strcpy(ndbuf, bufp);
+               } else
+                       ndbuf = realloc(dbuf, bufsiz + GROWBUF);
+               if (ndbuf) {
+                       dbuf = ndbuf;
+                       bufp = dbuf;
+                       bufsiz += GROWBUF;
+                       offset = strlen(dbuf);
+               } else {
+                       /* allocation failed; skip this long line */
+                       while ((c = getc(pvt->fp)) != EOF)
+                               if (c == '\n')
+                                       break;
+                       if (c != EOF)
+                               ungetc(c, pvt->fp);
+               }
+               goto again;
+       }
+
+       p -= offset;
+       offset = 0;
+
+       if (*p == '#')
+               goto again;
+
+       cp = strpbrk(p, "#\n");
+       if (cp != NULL)
+               *cp = '\0';
+       pvt->net.n_name = p;
+       cp = strpbrk(p, " \t");
+       if (cp == NULL)
+               goto again;
+       *cp++ = '\0';
+       while (*cp == ' ' || *cp == '\t')
+               cp++;
+       p = strpbrk(cp, " \t");
+       if (p != NULL)
+               *p++ = '\0';
+       pvt->net.n_length = inet_net_pton(AF_INET, cp, pvt->addr,
+                                         sizeof pvt->addr);
+       if (pvt->net.n_length < 0)
+               goto again;
+       pvt->net.n_addrtype = AF_INET;
+       pvt->net.n_addr = pvt->addr;
+       q = pvt->net.n_aliases = pvt->aliases;
+       if (p != NULL) {
+               cp = p;
+               while (cp && *cp) {
+                       if (*cp == ' ' || *cp == '\t') {
+                               cp++;
+                               continue;
+                       }
+                       if (q < &pvt->aliases[MAXALIASES - 1])
+                               *q++ = cp;
+                       cp = strpbrk(cp, " \t");
+                       if (cp != NULL)
+                               *cp++ = '\0';
+               }
+       }
+       *q = NULL;
+       ret = &pvt->net;
+
+ cleanup:
+       if (dbuf)
+               free(dbuf);
+
+       return (ret);
+}
+
+static void
+nw_minimize(struct irs_nw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (pvt->res)
+               res_nclose(pvt->res);
+       if (pvt->fp != NULL) {
+               (void)fclose(pvt->fp);
+               pvt->fp = NULL;
+       }
+}
+
+static struct __res_state *
+nw_res_get(struct irs_nw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (!pvt->res) {
+               struct __res_state *res;
+               res = (struct __res_state *)malloc(sizeof *res);
+               if (!res) {
+                       errno = ENOMEM;
+                       return (NULL);
+               }
+               memset(res, 0, sizeof *res);
+               nw_res_set(this, res, free);
+       }
+
+       return (pvt->res);
+}
+
+static void
+nw_res_set(struct irs_nw *this, struct __res_state *res,
+               void (*free_res)(void *)) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (pvt->res && pvt->free_res) {
+               res_nclose(pvt->res);
+               (*pvt->free_res)(pvt->res);
+       }
+
+       pvt->res = res;
+       pvt->free_res = free_res;
+}
+
+static int
+init(struct irs_nw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       
+       if (!pvt->res && !nw_res_get(this))
+               return (-1);
+       if (((pvt->res->options & RES_INIT) == 0) &&
+           res_ninit(pvt->res) == -1)
+               return (-1);
+       return (0);
+}
diff --git a/lib/bind/irs/lcl_p.h b/lib/bind/irs/lcl_p.h
new file mode 100644 (file)
index 0000000..7da2f26
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+/*
+ * $Id: lcl_p.h,v 1.1 2001/03/29 06:31:50 marka Exp $
+ */
+
+/*
+ * lcl_p.h - private include file for the local accessor functions.
+ */
+
+#ifndef _LCL_P_H_INCLUDED
+#define _LCL_P_H_INCLUDED
+
+/*
+ * Object state.
+ */
+struct lcl_p {
+       struct __res_state *    res;
+       void                    (*free_res) __P((void *));
+};
+
+/*
+ * Externs.
+ */
+
+extern struct irs_acc *        irs_lcl_acc __P((const char *));
+extern struct irs_gr * irs_lcl_gr __P((struct irs_acc *));
+extern struct irs_pw * irs_lcl_pw __P((struct irs_acc *));
+extern struct irs_sv * irs_lcl_sv __P((struct irs_acc *));
+extern struct irs_pr * irs_lcl_pr __P((struct irs_acc *));
+extern struct irs_ho * irs_lcl_ho __P((struct irs_acc *));
+extern struct irs_nw * irs_lcl_nw __P((struct irs_acc *));
+extern struct irs_ng * irs_lcl_ng __P((struct irs_acc *));
+
+#endif /*_LCL_P_H_INCLUDED*/
diff --git a/lib/bind/irs/lcl_pr.c b/lib/bind/irs/lcl_pr.c
new file mode 100644 (file)
index 0000000..a4010a5
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 1989, 1993, 1995
+ *     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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: lcl_pr.c,v 1.1 2001/03/29 06:31:50 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* extern */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <irs.h>
+#include <isc/memcluster.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "lcl_p.h"
+
+#ifndef _PATH_PROTOCOLS
+#define _PATH_PROTOCOLS "/etc/protocols"
+#endif
+#define MAXALIASES      35
+
+/* Types */
+
+struct pvt {
+       FILE *          fp;
+       char            line[BUFSIZ+1];
+       struct protoent proto;
+       char *          proto_aliases[MAXALIASES];
+};
+
+/* Forward */
+
+static void                    pr_close(struct irs_pr *);
+static struct protoent *       pr_next(struct irs_pr *);
+static struct protoent *       pr_byname(struct irs_pr *, const char *);
+static struct protoent *       pr_bynumber(struct irs_pr *, int);
+static void                    pr_rewind(struct irs_pr *);
+static void                    pr_minimize(struct irs_pr *);
+
+/* Portability. */
+
+#ifndef SEEK_SET
+# define SEEK_SET 0
+#endif
+
+/* Public */
+
+struct irs_pr *
+irs_lcl_pr(struct irs_acc *this) {
+       struct irs_pr *pr;
+       struct pvt *pvt;
+       
+       if (!(pr = memget(sizeof *pr))) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       if (!(pvt = memget(sizeof *pvt))) {
+               memput(pr, sizeof *this);
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pvt, 0, sizeof *pvt);
+       pr->private = pvt;
+       pr->close = pr_close;
+       pr->byname = pr_byname;
+       pr->bynumber = pr_bynumber;
+       pr->next = pr_next;
+       pr->rewind = pr_rewind;
+       pr->minimize = pr_minimize;
+       pr->res_get = NULL;
+       pr->res_set = NULL;
+       return (pr);
+}
+
+/* Methods */
+
+static void
+pr_close(struct irs_pr *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (pvt->fp)
+               (void) fclose(pvt->fp);
+       memput(pvt, sizeof *pvt);
+       memput(this, sizeof *this);
+}
+
+static struct protoent *
+pr_byname(struct irs_pr *this, const char *name) {
+               
+       struct protoent *p;
+       char **cp;
+
+       pr_rewind(this);
+       while ((p = pr_next(this))) {
+               if (!strcmp(p->p_name, name))
+                       goto found;
+               for (cp = p->p_aliases; *cp; cp++)
+                       if (!strcmp(*cp, name))
+                               goto found;
+       }
+ found:
+       return (p);
+}
+
+static struct protoent *
+pr_bynumber(struct irs_pr *this, int proto) {
+       struct protoent *p;
+
+       pr_rewind(this);
+       while ((p = pr_next(this)))
+               if (p->p_proto == proto)
+                       break;
+       return (p);
+}
+
+static void
+pr_rewind(struct irs_pr *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       
+       if (pvt->fp) {
+               if (fseek(pvt->fp, 0L, SEEK_SET) == 0)
+                       return;
+               (void)fclose(pvt->fp);
+       }
+       if (!(pvt->fp = fopen(_PATH_PROTOCOLS, "r" )))
+               return;
+       if (fcntl(fileno(pvt->fp), F_SETFD, 1) < 0) {
+               (void)fclose(pvt->fp);
+               pvt->fp = NULL;
+       }
+}
+
+static struct protoent *
+pr_next(struct irs_pr *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       char *p, *cp, **q;
+       char *bufp, *ndbuf, *dbuf = NULL;
+       int c, bufsiz, offset;
+
+       if (!pvt->fp)
+               pr_rewind(this);
+       if (!pvt->fp)
+               return (NULL);
+       bufp = pvt->line;
+       bufsiz = BUFSIZ;
+       offset = 0;
+ again:
+       if ((p = fgets(bufp + offset, bufsiz - offset, pvt->fp)) == NULL) {
+               if (dbuf)
+                       free(dbuf);
+               return (NULL);
+       }
+       if (!strchr(p, '\n') && !feof(pvt->fp)) {
+#define GROWBUF 1024
+               /* allocate space for longer line */
+               if (dbuf == NULL) {
+                       if ((ndbuf = malloc(bufsiz + GROWBUF)) != NULL)
+                               strcpy(ndbuf, bufp);
+               } else
+                       ndbuf = realloc(dbuf, bufsiz + GROWBUF);
+               if (ndbuf) {
+                       dbuf = ndbuf;
+                       bufp = dbuf;
+                       bufsiz += GROWBUF;
+                       offset = strlen(dbuf);
+               } else {
+                       /* allocation failed; skip this long line */
+                       while ((c = getc(pvt->fp)) != EOF)
+                               if (c == '\n')
+                                       break;
+                       if (c != EOF)
+                               ungetc(c, pvt->fp);
+               }
+               goto again;
+       }
+
+       p -= offset;
+       offset = 0;
+
+       if (*p == '#')
+               goto again;
+       cp = strpbrk(p, "#\n");
+       if (cp != NULL)
+               *cp = '\0';
+       pvt->proto.p_name = p;
+       cp = strpbrk(p, " \t");
+       if (cp == NULL)
+               goto again;
+       *cp++ = '\0';
+       while (*cp == ' ' || *cp == '\t')
+               cp++;
+       p = strpbrk(cp, " \t");
+       if (p != NULL)
+               *p++ = '\0';
+       pvt->proto.p_proto = atoi(cp);
+       q = pvt->proto.p_aliases = pvt->proto_aliases;
+       if (p != NULL) {
+               cp = p;
+               while (cp && *cp) {
+                       if (*cp == ' ' || *cp == '\t') {
+                               cp++;
+                               continue;
+                       }
+                       if (q < &pvt->proto_aliases[MAXALIASES - 1])
+                               *q++ = cp;
+                       cp = strpbrk(cp, " \t");
+                       if (cp != NULL)
+                               *cp++ = '\0';
+               }
+       }
+       *q = NULL;
+       return (&pvt->proto);
+}
+
+static void
+pr_minimize(struct irs_pr *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (pvt->fp != NULL) {
+               (void)fclose(pvt->fp);
+               pvt->fp = NULL;
+       }
+}
diff --git a/lib/bind/irs/lcl_pw.c b/lib/bind/irs/lcl_pw.c
new file mode 100644 (file)
index 0000000..6b63749
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 1989, 1993, 1995
+ *     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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: lcl_pw.c,v 1.1 2001/03/29 06:31:51 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* Extern */
+
+#include "port_before.h"
+
+#ifndef WANT_IRS_PW
+static int __bind_irs_pw_unneeded;
+#else
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <db.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <utmp.h>
+#include <unistd.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "lcl_p.h"
+
+/*
+ * The lookup techniques and data extraction code here must be kept
+ * in sync with that in `pwd_mkdb'.
+ */
+
+/* Types */
+
+struct  pvt {
+       struct passwd   passwd;         /* password structure */
+       DB              *pw_db;         /* password database */
+       int             pw_keynum;      /* key counter */
+       int             warned;
+       u_int           max;
+       char *          line;
+};
+
+/* Forward */
+
+static void                    pw_close(struct irs_pw *);
+static struct passwd *         pw_next(struct irs_pw *);
+static struct passwd *         pw_byname(struct irs_pw *, const char *);
+static struct passwd *         pw_byuid(struct irs_pw *, uid_t);
+static void                    pw_rewind(struct irs_pw *);
+static void                    pw_minimize(struct irs_pw *);
+
+static int                     initdb(struct pvt *);
+static int                     hashpw(struct irs_pw *, DBT *);
+
+/* Public */
+struct irs_pw *
+irs_lcl_pw(struct irs_acc *this) {
+       struct irs_pw *pw;
+       struct pvt *pvt;
+
+       UNUSED(this);
+                
+        if (!(pw = memget(sizeof *pw))) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pw, 0x5e, sizeof *pw);
+       if (!(pvt = memget(sizeof *pvt))) {
+               free(pw);
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pvt, 0, sizeof *pvt);
+       pw->private = pvt;
+       pw->close = pw_close;
+       pw->next = pw_next;
+       pw->byname = pw_byname;
+       pw->byuid = pw_byuid;
+       pw->rewind = pw_rewind;
+       pw->minimize = pw_minimize;
+       pw->res_get = NULL;
+       pw->res_set = NULL;
+       return (pw);
+}
+
+/* Methods */
+
+static void
+pw_close(struct irs_pw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       
+       if (pvt->pw_db) {
+               (void)(pvt->pw_db->close)(pvt->pw_db);
+               pvt->pw_db = NULL;
+       }
+       if (pvt->line)
+               memput(pvt->line, pvt->max);
+       memput(pvt, sizeof *pvt);
+       memput(this, sizeof *this);
+}
+
+static struct passwd *
+pw_next(struct irs_pw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       
+       DBT key;
+       char bf[sizeof(pvt->pw_keynum) + 1];
+       if (!initdb(pvt))
+               return (NULL);
+       ++pvt->pw_keynum;
+       bf[0] = _PW_KEYBYNUM;
+       memcpy(bf + 1, (char *)&pvt->pw_keynum, sizeof(pvt->pw_keynum));
+       key.data = (u_char *)bf;
+       key.size = sizeof(pvt->pw_keynum) + 1;
+       return (hashpw(this, &key) ? &pvt->passwd : NULL);
+}
+static struct passwd *
+pw_byname(struct irs_pw *this, const char *name) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       DBT key;
+       int len, rval;
+       char bf[UT_NAMESIZE + 1];
+       if (!initdb(pvt))
+               return (NULL);
+       bf[0] = _PW_KEYBYNAME;
+       len = strlen(name);
+       memcpy(bf + 1, name, MIN(len, UT_NAMESIZE));
+       key.data = (u_char *)bf;
+       key.size = len + 1;
+       rval = hashpw(this, &key);
+       return (rval ? &pvt->passwd : NULL);
+}
+
+static struct passwd *
+pw_byuid(struct irs_pw *this, uid_t uid) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       DBT key;
+       int keyuid, rval;
+       char bf[sizeof(keyuid) + 1];
+       if (!initdb(pvt))
+               return (NULL);
+       bf[0] = _PW_KEYBYUID;
+       keyuid = uid;
+       memcpy(bf + 1, &keyuid, sizeof(keyuid));
+       key.data = (u_char *)bf;
+       key.size = sizeof(keyuid) + 1;
+       rval = hashpw(this, &key);
+       return (rval ? &pvt->passwd : NULL);
+}
+
+static void
+pw_rewind(struct irs_pw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       pvt->pw_keynum = 0;
+}
+
+static void
+pw_minimize(struct irs_pw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (pvt->pw_db != NULL) {
+               (void) (*pvt->pw_db->close)(pvt->pw_db);
+               pvt->pw_db = NULL;
+       }
+}
+
+/* Private. */
+
+static int
+initdb(struct pvt *pvt) {
+       const char *p;
+
+       if (pvt->pw_db) {
+               if (lseek((*pvt->pw_db->fd)(pvt->pw_db), 0L, SEEK_CUR) >= 0L)
+                       return (1);
+               else
+                       (void) (*pvt->pw_db->close)(pvt->pw_db);
+       }
+       pvt->pw_db = dbopen((p = _PATH_SMP_DB), O_RDONLY, 0, DB_HASH, NULL);
+       if (!pvt->pw_db)
+               pvt->pw_db = dbopen((p =_PATH_MP_DB), O_RDONLY,
+                                   0, DB_HASH, NULL);
+       if (pvt->pw_db)
+               return (1);
+       if (!pvt->warned) {
+               syslog(LOG_ERR, "%s: %m", p);
+               pvt->warned++;
+       }
+       return (0);
+}
+
+static int
+hashpw(struct irs_pw *this, DBT *key) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       char *p, *t, *l;
+       DBT data;
+       if ((pvt->pw_db->get)(pvt->pw_db, key, &data, 0))
+               return (0);
+       p = (char *)data.data;
+       if (data.size > pvt->max) {
+               size_t newlen = pvt->max + 1024;
+               char *p = memget(newlen);
+               if (p == NULL) {
+                       return (0);
+               }
+               if (pvt->line != NULL) {
+                       memcpy(p, pvt->line, pvt->max);
+                       memput(pvt->line, pvt->max);
+               }
+               pvt->max = newlen;
+               pvt->line = p;
+       }
+
+       /* THIS CODE MUST MATCH THAT IN pwd_mkdb. */
+       t = pvt->line;
+       l = pvt->line + pvt->max;
+#define EXPAND(e) if ((e = t) == NULL) return (0); else \
+                 do if (t >= l) return (0); while ((*t++ = *p++) != '\0')
+#define SCALAR(v) if (t + sizeof v >= l) return (0); else \
+                 (memmove(&(v), p, sizeof v), p += sizeof v)
+       EXPAND(pvt->passwd.pw_name);
+       EXPAND(pvt->passwd.pw_passwd);
+       SCALAR(pvt->passwd.pw_uid);
+       SCALAR(pvt->passwd.pw_gid);
+       SCALAR(pvt->passwd.pw_change);
+       EXPAND(pvt->passwd.pw_class);
+       EXPAND(pvt->passwd.pw_gecos);
+       EXPAND(pvt->passwd.pw_dir);
+       EXPAND(pvt->passwd.pw_shell);
+       SCALAR(pvt->passwd.pw_expire);
+       return (1);
+}
+
+#endif /* WANT_IRS_PW */
diff --git a/lib/bind/irs/lcl_sv.c b/lib/bind/irs/lcl_sv.c
new file mode 100644 (file)
index 0000000..b83ce9a
--- /dev/null
@@ -0,0 +1,431 @@
+/*
+ * Copyright (c) 1989, 1993, 1995
+ *     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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: lcl_sv.c,v 1.1 2001/03/29 06:31:51 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* extern */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#ifdef IRS_LCL_SV_DB
+#include <db.h>
+#endif
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <irs.h>
+#include <isc/memcluster.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "lcl_p.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+/* Types */
+
+struct pvt {
+#ifdef IRS_LCL_SV_DB
+       DB *            dbh;
+       int             dbf;
+#endif
+       struct lcl_sv   sv;
+};
+
+/* Forward */
+
+static void                    sv_close(struct irs_sv*);
+static struct servent *                sv_next(struct irs_sv *);
+static struct servent *                sv_byname(struct irs_sv *, const char *,
+                                         const char *);
+static struct servent *                sv_byport(struct irs_sv *, int, const char *);
+static void                    sv_rewind(struct irs_sv *);
+static void                    sv_minimize(struct irs_sv *);
+/*global*/ struct servent *    irs_lclsv_fnxt(struct lcl_sv *);
+#ifdef IRS_LCL_SV_DB
+static struct servent *                sv_db_rec(struct lcl_sv *, DBT *, DBT *);
+#endif
+
+/* Portability */
+
+#ifndef SEEK_SET
+# define SEEK_SET 0
+#endif
+
+/* Public */
+
+struct irs_sv *
+irs_lcl_sv(struct irs_acc *this) {
+       struct irs_sv *sv;
+       struct pvt *pvt;
+
+       UNUSED(this);
+       
+       if ((sv = memget(sizeof *sv)) == NULL) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(sv, 0x5e, sizeof *sv);
+       if ((pvt = memget(sizeof *pvt)) == NULL) {
+               memput(sv, sizeof *sv);
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pvt, 0, sizeof *pvt);
+       sv->private = pvt;
+       sv->close = sv_close;
+       sv->next = sv_next;
+       sv->byname = sv_byname;
+       sv->byport = sv_byport;
+       sv->rewind = sv_rewind;
+       sv->minimize = sv_minimize;
+       sv->res_get = NULL;
+       sv->res_set = NULL;
+#ifdef IRS_LCL_SV_DB
+       pvt->dbf = R_FIRST;
+#endif
+       return (sv);
+}
+
+/* Methods */
+
+static void
+sv_close(struct irs_sv *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       
+#ifdef IRS_LCL_SV_DB
+       if (pvt->dbh != NULL)
+               (*pvt->dbh->close)(pvt->dbh);
+#endif
+       if (pvt->sv.fp)
+               fclose(pvt->sv.fp);
+       memput(pvt, sizeof *pvt);
+       memput(this, sizeof *this);
+}
+
+static struct servent *
+sv_byname(struct irs_sv *this, const char *name, const char *proto) {
+#ifdef IRS_LCL_SV_DB
+       struct pvt *pvt = (struct pvt *)this->private;
+#endif
+       struct servent *p;
+       char **cp;
+
+       sv_rewind(this);
+#ifdef IRS_LCL_SV_DB
+       if (pvt->dbh != NULL) {
+               DBT key, data;
+
+               /* Note that (sizeof "/") == 2. */
+               if ((strlen(name) + sizeof "/" + proto ? strlen(proto) : 0)
+                   > sizeof pvt->sv.line)
+                       goto try_local;
+               key.data = pvt->sv.line;
+               key.size = SPRINTF((pvt->sv.line, "%s/%s", name,
+                                   proto ? proto : "")) + 1;
+               if (proto != NULL) {
+                       if ((*pvt->dbh->get)(pvt->dbh, &key, &data, 0) != 0)
+                               return (NULL);
+               } else if ((*pvt->dbh->seq)(pvt->dbh, &key, &data, R_CURSOR)
+                          != 0)
+                       return (NULL);
+               return (sv_db_rec(&pvt->sv, &key, &data));
+       }
+ try_local:
+#endif
+
+       while ((p = sv_next(this))) {
+               if (strcmp(name, p->s_name) == 0)
+                       goto gotname;
+               for (cp = p->s_aliases; *cp; cp++)
+                       if (strcmp(name, *cp) == 0)
+                               goto gotname;
+               continue;
+ gotname:
+               if (proto == NULL || strcmp(p->s_proto, proto) == 0)
+                       break;
+       }
+       return (p);
+}
+
+static struct servent *
+sv_byport(struct irs_sv *this, int port, const char *proto) {
+#ifdef IRS_LCL_SV_DB
+       struct pvt *pvt = (struct pvt *)this->private;
+#endif
+       struct servent *p;
+
+       sv_rewind(this);
+#ifdef IRS_LCL_SV_DB
+       if (pvt->dbh != NULL) {
+               DBT key, data;
+               u_short *ports;
+
+               ports = (u_short *)pvt->sv.line;
+               ports[0] = 0;
+               ports[1] = port;
+               key.data = ports;
+               key.size = sizeof(u_short) * 2;
+               if (proto && *proto) {
+                       strncpy((char *)ports + key.size, proto,
+                               BUFSIZ - key.size);
+                       key.size += strlen((char *)ports + key.size) + 1;
+                       if ((*pvt->dbh->get)(pvt->dbh, &key, &data, 0) != 0)
+                               return (NULL);
+               } else {
+                       if ((*pvt->dbh->seq)(pvt->dbh, &key, &data, R_CURSOR)
+                           != 0)
+                               return (NULL);
+               }
+               return (sv_db_rec(&pvt->sv, &key, &data));
+       }
+#endif
+       while ((p = sv_next(this))) {
+               if (p->s_port != port)
+                       continue;
+               if (proto == NULL || strcmp(p->s_proto, proto) == 0)
+                       break;
+       }
+       return (p);
+}
+
+static void
+sv_rewind(struct irs_sv *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (pvt->sv.fp) {
+               if (fseek(pvt->sv.fp, 0L, SEEK_SET) == 0)
+                       return;
+               (void)fclose(pvt->sv.fp);
+               pvt->sv.fp = NULL;
+       }
+#ifdef IRS_LCL_SV_DB
+       pvt->dbf = R_FIRST;
+       if (pvt->dbh != NULL)
+               return;
+       pvt->dbh = dbopen(_PATH_SERVICES_DB, O_RDONLY,O_RDONLY,DB_BTREE, NULL);
+       if (pvt->dbh != NULL) {
+               if (fcntl((*pvt->dbh->fd)(pvt->dbh), F_SETFD, 1) < 0) {
+                       (*pvt->dbh->close)(pvt->dbh);
+                       pvt->dbh = NULL;
+               }
+               return;
+       }
+#endif
+       if ((pvt->sv.fp = fopen(_PATH_SERVICES, "r")) == NULL)
+               return;
+       if (fcntl(fileno(pvt->sv.fp), F_SETFD, 1) < 0) {
+               (void)fclose(pvt->sv.fp);
+               pvt->sv.fp = NULL;
+       }
+}
+
+static struct servent *
+sv_next(struct irs_sv *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+#ifdef IRS_LCL_SV_DB
+       if (pvt->dbh == NULL && pvt->sv.fp == NULL)
+#else
+       if (pvt->sv.fp == NULL)
+#endif
+               sv_rewind(this);
+
+#ifdef IRS_LCL_SV_DB
+       if (pvt->dbh != NULL) {
+               DBT key, data;
+
+               while ((*pvt->dbh->seq)(pvt->dbh, &key, &data, pvt->dbf) == 0){
+                       pvt->dbf = R_NEXT;
+                       if (((char *)key.data)[0])
+                               continue;
+                       return (sv_db_rec(&pvt->sv, &key, &data));
+               }
+       }
+#endif
+
+       if (pvt->sv.fp == NULL)
+               return (NULL);
+       return (irs_lclsv_fnxt(&pvt->sv));
+}
+
+static void
+sv_minimize(struct irs_sv *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+#ifdef IRS_LCL_SV_DB
+       if (pvt->dbh != NULL) {
+               (*pvt->dbh->close)(pvt->dbh);
+               pvt->dbh = NULL;
+       }
+#endif
+       if (pvt->sv.fp != NULL) {
+               (void)fclose(pvt->sv.fp);
+               pvt->sv.fp = NULL;
+       }
+}
+
+/* Quasipublic. */
+
+struct servent *
+irs_lclsv_fnxt(struct lcl_sv *sv) {
+       char *p, *cp, **q;
+
+ again:
+       if ((p = fgets(sv->line, BUFSIZ, sv->fp)) == NULL)
+               return (NULL);
+       if (*p == '#')
+               goto again;
+       sv->serv.s_name = p;
+       while (*p && *p != '\n' && *p != ' ' && *p != '\t' && *p != '#')
+               ++p;
+       if (*p == '\0' || *p == '#' || *p == '\n')
+               goto again;
+       *p++ = '\0';
+       while (*p == ' ' || *p == '\t')
+               p++;
+       if (*p == '\0' || *p == '#' || *p == '\n')
+               goto again;
+       sv->serv.s_port = htons((u_short)strtol(p, &cp, 10));
+       if (cp == p || (*cp != '/' && *cp != ','))
+               goto again;
+       p = cp + 1;
+       sv->serv.s_proto = p;
+
+       q = sv->serv.s_aliases = sv->serv_aliases;
+
+       while (*p && *p != '\n' && *p != ' ' && *p != '\t' && *p != '#')
+               ++p;
+
+       while (*p == ' ' || *p == '\t') {
+               *p++ = '\0';
+               while (*p == ' ' || *p == '\t')
+                       ++p;
+               if (*p == '\0' || *p == '#' || *p == '\n')
+                       break;
+               if (q < &sv->serv_aliases[IRS_SV_MAXALIASES - 1])
+                       *q++ = p;
+               while (*p && *p != '\n' && *p != ' ' && *p != '\t' && *p != '#')
+                       ++p;
+       }
+               
+       *p = '\0';
+       *q = NULL;
+       return (&sv->serv);
+}
+
+/* Private. */
+
+#ifdef IRS_LCL_SV_DB
+static struct servent *
+sv_db_rec(struct lcl_sv *sv, DBT *key, DBT *data) {
+       char *p, **q;
+       int n;
+
+       p = data->data;
+       p[data->size - 1] = '\0';       /* should be, but we depend on it */
+
+       if (((char *)key->data)[0] == '\0') {
+               if (key->size < sizeof(u_short)*2 || data->size < 2)
+                       return (NULL);
+               sv->serv.s_port = ((u_short *)key->data)[1];
+               n = strlen(p) + 1;
+               if (n > sizeof(sv->line)) {
+                       n = sizeof(sv->line);
+               }
+               memcpy(sv->line, p, n);
+               sv->serv.s_name = sv->line;
+               if ((sv->serv.s_proto = strchr(sv->line, '/')) != NULL)
+                       *(sv->serv.s_proto)++ = '\0';
+               p += n;
+               data->size -= n;
+       } else {
+               if (data->size < sizeof(u_short) + 1)
+                       return (NULL);
+               if (key->size > sizeof(sv->line))
+                       key->size = sizeof(sv->line);
+               ((char *)key->data)[key->size - 1] = '\0';
+               memcpy(sv->line, key->data, key->size);
+               sv->serv.s_name = sv->line;
+               if ((sv->serv.s_proto = strchr(sv->line, '/')) != NULL)
+                       *(sv->serv.s_proto)++ = '\0';
+               sv->serv.s_port = *(u_short *)data->data;
+               p += sizeof(u_short);
+               data->size -= sizeof(u_short);
+       }
+       q = sv->serv.s_aliases = sv->serv_aliases;
+       while (data->size > 0 && q < &sv->serv_aliases[IRS_SV_MAXALIASES - 1]) {
+
+               *q++ = p;
+               n = strlen(p) + 1;
+               data->size -= n;
+               p += n;
+       }
+       *q = NULL;
+       return (&sv->serv);
+}
+#endif
diff --git a/lib/bind/irs/nis.c b/lib/bind/irs/nis.c
new file mode 100644 (file)
index 0000000..e0ceccc
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * 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 rcsid[] = "$Id: nis.c,v 1.1 2001/03/29 06:31:51 marka Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#ifdef WANT_IRS_NIS
+
+#include <rpc/rpc.h>
+#include <rpc/xdr.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <netinet/in.h> 
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "hesiod.h"
+#include "nis_p.h"
+
+/* Forward */
+
+static void            nis_close(struct irs_acc *);
+static struct __res_state * nis_res_get(struct irs_acc *);
+static void            nis_res_set(struct irs_acc *, struct __res_state *,
+                               void (*)(void *));
+
+/* Public */
+
+struct irs_acc *
+irs_nis_acc(const char *options) {
+       struct nis_p *nis;
+       struct irs_acc *acc;
+       char *domain;
+
+       UNUSED(options);
+
+       if (yp_get_default_domain(&domain) != 0)
+               return (NULL);
+       if (!(nis = memget(sizeof *nis))) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(nis, 0, sizeof *nis);
+       if (!(acc = memget(sizeof *acc))) {
+               memput(nis, sizeof *nis);
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(acc, 0x5e, sizeof *acc);
+       acc->private = nis;
+       nis->domain = strdup(domain);
+#ifdef WANT_IRS_GR
+       acc->gr_map = irs_nis_gr;
+#else
+       acc->gr_map = NULL;
+#endif
+#ifdef WANT_IRS_PW
+       acc->pw_map = irs_nis_pw;
+#else
+       acc->pw_map = NULL;
+#endif
+       acc->sv_map = irs_nis_sv;
+       acc->pr_map = irs_nis_pr;
+       acc->ho_map = irs_nis_ho;
+       acc->nw_map = irs_nis_nw;
+       acc->ng_map = irs_nis_ng;
+       acc->res_get = nis_res_get;
+       acc->res_set = nis_res_set;
+       acc->close = nis_close;
+       return (acc);
+}
+
+/* Methods */
+
+static struct __res_state *
+nis_res_get(struct irs_acc *this) {
+       struct nis_p *nis = (struct nis_p *)this->private;
+
+       if (nis->res == NULL) {
+               struct __res_state *res;
+               res = (struct __res_state *)malloc(sizeof *res);
+               if (res == NULL)
+                       return (NULL);
+               memset(res, 0, sizeof *res);
+               nis_res_set(this, res, free);
+       }
+
+       if ((nis->res->options & RES_INIT) == 0 &&
+           res_ninit(nis->res) < 0)
+               return (NULL);
+
+       return (nis->res);
+}
+
+static void
+nis_res_set(struct irs_acc *this, struct __res_state *res,
+               void (*free_res)(void *)) {
+       struct nis_p *nis = (struct nis_p *)this->private;
+
+       if (nis->res && nis->free_res) {
+               res_nclose(nis->res);
+               (*nis->free_res)(nis->res);
+       }
+
+       nis->res = res;
+       nis->free_res = free_res;
+}
+
+static void
+nis_close(struct irs_acc *this) {
+       struct nis_p *nis = (struct nis_p *)this->private;
+
+       if (nis->res && nis->free_res)
+               (*nis->free_res)(nis->res);
+       free(nis->domain);
+       memput(nis, sizeof *nis);
+       memput(this, sizeof *this);
+}
+
+#endif /*WANT_IRS_NIS*/
diff --git a/lib/bind/irs/nis_gr.c b/lib/bind/irs/nis_gr.c
new file mode 100644 (file)
index 0000000..a617fd3
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 1989, 1993, 1995
+ *     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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: nis_gr.c,v 1.1 2001/03/29 06:31:51 marka Exp $";
+/* from getgrent.c 8.2 (Berkeley) 3/21/94"; */
+/* from BSDI Id: getgrent.c,v 2.8 1996/05/28 18:15:14 bostic Exp $     */
+#endif /* LIBC_SCCS and not lint */
+
+/* Imports */
+
+#include "port_before.h"
+
+#if !defined(WANT_IRS_GR) || !defined(WANT_IRS_NIS)
+static int __bind_irs_gr_unneeded;
+#else
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <isc/memcluster.h>
+
+#include <rpc/rpc.h>
+#include <rpc/xdr.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+
+#include <errno.h>
+#include <grp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <isc/memcluster.h>
+
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "nis_p.h"
+
+/* Definitions */
+
+struct pvt {
+       int             needrewind;
+       char *          nis_domain;
+       char *          curkey_data;
+       int             curkey_len;
+       char *          curval_data;
+       int             curval_len;
+       /*
+        * Need space to store the entries read from the group file.
+        * The members list also needs space per member, and the
+        * strings making up the user names must be allocated
+        * somewhere.  Rather than doing lots of small allocations,
+        * we keep one buffer and resize it as needed.
+        */
+       struct group    group;
+       size_t          nmemb;          /* Malloc'd max index of gr_mem[]. */
+       char *          membuf;
+       size_t          membufsize;
+};
+
+enum do_what { do_none = 0x0, do_key = 0x1, do_val = 0x2, do_all = 0x3 };
+
+static /*const*/ char group_bygid[] =  "group.bygid";
+static /*const*/ char group_byname[] = "group.byname";
+
+/* Forward */
+
+static void            gr_close(struct irs_gr *);
+static struct group *  gr_next(struct irs_gr *);
+static struct group *  gr_byname(struct irs_gr *, const char *);
+static struct group *  gr_bygid(struct irs_gr *, gid_t);
+static void            gr_rewind(struct irs_gr *);
+static void            gr_minimize(struct irs_gr *);
+
+static struct group *  makegroupent(struct irs_gr *);
+static void            nisfree(struct pvt *, enum do_what);
+
+/* Public */
+
+struct irs_gr *
+irs_nis_gr(struct irs_acc *this) {
+       struct irs_gr *gr;
+       struct pvt *pvt;
+
+       if (!(gr = memget(sizeof *gr))) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(gr, 0x5e, sizeof *gr);
+       if (!(pvt = memget(sizeof *pvt))) {
+               memput(gr, sizeof *gr);
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pvt, 0, sizeof *pvt);
+       pvt->needrewind = 1;
+       pvt->nis_domain = ((struct nis_p *)this->private)->domain;
+       gr->private = pvt;
+       gr->close = gr_close;
+       gr->next = gr_next;
+       gr->byname = gr_byname;
+       gr->bygid = gr_bygid;
+       gr->rewind = gr_rewind;
+       gr->list = make_group_list;
+       gr->minimize = gr_minimize;
+       gr->res_get = NULL;
+       gr->res_set = NULL;
+       return (gr);
+}
+
+/* Methods */
+
+static void
+gr_close(struct irs_gr *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (pvt->group.gr_mem)
+               free(pvt->group.gr_mem);
+       if (pvt->membuf)
+               free(pvt->membuf);
+       memput(pvt, sizeof *pvt);
+       memput(this, sizeof *this);
+}
+
+static struct group *
+gr_next(struct irs_gr *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct group *rval;
+       int r;
+
+       do {
+               if (pvt->needrewind) {
+                       nisfree(pvt, do_all);
+                       r = yp_first(pvt->nis_domain, group_byname,
+                                    &pvt->curkey_data, &pvt->curkey_len,
+                                    &pvt->curval_data, &pvt->curval_len);
+                       pvt->needrewind = 0;
+               } else {
+                       char *newkey_data;
+                       int newkey_len;
+
+                       nisfree(pvt, do_val);
+                       r = yp_next(pvt->nis_domain, group_byname,
+                                   pvt->curkey_data, pvt->curkey_len,
+                                   &newkey_data, &newkey_len,
+                                   &pvt->curval_data, &pvt->curval_len);
+                       nisfree(pvt, do_key);
+                       pvt->curkey_data = newkey_data;
+                       pvt->curkey_len = newkey_len;
+               }
+               if (r != 0) {
+                       errno = ENOENT;
+                       return (NULL);
+               }
+               rval = makegroupent(this);
+       } while (rval == NULL);
+       return (rval);
+}
+
+static struct group *
+gr_byname(struct irs_gr *this, const char *name) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       int r;
+
+       nisfree(pvt, do_val);
+       r = yp_match(pvt->nis_domain, group_byname, name, strlen(name),
+                    &pvt->curval_data, &pvt->curval_len);
+       if (r != 0) {
+               errno = ENOENT;
+               return (NULL);
+       }
+       return (makegroupent(this));
+}
+
+static struct group *
+gr_bygid(struct irs_gr *this, gid_t gid) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       char tmp[sizeof "4294967295"];
+       int r;
+
+       nisfree(pvt, do_val);
+       (void) sprintf(tmp, "%u", (unsigned int)gid);
+       r = yp_match(pvt->nis_domain, group_bygid, tmp, strlen(tmp),
+                    &pvt->curval_data, &pvt->curval_len);
+       if (r != 0) {
+               errno = ENOENT;
+               return (NULL);
+       }
+       return (makegroupent(this));
+}
+
+static void
+gr_rewind(struct irs_gr *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       pvt->needrewind = 1;
+}
+
+static void
+gr_minimize(struct irs_gr *this) {
+       UNUSED(this);
+       /* NOOP */
+}
+
+/* Private */
+
+static struct group *
+makegroupent(struct irs_gr *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       unsigned int num_members = 0;
+       char *cp, **new;
+       u_long t;
+
+       if (pvt->group.gr_mem) {
+               free(pvt->group.gr_mem);
+               pvt->group.gr_mem = NULL;
+               pvt->nmemb = 0;
+       }
+       if (pvt->membuf)
+               free(pvt->membuf);
+       pvt->membuf = pvt->curval_data;
+       pvt->curval_data = NULL;
+
+       cp = pvt->membuf;
+       pvt->group.gr_name = cp;
+       if (!(cp = strchr(cp, ':')))
+               goto cleanup;
+       *cp++ = '\0';
+       
+       pvt->group.gr_passwd = cp;
+       if (!(cp = strchr(cp, ':')))
+               goto cleanup;
+       *cp++ = '\0';
+
+       errno = -1;
+       t = strtoul(cp, NULL, 10);
+       if (errno == ERANGE)
+               goto cleanup;
+       pvt->group.gr_gid = (gid_t) t;
+       if (!(cp = strchr(cp, ':')))
+               goto cleanup;
+       cp++;
+
+        if (*cp && cp[strlen(cp)-1] == '\n')
+          cp[strlen(cp)-1] = '\0';
+
+       /*
+        * Parse the members out.
+        */
+       while (*cp) {
+               if (num_members+1 >= pvt->nmemb || pvt->group.gr_mem == NULL) {
+                       pvt->nmemb += 10;
+                       new = realloc(pvt->group.gr_mem,
+                                     pvt->nmemb * sizeof(char *));
+                       if (new == NULL)
+                               goto cleanup;
+                       pvt->group.gr_mem = new;
+               }
+               pvt->group.gr_mem[num_members++] = cp;
+               if (!(cp = strchr(cp, ',')))
+                       break;
+               *cp++ = '\0';
+       }
+       if (pvt->group.gr_mem == NULL) {
+               pvt->group.gr_mem = malloc(sizeof(char*));
+               if (!pvt->group.gr_mem)
+                       goto cleanup;
+               pvt->nmemb = 1;
+       }
+       pvt->group.gr_mem[num_members] = NULL;
+       
+       return (&pvt->group);
+       
+ cleanup:      
+       if (pvt->group.gr_mem) {
+               free(pvt->group.gr_mem);
+               pvt->group.gr_mem = NULL;
+               pvt->nmemb = 0;
+       }
+       if (pvt->membuf) {
+               free(pvt->membuf);
+               pvt->membuf = NULL;
+       }
+       return (NULL);
+}
+
+static void
+nisfree(struct pvt *pvt, enum do_what do_what) {
+       if ((do_what & do_key) && pvt->curkey_data) {
+               free(pvt->curkey_data);
+               pvt->curkey_data = NULL;
+       }
+       if ((do_what & do_val) && pvt->curval_data) {
+               free(pvt->curval_data);
+               pvt->curval_data = NULL;
+       }
+}
+
+#endif /* WANT_IRS_GR && WANT_IRS_NIS */
diff --git a/lib/bind/irs/nis_ho.c b/lib/bind/irs/nis_ho.c
new file mode 100644 (file)
index 0000000..970412f
--- /dev/null
@@ -0,0 +1,461 @@
+/*
+ * 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 rcsid[] = "$Id: nis_ho.c,v 1.1 2001/03/29 06:31:51 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* Imports */
+
+#include "port_before.h"
+
+#ifndef WANT_IRS_NIS
+static int __bind_irs_nis_unneeded;
+#else
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <rpc/rpc.h>
+#include <rpc/xdr.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "nis_p.h"
+
+/* Definitions */
+
+#define        MAXALIASES      35
+#define        MAXADDRS        35
+
+#if PACKETSZ > 1024
+#define        MAXPACKET       PACKETSZ
+#else
+#define        MAXPACKET       1024
+#endif
+
+struct pvt {
+       int             needrewind;
+       char *          nis_domain;
+       char *          curkey_data;
+       int             curkey_len;
+       char *          curval_data;
+       int             curval_len;
+       struct hostent  host;
+       char *          h_addr_ptrs[MAXADDRS + 1];
+       char *          host_aliases[MAXALIASES + 1];
+       char            hostbuf[8*1024];
+       u_char          host_addr[16];  /* IPv4 or IPv6 */
+       struct __res_state  *res;
+       void            (*free_res)(void *);
+};
+
+enum do_what { do_none = 0x0, do_key = 0x1, do_val = 0x2, do_all = 0x3 };
+
+static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
+static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
+static /*const*/ char hosts_byname[] = "hosts.byname";
+static /*const*/ char hosts_byaddr[] = "hosts.byaddr";
+
+/* Forwards */
+
+static void            ho_close(struct irs_ho *this);
+static struct hostent *        ho_byname(struct irs_ho *this, const char *name);
+static struct hostent *        ho_byname2(struct irs_ho *this, const char *name,
+                                       int af);
+static struct hostent *        ho_byaddr(struct irs_ho *this, const void *addr,
+                                      int len, int af);
+static struct hostent *        ho_next(struct irs_ho *this);
+static void            ho_rewind(struct irs_ho *this);
+static void            ho_minimize(struct irs_ho *this);
+static struct __res_state * ho_res_get(struct irs_ho *this);
+static void            ho_res_set(struct irs_ho *this,
+                                  struct __res_state *res,
+                                  void (*free_res)(void *));
+static struct addrinfo * ho_addrinfo(struct irs_ho *this, const char *name,
+                                    const struct addrinfo *pai);
+
+static struct hostent *        makehostent(struct irs_ho *this);
+static void            nisfree(struct pvt *, enum do_what);
+static int             init(struct irs_ho *this);
+
+/* Public */
+
+struct irs_ho *
+irs_nis_ho(struct irs_acc *this) {
+       struct irs_ho *ho;
+       struct pvt *pvt;
+
+       if (!(pvt = memget(sizeof *pvt))) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pvt, 0, sizeof *pvt);
+       if (!(ho = memget(sizeof *ho))) {
+               memput(pvt, sizeof *pvt);
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(ho, 0x5e, sizeof *ho);
+       pvt->needrewind = 1;
+       pvt->nis_domain = ((struct nis_p *)this->private)->domain;
+       ho->private = pvt;
+       ho->close = ho_close;
+       ho->byname = ho_byname;
+       ho->byname2 = ho_byname2;
+       ho->byaddr = ho_byaddr;
+       ho->next = ho_next;
+       ho->rewind = ho_rewind;
+       ho->minimize = ho_minimize;
+       ho->res_set = ho_res_set;
+       ho->res_get = ho_res_get;
+       ho->addrinfo = ho_addrinfo;
+       return (ho);
+}
+
+/* Methods */
+
+static void
+ho_close(struct irs_ho *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       ho_minimize(this);
+       nisfree(pvt, do_all);
+       if (pvt->res && pvt->free_res)
+               (*pvt->free_res)(pvt->res);
+       memput(pvt, sizeof *pvt);
+       memput(this, sizeof *this);
+}
+
+static struct hostent *
+ho_byname(struct irs_ho *this, const char *name) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct hostent *hp;
+
+       if (init(this) == -1)
+               return (NULL);
+
+       if (pvt->res->options & RES_USE_INET6) {
+               hp = ho_byname2(this, name, AF_INET6);
+               if (hp)
+                       return (hp);
+       }
+       return (ho_byname2(this, name, AF_INET));
+}
+
+static struct hostent *
+ho_byname2(struct irs_ho *this, const char *name, int af) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       int r;
+
+       UNUSED(af);
+       
+       if (init(this) == -1)
+               return (NULL);
+
+       nisfree(pvt, do_val);
+       r = yp_match(pvt->nis_domain, hosts_byname, name,
+                    strlen(name), &pvt->curval_data, &pvt->curval_len);
+       if (r != 0) {
+               RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
+               return (NULL);
+       }
+       return (makehostent(this));
+}
+
+static struct hostent *
+ho_byaddr(struct irs_ho *this, const void *addr, int len, int af) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
+       const u_char *uaddr = addr;
+       int r;
+       
+       if (init(this) == -1)
+               return (NULL);
+
+       if (af == AF_INET6 && len == IN6ADDRSZ &&
+           (!memcmp(uaddr, mapped, sizeof mapped) ||
+            !memcmp(uaddr, tunnelled, sizeof tunnelled))) {
+               /* Unmap. */
+               addr = (const u_char *)addr + sizeof mapped;
+               uaddr += sizeof mapped;
+               af = AF_INET;
+               len = INADDRSZ;
+       }
+       if (inet_ntop(af, uaddr, tmp, sizeof tmp) == NULL) {
+               RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+               return (NULL);
+       }
+       nisfree(pvt, do_val);
+       r = yp_match(pvt->nis_domain, hosts_byaddr, tmp, strlen(tmp),
+                    &pvt->curval_data, &pvt->curval_len);
+       if (r != 0) {
+               RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
+               return (NULL);
+       }
+       return (makehostent(this));
+}
+
+static struct hostent *
+ho_next(struct irs_ho *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct hostent *rval;
+       int r;
+
+       if (init(this) == -1)
+               return (NULL);
+
+       do {
+               if (pvt->needrewind) {
+                       nisfree(pvt, do_all);
+                       r = yp_first(pvt->nis_domain, hosts_byaddr,
+                                    &pvt->curkey_data, &pvt->curkey_len,
+                                    &pvt->curval_data, &pvt->curval_len);
+                       pvt->needrewind = 0;
+               } else {
+                       char *newkey_data;
+                       int newkey_len;
+
+                       nisfree(pvt, do_val);
+                       r = yp_next(pvt->nis_domain, hosts_byaddr,
+                                   pvt->curkey_data, pvt->curkey_len,
+                                   &newkey_data, &newkey_len,
+                                   &pvt->curval_data, &pvt->curval_len);
+                       nisfree(pvt, do_key);
+                       pvt->curkey_data = newkey_data;
+                       pvt->curkey_len = newkey_len;
+               }
+               if (r != 0) {
+                       RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
+                       return (NULL);
+               }
+               rval = makehostent(this);
+       } while (rval == NULL);
+       return (rval);
+}
+
+static void
+ho_rewind(struct irs_ho *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       pvt->needrewind = 1;
+}
+
+static void
+ho_minimize(struct irs_ho *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (pvt->res)
+               res_nclose(pvt->res);
+}
+
+static struct __res_state *
+ho_res_get(struct irs_ho *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (!pvt->res) {
+               struct __res_state *res;
+               res = (struct __res_state *)malloc(sizeof *res);
+               if (!res) {
+                       errno = ENOMEM;
+                       return (NULL);
+               }
+               memset(res, 0, sizeof *res);
+               ho_res_set(this, res, free);
+       }
+
+       return (pvt->res);
+}
+
+static void
+ho_res_set(struct irs_ho *this, struct __res_state *res,
+               void (*free_res)(void *)) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (pvt->res && pvt->free_res) {
+               res_nclose(pvt->res);
+               (*pvt->free_res)(pvt->res);
+       }
+
+       pvt->res = res;
+       pvt->free_res = free_res;
+}
+
+struct nis_res_target {
+       struct nis_res_target *next;
+       int family;
+};
+
+/* XXX */
+extern struct addrinfo *hostent2addrinfo __P((struct hostent *,
+                                             const struct addrinfo *pai));
+
+static struct addrinfo *
+ho_addrinfo(struct irs_ho *this, const char *name, const struct addrinfo *pai)
+{
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct hostent *hp;
+       struct nis_res_target q, q2, *p;
+       struct addrinfo sentinel, *cur;
+
+       memset(&q, 0, sizeof(q2));
+       memset(&q2, 0, sizeof(q2));
+       memset(&sentinel, 0, sizeof(sentinel));
+       cur = &sentinel;
+
+       switch(pai->ai_family) {
+       case AF_UNSPEC:         /* INET6 then INET4 */
+               q.family = AF_INET6;
+               q.next = &q2;
+               q2.family = AF_INET;
+               break;
+       case AF_INET6:
+               q.family = AF_INET6;
+               break;
+       case AF_INET:
+               q.family = AF_INET;
+               break;
+       default:
+               RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); /* ??? */
+               return(NULL);
+       }
+
+       for (p = &q; p; p = p->next) {
+               struct addrinfo *ai;
+
+               hp = (*this->byname2)(this, name, p->family);
+               if (hp == NULL) {
+                       /* byname2 should've set an appropriate error */
+                       continue;
+               }
+               if ((hp->h_name == NULL) || (hp->h_name[0] == 0) ||
+                   (hp->h_addr_list[0] == NULL)) {
+                       RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
+                       continue;
+               }
+               ai = hostent2addrinfo(hp, pai);
+               if (ai) {
+                       cur->ai_next = ai;
+                       while (cur && cur->ai_next)
+                               cur = cur->ai_next;
+               }
+       }
+
+       if (sentinel.ai_next == NULL)
+               RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
+
+       return(sentinel.ai_next);
+}
+
+/* Private */
+
+static struct hostent *
+makehostent(struct irs_ho *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       static const char spaces[] = " \t";
+       char *cp, **q, *p;
+       int af, len;
+
+       p = pvt->curval_data;
+       if ((cp = strpbrk(p, "#\n")) != NULL)
+               *cp = '\0';
+       if (!(cp = strpbrk(p, spaces)))
+               return (NULL);
+       *cp++ = '\0';
+       if ((pvt->res->options & RES_USE_INET6) &&
+           inet_pton(AF_INET6, p, pvt->host_addr) > 0) {
+               af = AF_INET6;
+               len = IN6ADDRSZ;
+       } else if (inet_pton(AF_INET, p, pvt->host_addr) > 0) {
+               if (pvt->res->options & RES_USE_INET6) {
+                       map_v4v6_address((char*)pvt->host_addr,
+                                        (char*)pvt->host_addr);
+                       af = AF_INET6;
+                       len = IN6ADDRSZ;
+               } else {
+                       af = AF_INET;
+                       len = INADDRSZ;
+               }
+       } else {
+               return (NULL);
+       }
+       pvt->h_addr_ptrs[0] = (char *)pvt->host_addr;
+       pvt->h_addr_ptrs[1] = NULL;
+       pvt->host.h_addr_list = pvt->h_addr_ptrs;
+       pvt->host.h_length = len;
+       pvt->host.h_addrtype = af;
+       cp += strspn(cp, spaces);
+       pvt->host.h_name = cp;
+       q = pvt->host.h_aliases = pvt->host_aliases;
+       if ((cp = strpbrk(cp, spaces)) != NULL)
+               *cp++ = '\0';
+       while (cp && *cp) {
+               if (*cp == ' ' || *cp == '\t') {
+                       cp++;
+                       continue;
+               }
+               if (q < &pvt->host_aliases[MAXALIASES])
+                       *q++ = cp;
+               if ((cp = strpbrk(cp, spaces)) != NULL)
+                       *cp++ = '\0';
+       }
+       *q = NULL;
+       RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS);
+       return (&pvt->host);
+}
+
+static void
+nisfree(struct pvt *pvt, enum do_what do_what) {
+       if ((do_what & do_key) && pvt->curkey_data) {
+               free(pvt->curkey_data);
+               pvt->curkey_data = NULL;
+       }
+       if ((do_what & do_val) && pvt->curval_data) {
+               free(pvt->curval_data);
+               pvt->curval_data = NULL;
+       }
+}
+
+static int
+init(struct irs_ho *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       
+       if (!pvt->res && !ho_res_get(this))
+               return (-1);
+       if (((pvt->res->options & RES_INIT) == 0) &&
+           res_ninit(pvt->res) == -1)
+               return (-1);
+       return (0);
+}
+#endif /*WANT_IRS_NIS*/
diff --git a/lib/bind/irs/nis_ng.c b/lib/bind/irs/nis_ng.c
new file mode 100644 (file)
index 0000000..9b4efa9
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ * 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 rcsid[] = "$Id: nis_ng.c,v 1.1 2001/03/29 06:31:52 marka Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#ifndef WANT_IRS_NIS
+static int __bind_irs_nis_unneeded;
+#else
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <rpc/rpc.h>
+#include <rpc/xdr.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+
+#include <isc/assertions.h>
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "nis_p.h"
+
+/* Definitions */
+
+struct tmpgrp {
+       const char *    name;
+       const char *    host;
+       const char *    user;
+       const char *    domain;
+       struct tmpgrp * next;
+};
+
+struct pvt {
+       char *          nis_domain;
+       struct tmpgrp * tmp;
+       struct tmpgrp * cur;
+       char *          tmpgroup;
+};
+
+enum do_what { do_none = 0x0, do_key = 0x1, do_val = 0x2, do_all = 0x3 };
+
+static /*const*/ char netgroup_map[]   = "netgroup";
+
+/* Forward */
+
+static void            ng_close(struct irs_ng *);
+static int             ng_next(struct irs_ng *, const char **,
+                               const char **, const char **);
+static int             ng_test(struct irs_ng *,
+                               const char *, const char *,
+                               const char *, const char *);
+static void            ng_rewind(struct irs_ng *, const char *);
+static void            ng_minimize(struct irs_ng *);
+
+static void            add_group_to_list(struct pvt *, const char *, int);
+static void            add_tuple_to_list(struct pvt *, const char *, char *);
+static void            tmpfree(struct pvt *);
+
+/* Public */
+
+struct irs_ng *
+irs_nis_ng(struct irs_acc *this) {
+       struct irs_ng *ng;
+       struct pvt *pvt;
+
+       if (!(ng = memget(sizeof *ng))) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(ng, 0x5e, sizeof *ng);
+       if (!(pvt = memget(sizeof *pvt))) {
+               memput(ng, sizeof *ng);
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pvt, 0, sizeof *pvt);
+       pvt->nis_domain = ((struct nis_p *)this->private)->domain;
+       ng->private = pvt;
+       ng->close = ng_close;
+       ng->next = ng_next;
+       ng->test = ng_test;
+       ng->rewind = ng_rewind;
+       ng->minimize = ng_minimize;
+       return (ng);
+}
+
+/* Methods */
+
+static void
+ng_close(struct irs_ng *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       tmpfree(pvt);
+       memput(pvt, sizeof *pvt);
+       memput(this, sizeof *this);
+}
+
+static int
+ng_next(struct irs_ng *this, const char **host, const char **user, const char **domain) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (!pvt->cur)
+               return (0);
+       *host = pvt->cur->host;
+       *user = pvt->cur->user;
+       *domain = pvt->cur->domain;
+       pvt->cur = pvt->cur->next;
+       return (1);
+}
+
+static int
+ng_test(struct irs_ng *this, const char *name,
+       const char *host, const char *user, const char *domain)
+{
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct tmpgrp *cur;
+
+       tmpfree(pvt);
+       add_group_to_list(pvt, name, strlen(name));
+       for (cur = pvt->tmp; cur; cur = cur->next) {
+               if ((!host || !cur->host || !strcmp(host, cur->host)) &&
+                   (!user || !cur->user || !strcmp(user, cur->user)) &&
+                   (!domain || !cur->domain || !strcmp(domain, cur->domain)))
+                       break;
+       }
+       tmpfree(pvt);
+       return ((cur == NULL) ? 0 : 1);
+}
+
+static void
+ng_rewind(struct irs_ng *this, const char *name) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       /* Either hand back or free the existing list. */
+       if (pvt->tmpgroup) {
+               if (pvt->tmp && !strcmp(pvt->tmpgroup, name))
+                       goto reset;
+               tmpfree(pvt);
+       }
+       pvt->tmpgroup = strdup(name);
+       add_group_to_list(pvt, name, strlen(name));
+ reset:
+       pvt->cur = pvt->tmp;
+}
+
+static void
+ng_minimize(struct irs_ng *this) {
+       UNUSED(this);
+       /* NOOP */
+}
+
+/* Private */
+
+static void
+add_group_to_list(struct pvt *pvt, const char *name, int len) {
+       char *vdata, *cp, *np;
+       struct tmpgrp *tmp;
+       int vlen, r;
+
+       /* Don't add the same group to the list more than once. */
+       for (tmp = pvt->tmp; tmp; tmp = tmp->next)
+               if (!strcmp(tmp->name, name))
+                       return;
+
+       r = yp_match(pvt->nis_domain, netgroup_map, name, len,
+                    &vdata, &vlen);
+       if (r == 0) {
+               cp = vdata;
+               if (*cp && cp[strlen(cp)-1] == '\n')
+                  cp[strlen(cp)-1] = '\0';
+               for ( ; cp; cp = np) {
+                       np = strchr(cp, ' ');
+                       if (np)
+                               *np++ = '\0';
+                       if (*cp == '(')
+                               add_tuple_to_list(pvt, name, cp);
+                       else
+                               add_group_to_list(pvt, cp, strlen(cp));
+               }
+               free(vdata);
+       }
+}
+
+static void
+add_tuple_to_list(struct pvt *pvt, const char *name, char *cp) {
+       struct tmpgrp *tmp;
+       char *tp, *np;
+
+       INSIST(*cp++ == '(');
+
+       tmp = malloc(sizeof *tmp + strlen(name) + sizeof '\0' +
+                    strlen(cp) - sizeof ')');
+       if (!tmp)
+               return;
+       memset(tmp, 0, sizeof *tmp);
+       tp = ((char *)tmp) + sizeof *tmp;
+
+       /* Name */
+       strcpy(tp, name);
+       tmp->name = tp;
+       tp += strlen(tp) + 1;
+
+       /* Host */
+       if (!(np = strchr(cp, ',')))
+               goto cleanup;
+       *np++ = '\0';
+       strcpy(tp, cp);
+       tmp->host = tp;
+       tp += strlen(tp) + 1;
+       cp = np;
+
+       /* User */
+       if (!(np = strchr(cp, ',')))
+               goto cleanup;
+       *np++ = '\0';
+       strcpy(tp, cp);
+       tmp->user = tp;
+       tp += strlen(tp) + 1;
+       cp = np;
+
+       /* Domain */
+       if (!(np = strchr(cp, ')')))
+               goto cleanup;
+       *np++ = '\0';
+       strcpy(tp, cp);
+       tmp->domain = tp;
+
+       /*
+        * Empty string in file means wildcard, but
+        * NULL string in return value means wildcard.
+        */
+       if (!*tmp->host)
+               tmp->host = NULL;
+       if (!*tmp->user)
+               tmp->user = NULL;
+       if (!*tmp->domain)
+               tmp->domain = NULL;
+
+       /* Add to list (LIFO). */
+       tmp->next = pvt->tmp;
+       pvt->tmp = tmp;
+       return;
+
+ cleanup:
+       free(tmp);
+}
+
+static void
+tmpfree(struct pvt *pvt) {
+       struct tmpgrp *cur, *next;
+
+       if (pvt->tmpgroup) {
+               free(pvt->tmpgroup);
+               pvt->tmpgroup = NULL;
+       }
+       for (cur = pvt->tmp; cur; cur = next) {
+               next = cur->next;
+               free(cur);
+       }
+       pvt->tmp = NULL;
+}
+
+#endif /*WANT_IRS_NIS*/
diff --git a/lib/bind/irs/nis_nw.c b/lib/bind/irs/nis_nw.c
new file mode 100644 (file)
index 0000000..3485f45
--- /dev/null
@@ -0,0 +1,379 @@
+/*
+ * 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 rcsid[] = "$Id: nis_nw.c,v 1.1 2001/03/29 06:31:52 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* Imports */
+
+#include "port_before.h"
+
+#ifndef WANT_IRS_NIS
+static int __bind_irs_nis_unneeded;
+#else
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <rpc/rpc.h>
+#include <rpc/xdr.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+
+#include <errno.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "nis_p.h"
+
+/* Definitions */
+
+#define MAXALIASES 35
+#define MAXADDRSIZE 4
+
+struct pvt {
+       int             needrewind;
+       char *          nis_domain;
+       char *          curkey_data;
+       int             curkey_len;
+       char *          curval_data;
+       int             curval_len;
+
+       struct nwent    nwent;
+       char *          nwbuf;
+
+       char *          aliases[MAXALIASES + 1];
+       u_char          addr[MAXADDRSIZE];
+
+       struct __res_state *  res;
+       void            (*free_res)(void *);
+};
+
+enum do_what { do_none = 0x0, do_key = 0x1, do_val = 0x2, do_all = 0x3 };
+
+static /*const*/ char networks_byname[] = "networks.byname";
+static /*const*/ char networks_byaddr[] = "networks.byaddr";
+
+/* Forward */
+
+static void            nw_close(struct irs_nw *);
+static struct nwent *  nw_byname(struct irs_nw *, const char *, int);
+static struct nwent *  nw_byaddr(struct irs_nw *, void *, int, int);
+static struct nwent *  nw_next(struct irs_nw *);
+static void            nw_rewind(struct irs_nw *);
+static void            nw_minimize(struct irs_nw *);
+static struct __res_state * nw_res_get(struct irs_nw *this);
+static void            nw_res_set(struct irs_nw *this,
+                                  struct __res_state *res,
+                                  void (*free_res)(void *));
+
+static struct nwent *  makenwent(struct irs_nw *this);
+static void            nisfree(struct pvt *, enum do_what);
+static int             init(struct irs_nw *this);
+
+/* Public */
+
+struct irs_nw *
+irs_nis_nw(struct irs_acc *this) {
+       struct irs_nw *nw;
+       struct pvt *pvt;
+
+       if (!(pvt = memget(sizeof *pvt))) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pvt, 0, sizeof *pvt);
+       if (!(nw = memget(sizeof *nw))) {
+               memput(pvt, sizeof *pvt);
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(nw, 0x5e, sizeof *nw);
+       pvt->needrewind = 1;
+       pvt->nis_domain = ((struct nis_p *)this->private)->domain;
+       nw->private = pvt;
+       nw->close = nw_close;
+       nw->byname = nw_byname;
+       nw->byaddr = nw_byaddr;
+       nw->next = nw_next;
+       nw->rewind = nw_rewind;
+       nw->minimize = nw_minimize;
+       nw->res_get = nw_res_get;
+       nw->res_set = nw_res_set;
+       return (nw);
+}
+
+/* Methods */
+
+static void
+nw_close(struct irs_nw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;  
+
+       nw_minimize(this);
+       if (pvt->res && pvt->free_res)
+               (*pvt->free_res)(pvt->res);
+       if (pvt->nwbuf)
+               free(pvt->nwbuf);
+       memput(pvt, sizeof *pvt);
+       memput(this, sizeof *this);
+}
+
+static struct nwent *
+nw_byaddr(struct irs_nw *this, void *net, int length, int af) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       char tmp[sizeof "255.255.255.255/32"], *t;
+       int r;
+
+       if (init(this) == -1)
+               return (NULL);
+
+       if (af != AF_INET) {
+               RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+               errno = EAFNOSUPPORT;
+               return (NULL);
+       }
+       nisfree(pvt, do_val);
+       /* Try it with /CIDR first. */
+       if (inet_net_ntop(AF_INET, net, length, tmp, sizeof tmp) == NULL) {
+               RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+               return (NULL);
+       }
+       r = yp_match(pvt->nis_domain, networks_byaddr, tmp, strlen(tmp),
+                    &pvt->curval_data, &pvt->curval_len);
+       if (r != 0) {
+               /* Give it a shot without the /CIDR. */
+               if ((t = strchr(tmp, '/')) != NULL) {
+                       *t = '\0';
+                       r = yp_match(pvt->nis_domain, networks_byaddr,
+                                    tmp, strlen(tmp),
+                                    &pvt->curval_data, &pvt->curval_len);
+               }
+               if (r != 0) {
+                       RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
+                       return (NULL);
+               }
+       }
+       return (makenwent(this));
+}
+
+static struct nwent *
+nw_byname(struct irs_nw *this, const char *name, int af) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       int r;
+       
+       if (init(this) == -1)
+               return (NULL);
+
+       if (af != AF_INET) {
+               RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
+               errno = EAFNOSUPPORT;
+               return (NULL);
+       }
+       nisfree(pvt, do_val);
+       r = yp_match(pvt->nis_domain, networks_byname, name,
+                    strlen(name), &pvt->curval_data, &pvt->curval_len);
+       if (r != 0) {
+               RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
+               return (NULL);
+       }
+       return (makenwent(this));
+}
+
+static void
+nw_rewind(struct irs_nw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       pvt->needrewind = 1;
+}
+
+static struct nwent *
+nw_next(struct irs_nw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct nwent *rval;
+       int r;
+
+       if (init(this) == -1)
+               return (NULL);
+
+       do {
+               if (pvt->needrewind) {
+                       nisfree(pvt, do_all);
+                       r = yp_first(pvt->nis_domain, networks_byaddr,
+                                    &pvt->curkey_data, &pvt->curkey_len,
+                                    &pvt->curval_data, &pvt->curval_len);
+                       pvt->needrewind = 0;
+               } else {
+                       char *newkey_data;
+                       int newkey_len;
+
+                       nisfree(pvt, do_val);
+                       r = yp_next(pvt->nis_domain, networks_byaddr,
+                                   pvt->curkey_data, pvt->curkey_len,
+                                   &newkey_data, &newkey_len,
+                                   &pvt->curval_data, &pvt->curval_len);
+                       nisfree(pvt, do_key);
+                       pvt->curkey_data = newkey_data;
+                       pvt->curkey_len = newkey_len;
+               }
+               if (r != 0) {
+                       RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
+                       return (NULL);
+               }
+               rval = makenwent(this);
+       } while (rval == NULL);
+       return (rval);
+}
+
+static void
+nw_minimize(struct irs_nw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (pvt->res)
+               res_nclose(pvt->res);
+}
+
+static struct __res_state *
+nw_res_get(struct irs_nw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (!pvt->res) {
+               struct __res_state *res;
+               res = (struct __res_state *)malloc(sizeof *res);
+               if (!res) {
+                       errno = ENOMEM;
+                       return (NULL);
+               }
+               memset(res, 0, sizeof *res);
+               nw_res_set(this, res, free);
+       }
+
+       return (pvt->res);
+}
+
+static void
+nw_res_set(struct irs_nw *this, struct __res_state *res,
+               void (*free_res)(void *)) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       if (pvt->res && pvt->free_res) {
+               res_nclose(pvt->res);
+               (*pvt->free_res)(pvt->res);
+       }
+
+       pvt->res = res;
+       pvt->free_res = free_res;
+}
+
+/* Private */
+
+static struct nwent *
+makenwent(struct irs_nw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       static const char spaces[] = " \t";
+       char *t, *cp, **ap;
+
+       if (pvt->nwbuf)
+               free(pvt->nwbuf);
+       pvt->nwbuf = pvt->curval_data;
+       pvt->curval_data = NULL;
+
+       if ((cp = strpbrk(pvt->nwbuf, "#\n")) != NULL)
+               *cp = '\0';
+       cp = pvt->nwbuf;
+
+       /* Name */
+       pvt->nwent.n_name = cp;
+       cp += strcspn(cp, spaces);
+       if (!*cp)
+               goto cleanup;
+       *cp++ = '\0';
+       cp += strspn(cp, spaces);
+
+       /* Network */
+       pvt->nwent.n_addrtype = AF_INET;
+       t = cp + strcspn(cp, spaces);
+       if (*t)
+               *t++ = '\0';
+       pvt->nwent.n_length = inet_net_pton(AF_INET, cp,
+                                           pvt->addr, sizeof pvt->addr);
+       if (pvt->nwent.n_length < 0)
+               goto cleanup;
+       pvt->nwent.n_addr = pvt->addr;
+       cp = t;
+
+       /* Aliases */
+       ap = pvt->nwent.n_aliases = pvt->aliases;
+       while (*cp) {
+               if (ap >= &pvt->aliases[MAXALIASES])
+                       break;
+               *ap++ = cp;
+               cp += strcspn(cp, spaces);
+               if (!*cp)
+                       break;
+               *cp++ = '\0';
+               cp += strspn(cp, spaces);
+       }
+       *ap = NULL;
+
+       return (&pvt->nwent);
+
+ cleanup:
+       if (pvt->nwbuf) {
+               free(pvt->nwbuf);
+               pvt->nwbuf = NULL;
+       }
+       return (NULL);
+}
+
+static void
+nisfree(struct pvt *pvt, enum do_what do_what) {
+       if ((do_what & do_key) && pvt->curkey_data) {
+               free(pvt->curkey_data);
+               pvt->curkey_data = NULL;
+       }
+       if ((do_what & do_val) && pvt->curval_data) {
+               free(pvt->curval_data);
+               pvt->curval_data = NULL;
+       }
+}
+
+static int
+init(struct irs_nw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       
+       if (!pvt->res && !nw_res_get(this))
+               return (-1);
+       if (((pvt->res->options & RES_INIT) == 0) &&
+           res_ninit(pvt->res) == -1)
+               return (-1);
+       return (0);
+}
+
+#endif /*WANT_IRS_NIS*/
diff --git a/lib/bind/irs/nis_p.h b/lib/bind/irs/nis_p.h
new file mode 100644 (file)
index 0000000..6461e85
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+/*
+ * $Id: nis_p.h,v 1.1 2001/03/29 06:31:52 marka Exp $
+ */
+
+/*
+ * nis_p.h - private include file for the NIS functions.
+ */
+
+/*
+ * Object state.
+ */
+struct nis_p {
+       char *                  domain;
+       struct __res_state *    res;
+       void                    (*free_res) __P((void *));
+};
+
+
+/*
+ * Methods.
+ */
+
+extern struct irs_gr * irs_nis_gr __P((struct irs_acc *));
+extern struct irs_pw * irs_nis_pw __P((struct irs_acc *));
+extern struct irs_sv * irs_nis_sv __P((struct irs_acc *));
+extern struct irs_pr * irs_nis_pr __P((struct irs_acc *));
+extern struct irs_ho * irs_nis_ho __P((struct irs_acc *));
+extern struct irs_nw * irs_nis_nw __P((struct irs_acc *));
+extern struct irs_ng * irs_nis_ng __P((struct irs_acc *));
diff --git a/lib/bind/irs/nis_pr.c b/lib/bind/irs/nis_pr.c
new file mode 100644 (file)
index 0000000..14847b0
--- /dev/null
@@ -0,0 +1,295 @@
+/*
+ * 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 rcsid[] = "$Id: nis_pr.c,v 1.1 2001/03/29 06:31:52 marka Exp $";
+#endif
+
+/* Imports */
+
+#include "port_before.h"
+
+#ifndef WANT_IRS_NIS
+static int __bind_irs_nis_unneeded;
+#else
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <rpc/rpc.h>
+#include <rpc/xdr.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "nis_p.h"
+
+/* Definitions */
+
+struct pvt {
+       int             needrewind;
+       char *          nis_domain;
+       char *          curkey_data;
+       int             curkey_len;
+       char *          curval_data;
+       int             curval_len;
+       struct protoent proto;
+       char *          prbuf;
+};
+
+enum do_what { do_none = 0x0, do_key = 0x1, do_val = 0x2, do_all = 0x3 };
+
+static /*const*/ char protocols_byname[] =     "protocols.byname";
+static /*const*/ char protocols_bynumber[] =   "protocols.bynumber";
+
+/* Forward */
+
+static void                    pr_close(struct irs_pr *);
+static struct protoent *       pr_byname(struct irs_pr *, const char *);
+static struct protoent *       pr_bynumber(struct irs_pr *, int);
+static struct protoent *       pr_next(struct irs_pr *);
+static void                    pr_rewind(struct irs_pr *);
+static void                    pr_minimize(struct irs_pr *);
+
+static struct protoent *       makeprotoent(struct irs_pr *this);
+static void                    nisfree(struct pvt *, enum do_what);
+
+/* Public */
+
+struct irs_pr *
+irs_nis_pr(struct irs_acc *this) {
+       struct irs_pr *pr;
+       struct pvt *pvt;
+
+       if (!(pr = memget(sizeof *pr))) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pr, 0x5e, sizeof *pr);
+       if (!(pvt = memget(sizeof *pvt))) {
+               memput(pr, sizeof *pr);
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pvt, 0, sizeof *pvt);
+       pvt->needrewind = 1;
+       pvt->nis_domain = ((struct nis_p *)this->private)->domain;
+       pr->private = pvt;
+       pr->byname = pr_byname;
+       pr->bynumber = pr_bynumber;
+       pr->next = pr_next;
+       pr->rewind = pr_rewind;
+       pr->close = pr_close;
+       pr->minimize = pr_minimize;
+       pr->res_get = NULL;
+       pr->res_set = NULL;
+       return (pr);
+}
+
+/* Methods. */
+
+static void
+pr_close(struct irs_pr *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       nisfree(pvt, do_all);
+       if (pvt->proto.p_aliases)
+               free(pvt->proto.p_aliases);
+       if (pvt->prbuf)
+               free(pvt->prbuf);
+       memput(pvt, sizeof *pvt);
+       memput(this, sizeof *this);
+}
+
+static struct protoent *
+pr_byname(struct irs_pr *this, const char *name) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       int r;
+       
+       nisfree(pvt, do_val);
+       r = yp_match(pvt->nis_domain, protocols_byname, name,
+                    strlen(name), &pvt->curval_data, &pvt->curval_len);
+       if (r != 0) {
+               errno = ENOENT;
+               return (NULL);
+       }
+       return (makeprotoent(this));
+}
+
+static struct protoent *
+pr_bynumber(struct irs_pr *this, int num) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       char tmp[sizeof "-4294967295"];
+       int r;
+       
+       nisfree(pvt, do_val);
+       (void) sprintf(tmp, "%d", num);
+       r = yp_match(pvt->nis_domain, protocols_bynumber, tmp, strlen(tmp),
+                    &pvt->curval_data, &pvt->curval_len);
+       if (r != 0) {
+               errno = ENOENT;
+               return (NULL);
+       }
+       return (makeprotoent(this));
+}
+
+static struct protoent *
+pr_next(struct irs_pr *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct protoent *rval;
+       int r;
+
+       do {
+               if (pvt->needrewind) {
+                       nisfree(pvt, do_all);
+                       r = yp_first(pvt->nis_domain, protocols_bynumber,
+                                    &pvt->curkey_data, &pvt->curkey_len,
+                                    &pvt->curval_data, &pvt->curval_len);
+                       pvt->needrewind = 0;
+               } else {
+                       char *newkey_data;
+                       int newkey_len;
+
+                       nisfree(pvt, do_val);
+                       r = yp_next(pvt->nis_domain, protocols_bynumber,
+                                   pvt->curkey_data, pvt->curkey_len,
+                                   &newkey_data, &newkey_len,
+                                   &pvt->curval_data, &pvt->curval_len);
+                       nisfree(pvt, do_key);
+                       pvt->curkey_data = newkey_data;
+                       pvt->curkey_len = newkey_len;
+               }
+               if (r != 0) {
+                       errno = ENOENT;
+                       return (NULL);
+               }
+               rval = makeprotoent(this);
+       } while (rval == NULL);
+       return (rval);
+}
+
+static void
+pr_rewind(struct irs_pr *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       pvt->needrewind = 1;
+}
+
+static void
+pr_minimize(struct irs_pr *this) {
+       UNUSED(this);
+       /* NOOP */
+}
+
+/* Private */
+
+static struct protoent *
+makeprotoent(struct irs_pr *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       char *p, **t;
+       int n, m;
+
+       if (pvt->prbuf)
+               free(pvt->prbuf);
+       pvt->prbuf = pvt->curval_data;
+       pvt->curval_data = NULL;
+
+       for (p = pvt->prbuf; *p && *p != '#';)
+               p++;
+       while (p > pvt->prbuf && isspace(p[-1]))
+               p--;
+       *p = '\0';
+
+       p = pvt->prbuf;
+       n = m = 0;
+
+       pvt->proto.p_name = p;
+       while (*p && !isspace(*p))
+               p++;
+       if (!*p)
+               return (NULL);
+       *p++ = '\0';
+
+       while (*p && isspace(*p))
+               p++;
+       pvt->proto.p_proto = atoi(p);
+       while (*p && !isspace(*p))
+               p++;
+       *p++ = '\0';
+
+       while (*p) {
+               if ((n + 1) >= m || !pvt->proto.p_aliases) {
+                       m += 10;
+                       t = realloc(pvt->proto.p_aliases,
+                                     m * sizeof(char *));
+                       if (!t) {
+                               errno = ENOMEM;
+                               goto cleanup;
+                       }
+                       pvt->proto.p_aliases = t;
+               }
+               pvt->proto.p_aliases[n++] = p;
+               while (*p && !isspace(*p))
+                       p++;
+               if (*p)
+                       *p++ = '\0';
+       }
+       if (!pvt->proto.p_aliases)
+               pvt->proto.p_aliases = malloc(sizeof(char *));
+       if (!pvt->proto.p_aliases)
+               goto cleanup;
+       pvt->proto.p_aliases[n] = NULL;
+       return (&pvt->proto);
+       
+ cleanup:
+       if (pvt->proto.p_aliases) {
+               free(pvt->proto.p_aliases);
+               pvt->proto.p_aliases = NULL;
+       }
+       if (pvt->prbuf) {
+               free(pvt->prbuf);
+               pvt->prbuf = NULL;
+       }
+       return (NULL);
+}
+
+static void
+nisfree(struct pvt *pvt, enum do_what do_what) {
+       if ((do_what & do_key) && pvt->curkey_data) {
+               free(pvt->curkey_data);
+               pvt->curkey_data = NULL;
+       }
+       if ((do_what & do_val) && pvt->curval_data) {
+               free(pvt->curval_data);
+               pvt->curval_data = NULL;
+       }
+}
+
+#endif /*WANT_IRS_NIS*/
diff --git a/lib/bind/irs/nis_pw.c b/lib/bind/irs/nis_pw.c
new file mode 100644 (file)
index 0000000..730dc68
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+ * 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 rcsid[] = "$Id: nis_pw.c,v 1.1 2001/03/29 06:31:52 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* Imports */
+
+#include "port_before.h"
+
+#if !defined(WANT_IRS_PW) || !defined(WANT_IRS_NIS)
+static int __bind_irs_pw_unneeded;
+#else
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <isc/memcluster.h>
+#include <rpc/rpc.h>
+#include <rpc/xdr.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <isc/memcluster.h>
+
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "nis_p.h"
+
+/* Definitions */
+
+struct pvt {
+       int             needrewind;
+       char *          nis_domain;
+       char *          curkey_data;
+       int             curkey_len;
+       char *          curval_data;
+       int             curval_len;
+       struct passwd   passwd;
+       char *          pwbuf;
+};
+
+enum do_what { do_none = 0x0, do_key = 0x1, do_val = 0x2, do_all = 0x3 };
+
+static /*const*/ char passwd_byname[] =        "passwd.byname";
+static /*const*/ char passwd_byuid[] = "passwd.byuid";
+
+/* Forward */
+
+static void                    pw_close(struct irs_pw *);
+static struct passwd *         pw_next(struct irs_pw *);
+static struct passwd *         pw_byname(struct irs_pw *, const char *);
+static struct passwd *         pw_byuid(struct irs_pw *, uid_t);
+static void                    pw_rewind(struct irs_pw *);
+static void                    pw_minimize(struct irs_pw *);
+
+static struct passwd *         makepasswdent(struct irs_pw *);
+static void                    nisfree(struct pvt *, enum do_what);
+
+/* Public */
+
+struct irs_pw *
+irs_nis_pw(struct irs_acc *this) {
+       struct irs_pw *pw;
+       struct pvt *pvt;
+                
+        if (!(pw = memget(sizeof *pw))) {
+                errno = ENOMEM;
+                return (NULL);
+        }
+        memset(pw, 0x5e, sizeof *pw);
+        if (!(pvt = memget(sizeof *pvt))) {
+                memput(pw, sizeof *pw);
+                errno = ENOMEM;
+                return (NULL);
+        }
+        memset(pvt, 0, sizeof *pvt);
+       pvt->needrewind = 1;
+       pvt->nis_domain = ((struct nis_p *)this->private)->domain;
+       pw->private = pvt;
+       pw->close = pw_close;
+       pw->next = pw_next;
+       pw->byname = pw_byname;
+       pw->byuid = pw_byuid;
+       pw->rewind = pw_rewind;
+       pw->minimize = pw_minimize;
+       pw->res_get = NULL;
+       pw->res_set = NULL;
+       return (pw);
+}
+
+/* Methods */
+
+static void
+pw_close(struct irs_pw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       
+       if (pvt->pwbuf)
+               free(pvt->pwbuf);
+       nisfree(pvt, do_all);
+       memput(pvt, sizeof *pvt);
+       memput(this, sizeof *this);
+}
+
+static struct passwd *
+pw_next(struct irs_pw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct passwd *rval;
+       int r;
+
+       do {
+               if (pvt->needrewind) {
+                       nisfree(pvt, do_all);
+                       r = yp_first(pvt->nis_domain, passwd_byname,
+                                    &pvt->curkey_data, &pvt->curkey_len,
+                                    &pvt->curval_data, &pvt->curval_len);
+                       pvt->needrewind = 0;
+               } else {
+                       char *newkey_data;
+                       int newkey_len;
+
+                       nisfree(pvt, do_val);
+                       r = yp_next(pvt->nis_domain, passwd_byname,
+                                   pvt->curkey_data, pvt->curkey_len,
+                                   &newkey_data, &newkey_len,
+                                   &pvt->curval_data, &pvt->curval_len);
+                       nisfree(pvt, do_key);
+                       pvt->curkey_data = newkey_data;
+                       pvt->curkey_len = newkey_len;
+               }
+               if (r != 0) {
+                       errno = ENOENT;
+                       return (NULL);
+               }
+               rval = makepasswdent(this);
+       } while (rval == NULL);
+       return (rval);
+}
+
+static struct passwd *
+pw_byname(struct irs_pw *this, const char *name) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       int r;
+
+       nisfree(pvt, do_val);
+       r = yp_match(pvt->nis_domain, passwd_byname, name, strlen(name),
+                    &pvt->curval_data, &pvt->curval_len);
+       if (r != 0) {
+               errno = ENOENT;
+               return (NULL);
+       }
+       return (makepasswdent(this));
+}
+
+static struct passwd *
+pw_byuid(struct irs_pw *this, uid_t uid) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       char tmp[sizeof "4294967295"];
+       int r;
+
+       nisfree(pvt, do_val);
+       (void) sprintf(tmp, "%u", (unsigned int)uid);
+       r = yp_match(pvt->nis_domain, passwd_byuid, tmp, strlen(tmp),
+                    &pvt->curval_data, &pvt->curval_len);
+       if (r != 0) {
+               errno = ENOENT;
+               return (NULL);
+       }
+       return (makepasswdent(this));
+}
+
+static void
+pw_rewind(struct irs_pw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       pvt->needrewind = 1;
+}
+
+static void
+pw_minimize(struct irs_pw *this) {
+       UNUSED(this);
+       /* NOOP */
+}
+
+/* Private */
+
+static struct passwd *
+makepasswdent(struct irs_pw *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       char *cp;
+
+       memset(&pvt->passwd, 0, sizeof pvt->passwd);
+       if (pvt->pwbuf)
+               free(pvt->pwbuf);
+       pvt->pwbuf = pvt->curval_data;
+       pvt->curval_data = NULL;
+
+       cp = pvt->pwbuf;
+       pvt->passwd.pw_name = cp;
+       if (!(cp = strchr(cp, ':')))
+               goto cleanup;
+       pvt->passwd.pw_class = cp;      /* Needs to point at a \0. */
+       *cp++ = '\0';
+
+       pvt->passwd.pw_passwd = cp;
+       if (!(cp = strchr(cp, ':')))
+               goto cleanup;
+       *cp++ = '\0';
+       
+       pvt->passwd.pw_uid = atoi(cp);
+       if (!(cp = strchr(cp, ':')))
+               goto cleanup;
+       *cp++ = '\0';
+
+       pvt->passwd.pw_gid = atoi(cp);
+       if (!(cp = strchr(cp, ':')))
+               goto cleanup;
+       *cp++ = '\0';
+
+       pvt->passwd.pw_gecos = cp;
+       if (!(cp = strchr(cp, ':')))
+               goto cleanup;
+       *cp++ = '\0';
+
+       pvt->passwd.pw_dir = cp;
+       if (!(cp = strchr(cp, ':')))
+               goto cleanup;
+       *cp++ = '\0';
+
+       pvt->passwd.pw_shell = cp;
+
+       if ((cp = strchr(cp, '\n')) != NULL)
+               *cp = '\0';
+
+       return (&pvt->passwd);
+       
+ cleanup:
+       free(pvt->pwbuf);
+       pvt->pwbuf = NULL;
+       return (NULL);
+}
+
+static void
+nisfree(struct pvt *pvt, enum do_what do_what) {
+       if ((do_what & do_key) && pvt->curkey_data) {
+               free(pvt->curkey_data);
+               pvt->curkey_data = NULL;
+       }
+       if ((do_what & do_val) && pvt->curval_data) {
+               free(pvt->curval_data);
+               pvt->curval_data = NULL;
+       }
+}
+
+#endif /* WANT_IRS_PW && WANT_IRS_NIS */
diff --git a/lib/bind/irs/nis_sv.c b/lib/bind/irs/nis_sv.c
new file mode 100644 (file)
index 0000000..799fe51
--- /dev/null
@@ -0,0 +1,305 @@
+/*
+ * 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 rcsid[] = "$Id: nis_sv.c,v 1.1 2001/03/29 06:31:52 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* Imports */
+
+#include "port_before.h"
+
+#ifndef WANT_IRS_NIS
+static int __bind_irs_nis_unneeded;
+#else
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <sys/socket.h>
+#include <rpc/rpc.h>
+#include <rpc/xdr.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/memcluster.h>
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "nis_p.h"
+
+/* Definitions */
+
+struct pvt {
+       int             needrewind;
+       char *          nis_domain;
+       char *          curkey_data;
+       int             curkey_len;
+       char *          curval_data;
+       int             curval_len;
+       char            line[BUFSIZ+1];
+       struct servent  serv;
+       char *          svbuf;
+};
+
+enum do_what { do_none = 0x0, do_key = 0x1, do_val = 0x2, do_all = 0x3 };
+
+static /*const*/ char services_byname[] = "services.byname";
+
+/* Forward */
+
+static void                    sv_close(struct irs_sv*);
+static struct servent *                sv_next(struct irs_sv *);
+static struct servent *                sv_byname(struct irs_sv *, const char *,
+                                         const char *);
+static struct servent *                sv_byport(struct irs_sv *, int, const char *);
+static void                    sv_rewind(struct irs_sv *);
+static void                    sv_minimize(struct irs_sv *);
+
+static struct servent *                makeservent(struct irs_sv *this);
+static void                    nisfree(struct pvt *, enum do_what);
+
+/* Public */
+
+struct irs_sv *
+irs_nis_sv(struct irs_acc *this) {
+       struct irs_sv *sv;
+       struct pvt *pvt;
+       
+       if (!(sv = memget(sizeof *sv))) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(sv, 0x5e, sizeof *sv);
+       if (!(pvt = memget(sizeof *pvt))) {
+               memput(sv, sizeof *sv);
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(pvt, 0, sizeof *pvt);
+       pvt->needrewind = 1;
+       pvt->nis_domain = ((struct nis_p *)this->private)->domain;
+       sv->private = pvt;
+       sv->close = sv_close;
+       sv->next = sv_next;
+       sv->byname = sv_byname;
+       sv->byport = sv_byport;
+       sv->rewind = sv_rewind;
+       sv->minimize = sv_minimize;
+       sv->res_get = NULL;
+       sv->res_set = NULL;
+       return (sv);
+}
+
+/* Methods */
+
+static void
+sv_close(struct irs_sv *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       
+       nisfree(pvt, do_all);
+       if (pvt->serv.s_aliases)
+               free(pvt->serv.s_aliases);
+       if (pvt->svbuf)
+               free(pvt->svbuf);
+       memput(pvt, sizeof *pvt);
+       memput(this, sizeof *this);
+}
+
+static struct servent *
+sv_byname(struct irs_sv *this, const char *name, const char *proto) {
+       struct servent *serv;
+       char **sap;
+
+       sv_rewind(this);
+       while ((serv = sv_next(this)) != NULL) {
+               if (proto != NULL && strcmp(proto, serv->s_proto))
+                       continue;
+               if (!strcmp(name, serv->s_name))
+                       break;
+               for (sap = serv->s_aliases; sap && *sap; sap++)
+                       if (!strcmp(name, *sap))
+                               break;
+       }
+       return (serv);
+}
+
+static struct servent *
+sv_byport(struct irs_sv *this, int port, const char *proto) {
+       struct servent *serv;
+
+       sv_rewind(this);
+       while ((serv = sv_next(this)) != NULL) {
+               if (proto != NULL && strcmp(proto, serv->s_proto))
+                       continue;
+               if (serv->s_port == port)
+                       break;
+       }
+       return (serv);
+}
+
+static void
+sv_rewind(struct irs_sv *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+
+       pvt->needrewind = 1;
+}
+
+static struct servent *
+sv_next(struct irs_sv *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       struct servent *rval;
+       int r;
+
+       do {
+               if (pvt->needrewind) {
+                       nisfree(pvt, do_all);
+                       r = yp_first(pvt->nis_domain, services_byname,
+                                    &pvt->curkey_data, &pvt->curkey_len,
+                                    &pvt->curval_data, &pvt->curval_len);
+                       pvt->needrewind = 0;
+               } else {
+                       char *newkey_data;
+                       int newkey_len;
+
+                       nisfree(pvt, do_val);
+                       r = yp_next(pvt->nis_domain, services_byname,
+                                   pvt->curkey_data, pvt->curkey_len,
+                                   &newkey_data, &newkey_len,
+                                   &pvt->curval_data, &pvt->curval_len);
+                       nisfree(pvt, do_key);
+                       pvt->curkey_data = newkey_data;
+                       pvt->curkey_len = newkey_len;
+               }
+               if (r != 0) {
+                       errno = ENOENT;
+                       return (NULL);
+               }
+               rval = makeservent(this);
+       } while (rval == NULL);
+       return (rval);
+}
+
+static void
+sv_minimize(struct irs_sv *this) {
+       UNUSED(this);
+       /* NOOP */
+}
+
+/* Private */
+
+static struct servent *
+makeservent(struct irs_sv *this) {
+       struct pvt *pvt = (struct pvt *)this->private;
+       static const char spaces[] = " \t";
+       char *p, **t;
+       int n, m;
+
+       if (pvt->svbuf)
+               free(pvt->svbuf);
+       pvt->svbuf = pvt->curval_data;
+       pvt->curval_data = NULL;
+
+       if (pvt->serv.s_aliases) {
+               free(pvt->serv.s_aliases);
+               pvt->serv.s_aliases = NULL;
+       }
+
+       if ((p = strpbrk(pvt->svbuf, "#\n")))
+               *p = '\0';
+
+       p = pvt->svbuf;
+
+       pvt->serv.s_name = p;
+       p += strcspn(p, spaces);
+       if (!*p)
+               goto cleanup;
+       *p++ = '\0';
+       p += strspn(p, spaces);
+
+       pvt->serv.s_port = htons((u_short) atoi(p));
+       pvt->serv.s_proto = NULL;
+       
+       while (*p && !isspace(*p))
+               if (*p++ == '/')
+                       pvt->serv.s_proto = p;
+       if (!pvt->serv.s_proto)
+               goto cleanup;
+       if (*p) {
+               *p++ = '\0';
+               p += strspn(p, spaces);
+       }
+
+       n = m = 0;
+       while (*p) {
+               if ((n + 1) >= m || !pvt->serv.s_aliases) {
+                       m += 10;
+                       t = realloc(pvt->serv.s_aliases, m * sizeof(char *));
+                       if (!t) {
+                               errno = ENOMEM;
+                               goto cleanup;
+                       }
+                       pvt->serv.s_aliases = t;
+               }
+               pvt->serv.s_aliases[n++] = p;
+               p += strcspn(p, spaces);
+               if (!*p)
+                       break;
+               *p++ = '\0';
+               p += strspn(p, spaces);
+       }
+       if (!pvt->serv.s_aliases)
+               pvt->serv.s_aliases = malloc(sizeof(char *));
+       if (!pvt->serv.s_aliases)
+               goto cleanup;
+       pvt->serv.s_aliases[n] = NULL;
+       return (&pvt->serv);
+       
+ cleanup:
+       if (pvt->serv.s_aliases) {
+               free(pvt->serv.s_aliases);
+               pvt->serv.s_aliases = NULL;
+       }
+       if (pvt->svbuf) {
+               free(pvt->svbuf);
+               pvt->svbuf = NULL;
+       }
+       return (NULL);
+}
+
+static void
+nisfree(struct pvt *pvt, enum do_what do_what) {
+       if ((do_what & do_key) && pvt->curkey_data) {
+               free(pvt->curkey_data);
+               pvt->curkey_data = NULL;
+       }
+       if ((do_what & do_val) && pvt->curval_data) {
+               free(pvt->curval_data);
+               pvt->curval_data = NULL;
+       }
+}
+
+#endif /*WANT_IRS_NIS*/
diff --git a/lib/bind/irs/nul_ng.c b/lib/bind/irs/nul_ng.c
new file mode 100644 (file)
index 0000000..9efc424
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * 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 rcsid[] = "$Id: nul_ng.c,v 1.1 2001/03/29 06:31:52 marka Exp $";
+#endif
+
+/*
+ * nul_ng.c - the netgroup accessor null map
+ */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <irs.h>
+#include <isc/memcluster.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+#include "hesiod.h"
+#include "dns_p.h"
+
+/* Forward. */
+
+static void            ng_close(struct irs_ng *);
+static int             ng_next(struct irs_ng *, const char **,
+                               const char **, const char **);
+static int             ng_test(struct irs_ng *,
+                               const char *, const char *,
+                               const char *, const char *);
+static void            ng_rewind(struct irs_ng *, const char *);
+static void            ng_minimize(struct irs_ng *);
+
+/* Public. */
+
+struct irs_ng *
+irs_nul_ng(struct irs_acc *this) {
+       struct irs_ng *ng;
+
+       UNUSED(this);
+
+       if (!(ng = memget(sizeof *ng))) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       memset(ng, 0x5e, sizeof *ng);
+       ng->private = NULL;
+       ng->close = ng_close;
+       ng->next = ng_next;
+       ng->test = ng_test;
+       ng->rewind = ng_rewind;
+       ng->minimize = ng_minimize;
+       return (ng);
+}
+
+/* Methods. */
+
+static void
+ng_close(struct irs_ng *this) {
+       memput(this, sizeof *this);
+}
+
+/* ARGSUSED */
+static int
+ng_next(struct irs_ng *this, const char **host, const char **user,
+       const char **domain)
+{
+       UNUSED(this);
+       UNUSED(host);
+       UNUSED(user);
+       UNUSED(domain);
+       errno = ENOENT;
+       return (-1);
+}
+
+static int
+ng_test(struct irs_ng *this, const char *name,
+       const char *user, const char *host, const char *domain)
+{
+       UNUSED(this);
+       UNUSED(name);
+       UNUSED(user);
+       UNUSED(host);
+       UNUSED(domain);
+       errno = ENODEV;
+       return (-1);
+}
+
+static void
+ng_rewind(struct irs_ng *this, const char *netgroup) {
+       UNUSED(this);
+       UNUSED(netgroup);
+       /* NOOP */
+}
+
+static void
+ng_minimize(struct irs_ng *this) {
+       UNUSED(this);
+       /* NOOP */
+}
diff --git a/lib/bind/irs/pathnames.h b/lib/bind/irs/pathnames.h
new file mode 100644 (file)
index 0000000..c436545
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+/*
+ * $Id: pathnames.h,v 1.1 2001/03/29 06:31:52 marka Exp $
+ */
+
+#ifndef _PATH_IRS_CONF
+#define        _PATH_IRS_CONF "/etc/irs.conf"
+#endif
+
+#ifndef _PATH_NETWORKS 
+#define _PATH_NETWORKS  "/etc/networks"
+#endif
+
+#ifndef _PATH_GROUP
+#define _PATH_GROUP "/etc/group"
+#endif
+
+#ifndef _PATH_NETGROUP
+#define _PATH_NETGROUP "/etc/netgroup"
+#endif
+
+#ifndef _PATH_SERVICES 
+#define _PATH_SERVICES "/etc/services"
+#endif
+
+#ifdef IRS_LCL_SV_DB
+#ifndef _PATH_SERVICES_DB
+#define        _PATH_SERVICES_DB _PATH_SERVICES ".db"
+#endif
+#endif
+
+#ifndef _PATH_HESIOD_CONF
+#define _PATH_HESIOD_CONF "/etc/hesiod.conf"
+#endif
diff --git a/lib/bind/irs/util.c b/lib/bind/irs/util.c
new file mode 100644 (file)
index 0000000..05d9015
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * 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 rcsid[] = "$Id: util.c,v 1.1 2001/03/29 06:31:52 marka Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <irs.h>
+
+#include "port_after.h"
+
+#include "irs_p.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) sprintf x
+#endif
+
+void
+map_v4v6_address(const char *src, char *dst) {
+       u_char *p = (u_char *)dst;
+       char tmp[NS_INADDRSZ];
+       int i;
+
+       /* Stash a temporary copy so our caller can update in place. */
+       memcpy(tmp, src, NS_INADDRSZ);
+       /* Mark this ipv6 addr as a mapped ipv4. */
+       for (i = 0; i < 10; i++)
+               *p++ = 0x00;
+       *p++ = 0xff;
+       *p++ = 0xff;
+       /* Retrieve the saved copy and we're done. */
+       memcpy((void*)p, tmp, NS_INADDRSZ);
+}
+
+int
+make_group_list(struct irs_gr *this, const char *name,
+       gid_t basegid, gid_t *groups, int *ngroups)
+{
+       struct group *grp;
+       int i, ng;
+       int ret, maxgroups;
+
+       ret = -1;
+       ng = 0;
+       maxgroups = *ngroups;
+       /*
+        * When installing primary group, duplicate it;
+        * the first element of groups is the effective gid
+        * and will be overwritten when a setgid file is executed.
+        */
+       if (ng >= maxgroups)
+               goto done;
+       groups[ng++] = basegid;
+       if (ng >= maxgroups)
+               goto done;
+       groups[ng++] = basegid;
+       /*
+        * Scan the group file to find additional groups.
+        */
+       (*this->rewind)(this);
+       while ((grp = (*this->next)(this)) != NULL) {
+               if ((gid_t)grp->gr_gid == basegid)
+                       continue;
+               for (i = 0; grp->gr_mem[i]; i++) {
+                       if (!strcmp(grp->gr_mem[i], name)) {
+                               if (ng >= maxgroups)
+                                       goto done;
+                               groups[ng++] = grp->gr_gid;
+                               break;
+                       }
+               }
+       }
+       ret = 0;
+ done:
+       *ngroups = ng;
+       return (ret);
+}
diff --git a/lib/bind/isc/Makefile.in b/lib/bind/isc/Makefile.in
new file mode 100644 (file)
index 0000000..3121783
--- /dev/null
@@ -0,0 +1,16 @@
+OBJS=  assertions.@O@ base64.@O@ bitncmp.@O@ ctl_clnt.@O@ ctl_p.@O@ \
+       ctl_srvr.@O@ ev_connects.@O@ ev_files.@O@ ev_streams.@O@ \
+       ev_timers.@O@ ev_waits.@O@ eventlib.@O@ heap.@O@ logging.@O@ \
+       memcluster.@O@ movefile.@O@ tree.@O@
+
+SRCS=  assertions.c base64.c bitncmp.c ctl_clnt.c ctl_p.c \
+       ctl_srvr.c ev_connects.c ev_files.c ev_streams.c \
+       ev_timers.c ev_waits.c eventlib.c heap.c logging.c \
+       memcluster.c movefile.c tree.c
+
+TARGETS= ${OBJS}
+
+CINCLUDES= -I.. -I../include
+CWARNINGS= -Werror
+
+@BIND9_MAKE_RULES@
diff --git a/lib/bind/isc/assertions.c b/lib/bind/isc/assertions.c
new file mode 100644 (file)
index 0000000..52ad3f9
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 1997,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(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: assertions.c,v 1.1 2001/03/29 06:31:53 marka Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/assertions.h>
+
+#include "port_after.h"
+
+/*
+ * Forward.
+ */
+
+static void default_assertion_failed(const char *, int, assertion_type,
+                                    const char *, int);
+
+/*
+ * Public.
+ */
+
+assertion_failure_callback __assertion_failed = default_assertion_failed;
+
+void
+set_assertion_failure_callback(assertion_failure_callback f) {
+       if (f == NULL)
+               __assertion_failed = default_assertion_failed;
+       else
+               __assertion_failed = f;
+}
+
+const char *
+assertion_type_to_text(assertion_type type) {
+       const char *result;
+
+       switch (type) {
+       case assert_require:
+               result = "REQUIRE";
+               break;
+       case assert_ensure:
+               result = "ENSURE";
+               break;
+       case assert_insist:
+               result = "INSIST";
+               break;
+       case assert_invariant:
+               result = "INVARIANT";
+               break;
+       default:
+               result = NULL;
+       }
+       return (result);
+}
+
+/*
+ * Private.
+ */
+
+static void
+default_assertion_failed(const char *file, int line, assertion_type type,
+                        const char *cond, int print_errno)
+{
+       fprintf(stderr, "%s:%d: %s(%s)%s%s failed.\n",
+               file, line, assertion_type_to_text(type), cond,
+               (print_errno) ? ": " : "",
+               (print_errno) ? strerror(errno) : "");
+       abort();
+       /* NOTREACHED */
+}
diff --git a/lib/bind/isc/assertions.mdoc b/lib/bind/isc/assertions.mdoc
new file mode 100644 (file)
index 0000000..7fa00c9
--- /dev/null
@@ -0,0 +1,134 @@
+.\" $Id: assertions.mdoc,v 1.1 2001/03/29 06:31:53 marka Exp $
+.\"
+.\"Copyright (c) 1997,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.
+.\"
+.Dd November 17, 1997
+.Dt ASSERTIONS 3
+.Os ISC
+.Sh NAME
+.Nm REQUIRE ,
+.Nm REQUIRE_ERR ,
+.Nm ENSURE ,
+.Nm ENSURE_ERR ,
+.Nm INSIST ,
+.Nm INSIST_ERR ,
+.Nm INVARIANT ,
+.Nm INVARIANT_ERR ,
+.Nm set_assertion_failure_callback
+.Nd assertion system
+.Sh SYNOPSIS
+.Fd #include <isc/assertions.h>
+.Fo "typedef void (*assertion_failure_callback)"
+.Fa "char *filename"
+.Fa "int line"
+.Fa "assertion_type type"
+.Fa "char *condition"
+.Fa "int print_errno"
+.Fc
+.Fn REQUIRE "int boolean_expression"
+.Fn REQUIRE_ERR "int boolean_expression"
+.Fn ENSURE "int boolean_expression"
+.Fn ENSURE_ERR "int boolean_expression"
+.Fn INSIST "int boolean_expression"
+.Fn INSIST_ERR "int boolean_expression"
+.Fn INVARIANT "int boolean_expression"
+.Fn INVARIANT_ERR "int boolean_expression"
+.Ft void
+.Fn set_assertion_failure_callback "assertion_failure_callback callback"
+.Ft char *
+.Fn assertion_type_to_text "assertion_type type"
+.Sh DESCRIPTION
+The
+.Fn REQUIRE ,
+.Fn ENSURE ,
+.Fn INSIST ,
+and
+.Fn INVARIANT
+macros evaluate a boolean expression, and if it is false, they invoke the
+current assertion failure callback.  The default callback will print a message
+to 
+.Li stderr
+describing the failure, and then cause the program to dump core.
+If the
+.Dq Fn _ERR
+variant of the assertion is used, the callback will include
+.Fn strerror "errno"
+in its message.
+.Pp
+Each assertion type has an associated
+.Li CHECK
+macro.  If this macro's value is
+.Dq 0
+when
+.Dq "<isc/assertions.h>"
+is included, then assertions of that type will not be checked.  E.g.
+
+.Dl #define CHECK_ENSURE 0
+
+will disable checking of
+.Fn ENSURE
+and
+.Fn ENSURE_ERR .
+The macros
+.Li CHECK_ALL
+and
+.Li CHECK_NONE
+may also be used, respectively specifying that either all or none of the
+assertion types should be checked.
+.Pp
+.Fn set_assertion_failure_callback
+specifies the function to call when an assertion fails.
+.Pp
+When an
+.li
+assertion_failure_callback
+is called, the 
+.Fa filename
+and
+.Fa line
+arguments specify the filename and line number of the failing assertion.
+The
+.Fa type
+is one of:
+.Bd -literal -offset indent
+assert_require
+assert_ensure
+assert_insist
+assert_invariant
+.Ed
+
+and may be used by the callback to determine the type of the failing
+assertion.
+.Fa condition
+is the literal text of the assertion that failed. 
+.Fa print_errno
+will be non-zero if the callback should print
+.Fa strerror "errno"
+as part of its output.
+.Pp
+.Fn assertion_type_to_text
+returns a textual representation of
+.Fa type .
+For example,
+.Fn assertion_type_to_text "assert_require"
+returns the string
+.Dq REQUIRE .
+.Sh SEE ALSO
+Bertrand Meyer,
+.Sy Object-Oriented Software Construction,
+2nd edition, Prentice\-Hall, 1997, ISBN 0\-13\-629155\-4, chapter 11.
+.Sh AUTHOR
+Bob Halley (ISC).
diff --git a/lib/bind/isc/base64.c b/lib/bind/isc/base64.c
new file mode 100644 (file)
index 0000000..4683328
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ * 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/03/29 06:31:53 marka Exp $";
+#endif /* not lint */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "port_after.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/lib/bind/isc/bitncmp.c b/lib/bind/isc/bitncmp.c
new file mode 100644 (file)
index 0000000..5425467
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * 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 rcsid[] = "$Id: bitncmp.c,v 1.1 2001/03/29 06:31:53 marka Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <sys/types.h>
+
+#include <string.h>
+
+#include "port_after.h"
+
+#include <isc/misc.h>
+
+/*
+ * int
+ * bitncmp(l, r, n)
+ *     compare bit masks l and r, for n bits.
+ * return:
+ *     -1, 1, or 0 in the libc tradition.
+ * note:
+ *     network byte order assumed.  this means 192.5.5.240/28 has
+ *     0x11110000 in its fourth octet.
+ * author:
+ *     Paul Vixie (ISC), June 1996
+ */
+int
+bitncmp(const void *l, const void *r, int n) {
+       u_int lb, rb;
+       int x, b;
+
+       b = n / 8;
+       x = memcmp(l, r, b);
+       if (x)
+               return (x);
+
+       lb = ((const u_char *)l)[b];
+       rb = ((const u_char *)r)[b];
+       for (b = n % 8; b > 0; b--) {
+               if ((lb & 0x80) != (rb & 0x80)) {
+                       if (lb & 0x80)
+                               return (1);
+                       return (-1);
+               }
+               lb <<= 1;
+               rb <<= 1;
+       }
+       return (0);
+}
diff --git a/lib/bind/isc/bitncmp.mdoc b/lib/bind/isc/bitncmp.mdoc
new file mode 100644 (file)
index 0000000..7ad37f3
--- /dev/null
@@ -0,0 +1,82 @@
+.\" $Id: bitncmp.mdoc,v 1.1 2001/03/29 06:31:53 marka Exp $
+.\"
+.\"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.
+.\"
+.Dd June 1, 1996
+.Dt BITNCMP 3
+.Os BSD 4
+.Sh NAME
+.Nm bitncmp 
+.Nd compare bit masks
+.Sh SYNOPSIS
+.Ft int
+.Fn bitncmp "const void *l" "const void *r" "int n"
+.Sh DESCRIPTION
+The function
+.Fn bitncmp
+compares the
+.Dq Fa n
+most-significant bits of the two masks pointed to by
+.Dq Fa l
+and
+.Dq Fa r ,
+and returns an integer less than, equal to, or greater than 0, according to
+whether or not
+.Dq Fa l
+is lexicographically less than, equal to, or greater than
+.Dq Fa r
+when taken to be unsigned characters (this behaviour is just like that of
+.Xr memcmp 3 ) .
+.Pp
+.Sy NOTE:
+.Fn Bitncmp 
+assumes 
+.Sy network byte order ;
+this means that the fourth octet of 
+.Li 192.5.5.240/28 
+.Li 0x11110000 .
+.Sh RETURN VALUES
+.Fn Bitncmp
+returns values in the manner of
+.Xr memcmp 3 :
+.Bd -filled -offset indent
++1 if 
+.Dq Fa 1
+is greater than 
+.Dq Fa r ;
+.Pp
+-1 if 
+.Dq Fa l
+is less than 
+.Dq Fa r ; 
+and
+.Pp
+0 if 
+.Dq Fa l
+is equal to
+.Dq Fa r ,
+.Ed
+.Pp
+where 
+.Dq Fa l
+and 
+.Dq Fa r
+are both interpreted as strings of unsigned characters (through bit 
+.Dq Fa n .)
+.Sh SEE ALSO
+.Xr memcmp 3 .
+.Sh AUTHOR
+Paul Vixie (ISC). 
diff --git a/lib/bind/isc/ctl_clnt.c b/lib/bind/isc/ctl_clnt.c
new file mode 100644 (file)
index 0000000..fbc298a
--- /dev/null
@@ -0,0 +1,598 @@
+#if !defined(lint) && !defined(SABER)
+static const char rcsid[] = "$Id: ctl_clnt.c,v 1.1 2001/03/29 06:31:53 marka Exp $";
+#endif /* not lint */
+
+/*
+ * Copyright (c) 1998,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.
+ */
+
+/* Extern. */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <isc/assertions.h>
+#include <isc/ctl.h>
+#include <isc/eventlib.h>
+#include <isc/list.h>
+#include <isc/memcluster.h>
+
+#include "ctl_p.h"
+
+#include "port_after.h"
+
+/* Constants. */
+
+
+/* Macros. */
+
+#define donefunc_p(ctx) ((ctx).donefunc != NULL)
+#define arpacode_p(line) (isdigit(line[0]) && isdigit(line[1]) && \
+                         isdigit(line[2]))
+#define arpacont_p(line) (line[3] == '-')
+#define arpadone_p(line) (line[3] == ' ' || line[3] == '\t' || \
+                         line[3] == '\r' || line[3] == '\0')
+
+/* Types. */
+
+enum state {
+       initializing = 0, connecting, connected, destroyed
+};
+
+struct ctl_tran {
+       LINK(struct ctl_tran)   link;
+       LINK(struct ctl_tran)   wlink;
+       struct ctl_cctx *       ctx;
+       struct ctl_buf          outbuf;
+       ctl_clntdone            donefunc;
+       void *                  uap;
+};
+
+struct ctl_cctx {
+       enum state              state;
+       evContext               ev;
+       int                     sock;
+       ctl_logfunc             logger;
+       ctl_clntdone            donefunc;
+       void *                  uap;
+       evConnID                coID;
+       evTimerID               tiID;
+       evFileID                rdID;
+       evStreamID              wrID;
+       struct ctl_buf          inbuf;
+       struct timespec         timeout;
+       LIST(struct ctl_tran)   tran;
+       LIST(struct ctl_tran)   wtran;
+};
+
+/* Forward. */
+
+static struct ctl_tran *new_tran(struct ctl_cctx *, ctl_clntdone, void *, int);
+static void            start_write(struct ctl_cctx *);
+static void            destroy(struct ctl_cctx *, int);
+static void            error(struct ctl_cctx *);
+static void            new_state(struct ctl_cctx *, enum state);
+static void            conn_done(evContext, void *, int,
+                                 const void *, int,
+                                 const void *, int);
+static void            write_done(evContext, void *, int, int);
+static void            start_read(struct ctl_cctx *);
+static void            stop_read(struct ctl_cctx *);
+static void            readable(evContext, void *, int, int);
+static void            start_timer(struct ctl_cctx *);
+static void            stop_timer(struct ctl_cctx *);
+static void            touch_timer(struct ctl_cctx *);
+static void            timer(evContext, void *,
+                             struct timespec, struct timespec);
+
+/* Private data. */
+
+static const char * const state_names[] = {
+       "initializing", "connecting", "connected", "destroyed"
+};
+
+/* Public. */
+
+/*
+ * void
+ * ctl_client()
+ *     create, condition, and connect to a listener on the control port.
+ */
+struct ctl_cctx *
+ctl_client(evContext lev, const struct sockaddr *cap, size_t cap_len,
+          const struct sockaddr *sap, size_t sap_len,
+          ctl_clntdone donefunc, void *uap,
+          u_int timeout, ctl_logfunc logger)
+{
+       static const char me[] = "ctl_client";
+       static const int on = 1;
+       struct ctl_cctx *ctx;
+
+       if (logger == NULL)
+               logger = ctl_logger;
+       ctx = memget(sizeof *ctx);
+       if (ctx == NULL) {
+               (*logger)(ctl_error, "%s: getmem: %s", me, strerror(errno));
+               goto fatal;
+       }
+       ctx->state = initializing;
+       ctx->ev = lev;
+       ctx->logger = logger;
+       ctx->timeout = evConsTime(timeout, 0);
+       ctx->donefunc = donefunc;
+       ctx->uap = uap;
+       ctx->coID.opaque = NULL;
+       ctx->tiID.opaque = NULL;
+       ctx->rdID.opaque = NULL;
+       ctx->wrID.opaque = NULL;
+       buffer_init(ctx->inbuf);
+       INIT_LIST(ctx->tran);
+       INIT_LIST(ctx->wtran);
+       ctx->sock = socket(sap->sa_family, SOCK_STREAM, PF_UNSPEC);
+       if (ctx->sock > evHighestFD(ctx->ev)) {
+               ctx->sock = -1;
+               errno = ENOTSOCK;
+       }
+       if (ctx->sock < 0) {
+               (*ctx->logger)(ctl_error, "%s: socket: %s",
+                              me, strerror(errno));
+               goto fatal;
+       }
+       if (cap != NULL) {
+               if (setsockopt(ctx->sock, SOL_SOCKET, SO_REUSEADDR,
+                              (const char *)&on, sizeof on) != 0) {
+                       (*ctx->logger)(ctl_warning,
+                                      "%s: setsockopt(REUSEADDR): %s",
+                                      me, strerror(errno));
+               }
+               if (bind(ctx->sock, cap, cap_len) < 0) {
+                       (*ctx->logger)(ctl_error, "%s: bind: %s", me,
+                                      strerror(errno));
+                       goto fatal;
+               }
+       }
+       if (evConnect(lev, ctx->sock, (const struct sockaddr *)sap, sap_len,
+                     conn_done, ctx, &ctx->coID) < 0) {
+               (*ctx->logger)(ctl_error, "%s: evConnect(fd %d): %s",
+                              me, (void *)ctx->sock, strerror(errno));
+ fatal:
+               if (ctx != NULL) {
+                       if (ctx->sock >= 0)
+                               close(ctx->sock);
+                       memput(ctx, sizeof *ctx);
+               }
+               return (NULL);
+       }
+       new_state(ctx, connecting);
+       return (ctx);
+}
+
+/*
+ * void
+ * ctl_endclient(ctx)
+ *     close a client and release all of its resources.
+ */
+void
+ctl_endclient(struct ctl_cctx *ctx) {
+       if (ctx->state != destroyed)
+               destroy(ctx, 0);
+       memput(ctx, sizeof *ctx);
+}
+
+/*
+ * int
+ * ctl_command(ctx, cmd, len, donefunc, uap)
+ *     Queue a transaction, which will begin with sending cmd
+ *     and complete by calling donefunc with the answer.
+ */
+int
+ctl_command(struct ctl_cctx *ctx, const char *cmd, size_t len,
+           ctl_clntdone donefunc, void *uap)
+{
+       struct ctl_tran *tran;
+       char *pc;
+       unsigned int n;
+
+       switch (ctx->state) {
+       case destroyed:
+               errno = ENOTCONN;
+               return (-1);
+       case connecting:
+       case connected:
+               break;
+       default:
+               abort();
+       }
+       if (len >= MAX_LINELEN) {
+               errno = EMSGSIZE;
+               return (-1);
+       }
+       tran = new_tran(ctx, donefunc, uap, 1);
+       if (tran == NULL)
+               return (-1);
+       if (ctl_bufget(&tran->outbuf, ctx->logger) < 0)
+               return (-1);
+       memcpy(tran->outbuf.text, cmd, len);
+       tran->outbuf.used = len;
+       for (pc = tran->outbuf.text, n = 0; n < tran->outbuf.used; pc++, n++)
+               if (!isascii(*pc) || !isprint(*pc))
+                       *pc = '\040';
+       start_write(ctx);
+       return (0);
+}
+
+/* Private. */
+
+static struct ctl_tran *
+new_tran(struct ctl_cctx *ctx, ctl_clntdone donefunc, void *uap, int w) {
+       struct ctl_tran *new = memget(sizeof *new);
+
+       if (new == NULL)
+               return (NULL);
+       new->ctx = ctx;
+       buffer_init(new->outbuf);
+       new->donefunc = donefunc;
+       new->uap = uap;
+       INIT_LINK(new, link);
+       INIT_LINK(new, wlink);
+       APPEND(ctx->tran, new, link);
+       if (w)
+               APPEND(ctx->wtran, new, wlink);
+       return (new);
+}
+
+static void
+start_write(struct ctl_cctx *ctx) {
+       static const char me[] = "isc/ctl_clnt::start_write";
+       struct ctl_tran *tran;
+       struct iovec iov[2], *iovp = iov;
+       char * tmp;
+
+       REQUIRE(ctx->state == connecting || ctx->state == connected);
+       /* If there is a write in progress, don't try to write more yet. */
+       if (ctx->wrID.opaque != NULL)
+               return;
+       /* If there are no trans, make sure timer is off, and we're done. */
+       if (EMPTY(ctx->wtran)) {
+               if (ctx->tiID.opaque != NULL)
+                       stop_timer(ctx);
+               return;
+       }
+       /* Pull it off the head of the write queue. */
+       tran = HEAD(ctx->wtran);
+       UNLINK(ctx->wtran, tran, wlink);
+       /* Since there are some trans, make sure timer is successfully "on". */
+       if (ctx->tiID.opaque != NULL)
+               touch_timer(ctx);
+       else
+               start_timer(ctx);
+       if (ctx->state == destroyed)
+               return;
+       /* Marshall a newline-terminated message and clock it out. */
+       *iovp++ = evConsIovec(tran->outbuf.text, tran->outbuf.used);
+       DE_CONST("\r\n", tmp);
+       *iovp++ = evConsIovec(tmp, 2);
+       if (evWrite(ctx->ev, ctx->sock, iov, iovp - iov,
+                   write_done, tran, &ctx->wrID) < 0) {
+               (*ctx->logger)(ctl_error, "%s: evWrite: %s", me,
+                              strerror(errno));
+               error(ctx);
+               return;
+       }
+       if (evTimeRW(ctx->ev, ctx->wrID, ctx->tiID) < 0) {
+               (*ctx->logger)(ctl_error, "%s: evTimeRW: %s", me,
+                              strerror(errno));
+               error(ctx);
+               return;
+       }
+}
+
+static void
+destroy(struct ctl_cctx *ctx, int notify) {
+       struct ctl_tran *this, *next;
+
+       if (ctx->sock != -1) {
+               (void) close(ctx->sock);
+               ctx->sock = -1;
+       }
+       switch (ctx->state) {
+       case connecting:
+               REQUIRE(ctx->wrID.opaque == NULL);
+               REQUIRE(EMPTY(ctx->tran));
+               /*
+                * This test is nec'y since destroy() can be called from
+                * start_read() while the state is still "connecting".
+                */
+               if (ctx->coID.opaque != NULL) {
+                       (void)evCancelConn(ctx->ev, ctx->coID);
+                       ctx->coID.opaque = NULL;
+               }
+               break;
+       case connected:
+               REQUIRE(ctx->coID.opaque == NULL);
+               if (ctx->wrID.opaque != NULL) {
+                       (void)evCancelRW(ctx->ev, ctx->wrID);
+                       ctx->wrID.opaque = NULL;
+               }
+               if (ctx->rdID.opaque != NULL)
+                       stop_read(ctx);
+               break;
+       case destroyed:
+               break;
+       default:
+               abort();
+       }
+       if (allocated_p(ctx->inbuf))
+               ctl_bufput(&ctx->inbuf);
+       for (this = HEAD(ctx->tran); this != NULL; this = next) {
+               next = NEXT(this, link);
+               if (allocated_p(this->outbuf))
+                       ctl_bufput(&this->outbuf);
+               if (notify && this->donefunc != NULL)
+                       (*this->donefunc)(ctx, this->uap, NULL, 0);
+               memput(this, sizeof *this);
+       }
+       if (ctx->tiID.opaque != NULL)
+               stop_timer(ctx);
+       new_state(ctx, destroyed);
+}
+
+static void
+error(struct ctl_cctx *ctx) {
+       REQUIRE(ctx->state != destroyed);
+       destroy(ctx, 1);
+}
+
+static void
+new_state(struct ctl_cctx *ctx, enum state new_state) {
+       static const char me[] = "isc/ctl_clnt::new_state";
+
+       (*ctx->logger)(ctl_debug, "%s: %s -> %s", me,
+                      state_names[ctx->state], state_names[new_state]);
+       ctx->state = new_state;
+}
+
+static void
+conn_done(evContext ev, void *uap, int fd,
+         const void *la, int lalen,
+         const void *ra, int ralen)
+{
+       static const char me[] = "isc/ctl_clnt::conn_done";
+       struct ctl_cctx *ctx = uap;
+       struct ctl_tran *tran;
+
+       UNUSED(ev);
+       UNUSED(la);
+       UNUSED(lalen);
+       UNUSED(ra);
+       UNUSED(ralen);
+
+       ctx->coID.opaque = NULL;
+       if (fd < 0) {
+               (*ctx->logger)(ctl_error, "%s: evConnect: %s", me,
+                              strerror(errno));
+               error(ctx);
+               return;
+       }
+       new_state(ctx, connected);
+       tran = new_tran(ctx, ctx->donefunc, ctx->uap, 0);
+       if (tran == NULL) {
+               (*ctx->logger)(ctl_error, "%s: new_tran failed: %s", me,
+                              strerror(errno));
+               error(ctx);
+               return;
+       }
+       start_read(ctx);
+       if (ctx->state == destroyed) {
+               (*ctx->logger)(ctl_error, "%s: start_read failed: %s",
+                              me, strerror(errno));
+               error(ctx);
+               return;
+       }
+}
+
+static void
+write_done(evContext lev, void *uap, int fd, int bytes) {
+       struct ctl_tran *tran = (struct ctl_tran *)uap;
+       struct ctl_cctx *ctx = tran->ctx;
+
+       UNUSED(lev);
+       UNUSED(fd);
+
+       ctx->wrID.opaque = NULL;
+       if (ctx->tiID.opaque != NULL)
+               touch_timer(ctx);
+       ctl_bufput(&tran->outbuf);
+       start_write(ctx);
+       if (bytes < 0)
+               destroy(ctx, 1);
+       else
+               start_read(ctx);
+}
+
+static void
+start_read(struct ctl_cctx *ctx) {
+       static const char me[] = "isc/ctl_clnt::start_read";
+
+       REQUIRE(ctx->state == connecting || ctx->state == connected);
+       REQUIRE(ctx->rdID.opaque == NULL);
+       if (evSelectFD(ctx->ev, ctx->sock, EV_READ, readable, ctx,
+                      &ctx->rdID) < 0)
+       {
+               (*ctx->logger)(ctl_error, "%s: evSelect(fd %d): %s", me,
+                              ctx->sock, strerror(errno));
+               error(ctx);
+               return;
+       }
+}
+
+static void
+stop_read(struct ctl_cctx *ctx) {
+       REQUIRE(ctx->coID.opaque == NULL);
+       REQUIRE(ctx->rdID.opaque != NULL);
+       (void)evDeselectFD(ctx->ev, ctx->rdID);
+       ctx->rdID.opaque = NULL;
+}
+
+static void
+readable(evContext ev, void *uap, int fd, int evmask) {
+       static const char me[] = "isc/ctl_clnt::readable";
+       struct ctl_cctx *ctx = uap;
+       struct ctl_tran *tran;
+       ssize_t n;
+       char *eos;
+
+       UNUSED(ev);
+
+       REQUIRE(ctx != NULL);
+       REQUIRE(fd >= 0);
+       REQUIRE(evmask == EV_READ);
+       REQUIRE(ctx->state == connected);
+       REQUIRE(!EMPTY(ctx->tran));
+       tran = HEAD(ctx->tran);
+       if (!allocated_p(ctx->inbuf) &&
+           ctl_bufget(&ctx->inbuf, ctx->logger) < 0) {
+               (*ctx->logger)(ctl_error, "%s: can't get an input buffer", me);
+               error(ctx);
+               return;
+       }
+       n = read(ctx->sock, ctx->inbuf.text + ctx->inbuf.used,
+                MAX_LINELEN - ctx->inbuf.used);
+       if (n <= 0) {
+               (*ctx->logger)(ctl_warning, "%s: read: %s", me,
+                              (n == 0) ? "Unexpected EOF" : strerror(errno));
+               error(ctx);
+               return;
+       }
+       if (ctx->tiID.opaque != NULL)
+               touch_timer(ctx);
+       ctx->inbuf.used += n;
+       (*ctx->logger)(ctl_debug, "%s: read %d, used %d", me,
+                      n, ctx->inbuf.used);
+ again:
+       eos = memchr(ctx->inbuf.text, '\n', ctx->inbuf.used);
+       if (eos != NULL && eos != ctx->inbuf.text && eos[-1] == '\r') {
+               int done = 0;
+
+               eos[-1] = '\0';
+               if (!arpacode_p(ctx->inbuf.text)) {
+                       /* XXX Doesn't FTP do this sometimes? Is it legal? */
+                       (*ctx->logger)(ctl_error, "%s: no arpa code (%s)", me,
+                                      ctx->inbuf.text);
+                       error(ctx);
+                       return;
+               }
+               if (arpadone_p(ctx->inbuf.text))
+                       done = 1;
+               else if (arpacont_p(ctx->inbuf.text))
+                       done = 0;
+               else {
+                       /* XXX Doesn't FTP do this sometimes? Is it legal? */
+                       (*ctx->logger)(ctl_error, "%s: no arpa flag (%s)", me,
+                                      ctx->inbuf.text);
+                       error(ctx);
+                       return;
+               }
+               (*tran->donefunc)(ctx, tran->uap, ctx->inbuf.text,
+                                 (done ? 0 : CTL_MORE));
+               ctx->inbuf.used -= ((eos - ctx->inbuf.text) + 1);
+               if (ctx->inbuf.used == 0)
+                       ctl_bufput(&ctx->inbuf);
+               else
+                       memmove(ctx->inbuf.text, eos + 1, ctx->inbuf.used);
+               if (done) {
+                       UNLINK(ctx->tran, tran, link);
+                       memput(tran, sizeof *tran);
+                       stop_read(ctx);
+                       start_write(ctx);
+                       return;
+               }
+               if (allocated_p(ctx->inbuf))
+                       goto again;
+               return;
+       }
+       if (ctx->inbuf.used == MAX_LINELEN) {
+               (*ctx->logger)(ctl_error, "%s: line too long (%-10s...)", me,
+                              ctx->inbuf.text);
+               error(ctx);
+       }
+}
+
+/* Timer related stuff. */
+
+static void
+start_timer(struct ctl_cctx *ctx) {
+       static const char me[] = "isc/ctl_clnt::start_timer";
+
+       REQUIRE(ctx->tiID.opaque == NULL);
+       if (evSetIdleTimer(ctx->ev, timer, ctx, ctx->timeout, &ctx->tiID) < 0){
+               (*ctx->logger)(ctl_error, "%s: evSetIdleTimer: %s", me,
+                              strerror(errno));
+               error(ctx);
+               return;
+       }
+}
+
+static void
+stop_timer(struct ctl_cctx *ctx) {
+       static const char me[] = "isc/ctl_clnt::stop_timer";
+
+       REQUIRE(ctx->tiID.opaque != NULL);
+       if (evClearIdleTimer(ctx->ev, ctx->tiID) < 0) {
+               (*ctx->logger)(ctl_error, "%s: evClearIdleTimer: %s", me,
+                              strerror(errno));
+               error(ctx);
+               return;
+       }
+       ctx->tiID.opaque = NULL;
+}
+
+static void
+touch_timer(struct ctl_cctx *ctx) {
+       REQUIRE(ctx->tiID.opaque != NULL);
+
+       evTouchIdleTimer(ctx->ev, ctx->tiID);
+}
+
+static void
+timer(evContext ev, void *uap, struct timespec due, struct timespec itv) {
+       static const char me[] = "isc/ctl_clnt::timer";
+       struct ctl_cctx *ctx = uap;
+
+       UNUSED(ev);
+       UNUSED(due);
+       UNUSED(itv);
+
+       ctx->tiID.opaque = NULL;
+       (*ctx->logger)(ctl_error, "%s: timeout after %u seconds while %s", me,
+                      ctx->timeout.tv_sec, state_names[ctx->state]);
+       error(ctx);
+}
diff --git a/lib/bind/isc/ctl_p.c b/lib/bind/isc/ctl_p.c
new file mode 100644 (file)
index 0000000..0a51a81
--- /dev/null
@@ -0,0 +1,186 @@
+#if !defined(lint) && !defined(SABER)
+static const char rcsid[] = "$Id: ctl_p.c,v 1.1 2001/03/29 06:31:53 marka Exp $";
+#endif /* not lint */
+
+/*
+ * Copyright (c) 1998,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.
+ */
+
+/* Extern. */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <isc/assertions.h>
+#include <isc/eventlib.h>
+#include <isc/logging.h>
+#include <isc/memcluster.h>
+#include <isc/ctl.h>
+
+#include "ctl_p.h"
+
+#include "port_after.h"
+
+/* Constants. */
+
+const char * const ctl_sevnames[] = {
+       "debug", "warning", "error"
+};
+
+/* Public. */
+
+/*
+ * ctl_logger()
+ *     if ctl_startup()'s caller didn't specify a logger, this one
+ *     is used.  this pollutes stderr with all kinds of trash so it will
+ *     probably never be used in real applications.
+ */
+void
+ctl_logger(enum ctl_severity severity, const char *format, ...) {
+       va_list ap;
+       static const char me[] = "ctl_logger";
+
+       fprintf(stderr, "%s(%s): ", me, ctl_sevnames[severity]);
+       va_start(ap, format);
+       vfprintf(stderr, format, ap);
+       va_end(ap);
+       fputc('\n', stderr);
+}
+
+int
+ctl_bufget(struct ctl_buf *buf, ctl_logfunc logger) {
+       static const char me[] = "ctl_bufget";
+
+       REQUIRE(!allocated_p(*buf) && buf->used == 0);
+       buf->text = memget(MAX_LINELEN);
+       if (!allocated_p(*buf)) {
+               (*logger)(ctl_error, "%s: getmem: %s", me, strerror(errno));
+               return (-1);
+       }
+       buf->used = 0;
+       return (0);
+}
+
+void
+ctl_bufput(struct ctl_buf *buf) {
+
+       REQUIRE(allocated_p(*buf));
+       memput(buf->text, MAX_LINELEN);
+       buf->text = NULL;
+       buf->used = 0;
+}
+
+const char *
+ctl_sa_ntop(const struct sockaddr *sa,
+           char *buf, size_t size,
+           ctl_logfunc logger)
+{
+       static const char me[] = "ctl_sa_ntop";
+       static const char punt[] = "[0].-1";
+       char tmp[INET6_ADDRSTRLEN];
+
+       switch (sa->sa_family) {
+       case AF_INET6: {
+               const struct sockaddr_in6 *in6 =
+                                       (const struct sockaddr_in6 *) sa;
+
+               if (inet_ntop(in6->sin6_family, &in6->sin6_addr, tmp, sizeof tmp)
+                   == NULL) {
+                       (*logger)(ctl_error, "%s: inet_ntop(%u %04x): %s",
+                                 me, in6->sin6_family,
+                                 in6->sin6_port, strerror(errno));
+                       return (punt);
+               }
+               if (strlen(tmp) + sizeof "[].65535" > size) {
+                       (*logger)(ctl_error, "%s: buffer overflow", me);
+                       return (punt);
+               }
+               (void) sprintf(buf, "[%s].%u", tmp, ntohs(in6->sin6_port));
+               return (buf);
+           }
+       case AF_INET: {
+               const struct sockaddr_in *in =
+                                             (const struct sockaddr_in *) sa;
+
+               if (inet_ntop(in->sin_family, &in->sin_addr, tmp, sizeof tmp)
+                   == NULL) {
+                       (*logger)(ctl_error, "%s: inet_ntop(%u %04x %08x): %s",
+                                 me, in->sin_family,
+                                 in->sin_port, in->sin_addr.s_addr,
+                                 strerror(errno));
+                       return (punt);
+               }
+               if (strlen(tmp) + sizeof "[].65535" > size) {
+                       (*logger)(ctl_error, "%s: buffer overflow", me);
+                       return (punt);
+               }
+               (void) sprintf(buf, "[%s].%u", tmp, ntohs(in->sin_port));
+               return (buf);
+           }
+#ifndef NO_SOCKADDR_UN
+       case AF_UNIX: {
+               const struct sockaddr_un *un = 
+                                             (const struct sockaddr_un *) sa;
+               unsigned int x = sizeof un->sun_path;
+
+               if (x > size)
+                       x = size;
+               strncpy(buf, un->sun_path, x - 1);
+               buf[x - 1] = '\0';
+               return (buf);
+           }
+#endif
+       default:
+               return (punt);
+       }
+}
+
+void
+ctl_sa_copy(const struct sockaddr *src, struct sockaddr *dst) {
+       switch (src->sa_family) {
+       case AF_INET6:
+               *((struct sockaddr_in6 *)dst) =
+                                        *((const struct sockaddr_in6 *)src);
+               break;
+       case AF_INET:
+               *((struct sockaddr_in *)dst) =
+                                         *((const struct sockaddr_in *)src);
+               break;
+#ifndef NO_SOCKADDR_UN
+       case AF_UNIX:
+               *((struct sockaddr_un *)dst) =
+                                         *((const struct sockaddr_un *)src);
+               break;
+#endif
+       default:
+               *dst = *src;
+               break;
+       }
+}
diff --git a/lib/bind/isc/ctl_p.h b/lib/bind/isc/ctl_p.h
new file mode 100644 (file)
index 0000000..1ebb254
--- /dev/null
@@ -0,0 +1,22 @@
+struct ctl_buf {
+       char *                  text;
+       size_t                  used;
+};
+
+#define        MAX_LINELEN             990     /* Like SMTP. */
+#define        MAX_NTOP                (sizeof "[255.255.255.255].65535")
+
+#define        allocated_p(Buf) ((Buf).text != NULL)
+#define        buffer_init(Buf) ((Buf).text = 0, (Buf.used) = 0)
+
+#define        ctl_bufget      __ctl_bufget
+#define        ctl_bufput      __ctl_bufput
+#define        ctl_sa_ntop     __ctl_sa_ntop
+#define        ctl_sa_copy     __ctl_sa_copy
+
+int                    ctl_bufget(struct ctl_buf *, ctl_logfunc);
+void                   ctl_bufput(struct ctl_buf *);
+const char *           ctl_sa_ntop(const struct sockaddr *, char *, size_t,
+                                   ctl_logfunc);
+void                   ctl_sa_copy(const struct sockaddr *,
+                                   struct sockaddr *);
diff --git a/lib/bind/isc/ctl_srvr.c b/lib/bind/isc/ctl_srvr.c
new file mode 100644 (file)
index 0000000..dfa280e
--- /dev/null
@@ -0,0 +1,778 @@
+#if !defined(lint) && !defined(SABER)
+static const char rcsid[] = "$Id: ctl_srvr.c,v 1.1 2001/03/29 06:31:53 marka Exp $";
+#endif /* not lint */
+
+/*
+ * Copyright (c) 1998,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.
+ */
+
+/* Extern. */
+
+#include "port_before.h"
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <isc/assertions.h>
+#include <isc/ctl.h>
+#include <isc/eventlib.h>
+#include <isc/list.h>
+#include <isc/logging.h>
+#include <isc/memcluster.h>
+
+#include "ctl_p.h"
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+/* Macros. */
+
+#define        lastverb_p(verb)        (verb->name == NULL || verb->func == NULL)
+#define        address_expr            ctl_sa_ntop((struct sockaddr *)&sess->sa, \
+                                           tmp, sizeof tmp, ctx->logger)
+
+/* Types. */
+
+enum state {
+       available = 0, initializing, writing, reading, reading_data,
+       processing, idling, quitting, closing
+};
+
+union sa_un {
+       struct sockaddr_in in;
+#ifndef NO_SOCKADDR_UN
+       struct sockaddr_un un;
+#endif
+};
+
+struct ctl_sess {
+       LINK(struct ctl_sess)   link;
+       struct ctl_sctx *       ctx;
+       enum state              state;
+       int                     sock;
+       union sa_un             sa;
+       evFileID                rdID;
+       evStreamID              wrID;
+       evTimerID               rdtiID;
+       evTimerID               wrtiID;
+       struct ctl_buf          inbuf;
+       struct ctl_buf          outbuf;
+       const struct ctl_verb * verb;
+       u_int                   helpcode;
+       const void *            respctx;
+       u_int                   respflags;
+       ctl_srvrdone            donefunc;
+       void *                  uap;
+       void *                  csctx;
+};
+
+struct ctl_sctx {
+       evContext               ev;
+       void *                  uctx;
+       u_int                   unkncode;
+       u_int                   timeoutcode;
+       const struct ctl_verb * verbs;
+       const struct ctl_verb * connverb;
+       int                     sock;
+       int                     max_sess;
+       int                     cur_sess;
+       struct timespec         timeout;
+       ctl_logfunc             logger;
+       evConnID                acID;
+       LIST(struct ctl_sess)   sess;
+};
+
+/* Forward. */
+
+static void                    ctl_accept(evContext, void *, int,
+                                          const void *, int,
+                                          const void *, int);
+static void                    ctl_close(struct ctl_sess *);
+static void                    ctl_new_state(struct ctl_sess *,
+                                             enum state,
+                                             const char *);
+static void                    ctl_start_read(struct ctl_sess *);
+static void                    ctl_stop_read(struct ctl_sess *);
+static void                    ctl_readable(evContext, void *, int, int);
+static void                    ctl_rdtimeout(evContext, void *,
+                                             struct timespec,
+                                             struct timespec);
+static void                    ctl_wrtimeout(evContext, void *,
+                                             struct timespec,
+                                             struct timespec);
+static void                    ctl_docommand(struct ctl_sess *);
+static void                    ctl_writedone(evContext, void *, int, int);
+static void                    ctl_morehelp(struct ctl_sctx *,
+                                            struct ctl_sess *,
+                                            const struct ctl_verb *,
+                                            const char *,
+                                            u_int, const void *, void *);
+static void                    ctl_signal_done(struct ctl_sctx *,
+                                               struct ctl_sess *);
+
+/* Private data. */
+
+static const char *            state_names[] = {
+       "available", "initializing", "writing", "reading",
+       "reading_data", "processing", "idling", "quitting", "closing"
+};
+
+static const char              space[] = " ";
+
+static const struct ctl_verb   fakehelpverb = {
+       "fakehelp", ctl_morehelp , NULL
+};
+
+/* Public. */
+
+/*
+ * void
+ * ctl_server()
+ *     create, condition, and start a listener on the control port.
+ */
+struct ctl_sctx *
+ctl_server(evContext lev, const struct sockaddr *sap, size_t sap_len,
+          const struct ctl_verb *verbs,
+          u_int unkncode, u_int timeoutcode,
+          u_int timeout, int backlog, int max_sess,
+          ctl_logfunc logger, void *uctx)
+{
+       static const char me[] = "ctl_server";
+       static const int on = 1;
+       const struct ctl_verb *connverb;
+       struct ctl_sctx *ctx;
+       int save_errno;
+
+       if (logger == NULL)
+               logger = ctl_logger;
+       for (connverb = verbs;
+            connverb->name != NULL && connverb->func != NULL;
+            connverb++)
+               if (connverb->name[0] == '\0')
+                       break;
+       if (connverb->func == NULL) {
+               (*logger)(ctl_error, "%s: no connection verb found", me);
+               return (NULL);
+       }
+       ctx = memget(sizeof *ctx);
+       if (ctx == NULL) {
+               (*logger)(ctl_error, "%s: getmem: %s", me, strerror(errno));
+               return (NULL);
+       }
+       ctx->ev = lev;
+       ctx->uctx = uctx;
+       ctx->unkncode = unkncode;
+       ctx->timeoutcode = timeoutcode;
+       ctx->verbs = verbs;
+       ctx->timeout = evConsTime(timeout, 0);
+       ctx->logger = logger;
+       ctx->connverb = connverb;
+       ctx->max_sess = max_sess;
+       ctx->cur_sess = 0;
+       INIT_LIST(ctx->sess);
+       ctx->sock = socket(sap->sa_family, SOCK_STREAM, PF_UNSPEC);
+       if (ctx->sock > evHighestFD(ctx->ev)) {
+               ctx->sock = -1;
+               errno = ENOTSOCK;
+       }
+       if (ctx->sock < 0) {
+               save_errno = errno;
+               (*ctx->logger)(ctl_error, "%s: socket: %s",
+                              me, strerror(errno));
+               memput(ctx, sizeof *ctx);
+               errno = save_errno;
+               return (NULL);
+       }
+       if (ctx->sock > evHighestFD(lev)) {
+               close(ctx->sock);
+               (*ctx->logger)(ctl_error, "%s: file descriptor > evHighestFD");
+               errno = ENFILE;
+               memput(ctx, sizeof *ctx);
+               return (NULL);
+       }
+#ifdef NO_UNIX_REUSEADDR
+       if (sap->sa_family != AF_UNIX)
+#endif
+               if (setsockopt(ctx->sock, SOL_SOCKET, SO_REUSEADDR,
+                              (const char *)&on, sizeof on) != 0) {
+                       (*ctx->logger)(ctl_warning,
+                                      "%s: setsockopt(REUSEADDR): %s",
+                                      me, strerror(errno));
+               }
+       if (bind(ctx->sock, sap, sap_len) < 0) {
+               char tmp[MAX_NTOP];
+               save_errno = errno;
+               (*ctx->logger)(ctl_error, "%s: bind: %s: %s",
+                              me, ctl_sa_ntop((const struct sockaddr *)sap,
+                              tmp, sizeof tmp, ctx->logger),
+                              strerror(save_errno));
+               close(ctx->sock);
+               memput(ctx, sizeof *ctx);
+               errno = save_errno;
+               return (NULL);
+       }
+       if (fcntl(ctx->sock, F_SETFD, 1) < 0) {
+               (*ctx->logger)(ctl_warning, "%s: fcntl: %s", me,
+                              strerror(errno));
+       }
+       if (evListen(lev, ctx->sock, backlog, ctl_accept, ctx,
+                    &ctx->acID) < 0) {
+               save_errno = errno;
+               (*ctx->logger)(ctl_error, "%s: evListen(fd %d): %s",
+                              me, (void *)ctx->sock, strerror(errno));
+               close(ctx->sock);
+               memput(ctx, sizeof *ctx);
+               errno = save_errno;
+               return (NULL);
+       }
+       (*ctx->logger)(ctl_debug, "%s: new ctx %p, sock %d",
+                      me, ctx, ctx->sock);
+       return (ctx);
+}
+
+/*
+ * void
+ * ctl_endserver(ctx)
+ *     if the control listener is open, close it.  clean out all eventlib
+ *     stuff.  close all active sessions.
+ */
+void
+ctl_endserver(struct ctl_sctx *ctx) {
+       static const char me[] = "ctl_endserver";
+       struct ctl_sess *this, *next;
+
+       (*ctx->logger)(ctl_debug, "%s: ctx %p, sock %d, acID %p, sess %p",
+                      me, ctx, ctx->sock, ctx->acID.opaque, ctx->sess);
+       if (ctx->acID.opaque != NULL) {
+               (void)evCancelConn(ctx->ev, ctx->acID);
+               ctx->acID.opaque = NULL;
+       }
+       if (ctx->sock != -1) {
+               (void) close(ctx->sock);
+               ctx->sock = -1;
+       }
+       for (this = HEAD(ctx->sess); this != NULL; this = next) {
+               next = NEXT(this, link);
+               ctl_close(this);
+       }
+       memput(ctx, sizeof *ctx);
+}
+
+/*
+ * If body is non-NULL then it we add a "." line after it.
+ * Caller must have  escaped lines with leading ".".
+ */
+void
+ctl_response(struct ctl_sess *sess, u_int code, const char *text,
+            u_int flags, const void *respctx, ctl_srvrdone donefunc,
+            void *uap, const char *body, size_t bodylen)
+{
+       static const char me[] = "ctl_response";
+       struct iovec iov[3], *iovp = iov;
+       struct ctl_sctx *ctx = sess->ctx;
+       char tmp[MAX_NTOP], *pc;
+       int n;
+
+       REQUIRE(sess->state == initializing ||
+               sess->state == processing ||
+               sess->state == reading_data ||
+               sess->state == writing);
+       REQUIRE(sess->wrtiID.opaque == NULL);
+       REQUIRE(sess->wrID.opaque == NULL);
+       ctl_new_state(sess, writing, me);
+       sess->donefunc = donefunc;
+       sess->uap = uap;
+       if (!allocated_p(sess->outbuf) &&
+           ctl_bufget(&sess->outbuf, ctx->logger) < 0) {
+               (*ctx->logger)(ctl_error, "%s: %s: cant get an output buffer",
+                              me, address_expr);
+               goto untimely;
+       }
+       if (sizeof "000-\r\n" + strlen(text) > MAX_LINELEN) {
+               (*ctx->logger)(ctl_error, "%s: %s: output buffer ovf, closing",
+                              me, address_expr);
+               goto untimely;
+       }
+       sess->outbuf.used = SPRINTF((sess->outbuf.text, "%03d%c%s\r\n",
+                                    code, (flags & CTL_MORE) != 0 ? '-' : ' ',
+                                    text));
+       for (pc = sess->outbuf.text, n = 0; n < (int)sess->outbuf.used-2; pc++, n++)
+               if (!isascii(*pc) || !isprint(*pc))
+                       *pc = '\040';
+       *iovp++ = evConsIovec(sess->outbuf.text, sess->outbuf.used);
+       if (body != NULL) {
+               char *tmp;
+               DE_CONST(body, tmp);
+               *iovp++ = evConsIovec(tmp, bodylen);
+               DE_CONST(".\r\n", tmp);
+               *iovp++ = evConsIovec(tmp, 3);
+       }
+       (*ctx->logger)(ctl_debug, "%s: [%d] %s", me,
+                      sess->outbuf.used, sess->outbuf.text);
+       if (evWrite(ctx->ev, sess->sock, iov, iovp - iov,
+                   ctl_writedone, sess, &sess->wrID) < 0) {
+               (*ctx->logger)(ctl_error, "%s: %s: evWrite: %s", me,
+                              address_expr, strerror(errno));
+               goto untimely;
+       }
+       if (evSetIdleTimer(ctx->ev, ctl_wrtimeout, sess, ctx->timeout,
+                          &sess->wrtiID) < 0)
+       {
+               (*ctx->logger)(ctl_error, "%s: %s: evSetIdleTimer: %s", me,
+                              address_expr, strerror(errno));
+               goto untimely;
+       }
+       if (evTimeRW(ctx->ev, sess->wrID, sess->wrtiID) < 0) {
+               (*ctx->logger)(ctl_error, "%s: %s: evTimeRW: %s", me,
+                              address_expr, strerror(errno));
+ untimely:
+               ctl_signal_done(ctx, sess);
+               ctl_close(sess);
+               return;
+       }
+       sess->respctx = respctx;
+       sess->respflags = flags;
+}
+
+void
+ctl_sendhelp(struct ctl_sess *sess, u_int code) {
+       static const char me[] = "ctl_sendhelp";
+       struct ctl_sctx *ctx = sess->ctx;
+
+       sess->helpcode = code;
+       sess->verb = &fakehelpverb;
+       ctl_morehelp(ctx, sess, NULL, me, CTL_MORE,
+                    (const void *)ctx->verbs, NULL);
+}
+
+void *
+ctl_getcsctx(struct ctl_sess *sess) {
+       return (sess->csctx);
+}
+
+void *
+ctl_setcsctx(struct ctl_sess *sess, void *csctx) {
+       void *old = sess->csctx;
+
+       sess->csctx = csctx;
+       return (old);
+}
+
+/* Private functions. */
+
+static void
+ctl_accept(evContext lev, void *uap, int fd,
+          const void *lav, int lalen,
+          const void *rav, int ralen)
+{
+       static const char me[] = "ctl_accept";
+       struct ctl_sctx *ctx = uap;
+       struct ctl_sess *sess = NULL;
+       char tmp[MAX_NTOP];
+
+       UNUSED(lev);
+       UNUSED(lalen);
+       UNUSED(ralen);
+
+       if (fd < 0) {
+               (*ctx->logger)(ctl_error, "%s: accept: %s",
+                              me, strerror(errno));
+               return;
+       }
+       if (ctx->cur_sess == ctx->max_sess) {
+               (*ctx->logger)(ctl_error, "%s: %s: too many control sessions",
+                              me, ctl_sa_ntop((const struct sockaddr *)rav,
+                                              tmp, sizeof tmp,
+                                              ctx->logger));
+               (void) close(fd);
+               return;
+       }
+       sess = memget(sizeof *sess);
+       if (sess == NULL) {
+               (*ctx->logger)(ctl_error, "%s: memget: %s", me,
+                              strerror(errno));
+               (void) close(fd);
+               return;
+       }
+       if (fcntl(fd, F_SETFD, 1) < 0) {
+               (*ctx->logger)(ctl_warning, "%s: fcntl: %s", me,
+                              strerror(errno));
+       }
+       ctx->cur_sess++;
+       INIT_LINK(sess, link);
+       APPEND(ctx->sess, sess, link);
+       sess->ctx = ctx;
+       sess->sock = fd;
+       sess->wrID.opaque = NULL;
+       sess->rdID.opaque = NULL;
+       sess->wrtiID.opaque = NULL;
+       sess->rdtiID.opaque = NULL;
+       sess->respctx = NULL;
+       sess->csctx = NULL;
+       if (((const struct sockaddr *)rav)->sa_family == AF_UNIX)
+               ctl_sa_copy((const struct sockaddr *)lav,
+                           (struct sockaddr *)&sess->sa);
+       else
+               ctl_sa_copy((const struct sockaddr *)rav,
+                           (struct sockaddr *)&sess->sa);
+       sess->donefunc = NULL;
+       buffer_init(sess->inbuf);
+       buffer_init(sess->outbuf);
+       sess->state = available;
+       ctl_new_state(sess, initializing, me);
+       sess->verb = ctx->connverb;
+       (*ctx->logger)(ctl_debug, "%s: %s: accepting (fd %d)",
+                      me, address_expr, sess->sock);
+       (*ctx->connverb->func)(ctx, sess, ctx->connverb, "", 0,
+                              (const struct sockaddr *)rav, ctx->uctx);
+}
+
+static void
+ctl_new_state(struct ctl_sess *sess, enum state new_state, const char *reason)
+{
+       static const char me[] = "ctl_new_state";
+       struct ctl_sctx *ctx = sess->ctx;
+       char tmp[MAX_NTOP];
+
+       (*ctx->logger)(ctl_debug, "%s: %s: %s -> %s (%s)",
+                      me, address_expr,
+                      state_names[sess->state],
+                      state_names[new_state], reason);
+       sess->state = new_state;
+}
+
+static void
+ctl_close(struct ctl_sess *sess) {
+       static const char me[] = "ctl_close";
+       struct ctl_sctx *ctx = sess->ctx;
+       char tmp[MAX_NTOP];
+
+       REQUIRE(sess->state == initializing ||
+               sess->state == writing ||
+               sess->state == reading ||
+               sess->state == processing ||
+               sess->state == reading_data ||
+               sess->state == idling);
+       REQUIRE(sess->sock != -1);
+       if (sess->state == reading || sess->state == reading_data)
+               ctl_stop_read(sess);
+       else if (sess->state == writing) {
+               if (sess->wrID.opaque != NULL) {
+                       (void) evCancelRW(ctx->ev, sess->wrID);
+                       sess->wrID.opaque = NULL;
+               }
+               if (sess->wrtiID.opaque != NULL) {
+                       (void) evClearIdleTimer(ctx->ev, sess->wrtiID);
+                       sess->wrtiID.opaque = NULL;
+               }
+       }
+       ctl_new_state(sess, closing, me);
+       (void) close(sess->sock);
+       if (allocated_p(sess->inbuf))
+               ctl_bufput(&sess->inbuf);
+       if (allocated_p(sess->outbuf))
+               ctl_bufput(&sess->outbuf);
+       (*ctx->logger)(ctl_debug, "%s: %s: closed (fd %d)",
+                      me, address_expr, sess->sock);
+       UNLINK(ctx->sess, sess, link);
+       memput(sess, sizeof *sess);
+       ctx->cur_sess--;
+}
+
+static void
+ctl_start_read(struct ctl_sess *sess) {
+       static const char me[] = "ctl_start_read";
+       struct ctl_sctx *ctx = sess->ctx;
+       char tmp[MAX_NTOP];
+
+       REQUIRE(sess->state == initializing ||
+               sess->state == writing ||
+               sess->state == processing ||
+               sess->state == idling);
+       REQUIRE(sess->rdtiID.opaque == NULL);
+       REQUIRE(sess->rdID.opaque == NULL);
+       sess->inbuf.used = 0;
+       if (evSetIdleTimer(ctx->ev, ctl_rdtimeout, sess, ctx->timeout,
+                          &sess->rdtiID) < 0)
+       {
+               (*ctx->logger)(ctl_error, "%s: %s: evSetIdleTimer: %s", me,
+                              address_expr, strerror(errno));
+               ctl_close(sess);
+               return;
+       }
+       if (evSelectFD(ctx->ev, sess->sock, EV_READ,
+                      ctl_readable, sess, &sess->rdID) < 0) {
+               (*ctx->logger)(ctl_error, "%s: %s: evSelectFD: %s", me,
+                              address_expr, strerror(errno));
+               return;
+       }
+       ctl_new_state(sess, reading, me);
+}
+
+static void
+ctl_stop_read(struct ctl_sess *sess) {
+       static const char me[] = "ctl_stop_read";
+       struct ctl_sctx *ctx = sess->ctx;
+
+       REQUIRE(sess->state == reading || sess->state == reading_data);
+       REQUIRE(sess->rdID.opaque != NULL);
+       (void) evDeselectFD(ctx->ev, sess->rdID);
+       sess->rdID.opaque = NULL;
+       if (sess->rdtiID.opaque != NULL) {
+               (void) evClearIdleTimer(ctx->ev, sess->rdtiID);
+               sess->rdtiID.opaque = NULL;
+       }
+       ctl_new_state(sess, idling, me);
+}
+
+static void
+ctl_readable(evContext lev, void *uap, int fd, int evmask) {
+       static const char me[] = "ctl_readable";
+       struct ctl_sess *sess = uap;
+       struct ctl_sctx *ctx = sess->ctx;
+       char *eos, tmp[MAX_NTOP];
+       ssize_t n;
+
+       REQUIRE(sess != NULL);
+       REQUIRE(fd >= 0);
+       REQUIRE(evmask == EV_READ);
+       REQUIRE(sess->state == reading || sess->state == reading_data);
+       evTouchIdleTimer(lev, sess->rdtiID);
+       if (!allocated_p(sess->inbuf) &&
+           ctl_bufget(&sess->inbuf, ctx->logger) < 0) {
+               (*ctx->logger)(ctl_error, "%s: %s: cant get an input buffer",
+                              me, address_expr);
+               ctl_close(sess);
+               return;
+       }
+       n = read(sess->sock, sess->inbuf.text + sess->inbuf.used,
+                MAX_LINELEN - sess->inbuf.used);
+       if (n <= 0) {
+               (*ctx->logger)(ctl_debug, "%s: %s: read: %s",
+                              me, address_expr,
+                              (n == 0) ? "Unexpected EOF" : strerror(errno));
+               ctl_close(sess);
+               return;
+       }
+       sess->inbuf.used += n;
+       eos = memchr(sess->inbuf.text, '\n', sess->inbuf.used);
+       if (eos != NULL && eos != sess->inbuf.text && eos[-1] == '\r') {
+               eos[-1] = '\0';
+               if ((sess->respflags & CTL_DATA) != 0) {
+                       INSIST(sess->verb != NULL);
+                       (*sess->verb->func)(sess->ctx, sess, sess->verb,
+                                           sess->inbuf.text,
+                                           CTL_DATA, sess->respctx,
+                                           sess->ctx->uctx);
+               } else {
+                       ctl_stop_read(sess);
+                       ctl_docommand(sess);
+               }
+               sess->inbuf.used -= ((eos - sess->inbuf.text) + 1);
+               if (sess->inbuf.used == 0)
+                       ctl_bufput(&sess->inbuf);
+               else
+                       memmove(sess->inbuf.text, eos + 1, sess->inbuf.used);
+               return;
+       }
+       if (sess->inbuf.used == MAX_LINELEN) {
+               (*ctx->logger)(ctl_error, "%s: %s: line too long, closing",
+                              me, address_expr);
+               ctl_close(sess);
+       }
+}
+
+static void
+ctl_wrtimeout(evContext lev, void *uap,
+             struct timespec due,
+             struct timespec itv)
+{
+       static const char me[] = "ctl_wrtimeout";
+       struct ctl_sess *sess = uap;
+       struct ctl_sctx *ctx = sess->ctx;
+       char tmp[MAX_NTOP];
+       
+       UNUSED(lev);
+       UNUSED(due);
+       UNUSED(itv);
+
+       REQUIRE(sess->state == writing);
+       sess->wrtiID.opaque = NULL;
+       (*ctx->logger)(ctl_warning, "%s: %s: write timeout, closing",
+                      me, address_expr);
+       if (sess->wrID.opaque != NULL) {
+               (void) evCancelRW(ctx->ev, sess->wrID);
+               sess->wrID.opaque = NULL;
+       }
+       ctl_signal_done(ctx, sess);
+       ctl_new_state(sess, processing, me);
+       ctl_close(sess);
+}
+
+static void
+ctl_rdtimeout(evContext lev, void *uap,
+             struct timespec due,
+             struct timespec itv)
+{
+       static const char me[] = "ctl_rdtimeout";
+       struct ctl_sess *sess = uap;
+       struct ctl_sctx *ctx = sess->ctx;
+       char tmp[MAX_NTOP];
+
+       UNUSED(lev);
+       UNUSED(due);
+       UNUSED(itv);
+
+       REQUIRE(sess->state == reading);
+       sess->rdtiID.opaque = NULL;
+       (*ctx->logger)(ctl_warning, "%s: %s: timeout, closing",
+                      me, address_expr);
+       if (sess->state == reading || sess->state == reading_data)
+               ctl_stop_read(sess);
+       ctl_signal_done(ctx, sess);
+       ctl_new_state(sess, processing, me);
+       ctl_response(sess, ctx->timeoutcode, "Timeout.", CTL_EXIT, NULL,
+                    NULL, NULL, NULL, 0);
+}
+
+static void
+ctl_docommand(struct ctl_sess *sess) {
+       static const char me[] = "ctl_docommand";
+       char *name, *rest, tmp[MAX_NTOP];
+       struct ctl_sctx *ctx = sess->ctx;
+       const struct ctl_verb *verb;
+
+       REQUIRE(allocated_p(sess->inbuf));
+       (*ctx->logger)(ctl_debug, "%s: %s: \"%s\" [%u]",
+                      me, address_expr,
+                      sess->inbuf.text, (u_int)sess->inbuf.used);
+       ctl_new_state(sess, processing, me);
+       name = sess->inbuf.text + strspn(sess->inbuf.text, space);
+       rest = name + strcspn(name, space);
+       if (*rest != '\0') {
+               *rest++ = '\0';
+               rest += strspn(rest, space);
+       }
+       for (verb = ctx->verbs;
+            verb != NULL && verb->name != NULL && verb->func != NULL;
+            verb++)
+               if (verb->name[0] != '\0' && strcasecmp(name, verb->name) == 0)
+                       break;
+       if (verb != NULL && verb->name != NULL && verb->func != NULL) {
+               sess->verb = verb;
+               (*verb->func)(ctx, sess, verb, rest, 0, NULL, ctx->uctx);
+       } else {
+               char buf[1100];
+
+               if (sizeof "Unrecognized command \"\" (args \"\")" +
+                   strlen(name) + strlen(rest) > sizeof buf)
+                       strcpy(buf, "Unrecognized command (buf ovf)");
+               else
+                       sprintf(buf,
+                               "Unrecognized command \"%s\" (args \"%s\")",
+                               name, rest);
+               ctl_response(sess, ctx->unkncode, buf, 0, NULL, NULL, NULL,
+                            NULL, 0);
+       }
+}
+
+static void
+ctl_writedone(evContext lev, void *uap, int fd, int bytes) {
+       static const char me[] = "ctl_writedone";
+       struct ctl_sess *sess = uap;
+       struct ctl_sctx *ctx = sess->ctx;
+       char tmp[MAX_NTOP];
+       int save_errno = errno;
+
+       UNUSED(lev);
+       UNUSED(uap);
+
+       REQUIRE(sess->state == writing);
+       REQUIRE(fd == sess->sock);
+       REQUIRE(sess->wrtiID.opaque != NULL);
+       sess->wrID.opaque = NULL;
+       (void) evClearIdleTimer(ctx->ev, sess->wrtiID);
+       sess->wrtiID.opaque = NULL;
+       if (bytes < 0) {
+               (*ctx->logger)(ctl_error, "%s: %s: %s",
+                              me, address_expr, strerror(save_errno));
+               ctl_close(sess);
+               return;
+       }
+
+       INSIST(allocated_p(sess->outbuf));
+       ctl_bufput(&sess->outbuf);
+       if ((sess->respflags & CTL_EXIT) != 0) {
+               ctl_signal_done(ctx, sess);
+               ctl_close(sess);
+               return;
+       } else if ((sess->respflags & CTL_MORE) != 0) {
+               INSIST(sess->verb != NULL);
+               (*sess->verb->func)(sess->ctx, sess, sess->verb, "",
+                                   CTL_MORE, sess->respctx, sess->ctx->uctx);
+       } else {
+               ctl_signal_done(ctx, sess);
+               ctl_start_read(sess);
+       }
+}
+
+static void
+ctl_morehelp(struct ctl_sctx *ctx, struct ctl_sess *sess,
+            const struct ctl_verb *verb, const char *text,
+            u_int respflags, const void *respctx, void *uctx)
+{
+       const struct ctl_verb *this = respctx, *next = this + 1;
+
+       UNUSED(ctx);
+       UNUSED(verb);
+       UNUSED(text);
+       UNUSED(uctx);
+
+       REQUIRE(!lastverb_p(this));
+       REQUIRE((respflags & CTL_MORE) != 0);
+       if (lastverb_p(next))
+               respflags &= ~CTL_MORE;
+       ctl_response(sess, sess->helpcode, this->help, respflags, next,
+                    NULL, NULL, NULL, 0);
+}
+
+static void
+ctl_signal_done(struct ctl_sctx *ctx, struct ctl_sess *sess) {
+       if (sess->donefunc != NULL) {
+               (*sess->donefunc)(ctx, sess, sess->uap);
+               sess->donefunc = NULL;
+       }
+}
diff --git a/lib/bind/isc/ev_connects.c b/lib/bind/isc/ev_connects.c
new file mode 100644 (file)
index 0000000..dbb417e
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ * 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.
+ */
+
+/* ev_connects.c - implement asynch connect/accept for the eventlib
+ * vix 16sep96 [initial]
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: ev_connects.c,v 1.1 2001/03/29 06:31:53 marka Exp $";
+#endif
+
+/* Import. */
+
+#include "port_before.h"
+#include "fd_setsize.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <unistd.h>
+
+#include <isc/eventlib.h>
+#include <isc/assertions.h>
+#include "eventlib_p.h"
+
+#include "port_after.h"
+
+/* Macros. */
+
+#define GETXXXNAME(f, s, sa, len) ( \
+       (f((s), (&sa), (&len)) >= 0) ? 0 : \
+               (errno != EAFNOSUPPORT && errno != EOPNOTSUPP) ? -1 : ( \
+                       memset(&(sa), 0, sizeof (sa)), \
+                       (len) = sizeof (sa), \
+                       (sa).sa_family = AF_UNIX, \
+                       0 \
+               ) \
+       )
+
+/* Forward. */
+
+static void    listener(evContext ctx, void *uap, int fd, int evmask);
+static void    connector(evContext ctx, void *uap, int fd, int evmask);
+
+/* Public. */
+
+int
+evListen(evContext opaqueCtx, int fd, int maxconn,
+        evConnFunc func, void *uap, evConnID *id)
+{
+       evContext_p *ctx = opaqueCtx.opaque;
+       evConn *new;
+       int mode;
+
+       OKNEW(new);
+       new->flags = EV_CONN_LISTEN;
+       OK(mode = fcntl(fd, F_GETFL, NULL));    /* side effect: validate fd. */
+       /*
+        * Remember the nonblocking status.  We assume that either evSelectFD
+        * has not been done to this fd, or that if it has then the caller
+        * will evCancelConn before they evDeselectFD.  If our assumptions
+        * are not met, then we might restore the old nonblocking status
+        * incorrectly.
+        */
+       if ((mode & PORT_NONBLOCK) == 0) {
+               OK(fcntl(fd, F_SETFL, mode | PORT_NONBLOCK));
+               new->flags |= EV_CONN_BLOCK;
+       }
+       OK(listen(fd, maxconn));
+       if (evSelectFD(opaqueCtx, fd, EV_READ, listener, new, &new->file) < 0){
+               int save = errno;
+
+               FREE(new);
+               errno = save;
+               return (-1);
+       }
+       new->flags |= EV_CONN_SELECTED;
+       new->func = func;
+       new->uap = uap;
+       new->fd = fd;
+       if (ctx->conns != NULL)
+               ctx->conns->prev = new;
+       new->prev = NULL;
+       new->next = ctx->conns;
+       ctx->conns = new;
+       if (id)
+               id->opaque = new;
+       return (0);
+}
+
+int
+evConnect(evContext opaqueCtx, int fd, const void *ra, int ralen,
+         evConnFunc func, void *uap, evConnID *id)
+{
+       evContext_p *ctx = opaqueCtx.opaque;
+       evConn *new;
+
+       OKNEW(new);
+       new->flags = 0;
+       /* Do the select() first to get the socket into nonblocking mode. */
+       if (evSelectFD(opaqueCtx, fd, EV_MASK_ALL,
+                      connector, new, &new->file) < 0) {
+               int save = errno;
+
+               FREE(new);
+               errno = save;
+               return (-1);
+       }
+       new->flags |= EV_CONN_SELECTED;
+       if (connect(fd, ra, ralen) < 0 &&
+           errno != EWOULDBLOCK &&
+           errno != EAGAIN &&
+           errno != EINPROGRESS) {
+               int save = errno;
+
+               (void) evDeselectFD(opaqueCtx, new->file);
+               FREE(new);
+               errno = save;
+               return (-1);
+       }
+       /* No error, or EWOULDBLOCK.  select() tells when it's ready. */
+       new->func = func;
+       new->uap = uap;
+       new->fd = fd;
+       if (ctx->conns != NULL)
+               ctx->conns->prev = new;
+       new->prev = NULL;
+       new->next = ctx->conns;
+       ctx->conns = new;
+       if (id)
+               id->opaque = new;
+       return (0);
+}
+
+int
+evCancelConn(evContext opaqueCtx, evConnID id) {
+       evContext_p *ctx = opaqueCtx.opaque;
+       evConn *this = id.opaque;
+       evAccept *acc, *nxtacc;
+       int mode;
+
+       if ((this->flags & EV_CONN_SELECTED) != 0)
+               (void) evDeselectFD(opaqueCtx, this->file);
+       if ((this->flags & EV_CONN_BLOCK) != 0) {
+               mode = fcntl(this->fd, F_GETFL, NULL);
+               if (mode == -1) {
+                       if (errno != EBADF)
+                               return (-1);
+               } else
+                       OK(fcntl(this->fd, F_SETFL, mode | PORT_NONBLOCK));
+       }
+       
+       /* Unlink from ctx->conns. */
+       if (this->prev != NULL)
+               this->prev->next = this->next;
+       else
+               ctx->conns = this->next;
+       if (this->next != NULL)
+               this->next->prev = this->prev;
+
+       /*
+        * Remove `this' from the ctx->accepts list (zero or more times).
+        */
+       for (acc = HEAD(ctx->accepts), nxtacc = NULL;
+            acc != NULL;
+            acc = nxtacc)
+       {
+               nxtacc = NEXT(acc, link);
+               if (acc->conn == this) {
+                       UNLINK(ctx->accepts, acc, link);
+                       close(acc->fd);
+                       FREE(acc);
+               }
+       }
+
+       /* Wrap up and get out. */
+       FREE(this);
+       return (0);
+}
+
+int evHold(evContext opaqueCtx, evConnID id) {
+       evConn *this = id.opaque;
+
+       if ((this->flags & EV_CONN_LISTEN) == 0) {
+               errno = EINVAL;
+               return (-1);
+       }
+       if ((this->flags & EV_CONN_SELECTED) == 0)
+               return (0);
+       this->flags &= ~EV_CONN_SELECTED;
+       return (evDeselectFD(opaqueCtx, this->file));
+}
+
+int evUnhold(evContext opaqueCtx, evConnID id) {
+       evConn *this = id.opaque;
+       int ret;
+
+       if ((this->flags & EV_CONN_LISTEN) == 0) {
+               errno = EINVAL;
+               return (-1);
+       }
+       if ((this->flags & EV_CONN_SELECTED) != 0)
+               return (0);
+       ret = evSelectFD(opaqueCtx, this->fd, EV_READ, listener, this,
+                        &this->file);
+       if (ret == 0)
+               this->flags |= EV_CONN_SELECTED;
+       return (ret);
+}
+
+int
+evTryAccept(evContext opaqueCtx, evConnID id, int *sys_errno) {
+       evContext_p *ctx = opaqueCtx.opaque;
+       evConn *conn = id.opaque;
+       evAccept *new;
+
+       if ((conn->flags & EV_CONN_LISTEN) == 0) {
+               errno = EINVAL;
+               return (-1);
+       }
+       OKNEW(new);
+       new->conn = conn;
+       new->ralen = sizeof new->ra;
+       new->fd = accept(conn->fd, &new->ra.sa, &new->ralen);
+       if (new->fd > ctx->highestFD) {
+               close(new->fd);
+               new->fd = -1;
+               new->ioErrno = ENOTSOCK;
+       }
+       if (new->fd >= 0) {
+               new->lalen = sizeof new->la;
+               if (GETXXXNAME(getsockname, new->fd, new->la.sa, new->lalen) < 0) {
+                       new->ioErrno = errno;
+                       (void) close(new->fd);
+                       new->fd = -1;
+               } else
+                       new->ioErrno = 0;
+       } else {
+               new->ioErrno = errno;
+               if (errno == EAGAIN || errno == EWOULDBLOCK) {
+                       FREE(new);
+                       return (-1);
+               }
+       }
+       INIT_LINK(new, link);
+       APPEND(ctx->accepts, new, link);
+       *sys_errno = new->ioErrno;
+       return (0);
+}
+
+/* Private. */
+
+static void
+listener(evContext opaqueCtx, void *uap, int fd, int evmask) {
+       evContext_p *ctx = opaqueCtx.opaque;
+       evConn *conn = uap;
+       union {
+               struct sockaddr    sa;
+               struct sockaddr_in in;
+#ifndef NO_SOCKADDR_UN
+               struct sockaddr_un un;
+#endif
+       } la, ra;
+       int new, lalen = 0, ralen;
+
+       REQUIRE((evmask & EV_READ) != 0);
+       ralen = sizeof ra;
+       new = accept(fd, &ra.sa, &ralen);
+       if (new > ctx->highestFD) {
+               close(new);
+               new = -1;
+               errno = ENOTSOCK;
+       }
+       if (new >= 0) {
+               lalen = sizeof la;
+               if (GETXXXNAME(getsockname, new, la.sa, lalen) < 0) {
+                       int save = errno;
+
+                       (void) close(new);
+                       errno = save;
+                       new = -1;
+               }
+       } else if (errno == EAGAIN || errno == EWOULDBLOCK)
+               return;
+       (*conn->func)(opaqueCtx, conn->uap, new, &la.sa, lalen, &ra.sa, ralen);
+}
+
+static void
+connector(evContext opaqueCtx, void *uap, int fd, int evmask) {
+       evConn *conn = uap;
+       union {
+               struct sockaddr    sa;
+               struct sockaddr_in in;
+#ifndef NO_SOCKADDR_UN
+               struct sockaddr_un un;
+#endif
+       } la, ra;
+       int lalen, ralen;
+       char buf[1];
+       void *conn_uap;
+       evConnFunc conn_func;
+       evConnID id;
+       int socket_errno = 0;
+       int optlen;
+
+       UNUSED(evmask);
+
+       lalen = sizeof la;
+       ralen = sizeof ra;
+       conn_uap = conn->uap;
+       conn_func = conn->func;
+       id.opaque = conn;
+#ifdef SO_ERROR
+       optlen = sizeof socket_errno;
+       if (fd < 0 &&
+           getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, (char *)&socket_errno,
+                      &optlen) < 0)
+               socket_errno = errno;
+       else
+               errno = socket_errno;
+#endif
+       if (evCancelConn(opaqueCtx, id) < 0 ||
+           socket_errno ||
+#ifdef NETREAD_BROKEN
+           0 ||
+#else
+           read(fd, buf, 0) < 0 ||
+#endif
+           GETXXXNAME(getsockname, fd, la.sa, lalen) < 0 ||
+           GETXXXNAME(getpeername, fd, ra.sa, ralen) < 0) {
+               int save = errno;
+
+               (void) close(fd);       /* XXX closing caller's fd */
+               errno = save;
+               fd = -1;
+       }
+       (*conn_func)(opaqueCtx, conn_uap, fd, &la.sa, lalen, &ra.sa, ralen);
+}
diff --git a/lib/bind/isc/ev_files.c b/lib/bind/isc/ev_files.c
new file mode 100644 (file)
index 0000000..a6c13ee
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * 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.
+ */
+
+/* ev_files.c - implement asynch file IO for the eventlib
+ * vix 11sep95 [initial]
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: ev_files.c,v 1.1 2001/03/29 06:31:54 marka Exp $";
+#endif
+
+#include "port_before.h"
+#include "fd_setsize.h"
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <isc/eventlib.h>
+#include "eventlib_p.h"
+
+#include "port_after.h"
+
+static evFile *FindFD(const evContext_p *ctx, int fd, int eventmask);
+
+int
+evSelectFD(evContext opaqueCtx,
+          int fd,
+          int eventmask,
+          evFileFunc func,
+          void *uap,
+          evFileID *opaqueID
+) {
+       evContext_p *ctx = opaqueCtx.opaque;
+       evFile *id;
+       int mode;
+
+       evPrintf(ctx, 1,
+                "evSelectFD(ctx %#x, fd %d, mask 0x%x, func %#x, uap %#x)\n",
+                ctx, fd, eventmask, func, uap);
+       if (eventmask == 0 || (eventmask & ~EV_MASK_ALL) != 0)
+               ERR(EINVAL);
+       if (fd > ctx->highestFD)
+               ERR(EINVAL);
+       OK(mode = fcntl(fd, F_GETFL, NULL));    /* side effect: validate fd. */
+
+       /*
+        * The first time we touch a file descriptor, we need to check to see
+        * if the application already had it in O_NONBLOCK mode and if so, all
+        * of our deselect()'s have to leave it in O_NONBLOCK.  If not, then
+        * all but our last deselect() has to leave it in O_NONBLOCK.
+        */
+       id = FindFD(ctx, fd, EV_MASK_ALL);
+       if (id == NULL) {
+               if (mode & PORT_NONBLOCK)
+                       FD_SET(fd, &ctx->nonblockBefore);
+               else {
+                       OK(fcntl(fd, F_SETFL, mode | PORT_NONBLOCK));
+                       FD_CLR(fd, &ctx->nonblockBefore);
+               }
+       }
+
+       /*
+        * If this descriptor is already in use, search for it again to see
+        * if any of the eventmask bits we want to set are already captured.
+        * We cannot usefully capture the same fd event more than once in the
+        * same context.
+        */
+       if (id != NULL && FindFD(ctx, fd, eventmask) != NULL)
+               ERR(ETOOMANYREFS);
+
+       /* Allocate and fill. */
+       OKNEW(id);
+       id->func = func;
+       id->uap = uap;
+       id->fd = fd;
+       id->eventmask = eventmask;
+
+       /*
+        * Insert at head.  Order could be important for performance if we
+        * believe that evGetNext()'s accesses to the fd_sets will be more
+        * serial and therefore more cache-lucky if the list is ordered by
+        * ``fd.''  We do not believe these things, so we don't do it.
+        *
+        * The interesting sequence is where GetNext() has cached a select()
+        * result and the caller decides to evSelectFD() on some descriptor.
+        * Since GetNext() starts at the head, it can miss new entries we add
+        * at the head.  This is not a serious problem since the event being
+        * evSelectFD()'d for has to occur before evSelectFD() is called for
+        * the file event to be considered "missed" -- a real corner case.
+        * Maintaining a "tail" pointer for ctx->files would fix this, but I'm
+        * not sure it would be ``more correct.''
+        */
+       if (ctx->files != NULL)
+               ctx->files->prev = id;
+       id->prev = NULL;
+       id->next = ctx->files;
+       ctx->files = id;
+
+       /* Insert into fd table. */
+       if (ctx->fdTable[fd] != NULL)
+               ctx->fdTable[fd]->fdprev = id;
+       id->fdprev = NULL;
+       id->fdnext = ctx->fdTable[fd];
+       ctx->fdTable[fd] = id;
+
+       /* Turn on the appropriate bits in the {rd,wr,ex}Next fd_set's. */
+       if (eventmask & EV_READ)
+               FD_SET(fd, &ctx->rdNext);
+       if (eventmask & EV_WRITE)
+               FD_SET(fd, &ctx->wrNext);
+       if (eventmask & EV_EXCEPT)
+               FD_SET(fd, &ctx->exNext);
+
+       /* Update fdMax. */
+       if (fd > ctx->fdMax)
+               ctx->fdMax = fd;
+
+       /* Remember the ID if the caller provided us a place for it. */
+       if (opaqueID)
+               opaqueID->opaque = id;
+
+       evPrintf(ctx, 5,
+               "evSelectFD(fd %d, mask 0x%x): new masks: 0x%lx 0x%lx 0x%lx\n",
+                fd, eventmask,
+                (u_long)ctx->rdNext.fds_bits[0],
+                (u_long)ctx->wrNext.fds_bits[0],
+                (u_long)ctx->exNext.fds_bits[0]);
+
+       return (0);
+}
+
+int
+evDeselectFD(evContext opaqueCtx, evFileID opaqueID) {
+       evContext_p *ctx = opaqueCtx.opaque;
+       evFile *del = opaqueID.opaque;
+       evFile *cur;
+       int mode, eventmask;
+
+       if (!del) {
+               evPrintf(ctx, 11, "evDeselectFD(NULL) ignored\n");
+               errno = EINVAL;
+               return (-1);
+       }
+
+       evPrintf(ctx, 1, "evDeselectFD(fd %d, mask 0x%x)\n",
+                del->fd, del->eventmask);
+
+       /* Get the mode.  Unless the file has been closed, errors are bad. */
+       mode = fcntl(del->fd, F_GETFL, NULL);
+       if (mode == -1 && errno != EBADF)
+               ERR(errno);
+
+       /* Remove from the list of files. */
+       if (del->prev != NULL)
+               del->prev->next = del->next;
+       else
+               ctx->files = del->next;
+       if (del->next != NULL)
+               del->next->prev = del->prev;
+
+       /* Remove from the fd table. */
+       if (del->fdprev != NULL)
+               del->fdprev->fdnext = del->fdnext;
+       else
+               ctx->fdTable[del->fd] = del->fdnext;
+       if (del->fdnext != NULL)
+               del->fdnext->fdprev = del->fdprev;
+
+       /*
+        * If the file descriptor does not appear in any other select() entry,
+        * and if !EV_WASNONBLOCK, and if we got no EBADF when we got the mode
+        * earlier, then: restore the fd to blocking status.
+        */
+       if (!(cur = FindFD(ctx, del->fd, EV_MASK_ALL)) &&
+           !FD_ISSET(del->fd, &ctx->nonblockBefore) &&
+           mode != -1) {
+               /*
+                * Note that we won't return an error status to the caller if
+                * this fcntl() fails since (a) we've already done the work
+                * and (b) the caller didn't ask us anything about O_NONBLOCK.
+                */
+               (void) fcntl(del->fd, F_SETFL, mode & ~PORT_NONBLOCK);
+       }
+
+       /*
+        * Now find all other uses of this descriptor and OR together an event
+        * mask so that we don't turn off {rd,wr,ex}Next bits that some other
+        * file event is using.  As an optimization, stop if the event mask
+        * fills.
+        */
+       eventmask = 0;
+       for ((void)NULL;
+            cur != NULL && eventmask != EV_MASK_ALL;
+            cur = cur->next)
+               if (cur->fd == del->fd)
+                       eventmask |= cur->eventmask;
+
+       /* OK, now we know which bits we can clear out. */
+       if (!(eventmask & EV_READ)) {
+               FD_CLR(del->fd, &ctx->rdNext);
+               if (FD_ISSET(del->fd, &ctx->rdLast)) {
+                       FD_CLR(del->fd, &ctx->rdLast);
+                       ctx->fdCount--;
+               }
+       }
+       if (!(eventmask & EV_WRITE)) {
+               FD_CLR(del->fd, &ctx->wrNext);
+               if (FD_ISSET(del->fd, &ctx->wrLast)) {
+                       FD_CLR(del->fd, &ctx->wrLast);
+                       ctx->fdCount--;
+               }
+       }
+       if (!(eventmask & EV_EXCEPT)) {
+               FD_CLR(del->fd, &ctx->exNext);
+               if (FD_ISSET(del->fd, &ctx->exLast)) {
+                       FD_CLR(del->fd, &ctx->exLast);
+                       ctx->fdCount--;
+               }
+       }
+
+       /* If this was the maxFD, find the new one. */
+       if (del->fd == ctx->fdMax) {
+               ctx->fdMax = -1;
+               for (cur = ctx->files; cur; cur = cur->next)
+                       if (cur->fd > ctx->fdMax)
+                               ctx->fdMax = cur->fd;
+       }
+
+       /* If this was the fdNext, cycle that to the next entry. */
+       if (del == ctx->fdNext)
+               ctx->fdNext = del->next;
+
+       evPrintf(ctx, 5,
+             "evDeselectFD(fd %d, mask 0x%x): new masks: 0x%lx 0x%lx 0x%lx\n",
+                del->fd, eventmask,
+                (u_long)ctx->rdNext.fds_bits[0],
+                (u_long)ctx->wrNext.fds_bits[0],
+                (u_long)ctx->exNext.fds_bits[0]);
+
+       /* Couldn't free it before now since we were using fields out of it. */
+       FREE(del);
+
+       return (0);
+}
+
+static evFile *
+FindFD(const evContext_p *ctx, int fd, int eventmask) {
+       evFile *id;
+
+       for (id = ctx->fdTable[fd]; id != NULL; id = id->fdnext)
+               if (id->fd == fd && (id->eventmask & eventmask) != 0)
+                       break;
+       return (id);
+}
diff --git a/lib/bind/isc/ev_streams.c b/lib/bind/isc/ev_streams.c
new file mode 100644 (file)
index 0000000..678be35
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ * 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.
+ */
+
+/* ev_streams.c - implement asynch stream file IO for the eventlib
+ * vix 04mar96 [initial]
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: ev_streams.c,v 1.1 2001/03/29 06:31:54 marka Exp $";
+#endif
+
+#include "port_before.h"
+#include "fd_setsize.h"
+
+#include <sys/types.h>
+#include <sys/uio.h>
+
+#include <errno.h>
+
+#include <isc/eventlib.h>
+#include <isc/assertions.h>
+#include "eventlib_p.h"
+
+#include "port_after.h"
+
+static int     copyvec(evStream *str, const struct iovec *iov, int iocnt);
+static void    consume(evStream *str, size_t bytes);
+static void    done(evContext opaqueCtx, evStream *str);
+static void    writable(evContext opaqueCtx, void *uap, int fd, int evmask);
+static void    readable(evContext opaqueCtx, void *uap, int fd, int evmask);
+
+struct iovec
+evConsIovec(void *buf, size_t cnt) {
+       struct iovec ret;
+
+       memset(&ret, 0xf5, sizeof ret);
+       ret.iov_base = buf;
+       ret.iov_len = cnt;
+       return (ret);
+}
+
+int
+evWrite(evContext opaqueCtx, int fd, const struct iovec *iov, int iocnt,
+       evStreamFunc func, void *uap, evStreamID *id)
+{
+       evContext_p *ctx = opaqueCtx.opaque;
+       evStream *new;
+       int save;
+
+       OKNEW(new);
+       new->func = func;
+       new->uap = uap;
+       new->fd = fd;
+       new->flags = 0;
+       if (evSelectFD(opaqueCtx, fd, EV_WRITE, writable, new, &new->file) < 0)
+               goto free;
+       if (copyvec(new, iov, iocnt) < 0)
+               goto free;
+       new->prevDone = NULL;
+       new->nextDone = NULL;
+       if (ctx->streams != NULL)
+               ctx->streams->prev = new;
+       new->prev = NULL;
+       new->next = ctx->streams;
+       ctx->streams = new;
+       if (id != NULL)
+               id->opaque = new;
+       return (0);
+ free:
+       save = errno;
+       FREE(new);
+       errno = save;
+       return (-1);
+}
+
+int
+evRead(evContext opaqueCtx, int fd, const struct iovec *iov, int iocnt,
+       evStreamFunc func, void *uap, evStreamID *id)
+{
+       evContext_p *ctx = opaqueCtx.opaque;
+       evStream *new;
+       int save;
+
+       OKNEW(new);
+       new->func = func;
+       new->uap = uap;
+       new->fd = fd;
+       new->flags = 0;
+       if (evSelectFD(opaqueCtx, fd, EV_READ, readable, new, &new->file) < 0)
+               goto free;
+       if (copyvec(new, iov, iocnt) < 0)
+               goto free;
+       new->prevDone = NULL;
+       new->nextDone = NULL;
+       if (ctx->streams != NULL)
+               ctx->streams->prev = new;
+       new->prev = NULL;
+       new->next = ctx->streams;
+       ctx->streams = new;
+       if (id)
+               id->opaque = new;
+       return (0);
+ free:
+       save = errno;
+       FREE(new);
+       errno = save;
+       return (-1);
+}
+
+int
+evTimeRW(evContext opaqueCtx, evStreamID id, evTimerID timer) /*ARGSUSED*/ {
+       evStream *str = id.opaque;
+
+       UNUSED(opaqueCtx);
+
+       str->timer = timer;
+       str->flags |= EV_STR_TIMEROK;
+       return (0);
+}
+
+int
+evUntimeRW(evContext opaqueCtx, evStreamID id) /*ARGSUSED*/ {
+       evStream *str = id.opaque;
+
+       UNUSED(opaqueCtx);
+
+       str->flags &= ~EV_STR_TIMEROK;
+       return (0);
+}
+
+int
+evCancelRW(evContext opaqueCtx, evStreamID id) {
+       evContext_p *ctx = opaqueCtx.opaque;
+       evStream *old = id.opaque;
+
+       /*
+        * The streams list is doubly threaded.  First, there's ctx->streams
+        * that's used by evDestroy() to find and cancel all streams.  Second,
+        * there's ctx->strDone (head) and ctx->strLast (tail) which thread
+        * through the potentially smaller number of "IO completed" streams,
+        * used in evGetNext() to avoid scanning the entire list.
+        */
+
+       /* Unlink from ctx->streams. */
+       if (old->prev != NULL)
+               old->prev->next = old->next;
+       else
+               ctx->streams = old->next;
+       if (old->next != NULL)
+               old->next->prev = old->prev;
+
+       /*
+        * If 'old' is on the ctx->strDone list, remove it.  Update
+        * ctx->strLast if necessary.
+        */
+       if (old->prevDone == NULL && old->nextDone == NULL) {
+               /*
+                * Either 'old' is the only item on the done list, or it's
+                * not on the done list.  If the former, then we unlink it
+                * from the list.  If the latter, we leave the list alone.
+                */
+               if (ctx->strDone == old) {
+                       ctx->strDone = NULL;
+                       ctx->strLast = NULL;
+               }
+       } else {
+               if (old->prevDone != NULL)
+                       old->prevDone->nextDone = old->nextDone;
+               else
+                       ctx->strDone = old->nextDone;
+               if (old->nextDone != NULL)
+                       old->nextDone->prevDone = old->prevDone;
+               else
+                       ctx->strLast = old->prevDone;
+       }
+
+       /* Deallocate the stream. */
+       if (old->file.opaque)
+               evDeselectFD(opaqueCtx, old->file);
+       memput(old->iovOrig, sizeof (struct iovec) * old->iovOrigCount);
+       FREE(old);
+       return (0);
+}
+
+/* Copy a scatter/gather vector and initialize a stream handler's IO. */
+static int
+copyvec(evStream *str, const struct iovec *iov, int iocnt) {
+       int i;
+
+       str->iovOrig = (struct iovec *)memget(sizeof(struct iovec) * iocnt);
+       if (str->iovOrig == NULL) {
+               errno = ENOMEM;
+               return (-1);
+       }
+       str->ioTotal = 0;
+       for (i = 0; i < iocnt; i++) {
+               str->iovOrig[i] = iov[i];
+               str->ioTotal += iov[i].iov_len;
+       }
+       str->iovOrigCount = iocnt;
+       str->iovCur = str->iovOrig;
+       str->iovCurCount = str->iovOrigCount;
+       str->ioDone = 0;
+       return (0);
+}
+
+/* Pull off or truncate lead iovec(s). */
+static void
+consume(evStream *str, size_t bytes) {
+       while (bytes > 0) {
+               if (bytes < str->iovCur->iov_len) {
+                       str->iovCur->iov_len -= bytes;
+                       str->iovCur->iov_base = (void *)
+                               ((u_char *)str->iovCur->iov_base + bytes);
+                       str->ioDone += bytes;
+                       bytes = 0;
+               } else {
+                       bytes -= str->iovCur->iov_len;
+                       str->ioDone += str->iovCur->iov_len;
+                       str->iovCur++;
+                       str->iovCurCount--;
+               }
+       }
+}
+
+/* Add a stream to Done list and deselect the FD. */
+static void
+done(evContext opaqueCtx, evStream *str) {
+       evContext_p *ctx = opaqueCtx.opaque;
+
+       if (ctx->strLast != NULL) {
+               str->prevDone = ctx->strLast;
+               ctx->strLast->nextDone = str;
+               ctx->strLast = str;
+       } else {
+               INSIST(ctx->strDone == NULL);
+               ctx->strDone = ctx->strLast = str;
+       }
+       evDeselectFD(opaqueCtx, str->file);
+       str->file.opaque = NULL;
+       /* evDrop() will call evCancelRW() on us. */
+}
+
+/* Dribble out some bytes on the stream.  (Called by evDispatch().) */
+static void
+writable(evContext opaqueCtx, void *uap, int fd, int evmask) {
+       evStream *str = uap;
+       int bytes;
+
+       UNUSED(evmask);
+
+       bytes = writev(fd, str->iovCur, str->iovCurCount);
+       if (bytes > 0) {
+               if ((str->flags & EV_STR_TIMEROK) != 0)
+                       evTouchIdleTimer(opaqueCtx, str->timer);
+               consume(str, bytes);
+       } else {
+               if (bytes < 0 && errno != EINTR) {
+                       str->ioDone = -1;
+                       str->ioErrno = errno;
+               }
+       }
+       if (str->ioDone == -1 || str->ioDone == str->ioTotal)
+               done(opaqueCtx, str);
+}
+
+/* Scoop up some bytes from the stream.  (Called by evDispatch().) */
+static void
+readable(evContext opaqueCtx, void *uap, int fd, int evmask) {
+       evStream *str = uap;
+       int bytes;
+
+       UNUSED(evmask);
+
+       bytes = readv(fd, str->iovCur, str->iovCurCount);
+       if (bytes > 0) {
+               if ((str->flags & EV_STR_TIMEROK) != 0)
+                       evTouchIdleTimer(opaqueCtx, str->timer);
+               consume(str, bytes);
+       } else {
+               if (bytes == 0)
+                       str->ioDone = 0;
+               else {
+                       if (errno != EINTR) {
+                               str->ioDone = -1;
+                               str->ioErrno = errno;
+                       }
+               }
+       }
+       if (str->ioDone <= 0 || str->ioDone == str->ioTotal)
+               done(opaqueCtx, str);
+}
diff --git a/lib/bind/isc/ev_timers.c b/lib/bind/isc/ev_timers.c
new file mode 100644 (file)
index 0000000..ce573b2
--- /dev/null
@@ -0,0 +1,415 @@
+/*
+ * 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.
+ */
+
+/* ev_timers.c - implement timers for the eventlib
+ * vix 09sep95 [initial]
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: ev_timers.c,v 1.1 2001/03/29 06:31:54 marka Exp $";
+#endif
+
+/* Import. */
+
+#include "port_before.h"
+#include "fd_setsize.h"
+
+#include <errno.h>
+
+#include <isc/assertions.h>
+#include <isc/eventlib.h>
+#include "eventlib_p.h"
+
+#include "port_after.h"
+
+/* Constants. */
+
+#define        MILLION 1000000
+#define BILLION 1000000000
+
+/* Forward. */
+
+static int due_sooner(void *, void *);
+static void set_index(void *, int);
+static void free_timer(void *, void *);
+static void print_timer(void *, void *);
+static void idle_timeout(evContext, void *, struct timespec, struct timespec);
+
+/* Private type. */
+
+typedef struct {
+       evTimerFunc     func;
+       void *          uap;
+       struct timespec lastTouched;
+       struct timespec max_idle;
+       evTimer *       timer;
+} idle_timer;
+
+/* Public. */
+
+struct timespec
+evConsTime(time_t sec, long nsec) {
+       struct timespec x;
+
+       x.tv_sec = sec;
+       x.tv_nsec = nsec;
+       return (x);
+}
+
+struct timespec
+evAddTime(struct timespec addend1, struct timespec addend2) {
+       struct timespec x;
+
+       x.tv_sec = addend1.tv_sec + addend2.tv_sec;
+       x.tv_nsec = addend1.tv_nsec + addend2.tv_nsec;
+       if (x.tv_nsec >= BILLION) {
+               x.tv_sec++;
+               x.tv_nsec -= BILLION;
+       }
+       return (x);
+}
+
+struct timespec
+evSubTime(struct timespec minuend, struct timespec subtrahend) {
+       struct timespec x;
+
+       x.tv_sec = minuend.tv_sec - subtrahend.tv_sec;
+       if (minuend.tv_nsec >= subtrahend.tv_nsec)
+               x.tv_nsec = minuend.tv_nsec - subtrahend.tv_nsec;
+       else {
+               x.tv_nsec = BILLION - subtrahend.tv_nsec + minuend.tv_nsec;
+               x.tv_sec--;
+       }
+       return (x);
+}
+
+int
+evCmpTime(struct timespec a, struct timespec b) {
+       long x = a.tv_sec - b.tv_sec;
+
+       if (x == 0L)
+               x = a.tv_nsec - b.tv_nsec;
+       return (x < 0L ? (-1) : x > 0L ? (1) : (0));
+}
+
+struct timespec
+evNowTime() {
+       struct timeval now;
+
+       if (gettimeofday(&now, NULL) < 0)
+               return (evConsTime(0, 0));
+       return (evTimeSpec(now));
+}
+
+struct timespec
+evLastEventTime(evContext opaqueCtx) {
+       evContext_p *ctx = opaqueCtx.opaque;
+
+       return (ctx->lastEventTime);
+}
+
+struct timespec
+evTimeSpec(struct timeval tv) {
+       struct timespec ts;
+
+       ts.tv_sec = tv.tv_sec;
+       ts.tv_nsec = tv.tv_usec * 1000;
+       return (ts);
+}
+
+struct timeval
+evTimeVal(struct timespec ts) {
+       struct timeval tv;
+
+       tv.tv_sec = ts.tv_sec;
+       tv.tv_usec = ts.tv_nsec / 1000;
+       return (tv);
+}
+
+int
+evSetTimer(evContext opaqueCtx,
+          evTimerFunc func,
+          void *uap,
+          struct timespec due,
+          struct timespec inter,
+          evTimerID *opaqueID
+) {
+       evContext_p *ctx = opaqueCtx.opaque;
+       evTimer *id;
+
+       evPrintf(ctx, 1,
+"evSetTimer(ctx %#x, func %#x, uap %#x, due %d.%09ld, inter %d.%09ld)\n",
+                ctx, func, uap,
+                due.tv_sec, due.tv_nsec,
+                inter.tv_sec, inter.tv_nsec);
+
+       /* due={0,0} is a magic cookie meaning "now." */
+       if (due.tv_sec == 0 && due.tv_nsec == 0L)
+               due = evNowTime();
+
+       /* Allocate and fill. */
+       OKNEW(id);
+       id->func = func;
+       id->uap = uap;
+       id->due = due;
+       id->inter = inter;
+
+       if (heap_insert(ctx->timers, id) < 0)
+               return (-1);
+
+       /* Remember the ID if the caller provided us a place for it. */
+       if (opaqueID)
+               opaqueID->opaque = id;
+
+       if (ctx->debug > 7) {
+               evPrintf(ctx, 7, "timers after evSetTimer:\n");
+               (void) heap_for_each(ctx->timers, print_timer, (void *)ctx);
+       }
+
+       return (0);
+}
+
+int
+evClearTimer(evContext opaqueCtx, evTimerID id) {
+       evContext_p *ctx = opaqueCtx.opaque;
+       evTimer *del = id.opaque;
+
+       if (ctx->cur != NULL &&
+           ctx->cur->type == Timer &&
+           ctx->cur->u.timer.this == del) {
+               evPrintf(ctx, 8, "deferring delete of timer (executing)\n");
+               /*
+                * Setting the interval to zero ensures that evDrop() will
+                * clean up the timer.
+                */
+               del->inter = evConsTime(0, 0);
+               return (0);
+       }
+
+       if (heap_element(ctx->timers, del->index) != del)
+               ERR(ENOENT);
+
+       if (heap_delete(ctx->timers, del->index) < 0)
+               return (-1);
+       FREE(del);
+
+       if (ctx->debug > 7) {
+               evPrintf(ctx, 7, "timers after evClearTimer:\n");
+               (void) heap_for_each(ctx->timers, print_timer, (void *)ctx);
+       }
+
+       return (0);
+}
+
+int
+evResetTimer(evContext opaqueCtx,
+            evTimerID id,
+            evTimerFunc func,
+            void *uap,
+            struct timespec due,
+            struct timespec inter
+) {
+       evContext_p *ctx = opaqueCtx.opaque;
+       evTimer *timer = id.opaque;
+       struct timespec old_due;
+       int result=0;
+
+       if (heap_element(ctx->timers, timer->index) != timer)
+               ERR(ENOENT);
+
+       old_due = timer->due;
+
+       timer->func = func;
+       timer->uap = uap;
+       timer->due = due;
+       timer->inter = inter;
+
+       switch (evCmpTime(due, old_due)) {
+       case -1:
+               result = heap_increased(ctx->timers, timer->index);
+               break;
+       case 0:
+               result = 0;
+               break;
+       case 1:
+               result = heap_decreased(ctx->timers, timer->index);
+               break;
+       }
+
+       if (ctx->debug > 7) {
+               evPrintf(ctx, 7, "timers after evResetTimer:\n");
+               (void) heap_for_each(ctx->timers, print_timer, (void *)ctx);
+       }
+
+       return (result);
+}
+
+int
+evSetIdleTimer(evContext opaqueCtx,
+               evTimerFunc func,
+               void *uap,
+               struct timespec max_idle,
+               evTimerID *opaqueID
+) {
+       evContext_p *ctx = opaqueCtx.opaque;
+       idle_timer *tt;
+
+       /* Allocate and fill. */
+       OKNEW(tt);
+       tt->func = func;
+       tt->uap = uap;
+       tt->lastTouched = ctx->lastEventTime;
+       tt->max_idle = max_idle;
+
+       if (evSetTimer(opaqueCtx, idle_timeout, tt,
+                      evAddTime(ctx->lastEventTime, max_idle),
+                      max_idle, opaqueID) < 0) {
+               FREE(tt);
+               return (-1);
+       }
+
+       tt->timer = opaqueID->opaque;
+
+       return (0);
+}
+
+int
+evClearIdleTimer(evContext opaqueCtx, evTimerID id) {
+       evTimer *del = id.opaque;
+       idle_timer *tt = del->uap;
+
+       FREE(tt);
+       return (evClearTimer(opaqueCtx, id));
+}
+
+int
+evResetIdleTimer(evContext opaqueCtx,
+                evTimerID opaqueID,
+                evTimerFunc func,
+                void *uap,
+                struct timespec max_idle
+) {
+       evContext_p *ctx = opaqueCtx.opaque;
+       evTimer *timer = opaqueID.opaque;
+       idle_timer *tt = timer->uap;
+
+       tt->func = func;
+       tt->uap = uap;
+       tt->lastTouched = ctx->lastEventTime;
+       tt->max_idle = max_idle;
+
+       return (evResetTimer(opaqueCtx, opaqueID, idle_timeout, tt,
+                            evAddTime(ctx->lastEventTime, max_idle),
+                            max_idle));
+}
+
+int
+evTouchIdleTimer(evContext opaqueCtx, evTimerID id) {
+       evContext_p *ctx = opaqueCtx.opaque;
+       evTimer *t = id.opaque;
+       idle_timer *tt = t->uap;
+
+       tt->lastTouched = ctx->lastEventTime;
+
+       return (0);
+}
+
+/* Public to the rest of eventlib. */
+
+heap_context
+evCreateTimers(const evContext_p *ctx) {
+
+       UNUSED(ctx);
+
+       return (heap_new(due_sooner, set_index, 2048));
+}
+
+void
+evDestroyTimers(const evContext_p *ctx) {
+       (void) heap_for_each(ctx->timers, free_timer, NULL);
+       (void) heap_free(ctx->timers);
+}
+
+/* Private. */
+
+static int
+due_sooner(void *a, void *b) {
+       evTimer *a_timer, *b_timer;
+
+       a_timer = a;
+       b_timer = b;
+       return (evCmpTime(a_timer->due, b_timer->due) < 0);
+}
+
+static void
+set_index(void *what, int index) {
+       evTimer *timer;
+
+       timer = what;
+       timer->index = index;
+}
+
+static void
+free_timer(void *what, void *uap) {
+       evTimer *t = what;
+
+       UNUSED(uap);
+
+       FREE(t);
+}
+
+static void
+print_timer(void *what, void *uap) {
+       evTimer *cur = what;
+       evContext_p *ctx = uap;
+
+       cur = what;
+       evPrintf(ctx, 7,
+           "  func %p, uap %p, due %d.%09ld, inter %d.%09ld\n",
+                cur->func, cur->uap,
+                cur->due.tv_sec, cur->due.tv_nsec,
+                cur->inter.tv_sec, cur->inter.tv_nsec);
+}
+
+static void
+idle_timeout(evContext opaqueCtx,
+            void *uap,
+            struct timespec due,
+            struct timespec inter
+) {
+       evContext_p *ctx = opaqueCtx.opaque;
+       idle_timer *this = uap;
+       struct timespec idle;
+
+       UNUSED(due);
+       UNUSED(inter);
+       
+       idle = evSubTime(ctx->lastEventTime, this->lastTouched);
+       if (evCmpTime(idle, this->max_idle) >= 0) {
+               (this->func)(opaqueCtx, this->uap, this->timer->due,
+                            this->max_idle);
+               /*
+                * Setting the interval to zero will cause the timer to
+                * be cleaned up in evDrop().
+                */
+               this->timer->inter = evConsTime(0, 0);
+               FREE(this);
+       } else {
+               /* evDrop() will reschedule the timer. */
+               this->timer->inter = evSubTime(this->max_idle, idle);
+       }
+}
diff --git a/lib/bind/isc/ev_waits.c b/lib/bind/isc/ev_waits.c
new file mode 100644 (file)
index 0000000..d6b15fa
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * 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.
+ */
+
+/* ev_waits.c - implement deferred function calls for the eventlib
+ * vix 05dec95 [initial]
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: ev_waits.c,v 1.1 2001/03/29 06:31:54 marka Exp $";
+#endif
+
+#include "port_before.h"
+#include "fd_setsize.h"
+
+#include <errno.h>
+
+#include <isc/eventlib.h>
+#include <isc/assertions.h>
+#include "eventlib_p.h"
+
+#include "port_after.h"
+
+/* Forward. */
+
+static void            print_waits(evContext_p *ctx);
+static evWaitList *    evNewWaitList(evContext_p *);
+static void            evFreeWaitList(evContext_p *, evWaitList *);
+static evWaitList *    evGetWaitList(evContext_p *, const void *, int);
+
+
+/* Public. */
+
+/*
+ * Enter a new wait function on the queue.
+ */
+int
+evWaitFor(evContext opaqueCtx, const void *tag,
+         evWaitFunc func, void *uap, evWaitID *id)
+{
+       evContext_p *ctx = opaqueCtx.opaque;
+       evWait *new;
+       evWaitList *wl = evGetWaitList(ctx, tag, 1);
+
+       OKNEW(new);
+       new->func = func;
+       new->uap = uap;
+       new->tag = tag;
+       new->next = NULL;
+       if (wl->last != NULL)
+               wl->last->next = new;
+       else
+               wl->first = new;
+       wl->last = new;
+       if (id != NULL)
+               id->opaque = new;
+       if (ctx->debug >= 9)
+               print_waits(ctx);
+       return (0);
+}
+
+/*
+ * Mark runnable all waiting functions having a certain tag.
+ */
+int
+evDo(evContext opaqueCtx, const void *tag) {
+       evContext_p *ctx = opaqueCtx.opaque;
+       evWaitList *wl = evGetWaitList(ctx, tag, 0);
+       evWait *first;
+
+       if (!wl) {
+               errno = ENOENT;
+               return (-1);
+       }
+
+       first = wl->first;
+       INSIST(first != NULL);
+
+       if (ctx->waitDone.last != NULL)
+               ctx->waitDone.last->next = first;
+       else
+               ctx->waitDone.first = first;
+       ctx->waitDone.last = wl->last;
+       evFreeWaitList(ctx, wl);
+
+       return (0);
+}
+
+/*
+ * Remove a waiting (or ready to run) function from the queue.
+ */
+int
+evUnwait(evContext opaqueCtx, evWaitID id) {
+       evContext_p *ctx = opaqueCtx.opaque;
+       evWait *this, *prev;
+       evWaitList *wl;
+       int found = 0;
+
+       this = id.opaque;
+       INSIST(this != NULL);
+       wl = evGetWaitList(ctx, this->tag, 0);
+       if (wl != NULL) {
+               for (prev = NULL, this = wl->first;
+                    this != NULL;
+                    prev = this, this = this->next)
+                       if (this == (evWait *)id.opaque) {
+                               found = 1;
+                               if (prev != NULL)
+                                       prev->next = this->next;
+                               else
+                                       wl->first = this->next;
+                               if (wl->last == this)
+                                       wl->last = prev;
+                               if (wl->first == NULL)
+                                       evFreeWaitList(ctx, wl);
+                               break;
+                       }
+       }
+
+       if (!found) {
+               /* Maybe it's done */
+               for (prev = NULL, this = ctx->waitDone.first;
+                    this != NULL;
+                    prev = this, this = this->next)
+                       if (this == (evWait *)id.opaque) {
+                               found = 1;
+                               if (prev != NULL)
+                                       prev->next = this->next;
+                               else
+                                       ctx->waitDone.first = this->next;
+                               if (ctx->waitDone.last == this)
+                                       ctx->waitDone.last = prev;
+                               break;
+                       }
+       }
+
+       if (!found) {
+               errno = ENOENT;
+               return (-1);
+       }
+
+       FREE(this);
+
+       if (ctx->debug >= 9)
+               print_waits(ctx);
+
+       return (0);
+}
+
+int
+evDefer(evContext opaqueCtx, evWaitFunc func, void *uap) {
+       evContext_p *ctx = opaqueCtx.opaque;
+       evWait *new;
+
+       OKNEW(new);
+       new->func = func;
+       new->uap = uap;
+       new->tag = NULL;
+       new->next = NULL;
+       if (ctx->waitDone.last != NULL)
+               ctx->waitDone.last->next = new;
+       else
+               ctx->waitDone.first = new;
+       ctx->waitDone.last = new;
+       if (ctx->debug >= 9)
+               print_waits(ctx);
+       return (0);
+}
+
+/* Private. */
+
+static void
+print_waits(evContext_p *ctx) {
+       evWaitList *wl;
+       evWait *this;
+
+       evPrintf(ctx, 9, "wait waiting:\n");
+       for (wl = ctx->waitLists; wl != NULL; wl = wl->next) {
+               INSIST(wl->first != NULL);
+               evPrintf(ctx, 9, "  tag %#x:", wl->first->tag);
+               for (this = wl->first; this != NULL; this = this->next)
+                       evPrintf(ctx, 9, " %#x", this);
+               evPrintf(ctx, 9, "\n");
+       }
+       evPrintf(ctx, 9, "wait done:");
+       for (this = ctx->waitDone.first; this != NULL; this = this->next)
+               evPrintf(ctx, 9, " %#x", this);
+       evPrintf(ctx, 9, "\n");
+}
+
+static evWaitList *
+evNewWaitList(evContext_p *ctx) {
+       evWaitList *new;
+
+       NEW(new);
+       if (new == NULL)
+               return (NULL);
+       new->first = new->last = NULL;
+       new->prev = NULL;
+       new->next = ctx->waitLists;
+       if (new->next != NULL)
+               new->next->prev = new;
+       ctx->waitLists = new;
+       return (new);
+}
+
+static void
+evFreeWaitList(evContext_p *ctx, evWaitList *this) {
+
+       INSIST(this != NULL);
+
+       if (this->prev != NULL)
+               this->prev->next = this->next;
+       else
+               ctx->waitLists = this->next;
+       if (this->next != NULL)
+               this->next->prev = this->prev;
+       FREE(this);
+}
+
+static evWaitList *
+evGetWaitList(evContext_p *ctx, const void *tag, int should_create) {
+       evWaitList *this;
+
+       for (this = ctx->waitLists; this != NULL; this = this->next) {
+               if (this->first != NULL && this->first->tag == tag)
+                       break;
+       }
+       if (this == NULL && should_create)
+               this = evNewWaitList(ctx);
+       return (this);
+}
diff --git a/lib/bind/isc/eventlib.c b/lib/bind/isc/eventlib.c
new file mode 100644 (file)
index 0000000..22ea951
--- /dev/null
@@ -0,0 +1,676 @@
+/*
+ * 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.
+ */
+
+/* eventlib.c - implement glue for the eventlib
+ * vix 09sep95 [initial]
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: eventlib.c,v 1.1 2001/03/29 06:31:54 marka Exp $";
+#endif
+
+#include "port_before.h"
+#include "fd_setsize.h"
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <isc/eventlib.h>
+#include <isc/assertions.h>
+#include "eventlib_p.h"
+
+#include "port_after.h"
+
+/* Forward. */
+
+#ifdef NEED_PSELECT
+static int             pselect(int, void *, void *, void *,
+                               struct timespec *,
+                               const sigset_t *);
+#endif
+
+/* Public. */
+
+int
+evCreate(evContext *opaqueCtx) {
+       evContext_p *ctx;
+
+       /* Make sure the memory heap is initialized. */
+       if (meminit(0, 0) < 0 && errno != EEXIST)
+               return (-1);
+
+       OKNEW(ctx);
+
+       /* Global. */
+       ctx->cur = NULL;
+
+       /* Debugging. */
+       ctx->debug = 0;
+       ctx->output = NULL;
+
+       /* Connections. */
+       ctx->conns = NULL;
+       INIT_LIST(ctx->accepts);
+
+       /* Files. */
+       ctx->files = NULL;
+       FD_ZERO(&ctx->rdNext);
+       FD_ZERO(&ctx->wrNext);
+       FD_ZERO(&ctx->exNext);
+       FD_ZERO(&ctx->nonblockBefore);
+       ctx->fdMax = -1;
+       ctx->fdNext = NULL;
+       ctx->fdCount = 0;       /* Invalidate {rd,wr,ex}Last. */
+       ctx->highestFD = FD_SETSIZE - 1;
+#ifdef EVENTLIB_TIME_CHECKS
+       ctx->lastFdCount = 0;
+#endif
+       memset(ctx->fdTable, 0, sizeof ctx->fdTable);
+
+       /* Streams. */
+       ctx->streams = NULL;
+       ctx->strDone = NULL;
+       ctx->strLast = NULL;
+
+       /* Timers. */
+       ctx->lastEventTime = evNowTime();
+#ifdef EVENTLIB_TIME_CHECKS
+       ctx->lastSelectTime = ctx->lastEventTime;
+#endif
+       ctx->timers = evCreateTimers(ctx);
+       if (ctx->timers == NULL)
+               return (-1);
+
+       /* Waits. */
+       ctx->waitLists = NULL;
+       ctx->waitDone.first = ctx->waitDone.last = NULL;
+       ctx->waitDone.prev = ctx->waitDone.next = NULL;
+
+       opaqueCtx->opaque = ctx;
+       return (0);
+}
+
+void
+evSetDebug(evContext opaqueCtx, int level, FILE *output) {
+       evContext_p *ctx = opaqueCtx.opaque;
+
+       ctx->debug = level;
+       ctx->output = output;
+}
+
+int
+evDestroy(evContext opaqueCtx) {
+       evContext_p *ctx = opaqueCtx.opaque;
+       int revs = 424242;      /* Doug Adams. */
+       evWaitList *this_wl, *next_wl;
+       evWait *this_wait, *next_wait;
+
+       /* Connections. */
+       while (revs-- > 0 && ctx->conns != NULL) {
+               evConnID id;
+
+               id.opaque = ctx->conns;
+               (void) evCancelConn(opaqueCtx, id);
+       }
+       INSIST(revs >= 0);
+
+       /* Streams. */
+       while (revs-- > 0 && ctx->streams != NULL) {
+               evStreamID id;
+
+               id.opaque = ctx->streams;
+               (void) evCancelRW(opaqueCtx, id);
+       }
+
+       /* Files. */
+       while (revs-- > 0 && ctx->files != NULL) {
+               evFileID id;
+
+               id.opaque = ctx->files;
+               (void) evDeselectFD(opaqueCtx, id);
+       }
+       INSIST(revs >= 0);
+
+       /* Timers. */
+       evDestroyTimers(ctx);
+
+       /* Waits. */
+       for (this_wl = ctx->waitLists;
+            revs-- > 0 && this_wl != NULL;
+            this_wl = next_wl) {
+               next_wl = this_wl->next;
+               for (this_wait = this_wl->first;
+                    revs-- > 0 && this_wait != NULL;
+                    this_wait = next_wait) {
+                       next_wait = this_wait->next;
+                       FREE(this_wait);
+               }
+               FREE(this_wl);
+       }
+       for (this_wait = ctx->waitDone.first;
+            revs-- > 0 && this_wait != NULL;
+            this_wait = next_wait) {
+               next_wait = this_wait->next;
+               FREE(this_wait);
+       }
+
+       FREE(ctx);
+       return (0);
+}
+
+int
+evGetNext(evContext opaqueCtx, evEvent *opaqueEv, int options) {
+       evContext_p *ctx = opaqueCtx.opaque;
+       struct timespec nextTime;
+       evTimer *nextTimer;
+       evEvent_p *new;
+       int x, pselect_errno, timerPast;
+#ifdef EVENTLIB_TIME_CHECKS
+       struct timespec interval;
+#endif
+
+       /* Ensure that exactly one of EV_POLL or EV_WAIT was specified. */
+       x = ((options & EV_POLL) != 0) + ((options & EV_WAIT) != 0);
+       if (x != 1)
+               ERR(EINVAL);
+
+       /* Get the time of day.  We'll do this again after select() blocks. */
+       ctx->lastEventTime = evNowTime();
+
+ again:
+       /* Finished accept()'s do not require a select(). */
+       if (!EMPTY(ctx->accepts)) {
+               OKNEW(new);
+               new->type = Accept;
+               new->u.accept.this = HEAD(ctx->accepts);
+               UNLINK(ctx->accepts, HEAD(ctx->accepts), link);
+               opaqueEv->opaque = new;
+               return (0);
+       }
+
+       /* Stream IO does not require a select(). */
+       if (ctx->strDone != NULL) {
+               OKNEW(new);
+               new->type = Stream;
+               new->u.stream.this = ctx->strDone;
+               ctx->strDone = ctx->strDone->nextDone;
+               if (ctx->strDone == NULL)
+                       ctx->strLast = NULL;
+               opaqueEv->opaque = new;
+               return (0);
+       }
+
+       /* Waits do not require a select(). */
+       if (ctx->waitDone.first != NULL) {
+               OKNEW(new);
+               new->type = Wait;
+               new->u.wait.this = ctx->waitDone.first;
+               ctx->waitDone.first = ctx->waitDone.first->next;
+               if (ctx->waitDone.first == NULL)
+                       ctx->waitDone.last = NULL;
+               opaqueEv->opaque = new;
+               return (0);
+       }
+
+       /* Get the status and content of the next timer. */
+       if ((nextTimer = heap_element(ctx->timers, 1)) != NULL) {
+               nextTime = nextTimer->due;
+               timerPast = (evCmpTime(nextTime, ctx->lastEventTime) <= 0);
+       } else
+               timerPast = 0;  /* Make gcc happy. */
+
+       evPrintf(ctx, 9, "evGetNext: fdCount %d\n", ctx->fdCount);
+       if (ctx->fdCount == 0) {
+               static const struct timespec NoTime = {0, 0L};
+               enum { JustPoll, Block, Timer } m;
+               struct timespec t, *tp;
+
+               /* Are there any events at all? */
+               if ((options & EV_WAIT) != 0 && !nextTimer && ctx->fdMax == -1)
+                       ERR(ENOENT);
+
+               /* Figure out what select()'s timeout parameter should be. */
+               if ((options & EV_POLL) != 0) {
+                       m = JustPoll;
+                       t = NoTime;
+                       tp = &t;
+               } else if (nextTimer == NULL) {
+                       m = Block;
+                       /* ``t'' unused. */
+                       tp = NULL;
+               } else if (timerPast) {
+                       m = JustPoll;
+                       t = NoTime;
+                       tp = &t;
+               } else {
+                       m = Timer;
+                       /* ``t'' filled in later. */
+                       tp = &t;
+               }
+#ifdef EVENTLIB_TIME_CHECKS
+               if (ctx->debug > 0) {
+                       interval = evSubTime(ctx->lastEventTime,
+                                            ctx->lastSelectTime);
+                       if (interval.tv_sec > 0)
+                               evPrintf(ctx, 1,
+                                  "time between pselect() %u.%09u count %d\n",
+                                        interval.tv_sec, interval.tv_nsec,
+                                        ctx->lastFdCount);
+               }
+#endif
+               do {
+                       /* XXX need to copy only the bits we are using. */
+                       ctx->rdLast = ctx->rdNext;
+                       ctx->wrLast = ctx->wrNext;
+                       ctx->exLast = ctx->exNext;
+
+                       if (m == Timer) {
+                               INSIST(tp == &t);
+                               t = evSubTime(nextTime, ctx->lastEventTime);
+                       }
+
+                       evPrintf(ctx, 4,
+                               "pselect(%d, 0x%lx, 0x%lx, 0x%lx, %d.%09ld)\n",
+                                ctx->fdMax+1,
+                                (u_long)ctx->rdLast.fds_bits[0],
+                                (u_long)ctx->wrLast.fds_bits[0],
+                                (u_long)ctx->exLast.fds_bits[0],
+                                tp ? tp->tv_sec : -1,
+                                tp ? tp->tv_nsec : -1);
+
+                       /* XXX should predict system's earliness and adjust. */
+                       x = pselect(ctx->fdMax+1,
+                                   &ctx->rdLast, &ctx->wrLast, &ctx->exLast,
+                                   tp, NULL);
+                       pselect_errno = errno;
+
+                       evPrintf(ctx, 4, "select() returns %d (err: %s)\n",
+                                x, (x == -1) ? strerror(errno) : "none");
+
+                       /* Anything but a poll can change the time. */
+                       if (m != JustPoll)
+                               ctx->lastEventTime = evNowTime();
+
+                       /* Select() likes to finish about 10ms early. */
+               } while (x == 0 && m == Timer &&
+                        evCmpTime(ctx->lastEventTime, nextTime) < 0);
+#ifdef EVENTLIB_TIME_CHECKS
+               ctx->lastSelectTime = ctx->lastEventTime;
+#endif
+               if (x < 0) {
+                       if (pselect_errno == EINTR) {
+                               if ((options & EV_NULL) != 0)
+                                       goto again;
+                               OKNEW(new);
+                               new->type = Null;
+                               /* No data. */
+                               opaqueEv->opaque = new;
+                               return (0);
+                       }
+                       if (pselect_errno == EBADF) {
+                               for (x = 0; x <= ctx->fdMax; x++) {
+                                       struct stat sb;
+
+                                       if (FD_ISSET(x, &ctx->rdNext) == 0 &&
+                                           FD_ISSET(x, &ctx->wrNext) == 0 &&
+                                           FD_ISSET(x, &ctx->exNext) == 0)
+                                               continue;
+                                       if (fstat(x, &sb) == -1 &&
+                                           errno == EBADF)
+                                               evPrintf(ctx, 1, "EBADF: %d\n",
+                                                        x);
+                               }
+                               abort();
+                       }
+                       ERR(pselect_errno);
+               }
+               if (x == 0 && (nextTimer == NULL || !timerPast) &&
+                   (options & EV_POLL))
+                       ERR(EWOULDBLOCK);
+               ctx->fdCount = x;
+#ifdef EVENTLIB_TIME_CHECKS
+               ctx->lastFdCount = x;
+#endif
+       }
+       INSIST(nextTimer || ctx->fdCount);
+
+       /* Timers go first since we'd like them to be accurate. */
+       if (nextTimer && !timerPast) {
+               /* Has anything happened since we blocked? */
+               timerPast = (evCmpTime(nextTime, ctx->lastEventTime) <= 0);
+       }
+       if (nextTimer && timerPast) {
+               OKNEW(new);
+               new->type = Timer;
+               new->u.timer.this = nextTimer;
+               opaqueEv->opaque = new;
+               return (0);
+       }
+
+       /* No timers, so there should be a ready file descriptor. */
+       x = 0;
+       while (ctx->fdCount > 0) {
+               evFile *fid;
+               int fd, eventmask;
+
+               if (ctx->fdNext == NULL) {
+                       if (++x == 2) {
+                               /*
+                                * Hitting the end twice means that the last
+                                * select() found some FD's which have since
+                                * been deselected.
+                                *
+                                * On some systems, the count returned by
+                                * selects is the total number of bits in
+                                * all masks that are set, and on others it's
+                                * the number of fd's that have some bit set,
+                                * and on others, it's just broken.  We 
+                                * always assume that it's the number of
+                                * bits set in all masks, because that's what
+                                * the man page says it should do, and
+                                * the worst that can happen is we do an
+                                * extra select().
+                                */
+                               ctx->fdCount = 0;
+                               break;
+                       }
+                       ctx->fdNext = ctx->files;
+               }
+               fid = ctx->fdNext;
+               ctx->fdNext = fid->next;
+
+               fd = fid->fd;
+               eventmask = 0;
+               if (FD_ISSET(fd, &ctx->rdLast))
+                       eventmask |= EV_READ;
+               if (FD_ISSET(fd, &ctx->wrLast))
+                       eventmask |= EV_WRITE;
+               if (FD_ISSET(fd, &ctx->exLast))
+                       eventmask |= EV_EXCEPT;
+               eventmask &= fid->eventmask;
+               if (eventmask != 0) {
+                       if ((eventmask & EV_READ) != 0) {
+                               FD_CLR(fd, &ctx->rdLast);
+                               ctx->fdCount--;
+                       }
+                       if ((eventmask & EV_WRITE) != 0) {
+                               FD_CLR(fd, &ctx->wrLast);
+                               ctx->fdCount--;
+                       }
+                       if ((eventmask & EV_EXCEPT) != 0) {
+                               FD_CLR(fd, &ctx->exLast);
+                               ctx->fdCount--;
+                       }
+                       OKNEW(new);
+                       new->type = File;
+                       new->u.file.this = fid;
+                       new->u.file.eventmask = eventmask;
+                       opaqueEv->opaque = new;
+                       return (0);
+               }
+       }
+       if (ctx->fdCount < 0) {
+               /*
+                * select()'s count is off on a number of systems, and
+                * can result in fdCount < 0.
+                */
+               evPrintf(ctx, 4, "fdCount < 0 (%d)\n", ctx->fdCount);
+               ctx->fdCount = 0;
+       }
+
+       /* We get here if the caller deselect()'s an FD. Gag me with a goto. */
+       goto again;
+}
+
+int
+evDispatch(evContext opaqueCtx, evEvent opaqueEv) {
+       evContext_p *ctx = opaqueCtx.opaque;
+       evEvent_p *ev = opaqueEv.opaque;
+#ifdef EVENTLIB_TIME_CHECKS
+       void *func;
+       struct timespec start_time;
+       struct timespec interval;
+#endif
+
+#ifdef EVENTLIB_TIME_CHECKS
+       if (ctx->debug > 0)
+               start_time = evNowTime();
+#endif
+       ctx->cur = ev;
+       switch (ev->type) {
+           case Accept: {
+               evAccept *this = ev->u.accept.this;
+
+               evPrintf(ctx, 5,
+                       "Dispatch.Accept: fd %d -> %d, func %#x, uap %#x\n",
+                        this->conn->fd, this->fd,
+                        this->conn->func, this->conn->uap);
+               errno = this->ioErrno;
+               (this->conn->func)(opaqueCtx, this->conn->uap, this->fd,
+                                  &this->la, this->lalen,
+                                  &this->ra, this->ralen);
+#ifdef EVENTLIB_TIME_CHECKS
+               func = this->conn->func;
+#endif
+               break;
+           }
+           case File: {
+               evFile *this = ev->u.file.this;
+               int eventmask = ev->u.file.eventmask;
+
+               evPrintf(ctx, 5,
+                       "Dispatch.File: fd %d, mask 0x%x, func %#x, uap %#x\n",
+                        this->fd, this->eventmask, this->func, this->uap);
+               (this->func)(opaqueCtx, this->uap, this->fd, eventmask);
+#ifdef EVENTLIB_TIME_CHECKS
+               func = this->func;
+#endif
+               break;
+           }
+           case Stream: {
+               evStream *this = ev->u.stream.this;
+
+               evPrintf(ctx, 5,
+                        "Dispatch.Stream: fd %d, func %#x, uap %#x\n",
+                        this->fd, this->func, this->uap);
+               errno = this->ioErrno;
+               (this->func)(opaqueCtx, this->uap, this->fd, this->ioDone);
+#ifdef EVENTLIB_TIME_CHECKS
+               func = this->func;
+#endif
+               break;
+           }
+           case Timer: {
+               evTimer *this = ev->u.timer.this;
+
+               evPrintf(ctx, 5, "Dispatch.Timer: func %#x, uap %#x\n",
+                        this->func, this->uap);
+               (this->func)(opaqueCtx, this->uap, this->due, this->inter);
+#ifdef EVENTLIB_TIME_CHECKS
+               func = this->func;
+#endif
+               break;
+           }
+           case Wait: {
+               evWait *this = ev->u.wait.this;
+
+               evPrintf(ctx, 5,
+                        "Dispatch.Wait: tag %#x, func %#x, uap %#x\n",
+                        this->tag, this->func, this->uap);
+               (this->func)(opaqueCtx, this->uap, this->tag);
+#ifdef EVENTLIB_TIME_CHECKS
+               func = this->func;
+#endif
+               break;
+           }
+           case Null: {
+               /* No work. */
+#ifdef EVENTLIB_TIME_CHECKS
+               func = NULL;
+#endif
+               break;
+           }
+           default: {
+               abort();
+           }
+       }
+#ifdef EVENTLIB_TIME_CHECKS
+       if (ctx->debug > 0) {
+               interval = evSubTime(evNowTime(), start_time);
+               /* 
+                * Complain if it took longer than 50 milliseconds.
+                *
+                * We call getuid() to make an easy to find mark in a kernel
+                * trace.
+                */
+               if (interval.tv_sec > 0 || interval.tv_nsec > 50000000)
+                       evPrintf(ctx, 1,
+                        "dispatch interval %u.%09u uid %d type %d func %p\n",
+                                interval.tv_sec, interval.tv_nsec,
+                                getuid(), ev->type, func);
+       }
+#endif
+       ctx->cur = NULL;
+       evDrop(opaqueCtx, opaqueEv);
+       return (0);
+}
+
+void
+evDrop(evContext opaqueCtx, evEvent opaqueEv) {
+       evContext_p *ctx = opaqueCtx.opaque;
+       evEvent_p *ev = opaqueEv.opaque;
+
+       switch (ev->type) {
+           case Accept: {
+               FREE(ev->u.accept.this);
+               break;
+           }
+           case File: {
+               /* No work. */
+               break;
+           }
+           case Stream: {
+               evStreamID id;
+
+               id.opaque = ev->u.stream.this;
+               (void) evCancelRW(opaqueCtx, id);
+               break;
+           }
+           case Timer: {
+               evTimer *this = ev->u.timer.this;
+               evTimerID opaque;
+
+               /* Check to see whether the user func cleared the timer. */
+               if (heap_element(ctx->timers, this->index) != this) {
+                       evPrintf(ctx, 5, "Dispatch.Timer: timer rm'd?\n");
+                       break;
+               }
+               /*
+                * Timer is still there.  Delete it if it has expired,
+                * otherwise set it according to its next interval.
+                */
+               if (this->inter.tv_sec == 0 && this->inter.tv_nsec == 0L) {
+                       opaque.opaque = this;                   
+                       (void) evClearTimer(opaqueCtx, opaque);
+               } else {
+                       opaque.opaque = this;
+                       (void) evResetTimer(opaqueCtx, opaque, this->func,
+                                           this->uap,
+                                           evAddTime(ctx->lastEventTime,
+                                                     this->inter),
+                                           this->inter);
+               }
+               break;
+           }
+           case Wait: {
+               FREE(ev->u.wait.this);
+               break;
+           }
+           case Null: {
+               /* No work. */
+               break;
+           }
+           default: {
+               abort();
+           }
+       }
+       FREE(ev);
+}
+
+int
+evMainLoop(evContext opaqueCtx) {
+       evEvent event;
+       int x;
+
+       while ((x = evGetNext(opaqueCtx, &event, EV_WAIT)) == 0)
+               if ((x = evDispatch(opaqueCtx, event)) < 0)
+                       break;
+       return (x);
+}
+
+int
+evHighestFD(evContext opaqueCtx) {
+       evContext_p *ctx = opaqueCtx.opaque;
+
+       return (ctx->highestFD);
+}
+
+void
+evPrintf(const evContext_p *ctx, int level, const char *fmt, ...) {
+       va_list ap;
+
+       va_start(ap, fmt);
+       if (ctx->output != NULL && ctx->debug >= level) {
+               vfprintf(ctx->output, fmt, ap);
+               fflush(ctx->output);
+       }
+       va_end(ap);
+}
+
+#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/lib/bind/isc/eventlib.mdoc b/lib/bind/isc/eventlib.mdoc
new file mode 100644 (file)
index 0000000..f3bfef3
--- /dev/null
@@ -0,0 +1,854 @@
+.\" $Id: eventlib.mdoc,v 1.1 2001/03/29 06:31:54 marka Exp $
+.\"
+.\"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.
+.\"
+.Dd March 6, 1996
+.Dt EVENTLIB 3
+.Os BSD 4
+.Sh NAME
+.Nm evConnFunc ,
+.Nm evFileFunc ,
+.Nm evStreamFunc ,
+.Nm evTimerFunc ,
+.Nm evWaitFunc ,
+.Nm evCreate ,
+.Nm evDestroy ,
+.Nm evGetNext ,
+.Nm evDispatch ,
+.Nm evDrop ,
+.Nm evMainLoop ,
+.Nm evConsTime ,
+.Nm evTimeSpec ,
+.Nm evTimeVal ,
+.Nm evAddTime ,
+.Nm evSubTime ,
+.Nm evCmpTime ,
+.Nm evNowTime ,
+.Nm evLastEventTime ,
+.Nm evSetTimer ,
+.Nm evResetTimer ,
+.Nm evClearTimer ,
+.Nm evSetIdleTimer ,
+.Nm evTouchIdleTimer ,
+.Nm evClearIdleTimer ,
+.Nm evWaitFor ,
+.Nm evDo ,
+.Nm evUnwait ,
+.Nm evDefer ,
+.Nm evSelectFD ,
+.Nm evDeselectFD ,
+.Nm evWrite ,
+.Nm evRead ,
+.Nm evCancelRW ,
+.Nm evTimeRW ,
+.Nm evUntimeRW ,
+.Nm evListen ,
+.Nm evConnect ,
+.Nm evCancelConn ,
+.Nm evHold ,
+.Nm evUnhold ,
+.Nm evTryAccept ,
+.Nm evConsIovec ,
+.Nm evSetDebug ,
+.Nm evPrintf ,
+.Nm evInitID ,
+.Nm evTestID
+.Nd event handling library
+.Sh SYNOPSIS
+.Fd #include <isc/eventlib.h>
+.Ft typedef void
+.Fn (*evConnFunc) "evContext ctx" "void *uap" "int fd" \
+"const void *la" "int lalen" "const void *ra" "int ralen"
+.Ft typedef void
+.Fn (*evTimerFunc) "evContext ctx" "void *uap" \
+"struct timespec due" "struct timespec inter"
+.Ft typedef void
+.Fn (*evFileFunc) "evContext ctx" "void *uap" "int fd" "int eventmask"
+.Ft typedef void
+.Fn (*evStreamFunc) "evContext ctx" "void *uap" "int fd" "int bytes"
+.Ft typedef void
+.Fn (*evWaitFunc) "evContext ctx" "void *uap" "const void *tag"
+.Ft int
+.Fn evCreate "evContext *ctx"
+.Ft int
+.Fn evDestroy "evContext ctx"
+.Ft int
+.Fn evGetNext "evContext ctx" "evEvent *ev" "int options"
+.Ft int
+.Fn evDispatch "evContext ctx" "evEvent ev"
+.Ft void
+.Fn evDrop "evContext ctx" "evEvent ev"
+.Ft int
+.Fn evMainLoop "evContext ctx"
+.Ft struct timespec
+.Fn evConsTime "int sec" "int usec"
+.Ft struct timespec
+.Fn evTimeSpec "struct timeval tv"
+.Ft struct timeval
+.Fn evTimeVal "struct timespec ts"
+.Ft struct timespec
+.Fn evAddTime "struct timespec addend1" "struct timespec addend2"
+.Ft struct timespec
+.Fn evSubTime "struct timespec minuend" "struct timespec subtrahend"
+.Ft struct timespec
+.Fn evCmpTime "struct timespec a" "struct timespec b"
+.Ft struct timespec
+.Fn evNowTime "void"
+.Ft struct timespec
+.Fn evLastEventTime "evContext opaqueCtx"
+.Ft int
+.Fn evSetTimer "evContext ctx" "evTimerFunc func" "void *uap" \
+"struct timespec due" "struct timespec inter" "evTimerID *id"
+.Ft int
+.Fn evResetTimer "evContext ctx" "evTimerID id" "evTimerFunc func" \
+"void *uap" "struct timespec due" "struct timespec inter"
+.Ft int
+.Fn evClearTimer "evContext ctx" "evTimerID id"
+.Ft int
+.Fn evSetIdleTimer "evContext opaqueCtx" "evTimerFunc func" "void *uap" \
+"struct timespec max_idle" "evTimerID *opaqueID"
+.Ft int 
+.Fn evTouchIdleTimer "evContext opaqueCtx" "evTimerID id"
+.Ft int 
+.Fn evResetIdleTimer "evContext opaqueCtx" "evTimerID id" "evTimerFunc func" \
+"void *uap" "struct timespec max_idle"
+.Ft int
+.Fn evClearIdleTimer "evContext opaqueCtx" "evTimerID id"
+.Ft int
+.Fn evWaitFor "evContext opaqueCtx" "const void *tag" \
+"evWaitFunc func" "void *uap" "evWaitID *id"
+.Ft int
+.Fn evDo "evContext opaqueCtx" "const void *tag"
+.Ft int
+.Fn evUnwait "evContext opaqueCtx" "evWaitID id"
+.Ft int
+.Fn evDefer "evContext opaqueCtx" "evWaitFunc func" "void *uap"
+.Ft int
+.Fn evSelectFD "evContext ctx" "int fd" "int eventmask" \
+"evFileFunc func" "void *uap" "evFileID *id"
+.Ft int
+.Fn evDeselectFD "evContext ctx" "evFileID id"
+.Ft struct iovec
+.Fn evConsIovec "void *buf" "size_t cnt"
+.Ft int
+.Fn evWrite "evContext ctx" "int fd" "const struct iovec *iov" "int cnt" \
+"evStreamFunc func" "void *uap" "evStreamID *id"
+.Ft int
+.Fn evRead "evContext ctx" "int fd" "const struct iovec *iov" "int cnt" \
+"evStreamFunc func" "void *uap" "evStreamID *id"
+.Ft int
+.Fn evCancelRW "evContext ctx" "evStreamID id"
+.Ft int
+.Fn evTimeRW "evContext opaqueCtx" "evStreamID id" "evTimerID timer"
+.Ft int
+.Fn evUntimeRW "evContext opaqueCtx" "evStreamID id"
+.Ft int
+.Fn evListen "evContext ctx" "int fd" "int maxconn" \
+"evConnFunc func" "void *uap" "evConnID *id"
+.Ft int
+.Fn evConnect "evContext ctx" "int fd" "void *ra" "int ralen" \
+"evConnFunc func" "void *uap" "evConnID *id"
+.Ft int
+.Fn evCancelConn "evContext ctx" "evConnID id"
+.Ft int
+.Fn evHold "evContext ctx" "evConnID id"
+.Ft int
+.Fn evUnhold "evContext ctx" "evConnID id"
+.Ft int
+.Fn evTryAccept "evContext ctx" "evConnID id" "int *sys_errno"
+.Ft void
+.Fn evSetDebug "evContext ctx" "int level" "FILE *output"
+.Ft void
+.Fn evPrintf "const evContext_p *ctx" "int level" "const char *fmt" "..."
+.Ft void
+.Fn evInitID "*\s-1ID\s+1"
+.Ft int
+.Fn evTestID "\s-1ID\s+1"
+.Sh DESCRIPTION
+This library provides multiple outstanding asynchronous timers and I/O
+to a cooperating application.  The model is similar to that of the X
+Toolkit, in that events are registered with the library and the application
+spends most of its time in the
+.Fn evMainLoop
+function.  If an application already has a main loop, it can safely register
+events with this library as long as it periodically calls the
+.Fn evGetNext
+and
+.Fn evDispatch
+functions.  (Note that
+.Fn evGetNext
+has both polling and blocking modes.)
+.Pp
+The function
+.Fn evCreate
+creates an event context which is needed by all the other functions in this
+library.  All information used internally by this library is bound to this
+context, rather than to static storage.  This makes the library 
+.Dq thread safe, 
+and permits other library functions to use events without
+disrupting the application's use of events.
+.Pp
+The function
+.Fn evDestroy
+destroys a context that has been created by
+.Fn evCreate .
+All dynamic memory bound to this context will be freed.  An implicit
+.Fn evTimerClear
+will be done on all timers set in this event context.  An implicit
+.Fn evDeselectFD
+will be done on all file descriptors selected in this event context.
+.Pp
+The function
+.Fn evGetNext
+potentially waits for and then retrieves the next asynchronous event,
+placing it in the object of the
+.Fa ev
+pointer argument.  The following
+.Fa options
+are available:
+.Fa EV_POLL ,
+meaning that
+.Fn evGetNext
+should not block, but rather return
+.Dq Fa -1
+with
+.Fa errno
+set to
+.Fa EWOULDBLOCK
+if no events have occurred;
+.Fa EV_WAIT ,
+which tells
+.Fn evGetNext
+to block internally until the next event occurs; and
+.Fa EV_NULL ,
+which tells
+.Fn evGetNext
+that it should return a special 
+.Dq no-op 
+event, which is ignored by
+.Fn evDispatch
+but handled correctly by
+.Fn evDrop .
+.Fa EV_NULL
+can be necessary to the correct functioning of a caller\-written equivilent to
+.Fn evMainLoop ,
+wherein perterbations caused by external system events must be polled for, and
+the default behaviour of internally ignoring such events is undesirable.
+Note that
+.Fa EV_POLL
+and
+.Fa EV_WAIT
+are mutually exclusive.
+.Pp
+The function
+.Fn evDispatch
+dispatches an event retrieved by
+.Fn evGetNext .
+This usually involves calling the function that was associated with the event
+when the event was registered with
+.Fn evSetTimer ,
+.Fn evResetTimer ,
+or
+.Fn evSelectFD .
+All events retrieved by
+.Fn evGetNext
+must be given over to
+.Fn evDispatch
+at some point, since there is some dynamic memory associated with each event.
+.Pp
+The function
+.Fn evDrop
+deallocates dynamic memory that has been allocated by
+.Fn evGetNext .
+Calling
+.Fn evDispatch
+has the side effect of calling
+.Fn evDrop ,
+but if you are going to drop the event rather than dispatch it, you will have
+to call
+.Fn evDrop
+directly.
+.Pp
+The function
+.Fn evMainLoop
+is just:
+.Bd -literal -offset indent
+while ((x = evGetNext(opaqueCtx, &event, EV_WAIT)) == 0)
+       if ((x = evDispatch(opaqueCtx, event)) < 0)
+               break;
+return (x);
+.Ed
+.Pp
+In other words, get events and dispatch them until an error occurs.  One such
+error would be that all the events under this context become unregistered; in
+that event, there will be nothing to wait for and
+.Fn evGetNext
+becomes an undefined operation.
+.Pp
+The function
+.Fn evConsTime
+is a constructor for
+.Dq Fa struct timespec
+which allows these structures to be created and then passed as arguments to
+other functions without the use of temporary variables.  (If C had inline
+constructors, there would be no need for this function.)
+.Pp
+The functions
+.Fn evTimeSpec
+and
+.Fn evTimeVal 
+are utilities which allow the caller to convert a
+.Dq Fa struct timeval
+to a 
+.Dq Fa struct timespec
+(the function of
+.Fn evTimeSpec )
+or vice versa (the function of
+.Fn evTimeVal ) .
+Note that the name of the function indicates the type of the return value.
+.Pp
+The function
+.Fn evAddTime
+adds two
+.Dq Fa struct timespec
+values and returns the result as a
+.Dq Fa struct timespec.
+.Pp
+The function
+.Fn evSubTime
+subtracts its second
+.Dq Fa struct timespec
+argument from its first
+.Dq Fa struct timespec
+argument and returns the result as a
+.Dq Fa struct timespec.
+.Pp
+The function
+.Fn evCmpTime
+compares its two
+.Dq Fa struct timespec
+arguments and returns an
+.Dq Fa int
+that is less than zero if the first argument specifies an earlier time than
+the second, or more than zero if the first argument specifies a later time
+than the second, or equal to zero if both arguments specify the same time.
+.Pp
+The function
+.Fn evNowTime
+returns a
+.Dq Fa struct timespec
+which either describes the current time (using
+.Xr gettimeofday 2 ) ,
+if successful, or has its fields set to zero, if there is an error.
+(In the latter case, the caller can check
+.Va errno ,
+since it will be set by
+.Xr gettimeofday 2 . )
+.Pp
+The function
+.Fn evLastEventTime 
+returns the
+.Dq Fa struct timespec
+which describes the last time that certain events happened to the 
+event context indicated by 
+.Fa opaqueCtx .
+This value is updated by
+.Fn evCreate 
+and
+.Fn evGetNext 
+(upon entry and after
+.Xr select 2
+returns); it is routinely compared with other times in the internal handling
+of, e.g., timers.
+.Pp
+The function
+.Fn evSetTimer
+registers a timer event, which will be delivered as a function call to the
+function specified by the
+.Fa func
+argument.  The event will be delivered at absolute time
+.Fa due ,
+and then if time
+.Fa inter
+is not equal to
+.Dq Fa evConsTime(0,0) ,
+subsequently at intervals equal to time
+.Fa inter .
+As a special case, specifying a
+.Fa due
+argument equal to
+.Dq Fa evConsTime(0,0)
+means 
+.Dq due immediately.  
+The
+.Fa opaqueID
+argument, if specified as a value other than
+.Fa NULL ,
+will be used to store the resulting 
+.Dq timer \s-1ID\s+1 , 
+useful as an argument to
+.Fn evClearTimer .
+Note that in a 
+.Dq one\-shot 
+timer (which has an
+.Fa inter
+argument equal to
+.Dq Fa evConsTime(0,0)
+.\" putting the ) after the Dq Fa arg did not work well.  --vix
+) the user function
+.Fa func
+should deallocate any dynamic memory that is uniquely bound to the
+.Fa uap ,
+since no handles to this memory will exist within the event library
+after a one\-shot timer has been delivered.
+.Pp
+The function
+.Fn evResetTimer
+resets the values of the timer specified by
+.Fa id
+to the given arguments.  The arguments are the same as in the description of
+.Fn evSetTimer
+above.
+.Pp
+The function
+.Fn evClearTimer
+will unregister the timer event specified by
+.Fa id .
+Note that if the
+.Fa uap
+specified in the corresponding
+.Fn evSetTimer
+call is uniquely bound to any dynamic memory, then that dynamic memory should
+be freed by the caller before the handle is lost.  After a call to
+.Fn evClearTimer ,
+no handles to this
+.Fa uap
+will exist within the event library.
+.Pp
+The function
+.Fn evSetIdleTimer 
+is similar to (and built on)
+.Fn evSetTimer ;
+it registers an idle timer event which provides for the function call to
+.Fa func
+to occur.  However, for an
+.Em idle
+timer, the call will occur after at least
+.Dq Fa max_idle
+time has passed since the time the idle timer was
+.Dq last touched ;
+originally, this is set to the time returned by
+.Fn evLastEventTime 
+(described above) for the event context specified by 
+.Fa opaqueCtx .  
+This is a 
+.Dq one\-shot 
+timer, but the time at which the
+.Fa func
+is actually called can be changed by recourse to
+.Fn evTouchIdleTimer
+(described below).  The pointer to the underlying 
+.Dq timer \s-1ID\s+1 
+is returned in
+.Fa opaqueID ,
+if it is
+.No non- Ns Dv NULL .
+.Pp
+The
+.Fn evTouchIdleTimer 
+function updates the idle timer associated with
+.Fa id ,
+setting its idea of the time it was last accessed to the value returned by
+.Fn evLastEventTime
+(described above) for the event context specified by
+.Fa opaqueCtx .
+This means that the idle timer will expire after at least
+.Fa max_idle
+time has passed since this (possibly new) time, providing a caller mechanism
+for resetting the call to the
+.Fa func
+associated with the idle timer.  (See the description of
+.Fn evSetIdleTimer ,
+above, for information about
+.Fa func
+and
+.Fa max_idle . )
+.Pp
+The
+.Fn evResetIdleTimer
+function reschedules a timer and resets the callback function and its argument.
+Note that resetting a timer also ``touches'' it.
+.Pp
+The
+.Fn evClearIdleTimer
+function unregisters the idle timer associated with
+.Fa id .
+See the discussion under
+.Fn evClearTimer , 
+above, for information regarding caller handling of the
+.Fa uap
+associated with the corresponding
+.Fn evSetIdleTimer
+call.
+.Pp
+The function
+.Fn evWaitFor
+places the function
+.Fa func
+on the given event context's wait queue with the associated (possibly
+.Dv NULL )
+.Dq Fa tag ;
+if 
+.Fa id
+is 
+.No non- Ns Dv NULL ,
+then it will contain the 
+.Dq wait \s-1ID\s+1 
+associated with the created queue element.
+.Pp
+The function
+.Fn evDo 
+marks 
+.Em all
+of the 
+.Dq waiting 
+functions in the given event context's wait queue with the associated (possibly
+.Dv NULL )
+.Dq Fa tag
+as runnable.  This places these functions in a
+.Dq done
+queue which will be read by
+.Fn evGetNext .
+.Pp
+The function
+.Fn evUnwait 
+will search for the
+.Dq wait \s-1ID\s+1 
+.Fa id
+in the wait queue of the given event context; if an element with the given
+.Fa id 
+is not found, then the
+.Dq done
+queue of that context is searched.  If found, the queue element is removed
+from the appropriate list.
+.Pp
+The function
+.Fn evDefer
+causes a function (specified as
+.Fa func ,
+with argument
+.Fa uap )
+to be dispatched at some later time.  Note that the
+.Fa tag
+argument to
+.Fa func
+will always be
+.Fa NULL
+when dispatched.
+.Pp
+The function
+.Fn evSelectFD
+registers a file I/O event for the file descriptor specified by
+.Fa fd .
+Bits in the
+.Fa eventmask
+argument are named
+.Fa EV_READ ,
+.Fa EV_WRITE ,
+and
+.Fa EV_EXCEPT .
+At least one of these bits must be specified.  If the
+.Fa id
+argument is not equal to
+.Fa NULL ,
+it will be used to store a unique ``file event \s-1ID\s+1'' for this event,
+which is useful in subsequent calls to
+.Fn evDeselectFD .
+A file descriptor will be made nonblocking using the
+.Fa O_NONBLOCK
+flag with
+.Xr fcntl 2
+on its first concurrent registration via
+.Fn evSelectFD .
+An
+.Fn evSelectFD
+remains in effect until cancelled via
+.Fn evDeselectFD .
+.Pp
+The function
+.Fn evDeselectFD
+unregisters the ``file event'' specified by the
+.Fa id
+argument.  If the corresponding
+.Fa uap
+uniquely points to dynamic memory, that memory should be freed before its
+handle is lost, since after a call to
+.Fn evDeselectFD ,
+no handles to this event's
+.Fa uap
+will remain within the event library.  A file descriptor will be taken out of
+nonblocking mode (see
+.Fa O_NONBLOCK
+and
+.Xr fcntl 2 )
+when its last event registration is removed via
+.Fn evDeselectFD ,
+if it was in blocking mode before the first registration via
+.Fn evSelectFD .
+.Pp
+The function
+.Fn evConsIovec
+is a constructor for a single
+.Ft struct iovec
+structure, which is useful for
+.Fn evWrite
+and
+.Fn evRead .
+.Pp
+The functions
+.Fn evWrite
+and
+.Fn evRead
+start asynchronous stream I/O operations on file descriptor
+.Fa fd .
+The data to be written or read is in the scatter/gather descriptor specified by
+.Fa iov
+and
+.Fa cnt .
+The supplied function
+.Fa func
+will be called with argument
+.Fa uap
+when the I/O operation is complete.  If
+.Fa id
+is not
+.Fa NULL ,
+it will be filled a with the stream event identifier suitable for use with
+.Fn evCancelRW .
+.Pp
+The function
+.Fn evCancelRW
+extinguishes an outstanding
+.Fn evWrite
+or
+.Fn evRead
+call.  System I/O calls cannot always be cancelled, but you are guaranteed
+that the
+.Fa func
+function supplied to
+.Fn evWrite
+or
+.Fn evRead
+will not be called after a call to
+.Fn evCancelRW .
+Care should be taken not to deallocate or otherwise reuse the space pointed
+to by the segment descriptors in
+.Fa iov
+unless the underlying file descriptor is closed first.
+.Pp
+The function
+.Fn evTimeRW
+sets the stream associated with the given stream \s-1ID\s+1 
+.Dq Fa id
+to have the idle timer associated with the timer \s-1ID\s+1 
+.Dq Fa timer .
+.Pp
+The function
+.Fn evUntimeRW
+says that the stream associated with the given stream \s-1ID\s+1
+.Dq Fa id
+should ignore its idle timer, if present.
+.Pp
+The functions
+.Fn evListen ,
+.Fn evConnect ,
+and
+.Fn evCancelConn
+can be used to manage asynchronous incoming and outgoing socket connections.
+Sockets to be used with these functions should first be created with
+.Xr socket 2
+and given a local name with
+.Xr bind 2 .
+It is extremely unlikely that the same socket will ever be
+useful for both incoming and outgoing connections.  The
+.Fa id
+argument to
+.Fn evListen
+and
+.Fn evConnect
+is either
+.Fa NULL
+or the address of a
+.Ft evFileID
+variable which can then be used in a subsequent call to
+.Fn evCancelConn .
+.Pp
+After a call to
+.Fn evListen ,
+each incoming connection arriving on
+.Fa fd
+will cause
+.Fa func
+to be called with
+.Fa uap
+as one of its arguments.
+.Fn evConnect
+initiates an outgoing connection on
+.Fa fd
+to destination address
+.Fa ra
+(whose length is
+.Fa ralen ).
+When the connection is complete,
+.Fa func
+will be called with
+.Fa uap
+as one of its arguments.  The argument
+.Fa fd
+to
+.Fn (*func)()
+will be
+.Fa -1
+if an error occurred that prevented this connection from completing 
+successfully.  In this case
+.Fn errno
+will have been set and the socket described by
+.Fa fd
+will have been closed.  The
+.Fn evCancelConn
+function will prevent delivery of all pending and subsequent
+events for the outstanding connection.  The
+.Fn evHold
+function will suspend the acceptance of new connections on the listener
+specified by
+.Fa id .
+Connections will be queued by the protocol stack up to the system's limit.  The
+.Fn evUnhold
+function will reverse the effects of
+.Fn evHold ,
+allowing incoming connections to be delivered for listener
+.Fa id .
+The
+.Fn evTryAccept
+function will poll the listener specified by
+.Fa id ,
+accepting a new connection if one is available, and queuing a connection event
+for later retrieval by
+.Fn evGetNext .
+If the connection event queued is an accept error(), sys_errno will contain
+the error code; otherwise it will be zero.  All connection events queued by
+.Fn evTryAccept
+will be delivered by
+.Fn evGetNext
+before a new select is done on the listener.
+.Pp
+The function
+.Fn evSetDebug
+sets the debugging
+.Fa level
+and diagnostic
+.Fa output
+file handle for an event context.  Greater numeric levels will
+result in more verbose output being sent to the output FILE during program
+execution.
+.Pp
+The function
+.Fn evPrintf
+prints a message with the format
+.Dq Fa fmt
+and the following arguments (if any), on the output stream associated
+with the event context pointed to by
+.Fa ctx .
+The message is output if the event context's debug level is greater than
+or equal to the indicated
+.Fa level .
+.Pp
+The function
+.Fn evInitID
+will initialize an opaque 
+.Dq evConn \s-1ID\s+1 , 
+.Dq evFile \s-1ID\s+1 , 
+.Dq evStream \s-1ID\s+1 , 
+.Dq evTimer \s-1ID\s+1 , 
+.Dq evWait \s-1ID\s+1 , 
+.Dq evContext , 
+or
+.Dq evEvent ,
+which is passed by reference.
+.Pp
+The function
+.Fn evTestID
+will examine an opaque \s-1ID\s+1 and return
+.Dq TRUE
+only if it is not in its initialized state.
+.Sh RETURN VALUES
+All the functions whose return type is
+.Dq Fa int
+use the standard convention of returning zero (0) to indicate success, or
+returning
+.Dq Fa -1
+and setting
+.Fa errno
+to indicate failure.
+.Sh FILE
+.Pa heap.h ,
+which is in the 
+.Pa src/lib/isc
+directory of the current 
+.Sy BIND
+distribution.
+.Sh ERRORS
+The possible values for
+.Fa errno
+when one of the
+.Dq Fa int
+functions in this library returns
+.Dq Fa -1
+include those of the Standard C Library and also:
+.Bl -tag -width EWOULDBLOCKAA
+.It Bq Er EINVAL
+Some function argument has an unreasonable value.
+.It Bq Er EINVAL
+The specified file descriptor has an integer value greater than the default
+.Fa FD_SETSIZE ,
+meaning that the application's limit is higher than the library's.
+.It Bq Er ENOENT
+The specified 
+.Dq event \s-1ID\s+1 
+does not exist.
+.It Bq Er EWOULDBLOCK
+No events have occurred and the
+.Fa EV_POLL
+option was specified.
+.It Bq Er EBADF
+The specified signal was unblocked outside the library.
+.El
+.Sh SEE ALSO
+.Xr gettimeofday 2 ,
+.Xr select 2 ,
+.Xr fcntl 3 ,
+.Xr malloc 3 ,
+.Xr @INDOT@named @SYS_OPS_EXT@ ,
+.Xr readv 3 ,
+.Xr writev 3 .
+.Sh BUGS
+This huge man page needs to be broken up into a handful of smaller ones.
+.Sh HISTORY
+The
+.Nm eventlib
+library was designed by Paul Vixie with excellent advice from his friends
+and with tips 'o the cap to the X Consortium and the implementors of DEC SRC
+Modula-3.
diff --git a/lib/bind/isc/eventlib_p.h b/lib/bind/isc/eventlib_p.h
new file mode 100644 (file)
index 0000000..e70eb7b
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * 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.
+ */
+
+/* eventlib_p.h - private interfaces for eventlib
+ * vix 09sep95 [initial]
+ *
+ * $Id: eventlib_p.h,v 1.1 2001/03/29 06:31:54 marka Exp $
+ */
+
+#ifndef _EVENTLIB_P_H
+#define _EVENTLIB_P_H
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+
+#define EVENTLIB_DEBUG 1
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/heap.h>
+#include <isc/list.h>
+#include <isc/memcluster.h>
+
+#define        EV_MASK_ALL     (EV_READ | EV_WRITE | EV_EXCEPT)
+#define ERR(e)         return (errno = (e), -1)
+#define OK(x)          if ((x) < 0) ERR(errno); else (void)NULL
+
+#define        NEW(p)          if (((p) = memget(sizeof *(p))) != NULL) \
+                               FILL(p); \
+                       else \
+                               (void)NULL;
+#define OKNEW(p)       if (!((p) = memget(sizeof *(p)))) { \
+                               errno = ENOMEM; \
+                               return (-1); \
+                       } else \
+                               FILL(p)
+#define FREE(p)                memput((p), sizeof *(p))
+
+#if EVENTLIB_DEBUG
+#define FILL(p)                memset((p), 0xF5, sizeof *(p))
+#else
+#define FILL(p)
+#endif
+
+typedef struct evConn {
+       evConnFunc      func;
+       void *          uap;
+       int             fd;
+       int             flags;
+#define EV_CONN_LISTEN         0x0001          /* Connection is a listener. */
+#define EV_CONN_SELECTED       0x0002          /* evSelectFD(conn->file). */
+#define EV_CONN_BLOCK          0x0004          /* Listener fd was blocking. */
+       evFileID        file;
+       struct evConn * prev;
+       struct evConn * next;
+} evConn;
+
+typedef struct evAccept {
+       int             fd;
+       union {
+               struct sockaddr         sa;
+               struct sockaddr_in      in;
+#ifndef NO_SOCKADDR_UN
+               struct sockaddr_un      un;
+#endif
+       }               la;
+       int             lalen;
+       union {
+               struct sockaddr         sa;
+               struct sockaddr_in      in;
+#ifndef NO_SOCKADDR_UN
+               struct sockaddr_un      un;
+#endif
+       }               ra;
+       int             ralen;
+       int             ioErrno;
+       evConn *        conn;
+       LINK(struct evAccept) link;
+} evAccept;
+
+typedef struct evFile {
+       evFileFunc      func;
+       void *          uap;
+       int             fd;
+       int             eventmask;
+       int             preemptive;
+       struct evFile * prev;
+       struct evFile * next;
+       struct evFile * fdprev;
+       struct evFile * fdnext;
+} evFile;
+
+typedef struct evStream {
+       evStreamFunc    func;
+       void *          uap;
+       evFileID        file;
+       evTimerID       timer;
+       int             flags;
+#define EV_STR_TIMEROK 0x0001  /* IFF timer valid. */
+       int             fd;
+       struct iovec *  iovOrig;
+       int             iovOrigCount;
+       struct iovec *  iovCur;
+       int             iovCurCount;
+       int             ioTotal;
+       int             ioDone;
+       int             ioErrno;
+       struct evStream *prevDone, *nextDone;
+       struct evStream *prev, *next;
+} evStream;
+
+typedef struct evTimer {
+       evTimerFunc     func;
+       void *          uap;
+       struct timespec due, inter;
+       int             index;
+} evTimer;
+
+typedef struct evWait {
+       evWaitFunc      func;
+       void *          uap;
+       const void *    tag;
+       struct evWait * next;
+} evWait;
+
+typedef struct evWaitList {
+       evWait *                first;
+       evWait *                last;
+       struct evWaitList *     prev;
+       struct evWaitList *     next;
+} evWaitList;
+
+typedef struct evEvent_p {
+       enum {  Accept, File, Stream, Timer, Wait, Free, Null  } type;
+       union {
+               struct {  evAccept *this;  }                    accept;
+               struct {  evFile *this; int eventmask;  }       file;
+               struct {  evStream *this;  }                    stream;
+               struct {  evTimer *this;  }                     timer;
+               struct {  evWait *this;  }                      wait;
+               struct {  struct evEvent_p *next;  }            free;
+               struct {  const void *placeholder;  }           null;
+       } u;
+} evEvent_p;
+
+typedef struct {
+       /* Global. */
+       const evEvent_p *cur;
+       /* Debugging. */
+       int             debug;
+       FILE            *output;
+       /* Connections. */
+       evConn          *conns;
+       LIST(evAccept)  accepts;
+       /* Files. */
+       evFile          *files, *fdNext;
+       fd_set          rdLast, rdNext;
+       fd_set          wrLast, wrNext;
+       fd_set          exLast, exNext;
+       fd_set          nonblockBefore;
+       int             fdMax, fdCount, highestFD;
+       evFile          *fdTable[FD_SETSIZE];
+#ifdef EVENTLIB_TIME_CHECKS
+       struct timespec lastSelectTime;
+       int             lastFdCount;
+#endif
+       /* Streams. */
+       evStream        *streams;
+       evStream        *strDone, *strLast;
+       /* Timers. */
+       struct timespec lastEventTime;
+       heap_context    timers;
+       /* Waits. */
+       evWaitList      *waitLists;
+       evWaitList      waitDone;
+} evContext_p;
+
+/* eventlib.c */
+#define evPrintf __evPrintf
+void evPrintf(const evContext_p *ctx, int level, const char *fmt, ...);
+
+/* ev_timers.c */
+#define evCreateTimers __evCreateTimers
+heap_context evCreateTimers(const evContext_p *);
+#define evDestroyTimers __evDestroyTimers
+void evDestroyTimers(const evContext_p *);
+
+/* ev_waits.c */
+#define evFreeWait __evFreeWait
+evWait *evFreeWait(evContext_p *ctx, evWait *old);
+
+#endif /*_EVENTLIB_P_H*/
diff --git a/lib/bind/isc/heap.c b/lib/bind/isc/heap.c
new file mode 100644 (file)
index 0000000..69f98da
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 1997,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.
+ */
+
+/*
+ * Heap implementation of priority queues adapted from the following:
+ *
+ *     _Introduction to Algorithms_, Cormen, Leiserson, and Rivest,
+ *     MIT Press / McGraw Hill, 1990, ISBN 0-262-03141-8, chapter 7.
+ *
+ *     _Algorithms_, Second Edition, Sedgewick, Addison-Wesley, 1988,
+ *     ISBN 0-201-06673-4, chapter 11.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: heap.c,v 1.1 2001/03/29 06:31:55 marka Exp $";
+#endif /* not lint */
+
+#include "port_before.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "port_after.h"
+
+#include <isc/heap.h>
+
+/*
+ * Note: to make heap_parent and heap_left easy to compute, the first
+ * element of the heap array is not used; i.e. heap subscripts are 1-based,
+ * not 0-based.
+ */
+#define heap_parent(i) ((i) >> 1)
+#define heap_left(i) ((i) << 1)
+
+#define ARRAY_SIZE_INCREMENT 512
+
+heap_context
+heap_new(heap_higher_priority_func higher_priority, heap_index_func index,
+        int array_size_increment) {
+       heap_context ctx;
+
+       ctx = (heap_context)malloc(sizeof (struct heap_context));
+       if (ctx == NULL || higher_priority == NULL)
+               return (NULL);
+       ctx->array_size = 0;
+       if (array_size_increment == 0)
+               ctx->array_size_increment = ARRAY_SIZE_INCREMENT;
+       else
+               ctx->array_size_increment = array_size_increment;
+       ctx->heap_size = 0;
+       ctx->heap = NULL;
+       ctx->higher_priority = higher_priority;
+       ctx->index = index;
+       return (ctx);
+}
+
+int
+heap_free(heap_context ctx) {
+       if (ctx == NULL) {
+               errno = EINVAL;
+               return (-1);
+       }
+
+       if (ctx->heap != NULL)
+               free(ctx->heap);
+       free(ctx);
+
+       return (0);
+}
+
+static int
+heap_resize(heap_context ctx) {
+       void **new_heap;
+
+       ctx->array_size += ctx->array_size_increment;
+       new_heap = (void **)realloc(ctx->heap,
+                                   (ctx->array_size) * (sizeof (void *)));
+       if (new_heap == NULL) {
+               errno = ENOMEM;
+               return (-1);
+       }
+       ctx->heap = new_heap;
+       return (0);
+}
+
+static void
+float_up(heap_context ctx, int i, void *elt) {
+       int p;
+
+       for ( p = heap_parent(i); 
+             i > 1 && ctx->higher_priority(elt, ctx->heap[p]);
+             i = p, p = heap_parent(i) ) {
+               ctx->heap[i] = ctx->heap[p];
+               if (ctx->index != NULL)
+                       (ctx->index)(ctx->heap[i], i);
+       }
+       ctx->heap[i] = elt;
+       if (ctx->index != NULL)
+               (ctx->index)(ctx->heap[i], i);
+}
+
+static void
+sink_down(heap_context ctx, int i, void *elt) {
+       int j, size, half_size;
+
+       size = ctx->heap_size;
+       half_size = size / 2;
+       while (i <= half_size) {
+               /* find smallest of the (at most) two children */
+               j = heap_left(i);
+               if (j < size && ctx->higher_priority(ctx->heap[j+1],
+                                                    ctx->heap[j]))
+                       j++;
+               if (ctx->higher_priority(elt, ctx->heap[j]))
+                       break;
+               ctx->heap[i] = ctx->heap[j];
+               if (ctx->index != NULL)
+                       (ctx->index)(ctx->heap[i], i);
+               i = j;
+       }
+       ctx->heap[i] = elt;
+       if (ctx->index != NULL)
+               (ctx->index)(ctx->heap[i], i);
+}
+
+int
+heap_insert(heap_context ctx, void *elt) {
+       int i;
+
+       if (ctx == NULL || elt == NULL) {
+               errno = EINVAL;
+               return (-1);
+       }
+
+       i = ++ctx->heap_size;
+       if (ctx->heap_size >= ctx->array_size && heap_resize(ctx) < 0)
+               return (-1);
+       
+       float_up(ctx, i, elt);
+
+       return (0);
+}
+
+int
+heap_delete(heap_context ctx, int i) {
+       void *elt;
+
+       if (ctx == NULL || i < 1 || i > ctx->heap_size) {
+               errno = EINVAL;
+               return (-1);
+       }
+
+       elt = ctx->heap[ctx->heap_size];
+       if (--ctx->heap_size > 0)
+               sink_down(ctx, i, elt);
+
+       return (0);
+}
+
+int
+heap_increased(heap_context ctx, int i) {
+       if (ctx == NULL || i < 1 || i > ctx->heap_size) {
+               errno = EINVAL;
+               return (-1);
+       }
+       
+       float_up(ctx, i, ctx->heap[i]);
+
+       return (0);
+}
+
+int
+heap_decreased(heap_context ctx, int i) {
+       if (ctx == NULL || i < 1 || i > ctx->heap_size) {
+               errno = EINVAL;
+               return (-1);
+       }
+       
+       sink_down(ctx, i, ctx->heap[i]);
+
+       return (0);
+}
+
+void *
+heap_element(heap_context ctx, int i) {
+       if (ctx == NULL || i < 1 || i > ctx->heap_size) {
+               errno = EINVAL;
+               return (NULL);
+       }
+
+       return (ctx->heap[i]);
+}
+
+int
+heap_for_each(heap_context ctx, heap_for_each_func action, void *uap) {
+       int i;
+
+       if (ctx == NULL || action == NULL) {
+               errno = EINVAL;
+               return (-1);
+       }
+
+       for (i = 1; i <= ctx->heap_size; i++)
+               (action)(ctx->heap[i], uap);
+       return (0);
+}
diff --git a/lib/bind/isc/heap.mdoc b/lib/bind/isc/heap.mdoc
new file mode 100644 (file)
index 0000000..cd1596a
--- /dev/null
@@ -0,0 +1,368 @@
+.\" $Id: heap.mdoc,v 1.1 2001/03/29 06:31:55 marka Exp $
+.\"
+.\"Copyright (c) 1997,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.
+.\"
+.Dd Jan 1, 1997
+.\"Os OPERATING_SYSTEM [version/release]
+.Os BSD 4
+.Dt HEAP @SYSCALL_EXT@
+.Sh NAME
+.Nm heap_new ,
+.Nm heap_free ,
+.Nm heap_insert ,
+.Nm heap_delete ,
+.Nm heap_increased ,
+.Nm heap_decreased ,
+.Nm heap_element ,
+.Nm heap_for_each 
+.Nd heap implementation of priority queues
+.Sh SYNOPSIS
+.Fd #include \&"heap.h\&"
+.Ft heap_context    
+.Fn heap_new "heap_higher_priority_func higher_priority" \
+"heap_index_func index" "int array_size_increment"
+.Ft int
+.Fn heap_free "heap_context ctx"
+.Ft int
+.Fn heap_insert "heap_context ctx" "void *elt"
+.Ft int
+.Fn heap_delete "heap_context ctx" "int i"
+.Ft int
+.Fn heap_increased "heap_context ctx" "int i"
+.Ft int
+.Fn heap_decreased "heap_context ctx" "int i"
+.Ft void *
+.Fn heap_element "heap_context ctx" "int i"
+.Ft int 
+.Fn heap_for_each "heap_context ctx" "heap_for_each_func action" "void *uap"
+.Sh DESCRIPTION
+These functions implement heap\-based priority queues.  The user defines a
+priority scheme, and provides a function for comparison of the priority
+of heap elements
+.Po see the description of the
+.Ft heap_higher_priority_func
+function pointer, below
+.Pc .
+.Pp
+Each of the functions depends upon the
+.Ft heap_context
+type, which is a pointer to a
+.Ft struct heap_context 
+.Pq see Pa heap.h No for more information .
+.Pp
+The
+.Pa heap.h
+header file also defines the following set of function
+function pointers:
+.Bd -literal -offset indent
+typedef int (*heap_higher_priority_func)(void *, void *);
+typedef void (*heap_index_func)(void *, int);
+typedef void (*heap_for_each_func)(void *, void *);
+.Ed
+.Pp
+These are pointers to user-defined functions.
+The 
+.Ft heap_higher_priority_func
+type is a pointer to a function which compares two
+different heap (queue) elements and returns an
+.Ft int
+which answers the question, "Does the first queue element 
+have a higher priority than the second?"  In other words, 
+a function pointer of this type 
+.Em must 
+return a number greater than zero
+if the element indicated by the first argument is of a higher priority than 
+that indicated by the second element, and zero otherwise.  
+.Pp
+The other two function pointers are documented in the descriptions
+of 
+.Fn heap_new
+.Pq Va heap_index_func
+and
+.Fn heap_for_each
+.Pq Va heap_for_each_func ,
+below.
+.Pp
+The function
+.Fn heap_new
+initializes a 
+.Ft struct heap_context
+and returns a pointer to it.  The
+.Fa higher_priority
+function pointer 
+.Em must 
+be 
+.No non\- Ns Dv NULL .
+As explained above, this refers to a 
+function supplied by the user which compares the priority of two different
+queue or heap elements; see above for more information. 
+The second argument, 
+.Fa index ,
+is a pointer to a user-defined function whose arguments are
+a heap element and its index in the heap.
+.Fa Index 
+is intended to provide the user a means of knowing the internal index
+of an element in the heap while maintaining the opacity of the implementation;
+since the user has to know the actual indexes of heap elements in order to use,
+e.g., 
+.Fn heap_delete
+or
+.Fn heap_element ,
+the user 
+.Fa index
+function could store the index in the heap element, itself.  If 
+.Fa index
+is 
+.No non\- Ns Dv NULL ,
+then it is called 
+.Em whenever 
+the index of an element changes, allowing the user to stay up\-to\-date
+with index changes.
+The last argument, 
+.Fa array_size_increment
+will be used, as its name suggests, by
+.Xr malloc 3
+or
+.Xr realloc 3
+to increment the array which implements the heap; if zero, a default value 
+will be used.
+.Pp
+The
+.Fn heap_free
+function frees the given
+.Ft heap_context
+argument 
+.Pq Fa ctx ,
+which also frees the entire
+.Nm heap ,
+if it is
+.No non\- Ns Dv NULL .
+The argument
+.Fa ctx
+should be
+.No non\- Ns Dv NULL .
+.Pp
+The 
+.Fn heap_insert
+function is used to insert the new heap element
+.Fa elt
+into the appropriate place (priority\-wise) in the
+.Ft heap
+indicated by 
+.Fa ctx
+.Po a pointer to a
+.Ft heap_context
+.Pc .
+If 
+.No non\- Ns Dv NULL ,
+the user-defined
+.Ft higher_priority
+function pointer associated with the indicated 
+.Nm heap
+is used to determine that
+.Dq appropriate place ;
+the highest\-priority elements are at the front of the queue (top of
+the heap).
+(See the description of 
+.Fn heap_new , 
+above, for more information.)
+.Pp
+The function
+.Fn heap_delete
+is used to delete the 
+.Fa i\- Ns th
+element of the queue (heap), and fixing up the queue (heap) from that
+element onward via the priority as determined by the user function
+pointed to by
+.Ft higher_priority 
+function pointer
+.Pq see description of Fn heap_new, No above .
+.Pp
+.Fn heap_increased
+.Pp
+.Fn heap_decreased
+.Pp
+The 
+.Fn heap_element
+function returns the
+.Fa i\- Ns th
+element of the queue/heap indicated by
+.Fa ctx ,
+if possible.
+.Pp
+The
+.Fn heap_for_each
+function provides a mechanism for the user to increment through the entire
+queue (heap) and perform some
+.Fa action 
+upon each of the queue elements.  This
+.Fa action 
+is pointer to a user\-defined function with two arguments, the first of
+which should be interpreted by the user's function as a heap element.  The 
+second value passed to the user function is just the
+.Fa uap
+argument to 
+.Fn heap_for_each ;
+this allows the user to specify additional arguments, if necessary, to
+the function pointed to by 
+.Fa action .
+.\" The following requests should be uncommented and
+.\" used where appropriate.  This next request is
+.\" for sections 2 and 3 function return values only.
+.Sh RETURN VALUES
+.Bl -tag -width "heap_decreased()"
+.It Fn heap_new
+.Dv NULL
+if unable to 
+.Xr malloc 3
+a 
+.Ft struct heap_context
+or if the
+.Fa higher_priority
+function pointer is 
+.Dv NULL;
+otherwise, a valid
+.Ft heap_context 
+.Ns .
+.It Fn heap_free
+-1 if 
+.Fa ctx
+is 
+.Dv NULL 
+(with 
+.Va errno
+set to
+.Dv EINVAL ) ;
+otherwise, 0.
+.It Fn heap_insert
+-1 
+if either
+.Fa ctx
+or 
+.Fa elt
+is 
+.Dv NULL ,
+or if an attempt to 
+.Xr malloc 3
+or 
+.Xr realloc 3
+the heap array fails (with
+.Va errno
+set to 
+.Dv EINVAL
+or 
+.Dv ENOMEM ,
+respectively).
+Otherwise, 0.
+.It Fn heap_delete
+-1 if 
+.Fa ctx
+is 
+.Dv NULL
+or 
+.Fa i 
+is out\-of\-range (with
+.Va errno
+set to
+.Dv EINVAL ) ;
+0 otherwise.
+.It Fn heap_increased
+As for
+.Fn heap_delete .
+.It Fn heap_decreased
+As for
+.Fn heap_delete .
+.It Fn heap_element
+NULL if 
+.Fa ctx 
+is 
+.Dv NULL
+or
+.Fa i
+out\-of-bounds (with
+.Va errno
+set to
+.Dv EINVAL ) ;
+otherwise, a pointer to the
+.Fa i\- Ns th
+queue element.
+.It Fn heap_for_each
+-1 if either
+.Fa ctx
+or 
+.Fa action
+is 
+.Dv NULL
+(with 
+.Va errno
+set to
+.Dv EINVAL ) ;
+0 otherwise.
+.El
+.\" This next request is for sections 1, 6, 7 & 8 only
+.\" .Sh ENVIRONMENT
+.Sh FILES
+.Bl -tag -width "heap.h000"
+.It Pa heap.h
+ heap library header file
+.El
+.\" .Sh EXAMPLES
+.\" This next request is for sections 1, 6, 7 & 8 only
+.\"     (command return values (to shell) and
+.\"    fprintf/stderr type diagnostics)
+.Sh DIAGNOSTICS
+Please refer to
+.Sx RETURN VALUES .
+.\" The next request is for sections 2 and 3 error
+.\" and signal handling only.
+.Sh ERRORS
+The variable
+.Va errno
+is set by
+.Fn heap_free , 
+.Fn heap_insert , 
+.Fn heap_delete , 
+.Fn heap_increased , 
+and
+.Fn heap_decreased 
+under the conditions of invalid input
+.Pq Dv EINVAL
+or lack of memory
+.Pq Dv ENOMEM ;
+please refer to
+.Sx RETURN VALUES .
+.Sh SEE ALSO
+.Xr malloc 3 ,
+.Xr realloc 3 .
+.Pp
+Cormen, Leiserson, and Rivest,  
+.Sy Introduction to Algorithms,
+MIT Press / McGraw Hill, 1990, ISBN 0\-262\-03141\-8, chapter 7.
+.Pp
+Sedgewick, 
+.Sy Algorithms,
+2nd ed'n, Addison\-Wesley, 1988, ISBN 0\-201\-06673\-4, chapter 11.
+.\" .Sh STANDARDS
+.\" .Sh HISTORY
+.Sh AUTHORS
+The
+.Nm heap
+library was implemented by Bob Halley (halley@vix.com) of Vixie Enterprises, 
+Inc., for the Internet Software consortium, and was adapted from
+the two books listed in the 
+.Sx SEE ALSO
+section, above.
+.\" .Sh BUGS
diff --git a/lib/bind/isc/logging.c b/lib/bind/isc/logging.c
new file mode 100644 (file)
index 0000000..468bb58
--- /dev/null
@@ -0,0 +1,702 @@
+/*
+ * 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(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: logging.c,v 1.1 2001/03/29 06:31:55 marka Exp $";
+#endif /* not lint */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <errno.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <isc/assertions.h>
+#include <isc/logging.h>
+#include <isc/memcluster.h>
+#include <isc/misc.h>
+
+#include "port_after.h"
+
+#ifdef VSPRINTF_CHAR
+# define VSPRINTF(x) strlen(vsprintf/**/x)
+#else
+# define VSPRINTF(x) ((size_t)vsprintf x)
+#endif
+
+#include "logging_p.h"
+
+static const int syslog_priority[] = { LOG_DEBUG, LOG_INFO, LOG_NOTICE,
+                                      LOG_WARNING, LOG_ERR, LOG_CRIT };
+
+static const char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+                               "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+static const char *level_text[] = {
+       "info: ", "notice: ", "warning: ", "error: ", "critical: "
+};
+
+static void
+version_rename(log_channel chan) {
+       unsigned int ver;
+       char old_name[PATH_MAX+1];
+       char new_name[PATH_MAX+1];
+       
+       ver = chan->out.file.versions;
+       if (ver < 1)
+               return;
+       if (ver > LOG_MAX_VERSIONS)
+               ver = LOG_MAX_VERSIONS;
+       /*
+        * Need to have room for '.nn' (XXX assumes LOG_MAX_VERSIONS < 100)
+        */
+       if (strlen(chan->out.file.name) > (PATH_MAX-3))
+               return;
+       for (ver--; ver > 0; ver--) {
+               sprintf(old_name, "%s.%d", chan->out.file.name, ver-1);
+               sprintf(new_name, "%s.%d", chan->out.file.name, ver);
+               (void)isc_movefile(old_name, new_name);
+       }
+       sprintf(new_name, "%s.0", chan->out.file.name);
+       (void)isc_movefile(chan->out.file.name, new_name);
+}
+
+FILE *
+log_open_stream(log_channel chan) {
+       FILE *stream;
+       int fd, flags;
+       struct stat sb;
+       int regular;
+
+       if (chan == NULL || chan->type != log_file) {
+               errno = EINVAL;
+               return (NULL);
+       }
+       
+       /*
+        * Don't open already open streams
+        */
+       if (chan->out.file.stream != NULL)
+               return (chan->out.file.stream);
+
+       if (stat(chan->out.file.name, &sb) < 0) {
+               if (errno != ENOENT) {
+                       syslog(LOG_ERR,
+                              "log_open_stream: stat of %s failed: %s",
+                              chan->out.file.name, strerror(errno));
+                       chan->flags |= LOG_CHANNEL_BROKEN;
+                       return (NULL);
+               }
+               regular = 1;
+       } else
+               regular = (sb.st_mode & S_IFREG);
+
+       if (chan->out.file.versions) {
+               if (!regular) {
+                       syslog(LOG_ERR,
+       "log_open_stream: want versions but %s isn't a regular file",
+                              chan->out.file.name);
+                       chan->flags |= LOG_CHANNEL_BROKEN;
+                       errno = EINVAL;
+                       return (NULL);
+               }
+       }
+
+       flags = O_WRONLY|O_CREAT|O_APPEND;
+
+       if ((chan->flags & LOG_TRUNCATE) != 0) {
+               if (regular) {
+                       (void)unlink(chan->out.file.name);
+                       flags |= O_EXCL;
+               } else {
+                       syslog(LOG_ERR,
+       "log_open_stream: want truncation but %s isn't a regular file",
+                              chan->out.file.name);
+                       chan->flags |= LOG_CHANNEL_BROKEN;
+                       errno = EINVAL;
+                       return (NULL);
+               }
+       }
+
+       fd = open(chan->out.file.name, flags,
+                 S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+       if (fd < 0) {
+               syslog(LOG_ERR, "log_open_stream: open(%s) failed: %s",
+                      chan->out.file.name, strerror(errno));
+               chan->flags |= LOG_CHANNEL_BROKEN;
+               return (NULL);
+       }
+       stream = fdopen(fd, "a");
+       if (stream == NULL) {
+               syslog(LOG_ERR, "log_open_stream: fdopen() failed");
+               chan->flags |= LOG_CHANNEL_BROKEN;
+               return (NULL);
+       }
+       (void) fchown(fd, chan->out.file.owner, chan->out.file.group);
+
+       chan->out.file.stream = stream;
+       return (stream);
+}
+
+int
+log_close_stream(log_channel chan) {
+       FILE *stream;
+
+       if (chan == NULL || chan->type != log_file) {
+               errno = EINVAL;
+               return (0);
+       }
+       stream = chan->out.file.stream;
+       chan->out.file.stream = NULL;
+       if (stream != NULL && fclose(stream) == EOF)
+               return (-1);
+       return (0);
+}
+
+FILE *
+log_get_stream(log_channel chan) {
+       if (chan == NULL || chan->type != log_file) {
+               errno = EINVAL;
+               return (NULL);
+       }
+       return (chan->out.file.stream);
+}
+
+char *
+log_get_filename(log_channel chan) {
+       if (chan == NULL || chan->type != log_file) {
+               errno = EINVAL;
+               return (NULL);
+       }
+       return (chan->out.file.name);
+}
+
+int
+log_check_channel(log_context lc, int level, log_channel chan) {
+       int debugging, chan_level;
+
+       REQUIRE(lc != NULL);
+
+       debugging = ((lc->flags & LOG_OPTION_DEBUG) != 0);
+
+       /*
+        * If not debugging, short circuit debugging messages very early.
+        */
+       if (level > 0 && !debugging)
+               return (0);
+
+       if ((chan->flags & (LOG_CHANNEL_BROKEN|LOG_CHANNEL_OFF)) != 0)
+               return (0);
+
+       /* Some channels only log when debugging is on. */
+       if ((chan->flags & LOG_REQUIRE_DEBUG) && !debugging)
+               return (0);
+
+       /* Some channels use the global level. */
+       if ((chan->flags & LOG_USE_CONTEXT_LEVEL) != 0) {
+               chan_level = lc->level;
+       } else
+               chan_level = chan->level;
+
+       if (level > chan_level)
+               return (0);
+
+       return (1);
+}
+
+int 
+log_check(log_context lc, int category, int level) {
+       log_channel_list lcl;
+       int debugging;
+
+       REQUIRE(lc != NULL);
+
+       debugging = ((lc->flags & LOG_OPTION_DEBUG) != 0);
+
+       /*
+        * If not debugging, short circuit debugging messages very early.
+        */
+       if (level > 0 && !debugging)
+               return (0);
+
+       if (category < 0 || category > lc->num_categories)
+               category = 0;           /* use default */
+       lcl = lc->categories[category];
+       if (lcl == NULL) {
+               category = 0;
+               lcl = lc->categories[0];
+       }
+
+       for ( /* nothing */; lcl != NULL; lcl = lcl->next) {
+               if (log_check_channel(lc, level, lcl->channel))
+                       return (1);
+       }
+       return (0);
+}
+
+void
+log_vwrite(log_context lc, int category, int level, const char *format, 
+          va_list args) {
+       log_channel_list lcl;
+       int pri, debugging, did_vsprintf = 0;
+       int original_category;
+       FILE *stream;
+       log_channel chan;
+       struct timeval tv;
+       struct tm *local_tm;
+       const char *category_name;
+       const char *level_str;
+       char time_buf[256];
+       char level_buf[256];
+
+       REQUIRE(lc != NULL);
+
+       debugging = (lc->flags & LOG_OPTION_DEBUG);
+
+       /*
+        * If not debugging, short circuit debugging messages very early.
+        */
+       if (level > 0 && !debugging)
+               return;
+
+       if (category < 0 || category > lc->num_categories)
+               category = 0;           /* use default */
+       original_category = category;
+       lcl = lc->categories[category];
+       if (lcl == NULL) {
+               category = 0;
+               lcl = lc->categories[0];
+       }
+
+       /*
+        * Get the current time and format it.
+        */
+       time_buf[0]='\0';
+       if (gettimeofday(&tv, NULL) < 0) {
+               syslog(LOG_INFO, "gettimeofday failed in log_vwrite()");
+       } else {
+#ifdef HAVE_TIME_R
+               localtime_r((time_t *)&tv.tv_sec, &local_tm);
+#else
+               local_tm = localtime((time_t *)&tv.tv_sec);
+#endif
+               if (local_tm != NULL) {
+                       sprintf(time_buf, "%02d-%s-%4d %02d:%02d:%02d.%03ld ",
+                               local_tm->tm_mday, months[local_tm->tm_mon],
+                               local_tm->tm_year+1900, local_tm->tm_hour,
+                               local_tm->tm_min, local_tm->tm_sec,
+                               (long)tv.tv_usec/1000);
+               }
+       }
+
+       /*
+        * Make a string representation of the current category and level
+        */
+
+       if (lc->category_names != NULL &&
+           lc->category_names[original_category] != NULL)
+               category_name = lc->category_names[original_category];
+       else
+               category_name = "";
+
+       if (level >= log_critical) {
+               if (level >= 0) {
+                       sprintf(level_buf, "debug %d: ", level);
+                       level_str = level_buf;
+               } else
+                       level_str = level_text[-level-1];
+       } else {
+               sprintf(level_buf, "level %d: ", level);
+               level_str = level_buf;
+       }
+
+       /*
+        * Write the message to channels.
+        */
+       for ( /* nothing */; lcl != NULL; lcl = lcl->next) {
+               chan = lcl->channel;
+
+               if (!log_check_channel(lc, level, chan))
+                       continue;
+
+               if (!did_vsprintf) {
+                       if (VSPRINTF((lc->buffer, format, args)) >
+                           LOG_BUFFER_SIZE) {
+                               syslog(LOG_CRIT,
+                                      "memory overrun in log_vwrite()");
+                               exit(1);
+                       }
+                       did_vsprintf = 1;
+               }
+
+               switch (chan->type) {
+               case log_syslog:
+                       if (level >= log_critical)
+                               pri = (level >= 0) ? 0 : -level;
+                       else
+                               pri = -log_critical;
+                       syslog(chan->out.facility|syslog_priority[pri],
+                              "%s%s%s%s",
+                              (chan->flags & LOG_TIMESTAMP) ?  time_buf : "",
+                              (chan->flags & LOG_PRINT_CATEGORY) ?
+                              category_name : "",
+                              (chan->flags & LOG_PRINT_LEVEL) ?
+                              level_str : "",
+                              lc->buffer);
+                       break;
+               case log_file:
+                       stream = chan->out.file.stream;
+                       if (stream == NULL) {
+                               stream = log_open_stream(chan);
+                               if (stream == NULL)
+                                       break;
+                       }
+                       if (chan->out.file.max_size != ULONG_MAX) {
+                               long pos;
+                               
+                               pos = ftell(stream);
+                               if (pos >= 0 &&
+                                   (unsigned long)pos >
+                                   chan->out.file.max_size) {
+                                       /*
+                                        * try to roll over the log files,
+                                        * ignoring all all return codes
+                                        * except the open (we don't want
+                                        * to write any more anyway)
+                                        */
+                                       log_close_stream(chan);
+                                       version_rename(chan);
+                                       stream = log_open_stream(chan);
+                                       if (stream == NULL)
+                                               break;
+                               }
+                       }
+                       fprintf(stream, "%s%s%s%s\n", 
+                               (chan->flags & LOG_TIMESTAMP) ? time_buf : "",
+                               (chan->flags & LOG_PRINT_CATEGORY) ?
+                               category_name : "",
+                               (chan->flags & LOG_PRINT_LEVEL) ?
+                               level_str : "",
+                               lc->buffer);
+                       fflush(stream);
+                       break;
+               case log_null:
+                       break;
+               default:
+                       syslog(LOG_ERR,
+                              "unknown channel type in log_vwrite()");
+               }
+       }
+}
+
+void
+log_write(log_context lc, int category, int level, const char *format, ...) {
+       va_list args;
+
+       va_start(args, format);
+       log_vwrite(lc, category, level, format, args);
+       va_end(args);
+}
+
+/*
+ * Functions to create, set, or destroy contexts
+ */
+
+int
+log_new_context(int num_categories, char **category_names, log_context *lc) {
+       log_context nlc;
+
+       nlc = memget(sizeof (struct log_context));
+       if (nlc == NULL) {
+               errno = ENOMEM;
+               return (-1);
+       }
+       nlc->num_categories = num_categories;
+       nlc->category_names = category_names;
+       nlc->categories = memget(num_categories * sizeof (log_channel_list));
+       if (nlc->categories == NULL) {
+               memput(nlc, sizeof (struct log_context));
+               errno = ENOMEM;
+               return (-1);
+       }
+       memset(nlc->categories, '\0',
+              num_categories * sizeof (log_channel_list));
+       nlc->flags = 0U;
+       nlc->level = 0;
+       *lc = nlc;
+       return (0);
+}
+
+void
+log_free_context(log_context lc) {
+       log_channel_list lcl, lcl_next;
+       log_channel chan;
+       int i;
+
+       REQUIRE(lc != NULL);
+
+       for (i = 0; i < lc->num_categories; i++)
+               for (lcl = lc->categories[i]; lcl != NULL; lcl = lcl_next) {
+                       lcl_next = lcl->next;
+                       chan = lcl->channel;
+                       (void)log_free_channel(chan);
+                       memput(lcl, sizeof (struct log_channel_list));
+               }
+       memput(lc->categories,
+              lc->num_categories * sizeof (log_channel_list));
+       memput(lc, sizeof (struct log_context));
+}
+
+int
+log_add_channel(log_context lc, int category, log_channel chan) {
+       log_channel_list lcl;
+
+       if (lc == NULL || category < 0 || category >= lc->num_categories) {
+               errno = EINVAL;
+               return (-1);
+       }
+
+       lcl = memget(sizeof (struct log_channel_list));
+       if (lcl == NULL) {
+               errno = ENOMEM;
+               return(-1);
+       }
+       lcl->channel = chan;
+       lcl->next = lc->categories[category];
+       lc->categories[category] = lcl;
+       chan->references++;
+       return (0);
+}
+
+int
+log_remove_channel(log_context lc, int category, log_channel chan) {
+       log_channel_list lcl, prev_lcl, next_lcl;
+       int found = 0;
+
+       if (lc == NULL || category < 0 || category >= lc->num_categories) {
+               errno = EINVAL;
+               return (-1);
+       }
+
+       for (prev_lcl = NULL, lcl = lc->categories[category];
+            lcl != NULL;
+            lcl = next_lcl) {
+               next_lcl = lcl->next;
+               if (lcl->channel == chan) {
+                       log_free_channel(chan);
+                       if (prev_lcl != NULL)
+                               prev_lcl->next = next_lcl;
+                       else
+                               lc->categories[category] = next_lcl;
+                       memput(lcl, sizeof (struct log_channel_list));
+                       /*
+                        * We just set found instead of returning because
+                        * the channel might be on the list more than once.
+                        */
+                       found = 1;
+               } else
+                       prev_lcl = lcl;
+       }
+       if (!found) {
+               errno = ENOENT;
+               return (-1);
+       }
+       return (0);
+}
+
+int
+log_option(log_context lc, int option, int value) {
+       if (lc == NULL) {
+               errno = EINVAL;
+               return (-1);
+       }
+       switch (option) {
+       case LOG_OPTION_DEBUG:
+               if (value)
+                       lc->flags |= option;
+               else
+                       lc->flags &= ~option;
+               break;
+       case LOG_OPTION_LEVEL:
+               lc->level = value;
+               break;
+       default:
+               errno = EINVAL;
+               return (-1);
+       }
+       return (0);
+}
+
+int
+log_category_is_active(log_context lc, int category) {
+       if (lc == NULL) {
+               errno = EINVAL;
+               return (-1);
+       }
+       if (category >= 0 && category < lc->num_categories &&
+           lc->categories[category] != NULL)
+               return (1);
+       return (0);
+}
+
+log_channel
+log_new_syslog_channel(unsigned int flags, int level, int facility) {
+       log_channel chan;
+
+       chan = memget(sizeof (struct log_channel));
+       if (chan == NULL) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       chan->type = log_syslog;
+       chan->flags = flags;
+       chan->level = level;
+       chan->out.facility = facility;
+       chan->references = 0;
+       return (chan);
+}
+
+log_channel
+log_new_file_channel(unsigned int flags, int level,
+                    char *name, FILE *stream, unsigned int versions,
+                    unsigned long max_size) {
+       log_channel chan;
+
+       chan = memget(sizeof (struct log_channel));
+       if (chan == NULL) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       chan->type = log_file;
+       chan->flags = flags;
+       chan->level = level;
+       if (name != NULL) {
+               size_t len;
+               
+               len = strlen(name);
+               /* 
+                * Quantize length to a multiple of 256.  There's space for the
+                * NUL, since if len is a multiple of 256, the size chosen will
+                * be the next multiple.
+                */
+               chan->out.file.name_size = ((len / 256) + 1) * 256;
+               chan->out.file.name = memget(chan->out.file.name_size);
+               if (chan->out.file.name == NULL) {
+                       memput(chan, sizeof (struct log_channel));
+                       errno = ENOMEM;
+                       return (NULL);
+               }
+               /* This is safe. */
+               strcpy(chan->out.file.name, name);
+       } else {
+               chan->out.file.name_size = 0;
+               chan->out.file.name = NULL;
+       }
+       chan->out.file.stream = stream;
+       chan->out.file.versions = versions;
+       chan->out.file.max_size = max_size;
+       chan->out.file.owner = getuid();
+       chan->out.file.group = getgid();
+       chan->references = 0;
+       return (chan);
+}
+
+int
+log_set_file_owner(log_channel chan, uid_t owner, gid_t group) {
+       if (chan->type != log_file) {
+               errno = EBADF;
+               return (-1);
+       }
+       chan->out.file.owner = owner;
+       chan->out.file.group = group;
+       return (0);
+}
+
+log_channel
+log_new_null_channel() {
+       log_channel chan;
+
+       chan = memget(sizeof (struct log_channel));
+       if (chan == NULL) {
+               errno = ENOMEM;
+               return (NULL);
+       }
+       chan->type = log_null;
+       chan->flags = LOG_CHANNEL_OFF;
+       chan->level = log_info;
+       chan->references = 0;
+       return (chan);
+}
+
+int
+log_inc_references(log_channel chan) {
+       if (chan == NULL) {
+               errno = EINVAL;
+               return (-1);
+       }
+       chan->references++;
+       return (0);
+}
+
+int
+log_dec_references(log_channel chan) {
+       if (chan == NULL || chan->references <= 0) {
+               errno = EINVAL;
+               return (-1);
+       }
+       chan->references--;
+       return (0);
+}
+
+log_channel_type
+log_get_channel_type(log_channel chan) {
+       REQUIRE(chan != NULL);
+       
+       return (chan->type);
+}
+
+int
+log_free_channel(log_channel chan) {
+       if (chan == NULL || chan->references <= 0) {
+               errno = EINVAL;
+               return (-1);
+       }
+       chan->references--;
+       if (chan->references == 0) {
+               if (chan->type == log_file) {
+                       if ((chan->flags & LOG_CLOSE_STREAM) &&
+                           chan->out.file.stream != NULL)
+                               (void)fclose(chan->out.file.stream);
+                       if (chan->out.file.name != NULL)
+                               memput(chan->out.file.name,
+                                      chan->out.file.name_size);
+               }
+               memput(chan, sizeof (struct log_channel));
+       }
+       return (0);
+}
diff --git a/lib/bind/isc/logging.mdoc b/lib/bind/isc/logging.mdoc
new file mode 100644 (file)
index 0000000..0b7dae1
--- /dev/null
@@ -0,0 +1,1052 @@
+.\" $Id: logging.mdoc,v 1.1 2001/03/29 06:31:55 marka Exp $
+.\"
+.\"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.
+.\"
+.\" The following six UNCOMMENTED lines are required.
+.Dd January 1, 1996
+.\"Os OPERATING_SYSTEM [version/release]
+.Os BSD 4
+.\"Dt DOCUMENT_TITLE [section number] [volume]
+.Dt LOGGING @SYSCALL_EXT@
+.Sh NAME
+.Nm log_open_stream ,
+.Nm log_close_stream ,
+.Nm log_get_stream ,
+.Nm log_get_filename ,
+.Nm log_vwrite ,
+.Nm log_write ,
+.Nm log_new_context ,
+.Nm log_free_context ,
+.Nm log_add_channel ,
+.Nm log_remove_channel ,
+.Nm log_option ,
+.Nm log_category_is_active ,
+.Nm log_new_syslog_channel ,
+.Nm log_new_file_channel ,
+.Nm log_set_file_owner ,
+.Nm log_new_null_channel ,
+.Nm log_inc_references ,
+.Nm log_dec_references ,
+.Nm log_free_channel
+.Nd logging system
+.Sh SYNOPSIS
+.Fd #include <isc/logging.h>
+.Ft FILE *
+.Fn log_open_stream "log_channel chan"
+.Ft int
+.Fn log_close_stream "log_channel chan"
+.Ft FILE * 
+.Fn log_get_stream "log_channel chan"
+.Ft char * 
+.Fn log_get_filename "log_channel chan"
+.Ft void 
+.Fn log_vwrite "log_context lc" "int category" "int level" \
+    "const char *format" va_list args"
+.Ft void 
+.Fn log_write "log_context lc" "int category" "int level" \
+    "const char *format" "..."
+.Ft int
+.Fn log_check_channel "log_context lc" "int level" "log_channel chan"
+.Ft int
+.Fn log_check "log_context lc" "int category" "int level"
+.Ft int 
+.Fn log_new_context "int num_categories" "char **category_names" \
+    "log_context *lc"
+.Ft void 
+.Fn log_free_context "log_context lc"
+.Ft int 
+.Fn log_add_channel "log_context lc" "int category" "log_channel chan"
+.Ft int 
+.Fn log_remove_channel "log_context lc" "int category" "log_channel chan"
+.Ft int 
+.Fn log_option "log_context lc" "int option" "int value"
+.Ft int 
+.Fn log_category_is_active "log_context lc" "int category"
+.Ft log_channel 
+.Fn log_new_syslog_channel "unsigned int flags" "int level" "int facility"
+.Ft log_channel 
+.Fn log_new_file_channel "unsigned int flags" "int level" \
+    "char *name" "FILE *stream" "unsigned int versions" \
+    "unsigned long max_size"
+.Ft int
+.Fn log_set_file_owner "log_channel chan" "uid_t owner" "gid_t group"
+.Ft log_channel 
+.Fn log_new_null_channel "void"
+.Ft int 
+.Fn log_inc_references "log_channel chan"
+.Ft int 
+.Fn log_dec_references "log_channel chan"
+.Ft int 
+.Fn log_free_channel "log_channel chan"
+.Sh DESCRIPTION
+The
+.Sy ISC
+.Nm logging library
+is flexible logging system which is based upon a set of concepts:
+.Nm logging channels ,
+.Nm categories ,
+and 
+.Nm logging contexts .
+.Pp
+The basic building block is the
+.Dq Nm logging channel , 
+which includes a 
+.Nm priority 
+(logging level), which type of logging is to occur, and other
+flags and information associated with technical aspects of the logging.  
+The set of priorities which are supported is shown below, in the section
+.Sx Message Priorities .
+A priority sets a threshold for message logging; a logging channel will
+.Em only
+log those messages which are 
+.Em at least as important
+as its priority indicates.  (The fact that 
+.Dq more important
+means 
+.Dq more negative ,
+under the current scheme, is an implementation detail; if a channel has
+a priority of
+.Dv log_error ,
+then it will
+.Em not
+log messages with the
+.Dv log_warning
+priority, but it
+.Em will
+log messages with the
+.Dv log_error
+or 
+.Dv log_critical
+priority.)
+.Pp
+The
+.Nm logging channel
+also has an indication of the type of logging performed.  Currently, 
+the supported
+.Nm logging types 
+include (see also 
+.Sx Logging Types ,
+below):
+.Bl -tag -width "log_syslog" -compact -offset indent
+.It Dv log_syslog
+for 
+.Xr syslog 3 Ns -style
+logging
+.It Dv log_file
+for use of a file
+.It Dv log_null
+for 
+.Em no
+logging
+.El
+A new logging channel is created by calling either
+.Fn log_new_syslog_channel ,
+.Fn log_new_file_channel ,
+or
+.Fn log_new_null_channel ,
+respectively.  
+When a channel is no longer to be used, it can be freed using
+.Fn log_free_channel .
+.Pp
+Both 
+.Dv log_syslog
+and
+.Dv log_file
+channel types can include more information; for instance, a
+.Dv log_syslog Ns -type 
+channel allows the specification of a 
+.Xr syslog 3 Ns -style
+.Dq facility , 
+and a
+.Dv log_file Ns -type
+channels allows the caller to set a maximum file size and number
+of versions.  (See 
+.Fn log_new_syslog_channel
+or
+.Fn log_new_file_channel ,
+below.)
+Additionally, once a logging channel of type
+.Dv log_file
+is defined, the functions
+.Fn log_open_stream
+and 
+.Fn log_close_stream
+can open or close the stream associated with the logging channel's logging
+filename.  The
+.Fn log_get_stream
+and
+.Fn log_get_filename
+functions return the stream or filename, respectively, of such a logging 
+channel.  Also unique to logging channels of type
+.Dv log_file
+is the
+.Fn log_set_file_owner
+function, which tells the logging system what user and group ought to own
+newly created files (which is only effective if the caller is privileged.)
+.Pp
+Callers provide
+.Dq Nm categories ,
+determining both the number of such categories and any (optional) names.
+Categories are like array indexes in C; if the caller declares 
+.Dq Va n
+categories, then they are considered to run from 0 to
+.Va n-1 ;
+with this scheme, a category number would be invalid if it were negative or 
+greater than/equal to 
+.Va n .
+Each category can have its own list of 
+.Nm logging channels 
+associated with it; we say that such a channel is 
+.Dq in 
+the particular category.
+.Sy NOTE:
+Individual logging channels can appear in more than one category.
+.Pp
+A
+.Dq Nm logging context
+is the set of all 
+.Nm logging channels 
+associated with the context's
+.Nm categories;
+thus, a particular 
+.Nm category 
+scheme is associated with a particular
+.Nm logging context.
+.Sy NOTE:
+A logging channel may appear in more than one logging context, and in 
+multiple categories within each logging context.
+.Pp
+Use 
+.Fn log_add_channel
+and
+.Fn log_remove_channel
+to add or remove a logging channel to some category in a logging context.
+To see if a given category in a logging context is being used, use the
+Boolean test
+.Fn log_category_is_active .
+.Pp
+A 
+.Nm logging context
+can also have a 
+.Nm priority
+(logging level)
+and various flags associated with the whole context; in order to alter the
+flags or change the priority of a context, use
+.Fn log_option .
+.Ss Message Priorities
+Currently, five 
+.Nm priorities
+(logging levels) are supported (they can also be found in the header file):
+.Bd -literal -offset indent
+#define log_critical            (-5)
+#define log_error               (-4)
+#define log_warning             (-3)
+#define log_notice              (-2)
+#define log_info                (-1)
+.Ed
+.Pp
+In the current implementation, logging messages which have a level greater
+than 0 are considered to be debugging messages.
+.Ss Logging Types
+The three different
+.Nm logging types 
+currently supported are different values of the enumerated type
+.Ft log_output_type 
+(these are also listed in the header file): 
+.Bd -literal -offset indent
+typedef enum { log_syslog, log_file, log_null } log_output_type;
+.Ed
+.Ss Logging Channel Flags 
+There are several flags which can be set on a logging channel; the flags 
+and their meanings are as follows (they are also found in the header file):
+.Bl -tag -width "LOG_USE_CONTEXT_LEVEL  " -offset indent
+.It Dv LOG_CHANNEL_BROKEN
+This is set only when some portion of 
+.Fn log_open_stream
+fails:
+.Xr open 2 
+or
+.Xr fdopen 3  
+fail;
+.Xr stat 2
+fails in a
+.Dq bad
+way; versioning or truncation is requested on a non-normal file.
+.It Dv LOG_CHANNEL_OFF
+This is set for channels opened by 
+.Fn log_new_null_channel .
+.It Dv LOG_CLOSE_STREAM
+If this flag is set, then 
+.Fn log_free_channel
+will free a 
+.No non- Dv NULL
+stream of a logging channel which is being
+.Xr free 3 Ns -d 
+(if the logging channel is of type
+.Dv log_file ,
+of course).
+.It Dv LOG_PRINT_CATEGORY
+If set, 
+.Fn log_vwrite
+will insert the category name, if available, into logging messages which are 
+logged to channels of type
+.Dv log_syslog
+or 
+.Dv log_file .
+.It Dv LOG_PRINT_LEVEL
+If set, 
+.Fn log_vwrite
+will insert a string identifying the message priority level into the 
+information logged to channels of type
+.Dv log_syslog
+or 
+.Dv log_file .
+.It Dv LOG_REQUIRE_DEBUG
+Only log debugging messages (i.e., those with a priority greater than zero).
+.It Dv LOG_TIMESTAMP
+If set, 
+.Fn log_vwrite
+will insert a timestamp into logging messages which are logged to channels of
+type
+.Dv log_syslog
+or 
+.Dv log_file .
+.It Dv LOG_TRUNCATE
+Truncate logging file when re-opened (
+.Fn log_open_stream 
+will
+.Xr unlink 2
+the file and then 
+.Xr open 2
+a new file of the same name with the
+.Dv O_EXCL
+bit set).
+.It Dv LOG_USE_CONTEXT_LEVEL
+Use the logging context's priority or logging level, rather than the logging 
+channel's own priority.  This can be useful for those channels which are 
+included in multiple logging contexts.
+.El
+.Ss FUNCTION DESCRIPTIONS
+The function
+.Fn log_open_stream 
+is for use with channels which log to a file; i.e., logging channels with a
+.Va type 
+field set to
+.Dq Dv log_file .
+If the logging channel pointed to by 
+.Dq Fa chan
+is valid, it attempts to open (and return) the stream associated with that
+channel.  If the stream is already opened, then it is returned; otherwise,
+.Xr stat 2
+is used to test the filename for the stream.
+.Pp
+At this point, if the logging file is supposed to have different
+.Va versions 
+(i.e., incremented version numbers; higher numbers indicate older versions
+of the logging file).  If so, then any existing versions are
+.Xr rename 2 Ns -d
+to have one version-number higher than previously, and the
+.Dq current
+filename for the stream is set to the
+.Dq \&.0
+form of the name.  Next, if the logging file is supposed to be truncated
+(i.e., the
+.Dv LOG_TRUNCATE
+bit of the
+.Va flags
+field of the logging channel structure is set), then any file with the
+.Dq current
+filename for the stream is
+.X4 unlink 2 Ns -d .
+.Sy NOTE:
+If the logging file is 
+.Em not 
+a regular file, and either of the above operations (version numbering
+or truncation) is supposed to take place, a
+.Dv NULL
+file pointer is returned.
+.Pp
+Finally, the filename associated with the logging channel is
+.Xr open 2 Ns -d
+using the appropriate flags and a mode which sets the read/write permissions
+for the user, group, and others.  The file descriptor returned by 
+.Xr open 2
+is then passed to
+.Xr fopen 3 ,
+with the append mode set, and the stream returned by this call is stored
+in the 
+.Fa chan
+structure and returned.
+.Pp
+If 
+.Fn log_open_stream
+fails at any point, then the 
+.Dv LOG_CHANNEL_BROKEN 
+bit of the
+.Va flags 
+field of the logging channel pointed to by
+.Fa chan
+is set, a 
+.Dv NULL
+is returned, and 
+.Va errno
+contains pertinent information.
+.Pp
+The
+.Fn log_close_stream
+function closes the stream associated with the logging channel pointed to by
+.Dq Fa chan 
+(if
+.Fa chan 
+is valid and the stream exists and can be closed properly by
+.Xr fclose 3 ) .  
+The stream is set to 
+.Dv NULL
+even if the call to 
+.Xr fclose 3
+fails.
+.Pp
+The function
+.Fn log_get_stream
+returns the stream associated with the logging channel pointed to by
+.Dq Fa chan ,
+if it is 
+.No non- Ns Dv NULL
+and specifies a logging channel which has a 
+.Dv FILE *
+or stream associated with it.
+.Pp
+The
+.Fn log_get_filename
+function returns the name of the file associated with the logging channel 
+pointed to by
+.Dq Fa chan ,
+if it is 
+.No non- Ns Dv NULL
+and specifies a logging channel which has a file associated with it.
+.Pp
+The
+.Fn log_vwrite 
+function performs the actual logging of a message to the various logging
+channels of a logging context
+.Fa lc .
+The message consists of an
+.Xr fprint 3 Ns -style
+.Fa format 
+and its associated
+.Fa args 
+(if any); it will be written to all logging channels in the given
+.Fa category
+which have a priority set to
+.Fa level
+or any 
+.Em less important
+priority value.  If the
+.Fa category
+is not valid or has no logging channels, then the category defaults to 0.
+.Pp
+There are a number of conditions under which a call to 
+.Fn log_vwrite
+will not result in actually logging the message: if there is no logging channel 
+at even the default category (0), or if a given channel is either 
+.Dq broken
+or
+.Dq off
+(i.e., its flags have 
+.Dv LOG_CHANNEL_BROKEN
+or
+.Dv LOG_CHANNEL_OFF
+set, respectively), or if the logging channel channel is of type
+.Dv log_null .
+Additionally, if the logging channel's flag has
+.Dv LOG_REQUIRE_DEBUG
+set and the message is not a debugging message (i.e., has a level greater
+than 0), then it will not be logged.
+Finally, if the message's priority is less important than the
+channel's logging level (the priority threshold), will not be logged.
+.Sy NOTE:
+If a logging channel's flag has
+.Dv LOG_USE_CONTEXT_LEVEL
+set, it will use the logging context's priority, rather than its own.
+.Pp
+If all of these hurdles are passed, then only
+.Dv log_syslog
+and
+.Dv log_file
+channels actually can have logging.  For channels which use
+.Xr syslog 3 ,
+the channel's 
+.Xr syslog 3
+facility is used in conjunction with a potentially modified form of the
+message's priority level, since 
+.Xr syslog 3
+has its own system of priorities
+.Pq Pa /usr/include/syslog.h . 
+All debug messages (priority >= 0) are mapped to 
+.Xr syslog 3 Ns 's
+.Dv LOG_DEBUG
+priority, all messages 
+.Dq more important
+than
+.Dv log_critical
+are mapped to
+.Dv LOG_CRIT ,
+and the priorities corresponding to the ones listed in the section
+.Sx Message Priorities
+are given the obvious corresponding 
+.Xr syslog 3
+priority.
+.Pp
+For 
+.Dv log_file
+type logging channels, if the file size is greater than the maximum file 
+size, then no logging occurs.  (The same thing happens if a 
+.Dv NULL
+stream is encountered and
+.Fn log_open_stream
+fails to open the channel's stream.)
+.Pp
+For both logging to normal files and logging via
+.Xr syslog 3 ,
+the value of the flags
+.Dv LOG_TIMESTAMP ,
+.Dv LOG_PRINT_CATEGORY , 
+and
+.Dv LOG_PRINT_LEVEL 
+are used in determining whether or not these items are included in the logged 
+information.
+.Pp
+The 
+.Fn log_write 
+function is merely a front-end to a call to 
+.Fn log_vwrite ;
+see the description of that function, above, for more information.
+.Pp
+.Fn log_check
+and
+.Fn log_check_channel
+are used to see if a contemplated logging call will actually generate any
+output, which is useful when creating a log message involves non-trivial
+work.
+.Fn log_check
+will return non-zero if a call to
+.Fn log_vwrite
+with the given 
+.Fa category
+and
+.Fa level
+would generate output on any channels, and zero otherwise.
+.Fn log_check_channel
+will return non-zero if writing to the
+.Fa chan
+at the given
+.Fa level
+would generate output.
+.Pp
+The function
+.Fn log_new_context 
+creates a new 
+.Nm logging context ,
+and stores this in the
+.Dq Va opaque
+field of the argument
+.Dq Fa lc , 
+and opaque structure used internally.  This new 
+.Nm context 
+will include the
+.Dq Fa num_categories
+and
+.Dq Fa category_names
+which are supplied; the latter can be
+.Dv NULL .
+.Sy NOTE:
+Since 
+.Dq Fa category_names
+is used directly, it 
+.Em must not 
+be freed by the caller, if it is 
+.No non- Ns Dv NULL .
+The initial logging flags and priority are both set to zero.
+.Pp
+The
+.Fn log_free_context 
+function is used to free the opaque structure 
+.Dq Va lc.opaque
+and its components.
+.Sy NOTE:
+The
+.Dq Va opaque
+field of 
+.Dq Fa lc
+.Em must 
+be
+.No non- Ns Dv NULL .
+For each of the various
+.Dq categories
+(indicated by the
+.Dq Va num_categories
+which were in the corresponding call to
+.Fn log_new_context ) 
+associated with the given 
+.Nm logging context ,
+.Em all 
+of the 
+.Nm logging channels
+are 
+.Xr free 3 Ns -d .
+The opaque structure itself is then
+.Xr free 3 Ns -d ,
+and 
+.Dq Va lc.opaque
+is set to
+.Dv NULL .
+.Pp
+.Sy NOTE:
+The function 
+.Fn log_free_context 
+does
+.Em not
+free the memory associated with 
+.Fa category_names ,
+since the logging library did not allocate the memory for it, originally;
+it was supplied in the call to
+.Fn log_new_context .
+.Pp
+The function
+.Fn log_add_channel 
+adds the 
+.Nm logging channel
+.Dq Fa chan
+to the list of logging channels in the given 
+.Fa category
+of the 
+.Nm logging context
+.Dq Fa lc .
+No checking is performed to see whether or not
+.Fa chan
+is already present in the given
+.Fa category ,
+so multiple instances in a single 
+.Fa category 
+can occur (but see
+.Fn log_remove_channel ,
+below).
+.Pp
+The
+.Fn log_remove_channel 
+function
+removes 
+.Em all
+occurrences of the
+.Nm logging channel
+.Dq Fa chan
+from the list of logging channels in the given 
+.Fa category
+of the 
+.Nm logging context
+.Dq Fa lc .
+It also attempts to free the channel by calling
+.Fn log_free_channel 
+(see its description, below).
+.Pp
+The
+.Fn log_option 
+function is used to change the
+.Fa option 
+of the indicated logging context
+.Fa lc
+to the given
+.Fa value .
+The 
+.Fa option
+can be either
+.Dv LOG_OPTION_LEVEL
+or
+.Dv LOG_OPTION_DEBUG ;
+in the first case, the log context's debugging level is reset to the
+indicated level.  If the
+.Fa option 
+is 
+.Dv LOG_OPTION_DEBUG , 
+then a non-zero
+.Fa value
+results in setting the debug flag of the logging context, while a zero
+.Fa value
+means that the debug flag is reset.
+.Pp
+The
+.Fn log_category_is_active 
+test returns a 1 if the given
+.Fa category
+of the indicated logging context
+.Fa lc
+has at least one logging channel, and 0, otherwise.
+.Pp
+The functions
+.Fn log_new_syslog_channel ,
+.Fn log_new_file_channel ,
+and 
+.Fn log_new_null_channel
+create a new channel of the type specified (thus, the difference in arguments);
+the 
+.Dq Va type
+field of the new
+.Dq Ft struct log_channel
+is always set to the appropriate value.
+.Pp
+The 
+.Fn log_new_syslog_channel
+function 
+.Xr malloc 3 Ns -s
+a new
+.Ft struct log_channel
+of
+.Va type
+.Dv log_syslog ,
+i.e., a logging channel which will use
+.Xr syslog 3 .
+The new structure is filled out with the 
+.Dq Fa flags ,
+.Dq Fa level , 
+and 
+.Dq Fa facility 
+which are given; the 
+.Va references
+field is initialized to zero.
+See 
+.Sx Logging Channel Flags
+and
+.Sx Message Priorities ,
+above, or the header file for information about acceptable values for
+.Dq Fa flags ,
+and 
+.Dq Fa level .
+The
+.Dq Fa facility .
+can be any valid
+.Xr syslog 3
+facility; see the appropriate system header file or manpage for more 
+information.
+.Pp
+.Ft log_channel 
+.Fn log_new_file_channel "unsigned int flags" "int level" \
+    "char *name" "FILE *stream" "unsigned int versions" \
+    "unsigned long max_size"
+.Pp
+.Fn log_new_null_channel 
+.Pp
+The functions
+.Fn log_inc_references 
+and
+.Fn log_dec_references 
+increment or decrements, respectively, the
+.Va references 
+field of the logging channel pointed to by
+.Dq Fa chan ,
+if it is a valid channel (and if the 
+.Va references
+field is strictly positive, in the case of
+.Fn log_dec_references ) .
+These functions are meant to track changes in the number of different clients
+which refer to the given logging channel.
+.Pp
+The 
+.Fn log_free_channel
+function frees the 
+field of the logging channel pointed to by
+.Dq Fa chan 
+if there are no more outstanding references to it.  If the channel uses a file, 
+the stream is 
+.Xr fclose 3 Ns -d 
+(if the
+.Dv LOG_CLOSE_STREAM
+flag is set), and the filename, if 
+.No non- Ns Dv NULL ,
+is 
+.Xr free 3 Ns -d 
+before 
+.Dq Fa chan
+is 
+.Xr free 3 Ns -d .
+.Pp
+.\" The following requests should be uncommented and
+.\" used where appropriate.  This next request is
+.\" for sections 2 and 3 function return values only.
+.Sh RETURN VALUES
+.\" This next request is for sections 1, 6, 7 & 8 only
+.Bl -tag -width "log_category_is_active()"
+.It Fn log_open_stream
+.Dv NULL 
+is returned under any of several error conditions:
+a) if 
+.Dq Fa chan
+is either
+.Dv NULL
+or a 
+.No non- Ns Dv log_file
+channel
+.Pq Va errno No is set to Dv EINVAL ;
+b) if either versioning or truncation is requested for a non-normal file
+.Pq Va errno No is set to Dv EINVAL ;
+c) if any of
+.Xr stat 2 , 
+.Xr open 2 , 
+or
+.Xr fdopen 3
+fails
+.Po Va errno 
+is set by the call which failed 
+.Pc .
+If some value other than
+.Dv NULL
+is returned, then it is a valid logging stream (either newly-opened or 
+already-open).
+.It Fn log_close_stream
+-1 if the stream associated with
+.Dq Fa chan
+is 
+.No non- Ns Dv NULL
+and the call to
+.Xr fclose 3
+fails.
+0 if successful or the logging channel pointed to by
+.Dq Fa chan
+is invalid (i.e.,
+.Dv NULL
+or not a logging channel which has uses a file); in the latter case, 
+.Va errno
+is set to 
+.Dv EINVAL .  
+.It Fn log_get_stream
+.Dv NULL 
+under the same conditions as those under which
+.Fn log_close_stream ,
+above, returns 0 (including the setting of 
+.Va errno ) .
+Otherwise, the stream associated with the logging channel is returned.
+.It Fn log_get_filename
+.Dv NULL 
+under the same conditions as those under which
+.Fn log_close_stream ,
+above, returns 0 (including the setting of 
+.Va errno ) .
+Otherwise, the name of the file associated with the logging channel is 
+returned.
+.It Fn log_new_context
+-1 if 
+.Xr malloc 3
+fails
+.Pq with Va errno No set to Dv ENOMEM .
+Otherwise, 0, with 
+.Dq Va lc->opaque
+containing the new structures and information.
+.It Fn log_add_channel
+-1 if
+a) either
+.Dq Va lc.opaque
+is
+.Dv NULL 
+or 
+.Fa category
+is invalid (negative or greater than or equal to 
+.Va lcp->num_categories ), with
+.Va errno 
+set to 
+.Dv EINVAL ;
+b) 
+.Xr malloc 3
+fails
+.Pq with Va errno No set to Dv ENOMEM .
+Otherwise, 0.
+.It Fn log_remove_channel
+-1 if
+a) either
+.Dq Va lc.opaque
+is 
+.Dv NULL
+or 
+.Fa category
+is invalid, as under failure condition a) for
+.Fn log_add_channel ,
+above, including the setting of
+.Va errno ;
+b) no channel numbered
+.Fa chan
+is found in the logging context indicated by
+.Fa lc 
+.Pq with Va errno No set to Dv ENOENT .
+Otherwise, 0.
+.It Fn log_option
+-1 if
+a) 
+.Dq Va lc.opaque
+is
+.Dv NULL , 
+b)
+.Fa option
+specifies an unknown logging option ;
+in either case, 
+.Va errno 
+is set to 
+.Dv EINVAL .
+Otherwise, 0.
+.It Fn log_category_is_active
+-1 if
+.Dq Va lc.opaque
+is
+.Dv NULL 
+.Pq with Va errno No set to Dv EINVAL ;
+1 if the
+.Fa category
+number is valid and there are logging channels in this 
+.Fa category
+within the indicated logging context; 0 if the
+.Fa category
+number is invalid or there are no logging channels in this
+.Fa category
+within the indicated logging context.
+.It Fn log_new_syslog_channel
+.Dv NULL
+if
+.Xr malloc 3
+fails
+.Pq with Va errno No set to ENOMEM ;
+otherwise, a valid 
+.Dv log_syslog Ns -type
+.Ft log_channel .
+.It Fn log_new_file_channel
+.Dv NULL
+if
+.Xr malloc 3
+fails
+.Pq with Va errno No set to ENOMEM ;
+otherwise, a valid
+.Dv log_file Ns -type
+.Ft log_channel .
+.It Fn log_new_null_channel
+.Dv NULL
+if
+.Xr malloc 3
+fails
+.Pq with Va errno No set to ENOMEM ;
+otherwise, a valid 
+.Dv log_null Ns -type
+.Ft log_channel .
+.It Fn log_inc_references
+-1 if 
+.Dq Fa chan
+is 
+.Dv NULL 
+.Pq with Va errno set to Dv EINVAL .
+Otherwise, 0.
+.It Fn log_dec_references
+-1 if 
+.Dq Fa chan
+is 
+.Dv NULL 
+or its
+.Va references
+field is already <= 0
+.Pq with Va errno set to Dv EINVAL .
+Otherwise, 0.
+.It Fn log_free_channel
+-1 under the same conditions as
+.Fn log_dec_references ,
+above, including the setting of 
+.Va errno ;
+0 otherwise.
+.El
+.\" .Sh ENVIRONMENT
+.Sh FILES
+.Bl -tag -width "isc/logging.h"
+.It Pa isc/logging.h
+include file for logging library
+.It Pa syslog.h
+.Xr syslog 3 Ns -style
+priorities
+.El
+.\" .Sh EXAMPLES
+.\" This next request is for sections 1, 6, 7 & 8 only
+.\"     (command return values (to shell) and
+.\"    fprintf/stderr type diagnostics)
+.\" .Sh DIAGNOSTICS
+.\" The next request is for sections 2 and 3 error
+.\" and signal handling only.
+.Sh ERRORS
+This table shows which functions can return the indicated error in the
+.Va errno
+variable; see the
+.Sx RETURN VALUES
+section, above, for more information.
+.Bl -tag -width "(any0other0value)0"
+.It Dv EINVAL
+.Fn log_open_stream ,
+.Fn log_close_stream ,
+.Fn log_get_stream ,
+.Fn log_get_filename ,
+.Fn log_add_channel ,
+.Fn log_remove_channel ,
+.Fn log_option ,
+.Fn log_category_is_active ,
+.Fn log_inc_references ,
+.Fn log_dec_references ,
+.Fn log_free_channel .
+.It Dv ENOENT
+.Fn log_remove_channel .
+.It Dv ENOMEM
+.Fn log_new_context ,
+.Fn log_add_channel ,
+.Fn log_new_syslog_channel ,
+.Fn log_new_file_channel ,
+.Fn log_new_null_channel .
+.It (any other value)
+returned via a pass-through of an error code from
+.Xr stat 2 , 
+.Xr open 2 , 
+or
+.Xr fdopen 3 ,
+which can occur in 
+.Fn log_open_stream
+and functions which call it
+.Pq currently, only Fn log_vwrite .
+.El
+.Pp
+Additionally, 
+.Fn log_vwrite
+and
+.Fn log_free_context
+will fail via 
+.Fn assert
+if 
+.Dq Va lc.opaque
+is
+.Dv NULL .
+The function
+.Fn log_vwrite
+can also exit with a critical error logged via
+.Xr syslog 3
+indicating a memory overrun
+.Sh SEE ALSO
+.Xr @INDOT@named @SYS_OPS_EXT@ ,
+.Xr syslog 3 .
+The HTML documentation includes a file,
+.Pa logging.html ,
+which has more information about this logging system.
+.\" .Sh STANDARDS
+.\" .Sh HISTORY
+.Sh AUTHORS
+Bob Halley...TODO
+.\" .Sh BUGS
diff --git a/lib/bind/isc/logging_p.h b/lib/bind/isc/logging_p.h
new file mode 100644 (file)
index 0000000..875da0e
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * 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 LOGGING_P_H
+#define LOGGING_P_H
+
+typedef struct log_file_desc {
+       char *name;
+       size_t name_size;
+       FILE *stream;
+       unsigned int versions;
+       unsigned long max_size;
+       uid_t owner;
+       gid_t group;
+} log_file_desc;
+
+typedef union log_output {
+       int facility;
+       log_file_desc file;
+} log_output;
+
+struct log_channel {
+       int level;                      /* don't log messages > level */
+       log_channel_type type;
+       log_output out;
+       unsigned int flags;
+       int references;
+};
+
+typedef struct log_channel_list {
+       log_channel channel;
+       struct log_channel_list *next;
+} *log_channel_list;
+
+#define LOG_BUFFER_SIZE 20480
+
+struct log_context {
+       int num_categories;
+       char **category_names;
+       log_channel_list *categories;
+       int flags;
+       int level;
+       char buffer[LOG_BUFFER_SIZE];
+};
+
+#endif /* !LOGGING_P_H */
diff --git a/lib/bind/isc/memcluster.c b/lib/bind/isc/memcluster.c
new file mode 100644 (file)
index 0000000..323a384
--- /dev/null
@@ -0,0 +1,532 @@
+/*
+ * Copyright (c) 1997,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.
+ */
+
+
+/* When this symbol is defined allocations via memget are made slightly 
+   bigger and some debugging info stuck before and after the region given 
+   back to the caller. */
+/* #define DEBUGGING_MEMCLUSTER */
+#define MEMCLUSTER_ATEND
+
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: memcluster.c,v 1.1 2001/03/29 06:31:55 marka Exp $";
+#endif /* not lint */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <isc/memcluster.h>
+#include <isc/assertions.h>
+
+#include "port_after.h"
+
+#ifdef MEMCLUSTER_RECORD
+#ifndef DEBUGGING_MEMCLUSTER
+#define DEBUGGING_MEMCLUSTER
+#endif
+#endif
+
+#define DEF_MAX_SIZE           1100
+#define DEF_MEM_TARGET         4096
+
+typedef u_int32_t fence_t;
+
+typedef struct {
+       void *                  next;
+#if defined(DEBUGGING_MEMCLUSTER)
+#if defined(MEMCLUSTER_RECORD)
+       const char *            file;
+       int                     line;
+#endif
+       int                     size;
+       fence_t                 fencepost;
+#endif
+} memcluster_element;
+
+#define SMALL_SIZE_LIMIT sizeof(memcluster_element)
+#define P_SIZE sizeof(void *)
+#define FRONT_FENCEPOST 0xfebafeba
+#define BACK_FENCEPOST 0xabefabef
+#define FENCEPOST_SIZE 4
+
+#ifndef MEMCLUSTER_LITTLE_MALLOC
+#define MEMCLUSTER_BIG_MALLOC 1
+#define NUM_BASIC_BLOCKS 64
+#endif
+
+struct stats {
+       u_long                  gets;
+       u_long                  totalgets;
+       u_long                  blocks;
+       u_long                  freefrags;
+};
+
+/* Private data. */
+
+static size_t                  max_size;
+static size_t                  mem_target;
+static size_t                  mem_target_half;
+static size_t                  mem_target_fudge;
+static memcluster_element **   freelists;
+#ifdef MEMCLUSTER_RECORD
+static memcluster_element **   activelists;
+#endif
+#ifdef MEMCLUSTER_BIG_MALLOC
+static memcluster_element *    basic_blocks;
+#endif
+static struct stats *          stats;
+
+/* Forward. */
+
+static size_t                  quantize(size_t);
+#if defined(DEBUGGING_MEMCLUSTER)
+static void                    check(unsigned char *, int, size_t);
+#endif
+
+/* Public. */
+
+int
+meminit(size_t init_max_size, size_t target_size) {
+
+#if defined(DEBUGGING_MEMCLUSTER)
+       INSIST(sizeof(fence_t) == FENCEPOST_SIZE);
+#endif
+       if (freelists != NULL) {
+               errno = EEXIST;
+               return (-1);
+       }
+       if (init_max_size == 0)
+               max_size = DEF_MAX_SIZE;
+       else
+               max_size = init_max_size;
+       if (target_size == 0)
+               mem_target = DEF_MEM_TARGET;
+       else
+               mem_target = target_size;
+       mem_target_half = mem_target / 2;
+       mem_target_fudge = mem_target + mem_target / 4;
+       freelists = malloc(max_size * sizeof (memcluster_element *));
+       stats = malloc((max_size+1) * sizeof (struct stats));
+       if (freelists == NULL || stats == NULL) {
+               errno = ENOMEM;
+               return (-1);
+       }
+       memset(freelists, 0,
+              max_size * sizeof (memcluster_element *));
+       memset(stats, 0, (max_size + 1) * sizeof (struct stats));
+#ifdef MEMCLUSTER_RECORD
+       activelists = malloc((max_size + 1) * sizeof (memcluster_element *));
+       if (activelists == NULL) {
+               errno = ENOMEM;
+               return (-1);
+       }
+       memset(activelists, 0,
+              (max_size + 1) * sizeof (memcluster_element *));
+#endif
+#ifdef MEMCLUSTER_BIG_MALLOC
+       basic_blocks = NULL;
+#endif
+       return (0);
+}
+
+void *
+__memget(size_t size) {
+       return (__memget_record(size, NULL, 0));
+}
+
+void *
+__memget_record(size_t size, const char *file, int line) {
+       size_t new_size = quantize(size);
+#if defined(DEBUGGING_MEMCLUSTER)
+       memcluster_element *e;
+       char *p;
+       fence_t fp = BACK_FENCEPOST;
+#endif
+       void *ret;
+
+#if !defined(MEMCLUSTER_RECORD)
+       UNUSED(file);
+       UNUSED(line);
+#endif
+       if (freelists == NULL)
+               if (meminit(0, 0) == -1)
+                       return (NULL);
+       if (size == 0) {
+               errno = EINVAL;
+               return (NULL);
+       }
+       if (size >= max_size || new_size >= max_size) {
+               /* memget() was called on something beyond our upper limit. */
+               stats[max_size].gets++;
+               stats[max_size].totalgets++;
+#if defined(DEBUGGING_MEMCLUSTER)
+               e = malloc(new_size);
+               if (e == NULL) {
+                       errno = ENOMEM;
+                       return (NULL);
+               }
+               e->next = NULL;
+               e->size = size;
+#ifdef MEMCLUSTER_RECORD
+               e->file = file;
+               e->line = line;
+               e->next = activelists[max_size];
+               activelists[max_size] = e;
+#endif
+               e->fencepost = FRONT_FENCEPOST;
+               p = (char *)e + sizeof *e + size;
+               memcpy(p, &fp, sizeof fp);
+               return ((char *)e + sizeof *e);
+#else
+               return (malloc(size));
+#endif
+       }
+
+       /* 
+        * If there are no blocks in the free list for this size, get a chunk
+        * of memory and then break it up into "new_size"-sized blocks, adding
+        * them to the free list.
+        */
+       if (freelists[new_size] == NULL) {
+               int i, frags;
+               size_t total_size;
+               void *new;
+               char *curr, *next;
+
+#ifdef MEMCLUSTER_BIG_MALLOC
+               if (basic_blocks == NULL) {
+                       new = malloc(NUM_BASIC_BLOCKS * mem_target);
+                       if (new == NULL) {
+                               errno = ENOMEM;
+                               return (NULL);
+                       }
+                       curr = new;
+                       next = curr + mem_target;
+                       for (i = 0; i < (NUM_BASIC_BLOCKS - 1); i++) {
+                               ((memcluster_element *)curr)->next = next;
+                               curr = next;
+                               next += mem_target;
+                       }
+                       /*
+                        * curr is now pointing at the last block in the
+                        * array.
+                        */
+                       ((memcluster_element *)curr)->next = NULL;
+                       basic_blocks = new;
+               }
+               total_size = mem_target;
+               new = basic_blocks;
+               basic_blocks = basic_blocks->next;
+#else
+               if (new_size > mem_target_half)
+                       total_size = mem_target_fudge;
+               else
+                       total_size = mem_target;
+               new = malloc(total_size);
+               if (new == NULL) {
+                       errno = ENOMEM;
+                       return (NULL);
+               }
+#endif
+               frags = total_size / new_size;
+               stats[new_size].blocks++;
+               stats[new_size].freefrags += frags;
+               /* Set up a linked-list of blocks of size "new_size". */
+               curr = new;
+               next = curr + new_size;
+               for (i = 0; i < (frags - 1); i++) {
+#if defined (DEBUGGING_MEMCLUSTER)
+                       memset(curr, 0xa5, new_size);
+#endif
+                       ((memcluster_element *)curr)->next = next;
+                       curr = next;
+                       next += new_size;
+               }
+               /* curr is now pointing at the last block in the array. */
+#if defined (DEBUGGING_MEMCLUSTER)
+               memset(curr, 0xa5, new_size);
+#endif
+               ((memcluster_element *)curr)->next = freelists[new_size];
+               freelists[new_size] = new;
+       }
+
+       /* The free list uses the "rounded-up" size "new_size". */
+#if defined (DEBUGGING_MEMCLUSTER)
+       e = freelists[new_size];
+       ret = (char *)e + sizeof *e;
+       /*
+        * Check to see if this buffer has been written to while on free list.
+        */
+       check(ret, 0xa5, new_size - sizeof *e);
+       /*
+        * Mark memory we are returning.
+        */
+       memset(ret, 0xe5, size);
+#else
+       ret = freelists[new_size];
+#endif
+       freelists[new_size] = freelists[new_size]->next;
+#if defined(DEBUGGING_MEMCLUSTER)
+       e->next = NULL;
+       e->size = size;
+       e->fencepost = FRONT_FENCEPOST;
+#ifdef MEMCLUSTER_RECORD
+       e->file = file;
+       e->line = line;
+       e->next = activelists[size];
+       activelists[size] = e;
+#endif
+       p = (char *)e + sizeof *e + size;
+       memcpy(p, &fp, sizeof fp);
+#endif
+
+       /* 
+        * The stats[] uses the _actual_ "size" requested by the
+        * caller, with the caveat (in the code above) that "size" >= the
+        * max. size (max_size) ends up getting recorded as a call to
+        * max_size.
+        */
+       stats[size].gets++;
+       stats[size].totalgets++;
+       stats[new_size].freefrags--;
+#if defined(DEBUGGING_MEMCLUSTER)
+       return ((char *)e + sizeof *e);
+#else
+       return (ret);
+#endif
+}
+
+/* 
+ * This is a call from an external caller, 
+ * so we want to count this as a user "put". 
+ */
+void
+__memput(void *mem, size_t size) {
+       __memput_record(mem, size, NULL, 0);
+}
+
+void
+__memput_record(void *mem, size_t size, const char *file, int line) {
+       size_t new_size = quantize(size);
+#if defined (DEBUGGING_MEMCLUSTER)
+       memcluster_element *e;
+#ifdef MEMCLUSTER_RECORD
+       memcluster_element *prev, *el;
+#endif
+       int fp;
+       char *p;
+#endif
+
+#if !defined (MEMCLUSTER_RECORD)
+       UNUSED(file);
+       UNUSED(line);
+#endif
+
+       REQUIRE(freelists != NULL);
+
+       if (size == 0) {
+               errno = EINVAL;
+               return;
+       }
+
+#if defined (DEBUGGING_MEMCLUSTER)
+       e = (memcluster_element *) ((char *)mem - sizeof *e);
+       INSIST(e->fencepost == FRONT_FENCEPOST);
+       INSIST(e->size == size);
+       p = (char *)e + sizeof *e + size;
+       memcpy(&fp, p, sizeof fp);
+       INSIST(fp == BACK_FENCEPOST);
+       INSIST(((int)mem % 4) == 0);
+#ifdef MEMCLUSTER_RECORD
+       prev = NULL;
+       if (size == max_size || new_size >= max_size)
+               el = activelists[max_size];
+       else
+               el = activelists[size];
+       while (el != NULL && el != e) {
+               prev = el;
+               el = el->next;
+       }
+       INSIST(el != NULL);     /* double free */
+       if (prev == NULL) {
+               if (size == max_size || new_size >= max_size)
+                       activelists[max_size] = el->next;
+               else
+                       activelists[size] = el->next;
+       } else
+               prev->next = el->next;
+#endif
+#endif
+
+       if (size == max_size || new_size >= max_size) {
+               /* memput() called on something beyond our upper limit */
+#if defined(DEBUGGING_MEMCLUSTER)
+               free(e);
+#else
+               free(mem);
+#endif
+
+               INSIST(stats[max_size].gets != 0);
+               stats[max_size].gets--;
+               return;
+       }
+
+       /* The free list uses the "rounded-up" size "new_size": */
+#if defined(DEBUGGING_MEMCLUSTER)
+       memset(mem, 0xa5, new_size - sizeof *e); /* catch write after free */
+       e->size = 0;    /* catch double memput() */
+#ifdef MEMCLUSTER_RECORD
+       e->file = file;
+       e->line = line;
+#endif
+#ifdef MEMCLUSTER_ATEND
+       e->next = NULL;
+       el = freelists[new_size];
+       while (el != NULL && el->next != NULL)
+               el = el->next;
+       if (el)
+               el->next = e;
+       else
+               freelists[new_size] = e;
+#else
+       e->next = freelists[new_size];
+       freelists[new_size] = (void *)e;
+#endif
+#else
+       ((memcluster_element *)mem)->next = freelists[new_size];
+       freelists[new_size] = (memcluster_element *)mem;
+#endif
+
+       /* 
+        * The stats[] uses the _actual_ "size" requested by the
+        * caller, with the caveat (in the code above) that "size" >= the
+        * max. size (max_size) ends up getting recorded as a call to
+        * max_size.
+        */
+       INSIST(stats[size].gets != 0);
+       stats[size].gets--;
+       stats[new_size].freefrags++;
+}
+
+void *
+__memget_debug(size_t size, const char *file, int line) {
+       void *ptr;
+       ptr = __memget_record(size, file, line);
+       fprintf(stderr, "%s:%d: memget(%lu) -> %p\n", file, line,
+               (u_long)size, ptr);
+       return (ptr);
+}
+
+void
+__memput_debug(void *ptr, size_t size, const char *file, int line) {
+       fprintf(stderr, "%s:%d: memput(%p, %lu)\n", file, line, ptr,
+               (u_long)size);
+       __memput_record(ptr, size, file, line);
+}
+
+/*
+ * Print the stats[] on the stream "out" with suitable formatting.
+ */
+void
+memstats(FILE *out) {
+       size_t i;
+#ifdef MEMCLUSTER_RECORD
+       memcluster_element *e;
+#endif
+
+       if (freelists == NULL)
+               return;
+       for (i = 1; i <= max_size; i++) {
+               const struct stats *s = &stats[i];
+
+               if (s->totalgets == 0 && s->gets == 0)
+                       continue;
+               fprintf(out, "%s%5d: %11lu gets, %11lu rem",
+                       (i == max_size) ? ">=" : "  ",
+                       i, s->totalgets, s->gets);
+               if (s->blocks != 0)
+                       fprintf(out, " (%lu bl, %lu ff)",
+                               s->blocks, s->freefrags);
+               fputc('\n', out);
+       }
+#ifdef MEMCLUSTER_RECORD
+       fprintf(out, "Active Memory:\n");
+       for (i = 1; i <= max_size; i++) {
+               if ((e = activelists[i]) != NULL)
+                       while (e != NULL) {
+                               fprintf(out, "%s:%d %#p:%d\n",
+                                       e->file != NULL ? e->file :
+                                               "<UNKNOWN>", e->line,
+                                       (char *)e + sizeof *e, e->size);
+                               e = e->next;
+                       }
+       }
+#endif
+}
+
+/* Private. */
+
+/* 
+ * Round up size to a multiple of sizeof(void *).  This guarantees that a
+ * block is at least sizeof void *, and that we won't violate alignment
+ * restrictions, both of which are needed to make lists of blocks.
+ */
+static size_t
+quantize(size_t size) {
+       int remainder;
+       /*
+        * If there is no remainder for the integer division of 
+        *
+        *      (rightsize/P_SIZE)
+        *
+        * then we already have a good size; if not, then we need
+        * to round up the result in order to get a size big
+        * enough to satisfy the request _and_ aligned on P_SIZE boundaries.
+        */
+       remainder = size % P_SIZE;
+       if (remainder != 0)
+               size += P_SIZE - remainder;
+#if defined(DEBUGGING_MEMCLUSTER)
+       return (size + SMALL_SIZE_LIMIT + sizeof (int));
+#else
+       return (size);
+#endif
+}
+
+#if defined(DEBUGGING_MEMCLUSTER)
+static void
+check(unsigned char *a, int value, size_t len) {
+       int i;
+       for (i = 0; i < len; i++)
+               INSIST(a[i] == value);
+}
+#endif
diff --git a/lib/bind/isc/memcluster.mdoc b/lib/bind/isc/memcluster.mdoc
new file mode 100644 (file)
index 0000000..5425650
--- /dev/null
@@ -0,0 +1,375 @@
+.\" $Id: memcluster.mdoc,v 1.1 2001/03/29 06:31:55 marka Exp $
+.\"
+.\"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.
+.\"
+.\" The following six UNCOMMENTED lines are required.
+.Dd Month day, year
+.\"Os OPERATING_SYSTEM [version/release]
+.Os BSD 4
+.\"Dt DOCUMENT_TITLE [section number] [volume]
+.Dt memcluster 3
+.Sh NAME
+.Nm meminit ,
+.Nm memget ,
+.Nm memput ,
+.Nm memstats 
+.Nd memory allocation/deallocation system
+.Sh SYNOPSIS
+.Fd #include \&<isc/memcluster.h\&>
+.Ft void * 
+.Fn memget "size_t size"
+.Ft void 
+.Fn memput "void *mem" "size_t size"
+.Ft void 
+.Fn memstats "FILE *out"
+.Sh DESCRIPTION
+These functions access a memory management system which allows callers to not 
+fragment memory to the extent which can ordinarily occur through many random 
+calls to
+.Xr malloc 3 .
+Instead, 
+.Fn memget
+gets a large contiguous chunk of blocks of the requested 
+.Fa size 
+and parcels out these blocks as requested.  The symmetric call is
+.Fn memput ,
+which callers use to return a piece of memory obtained from
+.Fn memget .
+Statistics about memory usage are returned by
+.Fn memstats , 
+which prints a report on the stream
+.Fa out .
+.Ss INTERNALS
+Internally, linked lists of free memory blocks are stored in an array.
+The size of this array is determined by the value
+.Dv MEM_FREECOUNT ,
+currently set to 1100.  In general, for any requested blocksize
+.Dq Fa size ,
+any free blocks will be stored on the linked list at that index.
+No free lists are managed for blocks greater than or equal to
+.Dv MEM_FREECOUNT
+bytes; instead, calls to
+.Xr malloc 3
+or
+.Xr free 3
+are made, directly.
+.Pp
+Since the blocks are actually stored as linked lists, they must at least
+be large enough to hold a pointer to the next block.  This size, which is
+.Dv SMALL_SIZE_LIMIT ,
+is currently defined as
+.Bd -literal -offset indent
+#define SMALL_SIZE_LIMIT sizeof(struct { void *next; })
+.Ed
+.Pp
+Both 
+.Fn memget
+and
+.Fn memput
+enforce this limit; for example, any call to 
+.Fn memget 
+requesting a block smaller than
+.Dv SMALL_SIZE_LIMIT
+bytes will actually be considered to be of size
+.Dv SMALL_SIZE_LIMIT 
+internally.  (Such a caller request will be logged for 
+.Fn memstats
+purposes using the caller-requested
+.Fa size ;
+see the discussion of
+.Fn memstats ,
+below, for more information.)
+.Pp
+Additionally, the requested
+.Fa size
+will be adjusted so that when a large 
+.Xr malloc 3 Ns No -d
+chunk of memory is broken up into a linked list, the blocks will all fall on
+the correct memory alignment boundaries.  Thus, one can conceptualize a call
+which mentions
+.Fa size
+as resulting in a
+.Fa new_size
+which is used internally.
+.Pp
+In order to more efficiently allocate memory, there is a 
+.Dq target
+size for calls to 
+.Xr malloc 3 .
+It is given by the pre-defined value
+.Dv MEM_TARGET , 
+which is currently 4096 bytes.
+For any requested block
+.Fa size ,
+enough memory is 
+.Xr malloc 3 Ns No -d
+in order to fill up a block of about
+.Dv MEM_TARGET
+bytes.  
+.No [ Ns Sy NOTE :
+For allocations larger than
+.Dv MEM_TARGET Ns No /2
+bytes, there is a 
+.Dq fudge factor
+introduced which boosts the target size by 25% of
+.Dv MEM_TARGET .
+This means that enough memory for two blocks
+will actually be allocated for any 
+.Fa size
+such that
+.Pq Dv MEM_TARGET Ns No / 3 
+.No < Fa size No < 
+.Pq Dv MEM_TARGET Ns No *5/8 ,
+provided that the value of
+.Dv MEM_FREECOUNT 
+is at least as large as the upper limit shown above.]
+.Pp
+.Ss FUNCTION DESCRIPTIONS
+.Pp
+The function
+.Fn memget
+returns a pointer to a block of memory of at least the requested
+.Fa size .
+After adjusting
+.Fa size
+to the value
+.Va new_size
+as mentioned above in the 
+.Sx INTERNALS
+subsection, the internal array of free lists is checked.
+If there is no block of the needed
+.Va new_size ,
+then
+.Fn memget 
+will 
+.Xr malloc 3
+a chunk of memory which is as many times as 
+.Va new_size
+will fit into the target size.  This memory is then turned into a linked list 
+of 
+.Va new_size Ns No -sized
+blocks which are given out as requested; the last such block is the first one 
+returned by 
+.Fn memget .
+If the requested
+.Fa size
+is zero or negative, then 
+.Dv NULL
+is returned and
+.Va errno
+is set to
+.Dv EINVAL ;
+if 
+.Fa size
+is larger than or equal to the pre-defined maximum size
+.Dv MEM_FREECOUNT ,
+then only a single block of exactly 
+.Fa size
+will be
+.Xr malloc 3 Ns No -d
+and returned.
+.Pp
+The
+.Fn memput
+call is used to return memory once the caller is finished with it.
+After adjusting
+.Fa size
+the the value
+.Va new_size
+as mentioned in the 
+.Sx INTERNALS 
+subsection, above, the block is placed at the head of the free list of 
+.Va new_size Ns No -sized blocks.
+If the given
+.Fa size
+is zero or negative, then 
+.Va errno
+is set to
+.Dv EINVAL ,
+as for
+.Fn memget .
+If 
+.Fa size
+is larger than or equal to the pre-defined maximum size
+.Dv MEM_FREECOUNT ,
+then the block is immediately
+.Xr free 3 Ns No -d .
+.Pp
+.Sy NOTE :
+It is important that callers give 
+.Fn memput
+.Em only
+blocks of memory which were previously obtained from
+.Fn memget 
+if the block is 
+.Em actually 
+less than
+.Dv SMALL_SIZE_LIMIT
+bytes in size.  Since all blocks will be added to a free list, any block 
+which is not at least
+.Dv SMALL_SIZE_LIMIT
+bytes long will not be able to hold a pointer to the next block in the
+free list.
+.Pp
+The
+.Fn memstats
+function will summarize the number of calls to 
+.Fn memget
+and
+.Fn memput
+for any block size from 1 byte up to
+.Pq Dv MEM_FREECOUNT No - 1  
+bytes, followed by a single line for any calls using a 
+.Fa size
+greater than or equal to 
+.Dv MEM_FREECOUNT ; 
+a brief header with shell-style comment lines prefaces the report and
+explains the information.  The 
+.Dv FILE 
+pointer
+.Fa out
+identifies the stream which is used for this report.  Currently, 
+.Fn memstat
+reports the number of calls to 
+.Fn memget
+and
+.Fn memput
+using the caller-supplied value 
+.Fa size ; 
+the percentage of outstanding blocks of a given size (i.e., the percentage
+by which calls to
+.Fn memget
+exceed 
+.Fn memput )
+are also reported on the line for blocks of the given
+.Fa size .
+However, the percent of blocks used is computed using the number of 
+blocks allocated according to the internal parameter
+.Va new_size ;
+it is the percentage of blocks used to those available at a given
+.Va new_size ,
+and is computed using the
+.Em total
+number of caller 
+.Dq gets
+for any caller
+.Fa size Ns No -s
+which map to the internally-computed
+.Va new_size .
+Keep in mind that
+.Va new_size
+is generally 
+.Em not
+equal to
+.Fa size , 
+which has these implications:
+.Bl -enum -offset -indent means that, for 
+.It
+For
+.Fa size
+smaller than
+.Dv SMALL_SIZE_LIMIT ,
+.Fn memstat
+.Em will 
+show statistics for caller requests under
+.Fa size , 
+but "percent used" information about such blocks will be reported under
+.Dv SMALL_SIZE_LIMIT Ns No -sized
+blocks.  
+.It
+As a general case of point 1, internal statistics are reported on the the
+line corresponding to
+.Va new_size ,
+so that, for a given caller-supplied
+.Fa size ,
+the associated internal information will appear on that line or on the next
+line which shows "percent used" information.
+.El
+.Pp
+.Sy NOTE :
+If the caller returns blocks of a given
+.Fa size
+and requests others of 
+.Fa size Ns No -s 
+which map to the same internal
+.Va new_size ,
+it is possible for
+.Fn memstats
+to report usage of greater than 100% for blocks of size
+.Va new_size .
+This should be viewed as A Good Thing.
+.Sh RETURN VALUES
+The function
+.Fn memget
+returns a 
+.No non- Ns Dv NULL
+pointer to a block of memory of the requested
+.Fa size .
+It returns
+.Dv NULL
+if either the
+.Fa size
+is invalid (less than or equal to zero) or a 
+.Xr malloc 3
+of a new block of memory fails.  In the former case, 
+.Va errno
+is set to 
+.Dv EINVAL ; 
+in the latter, it is set to
+.Dv ENOMEM .
+.Pp
+Neither
+.Fn memput
+nor
+.Fn memstats
+return a value.
+.\" This next request is for sections 1, 6, 7 & 8 only
+.\" .Sh ENVIRONMENT
+.\" .Sh FILES
+.\" .Sh EXAMPLES
+.\" This next request is for sections 1, 6, 7 & 8 only
+.\"     (command return values (to shell) and
+.\"    fprintf/stderr type diagnostics)
+.\" .Sh DIAGNOSTICS
+.\" The next request is for sections 2 and 3 error
+.\" and signal handling only.
+.Sh ERRORS
+.Va errno
+is set as follows:
+.Bl -tag -width "ENOMEM  " -offset indent
+.It Dv EINVAL
+set by both
+.Fn memget
+and
+.Fn memput
+if the 
+.Fa size
+is zero or negative
+.It Dv ENOMEM
+set by 
+.Fn memget
+if a call to
+.Xr malloc 3
+fails
+.El
+.Sh SEE ALSO
+.Xr free 3 ,
+.Xr malloc 3 .
+.\" .Sh STANDARDS
+.\" .Sh HISTORY
+.Sh AUTHORS
+Steven J. Richardson and Paul Vixie, Vixie Enterprises.
+.\" .Sh BUGS
diff --git a/lib/bind/isc/movefile.c b/lib/bind/isc/movefile.c
new file mode 100644 (file)
index 0000000..1b64b6c
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2000 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.
+ */
+
+
+#include <port_before.h>
+#include <stdio.h>
+#include <isc/misc.h>
+#include <port_after.h>
+#ifndef HAVE_MOVEFILE
+/*
+ * rename() is lame (can't overwrite an existing file) on some systems.
+ * use movefile() instead, and let lame OS ports do what they need to.
+ */
+
+int
+isc_movefile(const char *oldname, const char *newname) {
+       return (rename(oldname, newname));
+}
+#else
+       static int os_port_has_isc_movefile = 1;
+#endif
diff --git a/lib/bind/isc/tree.c b/lib/bind/isc/tree.c
new file mode 100644 (file)
index 0000000..ea4753d
--- /dev/null
@@ -0,0 +1,532 @@
+#ifndef LINT
+static const char rcsid[] = "$Id: tree.c,v 1.1 2001/03/29 06:31:55 marka Exp $";
+#endif
+
+/*
+ * tree - balanced binary tree library
+ *
+ * vix 05apr94 [removed vixie.h dependencies; cleaned up formatting, names]
+ * vix 22jan93 [revisited; uses RCS, ANSI, POSIX; has bug fixes]
+ * vix 23jun86 [added delete uar to add for replaced nodes]
+ * vix 20jun86 [added tree_delete per wirth a+ds (mod2 v.) p. 224]
+ * vix 06feb86 [added tree_mung()]
+ * vix 02feb86 [added tree balancing from wirth "a+ds=p" p. 220-221]
+ * vix 14dec85 [written]
+ */
+
+/*
+ * This program text was created by Paul Vixie using examples from the book:
+ * "Algorithms & Data Structures," Niklaus Wirth, Prentice-Hall, 1986, ISBN
+ * 0-13-022005-1.  Any errors in the conversion from Modula-2 to C are Paul
+ * Vixie's.
+ */
+
+/*
+ * 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.
+ */
+
+/*#define              DEBUG   "tree"*/
+
+#include "port_before.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "port_after.h"
+
+#include <isc/memcluster.h>
+#include <isc/tree.h>
+
+#ifdef DEBUG
+static int     debugDepth = 0;
+static char    *debugFuncs[256];
+# define ENTER(proc) { \
+                       debugFuncs[debugDepth] = proc; \
+                       fprintf(stderr, "ENTER(%d:%s.%s)\n", \
+                               debugDepth, DEBUG, \
+                               debugFuncs[debugDepth]); \
+                       debugDepth++; \
+               }
+# define RET(value) { \
+                       debugDepth--; \
+                       fprintf(stderr, "RET(%d:%s.%s)\n", \
+                               debugDepth, DEBUG, \
+                               debugFuncs[debugDepth]); \
+                       return (value); \
+               }
+# define RETV { \
+                       debugDepth--; \
+                       fprintf(stderr, "RETV(%d:%s.%s)\n", \
+                               debugDepth, DEBUG, \
+                               debugFuncs[debugDepth]); \
+                       return; \
+               }
+# define MSG(msg)      fprintf(stderr, "MSG(%s)\n", msg);
+#else
+# define ENTER(proc)   ;
+# define RET(value)    return (value);
+# define RETV          return;
+# define MSG(msg)      ;
+#endif
+
+#ifndef TRUE
+# define TRUE          1
+# define FALSE         0
+#endif
+
+static tree *  sprout(tree **, tree_t, int *, int (*)(), void (*)());
+static int     delete(tree **, int (*)(), tree_t, void (*)(), int *, int *);
+static void    del(tree **, int *, tree **, void (*)(), int *);
+static void    bal_L(tree **, int *);
+static void    bal_R(tree **, int *);
+
+void
+tree_init(tree **ppr_tree) {
+       ENTER("tree_init")
+       *ppr_tree = NULL;
+       RETV
+}
+       
+tree_t
+tree_srch(tree **ppr_tree, int (*pfi_compare)(), tree_t        p_user) {
+       ENTER("tree_srch")
+
+       if (*ppr_tree) {
+               int i_comp = (*pfi_compare)(p_user, (**ppr_tree).data);
+
+               if (i_comp > 0)
+                       RET(tree_srch(&(**ppr_tree).right,
+                                     pfi_compare,
+                                     p_user))
+
+               if (i_comp < 0)
+                       RET(tree_srch(&(**ppr_tree).left,
+                                     pfi_compare,
+                                     p_user))
+
+               /* not higher, not lower... this must be the one.
+                */
+               RET((**ppr_tree).data)
+       }
+
+       /* grounded. NOT found.
+        */
+       RET(NULL)
+}
+
+tree_t
+tree_add(tree **ppr_tree, int (*pfi_compare)(),
+        tree_t p_user, void (*pfv_uar)())
+{
+       int i_balance = FALSE;
+
+       ENTER("tree_add")
+       if (!sprout(ppr_tree, p_user, &i_balance, pfi_compare, pfv_uar))
+               RET(NULL)
+       RET(p_user)
+}
+
+int
+tree_delete(tree **ppr_p, int (*pfi_compare)(),
+           tree_t p_user, void (*pfv_uar)())
+{
+       int i_balance = FALSE, i_uar_called = FALSE;
+
+       ENTER("tree_delete");
+       RET(delete(ppr_p, pfi_compare, p_user, pfv_uar,
+                  &i_balance, &i_uar_called))
+}
+
+int
+tree_trav(tree **ppr_tree, int (*pfi_uar)()) {
+       ENTER("tree_trav")
+
+       if (!*ppr_tree)
+               RET(TRUE)
+
+       if (!tree_trav(&(**ppr_tree).left, pfi_uar))
+               RET(FALSE)
+       if (!(*pfi_uar)((**ppr_tree).data))
+               RET(FALSE)
+       if (!tree_trav(&(**ppr_tree).right, pfi_uar))
+               RET(FALSE)
+       RET(TRUE)
+}
+
+void
+tree_mung(tree **ppr_tree, void        (*pfv_uar)()) {
+       ENTER("tree_mung")
+       if (*ppr_tree) {
+               tree_mung(&(**ppr_tree).left, pfv_uar);
+               tree_mung(&(**ppr_tree).right, pfv_uar);
+               if (pfv_uar)
+                       (*pfv_uar)((**ppr_tree).data);
+               memput(*ppr_tree, sizeof(tree));
+               *ppr_tree = NULL;
+       }
+       RETV
+}
+
+static tree *
+sprout(tree **ppr, tree_t p_data, int *pi_balance,
+       int (*pfi_compare)(), void (*pfv_delete)())
+{
+       tree *p1, *p2, *sub;
+       int cmp;
+
+       ENTER("sprout")
+
+       /* are we grounded?  if so, add the node "here" and set the rebalance
+        * flag, then exit.
+        */
+       if (!*ppr) {
+               MSG("grounded. adding new node, setting h=true")
+               *ppr = (tree *) memget(sizeof(tree));
+               if (*ppr) {
+                       (*ppr)->left = NULL;
+                       (*ppr)->right = NULL;
+                       (*ppr)->bal = 0;
+                       (*ppr)->data = p_data;
+                       *pi_balance = TRUE;
+               }
+               RET(*ppr);
+       }
+
+       /* compare the data using routine passed by caller.
+        */
+       cmp = (*pfi_compare)(p_data, (*ppr)->data);
+
+       /* if LESS, prepare to move to the left.
+        */
+       if (cmp < 0) {
+               MSG("LESS. sprouting left.")
+               sub = sprout(&(*ppr)->left, p_data, pi_balance,
+                            pfi_compare, pfv_delete);
+               if (sub && *pi_balance) {       /* left branch has grown */
+                       MSG("LESS: left branch has grown")
+                       switch ((*ppr)->bal) {
+                       case 1:
+                               /* right branch WAS longer; bal is ok now */
+                               MSG("LESS: case 1.. bal restored implicitly")
+                               (*ppr)->bal = 0;
+                               *pi_balance = FALSE;
+                               break;
+                       case 0:
+                               /* balance WAS okay; now left branch longer */
+                               MSG("LESS: case 0.. balnce bad but still ok")
+                               (*ppr)->bal = -1;
+                               break;
+                       case -1:
+                               /* left branch was already too long. rebal */
+                               MSG("LESS: case -1: rebalancing")
+                               p1 = (*ppr)->left;
+                               if (p1->bal == -1) {            /* LL */
+                                       MSG("LESS: single LL")
+                                       (*ppr)->left = p1->right;
+                                       p1->right = *ppr;
+                                       (*ppr)->bal = 0;
+                                       *ppr = p1;
+                               } else {                        /* double LR */
+                                       MSG("LESS: double LR")
+
+                                       p2 = p1->right;
+                                       p1->right = p2->left;
+                                       p2->left = p1;
+
+                                       (*ppr)->left = p2->right;
+                                       p2->right = *ppr;
+
+                                       if (p2->bal == -1)
+                                               (*ppr)->bal = 1;
+                                       else
+                                               (*ppr)->bal = 0;
+
+                                       if (p2->bal == 1)
+                                               p1->bal = -1;
+                                       else
+                                               p1->bal = 0;
+                                       *ppr = p2;
+                               } /*else*/
+                               (*ppr)->bal = 0;
+                               *pi_balance = FALSE;
+                       } /*switch*/
+               } /*if*/
+               RET(sub)
+       } /*if*/
+
+       /* if MORE, prepare to move to the right.
+        */
+       if (cmp > 0) {
+               MSG("MORE: sprouting to the right")
+               sub = sprout(&(*ppr)->right, p_data, pi_balance,
+                            pfi_compare, pfv_delete);
+               if (sub && *pi_balance) {
+                       MSG("MORE: right branch has grown")
+
+                       switch ((*ppr)->bal) {
+                       case -1:
+                               MSG("MORE: balance was off, fixed implicitly")
+                               (*ppr)->bal = 0;
+                               *pi_balance = FALSE;
+                               break;
+                       case 0:
+                               MSG("MORE: balance was okay, now off but ok")
+                               (*ppr)->bal = 1;
+                               break;
+                       case 1:
+                               MSG("MORE: balance was off, need to rebalance")
+                               p1 = (*ppr)->right;
+                               if (p1->bal == 1) {             /* RR */
+                                       MSG("MORE: single RR")
+                                       (*ppr)->right = p1->left;
+                                       p1->left = *ppr;
+                                       (*ppr)->bal = 0;
+                                       *ppr = p1;
+                               } else {                        /* double RL */
+                                       MSG("MORE: double RL")
+
+                                       p2 = p1->left;
+                                       p1->left = p2->right;
+                                       p2->right = p1;
+
+                                       (*ppr)->right = p2->left;
+                                       p2->left = *ppr;
+
+                                       if (p2->bal == 1)
+                                               (*ppr)->bal = -1;
+                                       else
+                                               (*ppr)->bal = 0;
+
+                                       if (p2->bal == -1)
+                                               p1->bal = 1;
+                                       else
+                                               p1->bal = 0;
+
+                                       *ppr = p2;
+                               } /*else*/
+                               (*ppr)->bal = 0;
+                               *pi_balance = FALSE;
+                       } /*switch*/
+               } /*if*/
+               RET(sub)
+       } /*if*/
+
+       /* not less, not more: this is the same key!  replace...
+        */
+       MSG("FOUND: Replacing data value")
+       *pi_balance = FALSE;
+       if (pfv_delete)
+               (*pfv_delete)((*ppr)->data);
+       (*ppr)->data = p_data;
+       RET(*ppr)
+}
+
+static int
+delete(tree **ppr_p, int (*pfi_compare)(), tree_t p_user,
+       void (*pfv_uar)(), int *pi_balance, int *pi_uar_called)
+{
+       tree *pr_q;
+       int i_comp, i_ret;
+
+       ENTER("delete")
+
+       if (*ppr_p == NULL) {
+               MSG("key not in tree")
+               RET(FALSE)
+       }
+
+       i_comp = (*pfi_compare)((*ppr_p)->data, p_user);
+       if (i_comp > 0) {
+               MSG("too high - scan left")
+               i_ret = delete(&(*ppr_p)->left, pfi_compare, p_user, pfv_uar,
+                              pi_balance, pi_uar_called);
+               if (*pi_balance)
+                       bal_L(ppr_p, pi_balance);
+       } else if (i_comp < 0) {
+               MSG("too low - scan right")
+               i_ret = delete(&(*ppr_p)->right, pfi_compare, p_user, pfv_uar,
+                              pi_balance, pi_uar_called);
+               if (*pi_balance)
+                       bal_R(ppr_p, pi_balance);
+       } else {
+               MSG("equal")
+               pr_q = *ppr_p;
+               if (pr_q->right == NULL) {
+                       MSG("right subtree null")
+                       *ppr_p = pr_q->left;
+                       *pi_balance = TRUE;
+               } else if (pr_q->left == NULL) {
+                       MSG("right subtree non-null, left subtree null")
+                       *ppr_p = pr_q->right;
+                       *pi_balance = TRUE;
+               } else {
+                       MSG("neither subtree null")
+                       del(&pr_q->left, pi_balance, &pr_q,
+                           pfv_uar, pi_uar_called);
+                       if (*pi_balance)
+                               bal_L(ppr_p, pi_balance);
+               }
+               if (!*pi_uar_called && pfv_uar)
+                       (*pfv_uar)(pr_q->data);
+               /* Thanks to wuth@castrov.cuc.ab.ca for the following stmt. */
+               memput(pr_q, sizeof(tree));
+               i_ret = TRUE;
+       }
+       RET(i_ret)
+}
+
+static void
+del(tree **ppr_r, int *pi_balance, tree **ppr_q,
+    void (*pfv_uar)(), int *pi_uar_called)
+{
+       ENTER("del")
+
+       if ((*ppr_r)->right != NULL) {
+               del(&(*ppr_r)->right, pi_balance, ppr_q,
+                   pfv_uar, pi_uar_called);
+               if (*pi_balance)
+                       bal_R(ppr_r, pi_balance);
+       } else {
+               if (pfv_uar)
+                       (*pfv_uar)((*ppr_q)->data);
+               *pi_uar_called = TRUE;
+               (*ppr_q)->data = (*ppr_r)->data;
+               *ppr_q = *ppr_r;
+               *ppr_r = (*ppr_r)->left;
+               *pi_balance = TRUE;
+       }
+
+       RETV
+}
+
+static void
+bal_L(tree **ppr_p, int *pi_balance) {
+       tree *p1, *p2;
+       int b1, b2;
+
+       ENTER("bal_L")
+       MSG("left branch has shrunk")
+
+       switch ((*ppr_p)->bal) {
+       case -1:
+               MSG("was imbalanced, fixed implicitly")
+               (*ppr_p)->bal = 0;
+               break;
+       case 0:
+               MSG("was okay, is now one off")
+               (*ppr_p)->bal = 1;
+               *pi_balance = FALSE;
+               break;
+       case 1:
+               MSG("was already off, this is too much")
+               p1 = (*ppr_p)->right;
+               b1 = p1->bal;
+               if (b1 >= 0) {
+                       MSG("single RR")
+                       (*ppr_p)->right = p1->left;
+                       p1->left = *ppr_p;
+                       if (b1 == 0) {
+                               MSG("b1 == 0")
+                               (*ppr_p)->bal = 1;
+                               p1->bal = -1;
+                               *pi_balance = FALSE;
+                       } else {
+                               MSG("b1 != 0")
+                               (*ppr_p)->bal = 0;
+                               p1->bal = 0;
+                       }
+                       *ppr_p = p1;
+               } else {
+                       MSG("double RL")
+                       p2 = p1->left;
+                       b2 = p2->bal;
+                       p1->left = p2->right;
+                       p2->right = p1;
+                       (*ppr_p)->right = p2->left;
+                       p2->left = *ppr_p;
+                       if (b2 == 1)
+                               (*ppr_p)->bal = -1;
+                       else
+                               (*ppr_p)->bal = 0;
+                       if (b2 == -1)
+                               p1->bal = 1;
+                       else
+                               p1->bal = 0;
+                       *ppr_p = p2;
+                       p2->bal = 0;
+               }
+       }
+       RETV
+}
+
+static void
+bal_R(tree **ppr_p, int *pi_balance) {
+       tree *p1, *p2;
+       int b1, b2;
+
+       ENTER("bal_R")
+       MSG("right branch has shrunk")
+       switch ((*ppr_p)->bal) {
+       case 1:
+               MSG("was imbalanced, fixed implicitly")
+               (*ppr_p)->bal = 0;
+               break;
+       case 0:
+               MSG("was okay, is now one off")
+               (*ppr_p)->bal = -1;
+               *pi_balance = FALSE;
+               break;
+       case -1:
+               MSG("was already off, this is too much")
+               p1 = (*ppr_p)->left;
+               b1 = p1->bal;
+               if (b1 <= 0) {
+                       MSG("single LL")
+                       (*ppr_p)->left = p1->right;
+                       p1->right = *ppr_p;
+                       if (b1 == 0) {
+                               MSG("b1 == 0")
+                               (*ppr_p)->bal = -1;
+                               p1->bal = 1;
+                               *pi_balance = FALSE;
+                       } else {
+                               MSG("b1 != 0")
+                               (*ppr_p)->bal = 0;
+                               p1->bal = 0;
+                       }
+                       *ppr_p = p1;
+               } else {
+                       MSG("double LR")
+                       p2 = p1->right;
+                       b2 = p2->bal;
+                       p1->right = p2->left;
+                       p2->left = p1;
+                       (*ppr_p)->left = p2->right;
+                       p2->right = *ppr_p;
+                       if (b2 == -1)
+                               (*ppr_p)->bal = 1;
+                       else
+                               (*ppr_p)->bal = 0;
+                       if (b2 == 1)
+                               p1->bal = -1;
+                       else
+                               p1->bal = 0;
+                       *ppr_p = p2;
+                       p2->bal = 0;
+               }
+       }
+       RETV
+}
diff --git a/lib/bind/isc/tree.mdoc b/lib/bind/isc/tree.mdoc
new file mode 100644 (file)
index 0000000..02d452f
--- /dev/null
@@ -0,0 +1,154 @@
+.\" $Id: tree.mdoc,v 1.1 2001/03/29 06:31:55 marka Exp $
+.\"
+.\"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.
+.\"
+.Dd April 5, 1994
+.Dt TREE 3
+.Os BSD 4
+.Sh NAME
+.Nm tree_init ,
+.Nm tree_mung ,
+.Nm tree_srch ,
+.Nm tree_add ,
+.Nm tree_delete ,
+.Nm tree_trav
+.Nd balanced binary tree routines
+.Sh SYNOPSIS
+.Ft void
+.Fn tree_init "void **tree"
+.Ft void *
+.Fn tree_srch "void **tree" "int (*compare)()" "void *data"
+.Ft void
+.Fn tree_add(tree, compare, data, del_uar) "void **tree" "int (*compare)()" \
+"void *data" "void (*del_uar)()"
+.Ft int
+.Fn tree_delete(tree, compare, data, del_uar) "void **tree" "int (*compare)()" \
+"void *data" "void (*del_uar)()"
+.Ft int
+.Fn tree_trav(tree, trav_uar) "void **tree" "int (*trav_uar)()"
+.Ft void
+.Fn tree_mung(tree, del_uar) "void **tree" "void (*del_uar)()"
+.Sh DESCRIPTION
+These functions create and manipulate a balanced binary (AVL) tree.  Each node
+of the tree contains the expected left & right subtree pointers, a short int
+balance indicator, and a pointer to the user data.  On a 32 bit system, this
+means an overhead of 4+4+2+4 bytes per node (or, on a RISC or otherwise
+alignment constrained system with implied padding, 4+4+4+4 bytes per node).
+There is no key data type enforced by this package; a caller supplied
+compare routine is used to compare user data blocks.
+.Pp
+Balanced binary trees are very fast on searches and replacements, but have a
+moderately high cost for additions and deletions.  If your application does a
+lot more searches and replacements than it does additions and deletions, the
+balanced (AVL) binary tree is a good choice for a data structure.
+.Pp
+.Fn Tree_init
+creates an empty tree and binds it to
+.Dq Fa tree
+(which for this and all other routines in this package should be declared as
+a pointer to void or int, and passed by reference), which can then be used by
+other routines in this package.  Note that more than one
+.Dq Fa tree
+variable can exist at once; thus multiple trees can be manipulated
+simultaneously.
+.Pp
+.Fn Tree_srch
+searches a tree for a specific node and returns either
+.Fa NULL
+if no node was found, or the value of the user data pointer if the node
+was found.
+.Fn compare
+is the address of a function to compare two user data blocks.  This routine
+should work much the way 
+.Xr strcmp 3
+does; in fact,
+.Xr strcmp
+could be used if the user data was a \s-2NUL\s+2 terminated string.
+.Dq Fa Data
+is the address of a user data block to be used by
+.Fn compare
+as the search criteria.  The tree is searched for a node where
+.Fn compare
+returns 0.
+.Pp
+.Fn Tree_add
+inserts or replaces a node in the specified tree.  The tree specified by
+.Dq Fa tree
+is searched as in
+.Fn tree_srch,
+and if a node is found to match
+.Dq Fa data,
+then the
+.Fn del_uar
+function, if non\-\s-2NULL\s+2, is called with the address of the user data
+block for the node (this routine should deallocate any dynamic memory which
+is referenced exclusively by the node); the user data pointer for the node
+is then replaced by the value of
+.Dq Fa data.
+If no node is found to match, a new node is added (which may or may not
+cause a transparent rebalance operation), with a user data pointer equal to
+.Dq Fa data.
+A rebalance may or may not occur, depending on where the node is added
+and what the rest of the tree looks like.
+.Fn Tree_add
+will return the
+.Dq Fa data
+pointer unless catastrophe occurs in which case it will return \s-2NULL\s+2.
+.Pp
+.Fn Tree_delete
+deletes a node from
+.Dq Fa tree.
+A rebalance may or may not occur, depending on where the node is removed from
+and what the rest of the tree looks like.
+.Fn Tree_delete
+returns TRUE if a node was deleted, FALSE otherwise.
+.Pp
+.Fn Tree_trav
+traverses all of
+.Dq Fa tree,
+calling
+.Fn trav_uar
+with the address of each user data block.  If
+.Fn trav_uar
+returns FALSE at any time,
+.Fn tree_trav
+will immediately return FALSE to its caller.  Otherwise all nodes will be 
+reached and
+.Fn tree_trav
+will return TRUE.
+.Pp
+.Fn Tree_mung
+deletes every node in
+.Dq Fa tree,
+calling
+.Fn del_uar
+(if it is not \s-2NULL\s+2) with the user data address from each node (see
+.Fn tree_add
+and
+.Fn tree_delete
+above).  The tree is left in the same state that
+.Fn tree_init
+leaves it in \- i.e., empty.
+.Sh BUGS
+Should have a way for the caller to specify application-specific
+.Xr malloc
+and
+.Xr free
+functions to be used internally when allocating meta data.
+.Sh AUTHOR
+Paul Vixie, converted and augumented from Modula\-2 examples in
+.Dq Algorithms & Data Structures ,
+Niklaus Wirth, Prentice\-Hall, ISBN 0\-13\-022005\-1.
diff --git a/lib/bind/make/includes.in b/lib/bind/make/includes.in
new file mode 100644 (file)
index 0000000..d471656
--- /dev/null
@@ -0,0 +1,44 @@
+# Copyright (C) 1999-2001  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.
+
+# $Id: includes.in,v 1.1 2001/03/29 06:31:55 marka Exp $
+
+# Search for machine-generated header files in the build tree,
+# and for normal headers in the source tree (${top_srcdir}).
+# We only need to look in OS-specific subdirectories for the
+# latter case, because there are no machine-generated OS-specific
+# headers.
+
+ISC_INCLUDES = @BIND9_ISC_BUILDINCLUDE@ \
+       -I${top_srcdir}/lib/isc \
+       -I${top_srcdir}/lib/isc/include \
+       -I${top_srcdir}/lib/isc/unix/include \
+       -I${top_srcdir}/lib/isc/@ISC_THREAD_DIR@/include
+
+ISCCFG_INCLUDES = @BIND9_ISCCFG_BUILDINCLUDE@ \
+       -I${top_srcdir}/lib/isccfg/include
+
+DNS_INCLUDES = @BIND9_DNS_BUILDINCLUDE@ \
+       -I${top_srcdir}/lib/dns/include \
+       -I${top_srcdir}/lib/dns/sec/dst/include
+
+OMAPI_INCLUDES = @BIND9_OMAPI_BUILDINCLUDE@ \
+       -I${top_srcdir}/lib/omapi/include
+
+LWRES_INCLUDES = @BIND9_LWRES_BUILDINCLUDE@ \
+       -I${top_srcdir}/lib/lwres/include
+
+TEST_INCLUDES = \
+       -I${top_srcdir}/lib/tests/include
diff --git a/lib/bind/make/mkdep.in b/lib/bind/make/mkdep.in
new file mode 100644 (file)
index 0000000..60aea6f
--- /dev/null
@@ -0,0 +1,147 @@
+#!/bin/sh -
+
+## ++Copyright++ 1987
+## -
+## Copyright (c) 1987 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.
+## -
+## --Copyright--
+
+#
+#      @(#)mkdep.sh    5.12 (Berkeley) 6/30/88
+#
+
+MAKE=Makefile                  # default makefile name is "Makefile"
+
+while :
+       do case "$1" in
+               # -f allows you to select a makefile name
+               -f)
+                       MAKE=$2
+                       shift; shift ;;
+
+               # the -p flag produces "program: program.c" style dependencies
+               # so .o's don't get produced
+               -p)
+                       SED='s;\.o;;'
+                       shift ;;
+               *)
+                       break ;;
+       esac
+done
+
+if [ $# = 0 ] ; then
+       echo 'usage: mkdep [-p] [-f makefile] [flags] file ...'
+       exit 1
+fi
+
+if [ ! -w $MAKE ]; then
+       echo "mkdep: no writeable file \"$MAKE\""
+       exit 1
+fi
+
+TMP=mkdep$$
+
+trap 'rm -f $TMP ; exit 1' 1 2 3 13 15
+
+cp $MAKE ${MAKE}.bak
+
+sed -e '/DO NOT DELETE THIS LINE/,$d' < $MAKE > $TMP
+
+cat << _EOF_ >> $TMP
+# DO NOT DELETE THIS LINE -- mkdep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
+
+_EOF_
+
+# If your compiler doesn't have -M, add it.  If you can't, the next two
+# lines will try and replace the "cc -M".  The real problem is that this
+# hack can't deal with anything that requires a search path, and doesn't
+# even try for anything using bracket (<>) syntax.
+#
+# egrep '^#include[    ]*".*"' /dev/null $* |
+# sed -e 's/:[^"]*"\([^"]*\)".*/: \1/' -e 's/\.c/.o/' |
+
+MKDEPPROG="@MKDEPPROG@"
+if [ X"${MKDEPPROG}" != X ]; then
+    @SHELL@ -c "${MKDEPPROG} $*"
+else
+    @MKDEPCC@ @MKDEPCFLAGS@ $* |
+    sed "
+       s; \./; ;g
+       $SED" |
+    awk '{
+       if ($1 != prev) {
+               if (rec != "")
+                       print rec;
+               rec = $0;
+               prev = $1;
+       }
+       else {
+               if (length(rec $2) > 78) {
+                       print rec;
+                       rec = $0;
+               }
+               else
+                       rec = rec " " $2
+       }
+    }
+    END {
+       print rec
+    }' >> $TMP
+fi
+
+cat << _EOF_ >> $TMP
+
+# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
+_EOF_
+
+# copy to preserve permissions
+cp $TMP $MAKE
+rm -f ${MAKE}.bak $TMP
+exit 0
diff --git a/lib/bind/make/rules.in b/lib/bind/make/rules.in
new file mode 100644 (file)
index 0000000..fca8c72
--- /dev/null
@@ -0,0 +1,172 @@
+# Copyright (C) 1998-2001  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.
+
+# $Id: rules.in,v 1.1 2001/03/29 06:31:56 marka Exp $
+
+###
+### Common Makefile rules for BIND 9.
+###
+
+###
+### Paths
+###
+### Note: paths that vary by Makefile MUST NOT be listed
+### here, or they won't get expanded correctly.
+
+prefix =       @prefix@
+exec_prefix =  @exec_prefix@
+bindir =       @bindir@
+sbindir =      @sbindir@
+includedir =   @includedir@
+libdir =       @libdir@
+sysconfdir =   @sysconfdir@
+localstatedir =        @localstatedir@
+mandir =       @mandir@
+
+DESTDIR =
+
+@SET_MAKE@
+
+top_builddir = @BIND9_TOP_BUILDDIR@
+
+###
+### All
+###
+### Makefile may define:
+###    TARGETS
+
+all: subdirs ${TARGETS}
+
+###
+### Subdirectories
+###
+### Makefile may define:
+###    SUBDIRS
+
+ALL_SUBDIRS = ${SUBDIRS} nulldir
+
+#
+# We use a single-colon rule so that additional dependencies of
+# subdirectories can be specified after the inclusion of this file.
+# The "depend" target is treated the same way.
+#
+subdirs:
+       @for i in ${ALL_SUBDIRS}; do \
+               if [ "$$i" != "nulldir" -a -d $$i ]; then \
+                       echo "making all in `pwd`/$$i"; \
+                       (cd $$i; ${MAKE} ${MAKEDEFS} all) || exit 1; \
+               fi \
+       done
+
+install clean distclean::
+       @for i in ${ALL_SUBDIRS}; do \
+               if [ "$$i" != "nulldir" -a -d $$i ]; then \
+                       echo "making $@ in `pwd`/$$i"; \
+                       (cd $$i; ${MAKE} ${MAKEDEFS} $@) || exit 1; \
+               fi \
+       done
+
+###
+### C Programs
+###
+### Makefile must define
+###    CC
+### Makefile may define
+###    CFLAGS
+###    CINCLUDES
+###    CDEFINES
+###    CWARNINGS
+### User may define externally
+###     EXT_CFLAGS
+
+CC =           @CC@
+CFLAGS =       @CFLAGS@
+STD_CINCLUDES =        @STD_CINCLUDES@
+STD_CDEFINES = @STD_CDEFINES@
+STD_CWARNINGS =        @STD_CWARNINGS@
+
+.SUFFIXES:
+.SUFFIXES: .c .@O@
+
+ALWAYS_INCLUDES = -I${top_builddir}
+ALWAYS_DEFINES = @ALWAYS_DEFINES@
+ALWAYS_WARNINGS =
+
+ALL_CPPFLAGS = \
+       ${ALWAYS_INCLUDES} ${CINCLUDES} ${STD_CINCLUDES} \
+       ${ALWAYS_DEFINES} ${CDEFINES} ${STD_CDEFINES}
+
+ALL_CFLAGS = ${EXT_CFLAGS} ${CFLAGS} \
+       ${ALL_CPPFLAGS} \
+       ${ALWAYS_WARNINGS} ${STD_CWARNINGS} ${CWARNINGS}
+
+.c.@O@:
+       ${LIBTOOL} ${CC} ${ALL_CFLAGS} -c $<
+
+SHELL = @SHELL@
+LIBTOOL = @LIBTOOL@
+PURIFY = @PURIFY@
+
+MKDEP = ${SHELL} ${top_builddir}/make/mkdep
+
+cleandir: distclean
+
+clean distclean::
+       rm -f *.@O@ *.lo *.la core *.core
+       rm -rf .libs
+
+distclean::
+       rm -f Makefile
+
+depend:
+       @for i in ${ALL_SUBDIRS}; do \
+               if [ "$$i" != "nulldir" -a -d $$i ]; then \
+                       echo "making depend in `pwd`/$$i"; \
+                       (cd $$i; ${MAKE} ${MAKEDEFS} $@) || exit 1; \
+               fi \
+       done
+       @if [ X"${SRCS}" != X -a X"${PSRCS}" != X ] ; then \
+               echo ${MKDEP} ${ALL_CPPFLAGS} ${SRCS}; \
+               ${MKDEP} ${ALL_CPPFLAGS} ${SRCS}; \
+               echo ${MKDEP} -ap ${ALL_CPPFLAGS} ${PSRCS}; \
+               ${MKDEP} -ap ${ALL_CPPFLAGS} ${PSRCS}; \
+               ${DEPENDEXTRA} \
+       elif [ X"${SRCS}" != X ] ; then \
+               echo ${MKDEP} ${ALL_CPPFLAGS} ${SRCS}; \
+               ${MKDEP} ${ALL_CPPFLAGS} ${SRCS}; \
+               ${DEPENDEXTRA} \
+       elif [ X"${PSRCS}" != X ] ; then \
+               echo ${MKDEP} ${ALL_CPPFLAGS} ${PSRCS}; \
+               ${MKDEP} -p ${ALL_CPPFLAGS} ${PSRCS}; \
+               ${DEPENDEXTRA} \
+       fi
+
+FORCE:
+
+###
+### Libraries
+###
+
+AR =           @AR@
+ARFLAGS =      @ARFLAGS@
+RANLIB =       @RANLIB@
+
+###
+### Installation
+###
+
+INSTALL =              @INSTALL@
+INSTALL_PROGRAM =      @INSTALL_PROGRAM@
+INSTALL_DATA =         @INSTALL_DATA@
diff --git a/lib/bind/nameser/Makefile.in b/lib/bind/nameser/Makefile.in
new file mode 100644 (file)
index 0000000..5f836e2
--- /dev/null
@@ -0,0 +1,12 @@
+OBJS=  ns_date.@O@ ns_name.@O@ ns_netint.@O@ ns_parse.@O@ ns_print.@O@ \
+       ns_samedomain.@O@ ns_sign.@O@ ns_ttl.@O@ ns_verify.@O@
+
+SRCS=  ns_date.c ns_name.c ns_netint.c ns_parse.c ns_print.c \
+       ns_samedomain.c ns_sign.c ns_ttl.c ns_verify.c
+
+TARGETS= ${OBJS}
+
+CINCLUDES= -I.. -I../include
+CWARNINGS= -Werror
+
+@BIND9_MAKE_RULES@
diff --git a/lib/bind/nameser/ns_date.c b/lib/bind/nameser/ns_date.c
new file mode 100644 (file)
index 0000000..486f70a
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * 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.1 2001/03/29 06:31:56 marka Exp $";
+#endif
+
+/* Import. */
+
+#include "port_before.h"
+
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include "port_after.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/lib/bind/nameser/ns_name.c b/lib/bind/nameser/ns_name.c
new file mode 100644 (file)
index 0000000..1bed101
--- /dev/null
@@ -0,0 +1,934 @@
+/*
+ * 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 2001/03/29 06:31:56 marka Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <resolv.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#include "port_after.h"
+
+#define NS_TYPE_ELT                    0x40 /* EDNS0 extended label type */
+#define DNS_LABELTYPE_BITSTRING                0x41
+
+/* Data. */
+
+static const char      digits[] = "0123456789";
+
+static const char digitvalue[256] = {
+       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16*/
+       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/
+       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/
+        0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1, /*64*/
+       -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/
+       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/
+       -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/
+       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/
+       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/
+};
+
+/* 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 *);
+static int             encode_bitsring(const char **, const char *,
+                                       char **, char **, const char *);
+static int             labellen(const u_char *);
+static int             decode_bitstring(const char **, char *, const char *);
+
+/* 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;
+       int l;
+
+       cp = src;
+       dn = dst;
+       eom = dst + dstsiz;
+
+       while ((n = *cp++) != 0) {
+               if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+                       /* Some kind of compression pointer. */
+                       errno = EMSGSIZE;
+                       return (-1);
+               }
+               if (dn != dst) {
+                       if (dn >= eom) {
+                               errno = EMSGSIZE;
+                               return (-1);
+                       }
+                       *dn++ = '.';
+               }
+               if ((l = labellen(cp - 1)) < 0) {
+                       errno = EMSGSIZE; /* XXX */
+                       return(-1);
+               }
+               if (dn + l >= eom) {
+                       errno = EMSGSIZE;
+                       return (-1);
+               }
+               if ((n & NS_CMPRSFLGS) == NS_TYPE_ELT) {
+                       int m;
+
+                       if (n != DNS_LABELTYPE_BITSTRING) {
+                               /* XXX: labellen should reject this case */
+                               errno = EINVAL;
+                               return(-1);
+                       }
+                       if ((m = decode_bitstring((const char **)&cp, dn, eom)) < 0)
+                       {
+                               errno = EMSGSIZE;
+                               return(-1);
+                       }
+                       dn += m; 
+                       continue;
+               }
+               for ((void)NULL; l > 0; l--) {
+                       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, e = 0;
+       char *cp;
+
+       escaped = 0;
+       bp = dst;
+       eom = dst + dstsiz;
+       label = bp++;
+
+       while ((c = *src++) != 0) {
+               if (escaped) {
+                       if (c == '[') { /* start a bit string label */
+                               if ((cp = strchr(src, ']')) == NULL) {
+                                       errno = EINVAL; /* ??? */
+                                       return(-1);
+                               }
+                               if ((e = encode_bitsring(&src,
+                                                        cp + 2,
+                                                        (char **)&label,
+                                                        (char **)&bp,
+                                                        (const char *)eom))
+                                   != 0) {
+                                       errno = e;
+                                       return(-1);
+                               }
+                               escaped = 0;
+                               label = bp++;
+                               if ((c = *src++) == 0)
+                                       goto done;
+                               else if (c != '.') {
+                                       errno = EINVAL;
+                                       return(-1);
+                               }
+                               continue;
+                       }
+                       else 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);
+       }
+  done:
+       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;
+       int l;
+
+       cp = src;
+       dn = dst;
+       eom = dst + dstsiz;
+
+       while ((n = *cp++) != 0) {
+               if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+                       /* Some kind of compression pointer. */
+                       errno = EMSGSIZE;
+                       return (-1);
+               }
+               *dn++ = n;
+               if ((l = labellen(cp - 1)) < 0) {
+                       errno = EMSGSIZE;
+                       return (-1);
+               }
+               if (dn + l >= eom) {
+                       errno = EMSGSIZE;
+                       return (-1);
+               }
+               for ((void)NULL; l > 0; l--) {
+                       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;
+       int n, len, checked, l;
+
+       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:
+               case NS_TYPE_ELT:
+                       /* Limit checks. */
+                       if ((l = labellen(srcp - 1)) < 0) {
+                               errno = EMSGSIZE;
+                               return(-1);
+                       }
+                       if (dstp + l + 1 >= dstlim || srcp + l >= eom) {
+                               errno = EMSGSIZE;
+                               return (-1);
+                       }
+                       checked += l + 1;
+                       *dstp++ = n;
+                       memcpy(dstp, srcp, l);
+                       dstp += l;
+                       srcp += l;
+                       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, int dstsiz,
+            const u_char **dnptrs, const u_char **lastdnptr)
+{
+       u_char *dstp;
+       const u_char **cpp, **lpp, *eob, *msg;
+       const u_char *srcp;
+       int n, l, first = 1;
+
+       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 {
+               int l0;
+
+               n = *srcp;
+               if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+                       errno = EMSGSIZE;
+                       return (-1);
+               }
+               if ((l0 = labellen(srcp)) < 0) {
+                       errno = EINVAL;
+                       return(-1);
+               }
+               l += l0 + 1;
+               if (l > MAXCDNAME) {
+                       errno = EMSGSIZE;
+                       return (-1);
+               }
+               srcp += l0 + 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 && first) {
+                               *cpp++ = dstp;
+                               *cpp = NULL;
+                               first = 0;
+                       }
+               }
+               /* copy label to buffer */
+               if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+                       /* Should not happen. */
+                       goto cleanup;
+               }
+               n = labellen(srcp);
+               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));
+}
+
+/*
+ * Reset dnptrs so that there are no active references to pointers at or
+ * after src.
+ */
+void
+ns_name_rollback(const u_char *src, const u_char **dnptrs,
+                const u_char **lastdnptr)
+{
+       while (dnptrs < lastdnptr && *dnptrs != NULL) {
+               if (*dnptrs >= src) {
+                       *dnptrs = NULL;
+                       break;
+               }
+               dnptrs++;
+       }
+}
+
+/*
+ * 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;
+       int l;
+
+       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_TYPE_ELT: /* EDNS0 extended label */
+                       if ((l = labellen(cp - 1)) < 0) {
+                               errno = EMSGSIZE; /* XXX */
+                               return(-1);
+                       }
+                       cp += l;
+                       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++) {
+               sp = *cpp;
+               /*
+                * terminate search on:
+                * root label
+                * compression pointer
+                * unusable offset
+                */
+               while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 &&
+                      (sp - msg) < 0x4000) {
+                       dn = domain;
+                       cp = sp;
+                       while ((n = *cp++) != 0) {
+                               /*
+                                * check for indirection
+                                */
+                               switch (n & NS_CMPRSFLGS) {
+                               case 0:         /* normal case, n == len */
+                                       n = labellen(cp - 1); /* XXX */
+
+                                       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: ;
+                       sp += *sp + 1;
+       }
+       errno = ENOENT;
+       return (-1);
+}
+
+static int
+decode_bitstring(const char **cpp, char *dn, const char *eom)
+{
+       const char *cp = *cpp;
+       char *beg = dn, tc;
+       int b, blen, plen;
+
+       if ((blen = (*cp & 0xff)) == 0)
+               blen = 256;
+       plen = (blen + 3) / 4;
+       plen += sizeof("\\[x/]") + (blen > 99 ? 3 : (blen > 9) ? 2 : 1);
+       if (dn + plen >= eom)
+               return(-1);
+
+       cp++;
+       dn += sprintf(dn, "\\[x");
+       for (b = blen; b > 7; b -= 8, cp++)
+               dn += sprintf(dn, "%02x", *cp & 0xff);
+       if (b > 4) {
+               tc = *cp++;
+               dn += sprintf(dn, "%02x", tc & (0xff << (8 - b)));
+       } else if (b > 0) {
+               tc = *cp++;
+               dn += sprintf(dn, "%1x", ((tc >> 4) & 0x0f) & (0x0f << (4 - b))); 
+       }
+       dn += sprintf(dn, "/%d]", blen);
+
+       *cpp = cp;
+       return(dn - beg);
+}
+
+static int
+encode_bitsring(const char **bp, const char *end, char **labelp,
+               char ** dst, const char *eom)
+{
+       int afterslash = 0;
+       const char *cp = *bp;
+       char *tp, c;
+       const char *beg_blen;
+       char *end_blen = NULL;
+       int value = 0, count = 0, tbcount = 0, blen = 0;
+
+       beg_blen = end_blen = NULL;
+
+       /* a bitstring must contain at least 2 characters */
+       if (end - cp < 2)
+               return(EINVAL);
+
+       /* XXX: currently, only hex strings are supported */
+       if (*cp++ != 'x')
+               return(EINVAL);
+       if (!isxdigit((*cp) & 0xff)) /* reject '\[x/BLEN]' */
+               return(EINVAL);
+
+       for (tp = *dst + 1; cp < end && tp < eom; cp++) {
+               switch((c = *cp)) {
+               case ']':       /* end of the bitstring */
+                       if (afterslash) {
+                               if (beg_blen == NULL)
+                                       return(EINVAL);
+                               blen = (int)strtol(beg_blen, &end_blen, 10);
+                               if (*end_blen != ']')
+                                       return(EINVAL);
+                       }
+                       if (count)
+                               *tp++ = ((value << 4) & 0xff);
+                       cp++;   /* skip ']' */
+                       goto done;
+               case '/':
+                       afterslash = 1;
+                       break;
+               default:
+                       if (afterslash) {
+                               if (!isdigit(c))
+                                       return(EINVAL);
+                               if (beg_blen == NULL) {
+                                       
+                                       if (c == '0') {
+                                               /* blen never begings with 0 */
+                                               return(EINVAL);
+                                       }
+                                       beg_blen = cp;
+                               }
+                       } else {
+                               if (!isxdigit(c))
+                                       return(EINVAL);
+                               value <<= 4;
+                               value += digitvalue[(int)c];
+                               count += 4;
+                               tbcount += 4;
+                               if (tbcount > 256)
+                                       return(EINVAL);
+                               if (count == 8) {
+                                       *tp++ = value;
+                                       count = 0;
+                               }
+                       }
+                       break;
+               }
+       }
+  done:
+       if (cp >= end || tp >= eom)
+               return(EMSGSIZE);
+
+       /*
+        * bit length validation:
+        * If a <length> is present, the number of digits in the <bit-data>
+        * MUST be just sufficient to contain the number of bits specified
+        * by the <length>. If there are insignificant bits in a final
+        * hexadecimal or octal digit, they MUST be zero.
+        * RFC 2673, Section 3.2.
+        */
+       if (blen > 0) {
+               int traillen;
+
+               if (((blen + 3) & ~3) != tbcount)
+                       return(EINVAL);
+               traillen = tbcount - blen; /* between 0 and 3 */
+               if (((value << (8 - traillen)) & 0xff) != 0)
+                       return(EINVAL);
+       }
+       else
+               blen = tbcount;
+       if (blen == 256)
+               blen = 0;
+
+       /* encode the type and the significant bit fields */
+       **labelp = DNS_LABELTYPE_BITSTRING;
+       **dst = blen;
+
+       *bp = cp;
+       *dst = tp;
+
+       return(0);
+}
+
+static int
+labellen(const u_char *lp)
+{
+       int bitlen;
+       u_char l = *lp;
+
+       if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+               /* should be avoided by the caller */
+               return(-1);
+       }
+
+       if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) {
+               if (l == DNS_LABELTYPE_BITSTRING) {
+                       if ((bitlen = *(lp + 1)) == 0)
+                               bitlen = 256;
+                       return((bitlen + 7 ) / 8 + 1);
+               }
+               return(-1);     /* unknwon ELT */
+       }
+       return(l);
+}
diff --git a/lib/bind/nameser/ns_netint.c b/lib/bind/nameser/ns_netint.c
new file mode 100644 (file)
index 0000000..509ae86
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * 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_netint.c,v 1.1 2001/03/29 06:31:56 marka Exp $";
+#endif
+
+/* Import. */
+
+#include "port_before.h"
+
+#include <arpa/nameser.h>
+
+#include "port_after.h"
+
+/* Public. */
+
+u_int
+ns_get16(const u_char *src) {
+       u_int dst;
+
+       NS_GET16(dst, src);
+       return (dst);
+}
+
+u_long
+ns_get32(const u_char *src) {
+       u_long dst;
+
+       NS_GET32(dst, src);
+       return (dst);
+}
+
+void
+ns_put16(u_int src, u_char *dst) {
+       NS_PUT16(src, dst);
+}
+
+void
+ns_put32(u_long src, u_char *dst) {
+       NS_PUT32(src, dst);
+}
diff --git a/lib/bind/nameser/ns_parse.c b/lib/bind/nameser/ns_parse.c
new file mode 100644 (file)
index 0000000..6b08ee1
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * 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.1 2001/03/29 06:31:57 marka Exp $";
+#endif
+
+/* Import. */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <resolv.h>
+#include <string.h>
+
+#include "port_after.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_msg_getflag(ns_msg handle, int flag) {
+       return(((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift);
+}
+
+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*/;
+                       NS_GET16(rdlength, ptr);
+                       ptr += rdlength/*RData*/;
+               }
+       }
+       if (ptr > eom)
+               RETERR(EMSGSIZE);
+       return (ptr - optr);
+}
+
+int
+ns_initparse(const u_char *msg, int 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);
+       NS_GET16(handle->_id, msg);
+       if (msg + NS_INT16SZ > eom)
+               RETERR(EMSGSIZE);
+       NS_GET16(handle->_flags, msg);
+       for (i = 0; i < ns_s_max; i++) {
+               if (msg + NS_INT16SZ > eom)
+                       RETERR(EMSGSIZE);
+               NS_GET16(handle->_counts[i], msg);
+       }
+       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);
+}
+
+int
+ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr) {
+       int b;
+
+       /* Make section right. */
+       if (section >= ns_s_max)
+               RETERR(ENODEV);
+       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)
+               RETERR(EMSGSIZE);
+       NS_GET16(rr->type, handle->_ptr);
+       NS_GET16(rr->rr_class, handle->_ptr);
+       if (section == ns_s_qd) {
+               rr->ttl = 0;
+               rr->rdlength = 0;
+               rr->rdata = NULL;
+       } else {
+               if (handle->_ptr + NS_INT32SZ + NS_INT16SZ > handle->_eom)
+                       RETERR(EMSGSIZE);
+               NS_GET32(rr->ttl, handle->_ptr);
+               NS_GET16(rr->rdlength, handle->_ptr);
+               if (handle->_ptr + rr->rdlength > handle->_eom)
+                       RETERR(EMSGSIZE);
+               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 (0);
+}
+
+/* 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/lib/bind/nameser/ns_print.c b/lib/bind/nameser/ns_print.c
new file mode 100644 (file)
index 0000000..c78bf5c
--- /dev/null
@@ -0,0 +1,901 @@
+/*
+ * 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_print.c,v 1.1 2001/03/29 06:31:57 marka Exp $";
+#endif
+
+/* Import. */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <isc/assertions.h>
+#include <errno.h>
+#include <resolv.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+/* Forward. */
+
+static size_t  prune_origin(const char *name, const char *origin);
+static int     charstr(const u_char *rdata, const u_char *edata,
+                       char **buf, size_t *buflen);
+static int     addname(const u_char *msg, size_t msglen,
+                       const u_char **p, const char *origin,
+                       char **buf, size_t *buflen);
+static void    addlen(size_t len, char **buf, size_t *buflen);
+static int     addstr(const char *src, size_t len,
+                      char **buf, size_t *buflen);
+static int     addtab(size_t len, size_t target, int spaced,
+                      char **buf, size_t *buflen);
+
+/* Proto. */
+
+u_int16_t       dst_s_dns_key_id(const u_char *, const int);
+
+/* Macros. */
+
+#define        T(x) \
+       do { \
+               if ((x) < 0) \
+                       return (-1); \
+       } while (0)
+
+/* Public. */
+
+/*
+ * int
+ * ns_sprintrr(handle, rr, name_ctx, origin, buf, buflen)
+ *     Convert an RR to presentation format.
+ * return:
+ *     Number of characters written to buf, or -1 (check errno).
+ */
+int
+ns_sprintrr(const ns_msg *handle, const ns_rr *rr,
+           const char *name_ctx, const char *origin,
+           char *buf, size_t buflen)
+{
+       int n;
+
+       n = ns_sprintrrf(ns_msg_base(*handle), ns_msg_size(*handle),
+                        ns_rr_name(*rr), ns_rr_class(*rr), ns_rr_type(*rr),
+                        ns_rr_ttl(*rr), ns_rr_rdata(*rr), ns_rr_rdlen(*rr),
+                        name_ctx, origin, buf, buflen);
+       return (n);
+}
+
+/*
+ * int
+ * ns_sprintrrf(msg, msglen, name, class, type, ttl, rdata, rdlen,
+ *            name_ctx, origin, buf, buflen)
+ *     Convert the fields of an RR into presentation format.
+ * return:
+ *     Number of characters written to buf, or -1 (check errno).
+ */
+int
+ns_sprintrrf(const u_char *msg, size_t msglen,
+           const char *name, ns_class class, ns_type type,
+           u_long ttl, const u_char *rdata, size_t rdlen,
+           const char *name_ctx, const char *origin,
+           char *buf, size_t buflen)
+{
+       const char *obuf = buf;
+       const u_char *edata = rdata + rdlen;
+       int spaced = 0;
+
+       const char *comment;
+       char tmp[100];
+       int len, x;
+
+       /*
+        * Owner.
+        */
+       if (name_ctx != NULL && ns_samename(name_ctx, name) == 1) {
+               T(addstr("\t\t\t", 3, &buf, &buflen));
+       } else {
+               len = prune_origin(name, origin);
+               if (*name == '\0') {
+                       goto root;
+               } else if (len == 0) {
+                       T(addstr("@\t\t\t", 4, &buf, &buflen));
+               } else {
+                       T(addstr(name, len, &buf, &buflen));
+                       /* Origin not used or not root, and no trailing dot? */
+                       if (((origin == NULL || origin[0] == '\0') ||
+                           (origin[0] != '.' && origin[1] != '\0' &&
+                           name[len] == '\0')) && name[len - 1] != '.') {
+ root:
+                               T(addstr(".", 1, &buf, &buflen));
+                               len++;
+                       }
+                       T(spaced = addtab(len, 24, spaced, &buf, &buflen));
+               }
+       }
+
+       /*
+        * TTL, Class, Type.
+        */
+       T(x = ns_format_ttl(ttl, buf, buflen));
+       addlen(x, &buf, &buflen);
+       len = SPRINTF((tmp, " %s %s", p_class(class), p_type(type)));
+       T(addstr(tmp, len, &buf, &buflen));
+       if (rdlen == 0)
+               return (buf - obuf);
+       T(spaced = addtab(x + len, 16, spaced, &buf, &buflen));
+
+       /*
+        * RData.
+        */
+       switch (type) {
+       case ns_t_a:
+               if (rdlen != NS_INADDRSZ)
+                       goto formerr;
+               (void) inet_ntop(AF_INET, rdata, buf, buflen);
+               addlen(strlen(buf), &buf, &buflen);
+               break;
+
+       case ns_t_cname:
+       case ns_t_mb:
+       case ns_t_mg:
+       case ns_t_mr:
+       case ns_t_ns:
+       case ns_t_ptr:
+       case ns_t_dname:
+               T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+               break;
+
+       case ns_t_hinfo:
+       case ns_t_isdn:
+               /* First word. */
+               T(len = charstr(rdata, edata, &buf, &buflen));
+               if (len == 0)
+                       goto formerr;
+               rdata += len;
+               T(addstr(" ", 1, &buf, &buflen));
+
+                   
+               /* Second word, optional in ISDN records. */
+               if (type == ns_t_isdn && rdata == edata)
+                       break;
+                   
+               T(len = charstr(rdata, edata, &buf, &buflen));
+               if (len == 0)
+                       goto formerr;
+               rdata += len;
+               break;
+
+       case ns_t_soa: {
+               u_long t;
+
+               /* Server name. */
+               T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+               T(addstr(" ", 1, &buf, &buflen));
+
+               /* Administrator name. */
+               T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+               T(addstr(" (\n", 3, &buf, &buflen));
+               spaced = 0;
+
+               if ((edata - rdata) != 5*NS_INT32SZ)
+                       goto formerr;
+
+               /* Serial number. */
+               t = ns_get32(rdata);  rdata += NS_INT32SZ;
+               T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
+               len = SPRINTF((tmp, "%lu", t));
+               T(addstr(tmp, len, &buf, &buflen));
+               T(spaced = addtab(len, 16, spaced, &buf, &buflen));
+               T(addstr("; serial\n", 9, &buf, &buflen));
+               spaced = 0;
+
+               /* Refresh interval. */
+               t = ns_get32(rdata);  rdata += NS_INT32SZ;
+               T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
+               T(len = ns_format_ttl(t, buf, buflen));
+               addlen(len, &buf, &buflen);
+               T(spaced = addtab(len, 16, spaced, &buf, &buflen));
+               T(addstr("; refresh\n", 10, &buf, &buflen));
+               spaced = 0;
+
+               /* Retry interval. */
+               t = ns_get32(rdata);  rdata += NS_INT32SZ;
+               T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
+               T(len = ns_format_ttl(t, buf, buflen));
+               addlen(len, &buf, &buflen);
+               T(spaced = addtab(len, 16, spaced, &buf, &buflen));
+               T(addstr("; retry\n", 8, &buf, &buflen));
+               spaced = 0;
+
+               /* Expiry. */
+               t = ns_get32(rdata);  rdata += NS_INT32SZ;
+               T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
+               T(len = ns_format_ttl(t, buf, buflen));
+               addlen(len, &buf, &buflen);
+               T(spaced = addtab(len, 16, spaced, &buf, &buflen));
+               T(addstr("; expiry\n", 9, &buf, &buflen));
+               spaced = 0;
+
+               /* Minimum TTL. */
+               t = ns_get32(rdata);  rdata += NS_INT32SZ;
+               T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
+               T(len = ns_format_ttl(t, buf, buflen));
+               addlen(len, &buf, &buflen);
+               T(addstr(" )", 2, &buf, &buflen));
+               T(spaced = addtab(len, 16, spaced, &buf, &buflen));
+               T(addstr("; minimum\n", 10, &buf, &buflen));
+
+               break;
+           }
+
+       case ns_t_mx:
+       case ns_t_afsdb:
+       case ns_t_rt: {
+               u_int t;
+
+               if (rdlen < NS_INT16SZ)
+                       goto formerr;
+
+               /* Priority. */
+               t = ns_get16(rdata);
+               rdata += NS_INT16SZ;
+               len = SPRINTF((tmp, "%u ", t));
+               T(addstr(tmp, len, &buf, &buflen));
+
+               /* Target. */
+               T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+
+               break;
+           }
+
+       case ns_t_px: {
+               u_int t;
+
+               if (rdlen < NS_INT16SZ)
+                       goto formerr;
+
+               /* Priority. */
+               t = ns_get16(rdata);
+               rdata += NS_INT16SZ;
+               len = SPRINTF((tmp, "%u ", t));
+               T(addstr(tmp, len, &buf, &buflen));
+
+               /* Name1. */
+               T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+               T(addstr(" ", 1, &buf, &buflen));
+
+               /* Name2. */
+               T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+
+               break;
+           }
+
+       case ns_t_x25:
+               T(len = charstr(rdata, edata, &buf, &buflen));
+               if (len == 0)
+                       goto formerr;
+               rdata += len;
+               break;
+
+       case ns_t_txt:
+               while (rdata < edata) {
+                       T(len = charstr(rdata, edata, &buf, &buflen));
+                       if (len == 0)
+                               goto formerr;
+                       rdata += len;
+                       if (rdata < edata)
+                               T(addstr(" ", 1, &buf, &buflen));
+               }
+               break;
+
+       case ns_t_nsap: {
+               char t[255*3];
+
+               (void) inet_nsap_ntoa(rdlen, rdata, t);
+               T(addstr(t, strlen(t), &buf, &buflen));
+               break;
+           }
+
+       case ns_t_aaaa:
+               if (rdlen != NS_IN6ADDRSZ)
+                       goto formerr;
+               (void) inet_ntop(AF_INET6, rdata, buf, buflen);
+               addlen(strlen(buf), &buf, &buflen);
+               break;
+
+       case ns_t_loc: {
+               char t[255];
+
+               /* XXX protocol format checking? */
+               (void) loc_ntoa(rdata, t);
+               T(addstr(t, strlen(t), &buf, &buflen));
+               break;
+           }
+
+       case ns_t_naptr: {
+               u_int order, preference;
+               char t[50];
+
+               if (rdlen < 2*NS_INT16SZ)
+                       goto formerr;
+
+               /* Order, Precedence. */
+               order = ns_get16(rdata);        rdata += NS_INT16SZ;
+               preference = ns_get16(rdata);   rdata += NS_INT16SZ;
+               len = SPRINTF((t, "%u %u ", order, preference));
+               T(addstr(t, len, &buf, &buflen));
+
+               /* Flags. */
+               T(len = charstr(rdata, edata, &buf, &buflen));
+               if (len == 0)
+                       goto formerr;
+               rdata += len;
+               T(addstr(" ", 1, &buf, &buflen));
+
+               /* Service. */
+               T(len = charstr(rdata, edata, &buf, &buflen));
+               if (len == 0)
+                       goto formerr;
+               rdata += len;
+               T(addstr(" ", 1, &buf, &buflen));
+
+               /* Regexp. */
+               T(len = charstr(rdata, edata, &buf, &buflen));
+               if (len < 0)
+                       return (-1);
+               if (len == 0)
+                       goto formerr;
+               rdata += len;
+               T(addstr(" ", 1, &buf, &buflen));
+
+               /* Server. */
+               T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+               break;
+           }
+
+       case ns_t_srv: {
+               u_int priority, weight, port;
+               char t[50];
+
+               if (rdlen < NS_INT16SZ*3)
+                       goto formerr;
+
+               /* Priority, Weight, Port. */
+               priority = ns_get16(rdata);  rdata += NS_INT16SZ;
+               weight   = ns_get16(rdata);  rdata += NS_INT16SZ;
+               port     = ns_get16(rdata);  rdata += NS_INT16SZ;
+               len = SPRINTF((t, "%u %u %u ", priority, weight, port));
+               T(addstr(t, len, &buf, &buflen));
+
+               /* Server. */
+               T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+               break;
+           }
+
+       case ns_t_minfo:
+       case ns_t_rp:
+               /* Name1. */
+               T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+               T(addstr(" ", 1, &buf, &buflen));
+
+               /* Name2. */
+               T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+
+               break;
+
+       case ns_t_wks: {
+               int n, lcnt;
+
+               if (rdlen < NS_INT32SZ + 1)
+                       goto formerr;
+
+               /* Address. */
+               (void) inet_ntop(AF_INET, rdata, buf, buflen);
+               addlen(strlen(buf), &buf, &buflen);
+               rdata += NS_INADDRSZ;
+
+               /* Protocol. */
+               len = SPRINTF((tmp, " %u ( ", *rdata));
+               T(addstr(tmp, len, &buf, &buflen));
+               rdata += NS_INT8SZ;
+
+               /* Bit map. */
+               n = 0;
+               lcnt = 0;
+               while (rdata < edata) {
+                       u_int c = *rdata++;
+                       do {
+                               if (c & 0200) {
+                                       if (lcnt == 0) {
+                                               T(addstr("\n\t\t\t\t", 5,
+                                                        &buf, &buflen));
+                                               lcnt = 10;
+                                               spaced = 0;
+                                       }
+                                       len = SPRINTF((tmp, "%d ", n));
+                                       T(addstr(tmp, len, &buf, &buflen));
+                                       lcnt--;
+                               }
+                               c <<= 1;
+                       } while (++n & 07);
+               }
+               T(addstr(")", 1, &buf, &buflen));
+
+               break;
+           }
+
+       case ns_t_key: {
+               char base64_key[NS_MD5RSA_MAX_BASE64];
+               u_int keyflags, protocol, algorithm, key_id;
+               const char *leader;
+               int n;
+
+               if (rdlen < NS_INT16SZ + NS_INT8SZ + NS_INT8SZ)
+                       goto formerr;
+
+               /* Key flags, Protocol, Algorithm. */
+               key_id = dst_s_dns_key_id(rdata, edata-rdata);
+               keyflags = ns_get16(rdata);  rdata += NS_INT16SZ;
+               protocol = *rdata++;
+               algorithm = *rdata++;
+               len = SPRINTF((tmp, "0x%04x %u %u",
+                              keyflags, protocol, algorithm));
+               T(addstr(tmp, len, &buf, &buflen));
+
+               /* Public key data. */
+               len = b64_ntop(rdata, edata - rdata,
+                              base64_key, sizeof base64_key);
+               if (len < 0)
+                       goto formerr;
+               if (len > 15) {
+                       T(addstr(" (", 2, &buf, &buflen));
+                       leader = "\n\t\t";
+                       spaced = 0;
+               } else
+                       leader = " ";
+               for (n = 0; n < len; n += 48) {
+                       T(addstr(leader, strlen(leader), &buf, &buflen));
+                       T(addstr(base64_key + n, MIN(len - n, 48),
+                                &buf, &buflen));
+               }
+               if (len > 15)
+                       T(addstr(" )", 2, &buf, &buflen));
+               n = SPRINTF((tmp, " ; key_tag= %u", key_id));
+               T(addstr(tmp, n, &buf, &buflen));
+
+               break;
+           }
+
+       case ns_t_sig: {
+               char base64_key[NS_MD5RSA_MAX_BASE64];
+               u_int type, algorithm, labels, footprint;
+               const char *leader;
+               u_long t;
+               int n;
+
+               if (rdlen < 22)
+                       goto formerr;
+
+               /* Type covered, Algorithm, Label count, Original TTL. */
+               type = ns_get16(rdata);  rdata += NS_INT16SZ;
+               algorithm = *rdata++;
+               labels = *rdata++;
+               t = ns_get32(rdata);  rdata += NS_INT32SZ;
+               len = SPRINTF((tmp, "%s %d %d %lu ",
+                              p_type(type), algorithm, labels, t));
+               T(addstr(tmp, len, &buf, &buflen));
+               if (labels > (u_int)dn_count_labels(name))
+                       goto formerr;
+
+               /* Signature expiry. */
+               t = ns_get32(rdata);  rdata += NS_INT32SZ;
+               len = SPRINTF((tmp, "%s ", p_secstodate(t)));
+               T(addstr(tmp, len, &buf, &buflen));
+
+               /* Time signed. */
+               t = ns_get32(rdata);  rdata += NS_INT32SZ;
+               len = SPRINTF((tmp, "%s ", p_secstodate(t)));
+               T(addstr(tmp, len, &buf, &buflen));
+
+               /* Signature Footprint. */
+               footprint = ns_get16(rdata);  rdata += NS_INT16SZ;
+               len = SPRINTF((tmp, "%u ", footprint));
+               T(addstr(tmp, len, &buf, &buflen));
+
+               /* Signer's name. */
+               T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+
+               /* Signature. */
+               len = b64_ntop(rdata, edata - rdata,
+                              base64_key, sizeof base64_key);
+               if (len > 15) {
+                       T(addstr(" (", 2, &buf, &buflen));
+                       leader = "\n\t\t";
+                       spaced = 0;
+               } else
+                       leader = " ";
+               if (len < 0)
+                       goto formerr;
+               for (n = 0; n < len; n += 48) {
+                       T(addstr(leader, strlen(leader), &buf, &buflen));
+                       T(addstr(base64_key + n, MIN(len - n, 48),
+                                &buf, &buflen));
+               }
+               if (len > 15)
+                       T(addstr(" )", 2, &buf, &buflen));
+               break;
+           }
+
+       case ns_t_nxt: {
+               int n, c;
+
+               /* Next domain name. */
+               T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+
+               /* Type bit map. */
+               n = edata - rdata;
+               for (c = 0; c < n*8; c++)
+                       if (NS_NXT_BIT_ISSET(c, rdata)) {
+                               len = SPRINTF((tmp, " %s", p_type(c)));
+                               T(addstr(tmp, len, &buf, &buflen));
+                       }
+               break;
+           }
+
+       case ns_t_cert: {
+               u_int c_type, key_tag, alg;
+               int n;
+               unsigned int siz;
+               char base64_cert[8192], tmp[40];
+               const char *leader;
+
+               c_type  = ns_get16(rdata); rdata += NS_INT16SZ;
+               key_tag = ns_get16(rdata); rdata += NS_INT16SZ;
+               alg = (u_int) *rdata++;
+
+               len = SPRINTF((tmp, "%d %d %d ", c_type, key_tag, alg));
+               T(addstr(tmp, len, &buf, &buflen));
+               siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
+               if (siz > sizeof(base64_cert) * 3/4) {
+                       const char *str = "record too long to print";
+                       T(addstr(str, strlen(str), &buf, &buflen));
+               }
+               else {
+                       len = b64_ntop(rdata, edata-rdata, base64_cert, siz);
+
+                       if (len < 0)
+                               goto formerr;
+                       else if (len > 15) {
+                               T(addstr(" (", 2, &buf, &buflen));
+                               leader = "\n\t\t";
+                               spaced = 0;
+                       }
+                       else
+                               leader = " ";
+       
+                       for (n = 0; n < len; n += 48) {
+                               T(addstr(leader, strlen(leader),
+                                        &buf, &buflen));
+                               T(addstr(base64_cert + n, MIN(len - n, 48),
+                                        &buf, &buflen));
+                       }
+                       if (len > 15)
+                               T(addstr(" )", 2, &buf, &buflen));
+               }
+               break;
+           }
+
+       case ns_t_tkey: {
+               /* KJD - need to complete this */
+               u_long t;
+               int mode, err, keysize;
+
+               /* Algorithm name. */
+               T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+               T(addstr(" ", 1, &buf, &buflen));
+
+               /* Inception. */
+               t = ns_get32(rdata);  rdata += NS_INT32SZ;
+               len = SPRINTF((tmp, "%s ", p_secstodate(t)));
+               T(addstr(tmp, len, &buf, &buflen));
+
+               /* Experation. */
+               t = ns_get32(rdata);  rdata += NS_INT32SZ;
+               len = SPRINTF((tmp, "%s ", p_secstodate(t)));
+               T(addstr(tmp, len, &buf, &buflen));
+
+               /* Mode , Error, Key Size. */
+               /* Priority, Weight, Port. */
+               mode = ns_get16(rdata);  rdata += NS_INT16SZ;
+               err  = ns_get16(rdata);  rdata += NS_INT16SZ;
+               keysize  = ns_get16(rdata);  rdata += NS_INT16SZ;
+               len = SPRINTF((tmp, "%u %u %u ", mode, err, keysize));
+               T(addstr(tmp, len, &buf, &buflen));
+
+        /* needs to dump key, print otherdata length & other data */
+               break;
+           }
+       case ns_t_tsig: {
+               /* BEW - need to complete this */
+               int n;
+
+               T(len = addname(msg, msglen, &rdata, origin, &buf, &buflen));
+               T(addstr(" ", 1, &buf, &buflen));
+               rdata += 8; /* time */
+               n = ns_get16(rdata); rdata += INT16SZ;
+               rdata += n; /* sig */
+               n = ns_get16(rdata); rdata += INT16SZ; /* original id */
+               sprintf(buf, "%d", ns_get16(rdata));
+               rdata += INT16SZ;
+               addlen(strlen(buf), &buf, &buflen);
+               break;
+           }
+
+       case ns_t_a6: {
+               struct in6_addr a;
+               int pbyte, pbit;
+
+               /* prefix length */
+               if (rdlen == 0) goto formerr;
+               len = SPRINTF((tmp, "%d ", *rdata));
+               T(addstr(tmp, len, &buf, &buflen));
+               pbit = *rdata;
+               if (pbit > 128) goto formerr;
+               pbyte = (pbit & ~7) / 8;
+               rdata++;
+
+               /* address suffix: provided only when prefix len != 128 */
+               if (pbit < 128) {
+                       if (rdata + pbyte >= edata) goto formerr;
+                       memset(&a, 0, sizeof(a));
+                       memcpy(&a.s6_addr[pbyte], rdata, sizeof(a) - pbyte);
+                       (void) inet_ntop(AF_INET6, &a, buf, buflen);
+                       addlen(strlen(buf), &buf, &buflen);
+                       rdata += sizeof(a) - pbyte;
+               }
+
+               /* prefix name: provided only when prefix len > 0 */
+               if (pbit == 0)
+                       break;
+               if (rdata >= edata) goto formerr;
+               T(addstr(" ", 1, &buf, &buflen));
+               T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+               
+               break;
+       }
+
+       case ns_t_opt: {
+               len = SPRINTF((tmp, "%u bytes", class));
+               T(addstr(tmp, len, &buf, &buflen));
+               break;
+       }
+
+       default:
+               comment = "unknown RR type";
+               goto hexify;
+       }
+       return (buf - obuf);
+ formerr:
+       comment = "RR format error";
+ hexify: {
+       int n, m;
+       char *p;
+
+       len = SPRINTF((tmp, "\\#(\t\t; %s", comment));
+       T(addstr(tmp, len, &buf, &buflen));
+       while (rdata < edata) {
+               p = tmp;
+               p += SPRINTF((p, "\n\t"));
+               spaced = 0;
+               n = MIN(16, edata - rdata);
+               for (m = 0; m < n; m++)
+                       p += SPRINTF((p, "%02x ", rdata[m]));
+               T(addstr(tmp, p - tmp, &buf, &buflen));
+               if (n < 16) {
+                       T(addstr(")", 1, &buf, &buflen));
+                       T(addtab(p - tmp + 1, 48, spaced, &buf, &buflen));
+               }
+               p = tmp;
+               p += SPRINTF((p, "; "));
+               for (m = 0; m < n; m++)
+                       *p++ = (isascii(rdata[m]) && isprint(rdata[m]))
+                               ? rdata[m]
+                               : '.';
+               T(addstr(tmp, p - tmp, &buf, &buflen));
+               rdata += n;
+       }
+       return (buf - obuf);
+    }
+}
+
+/* Private. */
+
+/*
+ * size_t
+ * prune_origin(name, origin)
+ *     Find out if the name is at or under the current origin.
+ * return:
+ *     Number of characters in name before start of origin,
+ *     or length of name if origin does not match.
+ * notes:
+ *     This function should share code with samedomain().
+ */
+static size_t
+prune_origin(const char *name, const char *origin) {
+       const char *oname = name;
+
+       while (*name != '\0') {
+               if (origin != NULL && ns_samename(name, origin) == 1)
+                       return (name - oname - (name > oname));
+               while (*name != '\0') {
+                       if (*name == '\\') {
+                               name++;
+                               /* XXX need to handle \nnn form. */
+                               if (*name == '\0')
+                                       break;
+                       } else if (*name == '.') {
+                               name++;
+                               break;
+                       }
+                       name++;
+               }
+       }
+       return (name - oname);
+}
+
+/*
+ * int
+ * charstr(rdata, edata, buf, buflen)
+ *     Format a <character-string> into the presentation buffer.
+ * return:
+ *     Number of rdata octets consumed
+ *     0 for protocol format error
+ *     -1 for output buffer error
+ * side effects:
+ *     buffer is advanced on success.
+ */
+static int
+charstr(const u_char *rdata, const u_char *edata, char **buf, size_t *buflen) {
+       const u_char *odata = rdata;
+       size_t save_buflen = *buflen;
+       char *save_buf = *buf;
+
+       if (addstr("\"", 1, buf, buflen) < 0)
+               goto enospc;
+       if (rdata < edata) {
+               int n = *rdata;
+
+               if (rdata + 1 + n <= edata) {
+                       rdata++;
+                       while (n-- > 0) {
+                               if (strchr("\n\"\\", *rdata) != NULL)
+                                       if (addstr("\\", 1, buf, buflen) < 0)
+                                               goto enospc;
+                               if (addstr((const char *)rdata, 1,
+                                          buf, buflen) < 0)
+                                       goto enospc;
+                               rdata++;
+                       }
+               }
+       }
+       if (addstr("\"", 1, buf, buflen) < 0)
+               goto enospc;
+       return (rdata - odata);
+ enospc:
+       errno = ENOSPC;
+       *buf = save_buf;
+       *buflen = save_buflen;
+       return (-1);
+}
+
+static int
+addname(const u_char *msg, size_t msglen,
+       const u_char **pp, const char *origin,
+       char **buf, size_t *buflen)
+{
+       size_t newlen, save_buflen = *buflen;
+       char *save_buf = *buf;
+       int n;
+
+       n = dn_expand(msg, msg + msglen, *pp, *buf, *buflen);
+       if (n < 0)
+               goto enospc;    /* Guess. */
+       newlen = prune_origin(*buf, origin);
+       if (**buf == '\0') {
+               goto root;
+       } else if (newlen == 0) {
+               /* Use "@" instead of name. */
+               if (newlen + 2 > *buflen)
+                       goto enospc;        /* No room for "@\0". */
+               (*buf)[newlen++] = '@';
+               (*buf)[newlen] = '\0';
+       } else {
+               if (((origin == NULL || origin[0] == '\0') ||
+                   (origin[0] != '.' && origin[1] != '\0' &&
+                   (*buf)[newlen] == '\0')) && (*buf)[newlen - 1] != '.') {
+                       /* No trailing dot. */
+ root:
+                       if (newlen + 2 > *buflen)
+                               goto enospc;    /* No room for ".\0". */
+                       (*buf)[newlen++] = '.';
+                       (*buf)[newlen] = '\0';
+               }
+       }
+       *pp += n;
+       addlen(newlen, buf, buflen);
+       **buf = '\0';
+       return (newlen);
+ enospc:
+       errno = ENOSPC;
+       *buf = save_buf;
+       *buflen = save_buflen;
+       return (-1);
+}
+
+static void
+addlen(size_t len, char **buf, size_t *buflen) {
+       INSIST(len <= *buflen);
+       *buf += len;
+       *buflen -= len;
+}
+
+static int
+addstr(const char *src, size_t len, char **buf, size_t *buflen) {
+       if (len >= *buflen) {
+               errno = ENOSPC;
+               return (-1);
+       }
+       memcpy(*buf, src, len);
+       addlen(len, buf, buflen);
+       **buf = '\0';
+       return (0);
+}
+
+static int
+addtab(size_t len, size_t target, int spaced, char **buf, size_t *buflen) {
+       size_t save_buflen = *buflen;
+       char *save_buf = *buf;
+       int t;
+
+       if (spaced || len >= target - 1) {
+               T(addstr("  ", 2, buf, buflen));
+               spaced = 1;
+       } else {
+               for (t = (target - len - 1) / 8; t >= 0; t--)
+                       if (addstr("\t", 1, buf, buflen) < 0) {
+                               *buflen = save_buflen;
+                               *buf = save_buf;
+                               return (-1);
+                       }
+               spaced = 0;
+       }
+       return (spaced);
+}
diff --git a/lib/bind/nameser/ns_samedomain.c b/lib/bind/nameser/ns_samedomain.c
new file mode 100644 (file)
index 0000000..54735b2
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * 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.1 2001/03/29 06:31:57 marka Exp $";
+#endif
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <arpa/nameser.h>
+#include <errno.h>
+#include <string.h>
+
+#include "port_after.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\\.
+ */
+
+int
+ns_makecanon(const char *src, char *dst, size_t dstsize) {
+       size_t n = strlen(src);
+
+       if (n + sizeof "." > dstsize) {
+               errno = EMSGSIZE;
+               return (-1);
+       }
+       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 (0);
+}
+
+/*
+ * 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];
+
+       if (ns_makecanon(a, ta, sizeof ta) < 0 ||
+           ns_makecanon(b, tb, sizeof tb) < 0)
+               return (-1);
+       if (strcasecmp(ta, tb) == 0)
+               return (1);
+       else
+               return (0);
+}
diff --git a/lib/bind/nameser/ns_sign.c b/lib/bind/nameser/ns_sign.c
new file mode 100644 (file)
index 0000000..2675444
--- /dev/null
@@ -0,0 +1,349 @@
+/*
+ * 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.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id: ns_sign.c,v 1.1 2001/03/29 06:31:57 marka Exp $";
+#endif
+
+/* Import. */
+
+#include "port_before.h"
+#include "fd_setsize.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <isc/dst.h>
+
+#include "port_after.h"
+
+#define BOUNDS_CHECK(ptr, count) \
+       do { \
+               if ((ptr) + (count) > eob) { \
+                       errno = EMSGSIZE; \
+                       return(NS_TSIG_ERROR_NO_SPACE); \
+               } \
+       } 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)
+ */
+int
+ns_sign(u_char *msg, int *msglen, int msgsize, int error, void *k,
+       const u_char *querysig, int querysiglen, u_char *sig, int *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;
+       int n;
+       time_t timesigned;
+
+       dst_init();
+       if (msg == NULL || msglen == NULL || sig == NULL || siglen == NULL)
+               return (-1);
+
+       /* Name. */
+       if (key != NULL && error != ns_r_badsig && error != ns_r_badkey)
+               n = dn_comp(key->dk_key_name, cp, eob - cp, NULL, NULL);
+       else
+               n = dn_comp("", cp, eob - cp, NULL, NULL);
+       if (n < 0)
+               return (NS_TSIG_ERROR_NO_SPACE);
+       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 (-ns_r_badkey);
+               n = dn_comp(NS_TSIG_ALG_HMAC_MD5, cp, eob - cp, NULL, NULL);
+       }
+       else
+               n = dn_comp("", cp, eob - cp, NULL, NULL);
+       if (n < 0)
+               return (NS_TSIG_ERROR_NO_SPACE);
+       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;
+               int 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, 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, cp2-buf,
+                             NULL, 0);
+
+               n = dst_sign_data(SIG_MODE_FINAL, key, &ctx, NULL, 0,
+                                 sig, *siglen);
+               if (n < 0)
+                       return (-ns_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 (0);
+}
+
+int
+ns_sign_tcp_init(void *k, const u_char *querysig, int querysiglen,
+                ns_tcp_tsig_state *state)
+{
+       dst_init();
+       if (state == NULL || k == NULL || querysig == NULL || querysiglen < 0)
+               return (-1);
+       state->counter = -1;
+       state->key = k;
+       if (state->key->dk_alg != KEY_HMAC_MD5)
+               return (-ns_r_badkey);
+       if (querysiglen > (int)sizeof(state->sig))
+               return (-1);
+       memcpy(state->sig, querysig, querysiglen);
+       state->siglen = querysiglen;
+       return (0);
+}
+
+int
+ns_sign_tcp(u_char *msg, int *msglen, int 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 (-1);
+
+       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 (0);
+
+       cp = msg + *msglen;
+       eob = msg + msgsize;
+
+       /* Name. */
+       n = dn_comp(state->key->dk_key_name, cp, eob - cp, NULL, NULL);
+       if (n < 0)
+               return (NS_TSIG_ERROR_NO_SPACE);
+       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, eob - cp, NULL, NULL);
+       if (n < 0)
+               return (NS_TSIG_ERROR_NO_SPACE);
+       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, 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 (-ns_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 (0);
+}
diff --git a/lib/bind/nameser/ns_ttl.c b/lib/bind/nameser/ns_ttl.c
new file mode 100644 (file)
index 0000000..9c24cd8
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * 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_ttl.c,v 1.1 2001/03/29 06:31:57 marka Exp $";
+#endif
+
+/* Import. */
+
+#include "port_before.h"
+
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+/* Forward. */
+
+static int     fmt1(int t, char s, char **buf, size_t *buflen);
+
+/* Macros. */
+
+#define T(x) if ((x) < 0) return (-1); else (void)NULL
+
+/* Public. */
+
+int
+ns_format_ttl(u_long src, char *dst, size_t dstlen) {
+       char *odst = dst;
+       int secs, mins, hours, days, weeks, x;
+       char *p;
+
+       secs = src % 60;   src /= 60;
+       mins = src % 60;   src /= 60;
+       hours = src % 24;  src /= 24;
+       days = src % 7;    src /= 7;
+       weeks = src;       src = 0;
+
+       x = 0;
+       if (weeks) {
+               T(fmt1(weeks, 'W', &dst, &dstlen));
+               x++;
+       }
+       if (days) {
+               T(fmt1(days, 'D', &dst, &dstlen));
+               x++;
+       }
+       if (hours) {
+               T(fmt1(hours, 'H', &dst, &dstlen));
+               x++;
+       }
+       if (mins) {
+               T(fmt1(mins, 'M', &dst, &dstlen));
+               x++;
+       }
+       if (secs || !(weeks || days || hours || mins)) {
+               T(fmt1(secs, 'S', &dst, &dstlen));
+               x++;
+       }
+
+       if (x > 1) {
+               int ch;
+
+               for (p = odst; (ch = *p) != '\0'; p++)
+                       if (isascii(ch) && isupper(ch))
+                               *p = tolower(ch);
+       }
+
+       return (dst - odst);
+}
+
+int
+ns_parse_ttl(const char *src, u_long *dst) {
+       u_long ttl, tmp;
+       int ch, digits, dirty;
+
+       ttl = 0;
+       tmp = 0;
+       digits = 0;
+       dirty = 0;
+       while ((ch = *src++) != '\0') {
+               if (!isascii(ch) || !isprint(ch))
+                       goto einval;
+               if (isdigit(ch)) {
+                       tmp *= 10;
+                       tmp += (ch - '0');
+                       digits++;
+                       continue;
+               }
+               if (digits == 0)
+                       goto einval;
+               if (islower(ch))
+                       ch = toupper(ch);
+               switch (ch) {
+               case 'W':  tmp *= 7;
+               case 'D':  tmp *= 24;
+               case 'H':  tmp *= 60;
+               case 'M':  tmp *= 60;
+               case 'S':  break;
+               default:   goto einval;
+               }
+               ttl += tmp;
+               tmp = 0;
+               digits = 0;
+               dirty = 1;
+       }
+       if (digits > 0) {
+               if (dirty)
+                       goto einval;
+               else
+                       ttl += tmp;
+       }
+       *dst = ttl;
+       return (0);
+
+ einval:
+       errno = EINVAL;
+       return (-1);
+}
+
+/* Private. */
+
+static int
+fmt1(int t, char s, char **buf, size_t *buflen) {
+       char tmp[50];
+       size_t len;
+
+       len = SPRINTF((tmp, "%d%c", t, s));
+       if (len + 1 > *buflen)
+               return (-1);
+       strcpy(*buf, tmp);
+       *buf += len;
+       *buflen -= len;
+       return (0);
+}
diff --git a/lib/bind/nameser/ns_verify.c b/lib/bind/nameser/ns_verify.c
new file mode 100644 (file)
index 0000000..919ed1e
--- /dev/null
@@ -0,0 +1,480 @@
+/*
+ * 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.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id: ns_verify.c,v 1.1 2001/03/29 06:31:58 marka Exp $";
+#endif
+
+/* Import. */
+
+#include "port_before.h"
+#include "fd_setsize.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <isc/dst.h>
+
+#include "port_after.h"
+
+/* 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)
+ */
+int
+ns_verify(u_char *msg, int *msglen, void *k,
+         const u_char *querysig, int querysiglen, u_char *sig, int *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;
+       int 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 (-1);
+
+       eom = msg + *msglen;
+
+       recstart = ns_find_tsig(msg, eom);
+       if (recstart == NULL)
+               return (NS_TSIG_ERROR_NO_TSIG);
+
+       cp = recstart;
+
+       /* Read the key name. */
+       n = dn_expand(msg, eom, cp, name, MAXDNAME);
+       if (n < 0)
+               return (NS_TSIG_ERROR_FORMERR);
+       cp += n;
+
+       /* Read the type. */
+       BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ);
+       GETSHORT(type, cp);
+       if (type != ns_t_tsig)
+               return (NS_TSIG_ERROR_NO_TSIG);
+
+       /* Skip the class and TTL, save the length. */
+       cp += INT16SZ + INT32SZ;
+       GETSHORT(length, cp);
+       if (eom - cp != length)
+               return (NS_TSIG_ERROR_FORMERR);
+
+       /* Read the algorithm name. */
+       rdatastart = cp;
+       n = dn_expand(msg, eom, cp, alg, MAXDNAME);
+       if (n < 0)
+               return (NS_TSIG_ERROR_FORMERR);
+       if (ns_samename(alg, NS_TSIG_ALG_HMAC_MD5) != 1)
+               return (-ns_r_badkey);
+       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 (NS_TSIG_ERROR_FORMERR);
+
+       /* Verify that the key used is OK. */
+       if (key != NULL) {
+               if (key->dk_alg != KEY_HMAC_MD5)
+                       return (-ns_r_badkey);
+               if (error != ns_r_badsig && error != ns_r_badkey) {
+                       if (ns_samename(key->dk_key_name, name) != 1)
+                               return (-ns_r_badkey);
+               }
+       }
+
+       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];
+               u_char buf2[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, recstart - msg,
+                               NULL, 0);
+
+               /* Digest the key name. */
+               n = ns_name_pton(name, buf2, sizeof(buf2));
+               if (n < 0)
+                       return (-1);
+               n = ns_name_ntol(buf2, buf, sizeof(buf));
+               if (n < 0)
+                       return (-1);
+               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_pton(alg, buf2, sizeof(buf2));
+               if (n < 0)
+                       return (-1);
+               n = ns_name_ntol(buf2, buf, sizeof(buf));
+               if (n < 0)
+                       return (-1);
+               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,
+                               otherfieldlen + INT16SZ + INT16SZ, NULL, 0);
+
+               n = dst_verify_data(SIG_MODE_FINAL, key, &ctx, NULL, 0,
+                                   sigstart, sigfieldlen);
+
+               if (n < 0)
+                       return (-ns_r_badsig);
+
+               if (sig != NULL && siglen != NULL) {
+                       if (*siglen < sigfieldlen)
+                               return (NS_TSIG_ERROR_NO_SPACE);
+                       memcpy(sig, sigstart, sigfieldlen);
+                       *siglen = sigfieldlen;
+               }
+       } else {
+               if (sigfieldlen > 0)
+                       return (NS_TSIG_ERROR_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 (-ns_r_badtime);
+
+       if (nostrip == 0) {
+               *msglen = recstart - msg;
+               hp->arcount = htons(ntohs(hp->arcount) - 1);
+       }
+
+       if (error != NOERROR)
+               return (error);
+
+       return (0);
+}
+
+int
+ns_verify_tcp_init(void *k, const u_char *querysig, int querysiglen,
+                  ns_tcp_tsig_state *state)
+{
+       dst_init();
+       if (state == NULL || k == NULL || querysig == NULL || querysiglen < 0)
+               return (-1);
+       state->counter = -1;
+       state->key = k;
+       if (state->key->dk_alg != KEY_HMAC_MD5)
+               return (-ns_r_badkey);
+       if (querysiglen > (int)sizeof(state->sig))
+               return (-1);
+       memcpy(state->sig, querysig, querysiglen);
+       state->siglen = querysiglen;
+       return (0);
+}
+
+int
+ns_verify_tcp(u_char *msg, int *msglen, ns_tcp_tsig_state *state,
+             int required)
+{
+       HEADER *hp = (HEADER *)msg;
+       u_char *recstart, *rdatastart, *sigstart;
+       unsigned int 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 (-1);
+
+       state->counter++;
+       if (state->counter == 0)
+               return (ns_verify(msg, msglen, state->key,
+                                 state->sig, state->siglen,
+                                 state->sig, &state->siglen, &timesigned, 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 (NS_TSIG_ERROR_NO_TSIG);
+               dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
+                               msg, *msglen, NULL, 0);
+               return (0);
+       }
+
+       hp->arcount = htons(ntohs(hp->arcount) - 1);
+       dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
+                       msg, recstart - msg, NULL, 0);
+       
+       /* Read the key name. */
+       n = dn_expand(msg, eom, cp, name, MAXDNAME);
+       if (n < 0)
+               return (NS_TSIG_ERROR_FORMERR);
+       cp += n;
+
+       /* Read the type. */
+       BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ);
+       GETSHORT(type, cp);
+       if (type != ns_t_tsig)
+               return (NS_TSIG_ERROR_NO_TSIG);
+
+       /* Skip the class and TTL, save the length. */
+       cp += INT16SZ + INT32SZ;
+       GETSHORT(length, cp);
+       if (eom - cp != length)
+               return (NS_TSIG_ERROR_FORMERR);
+
+       /* Read the algorithm name. */
+       rdatastart = cp;
+       n = dn_expand(msg, eom, cp, alg, MAXDNAME);
+       if (n < 0)
+               return (NS_TSIG_ERROR_FORMERR);
+       if (ns_samename(alg, NS_TSIG_ALG_HMAC_MD5) != 1)
+               return (-ns_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 (-ns_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 (NS_TSIG_ERROR_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, cp2 - buf, NULL, 0);
+
+       n = dst_verify_data(SIG_MODE_FINAL, state->key, &state->ctx, NULL, 0,
+                           sigstart, sigfieldlen);
+       if (n < 0)
+               return (-ns_r_badsig);
+
+       if (sigfieldlen > sizeof(state->sig))
+               return (NS_TSIG_ERROR_NO_SPACE);
+
+       memcpy(state->sig, sigstart, sigfieldlen);
+       state->siglen = sigfieldlen;
+
+       /* Verify the time. */
+       if (abs(timesigned - time(NULL)) > fudge)
+               return (-ns_r_badtime);
+
+       *msglen = recstart - msg;
+
+       if (error != NOERROR)
+               return (error);
+
+       return (0);
+}
diff --git a/lib/bind/port_after.h.in b/lib/bind/port_after.h.in
new file mode 100644 (file)
index 0000000..c692536
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef port_after_h
+#define port_after_h
+
+@NEED_PSELECT@
+@HAVE_SA_LEN@
+@HAVE_MINIMUM_IFREQ@
+
+/* XXX sunos and cygwin needs O_NDELAY */
+#define PORT_NONBLOCK O_NONBLOCK
+
+#endif
diff --git a/lib/bind/port_before.h.in b/lib/bind/port_before.h.in
new file mode 100644 (file)
index 0000000..6210c7c
--- /dev/null
@@ -0,0 +1,110 @@
+#ifndef port_before_h
+#define port_before_h
+
+@WANT_IRS_GR@
+@WANT_IRS_NIS@
+@WANT_IRS_PW@
+
+#define gettimeofday isc__gettimeofday
+
+@DO_PTHREADS@
+@GETGROUPLIST_ARGS@
+@GETNETBYADDR_ADDR_T@
+
+@NET_R_ARGS@
+@NET_R_BAD@
+@NET_R_COPY@
+@NET_R_COPY_ARGS@
+@NET_R_END_RESULT@
+@NET_R_END_RETURN@
+@NET_R_ENT_ARGS@
+@NET_R_OK@
+@NET_R_RETURN@
+@NET_R_SET_RESULT@
+@NET_R_SET_RETURN@
+
+@GROUP_R_RETURN@
+@GROUP_R_SET_RETURN@
+@GROUP_R_SET_RESULT@
+@GROUP_R_END_RETURN@
+@GROUP_R_END_RESULT@
+@GROUP_R_ARGS@
+@GROUP_R_ENT_ARGS@
+@GROUP_R_OK@
+@GROUP_R_BAD@
+
+@HOST_R_ARGS@
+@HOST_R_BAD@
+@HOST_R_COPY@
+@HOST_R_COPY_ARGS@
+@HOST_R_END_RESULT@
+@HOST_R_END_RETURN@
+@HOST_R_ENT_ARGS@
+@HOST_R_ERRNO@
+@HOST_R_OK@
+@HOST_R_RETURN@
+@HOST_R_SET_RESULT@
+@HOST_R_SET_RETURN@
+
+
+@SETPWENT_VOID@
+
+@NGR_R_ARGS@
+@NGR_R_BAD@
+@NGR_R_COPY@
+@NGR_R_COPY_ARGS@
+@NGR_R_END_RESULT@
+@NGR_R_END_RETURN@
+@NGR_R_ENT_ARGS@
+@NGR_R_OK@
+@NGR_R_RETURN@
+@NGR_R_SET_RESULT@
+@NGR_R_SET_RETURN@
+
+@PROTO_R_ARGS@
+@PROTO_R_BAD@
+@PROTO_R_COPY@
+@PROTO_R_COPY_ARGS@
+@PROTO_R_END_RESULT@
+@PROTO_R_END_RETURN@
+@PROTO_R_ENT_ARGS@
+@PROTO_R_OK@
+@PROTO_R_RETURN@
+@PROTO_R_SET_RESULT@
+@PROTO_R_SET_RETURN@
+
+@PASS_R_ARGS@
+@PASS_R_BAD@
+@PASS_R_COPY@
+@PASS_R_COPY_ARGS@
+@PASS_R_END_RESULT@
+@PASS_R_END_RETURN@
+@PASS_R_ENT_ARGS@
+@PASS_R_OK@
+@PASS_R_RETURN@
+@PASS_R_SET_RESULT@
+@PASS_R_SET_RETURN@
+
+@SERV_R_ARGS@
+@SERV_R_BAD@
+@SERV_R_COPY@
+@SERV_R_COPY_ARGS@
+@SERV_R_END_RESULT@
+@SERV_R_END_RETURN@
+@SERV_R_ENT_ARGS@
+@SERV_R_OK@
+@SERV_R_RETURN@
+@SERV_R_SET_RESULT@
+@SERV_R_SET_RETURN@
+
+
+#define DE_CONST(konst, var) \
+        do { \
+                union { const void *k; void *v; } _u; \
+                _u.k = konst; \
+                var = _u.v; \
+        } while (0)
+
+#define UNUSED(x) (x) = (x)
+
+#endif
diff --git a/lib/bind/prand_conf.c b/lib/bind/prand_conf.c
new file mode 100644 (file)
index 0000000..5cd5152
--- /dev/null
@@ -0,0 +1,219 @@
+/* $Id: prand_conf.c,v 1.1 2001/03/29 06:30:30 marka Exp $
+ *
+ * Portions Copyright (c) 1995-1998 by TIS Labs at Network Assoociates Inc.
+ * Portions Copyright (c) 1998-1998 by TIS Labs @ Network Associates 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 NETWORK ASSOCIATES
+ * 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.
+ *
+ * program to find where system commands reside 
+ * and what directores are avialable for inspection 
+ * this information is stored in the file prand_conf.h in current directory
+ *
+ * function my_find get variable number of arguments
+ * the first argument is the name of the command 
+ * all remaining arguments are list of directories to search for the command in
+ * this function returns the path to the command
+ */
+
+#include <sys/stat.h>
+#include <unistd.h>
+#include <time.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#define LINE_MAX 256
+
+static int 
+my_find(const char *cmd, const char **dir)
+{
+       unsigned int curr = 0, c_len, i;
+       char cmd_line[LINE_MAX];
+       
+       memset(cmd_line, 0, sizeof(cmd_line));
+       c_len = strlen(cmd);
+       for (i = 0; dir[i]; i++) {
+               curr = strlen(dir[i]);
+               if (curr + c_len < sizeof(cmd_line)-3) {
+                       sprintf(cmd_line, "%s%s",dir[i], cmd);
+                       if (access(cmd_line, X_OK) == 0) 
+                               return (i);
+                       memset(cmd_line, 0, c_len + curr + 2);
+               }
+       }
+       return (0);
+}
+
+/* 
+ * function to simulate the ` ` operator in perl  return the number
+ * of bytes read from the pipe 
+ */
+static int
+pipe_run(char *cmd_line)
+{
+       FILE *pd;
+       char scratch[LINE_MAX];
+       int ex, no_bytes = 0, no = 1;
+
+       pd = popen(cmd_line, "r");
+       for (; (pd != NULL) && (no > 0); no_bytes += no) 
+               no = fread(scratch, sizeof(char), sizeof(scratch), pd);
+       ex = pclose(pd);
+       return (no_bytes);
+}
+
+/*
+ * function that executes a command with certain flags and checks that the
+ * output is at least certain length
+ * First parameter the command 
+ * Second parameter is ther flags 
+ * third parameter is the number of bytes required 
+ * output is 1 if the command works 0 if not 
+ * This function writes to the include file if
+ */
+static int 
+ex(FILE *fd, const char *path, const char *cmd, const char *arg,
+   int lower_bound)
+{
+       char line[LINE_MAX];
+
+       if (strlen(path) + strlen(cmd) + strlen(arg) < sizeof(line)-7) { 
+               memset(line, 0, sizeof(line));
+               sprintf(line, "%s%s %s 2>&1", path, cmd, arg);
+               if (pipe_run(line) > lower_bound) {
+                       fprintf(fd,"\t\"%s\",\n", line);
+                       return (1);
+               }
+       }
+       return (0);
+}
+
+int 
+main() 
+{
+       extern int errno;
+       FILE *fd;
+       int res, vm, i;
+       int ps, arp, net, dig, cmd;
+/*
+ * set up list of directories where each command may be found in 
+ */
+       const char *arp_path[] = {"/usr/sbin", "/sbin", "/usr/etc/", "/etc/", 
+                          "/usr/bin/", NULL};
+       const char *ps_path[] = {"/usr/bin", "/bin/", NULL};
+       const char *net_path[]  = {"/usr/ucb/", "/usr/bin/", "/usr/etc/", 
+                            "/usr/sbin/", "/bin/", NULL};
+       const char *dig_path[] = {"/usr/bin/", "/usr/local/bin/", NULL};
+       const char **df_path  = ps_path;
+       const char *uptime_path[] = {"/usr/ucb/", "/usr/bin/", "/usr/bsd/", NULL};
+       const char *iostat_path[] = { "/usr/bin/", "/bin/", "/usr/sbin/", NULL};
+       const char *vmstat_path[] = {"/usr/ucb/", "/usr/bin/", "/usr/sbin/", NULL};
+       const char *vm_stat_path[] = {"/usr/ucb/", "/usr/bin/", NULL};
+       const char **w_path = uptime_path;
+
+/* find which directories exist  */
+       const char *dirs[] = {"/tmp", "/usr/tmp", "/var/tmp", ".", "/",  
+                       "/var/spool", "/usr/spool", 
+                       "/usr/adm", "/var/adm", "/dev", 
+                       "/usr/mail", "/var/spool/mail", "/var/mail", 
+                       "/home", "/usr/home", NULL};
+
+       const char *files[] = {"/proc/stat", "/proc/rtc", "/proc/meminfo", 
+                        "/proc/interrupts",  "/proc/self/status", 
+                        "/proc/self/maps",  "/proc/curproc/status",
+                        "/proc/curproc/map",
+                        "/var/log/messages", "/var/log/wtmp", 
+                        "/var/log/lastlog", "/var/adm/messages", 
+                        "/var/adm/wtmp", "/var/adm/lastlog", NULL};
+
+       struct stat st;
+       time_t tim;
+/* main program: */
+
+       if ((fd = fopen("prand_conf.h", "w")) == NULL) {
+               perror("Failed creating file prand_conf.h");
+               exit(errno);
+       }
+
+       fprintf(fd, "#ifndef _PRAND_CMD_H_\n#define _PRAND_CMD_H_\n\n");
+
+       fprintf(fd, "static const char *cmds[] = {\n");
+       
+       if ((ps = my_find("ps", ps_path)) >= 0)
+               res = ex(fd, ps_path[ps], "ps","-axlw", 460) || 
+                       ex(fd, ps_path[ps], "ps", "-ef", 300) || 
+                               ex(fd, ps_path[ps], "ps", "-ale", 300);
+
+       if ((arp = my_find("arp", arp_path)) >= 0) 
+           res = ex(fd, arp_path[arp], "arp", "-n -a", 40);
+
+       if ((net = my_find("netstat", net_path)) >= 0)
+               res = ex(fd, net_path[net], "netstat", "-an", 1000);
+       if ((cmd = my_find("df", df_path)) >= 0)
+               res = ex(fd, df_path[cmd], "df", "", 40);
+
+       if ((dig = my_find("dig", dig_path)) >= 0)
+               res = ex(fd, dig_path[dig], "dig", "com. soa +ti=1 +retry=0", 
+                        100);
+       if ((cmd = my_find("uptime", uptime_path)) >= 0)
+            res = ex(fd, uptime_path[cmd], "uptime", "", 40);
+       if ((cmd = my_find("printenv", uptime_path)) >= 0)
+            res = ex(fd, uptime_path[cmd], "printenv", "", 400);
+       if (net >= 0)
+               res = ex(fd, net_path[net], "netstat", "-s", 1000);
+
+       if (dig >= 0)
+               res = ex(fd, net_path[net], "dig", ". soa +ti=1 +retry=0",100);
+       if ((cmd = my_find("iostat", iostat_path)) >= 0)
+               res = ex(fd, iostat_path[cmd], "iostat", "", 100);
+
+       vm  = 0;
+       if ((cmd = my_find("vmstat", vmstat_path)))
+               vm = ex(fd, vmstat_path[cmd], "vmstat", "", 200);
+       if (vm ==0 && ((cmd = my_find("vm_stat", vm_stat_path)) >= 0))
+           vm = ex(fd, vm_stat_path[cmd], "vm_stat", "", 200);
+       if ((cmd = my_find("w", w_path)))
+               res = ex(fd, w_path[cmd], "w", "", 100);
+       fprintf(fd,"\tNULL\n};\n\n");
+
+       fprintf(fd, "static const char *dirs[] = {\n");
+
+       for (i=0; dirs[i]; i++) { 
+               if (lstat(dirs[i], &st) == 0) 
+                       if (S_ISDIR(st.st_mode))
+                               fprintf(fd,"\t\"%s\",\n", dirs[i]);
+       }
+       fprintf(fd,"\tNULL\n};\n\n");
+
+
+       fprintf(fd, "static const char *files[] = {\n");
+       tim = time(NULL);
+       for (i=0; files[i]; i++) {
+               if (lstat(files[i],&st) == 0)
+                       if (S_ISREG(st.st_mode) && 
+                           (tim - st.st_mtime) < 84600) 
+                               fprintf(fd,"\t\"%s\",\n", files[i]);
+       }
+       fprintf (fd, "\tNULL\n};\n");
+               
+       if ((stat("/dev/random", &st) == 0))
+               if (S_ISCHR(st.st_mode))
+                       fprintf(fd, "\n#ifndef HAVE_DEV_RANDOM\n%s%s",
+                               "# define HAVE_DEV_RANDOM 1\n",
+                               "#endif /* HAVE_DEV_RANDOM */\n\n");
+
+       fprintf(fd, "\n#endif /* _PRAND_CMD_H_ */\n");
+       fclose(fd);
+       exit (0);
+}
diff --git a/lib/bind/resolv/Makefile.in b/lib/bind/resolv/Makefile.in
new file mode 100644 (file)
index 0000000..3d4d6a5
--- /dev/null
@@ -0,0 +1,14 @@
+OBJS=  herror.@O@ res_comp.@O@ res_data.@O@ res_debug.@O@ \
+       res_findzonecut.@O@ res_init.@O@ res_mkquery.@O@ res_mkupdate.@O@ \
+       res_query.@O@ res_send.@O@ res_sendsigned.@O@ res_update.@O@
+
+SRCS=  herror.c res_comp.c res_data.c res_debug.c \
+       res_findzonecut.c res_init.c res_mkquery.c res_mkupdate.c \
+       res_query.c res_send.c res_sendsigned.c res_update.c
+
+TARGETS= ${OBJS}
+
+CINCLUDES= -I.. -I../include
+CWARNINGS=
+
+@BIND9_MAKE_RULES@
diff --git a/lib/bind/resolv/herror.c b/lib/bind/resolv/herror.c
new file mode 100644 (file)
index 0000000..e7e060d
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 1987, 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) 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[] = "@(#)herror.c     8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: herror.c,v 1.1 2001/03/29 06:31:58 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/uio.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <netdb.h>
+#include <resolv.h>
+#include <string.h>
+#include <unistd.h>
+#include <irs.h>
+
+#include "port_after.h"
+#undef h_errno
+
+const char *h_errlist[] = {
+       "Resolver Error 0 (no error)",
+       "Unknown host",                         /* 1 HOST_NOT_FOUND */
+       "Host name lookup failure",             /* 2 TRY_AGAIN */
+       "Unknown server error",                 /* 3 NO_RECOVERY */
+       "No address associated with name",      /* 4 NO_ADDRESS */
+};
+int    h_nerr = { sizeof h_errlist / sizeof h_errlist[0] };
+
+int    h_errno;
+
+/*
+ * herror --
+ *     print the error indicated by the h_errno value.
+ */
+void
+herror(const char *s) {
+       struct iovec iov[4], *v = iov;
+       extern int * __h_errno();
+       char *t;
+
+       if (s != NULL && *s != '\0') {
+               DE_CONST(s, t);
+               v->iov_base = t;
+               v->iov_len = strlen(t);
+               v++;
+               DE_CONST(": ", t);
+               v->iov_base = t;
+               v->iov_len = 2;
+               v++;
+       }
+       DE_CONST(hstrerror(*__h_errno()), t);
+       v->iov_base = t;
+       v->iov_len = strlen(v->iov_base);
+       v++;
+       DE_CONST("\n", t);
+       v->iov_base = t;
+       v->iov_len = 1;
+       writev(STDERR_FILENO, iov, (v - iov) + 1);
+}
+
+/*
+ * hstrerror --
+ *     return the string associated with a given "host" errno value.
+ */
+const char *
+hstrerror(int err) {
+       if (err < 0)
+               return ("Resolver internal error");
+       else if (err < h_nerr)
+               return (h_errlist[err]);
+       return ("Unknown resolver error");
+}
diff --git a/lib/bind/resolv/res_comp.c b/lib/bind/resolv/res_comp.c
new file mode 100644 (file)
index 0000000..cb86b3f
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * 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.1 2001/03/29 06:31:58 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+#include <sys/types.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <ctype.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "port_after.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, int 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, int 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.
+ */
+
+/*
+ * 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);
+}
+
+#ifdef BIND_4_COMPAT
+/*
+ * This module must export the following externally-visible symbols:
+ *     ___putlong
+ *     ___putshort
+ *     __getlong
+ *     __getshort
+ * Note that one _ comes from C and the others come from us.
+ */
+void __putlong(u_int32_t src, u_char *dst) { ns_put32(src, dst); }
+void __putshort(u_int16_t src, u_char *dst) { ns_put16(src, dst); }
+#ifndef __ultrix__
+u_int32_t _getlong(const u_char *src) { return (ns_get32(src)); }
+u_int16_t _getshort(const u_char *src) { return (ns_get16(src)); }
+#endif /*__ultrix__*/
+#endif /*BIND_4_COMPAT*/
diff --git a/lib/bind/resolv/res_data.c b/lib/bind/resolv/res_data.c
new file mode 100644 (file)
index 0000000..70eb070
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: res_data.c,v 1.1 2001/03/29 06:31:58 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+
+#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 <arpa/nameser.h>
+
+#include <ctype.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <res_update.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "port_after.h"
+#undef _res
+
+const char *_res_opcodes[] = {
+       "QUERY",
+       "IQUERY",
+       "CQUERYM",
+       "CQUERYU",      /* experimental */
+       "NOTIFY",       /* experimental */
+       "UPDATE",
+       "6",
+       "7",
+       "8",
+       "9",
+       "10",
+       "11",
+       "12",
+       "13",
+       "ZONEINIT",
+       "ZONEREF",
+};
+
+#ifdef BIND_UPDATE
+const char *_res_sectioncodes[] = {
+       "ZONE",
+       "PREREQUISITES",
+       "UPDATE",
+       "ADDITIONAL",
+};
+#endif
+
+#ifndef __BIND_NOSTATIC
+struct __res_state _res
+# if defined(__BIND_RES_TEXT)
+       = { RES_TIMEOUT, }      /* Motorola, et al. */
+# endif
+        ;
+
+/* Proto. */
+
+int  res_ourserver_p(const res_state, const struct sockaddr_in *);
+
+int
+res_init(void) {
+       extern int __res_vinit(res_state, int);
+
+       /*
+        * These three fields used to be statically initialized.  This made
+        * it hard to use this code in a shared library.  It is necessary,
+        * now that we're doing dynamic initialization here, that we preserve
+        * the old semantics: if an application modifies one of these three
+        * fields of _res before res_init() is called, res_init() will not
+        * alter them.  Of course, if an application is setting them to
+        * _zero_ before calling res_init(), hoping to override what used
+        * to be the static default, we can't detect it and unexpected results
+        * will follow.  Zero for any of these fields would make no sense,
+        * so one can safely assume that the applications were already getting
+        * unexpected results.
+        *
+        * _res.options is tricky since some apps were known to diddle the bits
+        * before res_init() was first called. We can't replicate that semantic
+        * with dynamic initialization (they may have turned bits off that are
+        * set in RES_DEFAULT).  Our solution is to declare such applications
+        * "broken".  They could fool us by setting RES_INIT but none do (yet).
+        */
+       if (!_res.retrans)
+               _res.retrans = RES_TIMEOUT;
+       if (!_res.retry)
+               _res.retry = 4;
+       if (!(_res.options & RES_INIT))
+               _res.options = RES_DEFAULT;
+
+       /*
+        * This one used to initialize implicitly to zero, so unless the app
+        * has set it to something in particular, we can randomize it now.
+        */
+       if (!_res.id)
+               _res.id = res_randomid();
+
+       return (__res_vinit(&_res, 1));
+}
+
+void
+p_query(const u_char *msg) {
+       fp_query(msg, stdout);
+}
+
+void
+fp_query(const u_char *msg, FILE *file) {
+       fp_nquery(msg, PACKETSZ, file);
+}
+
+void
+fp_nquery(const u_char *msg, int len, FILE *file) {
+       if ((_res.options & RES_INIT) == 0 && res_init() == -1)
+               return;
+
+       res_pquery(&_res, msg, len, file);
+}
+
+int
+res_mkquery(int op,                    /* opcode of query */
+           const char *dname,          /* domain name */
+           int class, int type,        /* class and type of query */
+           const u_char *data,         /* resource record data */
+           int datalen,                /* length of data */
+           const u_char *newrr_in,     /* new rr for modify or append */
+           u_char *buf,                /* buffer to put query */
+           int buflen)                 /* size of buffer */
+{
+       if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
+               RES_SET_H_ERRNO(&_res, NETDB_INTERNAL);
+               return (-1);
+       }
+       return (res_nmkquery(&_res, op, dname, class, type,
+                            data, datalen,
+                            newrr_in, buf, buflen));
+}
+
+int
+res_mkupdate(ns_updrec *rrecp_in, u_char *buf, int buflen) {
+       if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
+               RES_SET_H_ERRNO(&_res, NETDB_INTERNAL);
+               return (-1);
+       }
+
+       return (res_nmkupdate(&_res, rrecp_in, buf, buflen));
+}
+
+int
+res_query(const char *name,    /* domain name */
+         int class, int type,  /* class and type of query */
+         u_char *answer,       /* buffer to put answer */
+         int anslen)           /* size of answer buffer */
+{
+       if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
+               RES_SET_H_ERRNO(&_res, NETDB_INTERNAL);
+               return (-1);
+       }
+       return (res_nquery(&_res, name, class, type, answer, anslen));
+}
+
+void
+res_send_setqhook(res_send_qhook hook) {
+       _res.qhook = hook;
+}
+
+void
+res_send_setrhook(res_send_rhook hook) {
+       _res.rhook = hook;
+}
+
+int
+res_isourserver(const struct sockaddr_in *inp) {
+       return (res_ourserver_p(&_res, inp));
+}
+
+int
+res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) {
+       if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
+               /* errno should have been set by res_init() in this case. */
+               return (-1);
+       }
+
+       return (res_nsend(&_res, buf, buflen, ans, anssiz));
+}
+
+int
+res_sendsigned(const u_char *buf, int buflen, ns_tsig_key *key,
+              u_char *ans, int anssiz)
+{
+       if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
+               /* errno should have been set by res_init() in this case. */
+               return (-1);
+       }
+
+       return (res_nsendsigned(&_res, buf, buflen, key, ans, anssiz));
+}
+
+void
+res_close(void) {
+       res_nclose(&_res);
+}
+
+int
+res_update(ns_updrec *rrecp_in) {
+       if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
+               RES_SET_H_ERRNO(&_res, NETDB_INTERNAL);
+               return (-1);
+       }
+
+       return (res_nupdate(&_res, rrecp_in, NULL));
+}
+
+int
+res_search(const char *name,   /* domain name */
+          int class, int type, /* class and type of query */
+          u_char *answer,      /* buffer to put answer */
+          int anslen)          /* size of answer */
+{
+       if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
+               RES_SET_H_ERRNO(&_res, NETDB_INTERNAL);
+               return (-1);
+       }
+
+       return (res_nsearch(&_res, name, class, type, answer, anslen));
+}
+
+int
+res_querydomain(const char *name,
+               const char *domain,
+               int class, int type,    /* class and type of query */
+               u_char *answer,         /* buffer to put answer */
+               int anslen)             /* size of answer */
+{
+       if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
+               RES_SET_H_ERRNO(&_res, NETDB_INTERNAL);
+               return (-1);
+       }
+
+       return (res_nquerydomain(&_res, name, domain,
+                                class, type,
+                                answer, anslen));
+}
+
+const char *
+hostalias(const char *name) {
+       static char abuf[MAXDNAME];
+
+       return (res_hostalias(&_res, name, abuf, sizeof abuf));
+}
+
+#ifdef ultrix
+int
+local_hostname_length(const char *hostname) {
+       int len_host, len_domain;
+
+       if (!*_res.defdname)
+               res_init();
+       len_host = strlen(hostname);
+       len_domain = strlen(_res.defdname);
+       if (len_host > len_domain &&
+           !strcasecmp(hostname + len_host - len_domain, _res.defdname) &&
+           hostname[len_host - len_domain - 1] == '.')
+               return (len_host - len_domain - 1);
+       return (0);
+}
+#endif /*ultrix*/
+
+#endif
diff --git a/lib/bind/resolv/res_debug.c b/lib/bind/resolv/res_debug.c
new file mode 100644 (file)
index 0000000..ee28a8e
--- /dev/null
@@ -0,0 +1,1063 @@
+/*
+ * Copyright (c) 1985
+ *    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) 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.
+ */
+
+/*
+ * 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_debug.c  8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: res_debug.c,v 1.1 2001/03/29 06:31:58 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <math.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "port_after.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) sprintf x
+#endif
+
+extern const char *_res_opcodes[];
+extern const char *_res_sectioncodes[];
+
+/*
+ * Print the current options.
+ */
+void
+fp_resstat(const res_state statp, FILE *file) {
+       u_long mask;
+
+       fprintf(file, ";; res options:");
+       for (mask = 1;  mask != 0;  mask <<= 1)
+               if (statp->options & mask)
+                       fprintf(file, " %s", p_option(mask));
+       putc('\n', file);
+}
+
+static void
+do_section(const res_state statp,
+          ns_msg *handle, ns_sect section,
+          int pflag, FILE *file)
+{
+       int n, sflag, rrnum;
+       static int buflen = 2048;
+       char *buf;
+       ns_opcode opcode;
+       ns_rr rr;
+
+       /*
+        * Print answer records.
+        */
+       sflag = (statp->pfcode & pflag);
+       if (statp->pfcode && !sflag)
+               return;
+
+       buf = malloc(buflen);
+       if (buf == NULL) {
+               fprintf(file, ";; memory allocation failure\n");
+               return;
+       }
+
+       opcode = (ns_opcode) ns_msg_getflag(*handle, ns_f_opcode);
+       rrnum = 0;
+       for (;;) {
+               if (ns_parserr(handle, section, rrnum, &rr)) {
+                       if (errno != ENODEV)
+                               fprintf(file, ";; ns_parserr: %s\n",
+                                       strerror(errno));
+                       else if (rrnum > 0 && sflag != 0 &&
+                                (statp->pfcode & RES_PRF_HEAD1))
+                               putc('\n', file);
+                       goto cleanup;
+               }
+               if (rrnum == 0 && sflag != 0 && (statp->pfcode & RES_PRF_HEAD1))
+                       fprintf(file, ";; %s SECTION:\n",
+                               p_section(section, opcode));
+               if (section == ns_s_qd)
+                       fprintf(file, ";;\t%s, type = %s, class = %s\n",
+                               ns_rr_name(rr),
+                               p_type(ns_rr_type(rr)),
+                               p_class(ns_rr_class(rr)));
+               else {
+                       n = ns_sprintrr(handle, &rr, NULL, NULL,
+                                       buf, buflen);
+                       if (n < 0) {
+                               if (errno == ENOSPC) {
+                                       free(buf);
+                                       buf = NULL;
+                                       if (buflen < 131072)
+                                               buf = malloc(buflen += 1024);
+                                       if (buf == NULL) {
+                                               fprintf(file,
+                                             ";; memory allocation failure\n");
+                                             return;
+                                       }
+                                       continue;
+                               }
+                               fprintf(file, ";; ns_sprintrr: %s\n",
+                                       strerror(errno));
+                               goto cleanup;
+                       }
+                       fputs(buf, file);
+                       fputc('\n', file);
+               }
+               rrnum++;
+       }
+ cleanup:
+       if (buf != NULL)
+               free(buf);
+}
+
+/*
+ * Print the contents of a query.
+ * This is intended to be primarily a debugging routine.
+ */
+void
+res_pquery(const res_state statp, const u_char *msg, int len, FILE *file) {
+       ns_msg handle;
+       int qdcount, ancount, nscount, arcount;
+       u_int opcode, rcode, id;
+
+       if (ns_initparse(msg, len, &handle) < 0) {
+               fprintf(file, ";; ns_initparse: %s\n", strerror(errno));
+               return;
+       }
+       opcode = ns_msg_getflag(handle, ns_f_opcode);
+       rcode = ns_msg_getflag(handle, ns_f_rcode);
+       id = ns_msg_id(handle);
+       qdcount = ns_msg_count(handle, ns_s_qd);
+       ancount = ns_msg_count(handle, ns_s_an);
+       nscount = ns_msg_count(handle, ns_s_ns);
+       arcount = ns_msg_count(handle, ns_s_ar);
+
+       /*
+        * Print header fields.
+        */
+       if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEADX) || rcode)
+               fprintf(file,
+                       ";; ->>HEADER<<- opcode: %s, status: %s, id: %d\n",
+                       _res_opcodes[opcode], p_rcode(rcode), id);
+       if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEADX))
+               putc(';', file);
+       if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEAD2)) {
+               fprintf(file, "; flags:");
+               if (ns_msg_getflag(handle, ns_f_qr))
+                       fprintf(file, " qr");
+               if (ns_msg_getflag(handle, ns_f_aa))
+                       fprintf(file, " aa");
+               if (ns_msg_getflag(handle, ns_f_tc))
+                       fprintf(file, " tc");
+               if (ns_msg_getflag(handle, ns_f_rd))
+                       fprintf(file, " rd");
+               if (ns_msg_getflag(handle, ns_f_ra))
+                       fprintf(file, " ra");
+               if (ns_msg_getflag(handle, ns_f_z))
+                       fprintf(file, " ??");
+               if (ns_msg_getflag(handle, ns_f_ad))
+                       fprintf(file, " ad");
+               if (ns_msg_getflag(handle, ns_f_cd))
+                       fprintf(file, " cd");
+       }
+       if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEAD1)) {
+               fprintf(file, "; %s: %d",
+                       p_section(ns_s_qd, opcode), qdcount);
+               fprintf(file, ", %s: %d",
+                       p_section(ns_s_an, opcode), ancount);
+               fprintf(file, ", %s: %d",
+                       p_section(ns_s_ns, opcode), nscount);
+               fprintf(file, ", %s: %d",
+                       p_section(ns_s_ar, opcode), arcount);
+       }
+       if ((!statp->pfcode) || (statp->pfcode & 
+               (RES_PRF_HEADX | RES_PRF_HEAD2 | RES_PRF_HEAD1))) {
+               putc('\n',file);
+       }
+       /*
+        * Print the various sections.
+        */
+       do_section(statp, &handle, ns_s_qd, RES_PRF_QUES, file);
+       do_section(statp, &handle, ns_s_an, RES_PRF_ANS, file);
+       do_section(statp, &handle, ns_s_ns, RES_PRF_AUTH, file);
+       do_section(statp, &handle, ns_s_ar, RES_PRF_ADD, file);
+       if (qdcount == 0 && ancount == 0 &&
+           nscount == 0 && arcount == 0)
+               putc('\n', file);
+}
+
+const u_char *
+p_cdnname(const u_char *cp, const u_char *msg, int len, FILE *file) {
+       char name[MAXDNAME];
+       int n;
+
+       if ((n = dn_expand(msg, msg + len, cp, name, sizeof name)) < 0)
+               return (NULL);
+       if (name[0] == '\0')
+               putc('.', file);
+       else
+               fputs(name, file);
+       return (cp + n);
+}
+
+const u_char *
+p_cdname(const u_char *cp, const u_char *msg, FILE *file) {
+       return (p_cdnname(cp, msg, PACKETSZ, file));
+}
+
+/* Return a fully-qualified domain name from a compressed name (with
+   length supplied).  */
+
+const u_char *
+p_fqnname(cp, msg, msglen, name, namelen)
+       const u_char *cp, *msg;
+       int msglen;
+       char *name;
+       int namelen;
+{
+       int n, newlen;
+
+       if ((n = dn_expand(msg, cp + msglen, cp, name, namelen)) < 0)
+               return (NULL);
+       newlen = strlen(name);
+       if (newlen == 0 || name[newlen - 1] != '.') {
+               if (newlen + 1 >= namelen)      /* Lack space for final dot */
+                       return (NULL);
+               else
+                       strcpy(name + newlen, ".");
+       }
+       return (cp + n);
+}
+
+/* XXX:        the rest of these functions need to become length-limited, too. */
+
+const u_char *
+p_fqname(const u_char *cp, const u_char *msg, FILE *file) {
+       char name[MAXDNAME];
+       const u_char *n;
+
+       n = p_fqnname(cp, msg, MAXCDNAME, name, sizeof name);
+       if (n == NULL)
+               return (NULL);
+       fputs(name, file);
+       return (n);
+}
+
+/*
+ * Names of RR classes and qclasses.  Classes and qclasses are the same, except
+ * that C_ANY is a qclass but not a class.  (You can ask for records of class
+ * C_ANY, but you can't have any records of that class in the database.)
+ */
+const struct res_sym __p_class_syms[] = {
+       {C_IN,          "IN",           (char *)0},
+       {C_CHAOS,       "CHAOS",        (char *)0},
+       {C_HS,          "HS",           (char *)0},
+       {C_HS,          "HESIOD",       (char *)0},
+       {C_ANY,         "ANY",          (char *)0},
+       {C_NONE,        "NONE",         (char *)0},
+       {C_IN,          (char *)0,      (char *)0}
+};
+
+/*
+ * Names of message sections.
+ */
+const struct res_sym __p_default_section_syms[] = {
+       {ns_s_qd,       "QUERY",        (char *)0},
+       {ns_s_an,       "ANSWER",       (char *)0},
+       {ns_s_ns,       "AUTHORITY",    (char *)0},
+       {ns_s_ar,       "ADDITIONAL",   (char *)0},
+       {0,             (char *)0,      (char *)0}
+};
+
+const struct res_sym __p_update_section_syms[] = {
+       {S_ZONE,        "ZONE",         (char *)0},
+       {S_PREREQ,      "PREREQUISITE", (char *)0},
+       {S_UPDATE,      "UPDATE",       (char *)0},
+       {S_ADDT,        "ADDITIONAL",   (char *)0},
+       {0,             (char *)0,      (char *)0}
+};
+
+const struct res_sym __p_key_syms[] = {
+       {NS_ALG_MD5RSA,         "RSA",          "RSA KEY with MD5 hash"},
+       {NS_ALG_DH,             "DH",           "Diffie Hellman"},
+       {NS_ALG_DSA,            "DSA",          "Digital Signature Algorithm"},
+       {NS_ALG_EXPIRE_ONLY,    "EXPIREONLY",   "No algorithm"},
+       {NS_ALG_PRIVATE_OID,    "PRIVATE",      "Algorithm obtained from OID"},
+       {0,                     NULL,           NULL}
+};
+
+const struct res_sym __p_cert_syms[] = {
+       {cert_t_pkix,   "PKIX",         "PKIX (X.509v3) Certificate"},
+       {cert_t_spki,   "SPKI",         "SPKI certificate"},
+       {cert_t_pgp,    "PGP",          "PGP certificate"},
+       {cert_t_url,    "URL",          "URL Private"},
+       {cert_t_oid,    "OID",          "OID Private"},
+       {0,             NULL,           NULL}
+};
+
+/*
+ * Names of RR types and qtypes.  Types and qtypes are the same, except
+ * that T_ANY is a qtype but not a type.  (You can ask for records of type
+ * T_ANY, but you can't have any records of that type in the database.)
+ */
+const struct res_sym __p_type_syms[] = {
+       {ns_t_a,        "A",            "address"},
+       {ns_t_ns,       "NS",           "name server"},
+       {ns_t_md,       "MD",           "mail destination (deprecated)"},
+       {ns_t_mf,       "MF",           "mail forwarder (deprecated)"},
+       {ns_t_cname,    "CNAME",        "canonical name"},
+       {ns_t_soa,      "SOA",          "start of authority"},
+       {ns_t_mb,       "MB",           "mailbox"},
+       {ns_t_mg,       "MG",           "mail group member"},
+       {ns_t_mr,       "MR",           "mail rename"},
+       {ns_t_null,     "NULL",         "null"},
+       {ns_t_wks,      "WKS",          "well-known service (deprecated)"},
+       {ns_t_ptr,      "PTR",          "domain name pointer"},
+       {ns_t_hinfo,    "HINFO",        "host information"},
+       {ns_t_minfo,    "MINFO",        "mailbox information"},
+       {ns_t_mx,       "MX",           "mail exchanger"},
+       {ns_t_txt,      "TXT",          "text"},
+       {ns_t_rp,       "RP",           "responsible person"},
+       {ns_t_afsdb,    "AFSDB",        "DCE or AFS server"},
+       {ns_t_x25,      "X25",          "X25 address"},
+       {ns_t_isdn,     "ISDN",         "ISDN address"},
+       {ns_t_rt,       "RT",           "router"},
+       {ns_t_nsap,     "NSAP",         "nsap address"},
+       {ns_t_nsap_ptr, "NSAP_PTR",     "domain name pointer"},
+       {ns_t_sig,      "SIG",          "signature"},
+       {ns_t_key,      "KEY",          "key"},
+       {ns_t_px,       "PX",           "mapping information"},
+       {ns_t_gpos,     "GPOS",         "geographical position (withdrawn)"},
+       {ns_t_aaaa,     "AAAA",         "IPv6 address"},
+       {ns_t_loc,      "LOC",          "location"},
+       {ns_t_nxt,      "NXT",          "next valid name (unimplemented)"},
+       {ns_t_eid,      "EID",          "endpoint identifier (unimplemented)"},
+       {ns_t_nimloc,   "NIMLOC",       "NIMROD locator (unimplemented)"},
+       {ns_t_srv,      "SRV",          "server selection"},
+       {ns_t_atma,     "ATMA",         "ATM address (unimplemented)"},
+       {ns_t_tkey,     "TKEY",         "tkey"},
+       {ns_t_tsig,     "TSIG",         "transaction signature"},
+       {ns_t_ixfr,     "IXFR",         "incremental zone transfer"},
+       {ns_t_axfr,     "AXFR",         "zone transfer"},
+       {ns_t_zxfr,     "ZXFR",         "compressed zone transfer"},
+       {ns_t_mailb,    "MAILB",        "mailbox-related data (deprecated)"},
+       {ns_t_maila,    "MAILA",        "mail agent (deprecated)"},
+       {ns_t_naptr,    "NAPTR",        "URN Naming Authority"},
+       {ns_t_kx,       "KX",           "Key Exchange"},
+       {ns_t_cert,     "CERT",         "Certificate"},
+       {ns_t_a6,       "A6",           "IPv6 Address"},
+       {ns_t_dname,    "DNAME",        "dname"},
+       {ns_t_sink,     "SINK",         "Kitchen Sink (experimental)"},
+       {ns_t_opt,      "OPT",          "EDNS Options"},
+       {ns_t_any,      "ANY",          "\"any\""},
+       {0,             NULL,           NULL}
+};
+
+/*
+ * Names of DNS rcodes.
+ */
+const struct res_sym __p_rcode_syms[] = {
+       {ns_r_noerror,  "NOERROR",              "no error"},
+       {ns_r_formerr,  "FORMERR",              "format error"},
+       {ns_r_servfail, "SERVFAIL",             "server failed"},
+       {ns_r_nxdomain, "NXDOMAIN",             "no such domain name"},
+       {ns_r_notimpl,  "NOTIMP",               "not implemented"},
+       {ns_r_refused,  "REFUSED",              "refused"},
+       {ns_r_yxdomain, "YXDOMAIN",             "domain name exists"},
+       {ns_r_yxrrset,  "YXRRSET",              "rrset exists"},
+       {ns_r_nxrrset,  "NXRRSET",              "rrset doesn't exist"},
+       {ns_r_notauth,  "NOTAUTH",              "not authoritative"},
+       {ns_r_notzone,  "NOTZONE",              "Not in zone"},
+       {ns_r_max,      "",                     ""},
+       {ns_r_badsig,   "BADSIG",               "bad signature"},
+       {ns_r_badkey,   "BADKEY",               "bad key"},
+       {ns_r_badtime,  "BADTIME",              "bad time"},
+       {0,             NULL,                   NULL}
+};
+
+int
+sym_ston(const struct res_sym *syms, const char *name, int *success) {
+       for ((void)NULL; syms->name != 0; syms++) {
+               if (strcasecmp (name, syms->name) == 0) {
+                       if (success)
+                               *success = 1;
+                       return (syms->number);
+               }
+       }
+       if (success)
+               *success = 0;
+       return (syms->number);          /* The default value. */
+}
+
+const char *
+sym_ntos(const struct res_sym *syms, int number, int *success) {
+       static char unname[20];
+
+       for ((void)NULL; syms->name != 0; syms++) {
+               if (number == syms->number) {
+                       if (success)
+                               *success = 1;
+                       return (syms->name);
+               }
+       }
+
+       sprintf(unname, "%d", number);          /* XXX nonreentrant */
+       if (success)
+               *success = 0;
+       return (unname);
+}
+
+const char *
+sym_ntop(const struct res_sym *syms, int number, int *success) {
+       static char unname[20];
+
+       for ((void)NULL; syms->name != 0; syms++) {
+               if (number == syms->number) {
+                       if (success)
+                               *success = 1;
+                       return (syms->humanname);
+               }
+       }
+       sprintf(unname, "%d", number);          /* XXX nonreentrant */
+       if (success)
+               *success = 0;
+       return (unname);
+}
+
+/*
+ * Return a string for the type.
+ */
+const char *
+p_type(int type) {
+       return (sym_ntos(__p_type_syms, type, (int *)0));
+}
+
+/*
+ * Return a string for the type.
+ */
+const char *
+p_section(int section, int opcode) {
+       const struct res_sym *symbols;
+
+       switch (opcode) {
+       case ns_o_update:
+               symbols = __p_update_section_syms;
+               break;
+       default:
+               symbols = __p_default_section_syms;
+               break;
+       }
+       return (sym_ntos(symbols, section, (int *)0));
+}
+
+/*
+ * Return a mnemonic for class.
+ */
+const char *
+p_class(int class) {
+       return (sym_ntos(__p_class_syms, class, (int *)0));
+}
+
+/*
+ * Return a mnemonic for an option
+ */
+const char *
+p_option(u_long option) {
+       static char nbuf[40];
+
+       switch (option) {
+       case RES_INIT:          return "init";
+       case RES_DEBUG:         return "debug";
+       case RES_AAONLY:        return "aaonly(unimpl)";
+       case RES_USEVC:         return "usevc";
+       case RES_PRIMARY:       return "primry(unimpl)";
+       case RES_IGNTC:         return "igntc";
+       case RES_RECURSE:       return "recurs";
+       case RES_DEFNAMES:      return "defnam";
+       case RES_STAYOPEN:      return "styopn";
+       case RES_DNSRCH:        return "dnsrch";
+       case RES_INSECURE1:     return "insecure1";
+       case RES_INSECURE2:     return "insecure2";
+       case RES_NOALIASES:     return "noaliases";
+       case RES_USE_INET6:     return "inet6";
+#ifdef RES_USE_EDNS0   /* KAME extension */
+       case RES_USE_EDNS0:     return "edns0";
+#endif
+#ifdef RES_USE_A6
+       case RES_USE_A6:        return "a6";
+#endif
+#ifdef RES_USE_DNAME
+       case RES_USE_DNAME:     return "dname";
+#endif
+
+                               /* XXX nonreentrant */
+       default:                sprintf(nbuf, "?0x%lx?", (u_long)option);
+                               return (nbuf);
+       }
+}
+
+/*
+ * Return a mnemonic for a time to live.
+ */
+const char *
+p_time(u_int32_t value) {
+       static char nbuf[40];           /* XXX nonreentrant */
+
+       if (ns_format_ttl(value, nbuf, sizeof nbuf) < 0)
+               sprintf(nbuf, "%u", value);
+       return (nbuf);
+}
+
+/*
+ * Return a string for the rcode.
+ */
+const char *
+p_rcode(int rcode) {
+       return (sym_ntos(__p_rcode_syms, rcode, (int *)0));
+}
+
+/*
+ * routines to convert between on-the-wire RR format and zone file format.
+ * Does not contain conversion to/from decimal degrees; divide or multiply
+ * by 60*60*1000 for that.
+ */
+
+static unsigned int poweroften[10] = {1, 10, 100, 1000, 10000, 100000,
+                                     1000000,10000000,100000000,1000000000};
+
+/* takes an XeY precision/size value, returns a string representation. */
+static const char *
+precsize_ntoa(prec)
+       u_int8_t prec;
+{
+       static char retbuf[sizeof "90000000.00"];       /* XXX nonreentrant */
+       unsigned long val;
+       int mantissa, exponent;
+
+       mantissa = (int)((prec >> 4) & 0x0f) % 10;
+       exponent = (int)((prec >> 0) & 0x0f) % 10;
+
+       val = mantissa * poweroften[exponent];
+
+       (void) sprintf(retbuf, "%lu.%.2lu", val/100, val%100);
+       return (retbuf);
+}
+
+/* converts ascii size/precision X * 10**Y(cm) to 0xXY.  moves pointer. */
+static u_int8_t
+precsize_aton(strptr)
+       char **strptr;
+{
+       unsigned int mval = 0, cmval = 0;
+       u_int8_t retval = 0;
+       char *cp;
+       int exponent;
+       int mantissa;
+
+       cp = *strptr;
+
+       while (isdigit(*cp))
+               mval = mval * 10 + (*cp++ - '0');
+
+       if (*cp == '.') {               /* centimeters */
+               cp++;
+               if (isdigit(*cp)) {
+                       cmval = (*cp++ - '0') * 10;
+                       if (isdigit(*cp)) {
+                               cmval += (*cp++ - '0');
+                       }
+               }
+       }
+       cmval = (mval * 100) + cmval;
+
+       for (exponent = 0; exponent < 9; exponent++)
+               if (cmval < poweroften[exponent+1])
+                       break;
+
+       mantissa = cmval / poweroften[exponent];
+       if (mantissa > 9)
+               mantissa = 9;
+
+       retval = (mantissa << 4) | exponent;
+
+       *strptr = cp;
+
+       return (retval);
+}
+
+/* converts ascii lat/lon to unsigned encoded 32-bit number.  moves pointer. */
+static u_int32_t
+latlon2ul(latlonstrptr,which)
+       char **latlonstrptr;
+       int *which;
+{
+       char *cp;
+       u_int32_t retval;
+       int deg = 0, min = 0, secs = 0, secsfrac = 0;
+
+       cp = *latlonstrptr;
+
+       while (isdigit(*cp))
+               deg = deg * 10 + (*cp++ - '0');
+
+       while (isspace(*cp))
+               cp++;
+
+       if (!(isdigit(*cp)))
+               goto fndhemi;
+
+       while (isdigit(*cp))
+               min = min * 10 + (*cp++ - '0');
+
+       while (isspace(*cp))
+               cp++;
+
+       if (!(isdigit(*cp)))
+               goto fndhemi;
+
+       while (isdigit(*cp))
+               secs = secs * 10 + (*cp++ - '0');
+
+       if (*cp == '.') {               /* decimal seconds */
+               cp++;
+               if (isdigit(*cp)) {
+                       secsfrac = (*cp++ - '0') * 100;
+                       if (isdigit(*cp)) {
+                               secsfrac += (*cp++ - '0') * 10;
+                               if (isdigit(*cp)) {
+                                       secsfrac += (*cp++ - '0');
+                               }
+                       }
+               }
+       }
+
+       while (!isspace(*cp))   /* if any trailing garbage */
+               cp++;
+
+       while (isspace(*cp))
+               cp++;
+
+ fndhemi:
+       switch (*cp) {
+       case 'N': case 'n':
+       case 'E': case 'e':
+               retval = ((unsigned)1<<31)
+                       + (((((deg * 60) + min) * 60) + secs) * 1000)
+                       + secsfrac;
+               break;
+       case 'S': case 's':
+       case 'W': case 'w':
+               retval = ((unsigned)1<<31)
+                       - (((((deg * 60) + min) * 60) + secs) * 1000)
+                       - secsfrac;
+               break;
+       default:
+               retval = 0;     /* invalid value -- indicates error */
+               break;
+       }
+
+       switch (*cp) {
+       case 'N': case 'n':
+       case 'S': case 's':
+               *which = 1;     /* latitude */
+               break;
+       case 'E': case 'e':
+       case 'W': case 'w':
+               *which = 2;     /* longitude */
+               break;
+       default:
+               *which = 0;     /* error */
+               break;
+       }
+
+       cp++;                   /* skip the hemisphere */
+
+       while (!isspace(*cp))   /* if any trailing garbage */
+               cp++;
+
+       while (isspace(*cp))    /* move to next field */
+               cp++;
+
+       *latlonstrptr = cp;
+
+       return (retval);
+}
+
+/* converts a zone file representation in a string to an RDATA on-the-wire
+ * representation. */
+int
+loc_aton(ascii, binary)
+       const char *ascii;
+       u_char *binary;
+{
+       const char *cp, *maxcp;
+       u_char *bcp;
+
+       u_int32_t latit = 0, longit = 0, alt = 0;
+       u_int32_t lltemp1 = 0, lltemp2 = 0;
+       int altmeters = 0, altfrac = 0, altsign = 1;
+       u_int8_t hp = 0x16;     /* default = 1e6 cm = 10000.00m = 10km */
+       u_int8_t vp = 0x13;     /* default = 1e3 cm = 10.00m */
+       u_int8_t siz = 0x12;    /* default = 1e2 cm = 1.00m */
+       int which1 = 0, which2 = 0;
+
+       cp = ascii;
+       maxcp = cp + strlen(ascii);
+
+       lltemp1 = latlon2ul(&cp, &which1);
+
+       lltemp2 = latlon2ul(&cp, &which2);
+
+       switch (which1 + which2) {
+       case 3:                 /* 1 + 2, the only valid combination */
+               if ((which1 == 1) && (which2 == 2)) { /* normal case */
+                       latit = lltemp1;
+                       longit = lltemp2;
+               } else if ((which1 == 2) && (which2 == 1)) { /* reversed */
+                       longit = lltemp1;
+                       latit = lltemp2;
+               } else {        /* some kind of brokenness */
+                       return (0);
+               }
+               break;
+       default:                /* we didn't get one of each */
+               return (0);
+       }
+
+       /* altitude */
+       if (*cp == '-') {
+               altsign = -1;
+               cp++;
+       }
+    
+       if (*cp == '+')
+               cp++;
+
+       while (isdigit(*cp))
+               altmeters = altmeters * 10 + (*cp++ - '0');
+
+       if (*cp == '.') {               /* decimal meters */
+               cp++;
+               if (isdigit(*cp)) {
+                       altfrac = (*cp++ - '0') * 10;
+                       if (isdigit(*cp)) {
+                               altfrac += (*cp++ - '0');
+                       }
+               }
+       }
+
+       alt = (10000000 + (altsign * (altmeters * 100 + altfrac)));
+
+       while (!isspace(*cp) && (cp < maxcp)) /* if trailing garbage or m */
+               cp++;
+
+       while (isspace(*cp) && (cp < maxcp))
+               cp++;
+
+       if (cp >= maxcp)
+               goto defaults;
+
+       siz = precsize_aton(&cp);
+       
+       while (!isspace(*cp) && (cp < maxcp))   /* if trailing garbage or m */
+               cp++;
+
+       while (isspace(*cp) && (cp < maxcp))
+               cp++;
+
+       if (cp >= maxcp)
+               goto defaults;
+
+       hp = precsize_aton(&cp);
+
+       while (!isspace(*cp) && (cp < maxcp))   /* if trailing garbage or m */
+               cp++;
+
+       while (isspace(*cp) && (cp < maxcp))
+               cp++;
+
+       if (cp >= maxcp)
+               goto defaults;
+
+       vp = precsize_aton(&cp);
+
+ defaults:
+
+       bcp = binary;
+       *bcp++ = (u_int8_t) 0;  /* version byte */
+       *bcp++ = siz;
+       *bcp++ = hp;
+       *bcp++ = vp;
+       PUTLONG(latit,bcp);
+       PUTLONG(longit,bcp);
+       PUTLONG(alt,bcp);
+    
+       return (16);            /* size of RR in octets */
+}
+
+/* takes an on-the-wire LOC RR and formats it in a human readable format. */
+const char *
+loc_ntoa(binary, ascii)
+       const u_char *binary;
+       char *ascii;
+{
+       static const char *error = "?";
+       static char tmpbuf[sizeof
+"1000 60 60.000 N 1000 60 60.000 W -12345678.00m 90000000.00m 90000000.00m 90000000.00m"];
+       const u_char *cp = binary;
+
+       int latdeg, latmin, latsec, latsecfrac;
+       int longdeg, longmin, longsec, longsecfrac;
+       char northsouth, eastwest;
+       const char *altsign;
+       int altmeters, altfrac;
+
+       const u_int32_t referencealt = 100000 * 100;
+
+       int32_t latval, longval, altval;
+       u_int32_t templ;
+       u_int8_t sizeval, hpval, vpval, versionval;
+    
+       char *sizestr, *hpstr, *vpstr;
+
+       versionval = *cp++;
+
+       if (ascii == NULL)
+               ascii = tmpbuf;
+
+       if (versionval) {
+               (void) sprintf(ascii, "; error: unknown LOC RR version");
+               return (ascii);
+       }
+
+       sizeval = *cp++;
+
+       hpval = *cp++;
+       vpval = *cp++;
+
+       GETLONG(templ, cp);
+       latval = (templ - ((unsigned)1<<31));
+
+       GETLONG(templ, cp);
+       longval = (templ - ((unsigned)1<<31));
+
+       GETLONG(templ, cp);
+       if (templ < referencealt) { /* below WGS 84 spheroid */
+               altval = referencealt - templ;
+               altsign = "-";
+       } else {
+               altval = templ - referencealt;
+               altsign = "";
+       }
+
+       if (latval < 0) {
+               northsouth = 'S';
+               latval = -latval;
+       } else
+               northsouth = 'N';
+
+       latsecfrac = latval % 1000;
+       latval = latval / 1000;
+       latsec = latval % 60;
+       latval = latval / 60;
+       latmin = latval % 60;
+       latval = latval / 60;
+       latdeg = latval;
+
+       if (longval < 0) {
+               eastwest = 'W';
+               longval = -longval;
+       } else
+               eastwest = 'E';
+
+       longsecfrac = longval % 1000;
+       longval = longval / 1000;
+       longsec = longval % 60;
+       longval = longval / 60;
+       longmin = longval % 60;
+       longval = longval / 60;
+       longdeg = longval;
+
+       altfrac = altval % 100;
+       altmeters = (altval / 100);
+
+       sizestr = strdup(precsize_ntoa(sizeval));
+       hpstr = strdup(precsize_ntoa(hpval));
+       vpstr = strdup(precsize_ntoa(vpval));
+
+       sprintf(ascii,
+           "%d %.2d %.2d.%.3d %c %d %.2d %.2d.%.3d %c %s%d.%.2dm %sm %sm %sm",
+               latdeg, latmin, latsec, latsecfrac, northsouth,
+               longdeg, longmin, longsec, longsecfrac, eastwest,
+               altsign, altmeters, altfrac,
+               (sizestr != NULL) ? sizestr : error,
+               (hpstr != NULL) ? hpstr : error,
+               (vpstr != NULL) ? vpstr : error);
+
+       if (sizestr != NULL)
+               free(sizestr);
+       if (hpstr != NULL)
+               free(hpstr);
+       if (vpstr != NULL)
+               free(vpstr);
+
+       return (ascii);
+}
+
+
+/* Return the number of DNS hierarchy levels in the name. */
+int
+dn_count_labels(const char *name) {
+       int i, len, count;
+
+       len = strlen(name);
+       for (i = 0, count = 0; i < len; i++) {
+               /* XXX need to check for \. or use named's nlabels(). */
+               if (name[i] == '.')
+                       count++;
+       }
+
+       /* don't count initial wildcard */
+       if (name[0] == '*')
+               if (count)
+                       count--;
+
+       /* don't count the null label for root. */
+       /* if terminating '.' not found, must adjust */
+       /* count to include last label */
+       if (len > 0 && name[len-1] != '.')
+               count++;
+       return (count);
+}
+
+
+/* 
+ * Make dates expressed in seconds-since-Jan-1-1970 easy to read.  
+ * SIG records are required to be printed like this, by the Secure DNS RFC.
+ */
+char *
+p_secstodate (u_long secs) {
+       /* XXX nonreentrant */
+       static char output[15];         /* YYYYMMDDHHMMSS and null */
+       time_t clock = secs;
+       struct tm *time;
+       
+#ifdef HAVE_TIME_R
+       gmtime_r(&clock, &time);
+#else
+       time = gmtime(&clock);
+#endif
+       time->tm_year += 1900;
+       time->tm_mon += 1;
+       sprintf(output, "%04d%02d%02d%02d%02d%02d",
+               time->tm_year, time->tm_mon, time->tm_mday,
+               time->tm_hour, time->tm_min, time->tm_sec);
+       return (output);
+}
diff --git a/lib/bind/resolv/res_debug.h b/lib/bind/resolv/res_debug.h
new file mode 100644 (file)
index 0000000..4a0aa99
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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 _RES_DEBUG_H_
+#define _RES_DEBUG_H_
+
+#ifndef DEBUG
+#   define Dprint(cond, args) /*empty*/
+#   define DprintQ(cond, args, query, size) /*empty*/
+#   define Aerror(statp, file, string, error, address) /*empty*/
+#   define Perror(statp, file, string, error) /*empty*/
+#else
+#   define Dprint(cond, args) if (cond) {fprintf args;} else {}
+#   define DprintQ(cond, args, query, size) if (cond) {\
+                       fprintf args;\
+                       res_pquery(statp, query, size, stdout);\
+               } else {}
+#endif
+
+#endif /* _RES_DEBUG_H_ */ 
diff --git a/lib/bind/resolv/res_findzonecut.c b/lib/bind/resolv/res_findzonecut.c
new file mode 100644 (file)
index 0000000..8bb9dc5
--- /dev/null
@@ -0,0 +1,603 @@
+#if !defined(lint) && !defined(SABER)
+static const char rcsid[] = "$Id: res_findzonecut.c,v 1.1 2001/03/29 06:31:58 marka 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 "port_before.h"
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/list.h>
+
+#include "port_after.h"
+
+/* Data structures. */
+
+typedef struct rr_a {
+       LINK(struct rr_a)       link;
+       struct in_addr          addr;
+} rr_a;
+typedef LIST(rr_a) rrset_a;
+
+typedef struct rr_ns {
+       LINK(struct rr_ns)      link;
+       const char *            name;
+       rrset_a                 addrs;
+} rr_ns;
+typedef 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 int     get_soa(res_state, const char *, ns_class,
+                       char *, size_t, char *, size_t,
+                       rrset_ns *);
+static int     get_ns(res_state, const char *, ns_class, rrset_ns *);
+static int     get_glue(res_state, ns_class, rrset_ns *);
+static int     save_ns(res_state, ns_msg *, ns_sect,
+                       const char *, ns_class, rrset_ns *);
+static int     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 int     do_query(res_state, const char *, ns_class, ns_type,
+                        u_char *, ns_msg *);
+static void    dprintf(const char *, ...);
+
+/* Macros. */
+
+#define DPRINTF(x) do {\
+               int save_errno = errno; \
+               if ((statp->options & RES_DEBUG) != 0) dprintf x; \
+               errno = save_errno; \
+       } while (0)
+
+/* 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.
+ *
+ *     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.
+ */
+
+int
+res_findzonecut(res_state statp, const char *dname, ns_class class, int opts,
+               char *zname, size_t zsize, struct in_addr *addrs, int naddrs)
+{
+       char mname[NS_MAXDNAME];
+       u_long save_pfcode;
+       rrset_ns nsrrs;
+       int n;
+
+       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;
+       INIT_LIST(nsrrs);
+
+       DPRINTF(("get the soa, and see if it has enough glue"));
+       if ((n = get_soa(statp, dname, class, zname, zsize,
+                        mname, sizeof mname, &nsrrs)) < 0 ||
+           ((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 ((n = get_ns(statp, zname, class, &nsrrs)) < 0 ||
+           ((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 ((n = get_glue(statp, class, &nsrrs)) >= 0)
+               n = satisfy(statp, mname, &nsrrs, addrs, naddrs);
+
+ done:
+       DPRINTF(("FINISH n=%d (%s)", n, (n < 0) ? strerror(errno) : "OK"));
+       free_nsrrset(&nsrrs);
+       statp->pfcode = save_pfcode;
+       return (n);
+}
+
+/* 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 = HEAD(*nsrrsp);
+            nsrr != NULL && naddrs > 0;
+            nsrr = 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 = HEAD(nsrr->addrs); arr != NULL; arr = NEXT(arr, link)) {
+               if (naddrs <= 0)
+                       return (0);
+               *addrs++ = arr->addr;
+               naddrs--;
+               n++;
+       }
+       DPRINTF(("add_addrs: %d", n));
+       return (n);
+}
+
+static int
+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];
+       u_char resp[NS_PACKETSZ];
+       int n, i, ancount, nscount;
+       ns_sect sect;
+       ns_msg msg;
+       u_int rcode;
+
+       /*
+        * Find closest enclosing SOA, even if it's for the root zone.
+        */
+
+       /* First canonicalize dname (exactly one unescaped trailing "."). */
+       if (ns_makecanon(dname, tname, sizeof tname) < 0)
+               return (-1);
+       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? */
+               n = do_query(statp, dname, class, ns_t_soa, resp, &msg);
+               if (n < 0) {
+                       DPRINTF(("get_soa: do_query('%s', %s) failed (%d)",
+                                dname, p_class(class), n));
+                       return (-1);
+               }
+               if (n > 0) {
+                       DPRINTF(("get_soa: CNAME or DNAME found"));
+                       sect = ns_s_max, n = 0;
+               } else {
+                       rcode = ns_msg_getflag(msg, ns_f_rcode);
+                       ancount = ns_msg_count(msg, ns_s_an);
+                       nscount = ns_msg_count(msg, ns_s_ns);
+                       if (ancount > 0 && rcode == ns_r_noerror)
+                               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;
+
+                       if (ns_parserr(&msg, sect, i, &rr) < 0) {
+                               DPRINTF(("get_soa: ns_parserr(%s, %d) failed",
+                                        p_section(sect, ns_o_query), i));
+                               return (-1);
+                       }
+                       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: ns_samedomain('%s', '%s') == 0",
+                                                dname, t));
+                                       errno = EPROTOTYPE;
+                                       return (-1);
+                               }
+                               break;
+                       case ns_s_ns:
+                               if (ns_samename(dname, t) == 1 ||
+                                   ns_samedomain(dname, t) == 0) {
+                                       DPRINTF(("get_soa: ns_samename() || !ns_samedomain('%s', '%s')",
+                                                dname, t));
+                                       errno = EPROTOTYPE;
+                                       return (-1);
+                               }
+                               break;
+                       default:
+                               abort();
+                       }
+                       if (strlen(t) + 1 > zsize) {
+                               DPRINTF(("get_soa: zname(%d) too small (%d)",
+                                        zsize, strlen(t) + 1));
+                               errno = EMSGSIZE;
+                               return (-1);
+                       }
+                       strcpy(zname, t);
+                       rdata = ns_rr_rdata(rr);
+                       rdlen = ns_rr_rdlen(rr);
+                       if (ns_name_uncompress(resp, ns_msg_end(msg), rdata,
+                                              mname, msize) < 0) {
+                               DPRINTF(("get_soa: ns_name_uncompress failed"));
+                               return (-1);
+                       }
+                       if (save_ns(statp, &msg, ns_s_ns,
+                                   zname, class, nsrrsp) < 0) {
+                               DPRINTF(("get_soa: save_ns failed"));
+                               return (-1);
+                       }
+                       return (0);
+               }
+
+               /* 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') {
+                                       errno = EMSGSIZE;
+                                       return (-1);
+                               }
+                       dname++;
+               }
+       }
+       DPRINTF(("get_soa: out of labels"));
+       errno = EDESTADDRREQ;
+       return (-1);
+}
+
+static int
+get_ns(res_state statp, const char *zname, ns_class class, rrset_ns *nsrrsp) {
+       u_char resp[NS_PACKETSZ];
+       ns_msg msg;
+       int n;
+
+       /* Go and get the NS RRs for this zone. */
+       n = do_query(statp, zname, class, ns_t_ns, resp, &msg);
+       if (n != 0) {
+               DPRINTF(("get_ns: do_query('%s', %s) failed (%d)",
+                        zname, p_class(class), n));
+               return (-1);
+       }
+
+       /* Remember the NS RRs and associated A RRs that came back. */
+       if (save_ns(statp, &msg, ns_s_an, zname, class, nsrrsp) < 0) {
+               DPRINTF(("get_ns save_ns('%s', %s) failed",
+                        zname, p_class(class)));
+               return (-1);
+       }
+
+       return (0);
+}
+
+static int
+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 = HEAD(*nsrrsp); nsrr != NULL; nsrr = nsrr_n) {
+               u_char resp[NS_PACKETSZ];
+               ns_msg msg;
+               int n;
+
+               nsrr_n = NEXT(nsrr, link);
+
+               if (EMPTY(nsrr->addrs)) {
+                       n = do_query(statp, nsrr->name, class, ns_t_a,
+                                    resp, &msg);
+                       if (n < 0) {
+                               DPRINTF(("get_glue: do_query('%s', %s') failed",
+                                        nsrr->name, p_class(class)));
+                               return (-1);
+                       }
+                       if (n > 0) {
+                               DPRINTF((
+                       "get_glue: do_query('%s', %s') CNAME or DNAME found",
+                                        nsrr->name, p_class(class)));
+                       }
+                       if (save_a(statp, &msg, ns_s_an, nsrr->name, class,
+                                  &nsrr->addrs) < 0) {
+                               DPRINTF(("get_glue: save_r('%s', %s) failed",
+                                        nsrr->name, p_class(class)));
+                               return (-1);
+                       }
+                       /* If it's still empty, it's just chaff. */
+                       if (EMPTY(nsrr->addrs)) {
+                               DPRINTF(("get_glue: removing empty '%s' NS",
+                                        nsrr->name));
+                               free_nsrr(nsrrsp, nsrr);
+                       }
+               }
+       }
+       return (0);
+}
+
+static int
+save_ns(res_state statp, ns_msg *msg, ns_sect sect,
+       const char *owner, ns_class class,
+       rrset_ns *nsrrsp)
+{
+       int i;
+
+       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;
+
+               if (ns_parserr(msg, sect, i, &rr) < 0) {
+                       DPRINTF(("save_ns: ns_parserr(%s, %d) failed",
+                                p_section(sect, ns_o_query), i));
+                       return (-1);
+               }
+               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 (-1);
+                       }
+                       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 (-1);
+                       }
+                       nsrr->name = strdup(tname);
+                       if (nsrr->name == NULL) {
+                               DPRINTF(("save_ns: strdup failed"));
+                               free(nsrr);
+                               return (-1);
+                       }
+                       INIT_LINK(nsrr, link);
+                       INIT_LIST(nsrr->addrs);
+                       APPEND(*nsrrsp, nsrr, link);
+               }
+               if (save_a(statp, msg, ns_s_ar,
+                          nsrr->name, class, &nsrr->addrs) < 0) {
+                       DPRINTF(("save_ns: save_r('%s', %s) failed",
+                                nsrr->name, p_class(class)));
+                       return (-1);
+               }
+       }
+       return (0);
+}
+
+static int
+save_a(res_state statp, ns_msg *msg, ns_sect sect,
+       const char *owner, ns_class class,
+       rrset_a *arrsp)
+{
+       int i;
+
+       for (i = 0; i < ns_msg_count(*msg, sect); i++) {
+               ns_rr rr;
+               rr_a *arr;
+
+               if (ns_parserr(msg, sect, i, &rr) < 0) {
+                       DPRINTF(("save_a: ns_parserr(%s, %d) failed",
+                                p_section(sect, ns_o_query), i));
+                       return (-1);
+               }
+               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 (-1);
+               }
+               INIT_LINK(arr, link);
+               memcpy(&arr->addr, ns_rr_rdata(rr), NS_INADDRSZ);
+               APPEND(*arrsp, arr, link);
+       }
+       return (0);
+}
+
+static void
+free_nsrrset(rrset_ns *nsrrsp) {
+       rr_ns *nsrr;
+
+       while ((nsrr = HEAD(*nsrrsp)) != NULL)
+               free_nsrr(nsrrsp, nsrr);
+}
+
+static void
+free_nsrr(rrset_ns *nsrrsp, rr_ns *nsrr) {
+       rr_a *arr;
+       char *tmp;
+
+       while ((arr = HEAD(nsrr->addrs)) != NULL) {
+               UNLINK(nsrr->addrs, arr, link);
+               free(arr);
+       }
+       DE_CONST(nsrr->name, tmp);
+       free(tmp);
+       UNLINK(*nsrrsp, nsrr, link);
+       free(nsrr);
+}
+
+static rr_ns *
+find_ns(rrset_ns *nsrrsp, const char *dname) {
+       rr_ns *nsrr;
+
+       for (nsrr = HEAD(*nsrrsp); nsrr != NULL; nsrr = NEXT(nsrr, link))
+               if (ns_samename(nsrr->name, dname) == 1)
+                       return (nsrr);
+       return (NULL);
+}
+
+static int
+do_query(res_state statp, const char *dname, ns_class class, ns_type qtype,
+        u_char *resp, ns_msg *msg)
+{
+       u_char req[NS_PACKETSZ];
+       int i, n;
+
+       n = res_nmkquery(statp, ns_o_query, dname, class, qtype,
+                        NULL, 0, NULL, req, NS_PACKETSZ);
+       if (n < 0) {
+               DPRINTF(("do_query: res_nmkquery failed"));
+               return (-1);
+       }
+       n = res_nsend(statp, req, n, resp, NS_PACKETSZ);
+       if (n < 0) {
+               DPRINTF(("do_query: res_nsend failed"));
+               return (-1);
+       }
+       if (n == 0) {
+               DPRINTF(("do_query: res_nsend returned 0"));
+               errno = EMSGSIZE;
+               return (-1);
+       }
+       if (ns_initparse(resp, n, msg) < 0) {
+               DPRINTF(("do_query: ns_initparse failed"));
+               return (-1);
+       }
+       n = 0;
+       for (i = 0; i < ns_msg_count(*msg, ns_s_an); i++) {
+               ns_rr rr;
+
+               if (ns_parserr(msg, ns_s_an, i, &rr) < 0) {
+                       DPRINTF(("do_query: ns_parserr failed"));
+                       return (-1);
+               }
+               n += (ns_rr_class(rr) == class &&
+                     (ns_rr_type(rr) == ns_t_cname ||
+                      ns_rr_type(rr) == ns_t_dname));
+       }
+       return (n);
+}
+
+static void
+dprintf(const char *fmt, ...) {
+       va_list ap;
+
+       va_start(ap, fmt);
+       fputs(";; res_findzonecut: ", stderr);
+       vfprintf(stderr, fmt, ap);
+       fputc('\n', stderr);
+       va_end(ap);
+}
diff --git a/lib/bind/resolv/res_init.c b/lib/bind/resolv/res_init.c
new file mode 100644 (file)
index 0000000..3d05d0b
--- /dev/null
@@ -0,0 +1,556 @@
+/*
+ * 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.1 2001/03/29 06:31:59 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+
+#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 <arpa/nameser.h>
+
+#include <ctype.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <netdb.h>
+
+#include "port_after.h"
+
+/* Options.  Should all be left alone. */
+#define RESOLVSORT
+#define DEBUG
+
+static void res_setoptions __P((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 __P((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
+ */
+int
+res_ninit(res_state statp) {
+       extern int __res_vinit(res_state, int);
+
+       return (__res_vinit(statp, 0));
+}
+
+/* This function has to be reachable by res_data.c but not publically. */
+int
+__res_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
+       int dots;
+
+       if (!preinit) {
+               statp->retrans = RES_TIMEOUT;
+               statp->retry = RES_DFLRETRY;
+               statp->options = RES_DEFAULT;
+               statp->id = res_randomid();
+       }
+
+#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);
+#ifdef HAVE_SA_LEN
+       statp->nsaddr.sin_len = sizeof(struct sockaddr_in);
+#endif
+       statp->nscount = 1;
+       statp->ndots = 1;
+       statp->pfcode = 0;
+       statp->_vcsock = -1;
+       statp->_flags = 0;
+       statp->qhook = NULL;
+       statp->rhook = NULL;
+       statp->_u._ext.nscount = 0;
+       if (statp->_u._ext.ext == NULL) {
+           statp->_u._ext.ext = malloc(sizeof(*statp->_u._ext.ext));
+           if (statp->_u._ext.ext != NULL) {
+               memset(statp->_u._ext.ext, 0, sizeof(*statp->_u._ext.ext));
+               statp->_u._ext.ext->nsaddrs[0].sin = statp->nsaddr;
+           }
+       }
+
+       /* 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 addrinfo hints, *ai;
+                   char sbuf[NI_MAXSERV];
+                   const size_t minsiz =
+                       sizeof(statp->_u._ext.ext->nsaddrs[0]);
+
+                   cp = buf + sizeof("nameserver") - 1;
+                   while (*cp == ' ' || *cp == '\t')
+                       cp++;
+                   if ((*cp != '\0') && (*cp != '\n')) {
+                       n = strlen(cp);
+                       if (cp[n - 1] == '\n')
+                           cp[n - 1] = '\0';
+                       memset(&hints, 0, sizeof(hints));
+                       hints.ai_family = PF_UNSPEC;
+                       hints.ai_socktype = SOCK_DGRAM; /*dummy*/
+                       hints.ai_flags = AI_NUMERICHOST;
+                       snprintf(sbuf, sizeof(sbuf), "%u", NAMESERVER_PORT);
+                       if (getaddrinfo(cp, sbuf, &hints, &ai) == 0 &&
+                           ai->ai_addrlen <= minsiz) {
+                           if (statp->_u._ext.ext != NULL) {
+                               memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
+                                   ai->ai_addr, ai->ai_addrlen);
+                           }
+                           if (ai->ai_addrlen <=
+                               sizeof(statp->nsaddr_list[nserv])) {
+                               memcpy(&statp->nsaddr_list[nserv],
+                                   ai->ai_addr, ai->ai_addrlen);
+                           } else
+                               statp->nsaddr_list[nserv].sin_family = 0;
+                           freeaddrinfo(ai);
+                           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);
+       }
+/*
+ * Last chance to get a nameserver.  This should not normally
+ * be necessary
+ */
+#ifdef NO_RESOLV_CONF
+       if(nserv == 0)
+               nserv = get_nameservers(statp);
+#endif
+
+       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;
+
+               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
+       }
+
+       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;
+               }
+#ifdef RES_USE_EDNS0
+               else if (!strncmp(cp, "edns0", sizeof("edns0") - 1)) {
+                       statp->options |= RES_USE_EDNS0;
+               }
+#endif
+               else if (!strncmp(cp, "a6", sizeof("a6") - 1)) {
+                       statp->options |= RES_USE_A6;
+               }
+               else if (!strncmp(cp, "dname", sizeof("dname") - 1)) {
+                       statp->options |= RES_USE_DNAME;
+               }
+               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()));
+}
+
+/*
+ * 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) {
+       int ns;
+
+       if (statp->_vcsock >= 0) { 
+               (void) close(statp->_vcsock);
+               statp->_vcsock = -1;
+               statp->_flags &= ~(RES_F_VC | RES_F_CONN);
+       }
+       for (ns = 0; ns < statp->_u._ext.nscount; ns++) {
+               if (statp->_u._ext.nssocks[ns] != -1) {
+                       (void) close(statp->_u._ext.nssocks[ns]);
+                       statp->_u._ext.nssocks[ns] = -1;
+               }
+       }
+}
diff --git a/lib/bind/resolv/res_mkquery.c b/lib/bind/resolv/res_mkquery.c
new file mode 100644 (file)
index 0000000..f0bc427
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * 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.1 2001/03/29 06:31:59 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+#include <sys/types.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <string.h>
+#include "port_after.h"
+
+/* Options.  Leave them on. */
+#define DEBUG
+
+extern const char *_res_opcodes[];
+
+/*
+ * Form all types of queries.
+ * Returns the size of the result or -1.
+ */
+int
+res_nmkquery(res_state statp,
+            int op,                    /* opcode of query */
+            const char *dname,         /* domain name */
+            int class, int type,       /* class and type of query */
+            const u_char *data,        /* resource record data */
+            int datalen,               /* length of data */
+            const u_char *newrr_in,    /* new rr for modify or append */
+            u_char *buf,               /* buffer to put query */
+            int buflen)                /* size of buffer */
+{
+       register HEADER *hp;
+       register u_char *cp;
+       register int n;
+       u_char *dnptrs[20], **dpp, **lastdnptr;
+
+       UNUSED(newrr_in);
+
+#ifdef DEBUG
+       if (statp->options & RES_DEBUG)
+               printf(";; res_nmkquery(%s, %s, %s, %s)\n",
+                      _res_opcodes[op], dname, p_class(class), p_type(type));
+#endif
+       /*
+        * Initialize header fields.
+        */
+       if ((buf == NULL) || (buflen < HFIXEDSZ))
+               return (-1);
+       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 = buf + HFIXEDSZ;
+       buflen -= HFIXEDSZ;
+       dpp = dnptrs;
+       *dpp++ = 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 (-1);
+               if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
+                       return (-1);
+               cp += n;
+               buflen -= n;
+               __putshort(type, cp);
+               cp += INT16SZ;
+               __putshort(class, cp);
+               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 (-1);
+               cp += n;
+               buflen -= n;
+               __putshort(T_NULL, cp);
+               cp += INT16SZ;
+               __putshort(class, cp);
+               cp += INT16SZ;
+               __putlong(0, cp);
+               cp += INT32SZ;
+               __putshort(0, cp);
+               cp += INT16SZ;
+               hp->arcount = htons(1);
+               break;
+
+       case IQUERY:
+               /*
+                * Initialize answer section
+                */
+               if (buflen < 1 + RRFIXEDSZ + datalen)
+                       return (-1);
+               *cp++ = '\0';   /* no domain name */
+               __putshort(type, cp);
+               cp += INT16SZ;
+               __putshort(class, cp);
+               cp += INT16SZ;
+               __putlong(0, cp);
+               cp += INT32SZ;
+               __putshort(datalen, cp);
+               cp += INT16SZ;
+               if (datalen) {
+                       memcpy(cp, data, datalen);
+                       cp += datalen;
+               }
+               hp->ancount = htons(1);
+               break;
+
+       default:
+               return (-1);
+       }
+       return (cp - buf);
+}
+
+#ifdef RES_USE_EDNS0
+/* attach OPT pseudo-RR, as documented in RFC2671 (EDNS0). */
+#ifndef T_OPT
+#define T_OPT  41
+#endif
+
+int
+res_nopt(statp, n0, buf, buflen, anslen)
+       res_state statp;
+       int n0;
+       u_char *buf;            /* buffer to put query */
+       int buflen;             /* size of buffer */
+       int anslen;             /* answer buffer length */
+{
+       register HEADER *hp;
+       register u_char *cp;
+
+#ifdef DEBUG
+       if ((statp->options & RES_DEBUG) != 0)
+               printf(";; res_nopt()\n");
+#endif
+
+       hp = (HEADER *) buf;
+       cp = buf + n0;
+       buflen -= n0;
+
+       if (buflen < 1 + RRFIXEDSZ)
+               return -1;
+
+       *cp++ = 0;      /* "." */
+       buflen--;
+
+       __putshort(T_OPT, cp);  /* TYPE */
+       cp += INT16SZ;
+       __putshort(anslen & 0xffff, cp);        /* CLASS = UDP payload size */
+       cp += INT16SZ;
+       *cp++ = NOERROR;        /* extended RCODE */
+       *cp++ = 0;              /* EDNS version */
+       __putshort(0, cp);      /* MBZ */
+       cp += INT16SZ;
+       __putshort(0, cp);      /* RDLEN */
+       cp += INT16SZ;
+       hp->arcount = htons(ntohs(hp->arcount) + 1);
+       buflen -= RRFIXEDSZ;
+
+       return cp - buf;
+}
+#endif
diff --git a/lib/bind/resolv/res_mkupdate.c b/lib/bind/resolv/res_mkupdate.c
new file mode 100644 (file)
index 0000000..3eea590
--- /dev/null
@@ -0,0 +1,1100 @@
+/*
+ * 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.1 2001/03/29 06:31:59 marka Exp $";
+#endif /* not lint */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <res_update.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+
+#include "port_after.h"
+
+/* Options.  Leave them on. */
+#define DEBUG
+#define MAXPORT 1024
+
+static int getnum_str(u_char **, u_char *);
+static int gethexnum_str(u_char **, u_char *);
+static int getword_str(char *, int, u_char **, u_char *);
+static int getstr_str(char *, int, u_char **, u_char *);
+
+#define ShrinkBuffer(x)  if ((buflen -= x) < 0) return (-2);
+
+/* Forward. */
+
+int res_protocolnumber(const char *);
+int res_servicenumber(const char *);
+
+/*
+ * 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, u_char *buf, int buflen) {
+       ns_updrec *rrecp_start = rrecp_in;
+       HEADER *hp;
+       u_char *cp, *sp1, *sp2, *startp, *endp;
+       int n, i, soanum, multiline;
+       ns_updrec *rrecp;
+       struct in_addr ina;
+       struct in6_addr in6a;
+        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;
+       int siglen, keylen, certlen;
+
+       /*
+        * 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 = 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 int 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, 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, 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, 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, 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, n);
+                       cp += n;
+                       break;
+               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;
+               case ns_t_aaaa:
+                       if (!getword_str(buf2, sizeof buf2, &startp, endp))
+                               return (-1);
+                       if (inet_pton(AF_INET6, buf2, &in6a) <= 0)
+                               return (-1);
+                       ShrinkBuffer(NS_IN6ADDRSZ);
+                       memcpy(cp, &in6a, NS_IN6ADDRSZ);
+                       cp += NS_IN6ADDRSZ;
+                       break;
+               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]);
+       return (cp - buf);
+}
+
+/*
+ * 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, u_char **startpp, 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, u_char **startpp, 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(u_char **startpp, u_char *endp) {
+        int c, n;
+        int seendigit = 0;
+        int m = 0;
+
+       if (*startpp + 2 >= endp || strncasecmp((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(u_char **startpp, 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);
+       }
+       INIT_LINK(rrecp, r_link);
+       INIT_LINK(rrecp, r_glink);
+       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);
+}
+
+struct valuelist {
+       struct valuelist *      next;
+       struct valuelist *      prev;
+       char *                  name;
+       char *                  proto;
+       int                     port;
+};
+static struct valuelist *servicelist, *protolist;
+
+static 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(void) {
+       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(void) {
+       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(u_int16_t 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/lib/bind/resolv/res_mkupdate.h b/lib/bind/resolv/res_mkupdate.h
new file mode 100644 (file)
index 0000000..48edf63
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 1998,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 _RES_MKUPDATE_H_
+#define _RES_MKUPDATE_H_
+
+__BEGIN_DECLS
+__END_DECLS
+
+#endif /* _RES_MKUPDATE_H_ */ 
diff --git a/lib/bind/resolv/res_private.h b/lib/bind/resolv/res_private.h
new file mode 100644 (file)
index 0000000..856f8b8
--- /dev/null
@@ -0,0 +1,2 @@
+extern int
+res_ourserver_p(const res_state statp, const struct sockaddr *sa);
diff --git a/lib/bind/resolv/res_query.c b/lib/bind/resolv/res_query.c
new file mode 100644 (file)
index 0000000..3fb5c6e
--- /dev/null
@@ -0,0 +1,426 @@
+/*
+ * 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.1 2001/03/29 06:31:59 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "port_before.h"
+#include <sys/types.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "port_after.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.
+ */
+int
+res_nquery(res_state statp,
+          const char *name,    /* domain name */
+          int class, int type, /* class and type of query */
+          u_char *answer,      /* buffer to put answer */
+          int anslen)          /* size of answer buffer */
+{
+       u_char buf[MAXPACKET];
+       HEADER *hp = (HEADER *) answer;
+       int n;
+       u_int oflags;
+
+       oflags = statp->_flags;
+
+again:
+       hp->rcode = NOERROR;    /* default */
+
+#ifdef DEBUG
+       if (statp->options & RES_DEBUG)
+               printf(";; res_query(%s, %d, %d)\n", name, class, type);
+#endif
+
+       n = res_nmkquery(statp, QUERY, name, class, type, NULL, 0, NULL,
+                        buf, sizeof(buf));
+#ifdef RES_USE_EDNS0
+       if (n > 0 && (statp->options & RES_USE_EDNS0) != 0 &&
+           (statp->_flags & RES_F_EDNS0ERR) == 0)
+               n = res_nopt(statp, n, buf, sizeof(buf), anslen);
+#endif
+       if (n <= 0) {
+#ifdef DEBUG
+               if (statp->options & RES_DEBUG)
+                       printf(";; res_query: mkquery failed\n");
+#endif
+               RES_SET_H_ERRNO(statp, NO_RECOVERY);
+               return (n);
+       }
+       n = res_nsend(statp, buf, n, answer, anslen);
+       if (n < 0) {
+#ifdef RES_USE_EDNS0
+               /* if the query choked with EDNS0, retry without EDNS0 */
+               if ((statp->options & RES_USE_EDNS0) != 0 &&
+                   ((oflags ^ statp->_flags) & RES_F_EDNS0ERR) != 0) {
+                       statp->_flags |= RES_F_EDNS0ERR;
+                       if (statp->options & RES_DEBUG)
+                               printf(";; res_nquery: retry without EDNS0\n");
+                       goto again;
+               }
+#endif
+#ifdef DEBUG
+               if (statp->options & RES_DEBUG)
+                       printf(";; res_query: send error\n");
+#endif
+               RES_SET_H_ERRNO(statp, TRY_AGAIN);
+               return (n);
+       }
+
+       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 (-1);
+       }
+       return (n);
+}
+
+/*
+ * 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.
+ */
+int
+res_nsearch(res_state statp,
+           const char *name,   /* domain name */
+           int class, int type,        /* class and type of query */
+           u_char *answer,     /* buffer to put answer */
+           int anslen)         /* size of answer */
+{
+       const char *cp, * const *domain;
+       HEADER *hp = (HEADER *) answer;
+       char tmp[NS_MAXDNAME];
+       u_int dots;
+       int trailing_dot, ret, saved_herrno;
+       int got_nodata = 0, got_servfail = 0, root_on_list = 0;
+       int tried_as_is = 0;
+
+       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));
+
+       /*
+        * If there are enough dots in the name, let's just give it a
+        * try 'as is'. The threshold can be set with the "ndots" option.
+        * Also, query 'as is', if there is a trailing dot in the name.
+        */
+       saved_herrno = -1;
+       if (dots >= statp->ndots || trailing_dot) {
+               ret = res_nquerydomain(statp, name, NULL, class, type,
+                                        answer, anslen);
+               if (ret > 0 || trailing_dot)
+                       return (ret);
+               saved_herrno = h_errno;
+               tried_as_is++;
+       }
+
+       /*
+        * 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++;
+
+                       ret = res_nquerydomain(statp, name, *domain,
+                                              class, type,
+                                              answer, anslen);
+                       if (ret > 0)
+                               return (ret);
+
+                       /*
+                        * 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 (-1);
+                       }
+
+                       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 no earlier 'as-is' query 
+        * for the name, and "." is not on the search list, then try an as-is
+        * query now.
+        */
+       if (statp->ndots && !(tried_as_is || root_on_list)) {
+               ret = res_nquerydomain(statp, name, NULL, class, type,
+                                      answer, anslen);
+               if (ret > 0)
+                       return (ret);
+       }
+
+       /* 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 (saved_herrno != -1)
+               RES_SET_H_ERRNO(statp, saved_herrno);
+       else if (got_nodata)
+               RES_SET_H_ERRNO(statp, NO_DATA);
+       else if (got_servfail)
+               RES_SET_H_ERRNO(statp, TRY_AGAIN);
+       return (-1);
+}
+
+/*
+ * Perform a call on res_query on the concatenation of name and domain,
+ * removing a trailing dot from name if domain is NULL.
+ */
+int
+res_nquerydomain(res_state statp,
+           const char *name,
+           const char *domain,
+           int class, int type,        /* class and type of query */
+           u_char *answer,             /* buffer to put answer */
+           int anslen)         /* size of answer */
+{
+       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 (-1);
+               }
+               n--;
+               if (n >= 0 && name[n] == '.') {
+                       strncpy(nbuf, name, 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 (-1);
+               }
+               sprintf(nbuf, "%s.%s", name, domain);
+       }
+       return (res_nquery(statp, longname, class, type, answer, anslen));
+}
+
+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/lib/bind/resolv/res_send.c b/lib/bind/resolv/res_send.c
new file mode 100644 (file)
index 0000000..d9301c2
--- /dev/null
@@ -0,0 +1,1070 @@
+/*
+ * 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_send.c   8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: res_send.c,v 1.1 2001/03/29 06:31:59 marka Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Send query to name server and wait for reply.
+ */
+
+#include "port_before.h"
+#include "fd_setsize.h"
+
+#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/nameser.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <isc/eventlib.h>
+
+#include "port_after.h"
+
+/* Options.  Leave them on. */
+#define DEBUG
+#include "res_debug.h"
+#include "res_private.h"
+
+#define EXT(res) ((res)->_u._ext)
+
+static const int highestFD = FD_SETSIZE - 1;
+
+/* Forward. */
+
+static int             get_salen __P((const struct sockaddr *));
+static struct sockaddr * get_nsaddr __P((res_state, size_t));
+static int             send_vc(res_state, const u_char *, int,
+                               u_char *, int, int *, int);
+static int             send_dg(res_state, const u_char *, int,
+                               u_char *, int, int *, int,
+                               int *, int *);
+static void            Aerror(const res_state, FILE *, const char *, int,
+                              const struct sockaddr *, int);
+static void            Perror(const res_state, FILE *, const char *, int);
+static int             sock_eq(struct sockaddr *, struct sockaddr *);
+#ifdef NEED_PSELECT
+static int             pselect(int, void *, void *, void *,
+                               struct timespec *,
+                               const sigset_t *);
+#endif
+void res_pquery(const res_state, const u_char *, int, FILE *);
+
+#ifdef INET6
+static const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
+#endif
+
+/* Public. */
+
+/* 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 *sa) {
+       const struct sockaddr_in *inp, *srv;
+       const struct sockaddr_in6 *in6p, *srv6;
+       int ns;
+
+       switch (sa->sa_family) {
+       case AF_INET:
+               inp = (const struct sockaddr_in *)sa;
+               for (ns = 0;  ns < statp->nscount;  ns++) {
+                       srv = (struct sockaddr_in *)get_nsaddr(statp, ns);
+                       if (srv->sin_family == inp->sin_family &&
+                           srv->sin_port == inp->sin_port &&
+                           (srv->sin_addr.s_addr == INADDR_ANY ||
+                            srv->sin_addr.s_addr == inp->sin_addr.s_addr))
+                               return (1);
+               }
+               break;
+       case AF_INET6:
+               if (EXT(statp).ext == NULL)
+                       break;
+               in6p = (const struct sockaddr_in6 *)sa;
+               for (ns = 0;  ns < statp->nscount;  ns++) {
+                       srv6 = (struct sockaddr_in6 *)get_nsaddr(statp, ns);
+                       if (srv6->sin6_family == in6p->sin6_family &&
+                           srv6->sin6_port == in6p->sin6_port &&
+                           (IN6_IS_ADDR_UNSPECIFIED(&srv6->sin6_addr) ||
+                            IN6_ARE_ADDR_EQUAL(&srv6->sin6_addr, &in6p->sin6_addr)))
+                               return (1);
+               }
+               break;
+       default:
+               break;
+       }
+       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 = ns_get16(cp); cp += INT16SZ;
+               tclass = ns_get16(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 = ns_get16(cp);   cp += INT16SZ;
+               tclass = ns_get16(cp); cp += INT16SZ;
+               if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
+                       return (0);
+       }
+       return (1);
+}
+
+int
+res_nsend(res_state statp,
+         const u_char *buf, int buflen, u_char *ans, int anssiz)
+{
+       int gotsomewhere, terrno, try, v_circuit, resplen, ns, n;
+#ifdef INET6
+       char abuf[NI_MAXHOST];
+#endif
+
+       if (statp->nscount == 0) {
+               errno = ESRCH;
+               return (-1);
+       }
+       if (anssiz < HFIXEDSZ) {
+               errno = EINVAL;
+               return (-1);
+       }
+       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;
+       terrno = ETIMEDOUT;
+
+       /*
+        * If the ns_addr_list in the resolver context has changed, then
+        * invalidate our cached copy and the associated timing data.
+        */
+       if (EXT(statp).nscount != 0) {
+               int needclose = 0;
+#ifdef INET6
+               struct sockaddr_storage peer;
+#else
+               struct sockaddr peer;
+#endif
+               int peerlen;
+
+               if (EXT(statp).nscount != statp->nscount)
+                       needclose++;
+               else
+                       for (ns = 0; ns < statp->nscount; ns++) {
+                               if (statp->nsaddr_list[ns].sin_family &&
+                                   !sock_eq((struct sockaddr *)&statp->nsaddr_list[ns],
+                                            (struct sockaddr *)&EXT(statp).ext->nsaddrs[ns])) {
+                                       needclose++;
+                                       break;
+                               }
+
+                               if (EXT(statp).nssocks[ns] == -1)
+                                       continue;
+                               peerlen = sizeof(peer);
+                               if (getsockname(EXT(statp).nssocks[ns],
+                                   (struct sockaddr *)&peer, &peerlen) < 0) {
+                                       needclose++;
+                                       break;
+                               }
+                               if (!sock_eq((struct sockaddr *)&peer,
+                                   get_nsaddr(statp, ns))) {
+                                       needclose++;
+                                       break;
+                               }
+                       }
+               if (needclose) {
+                       res_nclose(statp);
+                       EXT(statp).nscount = 0;
+               }
+       }
+
+       /*
+        * Maybe initialize our private copy of the ns_addr_list.
+        */
+       if (EXT(statp).nscount == 0) {
+               for (ns = 0; ns < statp->nscount; ns++) {
+                       if (!statp->nsaddr_list[ns].sin_family)
+                               continue;
+                       EXT(statp).ext->nsaddrs[ns].sin = statp->nsaddr_list[ns];
+                       EXT(statp).nstimes[ns] = RES_MAXTIME;
+                       EXT(statp).nssocks[ns] = -1;
+               }
+               EXT(statp).nscount = statp->nscount;
+       }
+
+       /*
+        * Some resolvers want to even out the load on their nameservers.
+        * Note that RES_BLAST overrides RES_ROTATE.
+        */
+       if ((statp->options & RES_ROTATE) != 0 &&
+           (statp->options & RES_BLAST) == 0) {
+#ifdef INET6
+               union __res_sockaddr_union ina;
+               int inalen;
+#else
+               struct sockaddr_in ina;
+#endif
+               int lastns = statp->nscount - 1;
+               int fd;
+
+               /* XXX not IPv6 ready */
+#ifdef INET6
+               ina.sin = statp->nsaddr_list[0];
+#else
+               ina = statp->nsaddr_list[0];
+#endif
+               fd = EXT(statp).nssocks[0];
+               for (ns = 0; ns < lastns; ns++) {
+                       statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1];
+                       EXT(statp).nssocks[ns] = EXT(statp).nssocks[ns + 1];
+               }
+#ifdef INET6
+               statp->nsaddr_list[lastns] = ina.sin;
+#else
+               statp->nsaddr_list[lastns] = ina;
+#endif
+               EXT(statp).nssocks[lastns] = fd;
+       }
+
+       /*
+        * Send request, RETRY times, or until successful.
+        */
+       for (try = 0; try < statp->retry; try++) {
+           for (ns = 0; ns < statp->nscount; ns++) {
+               struct sockaddr *nsap;
+               int nsaplen;
+               nsap = get_nsaddr(statp, ns);
+               nsaplen = get_salen(nsap);
+ same_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:
+                                       goto fail;
+                               }
+                       } while (!done);
+               }
+
+#ifdef INET6
+               Dprint(((statp->options & RES_DEBUG) &&
+                       getnameinfo(nsap, nsaplen, abuf, sizeof(abuf),
+                                   NULL, 0, niflags) == 0),
+                      (stdout, ";; Querying server (# %d) address = %s\n",
+                       ns + 1, abuf));
+#else
+               Dprint(statp->options & RES_DEBUG,
+                      (stdout, ";; Querying server (# %d) address = %s\n",
+                       ns + 1,
+                       inet_ntoa(((struct sockaddr_in *)nsap)->sin_addr)));
+#endif
+
+
+               if (v_circuit) {
+                       /* Use VC; at most one attempt per server. */
+                       try = statp->retry;
+                       n = send_vc(statp, buf, buflen, ans, anssiz, &terrno,
+                                   ns);
+                       if (n < 0)
+                               goto fail;
+                       if (n == 0)
+                               goto next_ns;
+                       resplen = n;
+               } else {
+                       /* Use datagrams. */
+                       n = send_dg(statp, buf, buflen, ans, anssiz, &terrno,
+                                   ns, &v_circuit, &gotsomewhere);
+                       if (n < 0)
+                               goto fail;
+                       if (n == 0)
+                               goto next_ns;
+                       if (v_circuit)
+                               goto same_ns;
+                       resplen = n;
+               }
+
+               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 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) == 0) ||
+                   (statp->options & RES_STAYOPEN) == 0) {
+                       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:
+                                       goto fail;
+                               }
+                       } while (!done);
+
+               }
+               return (resplen);
+ next_ns: ;
+          } /*foreach ns*/
+       } /*foreach retry*/
+       res_nclose(statp);
+       if (!v_circuit) {
+               if (!gotsomewhere)
+                       errno = ECONNREFUSED;   /* no nameservers found */
+               else
+                       errno = ETIMEDOUT;      /* no answer obtained */
+       } else
+               errno = terrno;
+       return (-1);
+ fail:
+       res_nclose(statp);
+       return (-1);
+}
+
+/* Private */
+
+static int
+get_salen(sa)
+       const struct sockaddr *sa;
+{
+
+#ifdef HAVE_SA_LEN
+       /* there are people do not set sa_len.  be forgibing to them */
+       if (sa->sa_len)
+               return sa->sa_len;
+#endif
+
+       if (sa->sa_family == AF_INET)
+               return sizeof(struct sockaddr_in);
+#ifdef INET6
+       else if (sa->sa_family == AF_INET)
+               return sizeof(struct sockaddr_in6);
+#endif
+       else
+               return 0;       /* unknown, die on connect */
+}
+
+/*
+ * pick appropriate nsaddr_list for use.  see res_init() for initialization.
+ */
+static struct sockaddr *
+get_nsaddr(statp, n)
+       res_state statp;
+       size_t n;
+{
+
+#ifdef INET6
+       if (!statp->nsaddr_list[n].sin_family && EXT(statp).ext) {
+               /*
+                * - EXT(statp).ext->nsaddrs[n] holds an address that is larger
+                *   than struct sockaddr, and
+                * - user code did not update statp->nsaddr_list[n].
+                */
+               return (struct sockaddr *)(void *)&EXT(statp).ext->nsaddrs[n];
+       } else {
+               /*
+                * - user code updated statp->nsaddr_list[n], or
+                * - statp->nsaddr_list[n] has the same content as
+                *   EXT(statp).ext->nsaddrs[n].
+                */
+               return (struct sockaddr *)(void *)&statp->nsaddr_list[n];
+       }
+#else
+       return (struct sockaddr *)(void *)&statp->nsaddr_list[n];
+#endif
+}
+
+static int
+send_vc(res_state statp,
+       const u_char *buf, int buflen, u_char *ans, int anssiz,
+       int *terrno, int ns)
+{
+       const HEADER *hp = (const HEADER *) buf;
+       HEADER *anhp = (HEADER *) ans;
+       struct sockaddr *nsap;
+       int nsaplen;
+       int truncating, connreset, resplen, n;
+       struct iovec iov[2];
+       u_short len;
+       u_char *cp;
+       void *tmp;
+
+       nsap = get_nsaddr(statp, ns);
+       nsaplen = get_salen(nsap);
+
+       connreset = 0;
+ same_ns:
+       truncating = 0;
+
+       /* Are we still talking to whom we want to talk to? */
+       if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) {
+#ifdef INET6
+               struct sockaddr_storage peer;
+#else
+               struct sockaddr_in peer;
+#endif
+               int size = sizeof peer;
+
+               if (getpeername(statp->_vcsock,
+                               (struct sockaddr *)&peer, &size) < 0 ||
+                   !sock_eq((struct sockaddr *)&peer, nsap)) {
+                       res_nclose(statp);
+                       statp->_flags &= ~RES_F_VC;
+               }
+       }
+
+       if (statp->_vcsock < 0 || (statp->_flags & RES_F_VC) == 0) {
+               if (statp->_vcsock >= 0)
+                       res_nclose(statp);
+
+               statp->_vcsock = socket(nsap->sa_family, SOCK_STREAM, 0);
+               if (statp->_vcsock > highestFD) {
+                       res_nclose(statp);
+                       errno = ENOTSOCK;
+               }
+               if (statp->_vcsock < 0) {
+                       *terrno = errno;
+                       Perror(statp, stderr, "socket(vc)", errno);
+                       return (-1);
+               }
+               errno = 0;
+               if (connect(statp->_vcsock, nsap, nsaplen) < 0) {
+                       *terrno = errno;
+                       Aerror(statp, stderr, "connect/vc", errno, nsap,
+                           nsaplen);
+                       res_nclose(statp);
+                       return (0);
+               }
+               statp->_flags |= RES_F_VC;
+       }
+
+       /*
+        * Send length & message
+        */
+       putshort((u_short)buflen, (u_char*)&len);
+       iov[0] = evConsIovec(&len, INT16SZ);
+       DE_CONST(buf, tmp);
+       iov[1] = evConsIovec(tmp, buflen);
+       if (writev(statp->_vcsock, iov, 2) != (INT16SZ + buflen)) {
+               *terrno = errno;
+               Perror(statp, stderr, "write failed", errno);
+               res_nclose(statp);
+               return (0);
+       }
+       /*
+        * Receive length & response
+        */
+ read_len:
+       cp = ans;
+       len = INT16SZ;
+       while ((n = read(statp->_vcsock, (char *)cp, (int)len)) > 0) {
+               cp += n;
+               if ((len -= n) <= 0)
+                       break;
+       }
+       if (n <= 0) {
+               *terrno = 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 == ECONNRESET && !connreset) {
+                       connreset = 1;
+                       res_nclose(statp);
+                       goto same_ns;
+               }
+               res_nclose(statp);
+               return (0);
+       }
+       resplen = ns_get16(ans);
+       if (resplen > anssiz) {
+               Dprint(statp->options & RES_DEBUG,
+                      (stdout, ";; response truncated\n")
+                      );
+               truncating = 1;
+               len = anssiz;
+       } else
+               len = resplen;
+       if (len < HFIXEDSZ) {
+               /*
+                * Undersized message.
+                */
+               Dprint(statp->options & RES_DEBUG,
+                      (stdout, ";; undersized: %d\n", len));
+               *terrno = EMSGSIZE;
+               res_nclose(statp);
+               return (0);
+       }
+       cp = ans;
+       while (len != 0 && (n = read(statp->_vcsock, (char *)cp, (int)len)) > 0){
+               cp += n;
+               len -= n;
+       }
+       if (n <= 0) {
+               *terrno = errno;
+               Perror(statp, stderr, "read(vc)", errno);
+               res_nclose(statp);
+               return (0);
+       }
+       if (truncating) {
+               /*
+                * Flush rest of answer so connection stays in synch.
+                */
+               anhp->tc = 1;
+               len = resplen - anssiz;
+               while (len != 0) {
+                       char junk[PACKETSZ];
+
+                       n = read(statp->_vcsock, junk,
+                                (len > sizeof junk) ? sizeof junk : len);
+                       if (n > 0)
+                               len -= n;
+                       else
+                               break;
+               }
+       }
+       /*
+        * If 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, then 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;
+       }
+
+       /*
+        * All is well, or the error is fatal.  Signal that the
+        * next nameserver ought not be tried.
+        */
+       return (resplen);
+}
+
+static int
+send_dg(res_state statp,
+       const u_char *buf, int buflen, u_char *ans, int anssiz,
+       int *terrno, int ns, int *v_circuit, int *gotsomewhere)
+{
+       const HEADER *hp = (const HEADER *) buf;
+       HEADER *anhp = (HEADER *) ans;
+       const struct sockaddr *nsap;
+       int nsaplen;
+       struct timespec now, timeout, finish;
+       fd_set dsmask;
+#ifdef INET6
+       struct sockaddr_storage from;
+#else
+       struct sockaddr_in from;
+#endif
+       int fromlen, resplen, seconds, n, s;
+
+       nsap = get_nsaddr(statp, ns);
+       nsaplen = get_salen(nsap);
+       if (EXT(statp).nssocks[ns] == -1) {
+               EXT(statp).nssocks[ns] = socket(nsap->sa_family, SOCK_DGRAM, 0);
+               if (EXT(statp).nssocks[ns] > highestFD) {
+                       res_nclose(statp);
+                       errno = ENOTSOCK;
+               }
+               if (EXT(statp).nssocks[ns] < 0) {
+                       *terrno = errno;
+                       Perror(statp, stderr, "socket(dg)", errno);
+                       return (-1);
+               }
+#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 (connect(EXT(statp).nssocks[ns], nsap, nsaplen) < 0) {
+                       Aerror(statp, stderr, "connect(dg)", errno, nsap,
+                           nsaplen);
+                       res_nclose(statp);
+                       return (0);
+               }
+#endif /* !CANNOT_CONNECT_DGRAM */
+               Dprint(statp->options & RES_DEBUG,
+                      (stdout, ";; new DG socket\n"))
+       }
+       s = EXT(statp).nssocks[ns];
+#ifndef CANNOT_CONNECT_DGRAM
+       if (send(s, (const char*)buf, buflen, 0) != buflen) {
+               Perror(statp, stderr, "send", errno);
+               res_nclose(statp);
+               return (0);
+       }
+#else /* !CANNOT_CONNECT_DGRAM */
+       if (sendto(s, (const char*)buf, buflen, 0, nsap, nsaplen) != buflen)
+       {
+               Aerror(statp, stderr, "sendto", errno, nsap, nsaplen);
+               res_nclose(statp);
+               return (0);
+       }
+#endif /* !CANNOT_CONNECT_DGRAM */
+
+       /*
+        * Wait for reply.
+        */
+       seconds = (statp->retrans << ns);
+       if (ns > 0)
+               seconds /= statp->nscount;
+       if (seconds <= 0)
+               seconds = 1;
+       now = evNowTime();
+       timeout = evConsTime(seconds, 0);
+       finish = evAddTime(now, timeout);
+       goto nonow;
+ wait:
+       now = evNowTime();
+ nonow:
+       FD_ZERO(&dsmask);
+       FD_SET(s, &dsmask);
+       if (evCmpTime(finish, now) > 0)
+               timeout = evSubTime(finish, now);
+       else
+               timeout = evConsTime(0, 0);
+       n = pselect(s + 1, &dsmask, NULL, NULL, &timeout, NULL);
+       if (n == 0) {
+               Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n"));
+               *gotsomewhere = 1;
+               return (0);
+       }
+       if (n < 0) {
+               if (errno == EINTR)
+                       goto wait;
+               Perror(statp, stderr, "select", errno);
+               res_nclose(statp);
+               return (0);
+       }
+       errno = 0;
+       fromlen = sizeof(from);
+       resplen = recvfrom(s, (char*)ans, anssiz,0,
+                          (struct sockaddr *)&from, &fromlen);
+       if (resplen <= 0) {
+               Perror(statp, stderr, "recvfrom", errno);
+               res_nclose(statp);
+               return (0);
+       }
+       *gotsomewhere = 1;
+       if (resplen < HFIXEDSZ) {
+               /*
+                * Undersized message.
+                */
+               Dprint(statp->options & RES_DEBUG,
+                      (stdout, ";; undersized: %d\n",
+                       resplen));
+               *terrno = EMSGSIZE;
+               res_nclose(statp);
+               return (0);
+       }
+       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;
+       }
+       if (!(statp->options & RES_INSECURE1) &&
+           !res_ourserver_p(statp, (struct sockaddr *)&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;
+       }
+#ifdef RES_USE_EDNS0
+       if (anhp->rcode == FORMERR && (statp->options & RES_USE_EDNS0) != 0) {
+               /*
+                * Do not retry if the server do not understand EDNS0.
+                * The case has to be captured here, as FORMERR packet do not
+                * carry query section, hence res_queriesmatch() returns 0.
+                */
+               DprintQ(statp->options & RES_DEBUG,
+                       (stdout, "server rejected query with EDNS0:\n"),
+                       ans, (resplen > anssiz) ? anssiz : resplen);
+               /* record the error */
+               statp->_flags |= RES_F_EDNS0ERR;
+               res_nclose(statp);
+               return (0);
+       }
+#endif
+       if (!(statp->options & RES_INSECURE2) &&
+           !res_queriesmatch(buf, buf + buflen,
+                             ans, 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);
+               res_nclose(statp);
+               /* don't retry if called from dig */
+               if (!statp->pfcode)
+                       return (0);
+       }
+       if (!(statp->options & RES_IGNTC) && anhp->tc) {
+               /*
+                * To get the rest of answer,
+                * use TCP with same server.
+                */
+               Dprint(statp->options & RES_DEBUG,
+                      (stdout, ";; truncated answer\n"));
+               *v_circuit = 1;
+               res_nclose(statp);
+               return (1);
+       }
+       /*
+        * All is well, or the error is fatal.  Signal that the
+        * next nameserver ought not be tried.
+        */
+       return (resplen);
+}
+
+static void
+Aerror(const res_state statp, FILE *file, const char *string, int error,
+       const struct sockaddr *address, int alen)
+{
+       int save = errno;
+#ifdef INET6
+       char hbuf[NI_MAXHOST];
+       char sbuf[NI_MAXSERV];
+#else
+       char hbuf[sizeof "255.255.255.255"];
+       char sbuf[sizeof "65535"];
+#endif
+
+       alen = alen;
+
+       if ((statp->options & RES_DEBUG) != 0) {
+#ifdef INET6
+               if (getnameinfo(address, alen, hbuf, sizeof(hbuf),
+                   sbuf, sizeof(sbuf), niflags)) {
+                       strncpy(hbuf, "?", sizeof(hbuf) - 1);
+                       hbuf[sizeof(hbuf) - 1] = '\0';
+                       strncpy(sbuf, "?", sizeof(sbuf) - 1);
+                       sbuf[sizeof(sbuf) - 1] = '\0';
+               }
+#else
+               inet_ntop(AF_INET,
+                         &((const struct sockaddr_in *)address)->sin_addr,
+                         hbuf, sizeof hbuf),
+               snprintf(sbuf, sizeof(sbuf), "%u",
+                   ntohs(((const struct sockaddr_in *)address)->sin_port));
+#endif
+               fprintf(file, "res_send: %s ([%s].%s): %s\n",
+                       string, hbuf, sbuf, strerror(error));
+       }
+       errno = save;
+}
+
+static void
+Perror(const res_state statp, FILE *file, const char *string, int error) {
+       int save = errno;
+
+       if ((statp->options & RES_DEBUG) != 0)
+               fprintf(file, "res_send: %s: %s\n",
+                       string, strerror(error));
+       errno = save;
+}
+
+static int
+sock_eq(struct sockaddr *a, struct sockaddr *b) {
+       struct sockaddr_in *a4, *b4;
+#ifdef INET6
+       struct sockaddr_in6 *a6, *b6;
+#endif
+
+       if (a->sa_family != b->sa_family)
+               return 0;
+       switch (a->sa_family) {
+       case AF_INET:
+               a4 = (struct sockaddr_in *)a;
+               b4 = (struct sockaddr_in *)b;
+               return a4->sin_port == b4->sin_port &&
+                   a4->sin_addr.s_addr == b4->sin_addr.s_addr;
+#ifdef INET6
+       case AF_INET6:
+               a6 = (struct sockaddr_in6 *)a;
+               b6 = (struct sockaddr_in6 *)b;
+               return a6->sin6_port == b6->sin6_port &&
+                   a6->sin6_scope_id == b6->sin6_scope_id &&
+                   IN6_ARE_ADDR_EQUAL(&a6->sin6_addr, &b6->sin6_addr);
+#endif
+       default:
+               return 0;
+       }
+}
+
+#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/lib/bind/resolv/res_sendsigned.c b/lib/bind/resolv/res_sendsigned.c
new file mode 100644 (file)
index 0000000..b450926
--- /dev/null
@@ -0,0 +1,134 @@
+#include "port_before.h"
+#include "fd_setsize.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+
+#include <isc/dst.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "port_after.h"
+
+#define DEBUG
+#include "res_debug.h"
+
+
+/* res_nsendsigned */
+int
+res_nsendsigned(res_state statp, const u_char *msg, int msglen,
+               ns_tsig_key *key, u_char *answer, int anslen)
+{
+       res_state nstatp;
+       DST_KEY *dstkey;
+       int usingTCP = 0;
+       u_char *newmsg;
+       int newmsglen, bufsize, siglen;
+       u_char sig[64];
+       HEADER *hp;
+       time_t tsig_time;
+       int ret;
+
+       dst_init();
+
+       nstatp = (res_state) malloc(sizeof(*statp));
+       if (nstatp == NULL) {
+               errno = ENOMEM;
+               return (-1);
+       }
+       memcpy(nstatp, statp, sizeof(*statp));
+
+       bufsize = msglen + 1024;
+       newmsg = (u_char *) malloc(bufsize);
+       if (newmsg == NULL) {
+               errno = ENOMEM;
+               return (-1);
+       }
+       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) {
+               errno = EINVAL;
+               free(nstatp);
+               free(newmsg);
+               return (-1);
+       }
+
+       nstatp->nscount = 1;
+       siglen = sizeof(sig);
+       ret = ns_sign(newmsg, &newmsglen, bufsize, NOERROR, dstkey, NULL, 0,
+                     sig, &siglen, 0);
+       if (ret < 0) {
+               free (nstatp);
+               free (newmsg);
+               dst_free_key(dstkey);
+               if (ret == NS_TSIG_ERROR_NO_SPACE)
+                       errno  = EMSGSIZE;
+               else if (ret == -1)
+                       errno  = EINVAL;
+               return (ret);
+       }
+
+       if (newmsglen > PACKETSZ || (nstatp->options & RES_IGNTC))
+               usingTCP = 1;
+       if (usingTCP == 0)
+               nstatp->options |= RES_IGNTC;
+       else
+               nstatp->options |= RES_USEVC;
+
+retry:
+
+       ret = res_nsend(nstatp, newmsg, newmsglen, answer, anslen);
+       if (ret < 0) {
+               free (nstatp);
+               free (newmsg);
+               dst_free_key(dstkey);
+               return (ret);
+       }
+
+       anslen = ret;
+       ret = ns_verify(answer, &anslen, dstkey, sig, siglen,
+                       NULL, NULL, &tsig_time, nstatp->options & RES_KEEPTSIG);
+       if (ret != 0) {
+               Dprint(nstatp->pfcode & RES_PRF_REPLY,
+                      (stdout, ";; TSIG invalid (%s)\n", p_rcode(ret)));
+               free (nstatp);
+               free (newmsg);
+               dst_free_key(dstkey);
+               if (ret == -1)
+                       errno = EINVAL;
+               else
+                       errno = ENOTTY;
+               return (-1);
+       }
+       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);
+       dst_free_key(dstkey);
+       return (anslen);
+}
diff --git a/lib/bind/resolv/res_update.c b/lib/bind/resolv/res_update.c
new file mode 100644 (file)
index 0000000..db40da9
--- /dev/null
@@ -0,0 +1,240 @@
+#if !defined(lint) && !defined(SABER)
+static const char rcsid[] = "$Id: res_update.c,v 1.1 2001/03/29 06:31:59 marka 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 "port_before.h"
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <res_update.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/list.h>
+
+#include "port_after.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;
+       union __res_sockaddr_union z_nsaddrs[MAXNS];
+       int                     z_nscount;
+       int                     z_flags;
+       LIST(ns_updrec)         z_rrlist;
+       LINK(struct zonegrp)    z_link;
+};
+
+#define ZG_F_ZONESECTADDED     0x0001
+
+/* Forward. */
+
+static int     nscopy(union __res_sockaddr_union *,
+       const union __res_sockaddr_union *, int);
+static int     nsprom(union __res_sockaddr_union *, const struct in_addr *, int);
+static void    dprintf(const char *, ...);
+
+/* Macros. */
+
+#define DPRINTF(x) do {\
+               int save_errno = errno; \
+               if ((statp->options & RES_DEBUG) != 0) dprintf x; \
+               errno = save_errno; \
+       } while (0)
+
+/* Public. */
+
+int
+res_nupdate(res_state statp, ns_updrec *rrecp_in, ns_tsig_key *key) {
+       ns_updrec *rrecp;
+       u_char answer[PACKETSZ], packet[2*PACKETSZ];
+       struct zonegrp *zptr, tgrp;
+       LIST(struct zonegrp) zgrps;
+       int nzones = 0, nscount = 0, n;
+       union __res_sockaddr_union nsaddrs[MAXNS];
+
+       /* Thread all of the updates onto a list of groups. */
+       INIT_LIST(zgrps);
+       for (rrecp = rrecp_in; rrecp; rrecp = NEXT(rrecp, r_link)) {
+               struct in_addr nsaddrs[MAXNS];
+               int i;
+               /* XXX need to rewrite res_findzonecut */
+               for (i = 0; i < MAXNS; i++) {
+                       nsaddrs[i].s_addr = 0;
+                       if (tgrp.z_nsaddrs[i].sin.sin_family == AF_INET)
+                               nsaddrs[i] = tgrp.z_nsaddrs[i].sin.sin_addr;
+               }
+               /* Find the origin for it if there is one. */
+               tgrp.z_class = rrecp->r_class;
+               tgrp.z_nscount =
+                       res_findzonecut(statp, rrecp->r_dname, tgrp.z_class,
+                                       RES_EXHAUSTIVE,
+                                       tgrp.z_origin,
+                                       sizeof tgrp.z_origin,
+                                       nsaddrs, MAXNS);
+               if (tgrp.z_nscount <= 0) {
+                       DPRINTF(("res_findzonecut failed (%d)",
+                                tgrp.z_nscount));
+                       goto done;
+               }
+               /* Find the group for it if there is one. */
+               for (zptr = HEAD(zgrps); zptr != NULL; zptr = NEXT(zptr, z_link))
+                       if (ns_samename(tgrp.z_origin, zptr->z_origin) == 1 &&
+                           tgrp.z_class == zptr->z_class)
+                               break;
+               /* Make a group for it if there isn't one. */
+               if (zptr == NULL) {
+                       zptr = malloc(sizeof *zptr);
+                       if (zptr == NULL) {
+                               DPRINTF(("malloc failed"));
+                               goto done;
+                       }
+                       *zptr = tgrp;
+                       zptr->z_flags = 0;
+                       INIT_LINK(zptr, z_link);
+                       INIT_LIST(zptr->z_rrlist);
+                       APPEND(zgrps, zptr, z_link);
+               }
+               /* Thread this rrecp onto the right group. */
+               APPEND(zptr->z_rrlist, rrecp, r_glink);
+       }
+
+       for (zptr = HEAD(zgrps); zptr != NULL; zptr = NEXT(zptr, z_link)) {
+               /* 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) {
+                       DPRINTF(("res_mkupdrec failed"));
+                       goto done;
+               }
+               PREPEND(zptr->z_rrlist, rrecp, r_glink);
+               zptr->z_flags |= ZG_F_ZONESECTADDED;
+
+               /* Marshall the update message. */
+               n = res_nmkupdate(statp, HEAD(zptr->z_rrlist),
+                                 packet, sizeof packet);
+               DPRINTF(("res_mkupdate -> %d", n));
+               if (n < 0)
+                       goto done;
+
+               /* Temporarily replace the resolver's nameserver set. */
+               nscount = nscopy(nsaddrs, statp->_u._ext.ext->nsaddrs, statp->nscount);
+               statp->nscount = nscopy(statp->_u._ext.ext->nsaddrs,
+                                       zptr->z_nsaddrs, zptr->z_nscount);
+
+               /* Send the update and remember the result. */
+               if (key != NULL)
+                       n = res_nsendsigned(statp, packet, n, key,
+                                           answer, sizeof answer);
+               else
+                       n = res_nsend(statp, packet, n, answer, sizeof answer);
+               if (n < 0) {
+                       DPRINTF(("res_nsend: send error, n=%d (%s)\n",
+                                n, strerror(errno)));
+                       goto done;
+               }
+               if (((HEADER *)answer)->rcode == NOERROR)
+                       nzones++;
+
+               /* Restore resolver's nameserver set. */
+               statp->nscount = nscopy(statp->_u._ext.ext->nsaddrs, nsaddrs, nscount);
+               nscount = 0;
+       }
+ done:
+       while (!EMPTY(zgrps)) {
+               zptr = HEAD(zgrps);
+               if ((zptr->z_flags & ZG_F_ZONESECTADDED) != 0)
+                       res_freeupdrec(HEAD(zptr->z_rrlist));
+               UNLINK(zgrps, zptr, z_link);
+               free(zptr);
+       }
+       if (nscount != 0)
+               statp->nscount = nscopy(statp->_u._ext.ext->nsaddrs, nsaddrs, nscount);
+
+       return (nzones);
+}
+
+/* Private. */
+
+static int
+nscopy(union __res_sockaddr_union *dst, const union __res_sockaddr_union *src, int n) {
+       int i;
+
+       for (i = 0; i < n; i++)
+               dst[i] = src[i];
+       return (n);
+}
+
+static int
+nsprom(union __res_sockaddr_union *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.sin_family = AF_INET;
+               dst[i].sin.sin_port = htons(NS_DEFAULTPORT);
+               dst[i].sin.sin_addr = src[i];
+#ifdef HAVE_SA_LEN
+               dst[i].sin.sin_len = sizeof(struct sockaddr_in);
+#endif
+       }
+       return (n);
+}
+
+static void
+dprintf(const char *fmt, ...) {
+       va_list ap;
+
+       va_start(ap, fmt);
+       fputs(";; res_nupdate: ", stderr);
+       vfprintf(stderr, fmt, ap);
+       fputc('\n', stderr);
+       va_end(ap);
+}